Secret Managerのシークレットバージョン「破棄」時の挙動をまとめる
3行まとめ
- Google CloudのSecret Managerのシークレットバージョンには
有効
無効
破棄
の3つのステータスがある -
破棄
すると有効
無効
ステータスには2度と戻せなくなりシークレットにアクセスできなくなる - シークレットバージョンが削除されるわけではないので
latest
バージョンの破棄
は特に慎重におこなった方がいい
Secret Managerのシークレットバージョンが持つ3つのステータス
Google CloudのSecret Managerではシークレットがバージョン管理できるようになっている。そして、以下の3つのステータスを持つことができる。
- 有効
- 無効
- 破棄
簡単にそれぞれのステータスについて説明する。
有効
そのバージョンに保存されたシークレットは呼び出し、利用できる状態になっている。
保存したシークレットの値を確認することも可能。
後述する無効
破棄
ステータスへの変更が可能。
無効
そのバージョンに保存されたシークレットは呼び出し不可、利用できない状態になっている。
保存したシークレットの値を確認することは不可能。
有効
と後述する破棄
ステータスへの変更が可能。
破棄
そのバージョンに保存されたシークレットは呼び出し不可、利用できない状態になっている。
保存したシークレットの値を確認することは不可能。
どのステータスへの変更も不可能。
今回はその中でも破棄
ステータスの挙動についてをまとめていきたい。
「破棄」は「削除」ではない
そもそもシークレットバージョンには削除という概念がない。
そのため、上記のように当該のバージョンは永久欠番になるようなイメージだ。
後述するが、破棄
されたバージョンのシークレットを呼び出すと
Secret Version [projects/XXXXXXXXXXXXXX/secrets/hogehogesecret/versions/hoge] is in DESTROYED state.
といったようなエラーが返ってくる。(これはCloud FunctionsのPythonランタイムで呼び出した時のエラーメッセージ)
hoge
バージョンを呼び出すようにコードを書いていた場合、hoge
バージョンは削除して新規に作成することも不可能なため永久欠番になってしまい、呼び出せなくなってしまう。
「破棄したバージョンを呼び出さないようにすればいい」という話であるが、ここで見落とされてしまいがちなポイントについて話したいと思う。
3行まとめでも書いていたlatest
についてだ。
latestバージョンが「破棄」された場合
Secret Managerのシークレットバージョンにアクセスするには、以下のような指定方法がある。
シークレット バージョンにアクセスすると、シークレットのコンテンツとシークレット バージョンに関する追加のメタデータが返されます。シークレット バージョンにアクセスする際は、version-id または alias を指定します(割り当てられている場合)。また、"latest" をバージョンとして指定することにより、シークレットの最新バージョンにもアクセスできます。
バージョンを更新する際、基本的には以前のバージョンを無効化して最新のバージョンを有効にする運用をすることが多いと思われる。
例えば、Cloud Functionsでシークレットを取得する際に以下のようなコードを書いていたとする。
︙
def get_secret(project_id, secret_id, version='latest'):
"""
Secrets Managerから情報を取得する
"""
sm_client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/{secret_id}/versions/{version}"
response = sm_client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8").strip()
︙
get_secret
関数の引数にlatest
バージョンを指定してSecret Managerから保存したシークレットにアクセスしている。
この時、Secret Managerのシークレットが以下のような状態になったとしよう。
破棄
ステータスになったバージョンは、上記で説明した通り残り続ける。現状latest
バージョンは3
バージョンということになり、このままアクセスしようとすると以下のようなエラーが出てしまう。
status = StatusCode.FAILED_PRECONDITION
details = "Secret Version [projects/XXXXXXXXXXXXXX/secrets/hogehogesecret/versions/3] is in DESTROYED state."
上記環境でこの状況を解決するには、以下の手段のどれかを取る必要がある。
- Secret Managerのシークレットで新しいバージョンを作成し、
latest
バージョンに有効
ステータスのシークレットがある状態にする -
有効
ステータスのバージョンを明示的に指定するようにコードを変更する
ベストな運用方法を考えてみる
latest
バージョンを指定して常に最新バージョンのシークレットを利用すると、シークレット更新時にコードのデプロイ作業をしなくて済み常に最新のシークレットを利用することができるので運用面でもセキュリティ面でもlatest
バージョンを指定して利用することは望ましいと私は考えている。
Secret Managerにシークレットを保存する際に常に最新のシークレットが有効になる状態を作るように運用することが大事になってくるのではないだろうか。
ただ、どうしても以前のバージョンのシークレットを使わないといけない状況は出てくるので綺麗にバージョン管理を行うことが難しくなることはあると思う。
改善案としては、以下のようなものが実現可能であると考えている。
現在はコード内でバージョンを指定しているが、Cloud Functionsの環境変数として外出ししてバージョンを指定すればコード自体の変更が入らないので運用面の安定感は少し上がるのではないだろうか。(再デプロイ自体は必要になるのでサービスとしての一時的な停止はどうしても発生してしまうが)
おまけ
Secret Managerのバージョンにはエイリアス機能があり、エイリアス名でバージョンを指定することができる。
最新じゃないlatest
を作ってしまう……というトンチのようなことができたりしないかな?と思って確認してみた。
それはそう
案の定できないように予約されていた。エイリアス機能をトンチ的な使い方をするのはやめよう(できないが)
Discussion