Lambda Code Signing: Enforce CI-Built Artifacts in Every Account

Lambda Code Signing: Enforce CI-Built Artifacts in Every Account

Console “Upload .zip” is an incident waiting for a tired engineer. Code signing makes unsigned artifacts a hard deny in every account: only CI-built, signer-profile-attested packages update production functions. That is the unfair advantage — provenance as IAM, not as a wiki page.

⚡ TL;DR: Create a signing profile (PLATFORM or AWSLambda), sign in CI after npm ci/esbuild, attach a code-signing config with Enforce to every prod function. SCP-deny lambda:UpdateFunctionCode without signing when possible; block console upload paths. Combine with Secret-Aware Context Filters and Agent Tool Allowlists so agents cannot push unsigned blobs.

Signing profile + CI attestation

# .github/workflows/lambda-sign.yml
jobs:
  build-sign:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - name: Package
        run: (cd dist && zip -r ../function.zip .)
      - name: Start signing job
        run: |
          JOB=$(aws signer start-signing-job \
            --source "s3={bucketName=$BUCKET,key=function.zip,version=$VER}" \
            --destination "s3={bucketName=$BUCKET,prefix=signed/}" \
            --profile-name prod-lambda-signing)
          echo "job=$JOB" >> $GITHUB_OUTPUT
// BAD: laptop zip uploaded via console
aws lambda update-function-code --function-name checkout --zip-file fileb://local.zip

// GOOD: deploy only the signed S3 object ARN produced by Signer
aws lambda update-function-code \
  --function-name checkout \
  --s3-bucket "$BUCKET" --s3-key "signed/function.zip"

✅ Signer job in the same pipeline that ran tests.
❌ Signing a zip that engineers can replace in S3 without bucket policies / object lock.

Enforce on the function

{
  "CodeSigningConfigArn": "arn:aws:lambda:REGION:ACCT:code-signing-config:csc-xxx",
  "Description": "prod enforce",
  "AllowedPublishers": {
    "SigningProfileVersionArns": [
      "arn:aws:signer:REGION:ACCT:/signing-profiles/prod-lambda-signing/X"
    ]
  },
  "CodeSigningPolicies": {
    "UntrustedArtifactOnDeployment": "Enforce"
  }
}

Warn is for migration week. Enforce is production. Attach the CSC at function create time; drift-detect with Config rules if someone removes it.

Org-wide guardrails

{
  "Effect": "Deny",
  "Action": ["lambda:UpdateFunctionCode", "lambda:CreateFunction"],
  "Resource": "arn:aws:lambda:*:*:function:prod-*",
  "Condition": {
    "StringNotEquals": {
      "aws:RequestedRegion": "us-east-1"
    }
  }
}

Pair with permissions boundaries that deny lambda:PutFunctionCodeSigningConfig removal except for the platform role. Cross-account deploys: grant Signer profile use via Cross-Account Bedrock Access-style role assumption patterns (platform signs, app accounts consume).

Closing checklist

  • [ ] Signing profile owned by platform; versions pinned in CSC
  • [ ] CI signs only after tests; artifacts land in write-protected prefix
  • [ ] Prod functions use UntrustedArtifactOnDeployment=Enforce
  • [ ] Console/local zip updates denied by IAM/SCP for prod-*
  • [ ] Config rule alerts if CSC detached
  • [ ] Runbook for emergency break-glass with dual control

Related reading

Last updated on September 11, 2026


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply