# AWS credentials (/integrations/aws-credentials)

An AWS credential holds one AWS identity for the whole workspace. Every AWS block (S3, DynamoDB, Lambda, SQS, Athena, CloudWatch, and the rest) signs in with a saved credential, so keys live in one place instead of in each block.

Note:

Blocks added before saved credentials, which take access keys typed into the block, are marked legacy and keep working exactly as they are. Upgrade one by replacing it with the current block and selecting a credential.

## Choose how Sim signs in \[#choose-how-sim-signs-in]

| Option | What Sim stores | When to use it |
| - | - | - |
| **IAM role (keyless, via Sim OIDC)** | Nothing secret: only the role ARN | Recommended. No long-lived keys to rotate or leak. |
| **Access keys that assume an IAM role** | An access key pair, used only to assume the role | Your AWS account doesn't allow OIDC providers, or you need an external ID. |
| **Access keys** | An access key pair | The same behavior as keys typed into a block, shared across blocks. |

Every option resolves on Sim's servers at run time. The saved keys and the sessions Sim gets from them stay out of block outputs, logs, and anything a model sees, with two exceptions AWS requires: an S3 presigned URL made with a temporary session contains that session's token, and actions that issue credentials (STS **Assume Role** and **Get Session Token**, IAM **Create Access Key**) return what they issue. Anyone who can use the credential can run those actions to the extent its IAM permissions allow, so grant it only what your workflows need. Each assumed-role session is named `sim-<execution ID>`, so runs are traceable in CloudTrail.

Note:

STS **Get Session Token** works only with an **Access keys** credential: AWS refuses it for role sessions. An STS **Assume Role** call made with a role credential is role chaining, which AWS caps at one hour regardless of the requested duration.

## Set up a keyless IAM role \[#keyless-role]

In Sim, open **Integrations**, add an **AWS credential**, and choose **IAM role (keyless, via Sim OIDC)**. Keep the dialog open; it shows the values for the next steps.

In the AWS IAM console, open **Identity providers → Add provider**, choose **OpenID Connect**, and enter the dialog's **Issuer** as the **Provider URL**, and its **Audience**. You only do this once per AWS account.

Enter the role's ARN (`arn:aws:iam::<account ID>:role/<role name>`) in the dialog first. The **Role trust policy** fills in its account ID; until then it shows `<AWS_ACCOUNT_ID>`, which IAM rejects.

Create the role with that name (or edit the existing one) and set its trust policy to the **Role trust policy** shown in the dialog. It trusts only this credential's **Subject**, so no other Sim credential, workspace, or customer can assume the role.

Attach the permissions your workflows need to the role, then save. Sim verifies the connection by assuming the role before saving it, and refuses a role that would also trust a different subject.

Note:

The subject is unique to the credential. Reconnecting a keyless credential keeps its subject by default, so the role's trust policy keeps working; choose **Issue a new subject** only if you also update the trust policy.

### From the API or CLI \[#keyless-api-cli]

Run `sim credentials keyless-subject aws-service-account`, trust the printed subject as above, then add `roleArn` (optionally `stsRegion` and `sessionDurationSeconds`) to its `keylessConfig` and pass it to `sim credentials create aws-service-account`. See [the CLI credentials reference](/cli/credentials) for the full two-step example; the proof expires after 24 hours and works only for the user who requested it.

## Use access keys \[#use-access-keys]

Create an IAM user (or use an existing one) with an access key, choose **Access keys** or **Access keys that assume an IAM role**, and enter the key pair. For an assumed role, add the role ARN and, if the role's trust policy requires one, the external ID. For AWS GovCloud or China keys, set the **STS region** (for example `us-gov-west-1`). Sim checks the keys with `sts:GetCallerIdentity` before saving.

To rotate a key, create the new key in AWS, reconnect the credential with it, confirm a run succeeds, then deactivate and delete the old key. Every block using the credential switches at once.

## Self-hosted deployments \[#self-hosted-deployments]

Keyless roles need two things on a self-hosted deployment:

- `WORKLOAD_IDENTITY_SIGNING_KEY`: a PKCS#8 PEM RSA private key that signs Sim's tokens.
- An issuer AWS can reach over the public internet: an `https` URL on the default port, served by a certificate from a public CA. It defaults to `<NEXT_PUBLIC_APP_URL>/oidc/workload`; set `WORKLOAD_IDENTITY_ISSUER` to pin it. Trust policies reference this URL, so never change it once roles trust it. Sim keeps keyless off when the issuer isn't `https` or names a port, query, or fragment, because AWS can't use it.

Generate a key with `openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048`.

To rotate the signing key without failed runs:

1. Set the new key as `WORKLOAD_IDENTITY_PREVIOUS_KEY` and redeploy (including any background workers that run workflows). Sim publishes it but keeps signing with the current key.
2. Wait at least 5 minutes, so every cached copy of the published keys includes the new one. If any keyless [Snowflake connection](/integrations/snowflake-service-account#keyless-service-user) exists, wait 60 minutes instead: Snowflake caches an issuer's keys for up to an hour.
3. Swap them: set the new key as `WORKLOAD_IDENTITY_SIGNING_KEY` and the old key as `WORKLOAD_IDENTITY_PREVIOUS_KEY`, and redeploy everything that runs workflows.
4. Once every instance signs with the new key, wait 5 more minutes (10 with keyless Snowflake connections, whose tokens last that long), then remove `WORKLOAD_IDENTITY_PREVIOUS_KEY`.

Without a signing key, the keyless option is unavailable and access keys work as usual.

## Troubleshooting \[#troubleshooting]

- **`InvalidIdentityToken` or "No OpenIDConnect provider found":** the IAM identity provider's URL or audience doesn't match the dialog exactly, or AWS can't reach the issuer. Open `<issuer>/.well-known/openid-configuration` from outside your network; it must load over `https`.
- **"Sim could not assume this role: Not authorized to perform sts:AssumeRoleWithWebIdentity":** the role's trust policy doesn't trust this credential's subject. Paste the trust policy from the dialog again; if you chose **Issue a new subject**, update the policy to the new one.
- **"This role trusts every Sim subject":** the trust policy is missing the `sub` condition. Use the policy from the dialog.
