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 withEnforceto every prod function. SCP-denylambda:UpdateFunctionCodewithout 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
- Secret-Aware Context Filters: Stop AI Editors From Shipping Keys
- Agent Tool Allowlists: Least Privilege for Filesystem and Shell Access
- Cross-Account Bedrock Access: Platform Teams Without Shared Keys
- Secure AI Sandboxes: Ephemeral ECS Tasks for Agent Tool Execution
Last updated on September 11, 2026
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
