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

# fjall aws

> Run any AWS CLI command against a Fjall-managed account with short-lived credentials Fjall mints for you, without a profile or aws sso login.

<Info>
  **Wrapper command.** `fjall aws exec` spawns the command you give it with AWS
  credentials injected into that child process. `exec` is the only subcommand.
</Info>

## Overview

`fjall aws exec` is how you run an AWS command against an account Fjall manages without configuring anything locally. No `~/.aws/config` profile, no `aws sso login`, no long-lived access keys on your laptop.

Fjall resolves the account you name, mints a short-lived STS session for it, and hands that session to your command as environment variables. The command runs, the process exits, the credentials go with it.

Anything that reads AWS credentials from the environment works: the `aws` CLI, `terraform`, a Node or Python script using the AWS SDK.

```bash theme={null}
fjall aws exec --target production-use2 -- aws sts get-caller-identity
```

## Prerequisites

| Requirement                                     | How                                                                                              |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Logged in to Fjall                              | [`fjall login`](/cli/login)                                                                      |
| An AWS account connected                        | [`fjall connect`](/cli/connect)                                                                  |
| Run inside a project bound to your organisation | Fjall refuses only on a proven mismatch between the project's organisation and your credential's |

## Usage

```bash theme={null}
fjall aws exec [options] -- <command...>
```

Put `--` between Fjall's own flags and your command. Everything after the separator is passed to the child untouched, including its flags: `fjall aws exec` sets `allowUnknownOption`, so a flag such as `--query` or `--output` reaches the `aws` CLI rather than being rejected by Fjall.

```bash theme={null}
# Confirm which identity you are about to act as
fjall aws exec --target production-use2 -- aws sts get-caller-identity

# List a bucket in the same account
fjall aws exec --target production-use2 -- aws s3 ls s3://api-uploads/

# Flags after -- belong to the child, not to fjall
fjall aws exec --target staging-euw1 -- aws ecs list-clusters --output table
```

Running `fjall aws` with no subcommand prints `Available subcommands: exec` and exits `1`. So does any other subcommand name.

## Choosing the account

| Flag                    | Effect                                                                           |
| ----------------------- | -------------------------------------------------------------------------------- |
| `-t, --target <name>`   | Run against this deployment target. Exact match against the derived target names |
| `-a, --app <name>`      | Resolve the target from an application's configuration                           |
| neither                 | Falls back to the ambient active-target chain                                    |
| `-r, --region <region>` | Override the region within the resolved account                                  |

Target names are derived as `<accountname>-<regionabbrev>`, for example `production-use2` or `development-euw1`. Discover them with [`fjall target list`](/cli/target).

`--target` matching is exact and case-sensitive. An unknown name is a hard error naming the valid targets, never a silent fallback to a different account.

<Warning>
  `--app` will not accept a governance tier name. `--app organisation`, `--app
      platform` and `--app account` are refused with a teaching error, because each
  would otherwise resolve to a **workload** account's credentials. Use `--target   <name>` to address a specific account.
</Warning>

### The management account

The reserved target name `management` addresses your AWS Organizations management account. It requires an explicit second opt-in:

```bash theme={null}
fjall aws exec --target management --confirm-management -- aws organizations list-accounts
```

Without `--confirm-management` the command refuses and explains why. The guard exists because the management account is the one place where a mistyped command has organisation-wide blast radius, and because a bare word target reads like any other. Credentials for it are minted through the organisation OIDC connection and audited.

Solo-mode organisations have no management account, so `--target management` refuses there too.

## Timeouts

The child is killed if it has not finished in time. The default deadline is **10 minutes**.

```bash theme={null}
fjall aws exec --target production-use2 --timeout 30m -- ./scripts/backfill.sh
```

| Property | Value                                                  |
| -------- | ------------------------------------------------------ |
| Default  | `10m`                                                  |
| Grammar  | a positive integer plus a unit: `<n>s`, `<n>m`, `<n>h` |
| Maximum  | `1h`                                                   |
| Examples | `90s`, `30m`, `1h`                                     |

<Note>
  **Why the ceiling is one hour.** Fjall mints the STS session for 3600 seconds,
  and the credentials are injected into the child as static environment
  variables that nothing refreshes while it runs. A command
  allowed to outlive its own session could not finish, it could only fail
  partway through with an AWS auth error that says nothing about the timeout.
  Capping at the session length keeps the deadline meaningful. Split longer work
  into shorter phases.
</Note>

A malformed or over-cap `--timeout` is a refusal with a message naming the problem, not a silent fall back to the default.

A cached session is handed out with whatever validity it has left. When the remaining credential life is shorter than the timeout you asked for, Fjall prints a warning up front rather than letting you discover it from an auth failure mid-command.

## What the child process receives

Fjall builds the child's environment from your own, then:

| Step                            | Detail                                                                                                         |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Strips ambient AWS profile vars | `AWS_PROFILE`, `AWS_DEFAULT_PROFILE`, `AWS_CONFIG_FILE`, `AWS_SHARED_CREDENTIALS_FILE`                         |
| Injects the minted session      | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` (when present), `AWS_REGION`                 |
| Filters dangerous variables     | `filterDangerousEnvVars` drops loader and interpreter injection vectors (`LD_PRELOAD`, `NODE_OPTIONS`, `HOME`) |
| Spawns with `shell: false`      | Your command and its arguments are passed as an argv array, so no shell parses them                            |

Stripping the profile variables is load-bearing: leaving `AWS_PROFILE` set makes the AWS SDK inside the child ignore the injected keys and resolve a profile from `~/.aws/credentials` instead, which is how a command lands in the wrong account.

The credentials go to the child process and nowhere else. Fjall writes no AWS profile and no credentials file for this, and a child process cannot alter its parent's environment, so nothing is exported into the shell you ran the command from. When the process exits, the session is gone, and it expires within the hour regardless.

`stdin` stays connected in every mode, so piping into the child keeps working:

```bash theme={null}
fjall aws exec --target production-use1 -- aws s3 cp - s3://api-backups/dump.sql < dump.sql
```

<Warning>
  `HOME` is one of the filtered variables, so it is not set in the child's
  environment. A command that relies on it (tilde expansion, `~/.docker`, a
  tool's own cache directory) may not find what it expects. Pass those paths
  explicitly instead.
</Warning>

## Options

| Option                  | Description                                                                         | Required |
| ----------------------- | ----------------------------------------------------------------------------------- | -------- |
| `-a, --app <name>`      | Application name, used to resolve the target                                        | No       |
| `-t, --target <name>`   | Deployment target name, exact match                                                 | No       |
| `-r, --region <region>` | AWS region override                                                                 | No       |
| `--confirm-management`  | Required alongside `--target management`                                            | No       |
| `--timeout <duration>`  | Kill the child after this long: `<n>s`, `<n>m`, `<n>h`. Default `10m`, maximum `1h` | No       |
| `-v, --verbose`         | Print the resolved target, region, and command before running                       | No       |
| `--non-interactive`     | Force plain CLI output                                                              | No       |
| `--agent`               | Enable agent output mode                                                            | No       |
| `--budget <level>`      | Output budget: `minimal`, `compact`, or a token count                               | No       |
| `--fields <fields>`     | Select exactly these output fields                                                  | No       |
| `--full`                | Disable content truncation                                                          | No       |

In agent mode the child's stdout and stderr are framed as structured event blocks instead of streaming raw, so child bytes cannot interleave the output stream. See [Agent mode](/cli/agent-mode).

## What your token needs in CI

`aws exec` crosses two routes, so it needs two scopes: `read` to resolve the target, and `deploy:oidc:mint` to mint the session. The mint route applies a second, independent gate on the kind of token, not just its scopes: only a deploy token may mint AWS credentials.

| Token                         | Can run `fjall aws exec`?                                                                                            |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| CI deploy token (`fjall_dk_`) | Yes. `read` and `deploy:oidc:mint` are both in the base scope set of every deploy token, so nothing needs re-minting |
| Personal API key (`fj_`)      | No. Rejected at the kind gate                                                                                        |
| Agent token                   | No. Rejected at the kind gate                                                                                        |

A token that fails either gate gets a 403:

```text theme={null}
Only a CI deploy token can mint AWS credentials. Agent tokens and personal API keys cannot — create a deploy token in Settings → CI/CD Tokens.
```

## Exit codes

The wrapped command's exit code becomes Fjall's exit code, so CI can gate on it directly.

| Code    | Meaning                                                                          |
| ------- | -------------------------------------------------------------------------------- |
| `0`     | The command ran and exited `0`                                                   |
| `N`     | The command ran and exited `N`                                                   |
| `128+N` | The command was killed by signal `N`, following the shell convention             |
| `1`     | Fjall itself failed: no command given, bad target, bad timeout, credentials gone |

## Errors

| Message                                                                | Cause                                        | Fix                                                           |
| ---------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------- |
| `Missing command. Usage: ... -- <command...>`                          | Nothing followed the `--` separator          | Add the command to run                                        |
| `Command not found: '<cmd>'`                                           | The binary is not on your `PATH`             | Install it, or give the full path                             |
| `Command timed out after <duration>`                                   | The child outlived the deadline              | Raise `--timeout`, up to `1h`, or split the work              |
| `--target management runs against the organisation MANAGEMENT account` | `--target management` without the opt-in     | Add `--confirm-management` if that is genuinely what you want |
| `AWS credentials could not be resolved`                                | No connected account for the resolved target | Run [`fjall connect`](/cli/connect)                           |

## Examples

### Confirm identity before a write

```bash theme={null}
fjall aws exec --target production-use2 -- aws sts get-caller-identity
```

Read-only, and the fastest way to prove you are pointed at the account you think you are.

### Inspect storage in one region of a target

```bash theme={null}
fjall aws exec --target production-use2 --region us-east-1 -- aws s3 ls
```

### Run a long job with a raised deadline

```bash theme={null}
fjall aws exec --target staging-euw1 --timeout 30m -- \
  aws dynamodb scan --table-name events --output json > events.json
```

### Read the organisation's account list

```bash theme={null}
fjall aws exec --target management --confirm-management -- \
  aws organizations list-accounts --output table
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Deployment targets" icon="crosshairs" href="/cli/target">
    List, inspect, and set the target that names an account and region.
  </Card>

  <Card title="Connect an AWS account" icon="plug" href="/cli/connect">
    Set up the AWS connection the credentials are minted from.
  </Card>

  <Card title="Understanding profiles" icon="user-gear" href="/deployment/understanding-profiles">
    See how accounts, regions, and roles are derived rather than authored.
  </Card>

  <Card title="Agent mode" icon="robot" href="/cli/agent-mode">
    Structured output for scripted and agent callers.
  </Card>
</CardGroup>
