© 2020 NTT DATA Corporation
どうやって決める?kubernetesでのシークレット管理方法
2020年9月8日
株式会社NTTデータ デジタル技術部
里木、山田
Cloud Native Days 2020 発表資料
情 報 種 別 : 公開
会 社 名 : (株)NTTデータ
情報所有者 : デジタル技術部
© 2020 NTT DATA Corporation 2
目次
1. プロフィール
2. 本セッションのゴール
3. シークレット管理方法の考察
4. 最後に
© 2020 NTT DATA Corporation 3
プロフィール (里木)
Tomohiko Satoki
所属:
株式会社NTTデータ
技術革新統括本部システム技術本部デジタル技術部
業務:
DevOps、クラウドネイティブに関するR&Dや社内技術支援に
従事。
© 2020 NTT DATA Corporation 4
プロフィール (山田)
Shinya Yamada
所属:
デジタル技術部
職歴:
入社以来、社内のR&D部隊に所属。2年前程から現所属にて、
社内のクラウドネイティブ関連の仕事に従事。CKA取得。
Kubernetes, CNCF, Golang, Spring Boot, ReactJS,
GraphQL等幅広く好き
© 2020 NTT DATA Corporation 5
本セッションのゴール
1. (もしかしたら)なんとなくやっているかもしれないk8s上でのシークレット管
理について、シナリオに合わせた管理方法を考察する
2. 明日からシークレット管理に対してイイ感じに実践できる
© 2020 NTT DATA Corporation 6
シークレットとは?
シークレットとは、
パスワード、SSHキー、APIキーなどの
保護されたデータにアクセスするための機密情報を指す
Kubernetesでは、これらのシークレットを扱うために
Secretリソースを標準的なリソースとして提供している
※以降、カタカナのシークレットは機密情報のことを表現する
KubernetesのリソースはSecretリソースと表現する
© 2020 NTT DATA Corporation 7
シークレットを管理しないといけないのか?
適切にシークレットを管理しないと
漏えいにより保護しているデータに不正にアクセスされ
個人情報漏洩、クレジット・口座番号の漏洩、
データの不正操作等
様々な被害に繋がってしまう
© 2020 NTT DATA Corporation 8
こんな経験ありませんか?
シークレット管理の方法って数多くあって、どれを使うと良いか迷う・・・
とりあえず、AWS使っているからExternal Secret使うか・・・?
Sealed Secret?
Vault?
© 2020 NTT DATA Corporation 9
シークレットを管理する際に検討すべき観点
1. シークレットへのアクセス権限の制御
2. シークレットの保存場所
3. シークレットの生成方法
4. シークレットの適用・利用方法
5. シークレットの暗号化/復号
システムのセキュリティ要件や開発・運用体制に応じて
適切なシークレット管理のための要件はそれぞれで、唯一解はない・・・
5つのシナリオをベースにシークレットの管理方法を考察していく
© 2020 NTT DATA Corporation 10
シナリオ1
少人数で全員が開発・運用に携わる。
イントラからのネットワークアクセスのみ。
検証目的など、短期的かつ限定的な提供で、すぐに破棄する。
コードもプライベート領域で管理されており、
プロジェクトメンバ以外は参照できない。
このくらいの用途であれば、特に考慮する点はない。
10
© 2020 NTT DATA Corporation 11
Secretリソースの適用
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
設定例(Secretリソース)
Secretマニフェストを作成・VCS等で管理、マニフェストを適用して
Secretリソースを作成する。
あるいは、kubectlコマンドでSecretを作成する。
Base64エンコードした値を記述
© 2020 NTT DATA Corporation 12
シナリオ2
少人数で全員が開発・運用に携わる。
短期で破棄せず、継続的に提供する。
コードが非プライベート領域で管理されており、プロジェクト外からアクセス可能。
12
© 2020 NTT DATA Corporation 13
Secretマニフェストを管理する上での問題点
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
設定例(Secretリソース)
$ echo YWRtaW4= | base64 -d
admin
$ echo MWYyZDFlMmU2N2Rm | base64 -d
1f2d1e2e67df
Base64でデコードは容易に可能なため、平文と同等
これを不特定のメンバが参照可能なVCSに保存しておくと、
誰でもシークレットにアクセスできる
© 2020 NTT DATA Corporation 14
何を行う必要があるか
ポイント 対策
アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロー
ル
保存場所 マニフェストに記述。VCS上で管理。
生成方法 -
適用・利用方法 Secretリソースとしてデプロイ
Secretマニフェストを暗号化して管理する
暗号化/復号 プロジェクト内メンバのみマニフェストの
暗号化・復号が可能
© 2020 NTT DATA Corporation 15
「シークレットへのアクセス権限の制御」
Secretリソースはkubernetes APIで取得するとbase64エンコードされた平
文が表示されてしまうため、RBACでsecretリソースへのアクセスを制限する必
要がある。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: [“pods"]
verbs: ["get”, “watch”, “list”]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get”]
設定例(Secretアクセス可)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-forbidden
rules:
- apiGroups: [""]
resources: [“pods"]
verbs: ["get”, “watch”, “list”]
設定例(Secretアクセス不可)
© 2020 NTT DATA Corporation 16
補足 ~Kubernetesのベストプラクティス~
引用:
https://kubernetes.io/ja/docs/concepts/configuration/secret/#%E3%83%99%E3%82%B9%E3%83%88%E3%83
%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9
© 2020 NTT DATA Corporation 17
kubesec : https://github.com/shyiko/kubesec
• Secretリソースのマニフェストの構造を保ったまま、値部分のみを暗号化する
• kubesecコマンドで対象のマニフェストを暗号化。これを管理する。
• クラスタに適用する前にkubesecコマンドでマニフェストを復号してから適用する必要がある
• 暗号鍵の管理にはPGP, 各種クラウドプロバイダ提供のKMSを利用可能
© 2020 NTT DATA Corporation 18
kubesecで暗号化されたSecretマニフェスト
apiVersion: v1
data:
password: YWRtaW4=
user: YWRtaW4=
kind: Secret
metadata:
name: mysecret
元secret例
apiVersion: v1
data:
password: 4fc++z(...省略...)+GQ==
user: Gr3wTI(...省略...)6RQ==
kind: Secret
metadata:
name: mysecret
# kubesec:v:3
# kubesec:pgp:(...省略...)
# kubesec:mac:(...省略...)
暗号化後(kubesec)
kubesecコマンドで暗号化
© 2020 NTT DATA Corporation 19
helm-secrets : https://github.com/zendesk/helm-secrets
• helmのパラメータを暗号化して管理するためのツール
• 暗号化にはsopsを利用しており、鍵管理にPGP, 各種クラウドプロバイダ提
供のKMSを利用可能
• helm-wrapperを利用することで暗号化されたパラメータが復号される
© 2020 NTT DATA Corporation 20
シナリオ3
不特定のメンバが開発に携わっている、
あるいは開発メンバが必ずしも運用まで行わない。
コードはパブリック領域などプロジェクト外からアクセスできる領域で管理。
復号に必要な秘密鍵を外部に持ち出せないようにして、
内部不正へのリスクを低減したい。
監査への対応もしなければならない。
20
© 2020 NTT DATA Corporation 21
リスク
デプロイを行うマシン上に秘密鍵を保管しておく必要がある
→不適切な秘密鍵の管理によって秘密鍵の漏洩。
シークレットの流出の可能性。
Secretリソースへのアクセス権限を持つアカウントからの
不適切なKubernetes API利用によるシークレットの流出
21
© 2020 NTT DATA Corporation 22
何を行う必要があるか
ポイント 対策
アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール
保存場所 マニフェストに記述。VCS上で管理。
生成方法 -
適用・利用方法 Secretリソースとしてデプロイ
Secretマニフェストを暗号化して管理する
シークレットへアクセスした際の監査ログを出力する
暗号化/復号 メンバはシークレットを暗号化できるが、復号することはできな
い
© 2020 NTT DATA Corporation 23
Kubernetes APIのaudit
Kubernetes APIに対するaudit(監査)ログを設定できる。
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# omit
- level: Metadata
resources:
- group: "" # core
resources: ["secrets", "configmaps"]
- group: authentication.k8s.io
resources: ["tokenreviews"]
omitStages:
- "RequestReceived"
設定例(Policy)
引用:
https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh
© 2020 NTT DATA Corporation 24
Kubernetes APIのaudit
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "a1ee7f24-0c8e-405a-a0e2-3e9b57c28f2d",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/default/secrets/test-secret",
"verb": "get",
"user": {
"username": "test-user",
"groups": [
"system:masters",
"system:authenticated"
]
},
"sourceIPs": [
"172.17.0.1"
],
"userAgent": "kubectl/v1.19.0 (linux/amd64) kubernetes/e199641",
"objectRef": {
"resource": "secrets",
"namespace": "default",
"name": "test-secret",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2020-09-06T01:13:50.019092Z",
"stageTimestamp": "2020-09-06T01:13:50.019756Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": ""
}
}
ログの出力例
アクセスしたユーザ
対象オブジェクト
© 2020 NTT DATA Corporation 25
Sealed Secrets : https://github.com/bitnami-labs/sealed-secrets
• クラスタ内にインストールしたSealedSecretsコントローラが鍵ペアを生成
• kubesealコマンドで公開鍵を取得し、Secretリソースのマニフェストを暗号化して
SealedSecretマニフェストに変換。これをVCSで管理する。
• 秘密鍵はクラスタ内にのみ存在し、復号はクラスタ内のSealedSecretsコントローラで
行われる。クラスタ外での復号はできない(SealedSecretKeyをバックアップした場合を
除く)
© 2020 NTT DATA Corporation 26
Sealed Secretsで暗号化されたSecretマニフェスト
apiVersion: v1
data:
password: YWRtaW4=
user: YWRtaW4=
kind: Secret
metadata:
name: mysecret
元secret例
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
spec:
encryptedData:
password: AgBVj(...省略...)LjIqWCA==
user: AgBkU(...省略...)XsW09A==
template:
metadata:
name: mysecret
暗号化後(SealedSecret)
kubesealコマンドで公開鍵を使って暗号化
© 2020 NTT DATA Corporation 27
キーローテーションとSealedSecretの再暗号化
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
spec:
encryptedData:
password: AgBSe(...省略...)UmEmiA==
user: AgA8o(...省略...)rUYfQ==
template:
metadata:
name: mysecret
再暗号化SealedSecret
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
spec:
encryptedData:
password: AgBVj(...省略...)LjIqWCA==
user: AgBkU(...省略...)XsW09A==
template:
metadata:
name: mysecret
SealedSecret(旧)
kubeseal --re-encryptで再暗号化
再暗号化は全てクラスタ内で行われる
© 2020 NTT DATA Corporation 28
シナリオ4
不特定のメンバが開発に携わっている、
あるいは開発メンバが必ずしも運用まで行わない。
コードはパブリック領域などプロジェクト外からアクセスできる領域で管理。
暗号化された情報の公開もしたくない。
監査への対応もしなければならない。
28
© 2020 NTT DATA Corporation 29
何を行う必要があるか
ポイント 対策
アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール
保存場所 認証が必要な保管場所、暗号化されたシークレット。
生成方法 -
適用・利用方法 Secretリソースとしてデプロイ
Secretマニフェストを暗号化して管理する
シークレットへアクセスした際の監査ログを出力する
暗号化/復号 暗号化、復号はシークレットマネージャ等の人手を介さない機
構で実施
© 2020 NTT DATA Corporation 30
Kubernetes External Secret : https://github.com/godaddy/kubernetes-external-secrets
• 開発者はシークレットのキーと、値を管理するシークレットマネージャの参照キーを記述した
ExternalSecretマニフェストを作成、管理する。
• クラスタ内にインストールされたExternalSecretsコントローラがシークレットマネージャから値を取
得し、Secretを作成する。
© 2020 NTT DATA Corporation 31
Kubernetes External Secretの特徴
開発者はシークレットマネージャの参照キーだけ知っていれば良く、シークレットを
知る必要がない
暗号化・復号、シークレットの管理をシークレットマネージャに任せることができる
シークレットローテーションなど、シークレットマネージャがサポートする機能を利用
可能
Secretリソースへのアクセスと、シークレットマネージャへのアクセスの監査ログを
記録することを推奨
© 2020 NTT DATA Corporation 32
シナリオ5
さらなるリスク低減への対応
個人情報や高換金情報などの機微(センシティブ)情報をあつかうシステムでは
より高いセキュリティ要件を満たす必要がある
次のページでリスクを考察していく
32
© 2020 NTT DATA Corporation 33
Secretリソースに存在するリスク
今までの方法はSecretリソースとして扱われるため、以下のリスクがある。シーク
レットをより強固に取り扱う、またはシークレットが漏洩した場合の対策を考慮し
て、リスクを低減する必要がある
引用:https://kubernetes.io/ja/docs/concepts/configuration/secret/
© 2020 NTT DATA Corporation 34
その他のリスク
上記までで色々対策してきても
シークレット自身が漏洩してしまうリスクはある
シークレットの漏洩リスクも想定した対応を考察してみる
© 2020 NTT DATA Corporation 35
何を行う必要があるか
ポイント 対策
アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール
保存場所 認証が必要な保管場所、暗号化されたシークレット。Secretリ
ソースにも残さず、リスクを減らす
生成方法 永続化されたり、人手を介したりしない方法で、自動生成やロー
テション
適用・利用方法 シークレットをアプリケーションからのみ利用可能。取得経由で
もシークレットが流出しない。アクセスした際の監査ログを出力す
る
暗号化/復号 暗号化、復号はシークレットマネージャ等の人手を介さない機構
で実施
© 2020 NTT DATA Corporation 36
Bank Vaultを使った方法の紹介
Bank Vaultを使った方法を紹介
Bank VaultはBanzai Cloudが提供しており
HashiCorp Vaultの利用・操作を
k8s上で簡単にするために
Vaultの様々なツールを提供するプロジェクト
https://github.com/banzaicloud/bank-vaults
36
© 2020 NTT DATA Corporation 37
補足
以降のページでは、Bank VaultとVaultの違いは明確に説明していない。
シークレットの保持、認証・認可などのアクセスコントロールといった
バックエンド側の機能はVault
シークレットを取得し、アプリケーションに渡す
クライアントの役割をBank Vault
と理解してもらえるとわかりやすいです。
© 2020 NTT DATA Corporation 38
Vaultを使った場合の「シークレットへのアクセス権限の制御」
path "secret/foo" {
capabilities = [“read”, “create”, “update”]
}
→ Role Aに割当
PolicyベースでVaultへのアクセスコントロール
path "secret/bar/*" {
capabilities = ["read"]
}
→ Role Bに割当
Role A
Role B
© 2020 NTT DATA Corporation 39
Vaultを使った場合の「シークレットの保存場所」、「シークレットの暗号化/復号化」
※Vault の推奨事項は対応しておくこと
https://learn.hashicorp.com/tutorials/vault/production-hardening
Key Shareからしきい値以上(例えば3/5のKey)の
KeyからMaster Keyを構成※「シャミアの秘密分
散法」
Master Keyからシークレットバックエンドを暗号化/
復号化するEncrypt Keyringを生成(暗号化/復
号化)
Encrypt Keyを使って、シークレットバックエンドを暗
号化/復号化
※「シャミアの秘密分散法」のもっと詳しい説明は、公
式ページを参照
https://www.vaultproject.io/docs/concepts/seal
© 2020 NTT DATA Corporation 40
Bank Vaultを使った場合の「シークレットの適用・利用方法」
シークレットの生成方法
→永続化されたり、人手を介したりしない方法で、
自動生成やローテション
まずはローテションしないケースから考察
© 2020 NTT DATA Corporation 41
Bank Vaultを使った場合の「シークレットの適用・利用方法」のシーケンス
シークレット取得経路は暗号
化され、また経路途中で他の
媒体を介さずアプリケーションに
シークレットを渡すことが可能
© 2020 NTT DATA Corporation 42
Bank Vaultによる機密情報の設定例 ~適用前~
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
# omit
spec:
containers:
- name: go-http-server
image: sample/go-http-server
env:
- name: XXX_SECRET
value: "vault:secret/data/service#XXX_SECRET"
applyするdeployment.yaml
Vaultで管理している情報へのパスを設定
© 2020 NTT DATA Corporation 43
Bank Vaultによる機密情報の設定例 ~適用後~
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Init Containers:
copy-vault-env:
Image:
banzaicloud/vault-env:1.4.0
Command: sh -c cp /usr/local/bin/vault-env /vault/
Mounts: /vault/ from vault-env (rw)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Containers:
hello:
Image: go-http-server ・・・
Command: /vault/vault-env
Args: /usr/local/bin/server
Environment: XXX_SECRET: vault:secret/data/service#XXX_SECRET
Mounts: /vault/ from vault-env (rw)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Volumes:
vault-env:
Type:
EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
適用された設定
kubectl describe po hello
「vault-env」という実行ファイルを、アプリケーションコ
ンテナにコピー
① Commandがbank vaultのwebhookにて上
書きされ、アプリケーション実行前に「vault-
env」を実行することでシークレットをアプリケー
ションプロセスの環境変数としてインジェクト。
② K8s API経由で取得できる情報にはシーク
レット情報は表示されない
①
②
© 2020 NTT DATA Corporation 44
「vault-env」は何をしているのか?
~~~~~~~~~~~~~~~~~~~~~~~~~~~
client, err := vault.NewClientWithOptions(
vault.ClientRole(os.Getenv("VAULT_ROLE")),
vault.ClientAuthPath(os.Getenv("VAULT_PATH")),
vault.ClientLogger(logrusadapter.NewFromEntry(logger)),
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
inject := func(key, value string) {
sanitized.append(key, value)
}
err = secretInjector.InjectSecretsFromVault(environ, inject)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
err = syscall.Exec(binary, entrypointCmd, sanitized)
vault-envのソースコード抜粋
Vaultにログイン
Kubernetes Auth Methodというものを使ってます。
後述します。
Vaultからシークレット情報を取得
当該プロセスの環境変数に設定するプログラムを実
行
シークレットが他のどこにも(etcdにも)格納されず
起動アプリケーションからのみ取得可能
© 2020 NTT DATA Corporation 45
Kubernetes Auth Method
KubernetesのServiceAccountに紐づくトークン(JWT)、クラスタ証明書を
利用して認証を行う。RoleをServiceAccount名、namespace名と対応付
けし、アクセスコントロールを行うことができる。
※詳しい仕組みは下記を参考
https://learn.hashicorp.com/tutorials/vault/agent-kubernetes
© 2020 NTT DATA Corporation 46
監査ログ
ログの出力先には「File」、「Syslog」、「Socket」に対応。
※https://www.vaultproject.io/docs/commands/audit
{"time":"2020-04-30T14:27:10.6656485Z","type":"response","auth":{"client_token":"hmac-
sha256:bd6dd75911924ab82f9dcfa7adae6b821423f0f6b02a5f00343247bde2671d67","accessor":"hmac-
sha256:a01c4d69aa0bc6ea78d41ab81f0780cccbb2594e820c5823214327fa1b8d1802","display_name":"roo
t","policies":["root"],"token_policies":["root"],"token_type":"service"},"request":{"id":"9714ba87-8309-dd3e-
148a-a14c0ece37af","operation":"update","client_token":"hmac-
sha256:bd6dd75911924ab82f9dcfa7adae6b821423f0f6b02a5f00343247bde2671d67","client_token_access
or":"hmac-
sha256:a01c4d69aa0bc6ea78d41ab81f0780cccbb2594e820c5823214327fa1b8d1802","namespace":{"id":"r
oot"},"path":"sys/audit/file","data":{"description":"hmac-
sha256:f7a8a9725741192d8fb6ac5eb77f1ebcfc73587f8074cbcfbf7142bd410d1547","local":false,"options":{"
file_path":"hmac-
sha256:5a1a68f1f918d45d09c286ea08ed0b3eacb1779a24ed2ded7a59e01749f6a0f9"},"type":"hmac-
sha256:b6fe76f7946efe0451b2451f058c5d736bfe71f8133ca086246a68c4429c78f8"},"remote_address":"10.
10.42.222"},"response":{}}
引用サンプル:
https://raw.githubusercontent.com/hashicorp/vault-guides/master/monitoring-troubleshooting/vault-audit.log
© 2020 NTT DATA Corporation 47
さらに
シークレットの生成方法
→永続化されたり、人手を介したりしない方法で、
自動生成やローテション
ローテーションすることでシークレットが漏洩した際の
リスクを低減する方法を考察
© 2020 NTT DATA Corporation 48
VaultのDynamic Secretを利用した「シークレットの生成方法」のシーケンス
© 2020 NTT DATA Corporation 49
アプリケーションからの「シークレットの適用・利用方法」
import (
"github.com/banzaicloud/bank-vaults/vault"
)
vaultClient, err := vault.NewClient(vaultRole)
if err != nil {
err = errors.Wrap(err, "failed to establish vault connection")
return "", err
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~
vaultCredsEndpoint := "database/creds/" + vaultRole
secret, err := vaultClient.Vault().Logical().Read(vaultCredsEndpoint)
if err != nil {
err = errors.Wrap(err, "failed to read db credentials")
return "", err
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~
secretRenewer, err :=
vaultClient.Vault().NewRenewer(&vaultapi.RenewerInput{Secret: secret})
if err != nil {
vaultClient.Close()
err = errors.Wrap(err, "failed to start db credential renewer")
return "", err
}
アプリケーションからの利用例
引用:https://banzaicloud.com/blog/vault-dynamic-secrets/
アプリケーションからシークレットを取得
シークレットは環境変数にも残らず
起動アプリケーションからのみ取得可能
アプリケーションからシークレットを取得
© 2020 NTT DATA Corporation 50
最後に
幾つかのシナリオから要件を5つの観点で整理し
対応策を考察してみました
シークレット管理のためのツールは様々出てきていますが
改めて皆さんのシナリオに当てはめて
適切なシークレット管理の検討のためのお役に立てれば幸いです
※シークレット管理のセキュリティ観点での考察でしたので、
他の観点で必要な対策や良いアプローチもあると思いますので、
参考情報として扱ってもらえればと思います。
50
© 2020 NTT DATA Corporation
© 2020 NTT DATA Corporation

どうやって決める?kubernetesでのシークレット管理方法(Cloud Native Days 2020 発表資料)

  • 1.
    © 2020 NTTDATA Corporation どうやって決める?kubernetesでのシークレット管理方法 2020年9月8日 株式会社NTTデータ デジタル技術部 里木、山田 Cloud Native Days 2020 発表資料 情 報 種 別 : 公開 会 社 名 : (株)NTTデータ 情報所有者 : デジタル技術部
  • 2.
    © 2020 NTTDATA Corporation 2 目次 1. プロフィール 2. 本セッションのゴール 3. シークレット管理方法の考察 4. 最後に
  • 3.
    © 2020 NTTDATA Corporation 3 プロフィール (里木) Tomohiko Satoki 所属: 株式会社NTTデータ 技術革新統括本部システム技術本部デジタル技術部 業務: DevOps、クラウドネイティブに関するR&Dや社内技術支援に 従事。
  • 4.
    © 2020 NTTDATA Corporation 4 プロフィール (山田) Shinya Yamada 所属: デジタル技術部 職歴: 入社以来、社内のR&D部隊に所属。2年前程から現所属にて、 社内のクラウドネイティブ関連の仕事に従事。CKA取得。 Kubernetes, CNCF, Golang, Spring Boot, ReactJS, GraphQL等幅広く好き
  • 5.
    © 2020 NTTDATA Corporation 5 本セッションのゴール 1. (もしかしたら)なんとなくやっているかもしれないk8s上でのシークレット管 理について、シナリオに合わせた管理方法を考察する 2. 明日からシークレット管理に対してイイ感じに実践できる
  • 6.
    © 2020 NTTDATA Corporation 6 シークレットとは? シークレットとは、 パスワード、SSHキー、APIキーなどの 保護されたデータにアクセスするための機密情報を指す Kubernetesでは、これらのシークレットを扱うために Secretリソースを標準的なリソースとして提供している ※以降、カタカナのシークレットは機密情報のことを表現する KubernetesのリソースはSecretリソースと表現する
  • 7.
    © 2020 NTTDATA Corporation 7 シークレットを管理しないといけないのか? 適切にシークレットを管理しないと 漏えいにより保護しているデータに不正にアクセスされ 個人情報漏洩、クレジット・口座番号の漏洩、 データの不正操作等 様々な被害に繋がってしまう
  • 8.
    © 2020 NTTDATA Corporation 8 こんな経験ありませんか? シークレット管理の方法って数多くあって、どれを使うと良いか迷う・・・ とりあえず、AWS使っているからExternal Secret使うか・・・? Sealed Secret? Vault?
  • 9.
    © 2020 NTTDATA Corporation 9 シークレットを管理する際に検討すべき観点 1. シークレットへのアクセス権限の制御 2. シークレットの保存場所 3. シークレットの生成方法 4. シークレットの適用・利用方法 5. シークレットの暗号化/復号 システムのセキュリティ要件や開発・運用体制に応じて 適切なシークレット管理のための要件はそれぞれで、唯一解はない・・・ 5つのシナリオをベースにシークレットの管理方法を考察していく
  • 10.
    © 2020 NTTDATA Corporation 10 シナリオ1 少人数で全員が開発・運用に携わる。 イントラからのネットワークアクセスのみ。 検証目的など、短期的かつ限定的な提供で、すぐに破棄する。 コードもプライベート領域で管理されており、 プロジェクトメンバ以外は参照できない。 このくらいの用途であれば、特に考慮する点はない。 10
  • 11.
    © 2020 NTTDATA Corporation 11 Secretリソースの適用 apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm 設定例(Secretリソース) Secretマニフェストを作成・VCS等で管理、マニフェストを適用して Secretリソースを作成する。 あるいは、kubectlコマンドでSecretを作成する。 Base64エンコードした値を記述
  • 12.
    © 2020 NTTDATA Corporation 12 シナリオ2 少人数で全員が開発・運用に携わる。 短期で破棄せず、継続的に提供する。 コードが非プライベート領域で管理されており、プロジェクト外からアクセス可能。 12
  • 13.
    © 2020 NTTDATA Corporation 13 Secretマニフェストを管理する上での問題点 apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4= password: MWYyZDFlMmU2N2Rm 設定例(Secretリソース) $ echo YWRtaW4= | base64 -d admin $ echo MWYyZDFlMmU2N2Rm | base64 -d 1f2d1e2e67df Base64でデコードは容易に可能なため、平文と同等 これを不特定のメンバが参照可能なVCSに保存しておくと、 誰でもシークレットにアクセスできる
  • 14.
    © 2020 NTTDATA Corporation 14 何を行う必要があるか ポイント 対策 アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロー ル 保存場所 マニフェストに記述。VCS上で管理。 生成方法 - 適用・利用方法 Secretリソースとしてデプロイ Secretマニフェストを暗号化して管理する 暗号化/復号 プロジェクト内メンバのみマニフェストの 暗号化・復号が可能
  • 15.
    © 2020 NTTDATA Corporation 15 「シークレットへのアクセス権限の制御」 Secretリソースはkubernetes APIで取得するとbase64エンコードされた平 文が表示されてしまうため、RBACでsecretリソースへのアクセスを制限する必 要がある。 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: secret-reader rules: - apiGroups: [""] resources: [“pods"] verbs: ["get”, “watch”, “list”] - apiGroups: [""] resources: ["secrets"] verbs: ["get”] 設定例(Secretアクセス可) apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: secret-forbidden rules: - apiGroups: [""] resources: [“pods"] verbs: ["get”, “watch”, “list”] 設定例(Secretアクセス不可)
  • 16.
    © 2020 NTTDATA Corporation 16 補足 ~Kubernetesのベストプラクティス~ 引用: https://kubernetes.io/ja/docs/concepts/configuration/secret/#%E3%83%99%E3%82%B9%E3%83%88%E3%83 %97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9
  • 17.
    © 2020 NTTDATA Corporation 17 kubesec : https://github.com/shyiko/kubesec • Secretリソースのマニフェストの構造を保ったまま、値部分のみを暗号化する • kubesecコマンドで対象のマニフェストを暗号化。これを管理する。 • クラスタに適用する前にkubesecコマンドでマニフェストを復号してから適用する必要がある • 暗号鍵の管理にはPGP, 各種クラウドプロバイダ提供のKMSを利用可能
  • 18.
    © 2020 NTTDATA Corporation 18 kubesecで暗号化されたSecretマニフェスト apiVersion: v1 data: password: YWRtaW4= user: YWRtaW4= kind: Secret metadata: name: mysecret 元secret例 apiVersion: v1 data: password: 4fc++z(...省略...)+GQ== user: Gr3wTI(...省略...)6RQ== kind: Secret metadata: name: mysecret # kubesec:v:3 # kubesec:pgp:(...省略...) # kubesec:mac:(...省略...) 暗号化後(kubesec) kubesecコマンドで暗号化
  • 19.
    © 2020 NTTDATA Corporation 19 helm-secrets : https://github.com/zendesk/helm-secrets • helmのパラメータを暗号化して管理するためのツール • 暗号化にはsopsを利用しており、鍵管理にPGP, 各種クラウドプロバイダ提 供のKMSを利用可能 • helm-wrapperを利用することで暗号化されたパラメータが復号される
  • 20.
    © 2020 NTTDATA Corporation 20 シナリオ3 不特定のメンバが開発に携わっている、 あるいは開発メンバが必ずしも運用まで行わない。 コードはパブリック領域などプロジェクト外からアクセスできる領域で管理。 復号に必要な秘密鍵を外部に持ち出せないようにして、 内部不正へのリスクを低減したい。 監査への対応もしなければならない。 20
  • 21.
    © 2020 NTTDATA Corporation 21 リスク デプロイを行うマシン上に秘密鍵を保管しておく必要がある →不適切な秘密鍵の管理によって秘密鍵の漏洩。 シークレットの流出の可能性。 Secretリソースへのアクセス権限を持つアカウントからの 不適切なKubernetes API利用によるシークレットの流出 21
  • 22.
    © 2020 NTTDATA Corporation 22 何を行う必要があるか ポイント 対策 アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール 保存場所 マニフェストに記述。VCS上で管理。 生成方法 - 適用・利用方法 Secretリソースとしてデプロイ Secretマニフェストを暗号化して管理する シークレットへアクセスした際の監査ログを出力する 暗号化/復号 メンバはシークレットを暗号化できるが、復号することはできな い
  • 23.
    © 2020 NTTDATA Corporation 23 Kubernetes APIのaudit Kubernetes APIに対するaudit(監査)ログを設定できる。 apiVersion: audit.k8s.io/v1 kind: Policy rules: # omit - level: Metadata resources: - group: "" # core resources: ["secrets", "configmaps"] - group: authentication.k8s.io resources: ["tokenreviews"] omitStages: - "RequestReceived" 設定例(Policy) 引用: https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh
  • 24.
    © 2020 NTTDATA Corporation 24 Kubernetes APIのaudit { "kind": "Event", "apiVersion": "audit.k8s.io/v1", "level": "Metadata", "auditID": "a1ee7f24-0c8e-405a-a0e2-3e9b57c28f2d", "stage": "ResponseComplete", "requestURI": "/api/v1/namespaces/default/secrets/test-secret", "verb": "get", "user": { "username": "test-user", "groups": [ "system:masters", "system:authenticated" ] }, "sourceIPs": [ "172.17.0.1" ], "userAgent": "kubectl/v1.19.0 (linux/amd64) kubernetes/e199641", "objectRef": { "resource": "secrets", "namespace": "default", "name": "test-secret", "apiVersion": "v1" }, "responseStatus": { "metadata": {}, "code": 200 }, "requestReceivedTimestamp": "2020-09-06T01:13:50.019092Z", "stageTimestamp": "2020-09-06T01:13:50.019756Z", "annotations": { "authorization.k8s.io/decision": "allow", "authorization.k8s.io/reason": "" } } ログの出力例 アクセスしたユーザ 対象オブジェクト
  • 25.
    © 2020 NTTDATA Corporation 25 Sealed Secrets : https://github.com/bitnami-labs/sealed-secrets • クラスタ内にインストールしたSealedSecretsコントローラが鍵ペアを生成 • kubesealコマンドで公開鍵を取得し、Secretリソースのマニフェストを暗号化して SealedSecretマニフェストに変換。これをVCSで管理する。 • 秘密鍵はクラスタ内にのみ存在し、復号はクラスタ内のSealedSecretsコントローラで 行われる。クラスタ外での復号はできない(SealedSecretKeyをバックアップした場合を 除く)
  • 26.
    © 2020 NTTDATA Corporation 26 Sealed Secretsで暗号化されたSecretマニフェスト apiVersion: v1 data: password: YWRtaW4= user: YWRtaW4= kind: Secret metadata: name: mysecret 元secret例 apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: name: mysecret spec: encryptedData: password: AgBVj(...省略...)LjIqWCA== user: AgBkU(...省略...)XsW09A== template: metadata: name: mysecret 暗号化後(SealedSecret) kubesealコマンドで公開鍵を使って暗号化
  • 27.
    © 2020 NTTDATA Corporation 27 キーローテーションとSealedSecretの再暗号化 apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: name: mysecret spec: encryptedData: password: AgBSe(...省略...)UmEmiA== user: AgA8o(...省略...)rUYfQ== template: metadata: name: mysecret 再暗号化SealedSecret apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: name: mysecret spec: encryptedData: password: AgBVj(...省略...)LjIqWCA== user: AgBkU(...省略...)XsW09A== template: metadata: name: mysecret SealedSecret(旧) kubeseal --re-encryptで再暗号化 再暗号化は全てクラスタ内で行われる
  • 28.
    © 2020 NTTDATA Corporation 28 シナリオ4 不特定のメンバが開発に携わっている、 あるいは開発メンバが必ずしも運用まで行わない。 コードはパブリック領域などプロジェクト外からアクセスできる領域で管理。 暗号化された情報の公開もしたくない。 監査への対応もしなければならない。 28
  • 29.
    © 2020 NTTDATA Corporation 29 何を行う必要があるか ポイント 対策 アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール 保存場所 認証が必要な保管場所、暗号化されたシークレット。 生成方法 - 適用・利用方法 Secretリソースとしてデプロイ Secretマニフェストを暗号化して管理する シークレットへアクセスした際の監査ログを出力する 暗号化/復号 暗号化、復号はシークレットマネージャ等の人手を介さない機 構で実施
  • 30.
    © 2020 NTTDATA Corporation 30 Kubernetes External Secret : https://github.com/godaddy/kubernetes-external-secrets • 開発者はシークレットのキーと、値を管理するシークレットマネージャの参照キーを記述した ExternalSecretマニフェストを作成、管理する。 • クラスタ内にインストールされたExternalSecretsコントローラがシークレットマネージャから値を取 得し、Secretを作成する。
  • 31.
    © 2020 NTTDATA Corporation 31 Kubernetes External Secretの特徴 開発者はシークレットマネージャの参照キーだけ知っていれば良く、シークレットを 知る必要がない 暗号化・復号、シークレットの管理をシークレットマネージャに任せることができる シークレットローテーションなど、シークレットマネージャがサポートする機能を利用 可能 Secretリソースへのアクセスと、シークレットマネージャへのアクセスの監査ログを 記録することを推奨
  • 32.
    © 2020 NTTDATA Corporation 32 シナリオ5 さらなるリスク低減への対応 個人情報や高換金情報などの機微(センシティブ)情報をあつかうシステムでは より高いセキュリティ要件を満たす必要がある 次のページでリスクを考察していく 32
  • 33.
    © 2020 NTTDATA Corporation 33 Secretリソースに存在するリスク 今までの方法はSecretリソースとして扱われるため、以下のリスクがある。シーク レットをより強固に取り扱う、またはシークレットが漏洩した場合の対策を考慮し て、リスクを低減する必要がある 引用:https://kubernetes.io/ja/docs/concepts/configuration/secret/
  • 34.
    © 2020 NTTDATA Corporation 34 その他のリスク 上記までで色々対策してきても シークレット自身が漏洩してしまうリスクはある シークレットの漏洩リスクも想定した対応を考察してみる
  • 35.
    © 2020 NTTDATA Corporation 35 何を行う必要があるか ポイント 対策 アクセス権限の制御 作業者やアプリケーションレベルのroleでのアクセスコントロール 保存場所 認証が必要な保管場所、暗号化されたシークレット。Secretリ ソースにも残さず、リスクを減らす 生成方法 永続化されたり、人手を介したりしない方法で、自動生成やロー テション 適用・利用方法 シークレットをアプリケーションからのみ利用可能。取得経由で もシークレットが流出しない。アクセスした際の監査ログを出力す る 暗号化/復号 暗号化、復号はシークレットマネージャ等の人手を介さない機構 で実施
  • 36.
    © 2020 NTTDATA Corporation 36 Bank Vaultを使った方法の紹介 Bank Vaultを使った方法を紹介 Bank VaultはBanzai Cloudが提供しており HashiCorp Vaultの利用・操作を k8s上で簡単にするために Vaultの様々なツールを提供するプロジェクト https://github.com/banzaicloud/bank-vaults 36
  • 37.
    © 2020 NTTDATA Corporation 37 補足 以降のページでは、Bank VaultとVaultの違いは明確に説明していない。 シークレットの保持、認証・認可などのアクセスコントロールといった バックエンド側の機能はVault シークレットを取得し、アプリケーションに渡す クライアントの役割をBank Vault と理解してもらえるとわかりやすいです。
  • 38.
    © 2020 NTTDATA Corporation 38 Vaultを使った場合の「シークレットへのアクセス権限の制御」 path "secret/foo" { capabilities = [“read”, “create”, “update”] } → Role Aに割当 PolicyベースでVaultへのアクセスコントロール path "secret/bar/*" { capabilities = ["read"] } → Role Bに割当 Role A Role B
  • 39.
    © 2020 NTTDATA Corporation 39 Vaultを使った場合の「シークレットの保存場所」、「シークレットの暗号化/復号化」 ※Vault の推奨事項は対応しておくこと https://learn.hashicorp.com/tutorials/vault/production-hardening Key Shareからしきい値以上(例えば3/5のKey)の KeyからMaster Keyを構成※「シャミアの秘密分 散法」 Master Keyからシークレットバックエンドを暗号化/ 復号化するEncrypt Keyringを生成(暗号化/復 号化) Encrypt Keyを使って、シークレットバックエンドを暗 号化/復号化 ※「シャミアの秘密分散法」のもっと詳しい説明は、公 式ページを参照 https://www.vaultproject.io/docs/concepts/seal
  • 40.
    © 2020 NTTDATA Corporation 40 Bank Vaultを使った場合の「シークレットの適用・利用方法」 シークレットの生成方法 →永続化されたり、人手を介したりしない方法で、 自動生成やローテション まずはローテションしないケースから考察
  • 41.
    © 2020 NTTDATA Corporation 41 Bank Vaultを使った場合の「シークレットの適用・利用方法」のシーケンス シークレット取得経路は暗号 化され、また経路途中で他の 媒体を介さずアプリケーションに シークレットを渡すことが可能
  • 42.
    © 2020 NTTDATA Corporation 42 Bank Vaultによる機密情報の設定例 ~適用前~ apiVersion: apps/v1 kind: Deployment metadata: name: hello spec: # omit spec: containers: - name: go-http-server image: sample/go-http-server env: - name: XXX_SECRET value: "vault:secret/data/service#XXX_SECRET" applyするdeployment.yaml Vaultで管理している情報へのパスを設定
  • 43.
    © 2020 NTTDATA Corporation 43 Bank Vaultによる機密情報の設定例 ~適用後~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Init Containers: copy-vault-env: Image: banzaicloud/vault-env:1.4.0 Command: sh -c cp /usr/local/bin/vault-env /vault/ Mounts: /vault/ from vault-env (rw) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Containers: hello: Image: go-http-server ・・・ Command: /vault/vault-env Args: /usr/local/bin/server Environment: XXX_SECRET: vault:secret/data/service#XXX_SECRET Mounts: /vault/ from vault-env (rw) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Volumes: vault-env: Type: EmptyDir (a temporary directory that shares a pod's lifetime) Medium: Memory 適用された設定 kubectl describe po hello 「vault-env」という実行ファイルを、アプリケーションコ ンテナにコピー ① Commandがbank vaultのwebhookにて上 書きされ、アプリケーション実行前に「vault- env」を実行することでシークレットをアプリケー ションプロセスの環境変数としてインジェクト。 ② K8s API経由で取得できる情報にはシーク レット情報は表示されない ① ②
  • 44.
    © 2020 NTTDATA Corporation 44 「vault-env」は何をしているのか? ~~~~~~~~~~~~~~~~~~~~~~~~~~~ client, err := vault.NewClientWithOptions( vault.ClientRole(os.Getenv("VAULT_ROLE")), vault.ClientAuthPath(os.Getenv("VAULT_PATH")), vault.ClientLogger(logrusadapter.NewFromEntry(logger)), ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ inject := func(key, value string) { sanitized.append(key, value) } err = secretInjector.InjectSecretsFromVault(environ, inject) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ err = syscall.Exec(binary, entrypointCmd, sanitized) vault-envのソースコード抜粋 Vaultにログイン Kubernetes Auth Methodというものを使ってます。 後述します。 Vaultからシークレット情報を取得 当該プロセスの環境変数に設定するプログラムを実 行 シークレットが他のどこにも(etcdにも)格納されず 起動アプリケーションからのみ取得可能
  • 45.
    © 2020 NTTDATA Corporation 45 Kubernetes Auth Method KubernetesのServiceAccountに紐づくトークン(JWT)、クラスタ証明書を 利用して認証を行う。RoleをServiceAccount名、namespace名と対応付 けし、アクセスコントロールを行うことができる。 ※詳しい仕組みは下記を参考 https://learn.hashicorp.com/tutorials/vault/agent-kubernetes
  • 46.
    © 2020 NTTDATA Corporation 46 監査ログ ログの出力先には「File」、「Syslog」、「Socket」に対応。 ※https://www.vaultproject.io/docs/commands/audit {"time":"2020-04-30T14:27:10.6656485Z","type":"response","auth":{"client_token":"hmac- sha256:bd6dd75911924ab82f9dcfa7adae6b821423f0f6b02a5f00343247bde2671d67","accessor":"hmac- sha256:a01c4d69aa0bc6ea78d41ab81f0780cccbb2594e820c5823214327fa1b8d1802","display_name":"roo t","policies":["root"],"token_policies":["root"],"token_type":"service"},"request":{"id":"9714ba87-8309-dd3e- 148a-a14c0ece37af","operation":"update","client_token":"hmac- sha256:bd6dd75911924ab82f9dcfa7adae6b821423f0f6b02a5f00343247bde2671d67","client_token_access or":"hmac- sha256:a01c4d69aa0bc6ea78d41ab81f0780cccbb2594e820c5823214327fa1b8d1802","namespace":{"id":"r oot"},"path":"sys/audit/file","data":{"description":"hmac- sha256:f7a8a9725741192d8fb6ac5eb77f1ebcfc73587f8074cbcfbf7142bd410d1547","local":false,"options":{" file_path":"hmac- sha256:5a1a68f1f918d45d09c286ea08ed0b3eacb1779a24ed2ded7a59e01749f6a0f9"},"type":"hmac- sha256:b6fe76f7946efe0451b2451f058c5d736bfe71f8133ca086246a68c4429c78f8"},"remote_address":"10. 10.42.222"},"response":{}} 引用サンプル: https://raw.githubusercontent.com/hashicorp/vault-guides/master/monitoring-troubleshooting/vault-audit.log
  • 47.
    © 2020 NTTDATA Corporation 47 さらに シークレットの生成方法 →永続化されたり、人手を介したりしない方法で、 自動生成やローテション ローテーションすることでシークレットが漏洩した際の リスクを低減する方法を考察
  • 48.
    © 2020 NTTDATA Corporation 48 VaultのDynamic Secretを利用した「シークレットの生成方法」のシーケンス
  • 49.
    © 2020 NTTDATA Corporation 49 アプリケーションからの「シークレットの適用・利用方法」 import ( "github.com/banzaicloud/bank-vaults/vault" ) vaultClient, err := vault.NewClient(vaultRole) if err != nil { err = errors.Wrap(err, "failed to establish vault connection") return "", err } ~~~~~~~~~~~~~~~~~~~~~~~~~~~ vaultCredsEndpoint := "database/creds/" + vaultRole secret, err := vaultClient.Vault().Logical().Read(vaultCredsEndpoint) if err != nil { err = errors.Wrap(err, "failed to read db credentials") return "", err } ~~~~~~~~~~~~~~~~~~~~~~~~~~~ secretRenewer, err := vaultClient.Vault().NewRenewer(&vaultapi.RenewerInput{Secret: secret}) if err != nil { vaultClient.Close() err = errors.Wrap(err, "failed to start db credential renewer") return "", err } アプリケーションからの利用例 引用:https://banzaicloud.com/blog/vault-dynamic-secrets/ アプリケーションからシークレットを取得 シークレットは環境変数にも残らず 起動アプリケーションからのみ取得可能 アプリケーションからシークレットを取得
  • 50.
    © 2020 NTTDATA Corporation 50 最後に 幾つかのシナリオから要件を5つの観点で整理し 対応策を考察してみました シークレット管理のためのツールは様々出てきていますが 改めて皆さんのシナリオに当てはめて 適切なシークレット管理の検討のためのお役に立てれば幸いです ※シークレット管理のセキュリティ観点での考察でしたので、 他の観点で必要な対策や良いアプローチもあると思いますので、 参考情報として扱ってもらえればと思います。 50
  • 51.
    © 2020 NTTDATA Corporation © 2020 NTT DATA Corporation