nikkie-ftnextの日記

イベントレポートや読書メモを発信

GCPのSecret Managerで1つのシークレットに複数の秘密情報を保存し、External Secrets Operatorで参照してk8sのsecretを作る(M1 Mac・Docker Desktopで動かす例)

はじめに

君と夏の終わり nikkieです。

先日のExternal Secrets Operator(ESO) Getting startedの素振りを踏まえて、もう少し手を動かしてみました。

目次

結論:GCPのSecret Managerで1つのシークレットに複数の秘密情報を保存し、External Secrets Operatorで参照する方法

  • GCPのSecret ManagerでJSON形式でシークレットを定義する
  • ESOのExternalSecretでは
    • propertyを指定すると、JSONから指定したキーと値のペアk8sのsecretにできる
    • dataFromのextractを指定すると、JSONキーと値のペアすべてk8sのsecretにできる

動作環境

Getting started素振り記事と同様です。

  • M1 MacmacOS 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篇でした。

  • GCPのSecret ManagerでJSON形式でシークレットを定義する(AWS Secrets Managerのように)
  • ESOのExternalSecretでは
    • propertyを指定すると、JSONから指定したキーと値のペアをk8sのsecretにできる
    • dataFromとextractを指定すると、JSONのキーと値のペアすべてをk8sのsecretにできる

P.S. GCPのSecret ManagerにJSON形式で指定に気づいたきっかけ

モブプロする中で気づいたのですが、非常に楽しかったですね(一緒に作業した方々に感謝)

記事にする中でAWS Secrets Managerを触ったことで、JSON形式というのはまあ妥当だな〜と私は思いました(利用者数が多いAWSの仕様に引っ張られている)


  1. 記事執筆時に参照したESOのドキュメントのバージョンはv0.9.3です
  2. stringDataの参考 設定ファイルを使用してSecretを管理する | Kubernetes
  3. yaml中の|-ですが、YAMLの仕様 https://yaml.org/spec/1.2.2/ には「Example 8.4 Chomping Final Line Break」「Example 8.5 Chomping Trailing Lines」に例がありました。|と違って末尾に改行が入らないようです("{}\n"とならないのでJSONとしてパースできるという理解)
  4. これらはJSON形式にせずに、直接秘密情報を保存しているはずです。この記事の方法では、GCPにはdatabase-credentialsという1つのシークレットを作り、JSON形式でdatabase_usernameとdatabase_passwordを指定します。このシークレットをESOのExternalSecretで参照して、database_usernameとdatabase_passwordという2つのキーを持つsecretを作れます
  5. AWS Secrets ManagerはデフォルトがJSON形式での保存になるのもあって、Getting startedではpropertyを指定しているんですよね。ref: https://external-secrets.io/latest/introduction/getting-started/#create-your-first-externalsecret