🐥

[Kubernetes]External Secrets Operator入門

2021/12/06に公開

これは何?

Kubernetes External Secrets(KES)がメンテナンス期に移行する(新機能の追加などが対応されなくなる)というアナウンスが出たため(以下ISSUE)、External Secrets Operator(ESO)へ移行するために調査したことをまとめました。
*KESがESOへの移行を推奨していたこともあり、今回は他のSecret管理ツールは検討せずESOについてのみ調べました。

https://github.com/external-secrets/kubernetes-external-secrets/issues/864

External Secrets Operatorとは

ESOはAWSなどの外部providerに保存された機密情報を取得してKubernetesのSecretリソースとして利用できるようにするためのCRDです。
KESと比べてドキュメントの充実度や設定の柔軟さが良いらしいです。ちなみにKESはJavaScriptで作られており、ESOはGolangで作られています。

https://github.com/external-secrets/external-secrets

2021年12月時点での各種外部providerのメンテナンス状況は以下のとおりです。
基本的にはalpha版なので利用する場合にはアップデート時の破壊的更新に特に注意が必要そうです(Kubernetesのエコシステムではalpha版の利用は割と仕方ないですね..)。

Provider Stability maintenance
AWS Secrets Manager alpha Internally maintained
AWS Parameter Store alpha Internally maintained
Hashicorp Vault stable Internally maintained
Google Cloud Secrets Manager alpha Internally maintained
Azure Key Vault alpha Community maintained
IBM Cloud Secrets Manager alpha Community maintained
Yandex Lockbox stable Community maintained
Gitlab Project Variables alpha Community maintained
Alibaba Cloud KMS alpha Community maintained
Oracle Vault alpha Community maintained
Akeyless alpha Community maintained

エコシステム

ESOは SecretStore (or ClusterSecretStore) と ExternalSecret というCRDを使うことで機密情報を外部providerから取得します。SecretStore (or ClusterSecretStore) は外部providerに対する認証を行い、ExternalSecret は参照したい機密情報の指定を行います。
KESでは以下のように ExternalSecret を用意すればよかったのでこの点では設計思想に違いがあり、ESOでは役割(認証とリソースの指定)毎にCRDを分けた形をとっています。

# KESではこれだけ定義すればよかった
apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
  name: hoge-secret
spec:
  backendType: systemManager
  roleArn: IAM_ROLE_ARN
  data:
  - name: name
    key: key

ESOの各リソースの役割は以下の図の通りです(External Secrets Operator API Overviewより拝借)。

AWSのParameter Storeなどを利用する場合には以下のようなイメージです(External Secrets Operator AWS Parameter Storeより拝借)。

SecretStore

SecretStoreでは取得したいリソースに対してどのように(どのproviderのどの認証方式で)アクセスするのかを定義します。

AWSのParameter Storeに対するアクセスを行いたい場合にはおよそ以下の設定が必要です。
認証にはIRSAを利用できるので基本的にはKESで利用していたリソースをそのまま転用できそうです。

apiVersion: external-secrets.io/v1alpha1
kind: SecretStore
metadata:
  name: secretstore-sample
spec:
  # 機密情報を保管しているproviderに対する設定を記載する
  provider:
    aws:
      # `ParameterStore` or `SecretsManager` が指定可能
      service: ParameterStore
      # Parameter Storeに対してアクセス時にAssumeRoleするためのIAM Role。
      # IRSAを経由して認証する場合には
      # IRSAのIAM Roleに必要な権限を指定することでこちらは無指定でも良さそう?(要検証)
      role: iam-role
      region: ap-northeast-1
      # AWSに対する認証を行うためのリソースを指定する
      auth:
       # IRSAを経由して認証する場合にはこれを使う
        jwt:
          serviceAccountRef:
            name: my-serviceaccount
       # Access Key ID, Secret Access Keyを経由して認証する場合にはこれを使う
        secretRef:
          accessKeyIDSecretRef:
            name: awssm-secret
            key: access-key
          secretAccessKeySecretRef:
            name: awssm-secret
            key: secret-access-key

---
# ServiceAccount経由での認証の場合にはServiceAccountを作成
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   annotations:
     # IAM Role側で `ssm:GetParameter` などの権限を付与しておくと良さそう
     eks.amazonaws.com/role-arn: <IAM_ROLE_ARN>
   name: my-serviceaccount
   namespace: xxxxx

ExternalSecret

取得したいリソースを定義することでKubernetesのSecretリソースとして機密情報が保存されます。
ExternalSecretは以下のタイミングでデータの更新(SecretStoreに問い合わせて機密情報を取得し、差分があれば更新)を行います。

  • .spec.refreshInterval の指定を経過した場合
  • .metadata.labels または .metadata.annotations に差分がある場合
  • .spec に差分がある場合

AWSのParameter Storeに対するアクセスを行いたい場合にはおよそ以下の設定が必要です。

apiVersion: external-secrets.io/v1alpha1
kind: ExternalSecret
metadata:
  name: example
  # `labels` と `annotations` は作成されるSecretにも引き継がれる
  labels:
    acme.org/owned-by: "q-team"
  annotations:
    foo: bar
spec:
  # 外部providerに対してデータ参照を行いSecretの値を更新する頻度
  refreshInterval: 1h
  # 該当データをどのように取得するかを定義したSecretStoreを指定する
  secretStoreRef:
    name: secretstore-sample
    kind: SecretStore
  # ExternalSecretから作成される `kind: Secret` リソースの情報を定義する
  # ExternalSecretにつき1つだけ定義できる
  target:
    # `kind: Secret` として作成されたリソースの名前であり、無指定の場合には `.metadata.name` が指定される。
    name: secret-to-be-created
    # `Owner`, `Merge`, `None` から指定する。デフォルトは `Owner`
    # `Owner` は Secretリソースを作成し、 `.metadata.ownerReferences` をセットする。
    # `Merge` は Secretリソースを作成しないが `.spec.data` の値をSecretリソースに反映させる
    # `None` は Secretリソースを作成しない(将来的にはinjectorとして利用可能になる想定)
    creationPolicy: Owner
  # key/valueで何のデータがほしいかを明示的に指定する
  data:
  - secretKey: secret-key-to-be-managed
    remoteRef:
      # parameter storeの場合にはpathを指定
      key: provider-key
  # 指定したものを一括で取得することもできる
  dataFrom:
  - key: remote-key-in-the-provider

Helm Chart

ESOのHelm Chartは以下で公開されています(ESOのGitHubのrootには charts 系のディレクトリが見当たらなかったので、以下を見るのが手っ取り早そうです)。

https://artifacthub.io/packages/helm/external-secrets-operator/external-secrets

設定値はKESと同じようなものが多いため、KESで利用していたもの(ServiceAccountなど)をある程度そのままこちらに移行できそうな雰囲気はあります。

その他

External Secrets のProjectを見ていると、KESからESOにマイグレーションしてくれるRepositoryがありました。現状ではまだ開発中とのことで今後に期待ですね。

https://github.com/external-secrets/kes-to-eso

まとめ

私にとっては初めてのライブラリ乗り換えのため戦々恐々としていましたが、調べたところESOに対する学習コストやリソースの作り直しは思ったよりは少なそうで安心しました(大本のProjectが同じというのも影響していると思います)。

みなさんも素敵なKubernetesライフをお過ごしください!

参考

ESO公式ドキュメント
https://external-secrets.io/

Discussion