Managed Services Credential Configuration
Tech Preview
This feature requires the HCPEtcdBackup feature gate enabled in the HyperShift Operator.
The HCPEtcdBackup controller automatically detects the authentication mode from the credential Secret referenced in the backup specification. This page describes how to configure credentials for managed service platforms (ROSA HCP and ARO HCP) that use short-lived, federated credentials instead of long-lived static keys.
OADP Plugin Secret Flow
The credential Secret originates in the OADP namespace (typically openshift-adp) and is always named cloud-credentials. It always uses the cloud data key. When the OADP HyperShift plugin triggers an etcd snapshot backup, it copies this Secret to the HyperShift Operator namespace, remapping the key and preserving the original:
| Namespace | Secret Name | Data Keys | |
|---|---|---|---|
| Source | <OADP_NAMESPACE/VELERO_NAMESPACE> |
cloud-credentials |
cloud |
| Destination | hypershift (HO namespace) |
cloud-credentials |
credentials (remapped from cloud) + cloud (preserved) |
The destination Secret contains both keys with the same content. The controller's credential auto-detection logic reads from the destination copy:
- For S3 storage: reads the
credentialskey (remapped fromcloud) - For Azure Blob storage: checks the
cloudkey first (preserved original), then falls back tocredentials
No manual Secret creation or copying is required — the OADP plugin handles this automatically for both ROSA HCP and ARO HCP.
Credential Auto-Detection
The controller inspects the content of the credential Secret to determine the authentication mode. No explicit configuration flag is required — the Secret format itself drives the behavior.
AWS Credential Modes
| Mode | Detection | PodSpec Behavior |
|---|---|---|
| Static | credentials key contains an AWS credentials file ([default] profile) |
Mounts credentials file at /etc/etcd-backup-creds/credentials, passes --credentials-file |
| STS/IRSA | credentials key contains a bare IAM role ARN (arn:aws:iam::...) |
Projected SA token volume (sts.amazonaws.com audience), AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE env vars, no credentials file |
Azure Credential Modes
| Mode | Detection | PodSpec Behavior |
|---|---|---|
| Workload Identity | Secret has a cloud key containing a non-empty AZURE_CLIENT_ID= value |
Pod label azure.workload.identity/use=true, SA annotated with azure.workload.identity/client-id, no credentials file, no --azure-auth-type flag |
| Client Secret | credentials key contains JSON with a non-empty clientSecret field |
Mounts credentials file, passes --credentials-file and --azure-auth-type client-secret |
| Managed Identity | credentials key contains JSON without a clientSecret field |
Mounts credentials file, passes --credentials-file and --azure-auth-type managed-identity |
ROSA HCP (AWS STS/IRSA)
ROSA HCP clusters use IAM Roles for Service Accounts (IRSA) via AWS Security Token Service (STS). The backup Job Pod authenticates to S3 using a projected ServiceAccount token exchanged for temporary AWS credentials.
Prerequisites
- An S3 bucket for storing etcd snapshots
- An IAM role with a trust policy allowing the OIDC provider associated with your management cluster
- The IAM role must have permissions to write objects to the target S3 bucket
IAM Role Trust Policy
The trust policy must allow the etcd-backup-job ServiceAccount in the HyperShift Operator namespace to assume the role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/<OIDC_PROVIDER>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<OIDC_PROVIDER>:sub": "system:serviceaccount:<HO_NAMESPACE>:etcd-backup-job"
}
}
}
]
}
Replace:
<ACCOUNT_ID>: Your AWS account ID<OIDC_PROVIDER>: The OIDC provider URL for your management cluster (withouthttps://)<HO_NAMESPACE>: The namespace where the HyperShift Operator runs (typicallyhypershift)
IAM Role Permissions
The role needs S3 write access:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:AbortMultipartUpload"
],
"Resource": [
"arn:aws:s3:::<BUCKET_NAME>",
"arn:aws:s3:::<BUCKET_NAME>/*"
]
}
]
}
Note
The s3:PutObject permission authorizes all multipart upload operations (CreateMultipartUpload, UploadPart, CompleteMultipartUpload) used by the AWS SDK v2 Transfer Manager, which automatically splits files larger than 5 MB into multipart uploads. Etcd snapshots typically range from 30-100 MB, so multipart upload is used in practice. s3:AbortMultipartUpload is included to clean up incomplete uploads on failure.
Credential Secret Format
The credential Secret in the OADP namespace uses the cloud key with the IAM role ARN:
apiVersion: v1
kind: Secret
metadata:
name: cloud-credentials
namespace: <OADP_NAMESPACE/VELERO_NAMESPACE>
type: Opaque
stringData:
cloud: "arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>"
The OADP plugin copies this Secret to the HyperShift Operator namespace, remapping cloud → credentials and preserving the original cloud key (see OADP Plugin Secret Flow). The controller reads the credentials key in the destination copy and detects STS mode when the value starts with arn:.
Note
The cloud value must be a bare ARN string, not an AWS credentials file.
HCPEtcdBackup CR
apiVersion: hypershift.openshift.io/v1beta1
kind: HCPEtcdBackup
metadata:
name: my-backup
namespace: <HCP_NAMESPACE>
spec:
storage:
storageType: S3
s3:
bucket: <BUCKET_NAME>
region: <REGION>
keyPrefix: etcd-backups
credentials:
name: cloud-credentials
What Happens at Runtime
When the controller detects STS mode:
- The ServiceAccount
etcd-backup-jobis created in the HO namespace (no special annotations needed for AWS IRSA — the projected token handles authentication) - The Job Pod gets a projected volume with a ServiceAccount token using audience
sts.amazonaws.comand 1-hour expiration - The upload container receives environment variables
AWS_ROLE_ARNandAWS_WEB_IDENTITY_TOKEN_FILE - No credentials file is mounted — the AWS SDK uses the projected token to assume the role via STS
ARO HCP (Azure Workload Identity)
ARO HCP clusters use Azure AD Workload Identity for pod-level authentication. The backup Job Pod authenticates to Azure Blob Storage using a federated token projected by the Azure Workload Identity webhook.
Prerequisites
- An Azure Storage Account with a blob container for storing etcd snapshots
- A User-Assigned Managed Identity with a federated credential configured for the backup Job's ServiceAccount
- The managed identity must have
Storage Blob Data Contributorrole on the storage account
Federated Credential
Create a federated credential on the managed identity that trusts the etcd-backup-job ServiceAccount:
az identity federated-credential create \
--name etcd-backup-fedcred \
--identity-name <MANAGED_IDENTITY_NAME> \
--resource-group <RESOURCE_GROUP> \
--issuer <OIDC_ISSUER_URL> \
--subject "system:serviceaccount:<HO_NAMESPACE>:etcd-backup-job" \
--audiences "api://AzureADTokenExchange"
Replace:
<MANAGED_IDENTITY_NAME>: Name of the User-Assigned Managed Identity<RESOURCE_GROUP>: Resource group containing the managed identity<OIDC_ISSUER_URL>: The OIDC issuer URL of your management cluster<HO_NAMESPACE>: The namespace where the HyperShift Operator runs (typicallyhypershift)
Important
The subject must match exactly: system:serviceaccount:<HO_NAMESPACE>:etcd-backup-job. The Job runs in the HO namespace, not the HCP namespace.
Storage Account Role Assignment
Assign the Storage Blob Data Contributor role to the managed identity on the storage account:
az role assignment create \
--assignee-object-id $(az identity show -n <MANAGED_IDENTITY_NAME> -g <RESOURCE_GROUP> --query principalId -o tsv) \
--role "Storage Blob Data Contributor" \
--scope /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Storage/storageAccounts/<STORAGE_ACCOUNT>
Credential Secret Format
The credential Secret in the OADP namespace uses the cloud key with Azure identity configuration in key-value format:
apiVersion: v1
kind: Secret
metadata:
name: cloud-credentials
namespace: <OADP_NAMESPACE/VELERO_NAMESPACE>
type: Opaque
stringData:
cloud: |
AZURE_SUBSCRIPTION_ID=<SUBSCRIPTION_ID>
AZURE_TENANT_ID=<TENANT_ID>
AZURE_CLIENT_ID=<MANAGED_IDENTITY_CLIENT_ID>
AZURE_RESOURCE_GROUP=<RESOURCE_GROUP>
AZURE_CLOUD_NAME=AzurePublicCloud
The OADP plugin copies this Secret to the HyperShift Operator namespace, remapping cloud → credentials and preserving the original cloud key (see OADP Plugin Secret Flow). The controller reads the destination copy and detects Workload Identity mode when it finds the cloud key. It extracts the AZURE_CLIENT_ID value to annotate the ServiceAccount.
Note
Fields like AZURE_FEDERATED_TOKEN_FILE and AZURE_AUTHORITY_HOST are not needed in the Secret — they are injected at runtime by the Azure Workload Identity webhook into the Pod environment.
HCPEtcdBackup CR
apiVersion: hypershift.openshift.io/v1beta1
kind: HCPEtcdBackup
metadata:
name: my-backup
namespace: <HCP_NAMESPACE>
spec:
storage:
storageType: AzureBlob
azureBlob:
container: <CONTAINER_NAME>
storageAccount: <STORAGE_ACCOUNT>
keyPrefix: etcd-backups
credentials:
name: cloud-credentials
What Happens at Runtime
When the controller detects Azure Workload Identity mode:
- The ServiceAccount
etcd-backup-jobis created in the HO namespace with annotationazure.workload.identity/client-id: <CLIENT_ID> - The Job Pod template gets the label
azure.workload.identity/use: "true" - The Azure Workload Identity webhook mutates the Pod to inject:
- A projected volume with a federated token
- Environment variables
AZURE_CLIENT_ID,AZURE_TENANT_ID,AZURE_FEDERATED_TOKEN_FILE,AZURE_AUTHORITY_HOST
- No credentials file is mounted and no
--azure-auth-typeflag is passed — the Azure SDK uses the injected federated token
OADP Plugin Integration
The OADP HyperShift plugin handles credential propagation automatically for both ROSA HCP and ARO HCP. No manual Secret creation or copying is required. The plugin copies the cloud-credentials Secret from the OADP namespace to the HyperShift Operator namespace, performing key remapping as described in the OADP Plugin Secret Flow section above. The controller then auto-detects the credential mode from the destination Secret content.
Troubleshooting
AWS STS: Access Denied
An error occurred (AccessDenied) when calling the <S3_OPERATION> operation
- Verify the IAM role trust policy allows the correct OIDC provider and ServiceAccount subject
- Confirm the IAM role has all required S3 permissions on the target bucket (
s3:PutObject,s3:AbortMultipartUpload) — see IAM Role Permissions - Check that the OIDC provider URL matches the management cluster's issuer
Azure WI: No Matching Federated Identity Record
AADSTS700213: No matching federated identity record found for presented assertion subject
- Verify the federated credential subject matches exactly:
system:serviceaccount:<HO_NAMESPACE>:etcd-backup-job - The Job runs in the HO namespace (e.g.,
hypershift), not the HCP namespace - Confirm the OIDC issuer URL matches the management cluster's issuer
- Check the audience is set to
api://AzureADTokenExchange
Secret Key Mismatch
If the controller falls through to the wrong credential mode, check the destination Secret (in the HO namespace) has the expected keys after plugin copying:
- AWS: must have a
credentialskey (remapped fromcloudby the plugin) - Azure WI: must have a
cloudkey (preserved by the plugin; the presence of this key triggers WI mode).AZURE_CLIENT_ID=should be included in the value for SA annotation - Azure Client Secret: must have a
credentialskey with JSON containingclientSecret
Job Pods Not Starting
Check the ServiceAccount and its annotations:
kubectl get sa etcd-backup-job -n <HO_NAMESPACE> -o yaml
- For Azure WI: the SA must have annotation
azure.workload.identity/client-id - For AWS STS: verify the projected volume appears in the Pod spec
Verifying PodSpec
Inspect the generated Job to confirm the correct credential mode was applied:
kubectl get job -n <HO_NAMESPACE> -l app=etcd-backup -o yaml
- AWS STS: Look for
AWS_ROLE_ARNenv var andaws-iam-tokenprojected volume - Azure WI: Look for pod label
azure.workload.identity/use: "true"and no--credentials-filein container args - Static/Client Secret: Look for
backup-credentialsvolume and--credentials-filein container args