Configure Velero with IRSA on Amazon EKS
What you’ll accomplish
Section titled “What you’ll accomplish”You’ll configure Velero to authenticate to S3 using IAM Roles for Service Accounts (IRSA), replacing static access keys with temporary credentials the IRSA webhook injects automatically. Velero stores no long-lived keys in your cluster.
Prerequisites
Section titled “Prerequisites”- UDS CLI installed
- UDS Registry account created and authenticated locally with a read token
- Access to an EKS cluster with UDS Core deployed
- An OIDC (OpenID Connect) identity provider configured on the cluster
- Permission to create IAM roles and policies in AWS
- An S3 bucket for Velero backups
- OpenTofu installed
Before you begin
Section titled “Before you begin”IRSA works by annotating the Velero service account (velero/velero-server) with an IAM role ARN. The Amazon EKS OIDC webhook automatically injects temporary credentials into the Velero pod, which the AWS SDK uses in place of a credentials file.
-
Create an IAM policy for S3 access
The following examples use OpenTofu to provision the required IAM resources. They assume an
awsprovider is already configured in your workspace. Create the S3 access policy:velero-s3-policy.tf # Velero S3 backup storage policy# Reference: https://github.com/vmware-tanzu/velero-plugin-for-aws?tab=readme-ov-file#set-permissions-for-velerodata "aws_iam_policy_document" "velero_s3" {statement {effect = "Allow"actions = ["s3:GetObject","s3:DeleteObject","s3:PutObject","s3:AbortMultipartUpload","s3:ListMultipartUploadParts",]resources = ["arn:aws:s3:::YOUR_VELERO_BUCKET/*"]}statement {effect = "Allow"actions = ["s3:ListBucket","s3:GetBucketLocation","s3:ListBucketMultipartUploads",]resources = ["arn:aws:s3:::YOUR_VELERO_BUCKET"]}}resource "aws_iam_policy" "velero_s3" {name = "velero-s3-policy"policy = data.aws_iam_policy_document.velero_s3.json} -
Create an IAM role with an IRSA trust policy
Create a role that the
velero-serverservice account in theveleronamespace can assume:velero-irsa-role.tf # The OIDC provider URL for your EKS cluster, without the https:// prefix.# Example: oidc.eks.us-east-1.amazonaws.com/id/EXAMPLE1234567890variable "oidc_provider" {description = "EKS cluster OIDC provider URL (without https://)"}# Look up the OIDC provider already registered in IAM for this clusterdata "aws_iam_openid_connect_provider" "eks" {url = "https://${var.oidc_provider}"}data "aws_iam_policy_document" "velero_irsa_trust" {statement {effect = "Allow"principals {type = "Federated"identifiers = [data.aws_iam_openid_connect_provider.eks.arn]}actions = ["sts:AssumeRoleWithWebIdentity"]condition {test = "StringEquals"variable = "${var.oidc_provider}:sub"values = ["system:serviceaccount:velero:velero-server"]}condition {test = "StringEquals"variable = "${var.oidc_provider}:aud"values = ["sts.amazonaws.com"]}}}resource "aws_iam_role" "velero" {name = "velero-backup-role"assume_role_policy = data.aws_iam_policy_document.velero_irsa_trust.json}resource "aws_iam_role_policy_attachment" "velero_s3" {role = aws_iam_role.velero.namepolicy_arn = aws_iam_policy.velero_s3.arn}Place both
.tffiles in the same directory. Supplyoidc_providervia a-varflag or aterraform.tfvarsfile, then apply:Terminal window tofu inittofu plantofu apply -
Configure your bundle for IRSA
Add the overrides below to your bundle. Setting
credentials.useSecret: falsetells Velero not to mount a credentials file, so the AWS SDK uses the web identity token the IRSA webhook injects. Theconfiguration.backupStorageLocationoverride replaces the default UDS Core configuration, which includes a credentialSecretreference incompatible with IRSA.uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:velero:velero:variables:# IRSA role ARN annotated on the Velero service account- name: VELERO_IRSA_ROLE_ARNpath: serviceAccount.server.annotations.eks\.amazonaws\.com/role-arnvalues:# Disable the credentials Secret; Velero uses the web identity token from the IRSA webhook- path: credentials.useSecretvalue: false# Override the backup storage location to remove the credential reference# used by the default static-key configuration- path: configuration.backupStorageLocationvalue:- name: defaultprovider: awsbucket: "<your-bucket-name>"config:region: "<your-region>"s3ForcePathStyle: falseSupply the role ARN in your
uds-config.yaml:uds-config.yaml variables:core:VELERO_IRSA_ROLE_ARN: "arn:aws:iam::123456789012:role/velero-backup-role" -
Create and deploy your bundle
Build the bundle artifact and deploy it to your cluster:
Terminal window uds create <path-to-bundle-dir>uds deploy uds-bundle-<name>-<arch>-<version>.tar.zst
Verification
Section titled “Verification”Confirm Velero is using IRSA and the backup storage location is reachable:
# Verify the IRSA annotation is present on the Velero service accountuds zarf tools kubectl get sa -n velero velero-server -o jsonpath='{.metadata.annotations}' | grep eks.amazonaws.com
# Check Velero pod logs for credential or S3 connectivity errorsuds zarf tools kubectl logs -n velero deploy/velero --tail=30
# Confirm the backup storage location shows Availableuds zarf tools kubectl get backupstoragelocation -n veleroSuccess criteria:
- The
velero-serverservice account has aneks.amazonaws.com/role-arnannotation matching your role ARN - Velero logs contain no
AccessDeniedorNoCredentialProviderserrors BackupStorageLocationphase isAvailable
To confirm S3 write access end-to-end, trigger a manual backup and verify it completes. See Perform a manual backup.
Troubleshooting
Section titled “Troubleshooting”Problem: BackupStorageLocation shows “Unavailable”
Section titled “Problem: BackupStorageLocation shows “Unavailable””Symptoms: The BackupStorageLocation phase is Unavailable and Velero logs show AccessDenied or authentication errors.
Solution: Verify the IRSA annotation is on the service account and matches the role ARN:
uds zarf tools kubectl get sa -n velero velero-server -o yaml | grep eks.amazonaws.comIf the annotation is missing, confirm VELERO_IRSA_ROLE_ARN is set in uds-config.yaml and redeploy the bundle.
Confirm the IAM role trust policy’s sub condition is system:serviceaccount:velero:velero-server and the OIDC provider ARN matches your EKS cluster. A mismatch here produces AccessDenied errors even when the bucket policy is correct.
Problem: Velero pod fails to start
Section titled “Problem: Velero pod fails to start”Symptoms: The Velero pod is in CrashLoopBackOff with errors referencing missing or invalid credentials.
Solution: Check whether credentials.useSecret was applied. If the Velero pod is still mounting a credentials file, you may not have included the override in the deployed bundle:
uds zarf tools kubectl describe pod -n velero -l app.kubernetes.io/name=velero | grep -A5 "Volumes:"Confirm credentials.useSecret: false appears in your uds-bundle.yaml under the velero.velero chart overrides and redeploy.
Problem: Backup fails with “NoSuchBucket”
Section titled “Problem: Backup fails with “NoSuchBucket””Symptoms: Backups fail immediately with a bucket not found error.
Solution: Verify the bucket and region values in your configuration.backupStorageLocation override match the actual bucket name and AWS region. The bucket must exist in the specified region.
Related documentation
Section titled “Related documentation”- Velero Plugin for AWS: IAM Permissions - full list of S3 permissions required by Velero
- AWS: IAM Roles for Service Accounts - IRSA setup and OIDC provider configuration
- Configure Velero storage backends - static credential configuration and backup schedule customization.
- Enable volume snapshots (AWS EBS) - add EBS snapshot support after configuring IRSA.
- Backup & restore concepts - how Velero fits into UDS Core.