All Products
Search
Document Center

Key Management Service:ACK rapidly integrates KMS Agent through ack-kms-agent-webhook-injector component

Last Updated:Jul 25, 2025

This topic describes how Alibaba Cloud ACK integrates KMS Agent through the ack-kms-agent-webhook-injector component.

Overview

Architecture

Alibaba Cloud Container Service for Kubernetes (ACK) provides the ack-kms-agent-webhook-injector component, which injects KMS Agent as a sidecar container into pods through specific annotations (kms-agent-webhook-injector/inject). This allows applications in containers to access credentials from KMS instances through local HTTP interfaces and cache them in memory, avoiding hardcoded sensitive information and ensuring data security. Additionally, the caching mechanism of KMS Agent improves stability when accessing KMS in high concurrency and unstable network scenarios, enhancing the user experience. The following figure shows the architecture:

image

Limits

  • ACK cluster type limitations: Supports ACK managed and dedicated clusters, ACK serverless clusters.

  • Region limitations: ACK clusters and KMS instances must be in the same region.

  • Performance limitations: Because each pod runs a KMS Agent sidecar container independently, if your business deploys many pods, throttling will be triggered if STS Token requests exceed 500 per minute during authentication, which will affect the normal operation of KMS Agent.

Billing

  • KMS billing:

    • Subscription billing: Before using KMS Agent, you need to purchase a KMS instance. Using KMS Agent itself does not incur additional charges. For more information, see Subscription.

    • Pay-as-you-go billing: In addition to the costs you have already incurred, when using KMS Agent to obtain credentials, additional QPS call fees will be generated due to API call requests. For more information, see Pay-as-you-go.

  • ACK billing:

    The ack-kms-agent-webhook-injector component itself is completely free, but using this component may incur additional costs.

    • After installing the ack-kms-agent-webhook-injector component, a Webhook service workload will be generated, which will occupy certain computing resources and incur costs. You can limit the CPU and memory usage of this workload in the configuration file.

    • When you create or update workloads that meet the conditions, ack-kms-agent-webhook-injector will inject KMS Agent into your container as a sidecar, and KMS Agent will use certain computing resources and incur costs.

Authentication methods

Two authentication methods are supported: RRSA and Worker RAM role.

  • (Recommended) Method 1: RRSA method

    This method can achieve pod-level permission isolation. It is applicable to ACK managed clusters and ACK serverless clusters with version 1.22 and above.

    Important

    To achieve pod-level permission isolation, the version of ack-kms-agent-webhook-injector must be greater than or equal to v0.2.0.

    For example, through the RRSA method, you can allow applications deployed in app1-dev to use the app1-rrsa role to access credentials in KMS with the secret:app1 tag. Applications deployed in app2-dev use the app2-rrsa role to access credentials in KMS with the secret:app2 tag.

image
  • Method 2: Worker RAM role method

    This method can achieve worker-level permission isolation. Since ACK serverless clusters do not support binding Worker RAM roles, this method is only applicable to ACK managed clusters and ACK dedicated clusters.

    For example, you can use Worker RAM roles to set up applications in app1-dev and app2-dev to access credentials managed in KMS. Applications in the same worker use the same Worker RAM role, meaning you cannot set different permissions for app1-dev and app2-dev.

image

Prerequisites

Step 1: Configure authentication information to allow KMS Agent to access specific credentials

Method 1: RRSA authorization

For example, if you have two applications app1 and app2, app1 needs to access credentials in the KMS instance labeled with secret: app1, and app2 needs to access credentials in the KMS instance labeled with secret: app2.

  • app1's namespace is app1-dev, serviceAccountName is app1-service, and RAM role is app1-rrsa.

  • app2's namespace is app2-dev, serviceAccountName is app2-service, and RAM role is app2-rrsa.

  1. Enable ACK RRSA feature.

    Enable during cluster creation

    When you create an ACK managed cluster or ACK Edge cluster, click Enable next to RRSA OIDC in the Advanced Options (Optional) section of the Cluster Configurations step.

    image

    Enable after cluster creation

    1. Log on to the ACK console. In the navigation pane on the left, click Clusters.

    2. On the Clusters page, find the target cluster and click its name. In the navigation pane on the left, click Cluster Information.

    3. In the Security and Auditing section of the Basic Information tab, click Enable next to RRSA OIDC.image

    4. In the Enable RRSA dialog box, click Confirm.

      In the Basic Information section, if the cluster status changes from Updating to Running, the RRSA feature is enabled for the cluster.

  2. Open the cluster details page, on the Basic Information tab, in the Security And Audit section, hover over the "Enabled" status on the right side of RRSA OIDC to view the provider's URL link and ARN information.image

  3. Create a RAM role for app1 with a trusted entity of Identity Provider, and authorize it to access credentials tagged with secret: app1. For more information, see Create a RAM role for a trusted IdP.

    1. Log on to the RAM console.

    2. In the navigation pane on the left, choose Identities > Roles, and then on the Roles page, click Create Role.

    3. In the Create Role panel, select Identity Provider as the trusted entity type, and click Switch To Editor.image

    4. On the Create Role page, in Visual Editor, configure the following role information and click OK.

      Parameter

      Description

      Effect

      Select Allow.

      Principal

      Select an identity provider.

      • Identity Provider Type: Select OIDC.

      • Identity Provider: After RRSA is enabled, the ACK cluster creates an identity provider by default, named in the format ack-rrsa-<cluster_id>. <cluster_id> indicates the ID of your cluster.

      Action

      Keep the default. That is, select sts:AssumeRole.

      Condition

      Based on the default oidc:iss and oidc:aud conditions, add a new condition:

      • Condition Key: Select oidc:sub.

      • Operator: Select StringEquals.

      • Condition Value: system:serviceaccount:<namespace>:<serviceAccountName>. In this example, it is system:serviceaccount:app1-dev:app1-service.

        • <namespace>: The namespace where the application that you want to inject KMS Agent is located.

        • <serviceAccountName>: The service account name used by the application that you want to inject KMS Agent. The service account name provides identity for the pod and can be dynamically bound to RAM roles through the RRSA mechanism.

        Note

        To configure for multiple service accounts in different namespaces, you can configure multiple values.

    5. In the Create Role dialog box, set the role name and click OK. In this example, the role name is app1-rrsa.

    6. (Optional) View the trust policy of the app1-rrsa RAM role.

      The trust policy indicates that the service account app1-service is allowed to assume a RAM role through Alibaba Cloud RRSA (RAM Roles for Service Accounts) after meeting the OIDC authentication conditions.image

    7. Create a policy.

      The policy name is app1-rrsa-kms-policy in this example, and the policy content is to access credentials tagged with secret: app1.image

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "kms:Decrypt",
                      "kms:GetSecretValue"
                  ],
                  "Resource": "*",
                  "Condition": {
                      "StringEqualsIgnoreCase": {
                          "kms:tag/secret": [
                              "app1"
                          ]
                      }
                  }
              }
          ]
      }
    8. Attach the app1-rrsa-kms-policy to the app1-rrsa role. For more information, see Grant permissions to a RAM role.image

  4. Create a RAM role for app2 with a trusted entity of Identity Provider, and authorize it to access credentials tagged with secret: app1. For more information, see Create a RAM role for a trusted IdP.

    1. Log on to the RAM console.

    2. In the navigation pane on the left, choose Identities > Roles, and then on the Roles page, click Create Role.

    3. In the Create Role panel, select Identity Provider as the trusted entity type, and click Switch To Editor.

    4. On the Create Role page, in Visual Editor, configure the following role information and click OK.

      Parameter

      Description

      Effect

      Select Allow.

      Principal

      Select an identity provider.

      • Identity Provider Type: Select OIDC.

      • Identity Provider: After RRSA is enabled, the ACK cluster creates an identity provider by default, named in the format ack-rrsa-<cluster_id>. <cluster_id> indicates the ID of your cluster.

      Action

      Keep the default. That is, select sts:AssumeRole.

      Condition

      Based on the default oidc:iss and oidc:aud conditions, add a new condition:

      • Condition Key: Select oidc:sub.

      • Operator: Select StringEquals.

      • Condition Value: system:serviceaccount:<namespace>:<serviceAccountName>. In this example, it is system:serviceaccount:app2-dev:app2-service.

        • <namespace>: The namespace where the application that you want to inject KMS Agent is located.

        • <serviceAccountName>: The service account name used by the application that you want to inject KMS Agent. The service account name provides identity for the pod and can be dynamically bound to RAM roles through the RRSA mechanism.

        Note

        To configure for multiple service accounts in different namespaces, you can configure multiple values.

    5. In the Create Role dialog box, set the role name and click OK. In this example, the role name is app2-rrsa.

    6. (Optional) View the trust policy of the app2-rrsa RAM role.

      The trust policy indicates that the service account app2-service is allowed to assume a RAM role through Alibaba Cloud RRSA (RAM Roles for Service Accounts) after meeting the OIDC authentication conditions.

    7. Create a policy.

      The policy name is app2-rrsa-kms-policy in this example, and the policy content is to access credentials tagged with secret: app2.

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "kms:Decrypt",
                      "kms:GetSecretValue"
                  ],
                  "Resource": "*",
                  "Condition": {
                      "StringEqualsIgnoreCase": {
                          "kms:tag/secret": [
                              "app2"
                          ]
                      }
                  }
              }
          ]
      }
    8. Attach the app2-rrsa-kms-policy to the app2-rrsa role. For more information, see Grant permissions to a RAM role.

Method 2: Worker RAM role authorization

Worker RAM role is a regular service role. You can specify a Default Role or a Custom Role for the worker node pool.

  • Default role: ACK managed clusters automatically create a default Worker RAM role shared by all nodes. When you authorize through the default Worker RAM role, permissions will be shared with all nodes in the cluster, which may pose a risk of unintended permission expansion.

  • (Recommended) Custom role: You need to create a regular service role in the Resource Access Management console in advance and specify this role for the node pool. By assigning specific roles to different node pools, you can isolate permissions for each node pool, reducing the risk of all nodes in the cluster sharing the same permissions. This topic uses a custom role as an example.

  1. Create a regular service role. The role name is ack-secret-manager in this example.

    1. Log on to the RAM console. In the navigation pane on the left, choose Identities > Roles.

    2. On the Roles page, click Create Role.

    3. On the Create Role page, select Trusted Entity Type as Alibaba Cloud Service, select Trusted Service Name as Container Service For Kubernetes, and then click OK.image

    4. In the Create Role dialog box, enter the role name and click OK.

  2. Create the following custom policy. The policy name is ack-secret-manager-policy in this example. For more information, see Create a custom policy.image

    {
      "Version": "1",
      "Statement": [
        {
          "Action": [
            "kms:GetSecretValue",
            "kms:Decrypt"
          ],
          "Resource": [
            "*"
          ],
          "Effect": "Allow"
        }
      ]
    }
  3. Attach the custom policy ack-secret-manager-policy to the custom role ack-secret-manager.image

  4. When creating a node pool, specify the Worker RAM role for the node pool.

    For Worker RAM Role, select Custom, and then select ack-secret-manager.image

    To create a node pool when creating a cluster, see Create an ACK managed cluster, Create an ACK serverless cluster. To create a node pool for an existing cluster, see Create and manage node pools.

Step 2: Create namespaces and service accounts in the ACK cluster

Namespaces divide the ACK cluster into logically isolated virtual spaces to separate development, testing, production, and other environments. Applications in different namespaces cannot access each other's resources by default, providing a physical boundary for RAM role binding.

Create two namespaces, app1-dev and app2-dev. The corresponding serviceAccountNames are app1-service and app2-service.

  1. Create a namespace named app1-dev using a YAML file.

    1. Create a YAML file named app1-namespace.yaml.

      apiVersion: v1
      kind: Namespace
      metadata:
        name: app1-dev
    2. Run the following command to create a namespace named app1-dev in the ACK cluster.

      kubectl apply -f app1-namespace.yaml
    3. Check if the namespace has been created successfully.

      kubectl get namespaces

      If the output includes app1-dev, the creation is successful.

  2. Create a service account named app1-service using a YAML file.

    1. Create a YAML file named app1-serviceaccount.yaml.

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: app1-service
        namespace: app1-dev
    2. Run the following command to create a service account named app1-service in app1-dev.

      kubectl apply -f app1-serviceaccount.yaml
    3. Check if the service account has been created successfully.

      kubectl get serviceaccount -n app1-dev

      If the output includes app1-service, the creation is successful.

  3. Repeat the above steps to create the app2-dev namespace and app2-service service account.

Step 3: Install the ack-kms-agent-webhook-injector component in the ACK cluster

  1. Log on to the Container Service console and click Clusters in the navigation pane on the left.

  2. On the Clusters page, click the name of the target cluster. In the navigation pane on the left, choose Applications > Helm.

  3. On the Helm page, click Create, configure Basic Information, and click Next.

    Parameter

    Description

    Application Name

    Enter your application name. We recommend that you use the default application name. You do not need to enter it here. After you click Next, you will be prompted to use the default application name ack-kms-agent-webhook-injector. Select Yes.

    Namespace

    Select the namespace where the application is located. We recommend that you use the default namespace. You do not need to select it here. After you click Next, you will be prompted to use the default namespace kube-system. Select Yes.

    Installing the component in one namespace in an ACK cluster is sufficient. There is no need to install it repeatedly.

    Source

    The default is App Catalog, which cannot be modified.

    Chart

    Search for and select ack-kms-agent-webhook-injector.

  4. In the dialog box that appears, confirm the information and click Yes.

    Selecting Yes means using the default installation path. The component is installed in the kube-system namespace by default and published as an application with the component name.image

  5. On the Parameters page, complete the configuration and click OK.

    Parameter

    Description

    Chart Version

    We recommend that you select the latest version.

    Parameters

    Configuration instructions for agent.auth.roleArn and agent.auth.roleArnMapping parameters:

    • When using RRSA authorization: agent.auth.roleArn is empty, and the format of agent.auth.roleArnMapping is <NameSpace>:<serviceAccountName>:<RAM Role ARN>.

      agent:
        auth:
          roleArn: 
          roleArnMapping:
            app1-dev:app1-service: acs:ram::190325303126****:role/app1-rrsa
            app2-dev:app2-service: acs:ram::190325303126****:role/app2-rrsa
    • When using Worker RAM role authorization: both agent.auth.roleArn and agent.auth.roleArnMapping are set to empty.

  6. Wait for about 30 seconds, enter the namespace (default is kube-system), and check the component status in the Deployments workload to confirm whether the component is ready.

Step 4: Inject KMS Agent into workloads

Inject KMS Agent into pods by configuring annotations. The specific operation varies depending on whether you are configuring for a new workload's pod or an existing workload's pod.

Take the stateless workload Deployment as an example. In this example, perform the following operations for app1-dev and app2-dev respectively.

  1. Log on to the Container Service console.

  2. Go to the target cluster and choose Workloads > Deployments in the navigation pane on the left.

  3. When creating or modifying a workload, add the following pod annotation: Name is kms-agent-webhook-injector/inject, Value is true (values 1, T, t, True, and TRUE are also considered valid).

    Scenario 1: Create a new workload using an image

    Click Create From Image, complete the configuration, and click Create.

    When filling in Advanced, in the Labels And Annotations section, add the following pod annotation: Name is kms-agent-webhook-injector/inject, Value is true.image

    Scenario 2: Create a new workload using YAML

    Click Create From YAML, complete the configuration, and click Create.

    Edit the spec.template.metadata.annotations section in the YAML file (if it does not exist, you need to create it), and add the key-value pair kms-agent-webhook-injector/inject: "true". For information about how to configure other parameters, see Workload YAML examples.image.png

    Scenario 3: Existing workloads

    1. Locate the target workload and click Details in the Actions column.

    2. On the workload details page, click the YAML button in the upper right corner, find the spec.template.metadata.annotations section (if it does not exist, you need to create it), and add the key-value pair kms-agent-webhook-injector/inject: "true".image.png

    3. Click Update and wait for the workload to be ready again.

  4. Return to the Deployments page, enter the workload, and you can observe in the Pods tab that KMS Agent has been injected into your workload as a sidecar in the Image column.

    Important

    When viewing images in the Pods tab, you may notice that the KMS Agent image has been injected twice into the pod. This is because we use an initialization container (initContainer) to perform necessary initialization work. This initialization container terminates (Terminated) after initialization is complete and does not negatively impact your application or continuously occupy your computing resources.

    image

  5. If you use RRSA authorization, modify the YAML configuration file to change the serviceAccountName parameter to the service account authorized in Step 1.

    In this example, they are app1-service and app2-service. After modification, the application and KMS Agent can be properly authorized to access KMS credentials.

    Note

    When using Worker RAM role authorization, there is no need to modify the configuration file. The service account can automatically assume the Worker RAM role to obtain permissions.

Step 5: Obtain KMS credentials in the application container

After KMS Agent is injected into the workload, you can send requests to KMS Agent through the HTTP protocol in the application container to obtain credentials stored in KMS.

Example:

  • The local host HTTP port number takes the default value 2025. If you set it to another port number, please replace 2025 in the example with the actual port number you are using.

  • The token path takes the default path file:///var/run/kmstoken/token. If you set another path, such as file:///var/run/path1/path2, please replace /var/run/kmstoken/token in the example with /var/run/path1/path2.

KMS Agent obtains the ACSCurrent version of credentials by default. To obtain credential values of other versions, you can set versionStage or versionId.

Important

KMS Agent only listens on 127.0.0.1, which means it only allows applications or processes on the same machine to communicate with it. External network devices cannot connect. The access address only supports localhost or 127.0.0.1, and does not support changing to the local IP of the application. The following examples use localhost.

Using curl

When using in practice, replace <SecretId> in the example code with your actual credential name.

 # Read token from file
 curl -v -H "X-KMS-Token:$(</var/run/kmstoken/token)" 'http://localhost:2025/secretsmanager/get?secretId=<SecretId>'
 
 # Write token directly
 curl -v -H "X-KMS-Token:<token>" 'http://localhost:2025/secretsmanager/get?secretId=<SecretId>'

You can specify versionStage or versionId to obtain specific credential values. For example, to obtain credential values with a specified versionId, replace 0a7513ee719da740807b15b77500**** with your actual credential version when using.

 # Read token from file
 curl -v -H "X-KMS-Token:$(</var/run/kmstoken/token)" 'http://localhost:2025/secretsmanager/get?secretId=<SecretId>&versionId=0a7513ee719da740807b15b77500****'
 
 # Write token directly
 curl -v -H "X-KMS-Token:<token>" 'http://localhost:2025/secretsmanager/get?secretId=<SecretId>&versionId=0a7513ee719da740807b15b77500****'

Go code example

When using, replace agent-test in the example code with your actual credential name.

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	
	//Support specifying versionStage or versionId to obtain specific credential values.
	//For example, to obtain credential values with a specified versionId, url := fmt.Sprintf("http://localhost:2025/secretsmanager/get?secretId=%s&versionId=%s", "agent-test", "version-id").
	url := fmt.Sprintf("http://localhost:2025/secretsmanager/get?secretId=%s", "agent-test")

	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))
}