Slide 1

Slide 1 text

Kubernetes(k8s)でシステム運用する際の シークレット情報の管理について調べてみた 2019年9月2日 プラットフォームサービス本部 クラウド基盤ソリューション部ソリューションアーキテクトチーム 秋葉 洋毅

Slide 2

Slide 2 text

自己紹介 1 秋葉 洋毅 (あきば ひろき) 会社:株式会社オージス総研 ※転職組で3社目 仕事:ITインフラエンジニア一筋 在住:茨城県 年齢:アラフォー

Slide 3

Slide 3 text

アジェンダ 2  k8sシークレット情報(DBパスワードなど)の管理と懸念点 ※前置  セキュアにk8sシークレット情報を管理する方法 ※AWS EKS脳ベース  それぞれの利用概要 ※間違っていたら御免なさい

Slide 4

Slide 4 text

3  k8sシークレット情報(DBパスワードなど)の管理と懸念点 ※前置  セキュアにk8sシークレット情報を管理する方法 ※AWS EKS脳ベース  それぞれの利用概要 ※間違っていたら御免なさい

Slide 5

Slide 5 text

k8sの標準的なシークレット管理機能 4  K8s secretリソース • k8sではデータベースなどに接続する際のユーザ名やパスワードなどの機密情報を、アプリコンテナなどのPod に環境変数やVolumeとして渡す際に利用するk8s secretリソース機能が提供されている  懸念点 • K8s secretリソースを生成するマニフェストファイル(例:secret.yml)は、base64でエンコードされている が暗号化されている訳ではないのでマニフェストファイルをgithubなどにそのままpushするのはNG apiVersion: v1 kind: Secret metadata: name: service01 namespace: default data: MYSQL_PASSWORD: YWJjZAo= MYSQL_ROOT_PASSWORD: cm9vdDEyMzQ1Njc4Cg== type: Opaque 例:secret.yml 「abcd」、「root12345678」の値がbase64でエンコードされて定義 “MYSQL_PASSWORD”: “abcd”, "MYSQL_ROOT_PASSWORD": "root12345678" service01 kubesec CLI # kubectl apply -f secret.yml push

Slide 6

Slide 6 text

5  k8sシークレット情報(DBパスワードなど)の管理と懸念点 ※前置  セキュアにk8sシークレット情報を管理する方法 ※AWS EKS脳ベース  それぞれの利用概要 ※間違っていたら御免なさい

Slide 7

Slide 7 text

k8sシークレットをセキュアに管理 # 技術要素 概要・手法 備考 1 Kubesec • Secretリソースのbase64値をkubesecで更に暗号/複合化 • CI/CDツール or 人手でkubesecで暗号化/複合化を制御 • CI/CDツール or 人手の操作環境からAWSやGCP KMSを利用 • Apache-2.0ライセンス • 1つのyamlファイルに1つのSecretリ ソースを定義 • KMS利用時はIAM権限を含むインター ネットアクセスが必要 2 Kubernetes- external- secrets • k8sクラスタ内でSecretリソースを生成する専用リソース環境(External Secrets controller)を準備 • AWS Secrets Mangerに登録したKey/Vaule(JSON形式)を透過的に取得し Secretリソースを生成 • オープンソース by GoDaddy Operating Company • 専用リソース環境はAWS Secrets Managerへのアクセス権(IAM)が必要 • GithubにはAWS Parameter Storeのサ ンプルも記載されているがNotサポー トだと思う 3 Sealed- secrets • Secretリソースのbase64値をkubesealで更に暗号/複合化 • K8sクラスタ内でSecretリソースを生成する専用リソース環境(Sealed Secrets Controller)を準備し、透過的にSecretリソースを生成 • 専用リソース環境で暗号/複合化の鍵管理が必要 • オープンソース by bitnami • 1つのyamlファイルに1つのSecretリ ソースを定義 • 専用Podのデータ保全を要顧慮 4 HashiCorp社 vault • 永続データストアを含むVaultサーバを導入(EC2、Podなど) • Vaultサーバに登録されたKey/Value値を認証トークンで取得 • アプリコンテナへのKey/Value値の連携方法例  証明書をアプリコンテナへk8s Service Account経由で連携  Vault Agent(Init Container) + Vault Consul(Sidecar)でVaultサーバ からKey/Vaule値を取得しアプリコンテナへ連携 • Vaultサーバ(Pod)導入Helmあり • Vaultサーバ(EC2)導入AWSクイックス タートあり • Secrets-Store-csi-driver(k8s v1.15以上 がサポート)も利用出来れば便利 • Vaultサーバ簡易検証(devモード) ※ 参 考 AWS Secret Manager • AWS Secret Manager/Parameter Store情報をアプリコンテナに環境変数 で連携 • アプリコンテナ側でAWS Secret Manager/Parameter Storeから直接取得 • AWS Secret ManagerへIAM権限でインターネットアクセス • アプリコンテナ側でAWS Secret Manager/Parameter Storeから直接情報 を取得する実装が必要 • 「github:aws-samples/aws- workshop-for-kubernetes」にあったの で挙げてみた AWS Parameter Store 私の個人的なスキルセットの都合上、AWS EKS利用前提でAWSマネージドサービスや OSSツールを組み合わせ、シークレット情報をセキュアに管理する方法をいくつか列挙

Slide 8

Slide 8 text

7  k8sシークレット情報(DBパスワードなど)の管理と懸念点 ※前置  セキュアにk8sシークレット情報を管理する方法 ※AWS EKS脳ベース  それぞれの利用概要 ※間違っていたら御免なさい

Slide 9

Slide 9 text

1. Kubesecの利用例(例:AWS KMSを利用) 8 AWS Cloud KMS kubesec CLI # kubesec encrypt –key=[AWS KMS ARN] secret.yml > secret.encrypt.yml push apiVersion: v1 data: MYSQL_PASSWORD: [KMSで暗号化された値] MYSQL_ROOT_PASSWORD: [KMSで暗号化された値] kind: Secret metadata: creationTimestamp: null name: mysql-env namespace: default # kubesec:v:3 # kubesec:aws:arn:aws:kms:us-east-1:56780097****:key/(省略):(省略) # kubesec:mac:JrtSkBkhEzuQSQY2.LMCxqi****(省略) kubesec CLI pull or CI/CD ツール # kubesec decrypt secret.encrypt.yml | kubectl apply –f - ①secret.yml(Base64状態)をkubesec cliで AWS KMSを使用し暗号化 IAM IAM ③暗号化されたsecret.encrypt.ymlをkubesec cliで AWS KMSで複合化後、k8sへapplyしsecretリソースを生成。 ②Githubなどに セキュアに保管 Namespace:default • Base64で暗号化されている値が、kubesec で更に暗号化されている。 • AWS KMS ARNの定義が内包されている。 secret-encrypt.yml mysql-env

Slide 10

Slide 10 text

2. Kubernetes-external-secretsの利用例 9 AWS Cloud kubectl / AWS CLI IAM Namespace:kubernetes-external-secrets Kubernetes-external-secrets # wget https://raw.githubusercontent.com/godaddy/kubernetes-external-secrets/master/external-secrets.yml yamlファイルのAWSリージョンを修正し 、 # kubectl apply -f external-secrets.yml Secrets Manager # aws secretsmanager get-secret-value --secret-id test01 --region us-east-1 | jq '.SecretString' | jq -r . apiVersion: 'kubernetes-client.io/v1 kind: ExternalSecret metadata: name: mysql-env namespace: deault secretDescriptor: backendType: secretsManager data: - key: test01 name: MYSQL_PASSWORD property: MYSQL_PASSWORD - key: test01 name: MYSQL_ROOT_PASSWORD property: MYSQL_ROOT_PASSWORD kubectl CLI Namespace:default mysql-env ① 事前に登録済みのAWS Secrets Managerシークレット情報を確認 ② kubernetes-external-secrets環境(CRD)を作成(helm installも可) ③ 「kind:ExternalSecret」のマニフェストを作成し、kubectl apply。 Kubernetes-external-secretsで透過的にsecretリソースを生成。 { "MYSQL_PASSWORD": “abcd", "MYSQL_ROOT_PASSWORD": "root12345678" } AWS Secret Managerの シークレットID、Key値を指定 service01-external-secret.yml push pull CI/CD ツール or # kubectl apply -f service01-external-secret.yml IAM

Slide 11

Slide 11 text

3. SealedSecretの利用例 10 Helm & kubectl CLI # helm install --name sealed-secrets --namespace kube-system stable/sealed-secrets # kubectl apply -f https://github.com/bitnami-labs/sealed-srecrets/releases/download/v0.8.1/controller.yaml kubeseal CLI # kubeseal --fetch-cert --controller-namespace=kube-system --controller-name=sealed-secrets > pub-cert.pem apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: creationTimestamp: null name: mysql-env namespace: deault spec: encryptedData: MYSQL_PASSWORD: [kubesealで暗号化された値] MYSQL_ROOT_PASSWORD: [kubesealで暗号化された値] template: metadata: creationTimestamp: null name: mysql-env status: {} secret-encrypt.yml push # kubectl apply -f secret-encrypt.yml kubectl CLI pull ①SealedSecretController環境(CRD)を作成 CI/CD ツール or Namespace:kube-system sealed-secrets sealed-secrets-controller Namespace:default sealedsecret/ mysql-env secret/ mysql-env ②Sealed Secret Controllerを指定し鍵を生成。 secret.yml(Base64状態)を暗号化。 ③暗号化されたsecret-encrypt.ymlをkubectl apply。 Sealed Secrets Controllerで透過的に複合化されたsecretリソースを生成。 # kubeseal --format=yaml --cert=pub-cert.pem < secret.yml > secret-encrypt.yml Base64で暗号化されている 値がSealedSecretで更に 暗号化されている。

Slide 12

Slide 12 text

4. HashiCorp Vaultをk8sで利用(Vaultサーバ導入編) 11  前提 • 私の個人的なスキルセットの都合上、AWSでHashiCorp Vaultサーバを動作 • まずはk8s環境でのvaultの使い方レベルを検証。なので、実際にVaultサーバを本番でどう構築、 運用していけばよいかの考慮はこれから  検証用途でVaultサーバの導入を行う選択肢 1. EC2上でVaultツールバイナリ(Linux版)をダウンロードしdevelopモードでVaultサーバを起動 (https://learn.hashicorp.com/vault/getting-started/install) (https://learn.hashicorp.com/vault/getting-started/dev-server) ⇒ とりあえず検証するのであれば十分 2. Vault Helm Chartでセットアップ (https://www.vaultproject.io/docs/platform/k8s/helm.html) ⇒ AWS EKS上に 「Standalone Server with Load Balanced UI」でhelm install試したが、 AWS CLBのヘルスチェックが一向にパスせず原因不明(要調査)。 3. coreos/vault-operatorでセットアップ (https://github.com/coreos/vault-operator) ⇒ 個人的にまだ未確認 4. HashiCorp Vault on AWSクイックスタート (https://aws.amazon.com/jp/quickstart/architecture/vault/) ⇒ Vault + Consulがセットで複数台のEC2がマルチAZで起動 ⇒ 検証用途というよりは本番環境での利用を意識したリッチな構成 5. etc

Slide 13

Slide 13 text

4. HashiCorp Vaultをk8sで利用(全体概要編) 12 参考) https://learn.hashicorp.com/vault/identity-access-management/vault-agent-k8s > Challenge 今回はEKSで動かしている 今回はEC2(vaultサーバ)で動かしている

Slide 14

Slide 14 text

4. HashiCorp Vaultをk8sで利用(シークレット取得編) 13 参考) https://learn.hashicorp.com/vault/identity-access-management/vault-agent-k8s > Step 4: Leverage Vault Agent Auto-Auth 今回はEKSで動かしている 今回はEC2(vaultサーバ)で動かしている  Vaultサーバからシークレット情報(Key/Value)を取得しアプリコンテナ(例:nginx)へ連携する概要 ① 事前にVaultサーバへk8s service accountトークンやKey/Value値などの設定をしておく ② アプリコンテナ + InitContainer(Vaultエージェント) + SideCar(Consul)をapply  Vaultエージェントがk8s service accountトークンでvaultサーバへの一時トークンを取得  Consulが一時トークンでvaultサーバへKey/Value値を取得しアプリコンテナへ連携 Init Container SideCar 任意のアプリコンテナ

Slide 15

Slide 15 text

14 4. HashiCorp Vaultをk8sで利用(設定ポイント編)  基本、HashiCorp learnサイトを参考に設定 • https://learn.hashicorp.com/vault/identity-access-management/vault-agent-k8s  HashiCorp learnサイトのVaultサーバからk8s認証の設定箇所 • サイト記載の以下「 “https://$K8S_HOST:8443”」箇所は、Minikubeで動かしているk8s masterのURLを前 提にしている。AWS EKSなどk8s稼働環境によって値が異なるので注意する。  HashiCorp learnサイトの「Step 4: Leverage Vault Agent Auto-Auth」の例では、InitContainer(vault- agent-auth)と、SideCar(consul-template)でvaultサーバからシークレット値を取得し、Volume経由でアプリコンテナ (nginx-container)へ、シークレット値を含むindex.htmlファイルを連携している。この仕組みを流用する事で、vaultサー バから取得するシークレット値を、任意のアプリコンテナへ任意のファイルで連携出来る。 # vault write auth/kubernetes/config ¥ token_reviewer_jwt="$SA_JWT_TOKEN" ¥ kubernetes_host="https://$K8S_HOST:8443" ¥ kubernetes_ca_cert="$SA_CA_CRT“ # kubectl cluster-info Kubernetes master is running at https://303EF9D10F488446E748D87827378187.gr7.us-east-1.eks.amazonaws.com 私のAWS EKS環境では、k8s masterのURLは以下。 これを「kubernetes_host」に指定する。 vault { renew_token = false vault_agent_token_file = "/home/vault/.vault-token" retry { backoff = "1s" } } template { destination = "/etc/secrets/test01.text" contents = <

Slide 16

Slide 16 text

まとめ 15  各ツールの選定判断の目安 • 社内ガバナンス的にAWSやGCPなどのパブリッククラウドサービスを利用してもよい • 鍵管理やシークレット管理をAWSやGCPなどのマネージドサービスに任せたい ⇒「kubesec」、「kubernetes-external-secrets」を検討 • 社内ガバナンス的にAWSやGCPなどのパブリッククラウドサービスの利用が出来ない • 鍵管理やシークレット管理を自分達でコントロールしたい ⇒「Sealed-secrets」、「HashiCorp vault」を検討

Slide 17

Slide 17 text

16 以上です。 ご清聴ありがとうございました。