Stop Building on Your Laptop: Automating Lambda Builds with GitHub Actions
"It works on my machine" is not a deployment strategy.
If you are the only person on your team who knows the exact docker run command to deploy the production Lambda, you are a liability. You have a "Bus Factor" of 1. If you get sick, your laptop dies, or you go on vacation, production is frozen.
Manual deployments are fragile. They depend on your local Docker version, your internet connection, and your uncommitted local changes.
The solution is to move your terminal to the cloud.
This guide will show you how to take the bulletproof Docker build we mastered in previous articles and automate it inside a GitHub Actions pipeline using modern, secure OIDC authentication.
The Shift: Moving the Terminal to the Cloud
CI/CD (Continuous Integration / Continuous Deployment) sounds complex, but it is simple: It is a computer in the cloud running the commands you used to type manually.
Instead of:Code -> Your Laptop -> AWS
The flow becomes:Code -> GitHub -> GitHub Runner (The Cloud Terminal) -> AWS
This guarantees that what is in the repo is exactly what runs in production.
The Security Upgrade: Stop Using Access Keys
Before we write the pipeline, we must fix a security hole.
The Old Way: Creating an IAM User, generating AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, and pasting them into GitHub Secrets.
- The Risk: Keys last forever. If they leak, an attacker owns your account.
The Right Way: OIDC (OpenID Connect).
This is the modern standard. GitHub asks AWS for a temporary token for a specific build.
The Setup (One-Time):
You need to create an IAM Role in AWS that trusts your specific GitHub repository.
Trust Policy Example (JSON):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
}
}
}
]
}
Replace 123456789012 with your Account ID and my-org/my-repo with your GitHub details.
The Workflow: A Production-Grade Pipeline
Create a file in your repo at .github/workflows/lambda-deploy.yml.
This pipeline assumes we are building a Deployment Package (Code + Dependencies together), which is the standard starting point for most teams.
name: Deploy Lambda
on:
push:
branches:
- main # Only run when code is pushed to main
permissions:
id-token: write # Required for OIDC authentication
contents: read # Required to checkout code
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
# Optimization: Cache NPM modules to speed up builds
- name: Cache Node Modules
id: cache-npm
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/MyGitHubDeployRole
aws-region: us-east-1
- name: Build with Docker (The Golden Command)
# We mount the GitHub Runner's npm cache (~/.npm) into the Docker container
# so 'npm ci' doesn't have to re-download the internet every time.
run: |
# Ensure cache directory exists to avoid Docker mount errors
mkdir -p ~/.npm
docker run --rm \
--platform linux/amd64 \
-v "$PWD":/var/task \
-v "$HOME/.npm":/root/.npm \
amazonlinux:2023 \
bash -c "npm ci && zip -r function.zip ."
- name: Deploy to AWS Lambda
run: |
aws lambda update-function-code \
--function-name my-production-function \
--zip-file fileb://function.zip
Critical Architecture Note:
In the Docker command above, we used --platform linux/amd64.
- If your Lambda runs on Intel (x86_64), keep it as is.
- If your Lambda runs on Graviton (ARM64), you must change it to
--platform linux/arm64.
Pro Tips for Power Users
- Branch Protection: Go to your GitHub Repo Settings -> Branches. Enable "Require status checks to pass before merging." This stops anyone (even you) from breaking
main. - OIDC Flexibility: The JSON policy above is strict (only
mainbranch). If you want to allow any branch to deploy to a dev environment, changeStringEqualstoStringLikeand use a wildcard:"repo:my-org/my-repo:*". - Code vs. Layers: This pipeline builds a "Fat Zip" (Code + Deps). If you followed our Layers Guide, you would split this into two workflows: one that builds/publishes the Layer (rarely changes), and one that zips/deploys the Code (changes often).
Conclusion
By moving your build to GitHub Actions, you eliminate the "Human Element."
You no longer have to worry if your colleague is building on an M5 Mac vs. an Intel PC, or if they forgot to run npm install. The pipeline is the source of truth.
It works on the machine that matters: The Cloud.
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.
.jpeg)

Comments
Post a Comment