GKEでのsecretの扱いにkubernetes-external-secretsを導入した話


ミクシィグループ Advent Calendar 2020 の25日目の投稿です。

こんにちは, @Taillookです。
普段の業務ではRailsやGo,React,GKEなどを触っています。

はじめに

k8sのマニフェストをGitリポジトリで扱う場合、secretの情報をセキュアな状態で管理する必要があります。
自分はkubesec,SealedSecretをこれまでに使ってきましたがkubesecではArgoCD等を使ったGitOpsとの併用がしづらかったり、SealedSecretでは暗号化後のファイルのレビューができないという理由で別の手段を探していました。
今回これらを解決する手段としてkubernetes-external-secretsがあると知り導入してみました。

kubernetes-external-secretsとは

Kubernetes External Secrets — GoDaddy Engineering Blog

kubernetes-external-secretsはGoDaddyのチームが開発した、AWSのSecret Manager等、k8sのクラスタ外部にあるsecret情報にアクセスしk8sのsecretとして扱うようにするソリューションです。

GKEへの導入

本家のHelmChartを手元にダウンロード

(これを使い続けるのはvertion追従しづらいので最新のmasterのChartを取得するコマンドを書いておくとよさそうです。

サービスアカウントの追加

Secret Managerのsecretmanager.versions.access権限のあるサービスアカウントを追加します。

kubernetes-external-secretsのChartにGCP Secret Managerのためのsecretを追加する

external-secretsのためのsecretsを設定するためGit管理できるようにテンプレートから生成できるようにします。

secret.yaml.template
apiVersion: v1
kind: Secret
metadata:
  name: external-secrets-secret
type: Opaque
stringData:
  gcp-creds.json: |-

service_account_key.jsonという名前で先ほど追加したサービスアカウントの鍵のjsonを作成し以下スクリプトでテンプレートからsecretのyamlを生成するようにしました。

create-secret.sh
#!/bin/sh
sed -i '' 's/^/    /g' service_account_key.json && cat service_account_key.json >> secret.yaml.template && cp secret.yaml.template secret.yaml

valuesにexternal-secrets-secretを追加する

valuesにある

# GOOGLE_APPLICATION_CREDENTIALS: /app/gcp-creds/gcp-creds.json

# filesFromSecret:
#   gcp-creds:
#     secret: gcp-creds
#     mountPath: /app/gcp-creds

のコメントを外し/app/gcp-creds/gcp-creds.jsonに設定したexternal-secrets-secretをマウントしGOOGLE_APPLICATION_CREDENTIALSから参照できるようにします。

この状態で

install-external-secrets.sh
#!/bin/sh
helm install external-secrets ./chart --skip-crds

を実行しexternal-secretsをインストールします

secretを適用する

GCP Secret Managerで画像のようにシークレットを作成します。

作成したシークレットの名前で以下のyamlのsecretが適用できます。
dataのkeyはGCPのSecret Managerで設定したシークレットの名前で、nameはk8sのsecretでの名前になり、versionが同一シークレット名内でのバージョンとなります。バージョンはlatestでも指定できます。

secret.yaml
apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: gcp-secrets-manager-example
spec:
  backendType: gcpSecretsManager
  projectId: GCP-project
  data:
    - key: GCP_PROJECT_RAILS_ENV
      name: RAILS_ENV
      version: 1

これでk8s内でsecretとして扱えるようになります。

まとめ

SealedSecretと比較して、key: GCP_PROJECT_RAILS_ENVのように記述でき、GCPコンソール上で平文で確認もできるのでyamlのレビューが可能になったので読めない文字列のapproveをしてsecret適用できなかった!という事態も少なくなり治安も良くなりました。
kubesecとの比較としてもsecretへの変換をk8s上でハンドルできるのでArgoCDを使ったGitOpsの相性が良くなる利点もあります。


GKEやKubernetesについてはまだまだ勉強不足なのでより深く知れたら良いなと常々感じています。
来年はKubernetes周りのコードリーディングとかしてみたいです。