1クール続けるブログ

とりあえず1クール続けるソフトウェアエンジニアの備忘録

sealed-secrets 学んだ

記事一覧はこちら

背景・モチベーション

ArgoCD導入時に、リポジトリk8sクラスタの認証情報といったセンシティブな情報をk8sのSecretとして保存する必要が出てきました。さらにそれらをGitOpsで管理しなければなりません。 SecretをマニフェストとしてGitリポジトリに平文のまま置いておくのはリスクです。 セキュリティを担保するための方法として、いくつか方法があるなかで sealed-sectets を学ぼうと思いました。

Kubernetes secretsの管理方法

weave worksのこちらの記事を参考にしています

Built-in の secrets

kubectlを使って値を取り出すことは難しくはありません。Base64エンコードされているだけのためデコードすれば内容は見れてしまいます。 Secretsはk8sクラスタのetcdサーバに平文で保存されます。etcdがTLS通信使うように設定されていない場合は、etcdクラスタが同期しているときに通信内容が見えてしまいます。 また、nodeへのrootアクセスができる人は、kubeletになりすますことで全てのsecretsを読み取ることが出来ます。

そのため、セキュリティ要件がゆるゆるな場合を除いて、3rd Partyを利用した方が良いとのことです。

クラウドベンダが提供するマネージドストア

既にクラウドベンダの提供するSecretsのマネージドサービスを利用している場合やすぐに運用を開始したい場合で、かつベンダーロックインが気にならない場合には良い選択肢になります。

  • AWS Secrets Manager
  • Cloud KMS
  • Azure Key Vault

OSSのシークレットマネージャ

物理サーバでの運用を行っている場合または、クラウドベンダによるロックインを避けたい場合にはこの選択肢を取ることになる。

  • Vault
  • Sealed Secrets

Vaultは高機能で多くのk8sユーザが利用しているようです。 Vaultや上記のクラウドのソリューションは、シークレットデータのための second source of truth を導入する形となります。これはGitの外で管理されており、完全に追跡されない別の潜在的クラスタへの変更や障害のソースです(機械翻訳みたいな文章になってしまった)。これはトラブルシューティングを複雑にしレビュープロセスにバックドアを作ります。

Sealed Secretsは、この問題に取り組むために設計されたものだそうです。 Kubernetesオーケストレーションの利点である、「設定が宣言的な json または yaml ファイルのセットに基づいており、バージョン管理に簡単に保存できること = Gitリポジトリsingle source of truth 」に則るように出来ています。

GitOpsで運用する際には、Sealed Secretsは強い選択肢になりそうです。

Sealed Secrets

概要

github.com

Sealed Secretsは下記の2つのコンポーネントから構成されます

  • クラスタで動くController / Operator
  • クライアントで動かすツール kubeseal

kubeseal は 非対称鍵暗号方式 でシークレットを暗号化します。これはControllerのみ復号することができます。暗号化されたシークレットは SealedSecrets の中でエンコードされます。 暗号化された安全な認証情報をGitの設定ファイルに直接格納し共有することができますが、それらのユーザは認証情報にアクセスすることができません。セキュアなGitOpsワークフローに適する方法です。

導入

kustomizeやHelmといった導入方法がありますが、今回は下記の手段で導入していこうと思います。

  • クラスタサイド → kustomize(yaml
  • クライアントサイド → wget(バイナリをダウンロード)

環境としては、Katacodaのk8s Playgroundを利用します

$ VERSION=v0.14.1

# クライアントサイド
$ wget https://github.com/bitnami-labs/sealed-secrets/releases/download/${VERSION}/kubeseal-linux-amd64 -O kubeseal
$ sudo install -m 755 kubeseal /usr/local/bin/kubeseal
$ kubeseal --version
kubeseal version: v0.14.1

# クラスタサイド
$ curl -s "https://raw.githubusercontent.com/\
kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
$ mv /root/kustomize /usr/local/bin/kustomize
$ mkdir kustomize && cd kustomize
$ wget https://github.com/bitnami-labs/sealed-secrets/releases/download/${VERSION}/controller.yaml
$ kustomize create --resources controller.yaml # 本来なら更にoverrideするファイルなども作成する
$ kustomize build | kubectl apply --server-side -f -

# 作成
# Secretリソースのファイル作成
$ echo -n hogehoge | kubectl create secret generic repo-password --dry-run=client --from-file=password=/dev/stdin -o json >repo-password-secret.json
# SecretリソースからSealedSecret作成
$ kubeseal <repo-password-secret.json >repo-password-sealedsecret.json
$ kubectl apply -f repo-password-sealedsecret.json
$ kubectl get secret # Secretが作成されていることを確認

GitOpsにのせるときには、SealedSecretをファイルとして作成して、Gitリポジトリで管理することになります。

kubeseal はControllerから公開鍵を取得してデータを暗号化し、Controller側で復号してSecretを作成します。暗号化の処理に関しては、将来、KMSのようなクラウドの暗号化ソリューションにオフロードできるようになることが示唆されています。

既存のSecretをSealedSecretに移行したい場合には、既存のSecretに http://sealedsecrets.bitnami.com/managed: "true" というアノテーションが必要です。

実運用に乗っけるときには、鍵のローテーションにも注意が必要です。 デフォルトは30日ごとに更新されます。ただ、ローテーションされた後も、古い公開鍵で暗号化したものは古い秘密鍵によって復号されますので再暗号化を行なわくてはいけません。 秘密鍵が外部に漏れてしまったケースにおいては、暗号化対象の機密情報自体も更新しないと攻撃されてしまいます。その際、SealedSecretも合わせて鍵の更新を行う必要があります。

ちなみに秘密鍵は下記のようなコマンドで簡単に取得できてしまうそう Secretリソースに関するRBACはガチガチにしておく必要がありますね

$ kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml >master.key

GitOpsに適した機密情報の運用について学べました!業務がやりやすくなりそうです。以上!