发布

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

    frostbyte_neo 发布于 2026-04-29 14:17:23 +00:00 | 931 次提交 在此版本后已推送到 main

    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.ts
      createEcrRepository 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.


    Co-authored-by: nicktrn 55853254+nicktrn@users.noreply.github.com

    下载附件