Skip to content

feat(webapp): apply default repository policy on ECR repo creation#3467

Merged
nicktrn merged 3 commits intotriggerdotdev:mainfrom
ThullyoCunha:fix/ecr-default-repository-policy
Apr 29, 2026
Merged

feat(webapp): apply default repository policy on ECR repo creation#3467
nicktrn merged 3 commits intotriggerdotdev:mainfrom
ThullyoCunha:fix/ecr-default-repository-policy

Conversation

@ThullyoCunha
Copy link
Copy Markdown
Contributor

Summary

Self-hosters that operate the webapp's ECR account separately from the account running the EKS workers (e.g., a shared platform account that hosts the registry plus per-team accounts that host clusters) currently hit a 403 Forbidden the first time any project is deployed:

Failed to pull image "<acct-A>.dkr.ecr.<region>.amazonaws.com/<namespace>/proj_…:…":
unexpected status from HEAD request to .../v2/.../manifests/sha256:…: 403 Forbidden

ensureEcrRepositoryExists in apps/webapp/app/v3/getDeploymentImageRef.server.ts calls CreateRepository and PutLifecyclePolicy, but never SetRepositoryPolicy — so the new repo inherits the AWS default (only the registry-owner account can read/pull). Workers in the cluster account get 403 every single deploy. The only workarounds today are running a one-off post-create script or pre-creating every repo by hand.

Proposed change

Add an optional env var:

DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY  (V4 mirror: V4_DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY)

Raw IAM policy JSON. When set, the webapp calls SetRepositoryPolicy immediately after CreateRepository so every new repo carries that policy from creation. Operators control the principal/actions; we don't bake in any opinions about cross-account boundaries.

Example value (for the typical self-host case — grant pull to the cluster account):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowClusterAccountPull",
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::<cluster-account-id>:root"},
    "Action": [
      "ecr:GetDownloadUrlForLayer",
      "ecr:BatchGetImage",
      "ecr:BatchCheckLayerAvailability"
    ]
  }]
}

Why env var (not a chart-level field)

  • Mirrors the shape of the sibling vars (DEPLOY_REGISTRY_ECR_TAGS, DEPLOY_REGISTRY_ECR_ASSUME_ROLE_ARN, etc.) which are already operator-supplied via webapp.extraEnvVars in self-host setups.
  • Cloud is unaffected — the env var is optional, unset by default; existing behavior unchanged.
  • Existing repos are unaffected — only newly-created repos get the policy.
  • RepositoryCreationTemplate from the AWS provider isn't an alternative here: it only applies to repos created via pull-through-cache or replication, not to ecr:CreateRepository API calls.

Implementation

  • apps/webapp/app/env.server.ts — declare DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY and the V4 fallback.
  • apps/webapp/app/v3/registryConfig.server.ts — propagate ecrDefaultRepositoryPolicy to RegistryConfig.
  • apps/webapp/app/v3/getDeploymentImageRef.server.tscreateEcrRepository accepts the policy; if set, calls SetRepositoryPolicy after PutLifecyclePolicy.
  • docs/self-hosting/env/webapp.mdx — documentation row added under Deploy & Registry.

Verification

Verified end-to-end against a self-hosted Trigger.dev on EKS where the ECR account is separate from the cluster account:

  • Without the env var (current main): the new project's first run pod stays in ImagePullBackOff with 403 Forbidden.
  • With the env var set to a JSON granting ecr:BatchGetImage/GetDownloadUrlForLayer/BatchCheckLayerAvailability to the cluster account: a fresh trigger.dev deploy --env prod followed by a hello-world run completes in ~5s end-to-end on the first try.

Manually also confirmed that existing repos are untouched (the call only fires inside createEcrRepository, which only runs when DescribeRepositories returned RepositoryNotFoundException).

Out of scope

  • Chart values surface for this — operators already pass the existing ECR vars via webapp.extraEnvVars, so this follows the same pattern. Happy to add a first-class chart field in a follow-up if that's the preferred direction.
  • IAM-policy validation in the webapp — we forward the JSON verbatim to AWS and surface AWS's error messages on misuse, matching how DEPLOY_REGISTRY_ECR_TAGS is handled today.

This is a draft pending CI / CodeRabbit pass — happy to iterate on direction (e.g., split into per-action env vars, or extend the chart values schema) if any of the above choices feels off.

Self-hosters that run the webapp's ECR account separately from their EKS
worker account hit a 403 Forbidden on every new project's first run:
`ensureEcrRepositoryExists` calls CreateRepository but never sets a
repository policy, so kubelet can't pull the runner image cross-account.

Add an optional `DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY` env
var (raw IAM policy JSON, V4 mirror as well). When set, the webapp
calls SetRepositoryPolicy after CreateRepository, baking the operator's
cross-account pull rule into every new repo automatically.

Existing repos are unaffected — they keep their current policy.
Cloud is unaffected — the env var is optional and unset by default.

Verified locally against a self-host on EKS with cross-account ECR:
without the policy, runners stayed in ImagePullBackOff with 403; with
it, the same flow completes a hello-world run end-to-end in ~5s.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 28, 2026

⚠️ No Changeset found

Latest commit: 2299221

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Adds optional environment variables DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY and V4_DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY (v4 falls back to v3). Extends RegistryConfig with ecrDefaultRepositoryPolicy, threads that value from getRegistryConfig through getDeploymentImageRef into ensureEcrRepositoryExists/createEcrRepository, and applies the provided raw IAM policy to newly created ECR repositories using SetRepositoryPolicyCommand. For existing repositories, the code attempts idempotent policy reconciliation and catches/logs reconciliation failures instead of throwing.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding support for applying a default ECR repository policy on repository creation.
Description check ✅ Passed The PR description is comprehensive and detailed, covering the problem, proposed change, implementation details, and verification; required template sections are addressed with substantive content.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

Mirrors how the existing-repo branch already reconciles cache settings.
SetRepositoryPolicy is idempotent, so applying it on every deploy is
safe and covers two recovery cases that the previous version didn't:

1. A previous repo creation succeeded but SetRepositoryPolicy failed
   mid-flight, leaving the repo without a policy. Without
   reconciliation, the existing-repo branch would just return the repo
   and runners would keep getting 403 Forbidden forever — manual
   intervention required.
2. The operator updates DEPLOY_REGISTRY_ECR_DEFAULT_REPOSITORY_POLICY
   to grant pull to additional accounts/principals. Existing repos
   need to pick up the new value, not just freshly created ones.

The factored `applyEcrRepositoryPolicy` helper is shared between the
create and reconcile call sites, keeping behavior identical.
@ThullyoCunha ThullyoCunha marked this pull request as ready for review April 29, 2026 13:04
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@nicktrn nicktrn enabled auto-merge (squash) April 29, 2026 14:17
@nicktrn nicktrn merged commit f173659 into triggerdotdev:main Apr 29, 2026
2 of 35 checks passed
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 0 new potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants