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:ListBucketon 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 thests:ExternalIdcondition. Treat as moderately sensitive (a confused-deputy mitigation, not a full secret).
You will provide back to Argmin:
- The
role_arnoutput fromterraform 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:
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:
- Ask Argmin for a new
external_id. - Update
terraform.tfvarsandterraform apply. - Confirm Argmin can still assume the new role before destroying the old trust.
Removing access¶
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¶
- Module source:
infra/aws/onboarding/ - Verify script:
infra/aws/onboarding/scripts/verify.sh - Trust & security model
- Security policy: https://github.com/argmin-com/.github/blob/main/SECURITY.md