はじめまして、ACS 事業部の埜下です。
みなさんは Kubernetes のシークレットはどのように管理されていますか?
先日、HashiCorp 社から「Vault Secrets Operator」がプレビュー公開されました。 また、2023/2 には HCP Vault on Azure が GA しました。
そこで、今回はシークレット管理についてお伝えしつつ、Vault Secrets Operator と HCP Vault on Azure を組み合わせたシークレット管理の動作確認の内容についてもお伝えします。
はじめに
シークレット管理の必要性
「シークレット管理をする必要があるの?」と思われる方もいらっしゃるかもしれません。 そこで、はじめにシークレット管理の必要性について説明します。
コンテナで動くアプリケーションは他のサービス/システムと連携するために「ユーザ名/パスワード」や「トークン」といったシークレットを使います。
Kubernetes では Secret
というリソースでシークレットを表現しています。
たとえば、データベースに接続するためのユーザ名とパスワードを持たせた Secret リソースは以下のように表現できます。
apiVersion: v1 kind: Secret metadata: creationTimestamp: "2023-04-12T04:52:50Z" name: db-secret namespace: default type: Opaque data: username: aG9nZQ== password: ZnVnYQ==
こちらには username: hoge
と password: fuga
という認証情報を設定しています。
このマニフェストで password
と username
は一見暗号化されているように見えますが、これらは base64 エンコードされただけの文字列なので簡単に値を参照できてしまいます。
$ kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d fuga
そのため、他のリソースのマニフェストと同じように Git などで Secret のマニフェストをバージョン管理してしまうと情報漏洩に繋がる恐れがあります。 とは言え、Secret を手動で作成することは運用的によろしくないことは想像に難くないです。
そこで、安全に Secret リソースを Kubernetes 上にデプロイするために「シークレット管理」が必要になってきます。
Vault Secrets Operator について
それでは、どのような「シークレット管理」の方法があるでしょうか。 Kubernetes では以下のようなシークレット管理のエコシステムが公開されています。
それぞれの仕組みについては本記事では割愛させていただきます。
また、 HashiCorp 社からは「HashiCorp Vault (以下、Vault)」 と Kubernetes を統合する「Vault Sidecar Agent Injector」や「Vault Container Storage Interface (CSI) provider」という方法が公開されています。
Vault Sidecar Agent Injector は、サイドカーパターンを利用して Vault と連携する「Vault Agent コンテナ」を Pod 内にデプロイします。 Pod 内のアプリケーションコンテナは Vault Agent コンテナが Vault から取得したシークレットを共有ストレージ経由で参照できます。
Vault CSI provider は Secrets Store CSI Driver という機能を使って、Vault から取得したシークレットをボリュームとして Pod に見せることができます。
上記に加えて、先日新たに「Vault Secrets Operator」というシークレット管理が公開されました。
既存の方法と同じく、Vault Secrets Operator は Vault に格納されたシークレットを Kubernetes へ同期する機能をもっています。
それでは、HashiCorp から公開されている 3 種類の方法にはどのような違いがあるのでしょうか。
ちょうどよいタイミングで HashiCorp 公式ブログに比較記事が投稿されましたので詳細はそちらにお任せして、本記事では 1 点だけ Vault Secrets Operator が他と異なる点をお伝えします。
それは、「Deployment リソースなどをローリングアップデートしてシークレットを反映させることができる」という点です。 これについては動作確認の中で説明します。
また、Vault Secrets Operator では 3 種類のシークレットを扱うことができます。
- 静的シークレット (Static Secret)
- 動的シークレット (Dynamic Secret)
- PKI シークレット
今回は「静的シークレット」を対象に動作確認しています。
HCP Vault on Azure について
つぎに、「HCP Vault on Azure」について説明します。
HCP Vault は HashiCorp Cloud Platform (HCP) 上で提供されるフルマネージドな Vault のサービスです。 元々、HCP Vault は AWS 上にデプロイする方法しかなく、他のクラウドとはセキュアに連携することができませんでした。
HashiCorp 社は HCP をマルチクラウドに対応させることが目標ということらしく、2023/2 に HCP Vault が Azure に対応しました。
具体的には、HCP では HashiCorp Virtual Network (HVN) というものを使ってネットワークを構築し、そのネットワーク上に Vault などのプロダクトをデプロイします。
この HVN が Azure にも対応した、ということで「HCP Vault on Azure 」という表現がされています。
今回の目的
以上のように、Vault Secrets Opertor という新しいシークレット管理の方法が公開され、HCP Vault も Azure とセキュアに接続されるようになりました。
そこで、本記事では「AKS にインストールした Vault Secrets Operator から Azure のネットワークを介して HCP Vault に接続してシークレットを同期できるか確認する」と、「読者が同じような環境を構築できるアウトプットにする」ことを目的として検証をおこないます。
そのため作業の説明が多いところがございますが、ご了承ください。
また、ぜひ実際に構築してみていただき、手順どおりにいかなった等がございましたらご連絡いただけますと幸いです。
前提条件
今回ご紹介する手順では以下のコマンドを使用しています。 手順を実行される場合は、これらのコマンドが実行可能な環境をご準備ください。
- Azure CLI
- Terraform
- kubectl
- helm
環境構築
それでは、動作確認のための環境を構築していきます。
構築の流れは以下のようになります。
- HashiCorp Virtual Network 作成
- HCP Vault クラスタ作成
- AKS クラスタ作成
- Vault Secrets Operator インストール
- HCP Vault の認証設定
HashiCorp Virtual Network 作成
HCP Vault クラスタを作る前に、HashiCorp Cloud Platform (HCP) 上のサービスが使用する「HashiCorp Virtual Network (HVN)」という仮想ネットワークを作成します。
まずは HashiCorp Cloud Platform にログインします。 もし初めてログインする場合は、アカウントを作成したうえで Organization も作成してください*1。
Organization が表示されたら、左メニューの [HashiCorp Virtual Network] から [Create network] を選択します。
HVN 作成画面では以下のように設定しました。
項目 | 設定 |
---|---|
Network name | demo-hvn |
Provider | Microsoft Azure |
Region selection | Japan East (japaneast) |
CIDR block | 172.25.16.0/20 |
HVP Vault は Azure 東日本リージョンにも対応しているようですね。
5 分ほど待つと作成されます。
「This network is not fully configured. Create a peering connection to connect to your Azure infrastructure.」というメッセージの通り、HVN を使うためには Azure VNet とピアリングが必要です。
作成した HVN を選択すると左メニューに [Peering connections] が表示されるので、こちらからピアリングを設定していきます。 各項目にはピアリング先の Azure の情報を入力します。
項目 | 設定 |
---|---|
Connection ID | demo-hvn |
Azure tenant ID | Azure AD のテナント ID |
Azure subscription ID | Azure サブスクリプション ID |
Resource group name | ピアリングする VNet のリソースグループ |
VNet name | ピアリングする VNet 名 |
もし各項目の参照元が分からなければ「Where can i find this?」から Azure Portal のどこを見ればよいか分かるようになってます、とても親切ですね。
ピアリングを設定するとピアリング詳細ページを見れるようになりますが、設定直後は「Peering connection is pending」と「Create a route」という 2 つの警告メッセージが表示されます。
これは、Azure 側のピアリング設定ができていないことと、HVN のルートテーブルに Azure 向きのルートを作成していないためです。
それでは、それぞれの設定をしていきましょう。
Azure VNet ピアリング
Azure の VNet から HVN にピアリングを設定する方法は 2 種類あり、それぞれ実行するスクリプトは HCP ウェブコンソール上に表示されます。
- Terraform
- Azure Cloud Shell
そのはずですが、なぜか Azure Cloud Shell のほうは画面に表示されませんでした……。
そのため、今回は Terraform を使って Azure VNet にピアリングを設定します。
Terraform の場合は以下のような内容が HCP ウェブコンソールに表示されます。 内容を見てみると、サービスプリンシパルとピアリングに関するロールを作成することが分かります。 Terraform で直接ピアリングの設定をするわけではないようですね。
locals { application_id = "00000000-0000-0000-0000-000000000000" role_def_name = join("-", ["hcp-hvn-peering-access", local.application_id]) vnet_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hcp-vault-azure-demo/providers/Microsoft.Network/virtualNetworks/vnet-hcp-vault-azure-demo" } resource "azuread_service_principal" "principal" { application_id = local.application_id } resource "azurerm_role_definition" "definition" { name = local.role_def_name scope = local.vnet_id assignable_scopes = [ local.vnet_id ] permissions { actions = [ "Microsoft.Network/virtualNetworks/peer/action", "Microsoft.Network/virtualNetworks/virtualNetworkPeerings/read", "Microsoft.Network/virtualNetworks/virtualNetworkPeerings/write" ] } } resource "azurerm_role_assignment" "role_assignment" { principal_id = azuread_service_principal.principal.id role_definition_id = azurerm_role_definition.definition.role_definition_resource_id scope = local.vnet_id }
こちらを terraform
コマンドを実行可能な環境に保存して実行します。
しばらくすると HVN と Azure VNet のピアリングが完了します(私の環境では 15 分ほど掛かりました)。
HVN ルートテーブル
続きまして、HVN のルートテーブルを設定します。
項目 | 設定 |
---|---|
Route ID | demo-route |
Destinations | 172.16.2.0/24 |
Destinations
には HVN の CIDR と重ならないネットワーク範囲を指定します。
こちらはすぐに反映されます。
NSG 作成
これで HVN の設定も完了かと思いきや、最後に NSG の設定があります。
Azure 側のピアリング設定と同様、設定用のコマンドが HCP ウェブコンソールに表示されるのでこちらを使用します。
注意点としては、2023/4/12 時点でこちらの NSG 設定用コマンドに不備があるようで、Outbound の 401 というプライオリティが重複しています。 そのため、一部修正してから実行するようにしてください。
また、こちらのコマンドは対象の NSG 自体は作成しないため、あらかじめ作成しておいてください。
az
コマンドを実行可能な環境でスクリプトを実行します。
もしくはスクリプトの内容を Terraform に落とし込んで実行してもよいかもしれません。
HVN_CIDR="172.25.16.0/20" RESOURCE_GROUP_NAME=hcp-vault-azure-demo SECURITY_GROUP_ID=nsg-hcp-vault-azure-demo # Create inbound rules az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name ConsulServerInbound \ --priority 400 \ --source-address-prefixes "$HVN_CIDR" \ --destination-address-prefixes VirtualNetwork \ --destination-port-ranges 8301 \ --direction Inbound \ --access Allow az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name ConsulClientInbound \ --priority 401 \ --source-address-prefixes VirtualNetwork \ --destination-address-prefixes VirtualNetwork \ --destination-port-ranges 8301 \ --direction Inbound \ --access Allow # Create outbound rules az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name ConsulServerOutbound \ --priority 400 \ --source-address-prefixes VirtualNetwork \ --destination-address-prefixes "$HVN_CIDR" \ --destination-port-ranges "8300-8301" \ --direction Outbound \ --access Allow az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name ConsulClientOutbound \ --priority 401 \ --source-address-prefixes VirtualNetwork \ --destination-address-prefixes VirtualNetwork \ --destination-port-ranges 8301 \ --direction Outbound \ --access Allow az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name HTTPOutbound \ --priority 402 \ --source-address-prefixes VirtualNetwork \ --destination-address-prefixes "$HVN_CIDR" \ --destination-port-ranges 80 \ --direction Outbound \ --access Allow az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name HTTPSOutbound \ --priority 403 \ --source-address-prefixes VirtualNetwork \ --destination-address-prefixes "$HVN_CIDR" \ --destination-port-ranges 443 \ --direction Outbound \ --access Allow az network nsg rule create \ --resource-group "$RESOURCE_GROUP_NAME" \ --nsg-name "$SECURITY_GROUP_ID" \ --name ConsulServerOutboundGRPC \ --priority 401 \ <- プライオリティが重複しているため 404 に修正 --source-address-prefixes VirtualNetwork \ --destination-address-prefixes "$HVN_CIDR" \ --destination-port-ranges 8502 \ --direction Outbound \ --access Allow
Azure Portal で NSG のルールが作成されていることを確認します。
以上で、HashiCorp Virtual Network (HVN) と Azure VNet のピアリングが完了しました。
それではつづいて Vault クラスタの作成です。
HCP Vault クラスタ作成
HCP Vault クラスタも HCP ウェブコンソールから作成します。 今回はスクラッチで作成するため、[Start from scratch] の [Create cluster] を選択します。
HCP Vault クラスタ作成画面では以下のように設定します。
項目 | 設定 |
---|---|
Provider | Microsoft Azure |
Vault tier | Development |
Cluster size | Extra Small |
Network | 前章で作成した HVN |
Cluster accesibility | Public |
Cluster ID | demo-cluster |
Templates | Start from scratch |
「Vault tier」では運用レベルに合わせて 3 種類の Tier を選ぶことができます。
- Development
- Starter
- Standard
それぞれクライアント数の制限やバックアップの有無が異なります。
また、Vault tier 毎に選択できる「Cluster size」も異なります。
今回の Development Tier では 2 vCPU/1 GiB RAM
の「Extra Small」のみ選択でき、料金は $0.045/hr 掛かります。
ちなみに、HCP はアカウント作成時に $50 のクレジットが使える状態になっています。 Extra Small の HCP Vault クラスタのみの使用で計算すると約 1.5 ヶ月分のクレジットになります。 太っ腹ですね!
「Cluster accesibility」では HCP Vault クラスタへのアクセス制限を設定できます。
Private
を選択した場合はピアリングした Azure VNet 経由でしか接続できません。
この項目は後ほど変更可能ということですので、今回は Public
で構築します。
HCP Vault クラスタが作成できたら以下のような概要ページを見ることができます。 こちらには HCP Vault クラスタの構成情報やアクセス方法が載っていたり、admin 用トークンを生成できたりします。
以上で HCP Vault クラスタの構築が完了です。
AKS クラスタ作成
次に、Azure 上に AKS クラスタを構築していきます。 今回は検証中にクラスタの「作って壊して」が多かったので Terraform で構築しました。
使用した Terraform ファイルはデモ用リポジトリを参照ください。
本来はプライベート AKS クラスタで動作確認したかったのですが、HCP Vault から Kubernetes 認証(後述)することができなかったため、通常の AKS クラスタで確認しています。
構築後は kubeconfig を設定しておいてください。
Terraform を使って構築した場合は terraform output -json | jq -r .kube_config.value
で kubeconfig を参照できます。
$ terraform output -json | jq -r .kube_config.value > ~/.kube/config_aks $ export KUBECONFIG=~/.kube/config_aks $ kubectl config current-context aks-hcp-vault-azure-demo
Vault Secrets Operator インストール
AKS クラスタの構築が完了したら、Vault Secrets Operator をインストールします。
Vault Secrets Operator は Helm に対応しており、今回は 0.1.0-beta
というバージョンをインストールしました。
$ helm repo add hashicorp https://helm.releases.hashicorp.com $ helm search repo hashicorp/vault-secrets-operator --devel $ helm install --create-namespace --namespace vault-secrets-operator \ vault-secrets-operator hashicorp/vault-secrets-operator --version 0.1.0-beta
無事に Pod が起動しているか確認します。
$ kubectl get pods -n vault-secrets-operator NAME READY STATUS RESTARTS AGE vault-secrets-operator-controller-manager-d9949dd5-898lm 2/2 Running 0 152m
Vault Secrets Operator をインストールすると、以下の Custom Resource Definition (CRD) が Kubernetes にインストールされます。
CRD | 内容 |
---|---|
VaultConnection | Operator が接続する Vault の構成情報 |
VaultAuth | 使用する VaultConnection の指定や Vault に認証するための情報 |
VaultDynamicSecrets | 使用する VaultAuth の指定や同期する動的シークレット情報 |
VaultPKISecrets | 使用する VaultAuth の指定や同期する PKI シークレット情報 |
VaultStaticSecrets | 使用する VaultAuth の指定や同期する静的シークレット情報 |
今回は静的シークレットのみ対象とするため、作成するカスタムリソースは VaultConnection
と VaultAuth
、そして VaultStaticSecrets
となります。
これらのカスタムリソースについての説明は後述します。
つぎに、HCP Vault から Kubernetes 認証で使用するサービスアカウントトークンを作成します。
Kubernetes バージョン 1.21
以降では、BoundServiceAccountTokenVolume
という機能が有効になっており、サービスアカウントトークンの有効期限が 1 時間になっています。
そのため、有効期限がないサービスアカウントトークンを別途作成して、後ほど使用します。
サービスアカウントトークンは Secret リソースに kubernetes.io/service-account.name
アノテーションを付与して、対象のサービスアカウントを指定することで作成できます。
$ cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Secret metadata: name: vault-secrets-operator-token namespace: vault-secrets-operator annotations: kubernetes.io/service-account.name: "vault-secrets-operator-controller-manager" type: kubernetes.io/service-account-token EOF
HCP Vault の設定
Vault Secrets Operator をインストールしてもすぐに使えるわけではありません。 HCP Vault 側で「シークレット作成」と「ポリシー作成」および「認証設定」が必要です。
vault
コマンドを使って設定することも可能ですが、今回は HCP Vault の Web UI から設定していきます。
まず、Vault クラスタ概要ページの [New admin token] の Generate token
を選択して、admin 用のトークンを生成します。
そして、[Access web UI - Public] のリンクから Web UI にアクセスし、さきほどのトークンを使ってログインします。
シークレット作成
シークレットを格納するための KV
シークレットエンジンを作成します。
KV
シークレットエンジンとは、Vault の物理ストレージ内にシークレットを格納するための Key-Value ストアです。
上部メニューの [Secrets] から [Enable new engine] を選択します。
シークレットエンジン一覧から [KV] を選択します。
このページは何も変更しません。
これでシークレットエンジンは作成できました。 この流れで [Create secret] から Kubernetes に同期するシークレットを作成します。
[Path for this secret] には demo/config
、[Secret data] には以下のデータを設定します。
Key | Value |
---|---|
username | hoge |
password | fuga |
作成後もシークレットの値を参照できます。
後ほど、このシークレットが Kubernetes に同期されることを確認します。
ポリシー
次に、上部メニューの [Policies] を選択し、[Create ACL policy] から先ほど作成したシークレットを参照できる権限を持つポリシーを作成します。
名前は demo-policy
とし、権限は以下のように設定します。
path "secret/*" { capabilities = ["read"] }
Vault Secrets Operator は HCP Vault のシークレットを参照して Kubernetes に反映させるだけなので、シークレットの参照権限 (read) のみで構いません。
こちらは作成後のポリシーです。
このポリシーは次の Kubernetes 認証で使用します。
認証設定
Vault は認証に使用するバックエンドとして、さまざまな認証方法を有しています。 今回は Vault Secrets Operator から使用する認証方法として「Kubernetes 認証」を設定します。
プレビュー段階の Vault Secrets Operator は Kubernetes 認証のみ対応していますが、今後その他の認証方法もサポートされる予定です。
上部メニューの [Access] を選択し、[Enable new method] から新しい認証方法を作成していきます。
多くの認証方法が表示されますが、今回は [Kubernetes] を選択します。
[Path] は kubernetes
のままで [Enable Method] を選択して Kubernetes 認証を有効化します。
[Configure Kubernetes] ページでは、さきほど作成した AKS クラスタの情報を入力していきます。
[Kubernetes host] は Kubernetes API サーバの URL を入力します。 URL の確認方法はいろいろありますが、Terraform で AKS クラスタを構築している場合は以下のコマンドで URL を取得できます。
terraform output -json | jq -r .kube_config.value | yq .clusters[0].cluster.server
[Kubernetes CA Certificate] と [Token Reviewer JWT] は Kubernetes 認証時に使用する情報です。 前章で作成したサービスアカウントトークンを参照してそれぞれ設定します。
$ kubectl get secret vault-secrets-operator-token -n vault-secrets-operator -o jsonpath='{.data.ca\.crt}' | base64 -d $ kubectl get secret vault-secrets-operator-token -n vault-secrets-operator -o jsonpath='{.data.token}' | base64 -d
ロール
Kubernetes 認証の設定ができたら、Kubernetes 上のアプリケーションが使用するロールを作成します。 このロールに先ほど作成したポリシーを紐づけることで、アプリケーションは Kubernetes の TokenReview API で認証されたのち、ポリシーでシークレットの参照を認可されます。
Kubernetes 認証ページの [Create role] からロール作成ページに移ります。
項目 | 設定 |
---|---|
Name | demo-role |
Bound service account names | default |
Bound service account namespaces | vault-demo |
Generated Token's Plicies | demo-policy |
動作確認
HCP Vault の認証設定ができたので、いよいよ Vault Secrets Operator の動作確認です。
以下の観点で検証しました。
- HCP Vault に設定したシークレットが Kubernetes 側に同期されるか
- アプリケーションが更新後のシークレットを参照できるか
検証用マニフェスト
Terraform ファイルと同様、検証に使用したマニフェストはデモ用リポジトリに格納していますので、ご参照ください。
こちらのマニフェストには Vault Secrets Operator のカスタムリソースと同期する Secret、その Secret を使用する Deployment で構成されています。
では、マニフェストの中身について説明していきます。 カスタムリソースについては公式ドキュメントの API リファレンスもご参照ください。
VaultConnection
VaultConnection
リソースには Vault Secrets Operator が接続する Vault クラスタの情報を記載します。
apiVersion: secrets.hashicorp.com/v1alpha1 kind: VaultConnection metadata: name: vaultconnection-demo namespace: vault-demo spec: address: https://vault-private-vault-9640d9a6.d9c88c70.z1.hashicorp.cloud:8200
今回は spec.address
に HCP Vault のプライベートアクセス用 URL を設定しています。
プライベートアクセス用 URL は HCP ウェブコンソールのクラスタ概要ページから参照できます。
VaultConnection
でプライベートアクセス用 URL を指定することで、AKS から HCP Vault には Azure のピアリングされた VNet を通して接続されます。
ここが HCP Vault on Azure の醍醐味になります。
VaultAuth
VaultAuth
リソースには前述の VaultConnection
リソースや Vault クラスタへアクセスする際の認証方法を記載します。
apiVersion: secrets.hashicorp.com/v1alpha1 kind: VaultAuth metadata: name: vaultauth-demo namespace: vault-demo spec: vaultConnectionRef: vaultconnection-demo namespace: admin method: kubernetes mount: kubernetes kubernetes: role: demo-role serviceAccount: default
HCP Vault は Enterprise 版の Vault が使用されるため、Namespace 機能が有効になっています。
そのため、spec.namespace
で admin を指定しています。
spec.kubernetes.role
には Vault クラスタに作成したロールを指定します。
ロールという概念は Kubernetes にも存在するため、注意が必要です。
また、spec.kubernetes.serviceAccount
にはアプリケーションが利用する Kubernetes 上のサービスアカウント名を指定します。
Vault への認証には指定したサービスアカウントの「サービスアカウントトークン」が使用されます。
VaultStaticSecret
VaultStaticSecret
リソースには前述の VaultAuth
や同期するシークレットの情報を記載します。
apiVersion: secrets.hashicorp.com/v1alpha1 kind: VaultStaticSecret metadata: name: vaultstaticsecret-demo namespace: vault-demo spec: vaultAuthRef: vaultauth-demo namespace: admin mount: secret name: demo/config type: kv-v2 refreshAfter: 5s rolloutRestartTargets: - kind: Deployment name: vault-demo-app destination: name: secret-demo
spec.mount
にはシークレットエンジン名、spec.name
には Vault のシークレット名を指定します。
spec.destination.name
には Kubernetes 上の同期対象とする Secret リソース名を指定します。
spec.rolloutRestartTargets
では Vault シークレットの更新を検知した際にロールアウトするリソースの種類と名前を指定します。
サポートされているには Deployment/DaemonSet/StatefulSet の 3 種類です。
ここで指定されたリソースがロールアウトされることで、アプリケーションが参照するシークレットの情報も更新されるようになっています。
Secret
こちらは普通の Secret リソースですが、シークレット情報を含んでいません。 空っぽのリソースだけ作成しておいて、シークレット情報は Vault Secrets Operator に設定してもらいます。
Secret リソースが存在しない場合でも Vault Secrets Operator で新規作成するように VaultStaticSecret
で指定できますが、今回は事前に作成しておきます。
apiVersion: v1 kind: Secret metadata: name: secret-demo namespace: vault-demo type: Opaque
Deployment
こちらもいたって普通の Deployment リソースです。
先ほど作成した Secret を /etc/secrets
にマウントしています。
apiVersion: apps/v1 kind: Deployment metadata: name: vault-demo-app namespace: vault-demo spec: replicas: 1 selector: matchLabels: app: vault-demo-app template: metadata: labels: app: vault-demo-app spec: containers: - name: nginx image: nginx volumeMounts: - name: secrets mountPath: "/etc/secrets" readOnly: true volumes: - name: secrets secret: secretName: secret-demo optional: false
HCP Vault に設定したシークレットが Kubernetes 側に同期されるか
検証用マニフェストを AKS にデプロイします。
kubectl create namespace vault-demo kubectl apply -f vaultstaticsecret-demo.yaml
すると、Vault Secrets Operator がすぐに HCP Vault からシークレットを同期してくれました。
Secret のマニフェストでは data
を記載していませんでしたが、デプロイ後の状態をみると HCP Vault のシークレットが入っていました。
# Secret リソースの確認 $ kubectl get secret secret-demo -n vault-demo -o yaml apiVersion: v1 data: _raw: eyJkYXRhIjp7InBhc3N3b3JkIjoiZnVnYSIsInVzZXJuYW1lIjoiaG9nZSJ9LCJtZXRhZGF0YSI6eyJjcmVhdGVkX3RpbWUiOiIyMDIzLTA0LTEzVDE5OjQ0OjQ1LjI4NzIyOTk1NFoiLCJjdXN0b21fbWV0YWRhdGEiOm51bGwsImRlbGV0aW9uX3RpbWUiOiIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsImRlc3Ryb3llZCI6ZmFsc2UsInZlcnNpb24iOjV9fQ== password: ZnVnYQ== username: aG9nZQ== kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"secret-demo","namespace":"vault-demo"},"type":"Opaque"} creationTimestamp: "2023-04-13T19:45:16Z" name: secret-demo namespace: vault-demo resourceVersion: "58730" uid: bce83fcc-be62-4a01-aa5d-22a39a442c93 type: Opaque # data._raw の値の確認 $ kubectl get secret secret-demo -n vault-demo -o jsonpath='{.data._raw}' | base64 -d | jq { "data": { "password": "fuga", "username": "hoge" }, "metadata": { "created_time": "2023-04-13T19:44:45.287229954Z", "custom_metadata": null, "deletion_time": "0001-01-01T00:00:00Z", "destroyed": false, "version": 1 } } # data.username の値の確認 $ kubectl get secret secret-demo -n vault-demo -o jsonpath='{.data.username}' | base64 -d hoge # data.password の値の確認 $ kubectl get secret secret-demo -n vault-demo -o jsonpath='{.data.password}' | base64 -d fuga
それではデモ用コンテナでシークレットを参照できるか確認してみます。
# デモ用コンテナの /etc/secrets を確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- ls -l /etc/secrets total 0 lrwxrwxrwx 1 root root 11 Apr 13 19:45 _raw -> ..data/_raw lrwxrwxrwx 1 root root 15 Apr 13 19:45 password -> ..data/password lrwxrwxrwx 1 root root 15 Apr 13 19:45 username -> ..data/username # デモ用コンテナの /etc/secrets/username を確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- cat /etc/secrets/username hoge # デモ用コンテナの /etc/secrets/password を確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- cat /etc/secrets/password fuga
アプリケーションコンテナからも HCP Vault に設定したシークレットを参照できていました。
このように、Kubernetes マニフェストにシークレットを記載することなく HCP Vault からシークレットが同期されることを確認できました。
アプリケーションが更新後のシークレットを参照できるか
つぎに、HCP Vault のシークレットを password: fuga
から password: piyo
に更新してみます。
あわせてデモ Pod の状況もチェックしておきます。
すると、Vault Secrets Operator が検知して Pod が削除され、新しい Pod が立ち上がってきました。
$ kubectl get pods -n vault-demo -w NAME READY STATUS RESTARTS AGE vault-demo-app-57d48c77bd-7hd8b 1/1 Running 0 13m vault-demo-app-77697c6bfc-75rp9 0/1 Pending 0 0s vault-demo-app-77697c6bfc-75rp9 0/1 Pending 0 0s vault-demo-app-77697c6bfc-75rp9 0/1 ContainerCreating 0 0s vault-demo-app-77697c6bfc-75rp9 1/1 Running 0 2s vault-demo-app-57d48c77bd-7hd8b 1/1 Terminating 0 14m vault-demo-app-57d48c77bd-7hd8b 0/1 Terminating 0 14m vault-demo-app-57d48c77bd-7hd8b 0/1 Terminating 0 14m vault-demo-app-57d48c77bd-7hd8b 0/1 Terminating 0 14m
また、ReplicaSet を見てみるとローリングアップデートされたことが分かります。
$ kubectl get replicaset -n vault-demo NAME DESIRED CURRENT READY AGE vault-demo-app-57d48c77bd 0 0 0 14m vault-demo-app-77697c6bfc 1 1 1 19s
アプリケーションのコンテナからも password
のみ値が更新されていることを確認できました。
# デモ用コンテナの /etc/secrets を確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- ls -l /etc/secrets total 0 lrwxrwxrwx 1 root root 11 Apr 13 19:59 _raw -> ..data/_raw lrwxrwxrwx 1 root root 15 Apr 13 19:59 password -> ..data/password lrwxrwxrwx 1 root root 15 Apr 13 19:59 username -> ..data/username # デモ用コンテナの /etc/secrets/username を確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- cat /etc/secrets/username hoge # デモ用コンテナの /etc/secrets/passwordを確認 $ kubectl exec -it $(kubectl get pods -n vault-demo -o jsonpath={.items[*].metadata.name}) -n vault-demo -- cat /etc/secrets/password piyo
このように、Vault Secrets Operator がシークレットの更新を検知して Deployment をローリングアップデートすることを確認できました。
おわりに
以上で、Vault Secrets Operator と HCP Vault on Azure を使った動作確認は終了です。
それでは、まとめに入ります。
まとめ
今回検証した Vault Secrets Operator と HCP Vault について要点をまとめます。
- Vault Secrets Operator
- 2023/4 にプレビュー公開された
- Vault シークレットと Kubnertnetes シークレットを同期
- Deployment をローリングアップデートしてシークレットを反映
- HCP Vault on Azure
- 2023/2 に GA
- Azure VNet とピアリングして Azure VM や AKS とセキュアに接続可能
今後の展望
今回の検証では静的シークレットのみ対象としていましたが、Vault には「動的シークレット」というとても便利な機能があります。 Vault Secrets Operator で動的シークレットを使うことで、Kubernetes 上で Azure のサービスプリンシパルをより扱い易くなるのでは、と考えています。 こちらは別途、動作確認してみるつもりです。
また、Vault Secrets Operator はまだプレビュー段階のため Kubernetes 認証しかサポートしていませんが、今後は他の認証方法もサポートされる予定です。 今後とも Vault Secrets Operator には注目していきたいですね。
ACS事業部のご紹介
私達 ACS 事業部は Azure・AKS などのクラウドネイティブ技術を活用した内製化のご支援をしております。
また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。