搭配 Python 使用 Secret Manager

1. 總覽

在本程式碼研究室中,您將專注於以 Python 使用 Secret Manager。

Secret Manager 能以二進位 blob 或文字字串的形式,儲存、管理及存取密鑰。具備適當的權限,即可查看密鑰內容。

Secret Manager 非常適合用來在執行階段儲存設定資訊,例如資料庫密碼、API 金鑰或應用程式所需的 TLS 憑證。

課程內容

  • 如何使用 Cloud Shell
  • 如何安裝 Python 適用的 Secret Manager 用戶端程式庫
  • 如何使用 Python 用戶端程式庫建立及存取密鑰
  • 如何使用 Python 用戶端程式庫存取 Cloud Functions 中的密鑰

軟硬體需求

  • Google Cloud 專案
  • 瀏覽器,例如 ChromeFirefox
  • 熟悉使用 Python 3

問卷調查

您會如何使用這個教學課程?

僅供閱讀 閱讀並完成練習

您對 Python 的使用體驗有何評價?

新手 中級 還算容易

針對使用 Google Cloud 服務的經驗,您會給予什麼評價?

新手 中級 還算容易

2. 設定和需求

自修環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 未使用的字元字串。您隨時可以更新這項資訊。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。此外,您也可以自行嘗試,看看系統是否提供該付款方式。在完成這個步驟後就無法變更,而且在專案期間仍會保持有效。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行這個程式碼研究室並不會產生任何費用,如果有的話。如要關閉資源,以免系統產生本教學課程結束後產生的費用,您可以刪除自己建立的資源,或刪除整個專案。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。

啟動 Cloud Shell

雖然 Google Cloud 可以從筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是一種在 Cloud 中執行的指令列環境。

啟用 Cloud Shell

  1. 在 Cloud 控制台中,按一下「啟用 Cloud Shell」圖示 853e55310c205094.png

55efc1aaa7a4d3ad.png

如果您先前從未啟動 Cloud Shell,您會看見中繼畫面 (需捲動位置),說明螢幕內容。如果出現這種情況,請按一下「繼續」 (之後不會再顯示)。以下是單次畫面的外觀:

9c92662c6a846a5c.png

佈建並連線至 Cloud Shell 只需幾分鐘的時間。

9f0e51b578fecce5.png

這個虛擬機器搭載您需要的所有開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。在本程式碼研究室中,您的大部分作業都可以透過瀏覽器或 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

您必須先啟用 API,才能開始使用 Secret Manager 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

新增密鑰版本

現在 Secret 已存在,您可以透過建立版本來為其指派

將下列程式碼複製到您的 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

Secret 可以有多個版本。使用不同的值再次呼叫函式:

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. 搭配使用 Secret Manager 與 Cloud Functions

您可以在 Google Cloud 的多個部分使用密鑰。本節的重點將放在 Cloud Functions,也就是 Google 的事件導向無伺服器運算服務。

如果您想在 Cloud Functions 中使用 Python,請參閱在 Python 程式碼研究室中使用 HTTP Google Cloud Functions

呼叫 exit 函式關閉 IPython:

exit

您應該返回 Cloud Shell:

yourname@cloudshell:~ (<PROJECT_ID>)$

您必須先啟用 API,才能開始使用 Cloud Functions 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
...

使用下列指令擷取函式網址 (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 控制台中,前往「管理資源」頁面。
  • 在專案清單中,選取您的專案,然後按一下「Delete」(刪除)
  • 在對話方塊中輸入專案 ID,然後按一下「Shut down」(關閉) 即可刪除專案。

瞭解詳情

授權

這項內容採用的是創用 CC 姓名標示 2.0 通用授權。