全部產品
Search
文件中心

Key Management Service:ACK容器環境中部署KMS Agent擷取憑據

更新時間:Jan 17, 2026

KMS支援您在ACK叢集中以Sidecar形式部署KMS Agent,Agent通過RRSA機制向KMS擷取憑據值,業務應用通過本地介面向Agent擷取KMS憑據。該方式無需整合SDK,可以降低應用改造成本,確保統一的整合標準,適用於大規模應用訪問KMS的情境。本文介紹如何在ACK容器環境中部署KMS Agent擷取憑據。

前置概念

在您瞭解本最佳實務前,請先瞭解以下內容:

  • 什麼是KMS Agent:KMS Agent是一個HTTP代理服務,負責擷取KMS服務中的憑據值並緩衝在記憶體中,應用通過HTTP請求向KMS Agent擷取憑據值。

  • 通過RRSA配置ServiceAccount的RAM許可權實現Pod許可權隔離:如果您的應用程式部署在阿里雲ACK容器叢集上,則可以基於RRSA(RAM Roles for Service Accounts)功能,在容器叢集內實現應用隔離的RAM角色功能,各個應用可以扮演獨立的RAM角色,訪問阿里雲OpenAPI。

應用情境

在ACK容器環境中部署KMS Agent擷取憑據,使用RRSA作為訪問憑證,適用於以下業務情境。

  • 企業需要解決last key問題。

    企業將敏感憑證託管至阿里雲KMS以提升安全性,但由於訪問KMS本身仍需進行身份認證,若長期依賴固定AccessKey訪問雲端服務,會導致KMS的訪問憑證成為新的潛在安全隱患。

    通過在阿里雲ACK叢集上開啟RRSA功能,基於RRSA可以為不同Pod關聯不同的RAM角色,不同Pod內的各個應用可以扮演獨立的RAM角色並使用擷取的臨時憑證訪問雲資源,從而實現應用RAM許可權最小化以及無AccessKey訪問阿里雲OpenAPI,避免AccessKey泄露。

  • 企業需要隔離不同應用對憑據的存取權限。

    例如同一應用的測試與正式環境以及不同應用間,都需要進行許可權隔離,避免存取權限擴大,憑據被非法擷取。

    RRSA基於RAM策略,不同的應用運行在不同的namespace和service account,綁定不同的ramrole,通過為ramrole授予不同的許可權,實現不同應用對KMS憑據的存取權限控制。

  • 降低應用與KMS的整合的研發成本。

    如果只有少數幾個應用需要訪問KMS,應用可以整合SDK,但對於大中型企業來說,面對成百上千的應用,讓每個應用改造去整合SDK,並且都按照一致的標準去設計容災和緩衝是非常困難的。同時由於一般中國內地企業的安全、營運、開發分屬不同團隊,已經存在的開源external secret方式在中國內地企業也不太適用,其更適合於集開發營運一體的devops模式。

    此時您可以通過KMS Agent來擷取憑據。在ACK容器叢集環境中,KMS Agent作為Sidecar容器運行在與業務容器相同的Pod裡。當ACK叢集啟動RRSA後,KMS Agent會自動以RRSA RamRole的身份訪問KMS,不需要再設定任何訪問憑證。Agent從遠端KMS擷取憑證並緩衝到記憶體,業務應用再從Agent擷取憑據。

解決方案架構

下圖以使用者擁有兩個應用dev和prod為例,通過ACK容器環境中部署KMS Agent擷取憑據,不同環境的應用只能訪問各自對應的KMS憑據。

image

使用限制

  • ACK叢集支援ACK託管叢集、ACK專有叢集、ACK註冊叢集、ACK Serverless叢集。

  • ACK叢集與KMS執行個體需要在同一地區。

操作步驟

以下流程示範了ACK、RAM、KMS如何配置,以實現業務應用通過KMS Agent擷取憑據。研發只需要在KMS建立憑據,然後在應用裡從本地檢索即可,其餘配置由營運和安全團隊提前配置。整個過程中,研發不需要在業務代碼裡整合SDK,也不需要關心應用訪問KMS的認證鑒權以及緩衝容災等。

image

步驟一:構建KMS Agent可執行檔

  1. 安裝Golang環境。具體操作,請參見Go安裝指南

  2. 下載源碼和依賴。

    1. 請訪問Git官網,下載並安裝Git工具。

    2. 執行以下命令下載源碼和依賴。

      git clone https://github.com/aliyun/alibabacloud-kms-agent
      go mod download
  3. 在專案根目錄下,執行go build .命令編譯可執行檔。檔案預設名稱alibabacloud-kms-agent,預設儲存在專案根目錄下 。

    編譯環境與部署環境一致,執行go build .命令即可。如果編譯環境和部署環境不一致,請參考以下命令進行跨平台編譯,產生64位可執行檔。

    編譯環境

    部署環境為Mac

    部署環境為Linux

    部署環境為Windows

    Mac

    go build .

    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .

    CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build .

    Linux

    CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build .

    go build .

    CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build .

    Windows

    SET CGO_ENABLED=0 SET GOOS=darwin SET GOARCH=amd64 go build .

    SET CGO_ENABLED=0 SET GOOS=linux SET GOARCH=amd64 go build .

    go build .

  4. 在專案根目錄下,查看是否存在可執行檔alibabacloud-kms-agent。image

步驟二:啟用ACK RRSA並授權其訪問特定的憑據

  1. 啟用ACK RRSA功能。

    建立叢集時開啟

    建立ACK託管叢集ACK Edge叢集時,您可以在叢集配置的進階選項(選填)地區,選中開啟RRSA功能。

    image

    在叢集資訊頁面開啟

    1. 登入Container Service管理主控台,在左側導覽列選擇叢集列表

    2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇叢集資訊

    3. 基本資料頁簽的安全與審計地區,單擊RRSA OIDC右側的開啟image

    4. 在彈出的啟用RRSA對話方塊,單擊確定

      基本資料地區,當叢集狀態由更新中變為運行中後,表明該叢集的RRSA特性已變更完成。

  2. 開啟叢集詳情頁,在基本資料頁簽的安全與審計地區,將滑鼠懸浮至RRSA OIDC右側已開啟上面,查看供應商的URL連結和ARN資訊。image

  3. 建立一個可信實體為身份供應商的RAM角色。

    1. 使用阿里雲帳號登入RAM控制台

    2. 在左側導覽列,選擇身份管理 > 角色,然後在角色頁面,單擊建立角色

    3. 建立角色面板,選擇可信實體類型為身份供應商,並單擊切換編輯器image

    4. 建立角色頁面的可視化編輯,配置如下角色資訊後,單擊確定

      配置項

      描述

      效果

      選擇允許

      主體

      選擇身份提供者。

      • 身份提供者類型:選擇OIDC。

      • 身份提供者:開啟RRSA後,ACK叢集會預設建立身份提供者,命名格式為ack-rrsa-<cluster_id>。其中,<cluster_id>為您的叢集ID。

      操作

      保持預設。即勾選sts:AssumeRole。

      條件

      在預設的oidc:issoidc:aud限制條件基礎上,新增一個限制條件:

      • 條件鍵:選擇oidc:sub

      • 運算子:選擇StringEquals

      • 條件值:system:serviceaccount:<namespace>:<serviceAccountName>

        • <namespace>:應用所在的命名空間。

        • <serviceAccountName>:服務賬戶名稱。

        本文以system:serviceaccount:rrsa-dev:dev-sa為例, 其中 rsa-dev 是下一步需要建立 k8s namespace,dev-sa 是下一步需要建立的 k8s service account。

    5. 建立角色對話方塊中,設定角色名稱,然後單擊確定。本文角色名稱以dev-role-for-rrsa為例。

    6. 查看dev-role-for-rrsa這個RAM角色的信任策略。

      該策略表示允許特定的服務賬戶通過阿里雲RRSA(RAM Roles for Service Accounts) ,在滿足 OIDC 身分識別驗證條件後,擔任某個RAM角色。

      {
        "Statement": [
          {
            "Action": "sts:AssumeRole",
            "Condition": {
              "StringEquals": {
                "oidc:aud": [
                  "sts.aliyuncs.com"
                ],
                "oidc:iss": [
                  "https://oidc-ack-cn-hongkong.oss-cn-hongkong.aliyuncs.com/cf01******"
                ],
                "oidc:sub": [
                  "system:serviceaccount:rrsa-dev:dev-sa"
                ]
              }
            },
            "Effect": "Allow",
            "Principal": {
              "Federated": [
                "acs:ram::5269************:oidc-provider/ack-rrsa-cf01******"
              ]
            }
          }
        ],
        "Version": "1"
      }
  4. 建立權限原則並授權給RAM角色。

    1. 權限原則名稱以dev-role-for-rrsa-kms-policy為例,策略內容以僅允許訪問帶有env:dev 標籤的憑據為例。image

      權限原則內容如下所示:

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "kms:Decrypt",
                      "kms:GetSecretValue"
                  ],
                  "Resource": "*",
                  "Condition": {
                      "StringEqualsIgnoreCase": {
                          "kms:tag/env": [
                              "dev"
                          ]
                      }
                  }
              }
          ]
      }
    2. 將dev-role-for-rrsa-kms-policy權限原則,授權給dev-role-for-rrsa角色。image

步驟三:在ACK中建立Namespace和Service Account

Namespace將ACK叢集劃分為邏輯隔離的虛擬空間,用於區分開發、測試、生產等環境,不同Namespace中的應用預設無法互訪資源,為RAM角色綁定提供物理邊界。Service Account為Pod提供身份標識,通過RRSA機制與RAM角色動態綁定。

  1. 通過YAML檔案建立Namespace。

    Namespace名稱以rrsa-dev為例,YAML檔案名稱以namespace.yaml為例。

    apiVersion: v1
    kind: Namespace
    metadata:
      name: rrsa-dev
  2. 執行如下命令在ACK叢集中建立名為 rrsa-dev 的 Namespace。

    kubectl apply -f namespace.yaml

    查看Namespace是否建立成功:

    kubectl get namespaces

    若輸出包含rrsa-dev,即代表建立成功。

  3. 通過YAML檔案建立Service Account。

    Service Account名稱以dev-sa為例,YAML檔案名稱以serviceaccount.yaml為例。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: dev-sa
      namespace: rrsa-dev
  4. 執行如下命令在 rrsa-dev 中建立一個名為 dev-sa 的ServiceAccount。

    kubectl apply -f serviceaccount.yaml

    查看 ServiceAccount 是否建立成功:

    kubectl get serviceaccount -n rrsa-dev

    若輸出包含 dev-sa,即代表建立成功。

步驟四:製作sidecar容器鏡像

將KMS Agent作為sidecar容器與應用程式容器一起部署到阿里雲的ACKContainer Service。

  1. 在config.toml中配置KMS Agent的運行參數。

    說明

    config.toml是Agent的設定檔,您可以在步驟一擷取的alibabacloud-kms-agent源碼的configs目錄下查看到該檔案。

    [Server]
    HttpPort = 2025
    
    [KMS]
    Region = "cn-hangzhou"
    
    [Cache]
    CacheType = "InMemory"
    CacheSize = 1000
    TtlSeconds = 300
    
    [Log]
    LogLevel = "Debug"
    LogPath = "./logs/"
    MaxSize = 100
    MaxBackups = 2

  2. 建立Dockerfile檔案。

    以Agent部署在deploy/ack/agent路徑下為例,在該路徑下建立Dockerfile。檔案內容,請參考agent_Dockerfile

    # Use the centos image as the base
    FROM centos:centos7
    
    # Set the working directory inside the container
    WORKDIR /usr/local/alibabacloudkmsagent
    
    # Copy the binary and config to the container
    COPY alibabacloud-kms-agent .
    COPY config.toml .
    
    # Set the entry point to run the kms agent
    ENTRYPOINT ["./alibabacloud-kms-agent", "agent", "./config.toml"]

  3. 將步驟1和步驟2建立的檔案拷貝到deploy/ack/agent目錄下。

    deploy/ack/agent
    ├── alibabacloud-kms-agent
    ├── config.toml
    ├── Dockerfile.agent
  4. 編譯sidecar容器鏡像並上傳到阿里雲鏡像服務。

    # 編譯
    docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0 .
    # 上傳
    docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0

步驟五:製作業務容器鏡像

  1. 以業務應用部署在deploy/ack/app路徑下為例,在該路徑下編寫應用程式容器鏡像的Dockerfile。

    # Use the centos image as the base
    FROM centos:centos7
    
    # Set the working directory inside the container
    WORKDIR /
    
    # Set the entry point to run the kms agent
    ENTRYPOINT ["sleep", "360000"]

  2. 編譯應用程式容器鏡像,並將鏡像上傳到阿里雲鏡像倉庫。

    # 編譯
    docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0 .
    # 上傳
    docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0

步驟六:發布應用

方法一:自訂Deployment模板

編寫一個自訂的deployment模板,將KMS Agent與應用程式容器部署在同一個Pod中作為附加容器。如下所示,將app與sidecar容器放到同一個Pod或者Deployment裡一起部署。如何運行您的容器應用,請參見建立無狀態工作負載Deployment

  • KMS_TOKEN:指定Agent啟動時產生的SSRF Token檔案的儲存路徑。

  • ALIBABA_CLOUD_ROLE_ARN:RAM角色的ARN。

  • ALIBABA_CLOUD_OIDC_PROVIDER_ARN :OIDC身份供應商的ARN,此處為ACK叢集ARN。

  • ALIBABA_CLOUD_OIDC_TOKEN_FILE:包含OIDC Token的檔案路徑。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: rrsa-dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      serviceAccountName: dev-sa
      containers:
      - name: kmsagent
        image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0
        env:
        - name: ALIBABA_CLOUD_ROLE_ARN
          value: acs:ram::<uid>:role/dev-role-for-rrsa
        - name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
          value: acs:ram::<uid>:oidc-provider/ack-rrsa-<ackClusterId>
        - name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
          value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
        - name: KMS_TOKEN
          value: file:///var/run/kmstoken/token
        volumeMounts:
          - name: shared-volume
            mountPath: /var/run/kmstoken
          - name: rrsa-oidc-token
            mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
            readOnly: true
        command: ["/bin/sh", "-c", "./alibabacloud-kms-agent token /var/run/kmstoken/token && ./alibabacloud-kms-agent agent config.toml"]
      - name: my-app
        image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns/<repo>:app-v1.0
        volumeMounts:
          - name: shared-volume
            mountPath: /var/run/kmstoken
      volumes:
        - name: shared-volume
          emptyDir: {}
        - name: rrsa-oidc-token
          projected:
            defaultMode: 420
            sources:
            - serviceAccountToken:
               audience: sts.aliyuncs.com
               expirationSeconds: 3600
               path: token

方法二:安裝OpenKruise,配置注入規則

OpenKruise是基於Kubernetes的一個標準向外延展群組件,可以配合原生Kubernetes使用,高效管理應用程式容器、Sidecar容器及鏡像分發。詳細介紹,請參見使用OpenKruise部署雲原生應用

  1. 安裝OpenKruise。image

    1. 登入Container Service管理主控台,在左側導覽列選擇叢集列表

    2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,單擊組件管理

    3. 組件管理頁面,單擊應用管理頁簽。在ack-kruise地區,單擊安裝

      安裝ack-cruise對話方塊確認組件資訊後,單擊確認

  2. 設定Sidecar注入規則。

    設定Sidecar容器注入規則,為帶有標籤label: app的Pod注入Sidecar容器。

    • 環境變數定義:

      • KMS_TOKEN:指定Agent啟動時產生的SSRF Token檔案的儲存路徑。

      • ALIBABA_CLOUD_ROLE_ARN:RAM角色的ARN。

      • ALIBABA_CLOUD_OIDC_PROVIDER_ARN :OIDC身份供應商的ARN,此處為ACK叢集ARN。

      • ALIBABA_CLOUD_OIDC_TOKEN_FILE:包含OIDC Token的檔案路徑。

    • selector 定義:選擇需要注入sidecar的Pod,可以根據實際情況修改,本文以對帶有標籤app的Pod注入sidecar容器為例。

    apiVersion: apps.kruise.io/v1alpha1
    kind: SidecarSet
    metadata:
      name: kms-agent-sidecarset
      namespace: rrsa-dev
    spec:
      serviceAccountName: dev-sa
      containers:
      - name: kms-agent
        image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0
        env:
        - name: ALIBABA_CLOUD_ROLE_ARN
          value: acs:ram::<uid>:role/dev-role-for-rrsa
        - name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
          value: acs:ram::<uid>:oidc-provider/ack-rrsa-<ackClusterId>
        - name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
          value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
        - name: KMS_TOKEN
          value: file:///var/run/kmstoken/token
        volumeMounts:
           - name: shared-volume
             mountPath: /var/run/kmstoken
           - name: rrsa-oidc-token
             mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
             readOnly: true
        command: ["/bin/sh", "-c", "./alibabacloud-kms-agent token /var/run/kmstoken/token && ./alibabacloud-kms-agent agent config.toml"]
      # 用於選擇需要注入 sidecar 的 Pod,可以根據實際情況修改
      selector:
        matchLabels:
          app: app
      volumes:
         - name: shared-volume
           emptyDir: {}
         - name: rrsa-oidc-token
           projected:
             defaultMode: 420
             sources:
             - serviceAccountToken:
                 audience: sts.aliyuncs.com
                 expirationSeconds: 3600
                 path: token
  3. 自動注入KMS Agent。

    編寫Deployment檔案,在ACK上發布應用,labels標註上app: app,才能被注入Sidecar容器。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-with-kmsagent
      namespace: rrsa-dev
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: app
      template:
        metadata:
          labels:
            app: app
        spec:
          serviceAccountName: dev-sa
          containers:
          - name: my-app
            image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0
            volumeMounts:
              - name: shared-volume
                mountPath: /var/run/kmstoken
          volumes:
            - name: shared-volume
              emptyDir: {}
  4. 運行您的容器應用。具體操作,請參見建立無狀態工作負載Deployment

    應用啟動,可以看到在應用所在Pod裡,已經被注入了kms agent代理容器。

    image.png

步驟七:建立並擷取憑據值

  1. 在KMS建立憑據。

    本文樣本中建立憑據時需要加上標籤 env:dev,應用程式容器只能擷取到有這個標籤的憑據,沒有許可權擷取其他憑據。

    1. 登入Key Management Service控制台,在頂部功能表列選擇地區後,在左側導覽列單擊资源 > 凭据管理

    2. 單擊通用凭据頁簽,選擇实例ID後,單擊创建凭据,完成各項配置後單擊確定

      配置項

      說明

      凭据名称

      自訂的憑據名稱。憑據名稱在當前地區內唯一。

      设置凭据值

      根據您要託管的敏感性資料類型,選擇憑據鍵/值純文字

      長度不超過30720位元組(30KB)。

      初始版本号

      憑據的初始版本號碼。預設為v1,也支援自訂版本號碼。

      加密主密钥

      選擇用於加密憑據值的密鑰。

      重要
      • 密鑰和憑據需要屬於同一個KMS執行個體,且密鑰必須為對稱金鑰。關於KMS支援哪些對稱金鑰,請參見密鑰管理類型和密鑰規格

      • 如果是RAM使用者、RAM角色,需要具備使用加密主要金鑰執行GenerateDataKey操作的許可權。

      標籤

      憑據的標籤,方便您對憑據進行分類管理。每個標籤由一個索引值對(Key:Value)組成,包含標籤鍵(Key)、標籤值(Value)。

      說明
      • 標籤鍵和標籤值的格式:最多支援128個字元,可以包含英文大小寫字母、數字、正斜線(/)、反斜線(\)、底線(_)、短劃線(-)、半形句號(.)、加號(+)、等號(=)、半形冒號(:)、字元at(@)、空格。

      • 標籤鍵不能以aliyun或acs:開頭。

      • 每個憑據最多可以設定20個標籤索引值對。

      描述信息

      憑據的描述資訊。

      高级设置 > 策略配置

      憑據的策略配置。詳細介紹,請參見憑據策略概述

      您可以先選擇預設策略,建立憑據後根據業務需要再修改策略。

  2. 擷取憑據值。

    • 使用curl命令。

      curl -v -H "X-Vault-Token:$(</var/run/kmstoken/token)" 'http://localhost:2025/secretsmanager/get?secretId=app/dev/secret-1'
    • 在業務代碼裡使用HTTP GET請求擷取憑據。

      package main
      
      import (
      	"fmt"
      	"io/ioutil"
      	"net/http"
      )
      
      func main() {
      	url := fmt.Sprintf("http://localhost:2025/secretsmanager/get?secretId=%s", "app/dev/secret-1")
      
      	token, err := ioutil.ReadFile("/var/run/kmstoken/token")
      	if err != nil {
      		fmt.Printf("error reading token file: %v\n", err)
      	}
      
      	req, err := http.NewRequest("GET", url, nil)
      	if err != nil {
      		fmt.Printf("error creating request: %v\n", err)
      	}
      
      	req.Header.Add("X-KMS-Token", string(token))
      
      	client := &http.Client{}
      	resp, err := client.Do(req)
      	if err != nil {
      		fmt.Printf("error sending request: %v \n", err)
      	}
      	defer resp.Body.Close()
      
      	body, _ := ioutil.ReadAll(resp.Body)
      	fmt.Printf("status code %d - %s \n", resp.StatusCode, string(body))
      }