Secrets Management
Upbound's Shared Secrets is a built in secrets management feature that provides an integrated way to manage secrets across your platform. It allows you to store sensitive data like passwords and certificates for your managed control planes as secrets in an external secret store.
This feature is a wrapper around the External Secrets Operator (ESO) that pulls secrets from external vaults and distributes them across your platform.
Benefits
The Shared Secrets feature allows you to:
- Access secrets from a variety of external secret stores without operation overhead
- Configure synchronization for multiple control planes in a group
- Store and manage all your secrets centrally
- Use Shared Secrets across all Upbound environments(Cloud and Disconnected Spaces)
- Synchronize secrets across groups of control planes while maintaining clear security boundaries
- Manage secrets at scale programmatically while ensuring proper isolation and access control
Understanding the Architecture
The Shared Secrets feature uses a hierarchical approach to centrally manage secrets and effectively control their distribution.

- The flow begins at the group level, where you define your secret sources and distribution rules
- These rules automatically create corresponding resources in your control planes
- In each control plane, specific namespaces receive the secrets
- Changes at the group level automatically propagate through this chain
Component configuration
Upbound Shared Secrets consists of two components:
- SharedSecretStore: Defines connections to external secret providers
- SharedExternalSecret: Specifies which secrets to synchronize and where
Connect to an External Vault
The SharedSecretStore component is the connection point to your external
secret vaults. It provisions ClusterSecretStore resources into control planes
within the group.
AWS Secrets Manager
In this example, you'll create a SharedSecretStore to connect to AWS
Secrets Manager in us-west-2. Then apply access to all control planes labeled with
environment: production, and make these secrets available in the default and
crossplane-system namespaces.
You can configure access to AWS Secrets Manager using static credentials or workload identity.
While the underlying ESO API supports more auth methods, static credentials are currently the only supported auth method in Cloud Spaces.
Static credentials
-
Use the AWS CLI to create access credentials.
-
Create your access credentials.
# Create a text file with AWS credentials
cat > aws-credentials.txt << EOF
[default]
aws_access_key_id = <YOUR_ACCESS_KEY_HERE>
aws_secret_access_key = <YOUR_SECRET_ACCESS_KEY_HERE>
EOF
- Next,store the access credentials in a secret in the namespace you want to have access to the
SharedSecretStore.
kubectl create secret \
generic aws-credentials \
-n default \
--from-file=creds=./aws-credentials.txt
- Create a
SharedSecretStorecustom resource file calledsecretstore.yaml. Paste the following configuration:
apiVersion: spaces.upbound.io/v1alpha1
kind: SharedSecretStore
metadata:
name: aws-secrets
spec:
# Define which control planes should receive this configuration
controlPlaneSelector:
labelSelectors:
- matchLabels:
environment: production
# Define which namespaces within those control planes can access secrets
namespaceSelector:
names:
- default
- crossplane-system
# Configure the connection to AWS Secrets Manager
provider:
aws:
service: SecretsManager
region: us-west-2
auth:
secretRef:
accessKeyIDSecretRef:
name: aws-credentials
key: access-key-id
secretAccessKeySecretRef:
name: aws-credentials
key: secret-access-key
Azure Key Vault
While the underlying ESO API supports more auth methods, static credentials are currently the only supported auth method in Cloud Spaces.
Static credentials
- Use the Azure CLI to create a service principal and authentication file.
- Create a service principal and save credentials in a file:
{
"appId": "myAppId",
"displayName": "myServicePrincipalName",
"password": "myServicePrincipalPassword",
"tenant": "myTentantId"
}
- Store the credentials as a Kubernetes secret:
kubectl create secret \
generic azure-secret-sp \
-n default \
--from-file=creds=./azure-credentials.json
- Create a SharedSecretStore referencing these credentials:
apiVersion: spaces.upbound.io/v1alpha1
kind: SharedSecretStore
metadata:
name: azure-kv
spec:
provider:
azurekv:
tenantId: "<your-tenant-id>"
vaultUrl: "<your-vault-url>"
authSecretRef:
clientId:
name: azure-secret-sp
key: ClientID
clientSecret:
name: azure-secret-sp
key: ClientSecret
controlPlaneSelector:
names:
- <control-plane-name>
namespaceSelector:
names:
- default
Google Cloud Secret Manager
You can configure access to Google Cloud Secret Manager using static credentials. See the ESO provider API for more information.
While the underlying ESO API supports more auth methods, static credentials are currently the only supported auth method in Cloud Spaces.
Static credentials
-
Use the GCP CLI to create access credentials.
-
Save the output in a file called
gcp-credentials.json. -
Store the access credentials in a secret in the same namespace as the
SharedSecretStore.kubectl create secret \
generic gcpsm-secret \
-n default \
--from-file=creds=./gcp-credentials.json -
Create a
SharedSecretStore, referencing the secret created earlier. ReplaceprojectIDwith your GCP Project ID:
apiVersion: spaces.upbound.io/v1alpha1
kind: SharedSecretStore
metadata:
name: gcp-sm
spec:
provider:
gcpsm:
auth:
secretRef:
secretAccessKeySecretRef:
name: gcpsm-secret
key: creds
projectID: <your-gcp-project>
controlPlaneSelector:
names:
- <control-plane-name>
namespaceSelector:
names:
- default
The example above maps a Shared Secret Store into a single namespace of a single control plane. Read control plane selection and namespace selection to learn how to map into one or more namespaces of one or more control planes.
Manage your secret distribution
After you create your SharedSecretStore, you can define which secrets to distribute using SharedExternalSecret:
apiVersion: spaces.upbound.io/v1alpha1
kind: SharedExternalSecret
metadata:
name: database-credentials
namespace: default
spec:
# Select the same control planes as your SharedSecretStore
controlPlaneSelector:
labelSelectors:
- matchLabels:
environment: production
externalSecretSpec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets # References the SharedSecretStore name
kind: ClusterSecretStore
target:
name: db-credentials
data:
- secretKey: username
remoteRef:
key: prod/database/credentials
property: username
- secretKey: password
remoteRef:
key: prod/database/credentials
property: password
Control plane selection
To configure which control planes in a group you want to project a SecretStore into, use the spec.controlPlaneSelector field. You can either use labelSelectors or the names of a control plane directly. A control plane matches if any of the label selectors match.
Namespace selection
To configure which namespaces within each matched control plane to project the secret store into, use spec.namespaceSelector field.
Best practices
Use consistent labeling schemes across your control planes for predictable and manageable secret distribution.
Organize your secrets in your external provider using a hierarchical structure that mirrors your control plane organization.
Set appropriate refresh intervals based on your security requires and the nature of the secrets.
Use namespace selection sparingly to limit secret distribution to only the namespaces that need them.
Use separate tokens for each environment. Keep them in distinct SharedSecretStores.
Document your secret management architecture, including which control planes should receive which secrets.