GoogleCloudのParameterManagerにパラメータテンプレートが追加されたので試してみる

GoogleCloudのParameterManagerにパラメータテンプレートが追加されたので試してみる

Google CloudのParameter Managerに新たに追加されたパラメータテンプレート機能を試してみました。設定の構造と環境ごとの値を分離し、1つのテンプレートを複数環境で使い回せる仕組みについて、実装例を交えながら紹介します。
2026.08.04

はじめに

データアナリティクス事業本部のkobayashiです。

これまでGoogle CloudのParameter Managerについて何本か記事を書いてきました。

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

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

これらの記事ではパラメータに設定値そのものを保存していましたが、環境ごとに似たような設定ファイルを個別に持つと、キーの追加や構造変更のたびにすべての環境分を手で直す必要があり管理が煩雑になります。

2026年7月12日のアップデートでParameter Managerに パラメータテンプレート(Parameter Templates) がPreviewとして追加されました。設定の「構造(雛形)」と「環境ごとの値」を分離し、1つのテンプレートを複数環境で使い回せるようになる機能です。今回はこのパラメータテンプレートを試してみます。

https://docs.cloud.google.com/release-notes#July_12_2026

https://docs.cloud.google.com/secret-manager/parameter-manager/docs/parameter-templates-overview

パラメータテンプレートとは

パラメータテンプレートは、設定の構造をテンプレートとして定義しておき、実際の値をレンダリング時に差し込む仕組みです。登場するリソースは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-authrequests を使用します。

$ 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 に渡します。

create_template.py
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"

environmentdatabase.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)に対して、開発用と本番用のパラメータバージョンをそれぞれ渡してみます。

render_template.py
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 を作成します。

add_template_v2.py
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 を付与する必要があります。パラメータの iamPolicyUidPrincipalgcloud 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 を指定してレンダリングします。

render_with_secret.py
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 参照先のシークレットに対して、パラメータの iamPolicyUidPrincipalroles/secretmanager.secretAccessor を付与する必要がある
提供状況 執筆時点ではPreview。gcloud 未対応でREST API・クライアントライブラリのみ

特に「シークレットはテンプレートではなくパラメータバージョン側で参照する」点は、テンプレートを構造の定義に徹させるうえでも理にかなった設計になっています。

まとめ

Parameter Managerのパラメータテンプレートを試してみました。設定の構造をテンプレートバージョンとして定義し、環境ごとの値をパラメータバージョンとして分離することで、1つのテンプレートを開発・本番で使い回せるようになります。さらにパラメータバージョン側で __REF__ を使えばSecret Managerのシークレット解決も同じレンダリングでまとめて行えるため、「構造・値・機密情報」を分けて管理しつつ最終設定を一発で組み立てる構成が作れます。環境ごとに似た設定ファイルを個別管理していたようなワークロードで有用な機能だと思います。

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

この記事をシェアする

関連記事