Skip to content

AWS access for jobs

A job reaches an AWS account only when its pipeline file says so, and only the accounts it names. Three pieces line up:

  1. A target AWS account, added to your execution plane: a profile name and an account id.
  2. A role named ci in that account, trusting your plane.
  3. aws in the pipeline file, naming the profiles a component’s jobs — or an environment’s deploys — may use.

On the aws page, under your connected account, choose + add a target AWS account:

  • profile: the name jobs use for it — dev, prod, data. Lower-case letters, digits and hyphens, starting with a letter; not default.
  • account: the twelve-digit account id.

Adding one changes nothing in that account. It lets your plane’s task role ask to assume the account’s ci role; the role still has to agree.

2. Create the ci role in the target account

Section titled “2. Create the ci role in the target account”

In each target account, a role named exactly ci, trusting the account your execution plane is in — the jobs’ own role there is tagged squidci:role = task:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<PLANE_ACCOUNT_ID>:root" },
"Action": ["sts:AssumeRole", "sts:TagSession"],
"Condition": {
"StringEquals": { "aws:PrincipalTag/squidci:role": "task" }
}
}
]
}

sts:TagSession is required: each job’s session carries tags a policy can read — squidci:repository (owner/name), squidci:commit and squidci:job. To let only one repository’s jobs in, add to the condition:

"aws:PrincipalTag/squidci:repository": "your-org/your-repo"

Give the role what your deploys need. A CI role commonly has broad rights in the account it deploys; the trust policy and the pipeline file are what narrow who becomes it. Sessions last an hour and the SDKs refresh them, so long jobs are fine.

# yaml-language-server: $schema=https://squidci.com/schema/pipelines.json
infra:
aws:
profile: prod # what plain `aws` uses
profiles: [prod, data] # everything the jobs may use
region: eu-west-2 # where they work; the plane's region otherwise
run:
- aws sts get-caller-identity # as prod's ci role
- aws --profile data s3 ls # as data's ci role

Each profile becomes an AWS CLI profile of that name, chaining from the job’s own credentials to that account’s ci role, so every SDK and tool that reads AWS profiles works: aws --profile data …, AWS_PROFILE=data cdk deploy. profile is set as AWS_PROFILE, so plain aws means it.

It is enforced, not a convenience. A job’s credentials can assume only the ci roles of the profiles its component names, whatever a step does with them. A profile no execution plane of yours has makes the file invalid; a component whose profiles no single plane has all of waits for one that does.

A deploy gets its environment’s aws, in place of the component’s — wholly, region included:

environments:
dev:
aws: {profile: dev, region: eu-west-1}
prod:
aws: {profile: prod, region: eu-west-2}
after: dev
api:
aws: {profile: tools} # check, test, build: the tools account
build:
- make build
deploy:
- make deploy # dev's account in dev, prod's in prod

region sets AWS_REGION and AWS_DEFAULT_REGION in the job. Without it, a job’s region is your execution plane’s. Tools that take the region from the environment — most of them — then work in the right place. SquidCI’s own work for the job, its cache and artifacts, stays in the plane’s region whatever the job’s is.

No target account at all. Its own credentials reach only its run’s artifacts in your plane, and the plane’s staging repository for images.

Pull requests ignore aws entirely, and their jobs get no AWS credentials: until someone merges it, the pipeline file is its author’s, and honouring its aws would let anyone who can open a pull request assume your roles.