進化したKubernetesのシークレット管理「External Secrets Operator」――シークレットを外部ツールで管理してGit上でもセキュアに使おう:Cloud Nativeチートシート(21)
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、外部のシークレット管理ツールと連携して、KubernetesのSecretオブジェクトを管理する「External Secrets Operator」を紹介する(External Secrets Operator 0.10.4、Kubernetes 1.30に合うように更新)。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。今回は外部のシークレット管理ツールと連携して、KubernetesのSecretオブジェクトを管理する「External Secrets Operator」を紹介します。
External Secrets Operatorを利用すれば、シークレットをGitでセキュアに管理でき、GitOpsとの親和性もバッチリです。
目次
External Secrets Operatorとは?
「External Secrets Operator」は、「AWS Secret」「GitLab Variable」などの外部ツールのシークレットを元にSecretオブジェクトを作成、管理できるフレームワークです。
特徴として、次の4つが挙げられます。
- 機密情報をYAMLに書かなくてよいので、シークレットに関する内容を安全にGitにコミットできる
- たくさんのシークレット管理ツールに対応している(「AWS SSMパラメータストア」「AWS Secrets Manager」「GCP Secret Manager」「Azure Key Vault」「GitLab Variable」など)
- 構成がシンプルで導入しやすい
- 設定ファイル内の特定の箇所(パスワード部分)に取得した内容を埋め込むなど、テンプレート機能を利用できる
特に1番目の特徴は重要です。Kubernetesには「Secret」というパスワードやトークンなどの機密情報を保持するオブジェクトがありますが、Secretのオブジェクト定義において、機密情報は暗号化されているわけではありません。文字列をただ「Base64」でエンコードしたものが記載されているので、オブジェクト定義を見られる人なら誰でも秘密情報の値を知ることができてしまいます。
そのため、シークレットのYAMLファイルは誰でも見られるソースリポジトリには配置することが難しく、例えばGitOpsをしたい場合には、シークレットは別の場所で分けて管理し、デプロイ時に組み合わせるなど作り込みで対応せざるを得ず、その管理、運用が困難でした。
External Secrets Operatorは、そんな課題を解決するために、外部のシークレット管理ツールと連携し、それらに保存されている機密情報を取得してシークレットを自動で作成します。そのため、ユーザーはオブジェクト定義情報に機密情報そのものを記載することなく、機密情報を管理できます。各種クラウドベンダーが提供しているシークレット管理サービスとも連携させることができ、多くの環境で利用可能です。
似たようなツールとして、過去には「Kubernetes External Secrets」(KES)が提供されていました。KES以外にも複数の類似のツールが、それぞれのシークレット管理ツールに合わせて開発されていましたが、それらを統合する動きの中で、JavaScriptで書かれたKESは標準化を進めることが難しく、Go言語で開発されたExternal Secrets Operatorが統合先として選ばれました。今ではKESは開発が止まり、下記リンクのissueにもある通り、External Secrets OperatorはKESの後継として推奨されています。
ここからはExternal Secrets Operatorの使い方を見ていきましょう。
External Secrets Operatorの構成
紹介するExternal Secrets Operatorは、下図のような構成になっています。
基本的には、「SecretStore」「ExternalSecret」の2つのオブジェクトから構成されます。図で色分けしている通り、SecretStoreとExternalSecretは、それぞれシークレット管理ツールとその各パラメーターに対応します。
SecretStoreは、外部のシークレット管理ツールと連携するためのオブジェクトで、例えばAmazon Web Services(AWS)のSSMパラメータストアサービスや、「GitLab」プロジェクトの情報を持ちます。
ExternalSecretは具体的なシークレットと結び付くオブジェクトです。先に説明したSecretStoreと連携して、「どの外部シークレット管理ツールから、どのパラメーターを取得するか」の情報と、それを元に「KubernetesのSecretオブジェクトをどのように作成するか」の情報を持ちます。図のAWS側の絵のように、1つのSecretStoreに複数のExternalSecretが参照することができ、シークレット管理ツールの複数のパラメーターを取り扱えます。
この後、具体的にExternal Secrets Operatorの使い方を説明しますが、この構成を頭の片隅に置きながら読んでいただくと、それらの関係性がより分かりやすいと思います。
External Secrets Operatorを使ってみよう
ここからはExternal Secrets Operatorを使ってみます。本記事では、下記のバージョンで動作を確認しています。
- External Secrets Operator:0.10.4
- Kubernetes(Amazon Elastic Kubernetes Service):1.30.0
インストール
External Secrets Operatorをインストールするには「Helmチャートを使う」「Operator Lifecycle Managerを使う」の2種類があります。今回は、Helmチャートを使う方法でインストールします。
次のコマンドを実行することで、簡単にインストールできます。
$ helm repo add external-secrets https://charts.external-secrets.io $ helm install external-secrets \ external-secrets/external-secrets \ -n external-secrets \ --create-namespace
インストールできたら、使いたいシークレット管理ツールに合わせて、SecretStoreとExternalSecretを作成していきます。
External Secrets Operatorは、クラウドのシークレットストアやGitLabなどのツールのシークレットストアなどをサポートしています。本稿ではクラウドの例としてAWS、ツールの例としてGitLabの2つのサンプルでExternal Secrets Operatorの使い方を見ていきます。
これら以外にも連携できるツールは数多くあるので、環境に合わせて使えます。詳細は下記、公式ドキュメントのメニューの中に「Provider」という項目があるので、その中から使いたいツールのページを参照してください。
AWSの場合
・SecretStoreの作成
External Secrets Operatorが参照する外部のシークレット管理ツールの情報(SecretStoreオブジェクト)を作成します。
AWSでは、SSMパラメータストアとSecrets Managerの2種類のシークレット管理ツールを連携させることができます。今回は、パラメータストアを利用します。
まず、Kubernetesからパラメータストアにアクセスできるように、ServiceAccountを作成しますが、下準備として、あらかじめ以下の設定の「AWS Identity and Access Management」(IAM)ポリシー「eks-eso-policy」を作成しておきます。
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "ssm:GetParameter*", "ssm:DescribeParameters" ], "Effect": "Allow", "Resource": "*" } ] }
IAMポリシーの作成については、公式ドキュメントをご参照ください。
次のコマンドを実行し、上記のIAMポリシーがアタッチされたIAMロールとServiceAccount「eso-serviceaccount」を作成して、それらをひも付けます。なお、コマンド中のARN(Amazon Resource Name)にはAWSアカウントが含まれているので、実行先環境に合わせて修正してから実行してください。
$ eksctl utils associate-iam-oidc-provider --cluster eks-sandbox --approve $ eksctl create iamserviceaccount \ --name eso-serviceaccount \ --cluster eks-sandbox \ --attach-policy-arn arn:aws:iam::123456789012:policy/eks-eso-policy \ --approve
これで、ServiceAccountの「eso-serviceaccount」で、パラメータストアにアクセスできるようになりました。
次に、SecretStoreを作成するために、以下のYAMLを用意します。先ほどの説明の通り、SecretStoreはシークレット管理ツールと連携するためのオブジェクトです。
SecretStoreのオブジェクト定義では、利用するシークレット管理ツールにアクセスするための設定だけを記載します。具体的なパラメーターは、この後、説明するExternalSecretオブジェクトで指定します。
apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: eso-secretstore-aws spec: provider: aws: service: ParameterStore region: us-east-1 auth: jwt: serviceAccountRef: name: eso-serviceaccount #先ほど作成したServiceAccountを指定する
YAMLを作成したらKubernetesに適用します。その結果SecretStoreが作成され、STATUSがValidかどうかを確認します。
$ kubectl apply -f eso-secretstore-aws.yaml $ kubectl get secretstore NAME AGE STATUS CAPABILITIES READY eso-secretstore-aws 18s Valid ReadWrite True
これで、AWSのパラメータストアをソースとするSecretStoreを作成できました。
・ExternalSecretを作成する
さて、シークレット管理ツールと連携させることができたので、次にExternalSecretを作成しましょう。以下のYAMLファイルを作成し、ExternalSecretオブジェクトを作成します。
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: eso-externalsecret spec: refreshInterval: 1h # シークレット管理ツールが更新をチェックする間隔 secretStoreRef: name: eso-secretstore-aws # 上で作成したSecretStoreを指定する kind: SecretStore target: name: secret-from-eso # 作成するシークレット名を指定する creationPolicy: Owner data: - secretKey: secretpassword # シークレットのキーを指定する remoteRef: key: password # パラメータストアのパラメーター名を指定する
YAMLをKubernetesに適用し、作成されたExternalSecretオブジェクトの「STATUS」が「SecretSynced」になっているかどうかを確認します。
$ kubectl apply -f eso-externalsecret.yaml $ kubectl get externalsecret NAME STORE REFRESH INTERVAL STATUS READY eso-externalsecret eso-secretstore-aws 1h SecretSynced True
最後に、ExternalSecretのオブジェクト定義の中で指定した名前のSecretオブジェクトが作成されていることを確認します。
$ kubectl get secret secret-from-eso NAME TYPE DATA AGE secret-from-eso Opaque 1 5s $ kubectl get secret secret-from-eso -o jsonpath='{.data}' {"secretpassword":"cGFzc3cwcmQxMjM="} $ kubectl get secret secret-from-eso -o jsonpath='{.data.secretpassword}' | base64 -d passw0rd123
無事に、ExternalSecretオブジェクトで指定したように、「secret-from-eso」というSecretオブジェクトが作成され、指定したキーでパラメータストアのパラメーターが格納されていることを確認できました。
ExternalSecretのYAMLは少しややこしいので、この後のページであらためて説明します。
GitLabの場合
クラウドプロバイダに設定した値を利用する例として、AWSの例を見てきました。次にツールの例として、GitLabのVariable(変数)からシークレットを生成します。
・SecretStoreの作成
GitLabではプロジェクトに設定した「Variable」をシークレットとして取得できます。Variableはプロジェクトのメニューの中から「Settings」→「CI/CD」を開き、その中の「Variables」で設定できます。
「Visibility」は「Visible」か「Masked」である必要があります。「Masked and hidden」 には対応していません。「Flags」の 「Protect variable」と「Expand variable reference」はどちらでも大丈夫です。
コラム GitLabではProject Access Tokenの利用を推奨
GitLabと連携させるには、事前にアクセストークンを作成する必要があり、固定のシークレットをKubernetes内部に直接保有する必要が出てきてしまいます。一般的に、アクセストークンは使い捨てが前提の仕組みです。GitLabのアクセストークンはProof of Possessionにも対応しておらず、「Bearer」で固定なシークレットは本質的に安全ではありませんので使用は推奨しません。
他にもExternal Secret Operatorでは、Secret StoreへのアクセスにBearerなシークレットを使用するストアのサポートが幾つか提供されております。可能であればクライアント証明書などの安全な認証方式が選択できるストアを利用してください。
External Secret Operatorの公式ドキュメントでは、GitLabのSecret Storeを使用する際に「Personal Access Tokens」を使用する方法が案内されておりますが、このトークンはアクセス先のプロジェクトを制限できず、そのユーザーのアクセス権がある範囲全てにアクセスできてしまうので、セキュリティ上問題があります。使用してしまうと、Kubernetesがマルウェアに感染した場合などに全く関係ない他のプロジェクト(アクセストークン発行者がアクセスできる全プロジェクト)のシークレットまで流出しかねないので、代わりにプロジェクトごとに閉じたアクセス権で発行できる「Project Access Tokens」を使用してください。
それでは、プロジェクト設定の「Access Tokens」から連携用のアクセストークンを作成してみましょう。
アクセストークンを作成する際には「トークンに、どの権限を割り当てるか」を設定する必要があります。External Secret Operatorの利用に当たっては、ロールは「Maintainer」で、スコープは「read_api」の権限があれば十分です。
注:このread_api権限により、参照系のかなり多くのAPIが実行できてしまうので、GitLabの他の機能(Gitリポジトリやwikiなど)を使用しているプロジェクトだと、想定していない情報へのアクセスを許してしまう懸念があります。Secret Storeとして利用する際は、 「Ultimate」プランの有償機能「カスタムロール」を使用して、詳細なアクセス権を制限するか、Secret Store専用のプロジェクトとして、環境ごとに空のプロジェクトを新規で作成し、最小権限の原則にのとって運用することを推奨します。
トークンを作成したらそれを参照できるようにSecretオブジェクトを作成します。
apiVersion: v1 kind: Secret metadata: name: gitlab-secret labels: type: gitlab type: Opaque stringData: token: glpat-xxxxxxxxxxxxxxxxxxxx # 作成したアクセストークンを入れる
$ kubectl apply -f gitlab-secret.yaml
次にSecretStoreを作成します。SecretStoreの作成には、プロジェクトID(プロジェクト名ではなく、IDの数字)が必要です。プロジェクトIDはプロジェクトの「Settings」→「General」で確認できます。
プロジェクトIDを確認したら、それを用いてSecretStoreを作成します。
apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: eso-secretstore-gitlab spec: provider: gitlab: url: https://gitlab.com/ # GitLabのURL指定する auth: SecretRef: accessToken: name: gitlab-secret # 先ほど作成したシークレットの情報を指定する key: token projectID: "12345"
作成したYAMLを適用し、SecretStoreのSTATUSがValidかどうかを確認します。
$ kubectl apply -f eso-secretstore-gitlab.yaml $ kubectl get secretstore NAME AGE STATUS READY eso-secretstore-gitlab 8s Valid True
これでGitLabプロジェクトのVariableをソースとするSecretStoreを作成できました。
なお、GitLabのアクセストークンには有効期限があります。有効期限が切れると当然SecretStoreがGitLabプロジェクトにアクセスできなくなるので、エラーになります。その場合には、SecretStoreが以下の状態になり、イベントからも有効期限が切れたことが分かります。
$ kubectl get secretstore NAME AGE STATUS READY eso-secretstore-gitlab 6d ValidationFailed False $ kubectl describe secretstore eso-secretstore-gitlab Name: eso-secretstore-gitlab (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ValidationFailed 27m (x25 over 43m) secret-store could not verify if the client is valid: GET https://gitlab.com/api/v4/projects/123456/variables: 401 {error: invalid_token}, {error_description: Token was revoked. You have to re-authorize from the user.}
アクセストークンの有効期限が切れてしまった場合でも、作成済みのSecretオブジェクトが削除されることはありません。
ただし、GitLab側のVariableの値を変更しても追従させることができなくなるので、定期的にアクセストークンの再発行が必要です。再発行したら、GitLabのアクセストークンを格納しているSecretオブジェクト(本稿ではgitlab-secretが該当)を、新たなアクセストークンで更新します。
特にSecretStoreやExternalSecretについては変更や再作成する必要はなく、新たなアクセストークンを用いて継続して利用できます。
・ExternalSecretの作成
SecretStoreを作成したら、後はAWSの場合と同じです。以下のYAMLファイルを作成し、ExternalSecretオブジェクトを作成します。
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: eso-externalsecret spec: refreshInterval: 1h # シークレット管理ツール側の更新をチェックする間隔 secretStoreRef: name: eso-secretstore-gitlab # SecretStoreを指定する kind: SecretStore target: name: secret-from-eso # 作成するシークレット名を指定する creationPolicy: Owner data: - secretKey: secretpassword # シークレットのキーを指定する remoteRef: key: password # 「CI/CD variables」のKey名を指定する
YAMLを適用し、作成されたExternalSecretオブジェクトのSTATUSがSecretSyncedになっていることを確認します。
$ kubectl apply -f eso-externalsecret.yaml $ kubectl get externalsecret NAME STORE REFRESH INTERVAL STATUS READY eso-externalsecret eso-secretstore-gitlab 1h SecretSynced True
最後に、ExternalSecretのオブジェクト定義で指定した名前のSecretオブジェクトが作成されていることを確認します。
$ kubectl get secret secret-from-eso NAME TYPE DATA AGE secret-from-eso Opaque 1 5s $ kubectl get secret secret-from-eso -o jsonpath='{.data}' {"secretpassword":"cGFzc3cwcmQxMjM="} $ kubectl get secret secret-from-eso -o jsonpath='{.data.secretpassword}' | base64 -d passw0rd123
GitLabの場合も、Variableの値を元にシークレットを作成できました。
ExternalSecretの各参照先の関係性
ここまでの例で、External Secrets Operatorを使ってAWSやGitLabからシークレット情報を取得できました。ExternalSecretオブジェクトのYAMLには、多くの参照先があり、少し複雑なので、あらためて図で振り返ります。
図中の番号が付いている各項目は以下の内容を指定しています。
【1】secretStoreRefには、「どのシークレット管理ツールから情報を取得するか」を指定するために、作成したSecretStoreの名前を設定します。
【2】targetには、作成するSecretオブジェクトの名前を設定します。
【3】dataのsecretKeyには、Secretオブジェクトに含めるシークレットデータのキー名を設定します。【2】で作成するSecretオブジェクトの中に、このsecretKeyで指定したキー名を持つシークレット情報が作成されることになります。
【4】dataのremoteRefにはシークレット管理ツールに保管されているシークレット情報のキー名を設定します。AWSパラメータストアであればパラメーター名、GitLabであれば変数名を設定することになります。
YAMLを振り返ってみると、ExternalSecretのYAMLの中には、機密情報が一切含まれていないことが分かります。これならGitにコミットしても、具体的なパスワードは分からないので、安全にシークレット情報を扱えます。
ExternalSecretの運用上の注意点
ExternalSecretのオブジェクト定義自体には機密情報は含まれず、ソースコードとしては安全に扱えますが、ここまでの例にもあったように、External Secrets OperatorはExternalSecretオブジェクトが作成されると、それにひも付いたSecretオブジェクトを作成します。作成されたSecretオブジェクトに関しては、シークレット情報はBase64でエンコードされているだけなので、その中身を見ることができれば、簡単にシークレット情報をデコードし、内容を見ることもできてしまいます。
そのため、External Secrets Operatorを使う場合でも、Secretオブジェクトへのアクセス権限管理はこれまで同様重要です。Secretオブジェクトに対するRBAC(Role Based Access Control)は確実に設定し、必要な参照元からのみ参照できるように制御しましょう。
コラム Kubernetesでシークレットを管理するツールたち
今回紹介しているExternal Secrets Operatorは外部のシークレット管理ツールと連携して機密情報を取り扱いますが、他のアプローチで機密情報を取り扱うソリューションも幾つかあります。
代表的なものとして、「Sealed Secrets」「HashiCorp Vault」を紹介します。
名前 | 特徴 | 利点 | 注意点 |
---|---|---|---|
Sealed Secrets | Kubernetesクラスタで暗号鍵を持つ。その暗号鍵で暗号化された文字列を適用すると、復号してSecretオブジェクトを作成する | 使い方がシンプル。外部ツールに依存せず、Kubernetesクラスタ単体で完結する | 複数のクラスタにまたがるシークレット管理が大変。Secretオブジェクトを作成するので、シークレットが読めるユーザーは機密情報を読めてしまう。暗号鍵を紛失したり、クラスタが破損したりすると、復号できなくなるので、鍵の管理が必要 |
External Secrets Operator | シークレット管理できる外部ツールと連携して、そこから機密情報を取得しSecretオブジェクトを作成する | 使い方がシンプル。既にシークレット管理ツールを利用している場合やクラウド環境の場合、簡単に導入できる(Vaultからも情報取得可能) | Secretオブジェクトを作成するので、シークレットが読めるユーザーは機密情報を読めてしまう。シークレット管理するためのツールは別で用意する必要がある |
HashiCorp Vault | Secretオブジェクトを作ることなく、Pod作成時にサイドカーコンテナが機密情報をPodに注入する | Secretを作成しないのでエンドツーエンドでセキュアに機密情報を扱える | 他の2つに比べて構成や仕組みが複雑。Vault自体の管理が必要 |
便利な使い方
External Secrets Operatorは、単に外部のシークレット管理ツールに格納されたデータを取ってくるだけでなく、Secretオブジェクトを便利に作成する機能が充実しています。その中から幾つかの機能を紹介します。
テンプレート機能
これまでの例では、シークレット管理ツールで保管されているデータをそのままシークレットにしていました。テンプレート機能を使うことで、あらかじめ作っておいたテンプレート文字列を元に、その一部を取得したシークレット情報に差し替えてシークレットとして作成することができます。
テンプレート機能を利用する場合は、以下のように「.spec.target.template」に作成したいSecretオブジェクトのテンプレート情報を設定します。
テンプレート中に{{.シークレットキー名}}のように、「.spec.data」で設定したシークレットキーの名前を入れる(頭にピリオドが付いていることに注意)ことでSecretオブジェクトを作成するときに、シークレット管理ツールから取得した値に置き換えてくれます。
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: secret-template spec: refreshInterval: 1h secretStoreRef: name: eso-secretstore kind: SecretStore target: name: secret-from-template template: type: kubernetes.io/Opaque data: # multiline string properties: | spring: datasource: url: jdbc:postgresql:{{.dbhost}}/{{.dbname}} username: {{.dbuser}} password: {{.dbpass}} data: - secretKey: dbhost remoteRef: key: mysecret-dbhost - secretKey: dbname remoteRef: key: mysecret-dbname - secretKey: dbuser remoteRef: key: mysecret-dbuser - secretKey: dbpass remoteRef: key: mysecret-dbpass
YAMLを作成したら、下記コマンドでExternalSecretオブジェクトを作成し、中身を確認してみましょう。
$ kubectl apply -f secret-template.yaml $ kubectl get secret NAME TYPE DATA AGE secret-from-template kubernetes.io/Opaque 1 25m $ kubectl get secret secret-from-template -o jsonpath='{.data}' {"properties":"c3ByaW5nOgogIGRhdGFzb3VyY2U6CiAgICB1cmw6IGpkYmM6cG9zdGdyZXNxbDpleGFtcGxlLmNvbTo1NDMyL3Rlc3RkYgogICAgdXNlcm5hbWU6IHRlc3R1c2VyCiAgICBwYXNzd29yZDogZGJwYXNzd29yZAo="} $ kubectl get secret secret-from-template -o jsonpath='{.data.properties}' | base64 -d spring: datasource: url: jdbc:postgresql:example.com:5432/testdb username: testuser password: dbpassword
なお外部シークレット管理ツールには、下記のシークレット情報が格納されているものとします。
パラメーター名 | 値 |
---|---|
mysecret-dbhost | example.com:5432 |
mysecret-dbname | testdb |
mysecret-dbuser | testuser |
mysecret-dbpass | dbpassword |
先ほど作成したテンプレートと見比べてみてください。テンプレートの変数部分が、取得した値に置き換えられていることを確認できます。
後は、この作成したSecretオブジェクトをPodにマウントすれば、シークレット文字列が埋め込まれた設定ファイルとして扱うこともできます。
さらにテンプレート機能では、幾つかの関数を利用でき、シークレット情報を加工して埋め込むことも可能です。興味がある方は下記公式ドキュメントをご参照ください。
注:上記公式マニュアルでは、テンプレートのYAMLで"engineVersion: v2"を設定するようになっていますが、engineVersionを指定しなくてもデフォルトでv2のテンプレートエンジンが利用されます。本稿ではengineVersionの設定を省略していますが、動作はv2を指定した場合と同じです。
複数のパラメーターを同時に取得する
ここまでは、利用するパラメーターを一つ一つ指定していました。場合によっては、複数のパラメーターをまとめて1つのシークレットに格納したいケースもあるでしょう。
例えば、先ほどの例のように特定のアプリケーションのパラメーターなら、それを明示的に示すように同一のプリフィックスを付与するような命名規則を用意していることは、よくあるケースだと思います。
パラメーター名 | 値 |
---|---|
mysecret-dbhost | example.com:5432 |
mysecret-dbname | testdb |
mysecret-dbuser | testuser |
mysecret-dbpass | dbpassword |
その場合は、下記YAMLのように「dataFrom」を利用すると、regexpにマッチしたパラメーターをまとめて取得できます。regexpは文字列として明示するためにダブルクオートで囲みます。
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: eso-externalsecret spec: refreshInterval: 1h secretStoreRef: name: eso-secretstore kind: SecretStore target: name: secret-from-eso creationPolicy: Owner dataFrom: - find: name: regexp: "mysecret" # マッチさせたいキー名の正規表現
これを適用すると、下記のように「mysecret」を含む各キーのパラメーターが、作成された1つのシークレットにまとめて格納されていることを確認できます。
$ kubectl get secret secret-from-eso -o jsonpath='{.data}' | jq { "mysecret-dbhost": "ZXhhbXBsZS5jb206NTQzMg==", "mysecret-dbname": "dGVzdGRi", "mysecret-dbpass": "ZGJwYXNzd29yZA==", "mysecret-dbuser": "dGVzdHVzZXI=" }
regexpに指定する文字列ですが、文字列だけを入れた場合は部分一致となり、「mysecret-xxxx」「yyyy-mysecret」など、mysecretを含むキーが全てマッチします。正規表現が利用できるので、前方一致にしたい場合には"^mysecret"とすることで、mysecretから始まるパラメーターだけをマッチさせることが可能です。
この複数のパラメーターを取得する方式をサポートしないシークレットストアも存在しますが、先述のAWSのパラメータストア、GitLabの「CI/CD Variables」はどちらも対応しています。
ところで、シークレット管理ツールでパラメーターとして管理する分には、プリフィックスがあると分かりやすいですが、アプリケーションで利用する場合は「そのままキー名にしてしまうと、冗長」という場合もあるかもしれません。
正規表現を基にまとめてキーを取得した場合、通常はシークレット管理ツールのパラメーター名がSecretオブジェクトのキーになりますが、キーのリライトルールを用いることができます。リライトルールは指定したルールで、シークレットに格納する際のキー名を書き換えることができます。
これを利用することで、共通部分を取り除いたり、逆に共通文字列(環境識別子など)を付与したりすることができます。
リライトルールを使ったYAMLの例はこちらです。
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: eso-externalsecret spec: refreshInterval: 1h secretStoreRef: name: eso-secretstore # SecretStoreを指定する kind: SecretStore target: name: secret-from-eso # 作成するシークレット名を指定する creationPolicy: Owner dataFrom: - find: name: regexp: "^mysecret" rewrite: - regexp: source: "mysecret-(.*)" # 書き換え前の文字列 target: "$1" # 書き換え後の文字列
リライトルールでは、プログラミング言語で正規表現を利用する場合と同様に、()で囲んだ部分の正規表現にマッチした文字列を、グループとして置換時に参照できます。「target」で参照する場合は、前から順番に「$1」「$2」というように「$n」とすることでn番目の文字列グループに置き換えることができます。
上のYAMLの例では、共通部分である"mysecret-"以外の部分にマッチさせ、マッチした部分をtargetで利用しています。つまり、"mysecret-"を除いた文字列をtargetに指定しているということです。
期待通りに動いているかどうかを確認してみましょう。
$ kubectl get secret secret-from-eso -o jsonpath='{.data}' | jq { "dbhost": "ZXhhbXBsZS5jb206NTQzMg==", "dbname": "dGVzdGRi", "dbpass": "ZGJwYXNzd29yZA==", "dbuser": "dGVzdHVzZXI=" }
先ほどの例と見比べてみましょう。期待通りに共通部分である"mysecret-"が除かれた内容がキー名になっていることを確認できます。
まとめ
Kubernetesを利用する上で、避けて通ることはできないシークレット管理。External Secrets Operatorを利用することで簡単に外部のシークレット管理ツールと連携してシークレット情報をKubernetesに取り込むことが可能になります。
Kubernetesにおけるシークレット管理に悩んでいる方は、External Secrets Operatorを試してみてはいかがでしょうか。
■更新履歴
【2024/12/12】External Secrets Operator 0.10.4、Kubernetes 1.30に合うように更新しました。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
コンテナ実行基盤「Kubernetes」の構成要素とエコシステムを解説――ネットワーク、シークレット管理の仕組み
コンテナオーケストレーションツールとして知られる「Kubernetes」とHashiCorpが提供する「Nomad」を比較検証する本連載。第2回はKubernetesを用いたクラスタ構築の手順やKubernetesの構成要素についてネットワーク、シークレット管理を中心に解説します。コンテナを保護するための10のベストプラクティス、InfraCloudが解説
InfraCloudが、アプリケーションコンテナのセキュリティを確保するための10のベストプラクティスを解説した。「マイクロサービスに出遅れた」ところは、先人から何を学べるか
これまでマイクロサービスアーキテクチャに取り組んだ組織の多くは、試行錯誤を重ねて、自らの組織における最適解を見いだしている。いま、マイクロサービスを考える人たちは、先人から何を学べばいいのだろうか。