When you deploy hundreds of containerized applications, embedding static credentials in each image creates a 'last key' security risk and increases maintenance overhead. You can deploy KMS Agent as a sidecar in your ACK cluster to retrieve secrets dynamically from Key Management Service (KMS) using the RRSA mechanism, eliminating the need for SDK integration in your application code.
Key concepts
Understand the following concepts before you proceed:
-
What is KMS Agent: KMS Agent is an HTTP proxy service that retrieves secrets from KMS and caches them in memory. Applications retrieve secrets from the agent through HTTP requests.
-
RAM Roles for Service Accounts (RRSA): RRSA allows you to isolate application permissions in an ACK cluster by binding different RAM roles to different Pods. Each application assumes an independent RAM role to access Alibaba Cloud APIs.
Use cases
Use KMS Agent with RRSA in the following scenarios:
-
Eliminate the "last key" problem
Storing sensitive credentials in KMS improves security, but accessing KMS itself requires authentication. Relying on a static AccessKey to access KMS creates a new security risk.
By enabling RRSA on an ACK cluster, each Pod can assume a different RAM role and use temporary security credentials to access KMS. This implements the principle of least privilege and eliminates the need for static AccessKeys, preventing credential leaks.
-
Isolate secret access across applications and environments
You need to restrict access to secrets between test and production environments, or between different applications, to prevent privilege escalation and unauthorized secret access.
With RRSA, each application runs in a separate namespace with its own service account and RAM role. Granting different permissions to each RAM role enforces fine-grained access control to KMS secrets.
-
Reduce KMS integration costs at scale
KMS SDK integration scales poorly for enterprises with hundreds of applications. Ensuring consistent caching, disaster recovery, and security standards across all applications is difficult, especially when security, operations, and development teams are separate.
KMS Agent solves this by running as a sidecar in the same Pod as your application. After RRSA is enabled, the agent automatically authenticates to KMS and caches secrets in memory. Your application retrieves secrets from the local agent without any SDK integration.
Solution architecture
The following figure shows an example with two applications: dev and prod. Each application can access only its own KMS secrets.
Limitations
-
Supported ACK cluster types: ACK managed clusters, ACK dedicated clusters, ACK registered clusters, and ACK Serverless clusters.
-
The ACK cluster and the KMS instance must reside in the same region.
Prerequisites
-
Docker is installed and configured on your build machine.
-
kubectl is configured with access to your ACK cluster.
-
You have an Alibaba Cloud account with the required RAM and KMS permissions.
-
A KMS instance exists in the same region as your ACK cluster.
-
Go 1.18 or later is installed.
-
Git is installed.
Procedure
This procedure walks through the ACK, RAM, and KMS configurations needed for an application to retrieve secrets via KMS Agent. Developers only need to create a secret in KMS and read it locally — the operations and security teams handle the infrastructure setup beforehand. No SDK integration, authentication logic, or caching design is required in the application code.
Step 1: Build the KMS Agent executable
-
Install Go. For instructions, see the Go installation guide.
-
Download the source code and dependencies.
-
Download and install Git from the official Git website.
-
Run the following commands to clone the repository and download dependencies:
git clone https://github.com/aliyun/alibabacloud-kms-agent go mod download
-
-
In the project root directory, run
go build .to compile the executable. The default executable name isalibabacloud-kms-agent, saved in the project root directory.If the build environment and deployment environment are the same, run
go build .directly. For cross-platform builds, use the following commands to generate a 64-bit executable:Build environment
Deploy to macOS
Deploy to Linux
Deploy to Windows
macOS
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 . -
In the project root directory, confirm that the
alibabacloud-kms-agentexecutable exists.
Step 2: Enable RRSA and authorize access to secrets
-
Enable RRSA for your ACK cluster.
Enable during cluster creation
When creating an ACK managed cluster or ACK Edge cluster, go to the Cluster Configurations step, expand Advanced Options (Optional), and click Enable next to RRSA OIDC.

Enable for an existing cluster
Log on to the ACK console. In the left navigation pane, click Clusters.
Click the name of your cluster. In the left navigation pane, click Cluster Information.
On the Basic Information tab, scroll to the Security and Auditing section and click Enable next to RRSA OIDC.

In the Enable RRSA dialog box, click Confirm. Wait for the cluster status to change from Updating to Running. RRSA is now enabled.
-
Go to the cluster details page. On the Basic Information tab, in the Security and Auditing section, hover over the Enabled status next to RRSA OIDC to view the provider URL and ARN.

-
Create a RAM role with an identity provider as the trusted entity.
-
Log on to the RAM console as a RAM administrator. In the left-side navigation pane, choose .
-
Click Create Role. On the create page, click Switch to Policy Editor in the upper-right corner.
-
In the editor, specify the OIDC identity provider. Select Visual Editor mode and configure the following settings:
NoteFor more information about other modes, see Create a RAM role for an OIDC identity provider.
-
In the Principal section, select IdP, and then click Edit.
-
In the Add Principal dialog box, configure the following parameters:
-
IdP Type: Select OIDC.
-
IdP: After RRSA is enabled, ACK creates a default identity provider named
ack-rrsa-<cluster_id>, where<cluster_id>is your cluster ID. -
Action: Keep the default
sts:AssumeRole. -
Condition: Add a new condition alongside the default
oidc:issandoidc:audconditions:-
Condition key: Select oidc:sub.
-
Operator: Select StringEquals.
-
Condition value: Enter
system:serviceaccount:<namespace>:<serviceAccountName>.-
<namespace>: The namespace where the application resides. -
<serviceAccountName>: The name of the service account.
This example uses
system:serviceaccount:rrsa-dev:dev-sa, whererrsa-devis the Kubernetes namespace anddev-sais the service account you will create in Step 3. -
-
-
-
-
In the Create Role dialog box, set a role name and click OK. This example uses
dev-role-for-rrsa. -
Review the trust policy for
dev-role-for-rrsa. The policy allows a specific service account to assume the RAM role through RRSA after passing OIDC authentication.{ "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" }
-
-
Create a permission policy and attach it to the RAM role.
-
Create a permission policy. This example uses the policy name
dev-role-for-rrsa-kms-policyand allows access only to secrets tagged withenv:dev.
The policy content is as follows:
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "kms:Decrypt", "kms:GetSecretValue" ], "Resource": "*", "Condition": { "StringEqualsIgnoreCase": { "kms:tag/env": [ "dev" ] } } } ] } -
Attach the
dev-role-for-rrsa-kms-policypolicy to thedev-role-for-rrsarole.
-
Step 3: Create a namespace and service account
A namespace divides an ACK cluster into logically isolated virtual spaces for different environments such as development, testing, and production. By default, applications in different namespaces cannot access each other's resources. A service account provides an identity for a Pod and dynamically binds to a RAM role through RRSA.
-
Create a namespace YAML file.
Create a file named
namespace.yamlwith the following content. This example creates a namespace namedrrsa-dev.apiVersion: v1 kind: Namespace metadata: name: rrsa-dev -
Run the following command to create the namespace:
kubectl apply -f namespace.yamlVerify the namespace was created:
kubectl get namespacesIf the output includes
rrsa-dev, the namespace is created successfully. -
Create a service account YAML file.
Create a file named
serviceaccount.yamlwith the following content. This example creates a service account nameddev-sain therrsa-devnamespace.apiVersion: v1 kind: ServiceAccount metadata: name: dev-sa namespace: rrsa-dev -
Run the following command to create the service account:
kubectl apply -f serviceaccount.yamlVerify the service account was created:
kubectl get serviceaccount -n rrsa-devIf the output includes
dev-sa, the service account is created successfully.
Step 4: Build the sidecar container image
Package KMS Agent as a sidecar container to deploy alongside your application in ACK.
-
Configure the KMS Agent runtime parameters in
config.toml.NoteThe
config.tomlfile is located in theconfigsdirectory of the alibabacloud-kms-agent source code obtained in Step 1.[Server] HttpPort = 2025 [KMS] Region = "cn-hangzhou" [Cache] CacheType = "InMemory" CacheSize = 1000 TtlSeconds = 300 [Log] LogLevel = "Debug" LogPath = "./logs/" MaxSize = 100 MaxBackups = 2 -
Create a
Dockerfile.For example, create a Dockerfile in
deploy/ack/agentto deploy the agent. For the file content, see 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"] -
Copy the executable and configuration to the
deploy/ack/agentdirectory:deploy/ack/agent ├── alibabacloud-kms-agent ├── config.toml ├── Dockerfile.agent -
Build the sidecar image and push it to Container Registry:
# Build the image. docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0 . # Push the image. docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0
Step 5: Build the application container image
-
For an application deployed in
deploy/ack/app, create a Dockerfile in that directory:# 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"] -
Build the application image and push it to Container Registry:
# Build the image. docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0 . # Push the image. docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0
Step 6: Deploy the application
Custom deployment template
Define a custom Deployment that runs KMS Agent as a sidecar alongside the application container in the same Pod. For more information about running containerized applications, see Create a stateless workload Deployment.
-
KMS_TOKEN: The storage path for the SSRF token file generated by the agent on startup. -
ALIBABA_CLOUD_ROLE_ARN: The ARN of the RAM role. -
ALIBABA_CLOUD_OIDC_PROVIDER_ARN: The ARN of the OIDC identity provider (the ACK cluster ARN). -
ALIBABA_CLOUD_OIDC_TOKEN_FILE: The path to the file that contains the 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 injection
OpenKruise is a standard Kubernetes extension that efficiently manages application containers, sidecar containers, and image distribution. For more information, see Deploy a cloud-native application by using OpenKruise.
-
Install OpenKruise.

Log on to the ACK console. In the left navigation pane, click Clusters.
On the Clusters page, click the name of your cluster. In the left navigation pane, click Components and Add-ons.
-
On the Add-ons page, click the Manage Applications tab. In the ack-kruise section, click Install.
In the Install ack-kruise dialog box, confirm the add-on information and click OK.
-
Configure the sidecar injection rule.
Define a SidecarSet that injects the KMS Agent sidecar into Pods with the
applabel.-
Environment variables:
-
KMS_TOKEN: The storage path for the SSRF token file generated by the agent on startup. -
ALIBABA_CLOUD_ROLE_ARN: The ARN of the RAM role. -
ALIBABA_CLOUD_OIDC_PROVIDER_ARN: The ARN of the OIDC identity provider (the ACK cluster ARN). -
ALIBABA_CLOUD_OIDC_TOKEN_FILE: The path to the file that contains the OIDC token.
-
-
selector: selects the Pods to inject the sidecar into. Modify the label selector to match your application.
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"] # Modify the selector to match your application Pods. 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 -
-
Deploy the application with automatic KMS Agent injection.
Create a Deployment with the
app: applabel so the sidecar is automatically injected.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: {} -
Run your containerized application. For more information, see Create a stateless workload Deployment.
After the application starts, the KMS Agent sidecar is injected into the Pod.

Step 7: Create and retrieve a secret
-
Create a secret in KMS.
Add the tag
env:devwhen you create the secret. The application container can only access secrets with this tag.Log on to the Key Management Service console. In the top navigation bar, select a region. In the left-side navigation pane, choose .
-
Click the Generic Secrets tab, select a Instance ID, and then click Create Secret. Configure the parameters and click OK.
Parameter
Description
Secret Name
A custom credential name. Must be unique within the current region.
Secret Value
Select Secret Key/Value or Plain Text and enter the sensitive data to store. The value must be up to 30,720 bytes (30 KB) in length.
Initial Version
The initial version number. Default value: v1. Custom values are supported.
CMK
Select the symmetric key used to encrypt the credential value. The key and the credential must belong to the same KMS instance.
ImportantThe key and the credential must belong to the same KMS instance, and the key must be a symmetric key. For more information about the symmetric keys supported by KMS, see Key types and specifications.
If a RAM user or RAM role is used, it must have permissions to perform the GenerateDataKey operation using the encryption master key.
Description
An optional description of the credential for identification and management.
Set the access policy for the credential to control which RAM users or roles can read or modify it.
You can select the default policy first and modify it later as needed.
-
Retrieve the secret value.
-
Use the
curlcommand:curl -v -H "X-KMS-Token:$(</var/run/kmstoken/token)" 'http://localhost:2025/secretsmanager/get?secretId=app/dev/secret-1' -
Retrieve the secret in your application code via an HTTP GET request:
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)) }
-