S3 and ECR Prerequisites for BYOC on AWS
What the S3 bucket and ECR endpoints in an AWS BYOC stack are used for, the permission set behind each one, and why Region placement decides your transfer bill.
An AWS BYOC stack needs one S3 bucket in the same Region as the stack, which holds artifact cache objects and runner system logs, and it needs a network path to ECR, which the stack provisions as VPC endpoints rather than as a repository you name up front. The authority to actually pull an image comes from a separate place: the instance profile you attach to a runner set, which the WarpBuild connection role never touches.
This page covers what each object stores, the permission set behind it, the failure you see when a piece is missing, and why the Region you pick at stack creation decides the transfer line on your AWS bill. The full prerequisite checklist lives in the AWS BYOC configuration guide, and the account-level view of the setup is on BYOC runners on AWS for GitHub Actions.
Overview
BYOC runs on AWS, GCP, and Azure. On AWS, storage and registry access break into four objects, and only two of them are things you decide.
| Prerequisite | What it holds or carries | Who creates it | Changeable after stack creation |
|---|---|---|---|
| Stack S3 bucket | Artifact cache objects and runner system logs | The CloudFormation template in create mode, or you supply an existing bucket in import mode | No. The stack name, the bucket, and the Region are fixed at creation |
| S3 gateway VPC endpoint | Runner traffic to that bucket, kept on the AWS network | The stack | Yes, endpoint management is part of the stack |
| ECR API and ECR Docker interface endpoints | Image pulls from runners in public and private subnets | The stack, automatically | Yes |
| Runner instance profile | The authority a job step holds to log in to ECR and read or write your own buckets | You, per runner set | Yes |
The bucket is the one irreversible choice on the list. Because the bucket, the stack name, and the Region are locked together at creation, teams that want runners in two AWS Regions create two stacks with two buckets rather than repointing one.
Inside the bucket, WarpBuild writes two prefixes with documented shapes, which is what makes lifecycle rules and cost queries straightforward to write:
- Cache:
<bucket_name>/<org_id>/artifact_cache/<vcs_org>/<vcs_repo>/<vcs_ref>/<version>/<key> - Telemetry:
<bucket_name>/runner/logs/all/<runner_id>.<log_file_name>
ECR has no equivalent line item, because the stack does not store images. It provisions the path, and your registry stays where it already is.
Architecture
Both prerequisites exist to keep bytes off metered paths. The stack provisions an S3 gateway endpoint for the bucket and ECR API and ECR Docker interface endpoints for image pulls, so cache traffic and registry traffic stay on the AWS network instead of leaving through a NAT gateway or the public internet. Those endpoints keep working when the runner security group has outbound-only rules, because the runner always initiates the connection.
| Traffic | Endpoint type | Used by |
|---|---|---|
| Cache reads and writes to the stack bucket | S3 gateway endpoint | The WarpBuild cache action during a job |
| Runner system logs | S3, outbound HTTPS | The runner telemetry writer |
docker login and image manifest calls | ECR API interface endpoint | Job steps on runners in public and private subnets |
| Layer downloads and uploads | ECR Docker interface endpoint | The same job steps |
One version detail matters here. Stacks created with CloudFormation template versions before v1.4 can hit ECR authentication failures, usually surfacing as an ecr login that times out, for runners placed in public subnets. The documented fix is a stack upgrade to template v1.4 through the WarpBuild dashboard. If a public subnet runner cannot log in while a private subnet runner in the same stack can, check the template version before you rewrite any IAM policy. AWS documents the endpoint behavior itself in the ECR VPC endpoints guide.
Configuration
Two identities carry the permissions, and mixing them up is the most common setup mistake on this surface.
The connection role, named warpbuild-<integration-id> and created by the CloudFormation connection stack, holds the StoragePermissions context. That context covers the stack bucket only: s3:CreateBucket, s3:ListBucket, s3:GetBucketLocation, s3:GetObject, s3:PutObject, s3:DeleteObject, the multipart actions, the bucket and object ACL actions, the bucket policy actions, and s3:PutLifecycleConfiguration with its matching read. It also carries EBS snapshot actions. It holds no ECR actions at all. The NetworkPermissions context is what lets the stack create and delete the VPC endpoints described above, through ec2:CreateVpcEndpoint and ec2:DeleteVpcEndpoints. The full policy document is expanded in the configuration guide, and the context-by-context walkthrough is on IAM permissions for BYOC on AWS.
The runner instance profile is what your job steps run as. It is set per runner set, under Custom Runner configuration and the Instance Profile ARN field, and WarpBuild injects nothing into it. A pull-only profile for a deploy pipeline is short:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ecr:GetAuthorizationToken"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:<region>:<account-id>:repository/<your-repo>"
}
]
}ecr:GetAuthorizationToken has to sit on Resource: "*" because the token is issued at account level rather than per repository. Everything else is scoped to the repository ARN. Push pipelines add ecr:PutImage and the three layer upload actions on the same resource, and jobs that write artifacts to a bucket of your own add s3:PutObject, s3:GetObject, and s3:ListBucket on that bucket ARN. Both examples are written out in the security hardening guide.
With the profile attached, a workflow needs no credential handling:
name: deploy
on:
push:
branches: [main]
jobs:
ship:
runs-on: warp-custom-deploy-linux
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/amazon-ecr-login@v2
- run: docker pull <account-id>.dkr.ecr.<region>.amazonaws.com/<your-repo>:latest
- run: ./scripts/deploy.shEach prerequisite fails in its own way, which is what makes this list worth reading before a security review rather than during an incident.
| Missing piece | What breaks | What keeps working |
|---|---|---|
StoragePermissions on the connection role | Cache reads and writes fail, runner system logs stop being pushed, lifecycle configuration cannot be applied | Jobs still run, at cold-cache speed |
ec2:CreateVpcEndpoint in NetworkPermissions | The stack cannot create or replace the S3 and ECR endpoints, so that traffic falls back to whichever metered path the subnet has | An already-created stack, until an endpoint changes |
ecr:GetAuthorizationToken on the instance profile | docker login to ECR fails outright, before any repository policy is consulted | Every step that does not touch the registry |
| Repository-scoped ECR read actions | Login succeeds and the pull fails on the first layer | Login, and any repository the profile does list |
| Stack template older than v1.4 | ECR authentication can time out for runners in public subnets | Runners in private subnets on the same stack |
| A bucket lifecycle policy | Nothing fails; cache objects and logs accumulate and the storage line grows every month | All job behavior |
Operations
Region placement is the decision that shows up on the bill rather than in a log. The bucket is required to sit in the stack's Region, and the stack is where the runners launch, so the cache side is handled by following the prerequisite. The registry side is yours to place, and four AWS prices decide what that placement costs. All four were checked on 2026-08-13.
| Path | AWS price | When you pay it |
|---|---|---|
| ECR to other services in the same Region | $0.00 per GB (Amazon ECR pricing) | Registry and runners in one Region |
| Across Availability Zones in the same Region | $0.01 per GB in each direction (Amazon EC2 On-Demand pricing) | Subnets spread for instance availability while the resources they read sit in one zone |
| Managed NAT data processing | $0.045 per GB in US East (N. Virginia), plus $0.045 per hour (Amazon VPC pricing) | Runners in private subnets, on everything leaving through that path |
| ECR across Regions | Internet data transfer rates on both sides; the AWS worked example uses $0.09 per GB (Amazon ECR pricing) | Registry in one Region, runners in another |
Same-Region placement plus the endpoints the stack provisions is what turns the first row into the row you are on. A registry one Region away from the runners moves the same gigabytes onto the last row, and the workflow file looks identical either way. The per-pull arithmetic, including the storage charge of $0.10 per GB-month per retained image version, is worked through on what pulling images from ECR costs your pipeline.
Two habits keep this surface quiet after setup. Set an S3 lifecycle policy on the stack bucket, with seven days of retention as the documented recommendation, because cache objects and telemetry logs are both written on every job and neither expires on its own. And scope your VPC endpoint policies to the repositories and buckets the runners actually need, which narrows the endpoints without touching the security group.
Costs split cleanly along the same line as the permissions. WarpBuild charges $0.002 per runner minute for BYOC Linux runners and $0.002 per runner minute for BYOC Windows runners, while your own AWS account is billed directly for EC2, EBS, S3 storage, and data transfer at your account rates, including discounts you already hold (WarpBuild pricing, checked 2026-08-13). The Linux and Windows sets are the ones an AWS stack launches.
One enterprise note for pull-heavy pipelines: egress costs are handled on the enterprise tier; see zero egress on the WarpBuild enterprise tier.
For the full inventory of objects a stack creates in your account, including the buckets, the endpoints, and the tags they carry, see what WarpBuild creates in your cloud account.
FAQ
Does the S3 bucket have to be in the same Region as the runners?
Yes. The bucket must sit in the same Region as the stack, and the stack name, bucket, and Region are all fixed at creation time. Runners launch inside that stack, so a bucket in another Region would put every cache read and write on a cross-Region path.
Do I have to create an ECR repository before the stack works?
No. WarpBuild configures the ECR API and ECR Docker VPC endpoints automatically for runners in public and private subnets. What you supply is the authority: an instance profile attached to the runner set that allows ecr:GetAuthorizationToken plus the read actions on the repositories your jobs pull.
Why does docker login to ECR time out on public subnet runners?
Stacks created with CloudFormation template versions before v1.4 can hit ECR authentication failures for runners in public subnets. Upgrading the stack to template v1.4 through the WarpBuild dashboard is the documented fix.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.