Python으로 Secret Manager 사용

1. 개요

이 Codelab에서는 Python에서 Secret Manager를 사용하는 데 중점을 둡니다.

Secret Manager를 사용하면 보안 비밀을 바이너리 blob 또는 텍스트 문자열로 저장, 관리, 액세스할 수 있습니다. 적절한 권한이 있으면 보안 비밀 콘텐츠를 볼 수 있습니다.

Secret Manager는 런타임에 애플리케이션에 필요한 데이터베이스 비밀번호, API 키 또는 TLS 인증서와 같은 구성 정보를 저장하는 데 적합합니다.

학습할 내용

  • Cloud Shell을 사용하는 방법
  • Python용 Secret Manager 클라이언트 라이브러리를 설치하는 방법
  • Python 클라이언트 라이브러리를 사용하여 보안 비밀을 만들고 액세스하는 방법
  • Python 클라이언트 라이브러리를 사용하여 Cloud Functions에서 보안 비밀에 액세스하는 방법

필요한 항목

  • Google Cloud 프로젝트
  • 브라우저(Chrome 또는 Firefox 등)
  • Python 3 사용에 관한 지식

설문조사

이 튜토리얼을 어떻게 사용하실 계획인가요?

읽기만 할 계획입니다 읽은 다음 연습 활동을 완료할 계획입니다

귀하의 Python 사용 경험이 어떤지 평가해 주세요.

초급 중급 고급

귀하의 Google Cloud 서비스 사용 경험을 평가해 주세요.

<ph type="x-smartling-placeholder"></ph> 초보자 중급 숙련도

2. 설정 및 요구사항

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유해야 하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔이 고유한 문자열을 자동으로 생성합니다. 보통은 그게 뭔지 상관하지 않습니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로 PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 무작위로 다른 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다.
  • 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스를 삭제하거나 전체 프로젝트를 삭제하면 됩니다. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

Cloud Shell 시작

Google Cloud를 노트북에서 원격으로 실행할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화853e55310c205094.png를 클릭합니다.

55efc1aaa7a4d3ad.png

이전에 Cloud Shell을 시작한 적이 없는 경우 기능을 설명하는 중간 화면 (스크롤해야 볼 수 있는 부분)이 표시됩니다. 이 경우 계속을 클릭합니다 (다시 표시되지 않음). 이 일회성 화면은 다음과 같습니다.

92662c6a846a5c.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

9f0e51b578fecce5.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저나 Chromebook만 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 이미 설정된 것을 볼 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list

명령어 결과

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

3. Secret Manager API 사용 설정

Secret Manager API를 사용하려면 먼저 API를 사용 설정해야 합니다. Cloud Shell에서는 다음 명령어로 API를 사용 설정할 수 있습니다.

gcloud services enable secretmanager.googleapis.com

다음과 같은 출력이 표시됩니다.

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

4. Python용 Secret Manager 클라이언트 라이브러리 설치

Secret Manager 클라이언트 라이브러리를 설치합니다.

pip3 install --user google-cloud-secret-manager==2.10.0

5. 대화형 Python 시작

이 튜토리얼에서는 Cloud Shell에 사전 설치되어 있는 IPython이라는 대화형 Python 인터프리터를 사용합니다. Cloud Shell에서 ipython를 실행하여 세션을 시작합니다.

ipython

다음과 같은 결과를 확인할 수 있습니다.

Python 3.9.2 (default, Feb 28 2021, 17:03:44)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.3.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

6. 보안 비밀 만들기

보안 비밀에는 하나 이상의 보안 비밀 버전이 포함됩니다. gcloud 명령줄을 사용하여 만들 수 있지만 Python을 사용하여 만들 수도 있습니다.

보안 비밀을 사용하려면 먼저 보안 비밀의 이름으로 보안 비밀을 만든 다음 보안 비밀 이 되는 보안 비밀 버전을 추가해야 합니다.

IPython 내에서 프로젝트 ID를 설정합니다.

PROJECT_ID = "<PROJECT_ID>"

보안 비밀 만들기

다음 코드를 IPython 세션에 복사합니다.

from google.cloud import secretmanager

def create_secret(secret_id):
    # Create the Secret Manager client.
    client = secretmanager.SecretManagerServiceClient()

    # Build the resource name of the parent project.
    parent = f"projects/{PROJECT_ID}"

    # Build a dict of settings for the secret
    secret = {'replication': {'automatic': {}}}

    # Create the secret
    response = client.create_secret(secret_id=secret_id, parent=parent, secret=secret)

    # Print the new secret name.
    print(f'Created secret: {response.name}')   

함수를 호출하여 my_secret_value라는 새 보안 비밀을 만듭니다.

create_secret("my_secret_value")

다음과 같은 출력이 표시됩니다.

Created secret: projects/<PROJECT_NUM>/secrets/my_secret_value

보안 비밀 버전 추가

이제 보안 비밀이 존재하므로 버전을 만들어 을 할당할 수 있습니다.

다음 코드를 IPython 세션에 복사합니다.

def add_secret_version(secret_id, payload):
    # Create the Secret Manager client.
    client = secretmanager.SecretManagerServiceClient()

    # Build the resource name of the parent secret.
    parent = f"projects/{PROJECT_ID}/secrets/{secret_id}"

    # Convert the string payload into a bytes. This step can be omitted if you
    # pass in bytes instead of a str for the payload argument.
    payload = payload.encode('UTF-8')

    # Add the secret version.
    response = client.add_secret_version(parent=parent, payload={'data': payload})

    # Print the new secret version name.
    print(f'Added secret version: {response.name}')   

새 보안 비밀 버전을 추가하는 함수를 호출합니다.

add_secret_version("my_secret_value", "Hello Secret Manager")

다음과 같은 출력이 표시됩니다.

Added secret version: projects/<PROJECT_NUM>/secrets/my_secret_value/versions/1

보안 비밀에는 여러 버전이 있을 수 있습니다. 다른 값으로 함수를 다시 호출합니다.

add_secret_version("my_secret_value", "Hello Again, Secret Manager")

다음과 같은 출력이 표시됩니다.

Added secret version: projects/<PROJECT_NUM>/secrets/my_secret_value/versions/2

새 버전의 보안 비밀이 원본보다 훨씬 더 긴 것을 볼 수 있습니다. 이 속성은 나중에 참조됩니다.

7. 보안 비밀 액세스

보안 비밀 버전에 액세스하면 보안 비밀 콘텐츠와 보안 비밀 버전에 대한 추가 메타데이터가 반환됩니다. 보안 비밀 버전에 액세스할 때 특정 버전을 지정하거나 'latest'를 지정하여 최신 버전을 요청할 수 있습니다.

보안 비밀은 비밀로 유지해야 합니다. 데이터베이스 사용자 인증 정보를 보안 비밀로 저장한 다음 인증에 사용하거나, 인증을 저장하여 사용합니다. 비밀번호를 직접 출력하지 마세요. 비밀로 유지할 목적을 무효화하기 때문입니다.

직접 출력하지 않고 그 가치를 평가하면서 비밀에 대한 작전을 펼치게 됩니다. 대신 보안 비밀 값의 해시를 출력합니다.

다음 코드를 IPython 세션에 복사합니다.

def access_secret_version(secret_id, version_id="latest"):
    # Create the Secret Manager client.
    client = secretmanager.SecretManagerServiceClient()

    # Build the resource name of the secret version.
    name = f"projects/{PROJECT_ID}/secrets/{secret_id}/versions/{version_id}"

    # Access the secret version.
    response = client.access_secret_version(name=name)

    # Return the decoded payload.
    return response.payload.data.decode('UTF-8')
    
import hashlib

def secret_hash(secret_value): 
  # return the sha224 hash of the secret value
  return hashlib.sha224(bytes(secret_value, "utf-8")).hexdigest()

보안 비밀을 값의 해시로 검색하는 함수를 호출합니다.

secret_hash(access_secret_version("my_secret_value"))

해시와 유사한 출력이 표시됩니다 (정확한 값은 이 출력과 일치하지 않을 수 있음).

83f8a4edb555cde4271029354395c9f4b7d79706ffa90c746e021d11

버전을 지정하지 않았으므로 최신 값을 가져왔습니다.

확인할 예상 버전 번호를 추가하는 함수를 호출하여 다음을 확인합니다.

secret_hash(access_secret_version("my_secret_value", version_id=2))

마지막 명령어와 동일한 출력이 표시됩니다.

83f8a4edb555cde4271029354395c9f4b7d79706ffa90c746e021d11

함수를 다시 호출하되 이번에는 첫 번째 버전을 지정합니다.

secret_hash(access_secret_version("my_secret_value", version_id=1))

이번에는 다른 해시가 표시되어 다른 출력을 나타냅니다.

9a3fc8b809ddc611c82aee950c636c7557e220893560ec2c1eeeb177

8. Cloud Functions에서 Secret Manager 사용

보안 비밀은 Google Cloud의 여러 부분에서 사용할 수 있습니다. 이 섹션에서는 Google의 이벤트 기반 서버리스 컴퓨팅 제품인 Cloud Functions를 집중적으로 살펴봅니다.

Cloud Functions에서 Python을 사용하는 데 관심이 있다면 Python의 HTTP Google Cloud Functions Codelab을 따르세요.

exit 함수를 호출하여 IPython을 닫습니다.

exit

Cloud Shell로 돌아갑니다.

yourname@cloudshell:~ (<PROJECT_ID>)$

Cloud Functions API를 사용하려면 먼저 API를 사용 설정해야 합니다. Cloud Shell에서는 다음 명령어로 API를 사용 설정할 수 있습니다.

gcloud services enable cloudfunctions.googleapis.com cloudbuild.googleapis.com

함수를 빌드할 새 폴더를 만들어 쓸 빈 파일을 만듭니다.

mkdir secret-manager-api-demo
cd secret-manager-api-demo
touch main.py
touch requirements.txt

Cloud Shell의 오른쪽 상단에서 코드 편집기를 엽니다.

7651a97c51e11a24.png

secret-manager-api-demo 폴더 내에서 main.py 파일로 이동합니다. 여기에 모든 코드를 입력합니다.

9. 보안 비밀에 액세스하는 Cloud 함수 작성

명령줄이나 IPython 터미널에서 보안 비밀 값을 저장하고 가져오는 것이 유용하지만, 함수 내에서 이러한 보안 비밀에 액세스하는 것이 훨씬 더 유용합니다.

앞에서 만든 access_secret_version 함수를 사용하여 이를 Cloud 함수의 기반으로 사용할 수 있습니다.

다음 코드를 main.py 파일에 복사합니다.

main.py

import os

from google.cloud import secretmanager

project_id = os.environ["PROJECT_ID"]

client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/my_secret_value/versions/latest"
response = client.access_secret_version(name=name)
my_secret_value = response.payload.data.decode("UTF-8")


def secret_hello(request):
    if "Again" in my_secret_value:
        return "We meet again!\n"

    return "Hello there.\n"

함수를 배포하려면 먼저 환경 설정을 완료해야 합니다. 이를 위해서는 함수 종속 항목을 설정해야 합니다.

requirements.txt라는 새 파일을 만들고 google-cloud-secret-manager 패키지를 추가합니다.

requirements.txt

google-cloud-secret-manager==2.10.0

이제 main.pyrequirements.txt만 포함된 폴더가 있습니다.

보안 비밀에 대한 액세스 허용

함수를 배포하려면 먼저 Cloud Functions에서 보안 비밀에 액세스할 수 있도록 허용해야 합니다.

터미널로 다시 전환합니다.

c5b686edf94b5222.png

Cloud Functions 서비스 계정에 보안 비밀에 액세스할 수 있는 액세스 권한을 부여합니다.

export PROJECT_ID=$(gcloud config get-value core/project)

gcloud secrets add-iam-policy-binding my_secret_value \
    --role roles/secretmanager.secretAccessor \
    --member serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com

다음과 같은 출력이 표시됩니다.

Updated IAM policy for secret [my_secret_value].
bindings:
- members:
  - serviceAccount:<PROJECT_ID>@appspot.gserviceaccount.com
  role: roles/secretmanager.secretAccessor
etag: BwWiRUt2oB4=
version: 1

10. Cloud 함수 배포

이전 섹션의 설정을 고려하면 이제 Cloud 함수를 배포하고 테스트할 수 있습니다.

생성한 파일 두 개만 포함된 폴더 내에서 함수를 배포합니다.

gcloud functions deploy secret_hello \
    --runtime python39 \
    --set-env-vars PROJECT_ID=${PROJECT_ID} \
    --trigger-http \
    --allow-unauthenticated

다음과 같이 잘린 출력이 표시됩니다.

Deploying function (may take a while - up to 2 minutes)...done.

...

entryPoint: secret_hello
httpsTrigger:
  url: https://<REGION>-<PROJECT_ID>.cloudfunctions.net/secret_hello
...
status: ACTIVE
...

다음 명령어를 사용하여 함수 URL (httpsTrigger.url 메타데이터)을 가져옵니다.

FUNCTION_URL=$(gcloud functions describe secret_hello --format 'value(httpsTrigger.url)')

이제 함수를 호출하여 예상되는 반환 값으로 함수에 액세스할 수 있는지 테스트합니다.

curl $FUNCTION_URL

다음과 같은 출력이 표시됩니다.

We meet again!

이 함수는 'Again' 문자열을 포함하도록 설정된 최신 버전의 보안 비밀을 참조하므로 이 함수가 정상적으로 작동합니다.

11. 축하합니다.

Python을 사용하여 Secret Manager API를 사용하는 방법을 알아봤습니다.

삭제

이 튜토리얼에서 사용한 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 안내를 따르세요.

  • Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.
  • 프로젝트 목록에서 해당 프로젝트를 선택한 후 삭제를 클릭합니다.
  • 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

자세히 알아보기

라이선스

이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.