Skip to content

Commit

Permalink
Add packer-pipeline config and Packer template for Lambda image build
Browse files Browse the repository at this point in the history
- csvd_config_packer.hcl: packer-pipeline config for tf-run-executor-builder CodeBuild project
- packer.pkr.hcl: Packer template; uses cloned lambda/python:3.12 from private ECR
- buildspec.yml.j2: Jinja2 buildspec template (copied from eks lambda, generic)

Clones public.ecr.aws/lambda/python:3.12 into tf-run-executor/lambda-python:3.12
Uses pip --proxy for dependency install inside the Packer Docker container.
  • Loading branch information
Dave Arnold committed May 11, 2026
1 parent de3d3a7 commit 0f1b01f
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 0 deletions.
93 changes: 93 additions & 0 deletions buildspec.yml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
version: 0.2

env:
variables:
PACKER_TEMPLATE_FILE: "{{ packer_template_file }}"
AWS_REGION: "{{ aws_region }}"
ECR_REPOSITORY: "{{ ecr_repository }}"
AWS_ACCOUNT_ID: "{{ aws_account_id }}"
{% if environment_variables %}
{% for key, value in environment_variables.items() %}
{{ key }}: "{{ value }}"
{% endfor %}
{% endif %}

phases:
install:
commands:
- echo "Installing Packer and dependencies for Service Catalog Lambda build..."
{% if tools %}
{% for tool in tools %}
- echo "Installing {{ tool.name }} version {{ tool.version }}..."
- aws s3 cp s3://{{ assets_bucket }}/{{ tool.zip_path }} /tmp/{{ tool.zip_path }}
- unzip -o /tmp/{{ tool.zip_path }} -d /tmp/{{ tool.name }}
- chmod +x /tmp/{{ tool.name }}/{{ tool.binary_name }}
- mv /tmp/{{ tool.name }}/{{ tool.binary_name }} {{ tool.install_path }}/
- {{ tool.binary_name }} version
{% endfor %}
{% endif %}
- echo "Packer installation complete"

pre_build:
commands:
- echo "Initializing Packer plugins for Lambda container build..."
- packer init ${PACKER_TEMPLATE_FILE}
- echo "Packer plugins initialized successfully"

build:
commands:
- echo "Building Service Catalog Lambda container image..."

# Get ECR login credentials
- echo "Logging into ECR..."
- aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

# Build repository URI for ECR
- |
if [ -n "$ECR_REPOSITORY" ]; then
REPOSITORY_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}"
else
echo "ERROR: ECR_REPOSITORY is required for container builds"
exit 1
fi

# Set image tag
- |
if [ -n "$IMAGE_VERSION_TAG" ]; then
TAG="$IMAGE_VERSION_TAG"
elif [ -n "$IMAGE_TAG" ]; then
TAG="$IMAGE_TAG"
else
TAG="latest"
fi

# Get ECR credentials for Packer
- ECR_USERNAME="AWS"
- ECR_PASSWORD=$(aws ecr get-login-password --region ${AWS_REGION})
- ECR_LOGIN_SERVER="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"

# Use the cloned base image from ECR instead of public ECR
- BASE_IMAGE="{{ base_image }}"

- echo "Building with repository_uri=$REPOSITORY_URI tag=$TAG base_image=$BASE_IMAGE"

# Run Packer build with required variables for Lambda container
- |
packer build \
-var "repository_uri=$REPOSITORY_URI" \
-var "tag=$TAG" \
-var "base_image=$BASE_IMAGE" \
-var "ecr_login_username=$ECR_USERNAME" \
-var "ecr_login_password=$ECR_PASSWORD" \
-var "ecr_login_server=$ECR_LOGIN_SERVER" \
${PACKER_TEMPLATE_FILE}

post_build:
commands:
- echo "Service Catalog Lambda container image build completed successfully"
- echo "Image pushed to $REPOSITORY_URI:$TAG"
- echo "Lambda function is ready for deployment with EventBridge and Service Catalog"

artifacts:
files:
- '**/*'
104 changes: 104 additions & 0 deletions csvd_config_packer.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// csvd_config_packer.hcl — Packer Pipeline Configuration for tf-run-executor Lambda
// Builds the Lambda container image that triggers CodeBuild tf-run runs from CFN.
//
// ACCOUNT-SPECIFIC VALUES: Fields marked (*) are account-specific.
// Update them when deploying to a new AWS account or region.
//
// Usage:
// source ~/.env-csvd && export AWS_DEFAULT_REGION=us-gov-west-1
// packer-pipeline --config csvd_config_packer.hcl --wait
//
// After the build completes (SUCCEEDED), force the Lambda to pull the new image:
// aws lambda update-function-code \
// --function-name tf-run-executor-trigger \
// --image-uri 229685449397.dkr.ecr.us-gov-west-1.amazonaws.com/tf-run-executor/lambda:latest \
// --region us-gov-west-1

packer_pipeline {
// Environment name — used to derive bucket names (convention: {env}-packer-pipeline-{builds|assets})
environment_name = "csvd"

// Required parameters
packer_template_file = "packer.pkr.hcl"
s3_bucket = "csvd-packer-pipeline-builds"
assets_bucket = "csvd-packer-pipeline-assets"
codebuild_project_name = "tf-run-executor-builder"

// Tools — Packer binary fetched from S3 (releases.hashicorp.com is blocked on Census network)
tools = [
{
name = "packer"
version = "1.10.3"
zip_path = "packer_1.10.3_linux_amd64.zip"
binary_name = "packer"
install_path = "/usr/local/bin"
}
]

// (*) AWS Account Configuration
account_number = "229685449397" // csvd-dev, us-gov-west-1
partition = "aws-us-gov"

// Role management — let packer-pipeline auto-create a builder role
// (separate from the tf-run-executor-codebuild runtime role managed by deploy/)
create_role = true

// Region / partition
aws_region = "us-gov-west-1"
gov_cloud = true

// Build settings
s3_key_prefix = "packer-builds/tf-run-executor"
compute_type = "BUILD_GENERAL1_MEDIUM"
image = "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
buildspec_template = "buildspec.yml.j2"

// Push the built image to ECR after packer completes
additional_post_build_commands = "docker push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:${IMAGE_TAG}"

// Don't package these into the S3 zip — CodeBuild doesn't need them
exclude_dirs = [
"deploy",
"design-docs",
"service-catalog",
"scripts",
"data",
".terraform",
".git"
]

// (*) VPC — same subnet/SG used by the existing EKS builder project in csvd-dev
vpc_config {
vpc_id = "vpc-00576a396ec570b94"
subnet_ids = ["subnet-0b1992a84536c581b"]
security_group_ids = ["sg-0641c697588b9aa6b"]
}

// Environment variables injected into the CodeBuild environment during build
environment_variables = {
ECR_REPOSITORY = "tf-run-executor/lambda"
// (*) AWS_ACCOUNT_ID must match account_number above
AWS_ACCOUNT_ID = "229685449397"
IMAGE_TAG = "latest"
HTTP_PROXY = "http://proxy.tco.census.gov:3128"
HTTPS_PROXY = "http://proxy.tco.census.gov:3128"
// NO_PROXY: bypass proxy for EC2 metadata, S3 gateway endpoint, ECR, AWS services, internal Census hosts
NO_PROXY = "169.254.169.254,169.254.170.2,.s3.us-gov-west-1.amazonaws.com,.s3.amazonaws.com,.s3-fips.us-gov-west-1.amazonaws.com,.dkr.ecr.us-gov-west-1.amazonaws.com,.ecr.us-gov-west-1.amazonaws.com,sts.us-gov-west-1.amazonaws.com,logs.us-gov-west-1.amazonaws.com,github.e.it.census.gov,nexus.it.census.gov"
ECR_REGISTRY = "229685449397.dkr.ecr.us-gov-west-1.amazonaws.com"
}

// Clone base image from public ECR into private ECR before building
// (public.ecr.aws is accessible via Census proxy; cloning avoids repeated pulls)
ecr_registry_name = "tf-run-executor"

ecr_clone_images = [
{
name = "lambda-python"
tag = "3.12"
source_registry = "public.ecr.aws"
source_image = "lambda/python"
source_tag = "3.12"
enabled = true
}
]
}
105 changes: 105 additions & 0 deletions packer.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# packer.pkr.hcl — Packer template for tf-run-executor Lambda
#
# Builds the Lambda container image that handles CFN Custom Resource events:
# validates inputs, starts the tf-run-executor CodeBuild project, polls it,
# and returns the PR URL to CloudFormation.
#
# Build via packer-pipeline (not directly):
# source ~/.env-csvd && export AWS_DEFAULT_REGION=us-gov-west-1
# packer-pipeline --config csvd_config_packer.hcl --wait

packer {
required_plugins {
docker = {
source = "github.com/hashicorp/docker"
version = "~> 1"
}
amazon = {
source = "github.com/hashicorp/amazon"
version = "~> 1"
}
}
}

variable "repository_uri" {
type = string
default = ""
description = "ECR repository URI for the tf-run-executor Lambda Docker image"
}

variable "tag" {
type = string
default = "latest"
description = "Docker image tag"
}

variable "terraform_version" {
type = string
default = "1.9.1"
description = "Not used in Lambda builds; required by packer-pipeline schema"
}

variable "base_image" {
type = string
default = "229685449397.dkr.ecr.us-gov-west-1.amazonaws.com/tf-run-executor/lambda-python:3.12"
description = "Base Lambda Python 3.12 image (cloned into private ECR by ecr_clone_images)"
}

variable "ecr_login_username" {
type = string
default = ""
}

variable "ecr_login_password" {
type = string
default = ""
sensitive = true
}

variable "ecr_login_server" {
type = string
default = ""
}

source "docker" "lambda" {
image = var.base_image
commit = true
changes = [
"WORKDIR /var/task",
"CMD [ \"app.lambda_handler\" ]"
]
}

build {
name = "tf-run-executor-lambda"
sources = ["source.docker.lambda"]

# Copy only the Lambda source files into the container
provisioner "file" {
source = "lambda/requirements.txt"
destination = "/var/task/requirements.txt"
}

provisioner "file" {
source = "lambda/app.py"
destination = "/var/task/app.py"
}

# Install Python dependencies
# pip uses --proxy to route through Census proxy; avoids needing to set env vars inside Docker
provisioner "shell" {
inline = [
"cd /var/task",
"echo 'Installing tf-run-executor Lambda dependencies...'",
"pip install --no-cache-dir --proxy http://proxy.tco.census.gov:3128 -r requirements.txt",
"echo 'Lambda image build complete.'"
]
}

post-processors {
post-processor "docker-tag" {
repository = var.repository_uri
tags = [var.tag]
}
}
}

0 comments on commit 0f1b01f

Please sign in to comment.