AWS Workload Identity (OIDC Federation)
Overview
Section titled “Overview”This guide configures AWS Secrets Manager as a secret provider using Workload Identity Federation: CrewAI Platform mints short-lived OIDC tokens, exchanges them for AWS credentials via STS, and reads your secrets — without a long-lived AWS access key being stored anywhere.
How it works at runtime
Section titled “How it works at runtime”- The deployment worker requests a fresh OIDC JWT from CrewAI Platform.
- The worker calls
sts:AssumeRoleWithWebIdentityon the IAM role you set up below, presenting the JWT. - AWS STS validates the JWT against CrewAI Platform’s public OIDC issuer (so your platform installation must be reachable from AWS), then returns short-lived AWS credentials.
- The worker uses those credentials to call
secretsmanager:GetSecretValue. - The fetched value is injected as the environment variable’s value for that automation kickoff.
OIDC subject tokens are cached for ~1 hour to avoid re-issuing on every kickoff. Secret values are fetched fresh on every kickoff regardless of OIDC cache state, which is what makes this path rotation-aware.
Prerequisites
Section titled “Prerequisites”Step 1 — Find Your CrewAI Platform OIDC Issuer URL
Section titled “Step 1 — Find Your CrewAI Platform OIDC Issuer URL”Your CrewAI Platform installation publishes an OpenID Connect discovery document at https://<your-platform-host>/.well-known/openid-configuration. The issuer field in that document is the URL AWS will register as a trusted OIDC provider.
Open the URL in a browser (replacing <your-platform-host> with your actual hostname, e.g. app.crewai.com):
https://<your-platform-host>/.well-known/openid-configurationYou should see JSON containing:
{ "issuer": "https://<your-platform-host>", "jwks_uri": "https://<your-platform-host>/oauth2/jwks", ...}Note the exact value of issuer — you’ll use it in Step 3.
Step 2 — Register CrewAI Platform as an IAM OIDC Identity Provider
Section titled “Step 2 — Register CrewAI Platform as an IAM OIDC Identity Provider”Open the IAM → Identity providers console and click Add provider.
- Provider type: OpenID Connect.
- Provider URL: the
issuervalue from Step 1 (e.g.https://app.crewai.com). - Audience:
sts.amazonaws.com
Click Add provider.
Or via CLI:
aws iam create-open-id-connect-provider \ --url "https://<your-platform-host>" \ --client-id-list "sts.amazonaws.com" \ --thumbprint-list "$(echo | openssl s_client -servername <your-platform-host> -connect <your-platform-host>:443 2>/dev/null | openssl x509 -fingerprint -noout -sha1 | cut -d= -f2 | tr -d ':')"Copy the OpenIDConnectProviderArn from the output (or the provider’s ARN from the console). You’ll use it in Step 3.
Step 3 — Create the IAM Role
Section titled “Step 3 — Create the IAM Role”Save as trust-policy.json, replacing <YOUR_ACCOUNT_ID>, <your-platform-host> (the issuer host without https:// or http://, e.g. app.crewai.com), and <YOUR_CREWAI_ORG_UUID> (from the Prerequisites):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<YOUR_ACCOUNT_ID>:oidc-provider/<your-platform-host>" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "<your-platform-host>:aud": "sts.amazonaws.com", "<your-platform-host>:sub": "organization:<YOUR_CREWAI_ORG_UUID>" } } } ]}Create the role:
aws iam create-role \ --role-name crewai-secrets-reader \ --assume-role-policy-document file://trust-policy.jsonCopy the Role Arn from the output — that’s your aws_role_arn. You’ll paste it into CrewAI Platform in Step 6.
Step 4 — Create and attach the IAM policy for Secrets Manager + KMS access
Section titled “Step 4 — Create and attach the IAM policy for Secrets Manager + KMS access”Save as secrets-policy.json, replacing the placeholders with your account ID, region, secret-name prefix, and the KMS key ARN(s) that encrypt those secrets:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "SecretsManagerListForUI", "Effect": "Allow", "Action": "secretsmanager:ListSecrets", "Resource": "*" }, { "Sid": "SecretsManagerRead", "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": "arn:aws:secretsmanager:<REGION>:<YOUR_ACCOUNT_ID>:secret:<SECRET_NAME_PREFIX>-*" }, { "Sid": "KMSDecrypt", "Effect": "Allow", "Action": [ "kms:Decrypt" ], "Resource": "arn:aws:kms:<REGION>:<YOUR_ACCOUNT_ID>:key/<KMS_KEY_ID>" } ]}SecretsManagerListForUI powers the Secret Name autocomplete in the Environment Variables form and the Test Connection button on the credential. secretsmanager:ListSecrets only accepts Resource: "*" — it is account-scoped at the IAM layer.
Attach the policy to the role using either the CLI (inline policy, simplest) or the console UI; for environments that reuse the same permissions across many roles, use the Managed policy tab for a reusable, named policy.
aws iam put-role-policy \ --role-name crewai-secrets-reader \ --policy-name SecretsManagerRead \ --policy-document file://secrets-policy.jsonThis attaches the policy inline to the role. Inline policies are tied to the role and cannot be reused on other roles.
POLICY_ARN=$(aws iam create-policy \ --policy-name CrewAISecretsReader \ --policy-document file://secrets-policy.json \ --query 'Policy.Arn' --output text)
aws iam attach-role-policy \ --role-name crewai-secrets-reader \ --policy-arn "$POLICY_ARN"A managed policy is a standalone IAM resource you can attach to multiple roles.
- Open the IAM → Roles console and select crewai-secrets-reader.
- On the Permissions tab, click Add permissions → Create inline policy.
- Switch to the JSON editor and paste the contents of
secrets-policy.json. - Click Next, give the policy a name (e.g.
SecretsManagerRead), and click Create policy.
To create a reusable managed policy instead, use IAM → Policies → Create policy and then attach it to the role from the role’s Permissions tab.
Step 5 — Create at Least One Secret in AWS
Section titled “Step 5 — Create at Least One Secret in AWS”If you don’t already have a secret to test against, create one now:
aws secretsmanager create-secret \ --region <REGION> \ --name crewai-test-keyword \ --secret-string "hello from aws"Or via the AWS Secrets Manager console → Store a new secret.
Step 6 — Add a Workload Identity Configuration in CrewAI Platform
Section titled “Step 6 — Add a Workload Identity Configuration in CrewAI Platform”In CrewAI Platform, navigate to Settings → Workload Identity and click Add Workload Identity Config.
Fill the form:
- Name: A descriptive name, e.g.
aws-prod. - Cloud Provider:
AWS. - AWS Role ARN: the Role Arn from Step 3.
- AWS Region: the region where your secrets live, e.g.
us-east-1. - (Optional) Check Set as default for AWS if you’d like this WI config to be the default selected when creating an AWS-backed secret credential.
Click Create.
Step 7 — Add a Secret Provider Credential Bound to the WI Config
Section titled “Step 7 — Add a Secret Provider Credential Bound to the WI Config”Navigate to Settings → Secret Provider Credentials and click Add Credential.
Fill the form:
- Name: A descriptive name, e.g.
aws-prod-wi. - Provider:
AWS Secrets Manager. - Authentication Method:
Workload Identity(instead of static keys / AssumeRole). - Workload Identity Configuration: select the config you created in Step 6 (e.g.
aws-prod). - (Optional) Check Set as default credential for this provider.
The form will only ask for AWS Region under Workload Identity — the static-credential fields (Access Key ID, Secret Access Key, Role ARN, External ID) are intentionally hidden because they don’t apply to this path; the role ARN comes from the linked WI config.
Click Create.
Step 8 — Test the Connection
Section titled “Step 8 — Test the Connection”After saving the credential, click Test Connection. For workload-identity credentials this verifies the OIDC handshake: CrewAI Platform mints a JWT, exchanges it with AWS STS via sts:AssumeRoleWithWebIdentity, and confirms the resulting credentials can call sts:GetCallerIdentity against the assumed role. A green result means the federation binding is healthy.
A successful Test Connection proves the trust policy, OIDC provider registration, and audience condition are all wired correctly. It does not prove per-secret IAM is correct — secretsmanager:GetSecretValue on a specific secret ARN is exercised separately when an environment variable resolves at kickoff. See Troubleshooting for handshake failure modes.
Step 9 — Reference the Secret in an Environment Variable
Section titled “Step 9 — Reference the Secret in an Environment Variable”Now reference the secret on an automation, exactly as you would for any other Secrets Manager-backed env var. See Using the Secrets Manager for the form fields and behavior.
The only difference between WI-backed and static-keys-backed env vars is when the secret is read:
- WI-backed: secret value is read fresh on every automation kickoff.
- Static-keys-backed: secret value is read at deploy time and baked into the deployment image.
Step 10 — Verify Rotation
Section titled “Step 10 — Verify Rotation”After the deployment is running, rotate the secret in AWS:
aws secretsmanager update-secret \ --region <REGION> \ --secret-id crewai-test-keyword \ --secret-string "rotated value"Trigger a new automation kickoff. The kickoff’s environment will see "rotated value" — no re-deploy, no worker restart, no waiting on a TTL.
To confirm in logs (if you have access to the worker), look for:
Workload identity config '<id>' (aws): N secret(s) resolvedThis line appears for every kickoff and indicates a fresh GetSecretValue call against AWS.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause |
|---|---|
| Test Connection fails with a handshake error | The sts:AssumeRoleWithWebIdentity call was rejected. Verify the trust policy’s federated principal ARN references oidc-provider/<your-platform-host> (host without https:// or http://, no trailing slash), the audience condition is exactly sts.amazonaws.com, the sub condition matches your CrewAI organization UUID, and the platform’s OIDC discovery URL is reachable from AWS over the public internet. |
InvalidIdentityToken: Couldn't retrieve verification key from your identity provider | AWS STS can’t reach your CrewAI Platform host to fetch JWKS. Confirm the host is internet-accessible from AWS, the OIDC discovery URL returns 200, and the JWKS endpoint is reachable. |
AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity | Trust policy mismatch. Re-check Step 3: the federated principal ARN must include oidc-provider/<your-platform-host> (host without https:// or http://, no trailing slash), the audience condition must be exactly sts.amazonaws.com, and the sub condition must equal organization:<YOUR_CREWAI_ORG_UUID>. |
Secret Name autocomplete shows AccessDenied: secretsmanager:ListSecrets | The role is missing secretsmanager:ListSecrets with Resource: "*". Add the SecretsManagerListForUI statement from Step 4. |
| Kickoff fails to resolve a secret even though Test Connection passes | The WI binding is healthy, but resource-scoped IAM is missing on the failing secret. Audit the role’s secretsmanager:GetSecretValue and kms:Decrypt permissions for that specific secret’s ARN and KMS key. |
RegionDisabledException / no secrets found | The region in the Workload Identity Config doesn’t match where the secret lives. Re-check Step 6. |
| Rotated value isn’t picked up on the next kickoff | Confirm the env var on the automation is referencing a Workload Identity-backed credential (not a static-keys credential). The static path bakes values into the deploy image. |
Reference Links
Section titled “Reference Links”- AWS: Creating OpenID Connect (OIDC) identity providers
- AWS: Configuring a role for OpenID Connect federation
- AWS: STS:AssumeRoleWithWebIdentity API reference
Next Steps
Section titled “Next Steps”- Use secrets in environment variables and manage permissions
- For multi-cloud, see also GCP Workload Identity Federation and Azure Workload Identity Federation.