ACK Secret Manager を使用して Alibaba Cloud KMS サービスの認証情報をインポートする
ack-secret-manager を使用すると、Key Management Service (KMS) のシークレットを Kubernetes Secret として ACK クラスターに同期できます。ファイルシステムからシークレットを読み取るアプリケーションは、コードを変更することなく KMS で管理されたシークレットを使用できます。このコンポーネントは同期を自動化するため、手動で更新しなくてもシークレットは最新の状態に保たれます。
仕組み
ack-secret-manager は、2 つのカスタムリソースを使用して KMS シークレットをクラスターに同期します。
SecretStore — ack-secret-manager が KMS で認証する *方法* (認証情報と認証メソッド) を定義します。
ExternalSecret — フェッチする *対象* (どの KMS シークレット、どのバージョン、どの Kubernetes Secret キーに値を書き込むか) を定義します。
ExternalSecret を適用すると、ack-secret-manager は参照先の SecretStore を読み取って KMS で認証し、指定されたシークレットをフェッチして、ExternalSecret と同じ名前と名前空間を持つ Kubernetes Secret を作成します。
セキュリティに関する考慮事項
ack-secret-manager を設定する前に、以下のセキュリティリスクを確認してください。
クラスター内のいずれかのアプリケーションに共通脆弱性識別子 (CVE) の脆弱性がある場合、ファイルシステムへのアクセスにより、ディレクトリトラバーサル攻撃にシークレットが晒される可能性があります。
デバッグのブレークポイントや誤って設定されたログ権限によって、シークレットが漏洩する可能性があります。環境変数を使用してシークレットをマウントしないでください。この方法はファイルシステムへのマウントよりも安全性が低いです。
シークレットの同期を有効にする場合は、最小権限の原則に従い、アクセス権限を厳密に制限してください。
アプリケーションでシークレットを永続化する必要がない場合は、RRSA を使用して Pod に必要な最小限の権限を付与し、アプリケーションコードから直接 GetSecretValue API を呼び出します。これにより、シークレットが Pod のファイルシステムや Kubernetes シークレットとして保存されるのを回避できます。
前提条件
開始する前に、以下が準備できていることを確認してください。
KMS シークレットと同じリージョンにある ACK クラスター。サポートされているクラスタータイプ:ACK マネージドクラスター、ACK 専用クラスター、登録済みクラスター、ACK Serverless クラスター。作成手順については、「ACK マネージドクラスターの作成」、「登録済みクラスターの作成」、および「ACK Serverless クラスターの作成」をご参照ください。
ステップ 1:ack-secret-manager のインストール
ACK コンソールにログインします。左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理したいクラスターを見つけてその名前をクリックします。左側のナビゲーションウィンドウで、[アプリケーション] > [Helm] を選択します。
[Helm] ページで、[デプロイ] をクリックします。[デプロイ] パネルの [チャート] セクションで、[ack-secret-manager] を見つけて選択し、他のパラメーターにはデフォルト値を使用してから、[次へ] をクリックします。[確認] メッセージに表示される情報は、コンポーネントがデフォルトで kube-system 名前空間にインストールされ、デフォルトのアプリケーション名がコンポーネント名として使用されることを示します。[はい] をクリックします。カスタムのアプリケーション名と名前空間を使用するには、[基本情報] ステップで [アプリケーション名] と [名前空間] パラメーターを設定します。
[パラメーター] ステップで、最新のチャートバージョンを選択し、必要に応じて以下のパラメーターを設定してから、[OK] をクリックします。
認証に RAM Roles for Service Accounts (RRSA) を有効にするには、
rrsa.enableを [true] に設定します。
シークレットのスケジュールされた同期を有効にするには、次の図に示すパラメーターを設定します。

command.disablePolling:シークレットのポーリングを無効化するかどうかを指定します。false を設定すると、ポーリングが有効になります。command.pollingInterval:同期間隔です。120s を指定すると、シークレットが 2 分ごとに同期されます。ご利用の要件に応じて調整してください。
クラスターに同期待ちの ExternalSecret が多数ある場合は、KMS 側または RAM 側でレート制限がトリガーされるのを避けるために、次のスロットリングパラメーターを設定します。
command.maxConcurrentKmsSecretPulls:1 秒あたりに同期できる KMS シークレットの最大数。デフォルト:10。
コンポーネントをインストールすると、ack-secret-manager ページにリダイレクトされます。コンポーネントがインストールされているかどうかを確認できます。次の図に示すリソースが作成されていれば、コンポーネントはインストールされています。

ステップ 2:ack-secret-manager に KMS シークレットへのアクセスを認可する
ack-secret-manager が KMS シークレットを読み取れるように SecretStore を作成します。SecretStore がないと、ack-secret-manager はシークレットをインポートまたは同期できません。
クラスターのタイプとセキュリティ要件に基づいて、次のいずれかの方法を選択してください。
| 方法 | 適用可能なクラスタータイプ | 主な特徴 |
|---|---|---|
| RRSA の使用 | ACK マネージドクラスターおよび ACK Serverless クラスター (Kubernetes 1.22 以降) | AccessKey ペア不要、Pod レベルの権限コントロール |
| ワーカー RAM ロールの使用 | ACK マネージドクラスター、ACK 専用クラスター、登録済みクラスター | ワーカーノード上のすべての Pod に適用、ACK Serverless クラスターには適用不可 |
| AccessKey ペアを使用した RAM ロールの引き受け | すべての ACK クラスタータイプ | AccessKey ペアを Kubernetes Secret として保存する必要がある |
RRSA を使用した権限の付与
RAM Roles for Service Accounts (RRSA) は、AccessKey ペアを必要とせずに Pod レベルの権限コントロールを可能にし、認証情報の漏洩リスクを低減します。この方法には Kubernetes 1.22 以降が必要です。
ACK コンソールで ACK クラスターの RRSA 機能を有効にします。詳細については、「RRSA の有効化」をご参照ください。
ack-secret-manager をインストールする際に、
rrsa.enableを [true] に設定して RRSA を有効にします。信頼できるエンティティが ack-secret-manager の OIDC ID プロバイダー (IdP) である RAM ロールを作成します。パラメーターを次のように設定します。詳細については、「OIDC IdP 用の RAM ロールの作成」をご参照ください。
パラメーター 値 ID プロバイダータイプ OIDC ID プロバイダー ack-rrsa-<cluster_id>を選択します。ここで<cluster_id>はご利用のクラスター ID です条件 — oidc:iss デフォルト設定を維持します 条件 — oidc:aud デフォルト設定を維持します 条件 — oidc:sub 手動で追加:キー = oidc:sub、演算子 =StringEquals、値 =system:serviceaccount:<namespace>:ack-secret-manager。<namespace>を ack-secret-manager がインストールされている実際の名前空間 (デフォルト:kube-system) に置き換えます次の内容でカスタム RAM ポリシーを作成し、作成した RAM ロールにアタッチします。詳細については、「カスタムポリシーの作成」および「RAM ロールへの権限付与」をご参照ください。
{ "Action": [ "kms:GetSecretValue", "kms:Decrypt" ], "Resource": [ "*" ], "Effect": "Allow" }RRSA 認証情報を参照する SecretStore を作成します。
secretstore-rrsa.yamlという名前のファイルを作成します。プレースホルダーを実際の値に置き換えます。apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-rrsa spec: KMS: KMSAuth: oidcProviderARN: "acs:ram::{accountID}:oidc-provider/ack-rrsa-{clusterID}" ramRoleARN: "acs:ram::{accountID}:role/{roleName}"{accountID}:KMS シークレットを同期するために使用される Alibaba Cloud アカウントの ID{clusterID}:ご利用のクラスター ID{roleName}:前のステップで作成した RAM ロールの名前
SecretStore を適用します。
kubectl apply -f secretstore-rrsa.yaml
ワーカー RAM ロールへの権限付与
この方法では、KMS アクセス権限をクラスターのワーカー RAM ロールに直接アタッチします。ACK Serverless クラスターにはワーカー RAM ロールがないため、この方法は適用できません。
次の内容でカスタム RAM ポリシーを作成します。詳細については、「カスタムポリシーの作成」をご参照ください。
{ "Action": [ "kms:GetSecretValue", "kms:Decrypt" ], "Resource": [ "*" ], "Effect": "Allow" }ポリシーをクラスターのワーカー RAM ロールにアタッチします。詳細については、「ワーカー RAM ロールへの権限付与」をご参照ください。この方法を使用する場合、ExternalSecret の
secretStoreRefは空白のままにできます。SecretStore は不要です。
AccessKey ペアを指定して RAM ロールを引き受ける
この方法はすべての ACK クラスタータイプで機能します。AccessKey ペアを Kubernetes Secret として保存する必要があります。
信頼できるエンティティがご利用の Alibaba Cloud アカウントである RAM ロールを作成します。信頼できるアカウントを選択するよう求められたら、[現在のアカウント] を選択します。詳細については、「信頼できる Alibaba Cloud アカウントの RAM ロールの作成」をご参照ください。
次の内容でカスタム RAM ポリシーを作成し、RAM ロールにアタッチします。詳細については、「カスタムポリシーの作成」および「RAM ロールへの権限付与」をご参照ください。
{ "Action": [ "kms:GetSecretValue", "kms:Decrypt" ], "Resource": [ "*" ], "Effect": "Allow" }RAM ユーザーが RAM ロールを引き受けることを許可する RAM ポリシーを作成し、RAM ユーザーにアタッチします。
次の内容でポリシーを作成します。
<account-id>を Alibaba Cloud アカウント ID に、<role-name>を RAM ロール名に置き換えます。ロールの ARN の取得方法の詳細については、「RAM ロールの ARN を表示するにはどうすればよいですか?」をご参照ください。{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Resource": "acs:ram:*:<account-id>:role/<role-name>" } ], "Version": "1" }ポリシーを RAM ユーザーにアタッチします。詳細については、「RAM ユーザーへの権限付与」をご参照ください。
RAM ユーザーの AccessKey ペアを Kubernetes Secret として保存します。
AccessKey ID と AccessKey Secret を Base64 でエンコードし、
ramuser.yamlという名前のファイルを作成します。apiVersion: v1 data: accessKey: {Base64 でエンコードされた AccessKey ID} accessKeySecret: {Base64 でエンコードされた AccessKey Secret} kind: Secret metadata: name: ramuser namespace: kube-system type: OpaqueSecret を適用します。
kubectl apply -f ramuser.yaml
AccessKey ペアを参照する SecretStore を作成します。
secretstore-ramrole.yamlという名前のファイルを作成します。プレースホルダーを実際の値に置き換えます。プレースホルダー 説明 {accountID}KMS シークレットを同期するために使用される Alibaba Cloud アカウントの ID {roleName}ステップ 1 で作成した RAM ロールの名前 {secretName}AccessKey ペアを格納する Kubernetes Secret の名前 {secretNamespace}Kubernetes Secret の名前空間 {secretKey}AccessKey の値を格納する Kubernetes Secret 内のキー {roleSessionName}apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-ramrole spec: KMS: KMSAuth: accessKey: name: {secretName} namespace: {secretNamespace} key: {secretKey} accessKeySecret: name: {secretName} namespace: {secretNamespace} key: {secretKey} ramRoleARN: "acs:ram::{accountID}:role/{roleName}" ramRoleSessionName: {roleSessionName}SecretStore を適用します。
kubectl apply -f secretstore-ramrole.yaml
ステップ 3:KMS シークレットをクラスターに同期する
ExternalSecret は、どの KMS シークレットをフェッチし、それを Kubernetes Secret としてどのように保存するかを ack-secret-manager に指示します。Kubernetes Secret は ExternalSecret と同じ名前と名前空間を持ちます。
ExternalSecret を作成します。
external.yamlという名前のファイルを作成します。プレースホルダーを実際の値に置き換えます。プレースホルダー 説明 {KMS secret name}同期する KMS シークレットの名前 {Kubernetes secret key}結果として生成される Kubernetes シークレットで使用するキー名 {KMS secret version stage}KMS シークレットのバージョンステージラベル (例: ACSCurrent)。代わりにバージョン番号で同期するには、 versionStageを versionIdに置き換え、バージョン番号を入力します {secret store name}作成した SecretStore の名前。ワーカー RAM ロールを介して ack-secret-manager を認可した場合は、空白のままにします {secret store namespace}apiVersion: 'alibabacloud.com/v1alpha1' kind: ExternalSecret metadata: name: esdemo spec: provider: kms # KMS から同期します。このフィールドは空のままにすることも、kms と設定することもできます。 data:キー: {KMS シークレット名} 名前: {Kubernetes シークレットキー} バージョンステージ: {KMS シークレットバージョンステージ} secretStoreRef:# ワーカー RAM ロールを介して承認されている場合は不要です。 名前: {シークレットストア名} 名前空間: {シークレットストア 名前空間}
ExternalSecret を適用します。
kubectl apply -f external.yaml
次のコマンドを実行して、Kubernetes Secret が存在するかどうかを確認します。
kubectl get secret esdemoKubernetes Secret が存在する場合、ack-secret-manager は KMS シークレットをクラスターに正常に同期しました。
高度な設定
Alibaba Cloud アカウント間での KMS シークレットの同期
KMS インスタンスが Alibaba Cloud アカウント A に属し、ACK クラスターが Alibaba Cloud アカウント B に属している場合、ack-secret-manager は RRSA を使用してアカウント A の RAM ロールを引き受け、クロスアカウントで KMS インスタンスにアクセスできます。
Alibaba Cloud アカウント A の権限設定
Alibaba Cloud アカウント A を使用して、信頼できるエンティティが Alibaba Cloud アカウント B である RAM ロールを作成します。信頼できるアカウントを選択する際に、[他のアカウント] を選択し、Alibaba Cloud アカウント B の ID を入力します。詳細については、「信頼できる Alibaba Cloud アカウントの RAM ロールの作成」をご参照ください。
次の内容でカスタム RAM ポリシーを作成します。詳細については、「カスタムポリシーの作成」をご参照ください。
{ "Action": [ "kms:GetSecretValue", "kms:Decrypt" ], "Resource": [ "*" ], "Effect": "Allow" }ポリシーを RAM ロールにアタッチします。詳細については、「RAM ロールへの権限付与」をご参照ください。
Alibaba Cloud アカウント B の権限設定
ACK コンソールで ACK クラスターの RRSA 機能を有効にします。詳細については、「RRSA の有効化」をご参照ください。
ack-secret-manager をインストールする際に、
rrsa.enableを [true] に設定して RRSA を有効にします。アカウント B で、信頼できるエンティティが OIDC IdP である RAM ロールを作成します。パラメーターを次のように設定します。詳細については、「OIDC IdP 用の RAM ロールの作成」をご参照ください。
パラメーター 値 ID プロバイダータイプ [OIDC] ID プロバイダー ack-rrsa-<cluster_id>を選択します。ここで<cluster_id>はご利用のクラスター ID です条件 — oidc:iss デフォルト設定を維持します 条件 — oidc:aud デフォルト設定を維持します 条件 — oidc:sub 手動で追加:キー = oidc:sub、演算子 =StringEquals、値 =system:serviceaccount:<namespace>:ack-secret-manager。<namespace>を実際のインストール名前空間に置き換えますアカウント B の RAM ロールがアカウント A の RAM ロールを引き受けることを許可するカスタム RAM ポリシーを作成し、その RAM ロールにアタッチします。
次の内容でポリシーを作成します。
<account-id>を Alibaba Cloud アカウント A の ID に、<role-name>をアカウント A で作成した RAM ロールに置き換えます。ロールの ARN の取得方法の詳細については、「RAM ロールの ARN を表示するにはどうすればよいですか?」をご参照ください。{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Resource": "acs:ram:*:<account-id>:role/<role-name>" } ], "Version": "1" }ポリシーをアカウント B で作成した RAM ロールにアタッチします。
クロスアカウント設定用の SecretStore を作成します。
secretstore-ramrole.yamlという名前のファイルを作成します。プレースホルダーを実際の値に置き換えます。プレースホルダー 説明 {ACK-accountID}Alibaba Cloud アカウント B の ID {clusterID}クラスター ID {ACK-roleName}アカウント B で作成した RAM ロールの名前 {KMS-accountID}Alibaba Cloud アカウント A の ID {KMS-roleName}アカウント A で作成した RAM ロールの名前 {roleSessionName}apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-cross-account spec: KMS: KMSAuth: oidcProviderARN: "acs:ram::{ACK-accountID}:oidc-provider/ack-rrsa-{clusterID}" ramRoleARN: "acs:ram::{ACK-accountID}:role/{ACK-roleName}" remoteRamRoleARN: "acs:ram::{KMS-accountID}:role/{KMS-roleName}" remoteRamRoleSessionName: {roleSessionName}SecretStore を適用します。
kubectl apply -f secretstore-ramrole.yaml
「ステップ 3:KMS シークレットをクラスターに同期する」で説明されているように ExternalSecret を作成します。
JSON シークレットから特定のキーを解析する
KMS シークレットが JSON 形式で、特定のキーと値のペアのみが必要な場合は、jmesPath パラメーターを使用してそれらを抽出します。たとえば、次の JSON が KMS Secrets Manager に保存されているとします。
{"name":"tom","friends":[{"name":"lily"},{"name":"mark"}]}jmesPath を使用して特定のフィールドを抽出する ExternalSecret を作成します。
path:どのフィールドを抽出するかを指定する JMESPath 式 (必須)objectAlias:結果として得られる Kubernetes Secret で使用するキー名
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: es-json-demo
spec:
provider: kms
data:
- key: {KMS secret name}
versionStage: {KMS secret version stage}
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
jmesPath:
- path: "name"
objectAlias: "myname"
- path: "friends[0].name"
objectAlias: "friendname"キー置換を使用して JSON シークレットからすべてのキーを解析する
JSON シークレットのデータ構造が事前にわからない場合は、dataProcess.extract を使用してすべてのキーと値のペアを自動的に解析します。Kubernetes Secret に無効な文字 (先頭または末尾のスラッシュなど) を含むキーの名前を変更するには、dataProcess.replaceRule を使用します。
たとえば、次の JSON には無効なキーが含まれています。
{"/name-invalid":"lily","name-invalid/":[{"name":"mark"}]}次の ExternalSecret は、すべてのキーを解析し、正規表現ルールを使用して無効なキーを置き換えます。
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: extract-secret
spec:
provider: kms
dataProcess:
- extract:
key: {KMS secret name}
versionStage: ACSCurrent
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
replaceRule:
- source: "^/.*d$" # / で始まり d で終わるキー → "tom" に名前変更
target: "tom"
- source: "^n.*/$" # n で始まり / で終わるキー → "mark" に名前変更
target: "mark"次のステップ
KMS から同期され、クラスターにキャッシュされた Kubernetes Secret を保護するには、シークレットの暗号化機能を有効にします。詳細については、「KMS を使用した Kubernetes Secret の暗号化」をご参照ください。