
GoogleCloudのParameterManagerにパラメータテンプレートが追加されたので試してみる
はじめに
データアナリティクス事業本部のkobayashiです。
これまでGoogle CloudのParameter Managerについて何本か記事を書いてきました。
これらの記事ではパラメータに設定値そのものを保存していましたが、環境ごとに似たような設定ファイルを個別に持つと、キーの追加や構造変更のたびにすべての環境分を手で直す必要があり管理が煩雑になります。
2026年7月12日のアップデートでParameter Managerに パラメータテンプレート(Parameter Templates) がPreviewとして追加されました。設定の「構造(雛形)」と「環境ごとの値」を分離し、1つのテンプレートを複数環境で使い回せるようになる機能です。今回はこのパラメータテンプレートを試してみます。
パラメータテンプレートとは
パラメータテンプレートは、設定の構造をテンプレートとして定義しておき、実際の値をレンダリング時に差し込む仕組みです。登場するリソースは2つに分かれています。
| リソース | 役割 |
|---|---|
| テンプレートバージョン(Template Version) | 設定の構造(雛形) を保持する。{{.variableName}} 形式のプレースホルダを埋め込む |
| パラメータバージョン(Parameter Version) | 雛形に差し込む実際の値 を保持する。これまで通りのParameter Managerのパラメータ |
テンプレートバージョンにプレースホルダを書いておき、レンダリング時にパラメータバージョンの値で置換して最終的な設定を生成します。プレースホルダは {{.env}} のように書き、{{.database.host}} のようにネストしたキーも参照できます。
これにより「構造は共通、値だけ環境ごとに差し替え」という運用が、テンプレート1つ+環境ごとのパラメータバージョン、という形で実現できます。
なお、執筆時点(2026年7月)ではパラメータテンプレートの操作は REST API およびクライアントライブラリのみ の対応で、gcloud parametermanager にはテンプレート用のサブコマンドがまだありません。そのため本記事ではテンプレート周りをPythonからREST APIで操作します。値を保持するパラメータバージョン側はこれまで通り gcloud で作成します。
事前準備
これまでの記事と同様、Pythonから認証付きでREST APIを叩く形で進めます。認証情報の取得には google-auth と requests を使用します。
$ pip install google-auth requests
テンプレートを作成する
まずはテンプレート本体と、{{.variableName}} を含むテンプレートバージョンを作成します。今回はアプリケーションの設定(接続先DBやログレベル)をYAML形式のテンプレートとして定義します。
テンプレートの作成は POST .../locations/global/templates?template_id=...、テンプレートバージョンの作成は POST .../templates/{template_id}/versions?template_version_id=... で、バージョンのペイロード(雛形の中身)はBase64エンコードして payload.data に渡します。
import base64
import requests
import google.auth
import google.auth.transport.requests
credentials, project = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
credentials.refresh(google.auth.transport.requests.Request())
headers = {
"Authorization": f"Bearer {credentials.token}",
"Content-Type": "application/json; charset=utf-8",
}
BASE = "https://parametermanager.googleapis.com/v1"
template_id = "app_config_template"
# 1. テンプレートを作成する(YAML形式)
res = requests.post(
f"{BASE}/projects/{project}/locations/global/templates",
headers=headers,
params={"template_id": template_id},
json={"format": "TEMPLATE_FORMAT_YAML"},
)
res.raise_for_status()
print(f"template created: {res.json()['name']}")
# 2. テンプレートバージョンを作成する({{.変数}} を含む雛形)
template_yaml = """appName: myapp-api
environment: {{.env}}
logLevel: {{.log_level}}
database:
host: {{.database.host}}
port: {{.database.port}}
name: {{.database.name}}
"""
encoded = base64.b64encode(template_yaml.encode("utf-8")).decode("utf-8")
res = requests.post(
f"{BASE}/projects/{project}/locations/global/templates/{template_id}/versions",
headers=headers,
params={"template_version_id": "v1"},
json={"payload": {"data": encoded}},
)
res.raise_for_status()
print(f"template version created: {res.json()['name']}")
実行するとテンプレートとテンプレートバージョンが作成されます。
$ python create_template.py
template created: projects/{プロジェクトID}/locations/global/templates/app_config_template
template version created: projects/{プロジェクトID}/locations/global/templates/app_config_template/versions/v1
作成状況は curl でも確認できます。
$ curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://parametermanager.googleapis.com/v1/projects/{プロジェクトID}/locations/global/templates/app_config_template/versions/v1" | jq .name
"projects/{プロジェクトID}/locations/global/templates/app_config_template/versions/v1"
environment や database.host など、環境によって変わる部分を {{.env}} {{.database.host}} としてプレースホルダにしている点がポイントです。この雛形自体には環境ごとの値は一切含まれていません。
値を供給するパラメータを用意する
次に、テンプレートに差し込む値を保持するパラメータバージョンを作成します。こちらは従来通り gcloud parametermanager で作成できます。テンプレートの {{.database.host}} のようなドット記法に対応させるため、ネストした構造を持つJSON形式のパラメータを作成します。
開発環境(develop)用と本番環境(production)用の2つを用意します。
# 開発環境用
$ gcloud parametermanager parameters create app_config_dev \
--location=global --parameter-format=json
Created parameter [app_config_dev].
$ gcloud parametermanager parameters versions create v1 \
--parameter=app_config_dev --location=global \
--payload-data='{"env":"develop","log_level":"DEBUG","database":{"host":"dev.example.com","port":5432,"name":"myapp_dev"}}'
Created version [v1].
# 本番環境用
$ gcloud parametermanager parameters create app_config_prod \
--location=global --parameter-format=json
Created parameter [app_config_prod].
$ gcloud parametermanager parameters versions create v1 \
--parameter=app_config_prod --location=global \
--payload-data='{"env":"production","log_level":"INFO","database":{"host":"prod.example.com","port":5432,"name":"myapp_prod"}}'
Created version [v1].
テンプレートのプレースホルダ名(env / log_level / database.host ...)と、パラメータバージョンのキー構造が一致している点が重要です。値のパースは構造化データとして行われるため、パラメータバージョンはJSON・YAMLどちらの形式でも同じ構造なら差し込めます。
レンダリングする
テンプレートバージョンとパラメータバージョンを組み合わせてレンダリングします。レンダリングは GET .../templates/{template_id}/versions/{version}:render?parameter_version=... で、クエリパラメータ parameter_version に差し込むパラメータバージョンのフルリソース名を指定します。レスポンスの renderedPayload に置換後の設定がBase64で入って返ってきます。
同じテンプレート(app_config_template/versions/v1)に対して、開発用と本番用のパラメータバージョンをそれぞれ渡してみます。
import base64
import requests
import google.auth
import google.auth.transport.requests
credentials, project = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
credentials.refresh(google.auth.transport.requests.Request())
headers = {"Authorization": f"Bearer {credentials.token}"}
BASE = "https://parametermanager.googleapis.com/v1"
template_id = "app_config_template"
template_version = "v1"
def render(param_id: str, param_version: str = "v1") -> str:
param_path = (
f"projects/{project}/locations/global"
f"/parameters/{param_id}/versions/{param_version}"
)
url = (
f"{BASE}/projects/{project}/locations/global"
f"/templates/{template_id}/versions/{template_version}:render"
)
res = requests.get(url, headers=headers, params={"parameter_version": param_path})
res.raise_for_status()
return base64.b64decode(res.json()["renderedPayload"]).decode("utf-8")
print("=== develop ===")
print(render("app_config_dev"))
print("=== production ===")
print(render("app_config_prod"))
実行すると、同一のテンプレートから環境ごとに異なる設定が生成されます。
$ python render_template.py
=== develop ===
appName: myapp-api
environment: develop
logLevel: DEBUG
database:
host: dev.example.com
port: 5432
name: myapp_dev
=== production ===
appName: myapp-api
environment: production
logLevel: INFO
database:
host: prod.example.com
port: 5432
name: myapp_prod
テンプレートには一切手を加えず、渡すパラメータバージョンを差し替えるだけで開発用・本番用の設定を出し分けできました。設定項目を追加したい場合はテンプレートバージョンを更新するだけで済み、環境ごとの設定ファイルを個別にメンテナンスする必要がなくなります。
Secret Managerを参照する値と組み合わせる
パラメータバージョンには、以前の記事で扱った __REF__ 記法でSecret Managerのシークレットを参照する値も入れられます。テンプレート側にパスワード用のプレースホルダを追加し、パラメータバージョン側でその値をSecret Manager参照にしておけば、レンダリング時に「テンプレートへの値差し込み」と「シークレットの解決」がまとめて行われます。
まずパスワード行を追加したテンプレートバージョン v2 を作成します。
import base64
import requests
import google.auth
import google.auth.transport.requests
credentials, project = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
credentials.refresh(google.auth.transport.requests.Request())
headers = {
"Authorization": f"Bearer {credentials.token}",
"Content-Type": "application/json; charset=utf-8",
}
BASE = "https://parametermanager.googleapis.com/v1"
template_id = "app_config_template"
template_yaml = """appName: myapp-api
environment: {{.env}}
logLevel: {{.log_level}}
database:
host: {{.database.host}}
port: {{.database.port}}
name: {{.database.name}}
password: {{.database.password}}
"""
encoded = base64.b64encode(template_yaml.encode("utf-8")).decode("utf-8")
res = requests.post(
f"{BASE}/projects/{project}/locations/global/templates/{template_id}/versions",
headers=headers,
params={"template_version_id": "v2"},
json={"payload": {"data": encoded}},
)
res.raise_for_status()
print(f"template version created: {res.json()['name']}")
次にSecret Managerにパスワードのシークレットを作成し、本番用パラメータに __REF__ でそれを参照する v2 を追加します。
$ gcloud secrets create db_password --replication-policy="automatic"
Created secret [db_password].
$ printf "prod_secret_password" | gcloud secrets versions add db_password --data-file=-
Created version [1] of the secret [db_password].
$ gcloud parametermanager parameters versions create v2 \
--parameter=app_config_prod --location=global \
--payload-data='{"env":"production","log_level":"INFO","database":{"host":"prod.example.com","port":5432,"name":"myapp_prod","password":"__REF__(\"//secretmanager.googleapis.com/projects/{プロジェクトID}/secrets/db_password/versions/latest\")"}}'
Created version [v2].
Parameter ManagerにSecret Manager参照を許可する
このままレンダリングすると、参照先のシークレットに対する読み取り権限がないため以下のエラーが返ります。
{
"error": {
"code": 400,
"message": "Encountered an error while retrieving secrets from Secret Manager: SECRET_REFERENCE_ERROR: [projects/{プロジェクトID}/secrets/db_password/versions/latest]-Please ensure that referred secret(s) exist and the iamPolicyUidPrincipal (IAM Principal Identifier) is given 'roles/secretmanager.secretAccessor' role to the referred secret(s).",
"status": "FAILED_PRECONDITION"
}
}
各パラメータには iamPolicyUidPrincipal という専用のプリンシパル識別子が割り当てられており、Secret Managerを参照するにはこの識別子に対して roles/secretmanager.secretAccessor を付与する必要があります。パラメータの iamPolicyUidPrincipal は gcloud parametermanager parameters describe で確認できます。
$ gcloud parametermanager parameters describe app_config_prod --location=global
createTime: '2026-07-18T12:00:07.498172872Z'
format: JSON
name: projects/{プロジェクトID}/locations/global/parameters/app_config_prod
policyMember:
iamPolicyUidPrincipal: principal://parametermanager.googleapis.com/projects/{プロジェクト番号}/uid/locations/global/parameters/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
updateTime: '2026-07-18T12:00:07.664822541Z'
この iamPolicyUidPrincipal の値をそのまま --member に渡してシークレットにアクセスを許可します。
$ gcloud secrets add-iam-policy-binding db_password \
--member="principal://parametermanager.googleapis.com/projects/{プロジェクト番号}/uid/locations/global/parameters/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--role="roles/secretmanager.secretAccessor"
Updated IAM policy for secret [db_password].
テンプレート v2 と本番パラメータ v2 を指定してレンダリングします。
import base64
import requests
import google.auth
import google.auth.transport.requests
credentials, project = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
credentials.refresh(google.auth.transport.requests.Request())
headers = {"Authorization": f"Bearer {credentials.token}"}
BASE = "https://parametermanager.googleapis.com/v1"
param_path = (
f"projects/{project}/locations/global/parameters/app_config_prod/versions/v2"
)
url = (
f"{BASE}/projects/{project}/locations/global"
f"/templates/app_config_template/versions/v2:render"
)
res = requests.get(url, headers=headers, params={"parameter_version": param_path})
res.raise_for_status()
print(base64.b64decode(res.json()["renderedPayload"]).decode("utf-8"))
実行結果は以下のようになります。
$ python render_with_secret.py
appName: myapp-api
environment: production
logLevel: INFO
database:
host: prod.example.com
port: 5432
name: myapp_prod
password: prod_secret_password
password にはテンプレートへの差し込みを経てSecret Managerのシークレット値が解決された状態で入っています。設定の構造(テンプレート)・環境ごとの値(パラメータバージョン)・機密情報(Secret Manager)の3つをそれぞれ別々に管理しつつ、最終的な設定としては1回のレンダリングでまとめて取得できます。IAMの付与単位もパラメータ単位で細かく制御できるため、環境ごとに参照可能なシークレットを分けるといった運用も自然に組めます。
使う上での注意点
パラメータテンプレートを使う上での制約をまとめます。
| 項目 | 内容 |
|---|---|
| 形式 | テンプレートバージョンはJSONまたはYAMLの有効なオブジェクトである必要がある。UNFORMATTED(プレーンテキスト)は非対応 |
| 変数の数 | 1つのテンプレートバージョンで使える変数は最大64個 |
| レンダリング後のサイズ | 最終的にレンダリングされる出力は1MBを超えられない |
| 置換の種類 | サポートされるのは {{.variableName}} による直接の値置換のみ。条件分岐やループのような複雑なロジックは不可 |
| シークレット参照 | Secret Managerの参照はテンプレートに直接書くのではなく、パラメータバージョン側で __REF__() 記法を使う |
| シークレット参照時のIAM | 参照先のシークレットに対して、パラメータの iamPolicyUidPrincipal に roles/secretmanager.secretAccessor を付与する必要がある |
| 提供状況 | 執筆時点ではPreview。gcloud 未対応でREST API・クライアントライブラリのみ |
特に「シークレットはテンプレートではなくパラメータバージョン側で参照する」点は、テンプレートを構造の定義に徹させるうえでも理にかなった設計になっています。
まとめ
Parameter Managerのパラメータテンプレートを試してみました。設定の構造をテンプレートバージョンとして定義し、環境ごとの値をパラメータバージョンとして分離することで、1つのテンプレートを開発・本番で使い回せるようになります。さらにパラメータバージョン側で __REF__ を使えばSecret Managerのシークレット解決も同じレンダリングでまとめて行えるため、「構造・値・機密情報」を分けて管理しつつ最終設定を一発で組み立てる構成が作れます。環境ごとに似た設定ファイルを個別管理していたようなワークロードで有用な機能だと思います。
最後まで読んで頂いてありがとうございました。

