Skip to content

Onboarding: AWS

This guide wires your AWS environment into Argmin. It assumes one AWS account and one customer-side workload identity (GitHub Actions OIDC, EKS IRSA, or similar) that will assume the role.

Time required

~15 minutes of click-and-paste, plus a single terraform apply.

What this grants Argmin

A cross-account IAM role that Argmin assumes from its own production account, restricted to read-only APIs:

  • Cost & billing — Cost Explorer (ce:Get*), Cost & Usage Report S3 bucket (s3:GetObject / s3:ListBucket on the CUR bucket only), pricing catalog (pricing:*).
  • Bedrock (optional, default on) — foundation/custom model metadata, invocation-logging configuration, inference profiles, provisioned-throughput inventory.
  • CloudWatch & CloudTrail — metrics, log events, and Bedrock API call history for the period under analysis.
  • Identity inventory — IAM roles/users listing (no policy mutation) and Organizations hierarchy read.

It does not grant write access to any AWS API. check_permissions.py in the platform repo enforces this at gate time; the role's policy is verifiable in infra/aws/onboarding/main.tf.

Step 1 — Get the values Argmin will provide

Email contact@argmin.co and ask for:

  • argmin_account_id — the AWS account ID Argmin assumes from.
  • external_id — a per-customer string for the sts:ExternalId condition. Treat as moderately sensitive (a confused-deputy mitigation, not a full secret).

You will provide back to Argmin:

  • The role_arn output from terraform apply.
  • The S3 bucket where your Cost & Usage Reports are delivered (cur_bucket_name).
  • (Optional) the cur_report_prefix, if your CUR uses a non-default prefix.

Step 2 — Configure your terraform.tfvars

Create terraform.tfvars in infra/aws/onboarding/ (or wherever you've vendored the module):

aws_region        = "us-east-1"               # the region your CUR bucket lives in
argmin_account_id = "<from Argmin>"
external_id       = "<from Argmin>"
cur_bucket_name   = "my-org-cur-bucket"
cur_report_prefix = "cur/"                    # optional, default depends on your CUR config

enable_bedrock_access = true                  # default true; flip to false if not using Bedrock

A complete terraform.tfvars.example ships in the module directory.

Step 3 — Apply

cd infra/aws/onboarding
terraform init
terraform plan        # confirm the role + policies that will be created
terraform apply

terraform apply prints two outputs:

  • role_arn — paste this into your reply to Argmin.
  • granted_permissions — a human-readable summary of what was granted; keep for audit.

Step 4 — Verify

You don't have to take Argmin's word that access is read-only. From inside your AWS account:

cd infra/aws/onboarding
./scripts/verify.sh

The script assumes the role under the same trust policy Argmin uses, then exercises one Get/List call per granted service. Pass = each call returns success or a 4xx that's clearly an access-scoped not-found (not 403). Any 403 means a permission gap; any 200 on a write API is a security finding and the script exits non-zero.

Step 5 — Hand the role ARN to Argmin

Reply to your onboarding email with:

role_arn:        <terraform output>
cur_bucket:      <bucket name>
cur_prefix:      <prefix>           (if non-default)
region(s):       us-east-1, ...     (any region where you want Bedrock or CW Logs inventoried)
notes:           <anything Argmin should know about your account layout>

Argmin responds within 1 business day confirming the role is reachable and that ingestion has started.

Rotating the external_id

Recommended every 12 months:

  1. Ask Argmin for a new external_id.
  2. Update terraform.tfvars and terraform apply.
  3. Confirm Argmin can still assume the new role before destroying the old trust.

Removing access

cd infra/aws/onboarding
terraform destroy

This deletes the IAM role and its policies; Argmin loses visibility within ~5 minutes. Notify Argmin first so attribution ingestion can pause cleanly.

Troubleshooting

Symptom Most likely cause
Argmin reports "AccessDenied" assuming the role external_id mismatch — confirm with your onboarding contact.
Argmin reports CUR data is missing CUR bucket name or prefix doesn't match terraform.tfvars.
Argmin reports Bedrock data is missing enable_bedrock_access = false, or Bedrock invocation logging isn't enabled. See AWS docs.
terraform apply fails on iam:CreateRole The caller lacks IAM admin. Run as a user with IAMFullAccess or equivalent.

Reference