GoogleCloudのParameterManagerでSecretManagerのリソースを参照する

GoogleCloudのParameterManagerでSecretManagerのリソースを参照する

Clock Icon2025.03.22

はじめに

データ事業本部のkobayashiです。前回Google CloudのParameter Managerについて調べて見ましたがパラメータとして機密情報を設定する場合にはSecret Managerを使うことができるので今回はこの機能を試してみたいと思います。

https://dev.classmethod.jp/articles/googlecloud-parametermanager/

Secret Managerとの統合

Parameter Managerでは、Secret Managerに保存すべき機密情報をパラメータに直接埋め込まずにSecret Managerのリソース名の参照として管理できます。
これにより以下が実現可能です。

  • 機密情報をコードに記載せず、漏洩リスクを低減できセキュリティの向上
  • 環境ごとの設定を Parameter Managerで設定管理の一元化
  • versions/latest を使うことでシークレットのローテーションの簡易化

https://cloud.google.com/secret-manager/parameter-manager/docs/reference-secrets-in-parameter

Parameter ManagerからSecret Managerを使ってみる

それでは、実際にSecret Managerとの統合を行ってみます。
手順としては

  1. Secret Managerにシークレットを保存
  2. Parameter Managerでシークレットを参照するパラメータを保存
  3. Pythonでシークレット含むパラメータを取得

といった流れで進めていきます。

1. Secret Managerにシークレットを保存

$ gcloud secrets create db_password --replication-policy="automatic"
$ printf "1234567890abcdef" | gcloud secrets versions add db_password --data-file=-

これで必要なシークレットは登録できたので一応確認してみます。

$ gcloud secrets versions access latest --secret=db_password
1234567890abcdef

2. Parameter Managerでシークレットを参照するパラメータを保存

はじめに参照するSecret Managerのリソース名が必要なのでglcoudコマンドで取得します。

$ gcloud secrets describe db_password --format="value(name)"
projects/{プロジェクトID}/secrets/db_password

取得したリソース名を参照するパラメータを設定します。

$ gcloud beta parametermanager parameters versions create production --parameter=param_store_test_json --location=global --payload-data='{         "database": "myapp_prod",         "username": "prod_user",         "password": "__REF__(\"//secretmanager.googleapis.com/projects/{プロジェクトID}//secrets/db_password/versions/1\")",         "host": "prod.example.com",         "port": 5432     }'
Created parameterVersion [production].

これでパラメータは登録できたので一旦中身を確認してみますがロールを付与しない場合は以下のエラーが出ます。

Encountered an error while retrieving secrets from Secret Manager: PERMISSION_DENIED: [projects/{プロジェクトID}/secrets/db_password/versions/1]-Please ensure that the iamPolicyUidPrincipal (Principal Identifier) is given 'roles/secretmanager.secretAccessor' access to the secret(s) referred by the resource (the secret(s) referred by the resource must exist)

Parameter ManagerがSecret Managerに保存されているシークレットにアクセスできるようにするには、roles/secretmanager.secretAccessorのロールをParameter Managerのパラメータを付与する必要があるので、リソースのプリンシパル IDに対してIAM ロールを付与します。

$ gcloud beta parametermanager parameters describe param_store_test_json --location=global
createTime: '2025-03-17T18:59:47.846690517Z'
format: JSON
name: projects/kobayashi-masahiro/locations/global/parameters/param_store_test_json
policyMember:
  iamPolicyUidPrincipal: principal://parametermanager.googleapis.com/projects/{プロジェクトID}/uid/locations/global/parameters/aaaa1234-bbbb-cccc-dddd-12345678
updateTime: '2025-03-17T18:59:48.002923724Z'

出力されたiamPolicyUidPrincipalがラメータのプリンシパルIDなのでこれに対してroles/secretmanager.secretAccessorのロールを付与します。

$ gcloud secrets add-iam-policy-binding projects/{プロジェクトID}/secrets/db_password --member="principal://parametermanager.googleapis.com/projects/{プロジェクトID}/uid/locations/global/parameters/aaaa1234-bbbb-cccc-dddd-12345678" --role="roles/secretmanager.secretAccessor"
Updated IAM policy for secret [db_password].
bindings:
- members:
  - principal://parametermanager.googleapis.com/projects/{プロジェクトID}/uid/locations/global/parameters/aaaa1234-bbbb-cccc-dddd-12345678
  role: roles/secretmanager.secretAccessor
etag: BwYwtzOEB7U=
version: 1

3. パラメータの取得

パラメータを取得するのは前回同様にPythonで実行します。

get_param.py
import requests
import google.auth
import google.auth.transport.requests

import base64
import json

# サービスアカウントの認証情報を取得
credentials, project = google.auth.default(
    scopes=["https://www.googleapis.com/auth/cloud-platform"]
)

# JSON形式のパラメータを取得
param_name = "param_store_test_json"
version = "production"
response = requests.get(
    f"https://parametermanager.googleapis.com/v1/projects/{project}/locations/global/parameters/{param_name}/versions/{version}:render",
    headers=headers,
)
ret = response.json()
print(ret)
print("JSON形式のパラメータを取得")
print(json.loads(base64.b64decode(ret["payload"]["data"]).decode("utf-8")))
print(json.loads(base64.b64decode(ret["renderedPayload"]).decode("utf-8")))

Parameter Managerに登録したSecret Managerのシークレットを含むパラメータを取得するには、:renderエンドポイントを使用する必要があります。シークレットを含むレスポンスは、通常のpayload.dataではなく、renderedPayloadフィールドに格納されます。

$ python get_param.py 
{'parameterVersion': 'projects/{プロジェクト名}/locations/global/parameters/param_store_test_json/versions/production', 'payload': {'data': 'eyAgICAgICAgICJkYXRhYmFzZSI6ICJteWFwcF9wcm9kIiwgICAgICAgICAidXNlcm5hbWUiOiAicHJvZF91c2VyIiwgICAgICAgICAicGFzc3dvcmQiOiAiX19SRUZfXyhcIi8vc2VjcmV0bWFuYWdlci5nb29nbGVhcGlzLmNvbS9wcm9qZWN0cy8yMzMxNTEzOTYwODgvc2VjcmV0cy9kYl9wYXNzd29yZC92ZXJzaW9ucy8xXCIpIiwgICAgICAgICAiaG9zdCI6ICJwcm9kLmV4YW1wbGUuY29tIiwgICAgICAgICAicG9ydCI6IDU0MzIgICAgIH0='}, 'renderedPayload': 'eyAgICAgICAgICJkYXRhYmFzZSI6ICJteWFwcF9wcm9kIiwgICAgICAgICAidXNlcm5hbWUiOiAicHJvZF91c2VyIiwgICAgICAgICAicGFzc3dvcmQiOiAiMTIzNDU2Nzg5MGFiY2RlZiIsICAgICAgICAgImhvc3QiOiAicHJvZC5leGFtcGxlLmNvbSIsICAgICAgICAgInBvcnQiOiA1NDMyICAgICB9'}
JSON形式のパラメータを取得
{'database': 'myapp_prod', 'username': 'prod_user', 'password': '__REF__("//secretmanager.googleapis.com/projects/{プロジェクトID}/secrets/db_password/versions/1")', 'host': 'prod.example.com', 'port': 5432}
{'database': 'myapp_prod', 'username': 'prod_user', 'password': '1234567890abcdef', 'host': 'prod.example.com', 'port': 5432}

まとめ

今回はGoogle CloudのSecret ManagerとParameter Managerの統合について検証しました。Secret Managerを利用することで、機密情報をコードに直接記載せずに管理でき、セキュリティの向上や設定の一元管理が可能になります。
また、Parameter Managerを利用することで、環境ごとの設定を統一的に管理 しつつ、Secret Managerのシークレットを安全に参照 できることが確認できました。

最後まで読んで頂いてありがとうございました。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.