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

# AWS

> How to access AWS APIs through the Formal Connector

## Overview

An AWS resource lets users access AWS APIs through the Formal Connector without
giving them credentials for the upstream IAM role. Users continue to send
requests to standard AWS service endpoints, such as
`ec2.us-west-2.amazonaws.com`. The Formal Endpoint routes those requests to the
Connector, where Formal evaluates policy and records the activity. The Connector
then re-signs allowed requests with the IAM identity selected by a Native User.
That Native User can select an assumed role or the Connector's ambient AWS
identity.

The AWS CLI and SDKs require an access key ID and secret access key to sign
requests. However, these client-side credentials can be placeholders. They only
produce the initial signature, which the Connector replaces before the request
reaches AWS.

This request path has four parts. You create the AWS resource, configure a Native
User, make the resource reachable through a Connector listener, and route AWS
traffic through the Formal Endpoint.

The Connector requires an authenticated Formal identity for this request path.
It rejects requests that do not resolve an authenticated Formal identity.

## Create an AWS resource

The resource hostname determines which AWS endpoints it covers. Set it to
`amazonaws.com` with port `443` to cover standard service endpoints across all
commercial AWS regions:

```hcl theme={null}
resource "formal_resource" "aws" {
  name       = "aws"
  technology = "aws"
  hostname   = "amazonaws.com"
  port       = 443
}
```

To limit access to one region, use a narrower suffix such as
`us-east-1.amazonaws.com`. Update the Formal Endpoint network rule to match that
suffix. AWS partitions with other domain suffixes require separate resources
and network rules.

## Configure the upstream AWS identity

Every signed request must resolve a Native User. Add one after creating the AWS
resource. The Formal console opens the **Add Native User** wizard automatically:

<img src="https://mintcdn.com/formal/2c74gnWddC8ud_xe/assets/images/aws_native_user_methods.png?fit=max&auto=format&n=2c74gnWddC8ud_xe&q=85&s=de2ddd068d1123013aa1efe9d886fd4c" alt="AWS Native User picker with standard and assume role authentication methods" width="1728" height="582" data-path="assets/images/aws_native_user_methods.png" />

1. Select an AWS IAM authentication method:
   * **AWS IAM (standard)** uses the Connector's ambient AWS identity.
   * **AWS IAM (assume role)** assumes the IAM role you specify.
2. In **Username**, enter a descriptive Formal label such as `aws-role`.
3. For **AWS IAM (assume role)**, enter the role ARN in **IAM Role ARN**.
4. Set **Use as Default** to **Yes**, then create the Native User.

<img src="https://mintcdn.com/formal/2c74gnWddC8ud_xe/assets/images/aws_native_user_assume_role.png?fit=max&auto=format&n=2c74gnWddC8ud_xe&q=85&s=eb57034e7f15b61185914a317b02c9e1" alt="AWS IAM assume role form with Username, IAM Role ARN, Use as Default, and Termination Protection fields" width="1728" height="1320" data-path="assets/images/aws_native_user_assume_role.png" />

Despite the **Username** label, this value is not an AWS username. It identifies
the Native User inside Formal. If you skipped the wizard, open the resource's
**Authentication** tab and select **Add User**.

See [Native Users](/docs/guides/core-concepts/resources/native_users) to assign
different roles to specific Formal users or groups.

In Terraform, use the `iam` secret to select the Connector's ambient AWS
identity:

```hcl theme={null}
resource "formal_native_user" "aws_ambient" {
  native_user_id     = "aws-ambient"
  native_user_secret = "iam"
  resource_id        = formal_resource.aws.id
  use_as_default     = true
}
```

Alternatively, store an IAM role ARN in the Native User secret:

```hcl theme={null}
resource "formal_native_user" "aws" {
  native_user_id     = "aws-role"
  native_user_secret = "arn:aws:iam::123456789012:role/formal-aws-access"
  resource_id        = formal_resource.aws.id
  use_as_default     = true
}
```

For an assumed role, both sides of the role assumption must allow it. The
Connector's ambient identity needs permission to call `sts:AssumeRole`. The
upstream role's trust policy must also trust that identity.

The AWS identity used to sign the request defines the maximum permissions
available through the resource. The resolved Native User explicitly selects an
assumed role or the Connector's ambient identity. Formal policies can narrow
that access further.

Use this Native User as the default for the resource. If some Formal users
or groups need different AWS access, create more Native Users. Assign each one
to the relevant Formal identities.

<Warning>
  The Connector does not use ambient AWS credentials as a fallback. A signed
  request fails when no Native User resolves, its configuration is invalid, or
  its role cannot be assumed.
</Warning>

## Make the resource reachable through a Connector

The Formal Endpoint needs a Connector and listener port to which it can forward
the intercepted request. A network rule alone does not create this route.

In the Formal Console:

1. Go to **Infrastructure** → **Connectors** and open the Connector that should
   proxy the AWS resource.
2. Open **Listeners**, select **New Listener**, and choose an available port.
   Port `8080` is reserved for Connector health checks.
3. Open the listener and select **New Rule**.
4. Set the rule type to **Resource**, select the AWS resource, and create the
   rule.
5. Confirm the AWS resource appears under the Connector's **Reachable
   Resources**.

See [Listeners and Rules](/docs/guides/core-concepts/connectors/listeners) for
more background.

The equivalent Terraform configuration is:

```hcl theme={null}
resource "formal_connector_listener" "aws" {
  connector_id = formal_connector.main.id
  name         = "aws-listener"
  port         = 4027
}

resource "formal_connector_listener_rule" "aws" {
  connector_listener_id = formal_connector_listener.aws.id
  type                  = "resource"
  rule                  = formal_resource.aws.id
}
```

The port can be any available Connector listener port other than `8080`.

## Route traffic through the Formal Endpoint

The final part of the request path is a Formal Endpoint network rule. Network
rules require the transparent proxy to be installed and enabled. Complete the
[transparent proxy setup](/docs/guides/client-apps/desktop-app#transparent-proxy)
before creating the rule.

One AWS resource can cover many service hostnames. The rule must preserve each
request's hostname so the Connector knows which AWS service to contact.

For a resource scoped to `amazonaws.com`, create a rule that:

* Matches `amazonaws.com` and hosts ending in `.amazonaws.com`.
* Selects the AWS resource.
* Enables **Forward to Connector**.

<Warning>
  **Forward to Connector** must be enabled. Without it, the Formal Endpoint treats
  `amazonaws.com` as the upstream host instead of forwarding the original AWS
  service hostname to the Connector.
</Warning>

The equivalent CEL configuration is:

```cel theme={null}
{
  "condition": {
    "pre_tls": hostname == "amazonaws.com" || hostname.endsWith(".amazonaws.com"),
    "post_tls": true
  },
  "outputs": {
    "resource_name": "<AWS_RESOURCE_NAME>",
    "forward_to_connector": true
  }
}
```

Replace `<AWS_RESOURCE_NAME>` with the name of the AWS resource you created.
Create the rule under **Infrastructure** → **Network Rules**, and set its status
to **Active**. New rules default to **Draft** and do not route traffic until
activated.

### Configure the AWS CLI

With the resource, Native User, Connector listener, and network rule in place,
create a dedicated AWS CLI profile. Give the profile placeholder credentials
and configure it to trust the Formal Endpoint's CA certificate:

<Tabs>
  <Tab title="macOS">
    ```bash theme={null}
    aws configure set aws_access_key_id FORMALPLACEHOLDER --profile formal-aws
    aws configure set aws_secret_access_key formal-placeholder-secret --profile formal-aws
    aws configure set region us-east-1 --profile formal-aws
    aws configure set ca_bundle "$HOME/.formal/ca/localca-cert.pem" --profile formal-aws
    ```
  </Tab>

  <Tab title="Linux">
    ```bash theme={null}
    aws configure set aws_access_key_id FORMALPLACEHOLDER --profile formal-aws
    aws configure set aws_secret_access_key formal-placeholder-secret --profile formal-aws
    aws configure set region us-east-1 --profile formal-aws
    aws configure set ca_bundle /var/lib/formal/ca/localca-cert.pem --profile formal-aws
    ```
  </Tab>
</Tabs>

Change `us-east-1` to the region you normally use. Keep the placeholder
credentials as shown: the Formal Endpoint authenticates your Formal identity,
while the Connector supplies the AWS identity used upstream.

Do not configure an `endpoint_url` or pass `--endpoint-url` to individual
commands. The AWS CLI must use standard service endpoints. This allows the
Formal Endpoint network rule to preserve and route each service hostname.

Verify the connection with AWS STS:

```bash theme={null}
aws sts get-caller-identity --profile formal-aws
```

The returned ARN should identify the IAM identity selected by the resolved Native
User. You can now use the `formal-aws` profile with other AWS CLI commands.
Formal will route, evaluate, and record each request in the same way.

### Troubleshoot `InvalidClientTokenId`

If AWS returns `InvalidClientTokenId` while using the placeholder credentials,
first verify the Formal route rather than replacing the placeholders:

1. Confirm the transparent proxy is enabled:

   ```bash theme={null}
   formal transparent-proxy enable
   formal transparent-proxy status
   ```

2. Confirm the network rule is **Active**, selects the AWS resource, and has
   **Forward to Connector** enabled.

3. Confirm you are logged in to the Formal Endpoint with `formal auth login`.

4. Confirm a default or assigned Native User resolves for your Formal identity.

5. Confirm the resource appears under the Connector's **Reachable Resources**.
   After adding a listener rule, allow up to one minute for the Formal Endpoint's
   reachability data to refresh. Restart the Formal Endpoint if the mapping still
   does not update.

6. On macOS, inspect `~/Library/Logs/Formal/main.log`. The message
   `catchall: failed to resolve connector forwarding target` means the Formal
   Endpoint cannot find a Connector listener that reaches the selected resource.

When the transparent proxy is configured to fail open, an unresolved Connector
route can pass the placeholder-signed request to AWS. AWS then reports a
credential error even though the underlying problem is Formal routing.
