はじめに
君と夏の終わり♪ nikkieです。
先日のExternal Secrets Operator(ESO) Getting startedの素振りを踏まえて、もう少し手を動かしてみました。
目次
- はじめに
- 目次
- 結論:GCPのSecret Managerで1つのシークレットに複数の秘密情報を保存し、External Secrets Operatorで参照する方法
- 動作環境
- ESOでGCPのSecret Managerを使う
- GCPのSecret Managerで複数の秘密情報を保存したシークレットを作る
- GCP Secret Managerのシークレット(JSON形式)から秘密情報1つだけを指定してk8sのシークレットを作る
- GCP Secret Managerのシークレット(JSON形式)にまとめた秘密情報全部を持ったk8sのシークレットを作る
- お片付け
- 終わりに
- P.S. GCPのSecret ManagerにJSON形式で指定に気づいたきっかけ
結論:GCPのSecret Managerで1つのシークレットに複数の秘密情報を保存し、External Secrets Operatorで参照する方法
動作環境
Getting started素振り記事と同様です。
- M1 Mac(macOS 12.6.6)
- Docker Desktop(Version 4.21.1 (114176))
- 操作するcontextはデフォルトの
docker-desktop
- 操作するnamespaceはデフォルトの
default
ESOでGCPのSecret Managerを使う
ESOのドキュメントの「Google Cloud Secret Manager」を参照します1
複数の方法が書いてあるようですが、今回は「GCP Service Account authentication」を採用しました。
- GCPのサービスアカウントを作成
- JSONファイルをダウンロード
- サービスアカウントのJSONファイルの内容でk8sのsecretを作成
- k8sのsecretを参照して、ESOのSecretStoreを設定
GCPのサービスアカウント作成
GCPのコンソールから作っていきます
After creating a GCP Service account go to IAM & Admin web UI, click ADD ANOTHER ROLE button, add Secret Manager Secret Accessor role to this service account.
とあったので、サービスアカウント作成中に「Secret Manager Secret Accessor」ロールを指定しました
サービスアカウントを作ったあとは選択して詳細画面に遷移し、「Keys」タブを操作。
「ADD KEY」>「Create new key」でJSONファイルを作り、ダウンロードします。
サービスアカウントのJSONファイルの内容でk8sのsecretを作成
ESOのドキュメントを参照し、以下のようなyamlファイル(secretの定義2)を書き3、applyします
apiVersion: v1 kind: Secret metadata: name: gcpsm-secret labels: type: gcpsm type: Opaque stringData: secret-access-credentials: |- { ... ここにサービスアカウントのJSONファイルの内容を貼り付ける ... }
% kubectl apply -f gcpsm-secret.yaml
secret/gcpsm-secret created
ESOのSecretStoreを設定
シークレット管理サービス(今回はGCPのSecret Manager)へのアクセスを定義するリソースSecretStoreを作ります。
「Update secret store」の内容です
% # helm repo add external-secrets https://charts.external-secrets.io # Getting startedの際にやっていたので不要でした % helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace
gcpsm-secretのsecret-access-credentialsを参照するという指定です。
GCPのプロジェクトを指定するのが独特でした
% kubectl apply -f secret-store.yaml
secretstore.external-secrets.io/gcp-store created
GCPのSecret Managerで複数の秘密情報を保存したシークレットを作る
GCPのコンソールを操作して、Secret Managerでシークレットを作ります(external-secret-practiceと命名)。
設定した値は以下です。
JSON形式がポイント!
{ "password": "ひ・み・つ", "username": "name", "surname": "great-surname" }
GCP Secret Managerのシークレット(JSON形式)から秘密情報1つだけを指定してk8sのシークレットを作る
ここでESOのドキュメントの「Creating external secret」から離れます。
ドキュメントの例はGCPのSecret Managerでdatabase_username、database_passwordと2つのシークレットを作り4、それをまとめる形で1つのExternalSecretを作っています。
離れる理由ですが、ESOのドキュメントのやり方ではどんどんSecret Managerのシークレットが増えていきます。
例えば、DBのユーザ名とパスワードは関連するのでまとめておきたいですよね(AWSのSecrets Managerなら複数のキーと値からシークレットが作れますもんね)。
というわけで、Secret Managerでは1つのシークレットにまとめる前提で、ESOのExternalSecretを作る方法を知りたかったのでした。
結論を言うと、property
を指定して5Secret Managerのシークレットから1つの秘密情報を取り出せます!
% kubectl apply -f external-secret.yaml externalsecret.external-secrets.io/example created % kubectl get secret practice -n default -o jsonpath='{.data.password}' | base64 -d ひ・み・つ
GCP Secret Managerのシークレット(JSON形式)にまとめた秘密情報全部を持ったk8sのシークレットを作る
ESOのドキュメントの中のガイドに見つけました!
先の設定値のusernameとsurnameはこのドキュメントから取っているのです。
ここで使うのは、dataFrom
!
extract
と指定すると...
% kubectl apply -f external-secret.yaml externalsecret.external-secrets.io/example configured % kubectl get secret practice -o jsonpath='{.data.username}' | base64 -d name % kubectl get secret practice -o jsonpath='{.data.surname}' | base64 -d great-surname % kubectl get secret practice -o jsonpath='{.data.password}' | base64 -d ひ・み・つ
ExternalSecretをdataFromとextractを使って定義することで、Secret Managerのシークレット(JSON形式)のすべてのキーと値のペアがk8sのsecretになっています!🙌
お片付け
% kubectl delete -f external-secret.yaml -f secret-store.yaml -f gcpsm-secret.yaml % helm delete external-secrets --namespace external-secrets % kubectl delete ns external-secrets
Secret Managerのシークレットも消します
終わりに
ESOの素振り、GCPのSecret Manager篇でした。
P.S. GCPのSecret ManagerにJSON形式で指定に気づいたきっかけ
モブプロする中で気づいたのですが、非常に楽しかったですね(一緒に作業した方々に感謝)
- 一同「GCPのシークレットの設定値がわからん...」
- propertyを指定してみたが「key (propertyに指定したキー) does not exist in secret ...」
- Aさん「これもうESOのソース見るしかないんじゃ」
- 私「じゃあエラーメッセージで検索するとか?」
- GCPはここっぽい https://github.com/external-secrets/external-secrets/blob/v0.9.3/pkg/provider/gcp/secretmanager/client.go#L394
getDataByProperty
関数の実装を見よう- gjsonはGoでJSONを扱うライブラリ
- 一同「あ〜、JSONか〜」
記事にする中でAWS Secrets Managerを触ったことで、JSON形式というのはまあ妥当だな〜と私は思いました(利用者数が多いAWSの仕様に引っ張られている)
- 記事執筆時に参照したESOのドキュメントのバージョンはv0.9.3です↩
- stringDataの参考 設定ファイルを使用してSecretを管理する | Kubernetes↩
-
yaml中の
|-
ですが、YAMLの仕様 https://yaml.org/spec/1.2.2/ には「Example 8.4 Chomping Final Line Break」「Example 8.5 Chomping Trailing Lines」に例がありました。|
と違って末尾に改行が入らないようです("{}\n"
とならないのでJSONとしてパースできるという理解)↩ - これらはJSON形式にせずに、直接秘密情報を保存しているはずです。この記事の方法では、GCPにはdatabase-credentialsという1つのシークレットを作り、JSON形式でdatabase_usernameとdatabase_passwordを指定します。このシークレットをESOのExternalSecretで参照して、database_usernameとdatabase_passwordという2つのキーを持つsecretを作れます↩
- AWS Secrets ManagerはデフォルトがJSON形式での保存になるのもあって、Getting startedではpropertyを指定しているんですよね。ref: https://external-secrets.io/latest/introduction/getting-started/#create-your-first-externalsecret↩