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

# AWS (Lambda, ECS, EC2, IRSA)

> Authenticate from AWS workloads to KnoxCall using IAM Roles for Service Accounts (IRSA) or static client credentials

# AWS Workload Identity

KnoxCall accepts AWS-issued OIDC tokens from EKS pods (IRSA) and other workloads with `AWS_WEB_IDENTITY_TOKEN_FILE` configured. STS workload identity for ECS / Lambda is supported via the same pattern.

## 1. Set up the IAM role + EKS service account (IRSA)

Existing AWS IAM setup — your cluster's OIDC provider must be registered. See [AWS docs](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html).

Once configured, your pod has these env vars automatically:

* `AWS_WEB_IDENTITY_TOKEN_FILE` (path to a file containing a signed JWT)
* `AWS_ROLE_ARN`

## 2. Configure the KnoxCall binding

Create the workload binding in the dashboard with **Settings → API → Workload Identity → Connect workload**, or call the admin API directly. The `/admin/*` routes are served on the admin host (`admin.knoxcall.com` / any `knoxcall.com` host) and are authenticated by your logged-in admin/owner session — a session JWT plus the `X-Tenant-ID` header — not an API key against `api.knoxcall.com`.

<Note>
  Creating a binding requires a **recent step-up verification** (passkey, TOTP or
  emailed code) within the last 5 minutes — a binding is a trust that lets an
  external workload mint tenant tokens, so it carries the same bar as creating an
  OAuth client. A `curl` carrying only a session JWT answers
  `403 {"requires_step_up": true}`: verify in the Dashboard (any action that
  prompts for your passkey or TOTP), then replay the request inside the 5-minute
  window. Each verification is single-use, so a retried request needs a fresh one.
  Listing and revoking bindings need no verification — containment must never be
  gated.
</Note>

```bash theme={"dark"}
curl -X POST https://admin.knoxcall.com/admin/oauth/workload-bindings \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "X-Tenant-ID: $TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "oauth_client_id": "<your_oauth_client_id>",
    "name": "aws-prod-eks",
    "issuer": "https://sts.amazonaws.com",
    "audience": "knoxcall:api",
    "attribute_conditions": {
      "arn": "arn:aws:iam::123456789012:role/knoxcall-prod"
    },
    "allowed_scopes": ["routes:write"],
    "access_token_ttl_seconds": 3600
  }'
```

Lock attribute conditions to the assumed IAM role ARN. The OIDC token from `sts.amazonaws.com` carries the role ARN in the `arn` claim.

## 3. Call KnoxCall

```javascript theme={"dark"}
import { KnoxCall } from "@knoxcall/sdk";
const client = new KnoxCall({ tenant: "acme" });
await client.routes.list();
```

The SDK reads `AWS_WEB_IDENTITY_TOKEN_FILE`, exchanges the token for a KnoxCall access token, and uses it. No secrets stored.

## Lambda / EC2 without IRSA — static client credentials

If you're on Lambda or EC2 without IRSA, the SDK falls back to plain `client_credentials`: the static `KNOXCALL_CLIENT_ID` + `KNOXCALL_CLIENT_SECRET` env vars. There is no IMDSv2 / EC2 instance-identity path — the SDK only reads `AWS_WEB_IDENTITY_TOKEN_FILE` for the OIDC flow and otherwise uses these env vars. Store them in AWS Secrets Manager or Lambda environment variables encrypted with a KMS key.

For Lambda with IRSA via container images, the IRSA env vars are set automatically by the Lambda runtime — same SDK works.

## Troubleshooting

* **`Could not detect KnoxCall credentials`** — `AWS_WEB_IDENTITY_TOKEN_FILE` is unset. Verify the pod's service account is annotated with `eks.amazonaws.com/role-arn`.
* **`invalid_grant: no binding matched`** — decode the JWT (`cat $AWS_WEB_IDENTITY_TOKEN_FILE | cut -d. -f2 | base64 -d`) and compare its `arn` claim to your binding.
