Applications running in ACK clusters often need access to credentials, API keys, and other sensitive configuration stored in CloudOps Orchestration Service (OOS). Embedding those values in code or container images creates security and rotation risks. ack-secret-manager solves this by continuously syncing OOS encryption parameters into Kubernetes Secrets, so your application reads credentials from the cluster without any code changes.
How it works
ack-secret-manager uses two custom resource definitions (CRDs):
SecretStore — defines *how* ack-secret-manager authenticates with OOS (authorization config)
ExternalSecret — defines *what* to sync (which OOS parameter maps to which Kubernetes Secret key)
The component polls OOS on a configurable interval, writes the latest parameter value into a Kubernetes Secret, and keeps it in sync automatically. The resulting Kubernetes Secret has the same name and namespace as the ExternalSecret.
Security notes
Before enabling secret synchronization, assess the following risks:
File system exposure: When Secrets are mounted as files, a CVE (Common Vulnerabilities and Exposures) exploit in an application can allow directory traversal and leak the secrets.
Environment variable exposure: Misconfigured debug breakpoints or log permissions can expose secrets referenced as environment variables. Avoid this pattern.
Least privilege: Apply the least privilege principle when granting sync permissions. RRSA (RAM Roles for Service Accounts) enforces per-pod isolation — other pods cannot access secrets unless explicitly associated with the same RAM role.
For workloads that don't need to persist secrets, use RRSA to authorize pods and call the GetSecretParameter API directly from your application. This minimizes the exposure surface in the pod file system and Kubernetes Secrets.
Prerequisites
Before you begin, ensure that you have:
An ACK managed cluster, ACK dedicated cluster, registered cluster, or ACK Serverless cluster in the same region as your OOS service. See Create an ACK managed cluster, Create an ACK One registered cluster, and Create an ACK Serverless cluster
An OOS encryption parameter. See Create an encrypted parameter and CreateSecretParameter
kubectl configured to connect to the cluster. See Get a cluster kubeconfig and connect to the cluster using kubectl
Step 1: Install ack-secret-manager
Log on to the ACK console. In the left navigation pane, click Clusters.
On the Clusters page, click the name of the target cluster. In the left-side pane, choose Applications > Helm.
On the Helm page, click Deploy. In the Chart section, find and select ack-secret-manager, keep the default values for other parameters, and click Next. The confirmation message indicates that the chart installs in the
kube-systemnamespace by default. Click Yes. To use a custom namespace, configure Application Name and Namespace in the Basic information step.In the Parameters step, select the latest chart version, configure the parameters below, and click OK. Enable RRSA authentication (recommended): Set
rrsa.enableto true. Enable scheduled synchronization (optional): Configure throttling (required for large clusters): If your cluster has many ExternalSecrets, improper concurrency can trigger throttling on OOS or RAM.command.disablePolling: Set to false to enable automatic parameter rotation.command.pollingInterval: Sync frequency in seconds. In this example, this parameter is set to 120 seconds (every 2 minutes). You can adjust the value as needed.command.maxConcurrentOosSecretPulls: Maximum OOS parameters synced per second. Default: 10.



After installation, you are redirected to the ack-secret-manager page. Verify that the following resources are created:

Step 2: Authorize ack-secret-manager to access OOS
Create a SecretStore to grant ack-secret-manager access to OOS encryption parameters. Choose the authorization method based on your cluster type:
| Method | Cluster types | Notes |
|---|---|---|
| RRSA (recommended) | ACK managed clusters, ACK Serverless clusters (Kubernetes 1.22+) | Per-pod isolation; no AccessKey exposure |
| Worker RAM role | ACK managed clusters, ACK dedicated clusters, registered clusters | Not supported on ACK Serverless clusters |
| AccessKey pair | All cluster types | Requires storing an AccessKey secret in Kubernetes |
Use RRSA to grant permissions
RRSA isolates permissions at the pod level, avoiding the credential-leak risks associated with AccessKey pairs.
Enable the RRSA feature for your cluster. See Enable RRSA.
Set
rrsa.enableto true when installing ack-secret-manager.Create a RAM role with an OIDC identity provider (IdP) as the trusted entity. See Create a RAM role for an OIDC IdP. Use the following key parameters:
Parameter Value Identity provider type OIDC Identity provider Select the provider named ack-rrsa-<cluster_id>, where<cluster_id>is your cluster IDCondition — oidc:iss Use the default value Condition — oidc:aud Use the default value Condition — oidc:sub Add a StringEqualscondition. Set Key tooidc:suband Value tosystem:serviceaccount:<namespace>:<serviceAccountName>. Replace<namespace>with the namespace where ack-secret-manager is installed (default:kube-system) and<serviceAccountName>with the service account nameCreate and attach a custom RAM policy to the RAM role. See Create custom policies and Grant permissions to a RAM role.
{ "Action": [ "oos:GetSecretParameter", "kms:GetSecretValue" ], "Resource": [ "*" ], "Effect": "Allow" }Create a SecretStore. Replace the placeholders and save the file as
secretstore-rrsa.yaml:{accountID}: The Alibaba Cloud account ID used to sync OOS parameters{clusterID}: Your cluster ID{roleName}: The RAM role name you created in step 2
apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-rrsa spec: OOS: OOSAuth: oidcProviderARN: "acs:ram::{accountID}:oidc-provider/ack-rrsa-{clusterID}" ramRoleARN: "acs:ram::{accountID}:role/{roleName}"Apply the SecretStore:
kubectl apply -f secretstore-rrsa.yaml
Grant permissions to the worker RAM role
This method applies to ACK managed clusters, ACK dedicated clusters, and registered clusters. ACK Serverless clusters have no worker RAM role and cannot use this method.
Create a custom RAM policy. See Create custom policies.
{ "Action": [ "oos:GetSecretParameter", "kms:GetSecretValue" ], "Resource": [ "*" ], "Effect": "Allow" }Attach the policy to the cluster's worker RAM role. See Permissions of the worker RAM role of ACK managed clusters.
Use an AccessKey pair to assume a RAM role
This method applies to all ACK cluster types.
Create a RAM role with an Alibaba Cloud account as the trusted entity. See Create a RAM role for a trusted Alibaba Cloud account.
Create and attach a RAM policy that grants access to OOS encryption parameters. See Create custom policies and Grant permissions to a RAM role.
{ "Action": [ "oos:GetSecretParameter", "kms:GetSecretValue" ], "Resource": [ "*" ], "Effect": "Allow" }Create a RAM policy that allows assuming the RAM role, and attach it to the RAM user you want to use. Replace the ARN placeholder with the Alibaba Cloud Resource Name (ARN) of the RAM role you created in step 1.
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Resource": "acs:ram::***:role/****" } ], "Version": "1" }Attach the policy to the RAM user. See Grant permissions to RAM users.
Create a Kubernetes Secret to store the RAM user's AccessKey pair. Replace the placeholder values with the actual Base64-encoded credentials and save the file as
ramuser.yaml:apiVersion: v1 data: accessKey: {AccessKey ID encoded in Base64} accessKeySecret: {AccessKey secret encoded in Base64} kind: Secret metadata: name: ramuser namespace: kube-system type: OpaqueApply the Secret:
kubectl apply -f ramuser.yamlCreate a SecretStore. Replace the placeholders and save the file as
secretstore-ramrole.yaml:{accountID}: The Alibaba Cloud account ID used to sync OOS parameters{roleName}: The RAM role name you created in step 1{secretName}: The name of the Kubernetes Secret that stores the AccessKey pair{secretNamespace}: The namespace of that Secret{secretKey}: The key within that Secret{roleSessionName}: A custom session name string
apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-ramrole spec: OOS: OOSAuth: accessKey: name: {secretName} namespace: {secretNamespace} key: {secretKey} accessKeySecret: name: {secretName} namespace: {secretNamespace} key: {secretKey} ramRoleARN: "acs:ram::{accountID}:role/{roleName}" ramRoleSessionName: {roleSessionName}Apply the SecretStore:
kubectl apply -f secretstore-ramrole.yaml
Step 3: Sync OOS parameters to Kubernetes Secrets
After authorization is configured, create an ExternalSecret to specify which OOS parameters to sync and where to store them in Kubernetes.
Create an ExternalSecret. Replace the placeholders and save the file as
external.yaml:apiVersion: 'alibabacloud.com/v1alpha1' kind: ExternalSecret metadata: name: esdemo spec: provider: oos # Sync from OOS (default is kms) data: - key: {OOS parameter name} # Name of the OOS encryption parameter name: {Kubernetes secret key} # Key in the resulting Kubernetes Secret secretStoreRef: # Omit if using the worker RAM role method name: {secret store name} # Name of the SecretStore namespace: {secret store namespace}Apply the ExternalSecret:
kubectl apply -f external.yamlVerify that the sync succeeded:
kubectl get secret esdemoIf a Kubernetes Secret is created, the OOS encryption parameter has been synced to your cluster.
Advanced configurations
Cross-account parameter synchronization
If your OOS instance and ACK cluster belong to different Alibaba Cloud accounts, use cross-account RRSA to sync parameters. The following example imports a parameter from Account A into an ACK cluster in Account B.
Account A configurations
Use Account A to create a RAM role with Account B as the trusted entity. Select Other Alibaba Cloud Account and enter Account B's ID. See Create a RAM role for a trusted Alibaba Cloud account.
ImportantWhen selecting the trusted Alibaba Cloud account, select Other Alibaba Cloud Account and enter the ID of Account B.
Create and attach a RAM policy to grant OOS access. See Create custom policies and Grant permissions to a RAM role.
{ "Action": [ "oos:GetSecretParameter", "kms:GetSecretValue" ], "Resource": [ "*" ], "Effect": "Allow" }
Account B configurations
Enable RRSA for the ACK cluster. See Enable RRSA.
Set
rrsa.enableto true when installing ack-secret-manager.Create a RAM role with an OIDC identity provider (IdP) as the trusted entity. Use the same parameters as described in the RRSA authorization section. See Create a RAM role for an OIDC IdP.
Create a RAM policy that allows assuming Account A's RAM role, and attach it to the RAM role from step 2. Set
Resourceto the ARN of Account A's RAM role. To find the ARN, see How do I view the ARN of a RAM role?<account-id>: Account A's ID (where the Key Management Service (KMS) instance is located)<role-name>: The name of Account A's RAM role
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Resource": "acs:ram:*:<account-id>:role/<role-name>" } ], "Version": "1" }Attach the policy to Account B's RAM role. See Grant permissions to a RAM role.
Create a SecretStore. Replace the placeholders and save the file as
secretstore-cross-account.yaml:{ACK-accountID}: Account B's ID{clusterID}: Your cluster ID{ACK-roleName}: The RAM role name created by Account B{OOS-accountID}: Account A's ID{OOS-roleName}: The RAM role name created by Account A{roleSessionName}: A custom session name string
apiVersion: 'alibabacloud.com/v1alpha1' kind: SecretStore metadata: name: scdemo-cross-account spec: OOS: OOSAuth: oidcProviderARN: "acs:ram::{ACK-accountID}:oidc-provider/ack-rrsa-{clusterID}" ramRoleARN: "acs:ram::{ACK-accountID}:role/{ACK-roleName}" remoteRamRoleARN: "acs:ram::{OOS-accountID}:role/{OOS-roleName}" remoteRamRoleSessionName: {roleSessionName}Create an ExternalSecret as described in Step 3: Sync OOS parameters to Kubernetes Secrets.
Parse structured parameters
Use jmesPath to extract specific fields from JSON or YAML-formatted OOS parameters into individual Kubernetes Secret keys.
Extract specific fields from a JSON parameter
If the following JSON value is stored in an OOS encryption parameter:
{"name":"tom","friends":[{"name":"lily"},{"name":"mark"}]}Use jmesPath to map specific fields to named keys in the Kubernetes Secret. path is a JMESPath expression. objectAlias is the resulting key in the Kubernetes Secret.
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: es-json-demo
spec:
provider: oos
data:
- key: {OOS parameter name}
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
jmesPath:
- path: "name"
objectAlias: "myname"
- path: "friends[0].name"
objectAlias: "friendname"Automatically parse a JSON parameter
If you don't know the structure of the JSON parameter, use dataProcess.extract to parse all fields automatically. Use dataProcess.replaceRule to rewrite keys that don't meet Kubernetes naming requirements.
For example, if the OOS parameter contains:
{"/name-invalid":"lily","name-invalid/":[{"name":"mark"}]}The keys /name-invalid and name-invalid/ are invalid as Kubernetes Secret keys. Use replaceRule to rename them:
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: extract-secret
spec:
provider: oos
dataProcess:
- extract:
key: {OOS parameter name}
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
replaceRule:
- source: "^/.*d$" # Keys starting with / and ending with d → renamed to "tom"
target: "tom"
- source: "^n.*/$" # Keys starting with n and ending with / → renamed to "mark"
target: "mark"Extract specific fields from a YAML parameter
If the following YAML value is stored in an OOS encryption parameter:
name: tom
friends:
- name: lily
- name: markUse the same jmesPath approach as for JSON:
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: es-yaml-demo
spec:
provider: oos
data:
- key: {OOS parameter name}
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
jmesPath:
- path: "name"
objectAlias: "myname"
- path: "friends[0].name"
objectAlias: "friendname"Automatically parse a YAML parameter
If the OOS parameter contains:
/name-invalid: lily
name-invalid/:
- name: markUse the same dataProcess.extract and replaceRule approach as for JSON:
apiVersion: 'alibabacloud.com/v1alpha1'
kind: ExternalSecret
metadata:
name: extract-secret
spec:
provider: oos
dataProcess:
- extract:
key: {OOS parameter name}
secretStoreRef:
name: {secret store name}
namespace: {secret store namespace}
replaceRule:
- source: "^/.*d$" # Keys starting with / and ending with d → renamed to "tom"
target: "tom"
- source: "^n.*/$" # Keys starting with n and ending with / → renamed to "mark"
target: "mark"What's next
To protect Kubernetes Secrets synced from OOS and cached in your ACK cluster, enable the Secret encryption feature. See Use KMS to encrypt Kubernetes Secrets.