> ## Documentation Index
> Fetch the complete documentation index at: https://ona.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS OIDC Integration

> Access AWS resources from Ona environments using OIDC federation, without static credentials.

<Note>Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.</Note>

Ona environments can assume AWS IAM roles using [OIDC federation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html). The Ona CLI generates a JWT token, which AWS STS exchanges for temporary credentials tied to an IAM role you configure.

No static AWS credentials are needed.

## Prerequisites

* Enable V3 tokens on the [OIDC Token Configuration](https://app.gitpod.io/settings/security/oidc) page in your organization settings. See [Enable V3 tokens](/ona/configuration/oidc#enable-v3-tokens).
* AWS CLI installed in your environment (for `ona idp login aws`).

## Step 1: Create an OIDC identity provider

Create an [OIDC identity provider](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) in AWS IAM:

* **Provider URL:** `https://app.gitpod.io`
* **Audience:** `sts.amazonaws.com`

Using the AWS CLI:

```bash theme={null}
aws iam create-open-id-connect-provider \
  --url https://app.gitpod.io \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list ""
```

<Note>AWS automatically fetches the OIDC configuration from `https://app.gitpod.io/.well-known/openid-configuration` and the signing keys from the JWKS endpoint.</Note>

## Step 2: Create an IAM role with a trust policy

[Create an IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp.html) that Ona environments can assume. The trust policy controls which tokens are accepted.

### Inspect your token

Run this in an Ona environment to see the claims AWS will evaluate:

```bash theme={null}
ona idp token --audience sts.amazonaws.com --decode
```

The V3 `sub` claim uses a `key:value` format:

```
organization_id:<orgID>:project_id:<projID>
```

### Trust policy: allow all environments in an organization

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/app.gitpod.io"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "app.gitpod.io:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "app.gitpod.io:sub": "organization_id:<ORG_ID>:*"
        }
      }
    }
  ]
}
```

### Trust policy: allow environments from a specific project

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/app.gitpod.io"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "app.gitpod.io:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "app.gitpod.io:sub": "organization_id:<ORG_ID>:project_id:<PROJECT_ID>:*"
        }
      }
    }
  ]
}
```

Replace `<ACCOUNT_ID>`, `<ORG_ID>`, `<PROJECT_ID>`, and `<USER_ID>` with your values. Find your organization and project IDs in the Ona dashboard URL or via the CLI.

<Note>Follow the principle of least privilege. Restrict trust policies to the narrowest scope needed.</Note>

## Step 3: Assume the role

Use `ona idp login aws` to assume the role and configure your local AWS credentials:

```bash theme={null}
ona idp login aws --role-arn arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>
```

This runs `aws sts assume-role-with-web-identity` under the hood and writes temporary credentials to your AWS config.

Options:

* `--duration-seconds` sets token expiry (default: 3600). Longer sessions require [AWS admin approval](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session).
* `--profile` sets the AWS profile to configure (default: `default`).
* `--role-session-name` sets a custom session name for audit trails.

### Automate on environment startup

Add the login command to your [automations](/ona/configuration/tasks-and-services/overview) so credentials are available when the environment starts:

```yaml theme={null}
# automations.yaml
tasks:
  aws-login:
    name: AWS Login
    command: |
      ona idp login aws --role-arn arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>
    triggeredBy:
      - postDevcontainerStart
```

After authentication, use AWS resources normally:

```bash theme={null}
aws s3 ls
aws secretsmanager get-secret-value --secret-id my-secret --region us-east-1
```

## Customizing the sub claim for AWS

By default, the `sub` claim for environment tokens includes `organization_id` and either `project_id` (if the environment belongs to a project) or `environment_id`.

You can add extra fields to the `sub` claim on the [OIDC Token Configuration](https://app.gitpod.io/settings/security/oidc) page. This lets you write more specific trust policies.

### Example: per-developer access

Add `creator_email` to the extra sub fields. The `sub` claim becomes:

```
organization_id:<orgID>:project_id:<projID>:creator_email:dev@example.com
```

Then restrict the trust policy:

```json theme={null}
{
  "Condition": {
    "StringEquals": {
      "app.gitpod.io:aud": "sts.amazonaws.com"
    },
    "StringLike": {
      "app.gitpod.io:sub": "organization_id:<ORG_ID>:*:creator_email:dev@example.com"
    }
  }
}
```

### Example: restrict by repository

Add `environment_initializers.git.remote_uri` to the extra sub fields. The `sub` claim becomes:

```
organization_id:<orgID>:project_id:<projID>:environment_initializers.git.remote_uri:https%3A//github.com/org/repo.git
```

<Note>Colons in values are URL-encoded as `%3A` in the sub claim.</Note>

See [Customizing the sub claim](/ona/configuration/oidc#customizing-the-sub-claim) for the full list of available fields.

## V2 trust policies

<Note>V2 is the previous token format. The examples below apply if your organization still uses V2 tokens. See the [V2 AWS guide](/ona/integrations/aws) for the full V2 setup.</Note>

V2 tokens use a path-based `sub` format: `org:<orgID>/prj:<projectID>/env:<envID>`. Trust policies use `StringLike` on this format:

```json theme={null}
{
  "Condition": {
    "StringEquals": {
      "app.gitpod.io:aud": "sts.amazonaws.com"
    },
    "StringLike": {
      "app.gitpod.io:sub": "org:<ORG_ID>/*"
    }
  }
}
```

## Further reading

* [AWS: Creating an OIDC identity provider](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html)
* [AWS: OIDC condition keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif)
* [AWS: AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html)
* [Ona OIDC overview](/ona/configuration/oidc)

## Troubleshooting

<Accordion title="Token exchange fails with &#x22;Not authorized to perform sts:AssumeRoleWithWebIdentity&#x22;">
  * Verify the OIDC provider URL is exactly `https://app.gitpod.io` (no trailing slash).
  * Check that the audience in the trust policy matches `sts.amazonaws.com`.
  * Decode your token (`ona idp token --decode --audience sts.amazonaws.com`) and verify the `sub` claim matches your trust policy conditions.
  * If you recently switched from V2 to V3, update your trust policy to use the V3 sub format.
</Accordion>

<Accordion title="Credentials expire during long-running tasks">
  * Increase `--duration-seconds` (requires the IAM role's max session duration to be increased in AWS).
  * Re-run `ona idp login aws` to refresh credentials.
</Accordion>
