diff --git a/buildspec.yml.j2 b/buildspec.yml.j2 new file mode 100644 index 0000000..fd4ea2c --- /dev/null +++ b/buildspec.yml.j2 @@ -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: + - '**/*' diff --git a/csvd_config_packer.hcl b/csvd_config_packer.hcl new file mode 100644 index 0000000..8c4b84b --- /dev/null +++ b/csvd_config_packer.hcl @@ -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 + } + ] +} diff --git a/packer.pkr.hcl b/packer.pkr.hcl new file mode 100644 index 0000000..93805d6 --- /dev/null +++ b/packer.pkr.hcl @@ -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] + } + } +}