From 3a1163135708c55af3b4b858cb9e70daad0f3777 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 3 Mar 2026 14:36:56 -0500 Subject: [PATCH] updating documentation --- .gitignore | 2 + config_packer.hcl => csvd_config_packer.hcl | 18 +- .../SERVICE_CATALOG_CENSUS_INTEGRATION.md | 619 ++++++++++++++---- lab_config_packer.hcl | 97 +++ 4 files changed, 599 insertions(+), 137 deletions(-) rename config_packer.hcl => csvd_config_packer.hcl (69%) create mode 100644 lab_config_packer.hcl diff --git a/.gitignore b/.gitignore index b16cc7b..f5f8850 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ build/ dist/ venv/ docs/venv/ +# Packer pipeline zip files +eks-terragrunt-repo-generator-builder.zip diff --git a/config_packer.hcl b/csvd_config_packer.hcl similarity index 69% rename from config_packer.hcl rename to csvd_config_packer.hcl index 9d2e12c..781cc5f 100644 --- a/config_packer.hcl +++ b/csvd_config_packer.hcl @@ -2,10 +2,15 @@ // Builds the Lambda container that renders Terragrunt HCL files into new GitHub repos. packer_pipeline { + // Environment name — used to derive bucket names when not explicitly set + // Convention: {environment_name}-packer-pipeline-{builds|assets} + // Run `packer-pipeline init` to create buckets and download tools for a new environment + environment_name = "csvd" + // Required parameters packer_template_file = "packer.pkr.hcl" // Relative path within the repo to the Packer template - s3_bucket = "csvd-template-automation-builds" // S3 bucket for artifacts - assets_bucket = "image-pipeline-assets-dev" // S3 bucket containing tool assets + s3_bucket = "csvd-packer-pipeline-builds" // S3 bucket for artifacts (derived from environment_name) + assets_bucket = "csvd-packer-pipeline-assets" // S3 bucket containing tool assets (derived from environment_name) codebuild_project_name = "eks-terragrunt-repo-generator-builder" // Name for the CodeBuild project // Tools configuration @@ -64,7 +69,14 @@ packer_pipeline { IMAGE_TAG = "latest" HTTP_PROXY = "http://proxy.tco.census.gov:3128" HTTPS_PROXY = "http://proxy.tco.census.gov:3128" - NO_PROXY = "public.ecr.aws,pypi.org,github.e.it.census.gov,files.pythonhosted.org,nexus.it.census.gov,public.ecr.aws" + // NO_PROXY: things that should bypass the proxy entirely + // - 169.254.* = EC2 metadata / ECS task credentials + // - .s3.*amazonaws.com = S3 via VPC gateway endpoint + // - .dkr.ecr / .ecr = private ECR via internal routing + // - sts / logs = AWS service endpoints via internal routing + // - github.e.it / nexus = internal census hosts + // Everything else (pypi.org, files.pythonhosted.org, public.ecr.aws) goes through proxy + 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" // ECR registry URL } diff --git a/design-docs/SERVICE_CATALOG_CENSUS_INTEGRATION.md b/design-docs/SERVICE_CATALOG_CENSUS_INTEGRATION.md index 5f38cc6..f1a0276 100644 --- a/design-docs/SERVICE_CATALOG_CENSUS_INTEGRATION.md +++ b/design-docs/SERVICE_CATALOG_CENSUS_INTEGRATION.md @@ -1,7 +1,8 @@ # Integration Plan: EKS Repo Generator → terraform-service-catalog-census -**Date:** February 20, 2026 -**Author:** David Arnold +**Date:** February 20, 2026 +**Last Updated:** March 3, 2026 +**Author:** David Arnold **Status:** DRAFT --- @@ -10,6 +11,10 @@ This document outlines the plan to integrate the EKS Terragrunt Repository Generator product into the centralized `terraform-service-catalog-census` repo, which manages all enterprise Service Catalog portfolios and products via Terragrunt. Currently, our Service Catalog product (portfolio, product, launch constraints) is managed independently in `lambda-template-repo-generator/deploy/`. Integrating into the census repo aligns us with the enterprise pattern and enables org-wide sharing of the product. +This plan is designed for **enterprise-wide deployment from the outset**. Rather than starting with a single account and expanding later, we classify every resource by its deployment scope (central, StackSet, or census-managed) and plan for org-wide availability from day one. + +> **Note:** The Service Catalog resources in `lambda-template-repo-generator/deploy/service_catalog.tf` have never been deployed to a production environment and are not in active use. This means there is no live product to migrate, no users to protect, and no coordination window required. The integration is a net-new greenfield deployment — the old SC code can be deleted without `terraform state rm` or cutover sequencing. + --- ## 1. Current Architecture (As-Is) @@ -80,70 +85,264 @@ terraform-service-catalog-census/ 1. **Portfolios** are defined in YAML files under `//configurations/portfolios/` 2. **Products** are defined in YAML files under `//configurations/products//` 3. **Product templates** (CFN YAMLs) live in `templates/products//.yaml` -4. **Launch roles** are deployed via CFN StackSets (shared across the org) +4. **Launch roles and service actions** are deployed via CFN StackSets to all shared accounts 5. The `sc-product` module creates an S3 bucket, uploads templates, creates products, and creates provisioning artifacts 6. The `main-module/service-catalog/main.tf` wires portfolios → products → constraints +**Active StackSets (deployed today by the census repo):** + +| StackSet Name | Module | What It Deploys | Scope | +|---|---|---|---| +| `CensusServiceCatalog-RoleAndAction-{region}` | `cfn-roles-actions` | IAM launch roles, Lambda functions, Service Catalog actions (SSM automations), action ID SSM params | All OU-shared accounts | +| `CensusServiceCatalog-ActionAssociation-{region}` | `cfn-deployment` | `AWS::ServiceCatalog::ServiceActionAssociation` resources that link actions to product versions | All OU-shared accounts | +| `CensusServiceCatalog-DyanamoDB-Table-ARN-SSM-Parameter-{region}` | `cfn-deployment` | SSM parameter `/enterprise/service-catalog/project_dynamodb_table_arn` | All OU-shared accounts | +| `CensusServiceCatalog-SSM-Parameter-{region}` | `ssm-parameter` main-module | General-purpose SSM parameters (currently `ssm_parameters = {}` — empty, ready to use) | All OU-shared accounts | + +All StackSets use `permission_model = SERVICE_MANAGED` with `auto_deployment { enabled = true }`, meaning any new account that joins a shared OU automatically receives the stack instances. + **Key difference from our approach:** - Census uses **YAML-driven configuration** (portfolios + products defined in YAML, not HCL) - Products are **versioned** (multiple YAML files per product: `1-0-0.yaml`, `1-1-0.yaml`, etc.) -- Launch roles are created via **CFN StackSets** (shared across the org), not per-account Terraform +- Launch roles are created via the **`cfn-roles-actions` StackSet** (auto-deployed org-wide), not per-account Terraform - Product templates are **static files** loaded from disk (not `templatefile()` rendered) - The `sc-product` module creates its **own S3 bucket** for artifacts (not a shared one) +- SSM parameters for shared resources are pushed to all accounts via the **`ssm-parameter` StackSet** --- -## 2. Integration Approach: Product-Only (Recommended) +## 2. Enterprise Deployment Model + +### Resource Classification + +Every resource in our system falls into one of three deployment tiers, based on where it needs to exist and how it gets there: + +| Tier | What | Deployment Mechanism | Scope | +|------|------|---------------------|-------| +| **Central Infrastructure** | Lambda, ECR, SSM params, API GW | Terraform (`lambda-template-repo-generator/deploy/`) | Single central account only | +| **StackSet Resources** | Launch role (IAM) | CFN StackSet via census `cfn-roles-actions` module | Every account in shared OUs (auto-deployed) | +| **Service Catalog Resources** | Portfolio, product, constraints, S3 artifacts | Terragrunt via census `main-modules/service-catalog` | Central SC admin account; shared to org via portfolio share | + +### Tier 1: Central Infrastructure (single account — our Terraform) + +These resources run the actual automation. They are deployed **once** in the Service Catalog admin account (`prod/operations-gov` account, or `csvd-dev-gov` for testing) via `lambda-template-repo-generator/deploy/`. Every other account invokes this Lambda cross-account. + +| Resource | Terraform Resource | Notes | +|----------|-------------------|-------| +| Lambda function | `aws_lambda_function` | Executes repo creation logic | +| IAM execution role | `aws_iam_role` (lambda) | Lambda assumes this for AWS API access | +| ECR repository + image | `aws_ecr_repository` | Container image built by `packer-pipeline` | +| API Gateway | `aws_apigatewayv2_api` | Alternative invocation endpoint | +| CloudWatch Log Group | `aws_cloudwatch_log_group` | Lambda logging | +| SSM parameters | `aws_ssm_parameter` | Lambda config (`GITHUB_API`, `GITHUB_ORG_NAME`, etc.) | +| Secrets Manager secret | Pre-existing | GitHub token | +| VPC config | Input variables | Network access to GHE | +| **Lambda resource policy** | `aws_lambda_permission` | **Must allow cross-account invocation (see below)** | -### Strategy +> **Cross-account invocation requirement:** The Lambda currently has a resource policy allowing CloudFormation invocation scoped to `source_account = data.aws_caller_identity.current.account_id` (single account only). For enterprise deployment, this must be broadened to allow CloudFormation from **any account in the organization** to invoke the Lambda. When a user in Account B provisions the Service Catalog product, CloudFormation in Account B creates a stack containing the `Custom::GitHubRepository` resource, and CloudFormation itself invokes the Lambda's `ServiceToken` cross-account. Without an org-scoped resource policy on the Lambda, this invocation fails with `AccessDeniedException`. +> +> **Required change to `terraform-aws-template-automation/main.tf`:** +> ```hcl +> # Replace the existing single-account CloudFormation permission: +> resource "aws_lambda_permission" "cloudformation" { +> statement_id = "AllowCloudFormationInvokeOrgWide" +> action = "lambda:InvokeFunction" +> function_name = aws_lambda_function.this.function_name +> principal = "cloudformation.amazonaws.com" +> # Remove source_account and add org condition: +> principal_org_id = data.aws_organizations_organization.current.id +> } +> ``` +> Alternatively, use a condition key: `aws:PrincipalOrgID` if `principal_org_id` is not supported for the `cloudformation.amazonaws.com` principal. -Move only the **Service Catalog product definition** (portfolio, product, constraints) into `terraform-service-catalog-census`. Keep the **Lambda infrastructure** (Lambda function, IAM execution role, ECR, VPC config, SSM parameters) in `lambda-template-repo-generator/deploy/`. +### Tier 2: StackSet Resources (all shared accounts — census cfn-roles-actions) -### Why Product-Only? +These resources **must exist locally in every account** where users can provision the product. They are deployed via the census repo's `CensusServiceCatalog-RoleAndAction-{region}` StackSet, which uses `permission_model = SERVICE_MANAGED` and `auto_deployment { enabled = true }`. -| Concern | Product-Only ✅ | Full Migration ❌ | -|---------|----------------|-------------------| -| Separation of concerns | SC catalog management separate from Lambda code | Everything in one monolith | -| Deploy independence | Lambda deploys independently of SC product catalog | Coupled deploy cycles | -| Census repo pattern | Matches existing products (ec2, rds, s3, etc.) | Would be an outlier requiring Lambda + ECR modules | -| Launch role | Already exists in Lambda's deploy/; referenced by name | Would need CFN StackSet role template | -| Org-wide sharing | Prod operations-gov deployment shares to org | Already shared per-account | -| Risk | Low — just moving YAML + config | High — must migrate Terraform state for Lambda, IAM, etc. | +| Resource | Purpose | Why It Must Be Local | +|----------|---------|---------------------| +| SC launch role (`eks-terragrunt-sc-launch-role`) | Service Catalog assumes this role to create the CFN stack | Service Catalog resolves the `launch_role` by **name** in the **local account**. If the role doesn't exist, provisioning fails immediately. | -### What Moves vs. What Stays +**Launch role permissions (to be defined in CFN role template snippet):** -| Component | Current Location | After Integration | -|-----------|-----------------|-------------------| -| **Product template YAML** | `service-catalog/product-template.yaml` | `terraform-service-catalog-census/templates/products/eks-terragrunt-repo/2-0-0.yaml` | -| **Portfolio definition** | `deploy/service_catalog.tf` (HCL) | `/configurations/portfolios/eks-terragrunt.yaml.tftpl` (YAML) | -| **Product definition** | `deploy/service_catalog.tf` (HCL) | `/configurations/products/eks-terragrunt-repo/EKS_REPO.yaml.tftpl` (YAML) | -| **Launch constraint** | `deploy/service_catalog.tf` (HCL) | Product YAML `launch_role` field | -| **Template constraint** | `deploy/service_catalog.tf` (HCL) | Product YAML `template_constraints` field | -| Lambda function | `deploy/main.tf` | **STAYS** in `lambda-template-repo-generator/deploy/` | -| IAM execution role | `deploy/main.tf` | **STAYS** | -| ECR repo + image | `deploy/main.tf` + packer-pipeline | **STAYS** | -| SSM parameters | `deploy/main.tf` | **STAYS** | -| VPC configuration | `deploy/main.tf` | **STAYS** | -| SC launch role | `deploy/service_catalog.tf` | **STAYS** (referenced by name in product YAML) | +```yaml +EksTerragruntScLaunchRole: + Type: AWS::IAM::Role + Properties: + RoleName: eks-terragrunt-sc-launch-role + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: servicecatalog.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: invoke-lambda-and-cfn + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: InvokeLambda + Effect: Allow + Action: lambda:InvokeFunction + Resource: arn:aws-us-gov:lambda:REGION:CENTRAL_ACCOUNT_ID:function:eks-terragrunt-repo-gen-template-automation + - Sid: CloudFormationOperations + Effect: Allow + Action: + - cloudformation:CreateStack + - cloudformation:DeleteStack + - cloudformation:DescribeStacks + - cloudformation:DescribeStackEvents + - cloudformation:GetTemplate + - cloudformation:GetTemplateSummary + - cloudformation:ValidateTemplate + - cloudformation:UpdateStack + - cloudformation:SetStackPolicy + Resource: "*" + - Sid: S3ReadTemplate + Effect: Allow + Action: s3:GetObject + Resource: "*" + Condition: + StringEquals: + s3:ExistingObjectTag/servicecatalog:provisioning: "true" + - Sid: S3ListBucket + Effect: Allow + Action: + - s3:ListBucket + - s3:GetBucketLocation + Resource: arn:aws-us-gov:s3:::servicecatalog-product-artifacts-* +``` + +The existing census `cfn-roles-actions` module already handles: +- Creating the StackSet with `SERVICE_MANAGED` permissions +- Deploying stack instances to all OUs specified in `share_ou_ids` +- Auto-deploying to new accounts that join the OU +- Also creating a local CFN stack in the admin account itself + +All we need to do is add our role template YAML and reference it in the `roles.yaml` configuration. + +### Tier 3: Service Catalog Resources (central, shared via portfolio share) + +These resources are deployed **once** in the SC admin account via the census repo's Terragrunt configuration. They are **not** deployed via StackSet — instead, portfolio sharing (`aws_servicecatalog_portfolio_share`) makes them visible across the org. + +| Resource | How It's Shared | +|----------|----------------| +| Portfolio | `aws_servicecatalog_portfolio_share` (type: `ORGANIZATIONAL_UNIT`) pushes to all accounts in target OUs | +| Product + provisioning artifacts | Inherited through portfolio share | +| S3 bucket + template objects | Accessible cross-account because the launch role has `s3:GetObject` with tag condition | +| Principal associations (IAM patterns) | `share_principals = true` on the portfolio share propagates these to shared accounts | +| Launch constraint | Propagated via portfolio share (references role by name — role must exist locally, hence Tier 2) | +| Template constraint | Propagated via portfolio share (locks `LambdaFunctionArn` to central Lambda ARN) | + +### End-to-End Provisioning Flow (Cross-Account) + +``` +Account B (any workload account) Account A (SC admin / central) +┌────────────────────────────────┐ ┌─────────────────────────────┐ +│ │ │ │ +│ User sees shared portfolio │ │ │ +│ (from Tier 3 portfolio share) │ │ │ +│ ↓ │ │ │ +│ Clicks "Launch Product" │ │ │ +│ ↓ │ │ │ +│ SC assumes local launch role │ │ │ +│ (eks-terragrunt-sc-launch-role │ │ │ +│ — deployed by Tier 2 StackSet)│ │ │ +│ ↓ │ │ │ +│ SC creates CFN stack │ │ │ +│ ↓ │ │ │ +│ CFN reads product template │─s3:Get───→ │ S3 bucket (census-managed) │ +│ ↓ │ │ │ +│ CFN invokes ServiceToken │─invoke───→ │ Lambda processes request │ +│ (Custom::GitHubRepository) │ │ Creates GitHub repo, opens │ +│ │ │ PR, renders HCL files │ +│ CFN receives SUCCESS response │←─response─ │ ↓ │ +│ ↓ │ │ Sends response via S3 URL │ +│ Stack outputs: repo URL, PR │ │ │ +└────────────────────────────────┘ └─────────────────────────────┘ +``` + +**Three things must be in place for this flow to work:** +1. **Tier 2 (StackSet):** Launch role exists in Account B +2. **Tier 3 (Census):** Portfolio is shared to Account B's OU +3. **Tier 1 (Central):** Lambda resource policy allows CloudFormation from Account B --- -## 3. Integration Steps +## 3. Implementation Plan + +The implementation is organized by deployment tier, not by account. Each step addresses one tier of the deployment model. + +### Step 1: Enable Cross-Account Lambda Invocation (Tier 1) + +**Repo:** `terraform-aws-template-automation` +**What:** Update the Lambda resource policy to allow CloudFormation invocation from any account in the AWS Organization. + +The current `aws_lambda_permission.cloudformation` resource restricts `source_account` to the deploying account. This blocks cross-account Service Catalog provisioning. + +**Actions:** +1. Add `data "aws_organizations_organization" "current" {}` to the module. +2. Replace the existing `aws_lambda_permission.cloudformation` resource: + ```hcl + resource "aws_lambda_permission" "cloudformation_org" { + statement_id = "AllowCloudFormationInvokeOrgWide" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.this.function_name + principal = "cloudformation.amazonaws.com" + principal_org_id = data.aws_organizations_organization.current.id + } + ``` +3. Re-deploy `lambda-template-repo-generator/deploy/` to apply the updated module. + +**Validation:** Manually invoke the Lambda from a different account using the CloudFormation CLI to confirm cross-account invocation works. + +### Step 2: Create StackSet Launch Role Template (Tier 2) + +**Repo:** `terraform-service-catalog-census` +**What:** Add the launch role to the `cfn-roles-actions` StackSet so it is deployed to every account in the shared OUs. + +**Actions:** +1. Create `templates/role-templates/eks-terragrunt-launch-role.yaml` — a CFN resource snippet defining the IAM role (see the role template in Section 2, Tier 2 for the full definition). +2. Add a role entry to the `roles.yaml.tftpl` configuration for each target deployment: + - `prod/operations-gov/west/configurations/roles.yaml.tftpl` + - `prod/operations-gov/east/configurations/roles.yaml.tftpl` (if east region is needed) + - `non-prod/csvd-dev/west/configurations/roles.yaml.tftpl` (for testing) + + Example entry: + ```yaml + - template: eks-terragrunt-launch-role.yaml + parameters: + - parameter: CentralAccountId + value: "229685449397" + - parameter: LambdaRegion + value: us-gov-west-1 + ``` +3. Run `terragrunt apply` on the `service-catalog` module. The `cfn-roles-actions` module will: + - Update the `CensusServiceCatalog-RoleAndAction-{region}` StackSet with the new role in the template body + - Push updated stack instances to all accounts in the shared OUs + - The `auto_deployment { enabled = true }` ensures any new account that joins the OU gets the role automatically -### Phase 1: Prepare Product Template for Census Format +**Parameterization:** The role template should accept `CentralAccountId` and `LambdaRegion` as parameters so the Lambda ARN is not hardcoded in the YAML — it's assembled from parameters. This allows the same template to work for different central accounts (e.g., non-prod vs prod Lambda). -The census repo expects product templates as **static YAML files** in `templates/products//.yaml`. Our current template uses `LambdaFunctionArn` as a parameter with a Terraform-injected default. For census integration, we need the `LambdaFunctionArn` locked via a **template constraint** instead. +**Validation:** After StackSet deployment, check a workload account's IAM console to confirm `eks-terragrunt-sc-launch-role` exists with the correct trust policy and permissions. -**Action:** Create `templates/products/eks-terragrunt-repo/2-0-0.yaml` -- Copy from `service-catalog/product-template.yaml` -- Remove the `Default` value from `LambdaFunctionArn` parameter (will be locked by template constraint) -- Add `Metadata.ServiceCatalog.ProductVersion.Description` for census versioning support +### Step 3: Integrate Product into Census Repo (Tier 3) -### Phase 2: Create Portfolio YAML (per account/region) +**Repo:** `terraform-service-catalog-census` +**What:** Add the product template, portfolio YAML, and product YAML using the census repo's YAML-driven configuration pattern. -Create portfolio YAML files for each account/region where the product should be available. +#### 3a. Product Template -**File:** `non-prod/csvd-dev/west/configurations/portfolios/eks-terragrunt.yaml.tftpl` +Create `templates/products/eks-terragrunt-repo/2-0-0.yaml`: +- Copy from `lambda-template-repo-generator/service-catalog/product-template.yaml` +- Remove the `Default` value from the `LambdaFunctionArn` parameter (it will be locked by template constraint) +- The template is a static file — no `templatefile()` rendering + +#### 3b. Portfolio YAML + +Create portfolio definitions for `prod/operations-gov` (org-wide) and `non-prod/csvd-dev` (testing). + +**File:** `prod/operations-gov/west/configurations/portfolios/eks-terragrunt.yaml.tftpl` ```yaml eks-terragrunt-portfolio: @@ -156,14 +355,20 @@ eks-terragrunt-portfolio: - /aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_inf-admin-t2_* - /aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_AdministratorAccess_* - /aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_AWSAdministratorAccess_* - tags: + tags: {} associated_tag_options: share_ous: + - Enterprise-GOV:Workloads + - Enterprise-GOV:ProgramWorkloads + - Enterprise-GOV:Security:Production + - Enterprise-GOV:Infrastructure:Production ``` -### Phase 3: Create Product YAML (per account/region) +The `share_ous` field controls which OUs see this portfolio. Setting it here (rather than leaving it blank to inherit from `terraform.tfvars`) lets us scope sharing explicitly for our product. + +#### 3c. Product YAML -**File:** `non-prod/csvd-dev/west/configurations/products/eks-terragrunt-repo/EKS_REPO.yaml.tftpl` +**File:** `prod/operations-gov/west/configurations/products/eks-terragrunt-repo/EKS_REPO.yaml.tftpl` ```yaml eks_terragrunt_repo: @@ -177,95 +382,94 @@ eks_terragrunt_repo: template_constraints: Parameters: LambdaFunctionArn: >- - arn:aws-us-gov:lambda:${aws_region}:229685449397:function:eks-terragrunt-repo-gen-template-automation + arn:aws-us-gov:lambda:us-gov-west-1:CENTRAL_ACCOUNT_ID:function:eks-terragrunt-repo-gen-template-automation versions: - name: 2.0.0 file_path: /eks-terragrunt-repo/2-0-0.yaml ``` -### Phase 4: Handle the Launch Role - -The census system creates launch roles via **CFN StackSets** (see `templates/role-templates/`). Our launch role (`eks-terragrunt-sc-launch-role`) is currently created by our own Terraform in `deploy/service_catalog.tf`. - -**Two options:** - -#### Option A: Reference Existing Role (Simpler — Recommended for Phase 1) -Keep the launch role in our Terraform deployment. The product YAML's `launch_role` field references the role **by name** (not ARN), so it will work as long as the role exists in the target account. - -**Prerequisite:** Deploy `lambda-template-repo-generator/deploy/` first to create the role in each account. - -#### Option B: Create Census Role Template (Long-term) -Create a new role template at `templates/role-templates/eks-terragrunt-launch-role.yaml` and add it to the roles configuration. This would let the census StackSet create the role across all accounts automatically. +Key fields: +- `launch_role: eks-terragrunt-sc-launch-role` — references the role deployed by the Tier 2 StackSet by name +- `template_constraints.Parameters.LambdaFunctionArn` — locks the hidden `LambdaFunctionArn` CFN parameter to the central Lambda ARN so users cannot change it +- `versions[].file_path` — points to the static template YAML in `templates/products/` -**Complexity:** The launch role needs permissions for Lambda invoke, CloudFormation responses, S3 read (with tag condition), and CloudWatch Logs — all of which reference specific ARNs. This is better suited for Phase 2 when scaling to more accounts. +#### 3d. Non-prod configuration (for testing) -### Phase 5: Remove SC Resources from Lambda Deploy +Create identical files under `non-prod/csvd-dev/west/configurations/` but with `share_ous: []` (no sharing — local testing only) and the csvd-dev Lambda ARN in the template constraint. -After the census integration is deployed and verified: +### Step 4: Delete Old SC Code from Lambda Deploy -1. Remove from `deploy/service_catalog.tf`: - - `aws_servicecatalog_portfolio` - - `aws_servicecatalog_product` - - `aws_servicecatalog_provisioning_artifact` - - `aws_servicecatalog_product_portfolio_association` - - `aws_servicecatalog_principal_portfolio_association` - - `aws_servicecatalog_constraint` (both LAUNCH and TEMPLATE) - - `aws_s3_object.product_template` -2. Remove from `deploy/variables.tf`: - - `create_service_catalog` variable - - `service_catalog_config` variable -3. Remove from `deploy/terraform.tfvars`: - - `create_service_catalog` and `service_catalog_config` blocks -4. Run `terraform state rm` for each resource before removing code (to avoid destroy) -5. Keep the **launch role** resource (Option A) or remove it too (Option B) +**Repo:** `lambda-template-repo-generator` +**What:** Since the SC resources in `deploy/` were never deployed to production, no live state exists to protect. Delete the code directly and apply. -### Phase 6: Multi-Account Expansion +**Actions:** +1. Delete `deploy/service_catalog.tf` entirely +2. Remove from `deploy/variables.tf`: `create_service_catalog`, `service_catalog_config` +3. Remove from `deploy/terraform.tfvars`: SC-related blocks +4. Remove SC-related outputs from `deploy/main.tf` +5. Run `terraform plan` to confirm no unexpected changes, then `terraform apply` -Once validated in `csvd-dev/west`, add the product to other environments: - -``` -non-prod/csvd-dev/west/configurations/ ← Phase 1 (current account) -prod/operations-gov/west/configurations/ ← Phase 2 (org-wide via sharing) -non-prod/lab-dev/east/configurations/ ← Phase 3 (lab environments) -``` - -The `prod/operations-gov` deployment uses `to_share_portfolios = true` with OU sharing, which would make the product available to all workload accounts in the org. +> **This step can be done at any time** — before, during, or after Steps 1-3. Since nothing is deployed, there is no `terraform state rm` needed, no risk of breaking users, and no coordination window required. The simplest approach is to do this step first and unblock the repo from dead code immediately. --- ## 4. Prerequisites & Dependencies -### Before integration, the following must exist in each target account: +### Before enterprise deployment, the following must exist: + +| Prerequisite | How Created | Scope | Current State | +|-------------|-------------|-------|---------------| +| Lambda function | `lambda-template-repo-generator/deploy/` | Central account | ✅ Deployed in csvd-dev-gov | +| Lambda execution role | `lambda-template-repo-generator/deploy/` | Central account | ✅ Deployed | +| ECR image | `packer-pipeline` → CodeBuild | Central account | ✅ Built and pushed | +| GitHub token in Secrets Manager | Manual / separate deploy | Central account | ✅ Exists at `/eks-cluster-deployment/github_token` | +| SSM parameters | `terraform-aws-template-automation` | Central account | ✅ Deployed | +| VPC/subnet access to GHE | Network team | Central account | ✅ Configured | +| Lambda resource policy (org-wide) | `terraform-aws-template-automation` | Central account | ❌ **Needs update** (currently single-account only) | +| SC launch role via StackSet | `terraform-service-catalog-census` / `cfn-roles-actions` | All shared accounts | ❌ **Not yet created** | +| SC portfolio + product in census | `terraform-service-catalog-census` | SC admin account | ❌ **Not yet created** | + +### Deployment Order -| Prerequisite | How Created | Current State | -|-------------|-------------|---------------| -| Lambda function | `lambda-template-repo-generator/deploy/` | ✅ Deployed in csvd-dev-gov | -| Lambda execution role | `lambda-template-repo-generator/deploy/` | ✅ Deployed | -| ECR image | `packer-pipeline` → CodeBuild | ✅ Built and pushed | -| SC launch role | `lambda-template-repo-generator/deploy/` | ✅ `eks-terragrunt-sc-launch-role` exists | -| GitHub token in Secrets Manager | Manual / separate deploy | ✅ Exists at `/eks-cluster-deployment/github_token` | -| SSM parameters | `terraform-aws-template-automation` | ✅ Deployed | -| VPC/subnet access to GHE | Network team | ✅ Configured | +All three tiers must be deployed before end-users can provision the product. The order matters because each tier depends on the previous one: -### Dependency order for new account deployment: ``` -1. terraform-aws-template-automation (SSM params) -2. packer-pipeline build (Container image) -3. lambda-template-repo-generator (Lambda + IAM + ECR) ← keeps launch role -4. terraform-service-catalog-census (SC portfolio + product) ← NEW +Step 1: Tier 1 — Central Infrastructure + ├── terraform-aws-template-automation (update Lambda resource policy for org-wide CF invocation) + ├── packer-pipeline build (ensure container image is in ECR) + └── lambda-template-repo-generator (deploy Lambda + IAM execution role) + ↓ +Step 2: Tier 2 — StackSet Resources + └── terraform-service-catalog-census (add eks-terragrunt-launch-role.yaml to role-templates/ + and roles.yaml config; terragrunt apply pushes role + to all shared accounts via cfn-roles-actions StackSet) + ↓ +Step 3: Tier 3 — Service Catalog Resources + └── terraform-service-catalog-census (add portfolio YAML, product YAML, product template; + terragrunt apply creates portfolio, product, constraints, + and shares to org OUs) + ↓ +Step 4: Cleanup + └── lambda-template-repo-generator (terraform state rm old SC resources + remove code) ``` +> Steps 2 and 3 can be done in a single `terragrunt apply` of the `service-catalog` module since the roles and products are all wired together in `main-modules/service-catalog/main.tf`. However, it's recommended to apply the StackSet role first and verify it propagates before adding the product — not for user safety (nothing is live), but because a product without its launch role will fail immediately on first use. +> +> Step 4 (code cleanup) has no dependencies and can be done at any time, including before Steps 1-3. + --- ## 5. Risks & Mitigations | Risk | Impact | Mitigation | |------|--------|------------| -| Template constraint with hardcoded Lambda ARN | Breaks if Lambda ARN changes | ARN is deterministic (function name is fixed in Terraform) | -| Launch role doesn't exist in shared accounts | Product launch fails | Phase 1 uses Option A (role stays in Lambda deploy); Phase 2 adds CFN StackSet role | -| S3 tag-based SCP blocks template access | Template 403 during launch | Census `sc-product` module adds its own S3 bucket with proper tags | -| Duplicate portfolio/product during migration | Users see two products | Run `terraform state rm` on old resources before census deploy | -| Census repo uses different S3 bucket | Old provisioned products reference old S3 URL | Existing provisioned products are unaffected; new launches use new bucket | +| Lambda resource policy not updated before product goes live | CF in shared accounts gets `AccessDeniedException` when invoking Lambda | Step 1 must be completed and validated before Steps 2-3. Test cross-account CF invocation manually. | +| StackSet role propagation delay | Launch role not yet in all accounts when product becomes visible | Apply StackSet role (Step 2) and verify it reaches target accounts before applying product (Step 3). Check StackSet instances status in the CloudFormation console. | +| StackSet auto-deployment race condition | New account joins OU; StackSet hasn't propagated yet; first launch fails | Known census repo pattern (documented in `modules/cfn-roles-actions/actions.tf`). Wait a few minutes after account joins OU, or check StackSet instances status. | +| Template constraint with hardcoded Lambda ARN | Breaks if Lambda moves to a different account or changes function name | The function name (`eks-terragrunt-repo-gen-template-automation`) is deterministic and fixed in Terraform. The account ID is parameterized in the role template. If either changes, update the role template, product YAML, and re-apply both StackSet and product. | +| S3 tag-based SCP blocks template access | Template 403 during launch | Census `sc-product` module creates its own S3 bucket with `servicecatalog:provisioning = true` tag. The launch role's S3 policy uses this tag condition. | +| ~~Duplicate portfolio/product during migration~~ | ~~Not applicable~~ | The SC resources in `deploy/` were never deployed to production. There is nothing to migrate. Delete the old code directly. | +| Launch role `lambda:InvokeFunction` is cross-account | SCP or permission boundary in workload accounts blocks it | Verify that no SCP in the org denies cross-account Lambda invocation from the `servicecatalog.amazonaws.com` principal. | --- @@ -273,58 +477,96 @@ The `prod/operations-gov` deployment uses `to_share_portfolios = true` with OU s ``` terraform-service-catalog-census/ -├── templates/products/eks-terragrunt-repo/ -│ └── 2-0-0.yaml ← Product CFN template -├── non-prod/csvd-dev/west/configurations/ -│ ├── portfolios/eks-terragrunt.yaml.tftpl ← Portfolio definition -│ └── products/eks-terragrunt-repo/ -│ └── EKS_REPO.yaml.tftpl ← Product definition -└── (future) templates/role-templates/ - └── eks-terragrunt-launch-role.yaml ← Launch role (Phase 2) +│ +├── templates/ +│ ├── products/eks-terragrunt-repo/ +│ │ └── 2-0-0.yaml ← Product CFN template (static) +│ └── role-templates/ +│ └── eks-terragrunt-launch-role.yaml ← CFN IAM role snippet for StackSet +│ +├── prod/operations-gov/west/configurations/ +│ ├── portfolios/eks-terragrunt.yaml.tftpl ← Portfolio definition (org-wide sharing) +│ ├── products/eks-terragrunt-repo/ +│ │ └── EKS_REPO.yaml.tftpl ← Product definition + template constraint +│ └── roles.yaml.tftpl ← MODIFY: add eks-terragrunt-launch-role entry +│ +└── non-prod/csvd-dev/west/configurations/ + ├── portfolios/eks-terragrunt.yaml.tftpl ← Portfolio definition (no sharing — testing only) + ├── products/eks-terragrunt-repo/ + │ └── EKS_REPO.yaml.tftpl ← Product definition (csvd-dev Lambda ARN) + └── roles.yaml.tftpl ← MODIFY: add eks-terragrunt-launch-role entry ``` -**Total: 3 new files** (Phase 1), 1 additional file (Phase 2) +**New files: 6** (2 templates + 2 portfolio YAMLs + 2 product YAMLs) +**Modified files: 2** (roles.yaml.tftpl in prod and non-prod) --- -## 7. Files to Modify in lambda-template-repo-generator +## 7. Files to Modify in terraform-aws-template-automation + +| File | Change | +|------|--------| +| `main.tf` | Update `aws_lambda_permission.cloudformation` to allow org-wide invocation (remove `source_account`, add `principal_org_id`) | +| `main.tf` | Add `data "aws_organizations_organization" "current" {}` | + +## 8. Files to Remove/Modify in lambda-template-repo-generator -After census integration is live and validated: +After census integration is deployed and validated (Step 4): | File | Change | |------|--------| -| `deploy/service_catalog.tf` | Remove all SC resources (portfolio, product, constraints, S3 object) | +| `deploy/service_catalog.tf` | Remove entirely (all SC resources, launch role, constraints, S3 upload) | | `deploy/variables.tf` | Remove `create_service_catalog` and `service_catalog_config` variables | | `deploy/terraform.tfvars` | Remove `create_service_catalog` and `service_catalog_config` blocks | -| `deploy/main.tf` | Remove SC-related outputs | +| `deploy/main.tf` | Remove SC-related outputs (`service_catalog_portfolio_id`, `service_catalog_product_id`, `service_catalog_provisioning_url`, `cloudformation_template_example`) | | Documentation (.md files) | Update deployment instructions to reference census repo | -**Keep:** Lambda, IAM execution role, SC launch role (until Phase 2), ECR, VPC config, SSM params +**Keep in `deploy/`:** Lambda function, IAM execution role, ECR, VPC config, SSM params, API Gateway, CloudWatch, Lambda resource policy + +> No `terraform state rm` is needed — these SC resources were never deployed. Delete the code and apply. --- -## 8. Validation Checklist +## 9. Validation Checklist + +### After Step 1 (Tier 1 — Central): +- [ ] Lambda resource policy updated to allow org-wide CloudFormation invocation +- [ ] Manual test: invoke Lambda from a different account via CloudFormation Custom Resource succeeds +- [ ] Existing single-account Service Catalog provisioning still works (no regression) -- [ ] Product template uploaded to census-managed S3 bucket -- [ ] Portfolio visible in Service Catalog console +### After Step 2 (Tier 2 — StackSet): +- [ ] `CensusServiceCatalog-RoleAndAction-{region}` StackSet updated with new role template +- [ ] StackSet instances show as `CURRENT` in CloudFormation console for target OUs +- [ ] `eks-terragrunt-sc-launch-role` IAM role exists in at least 2-3 workload accounts (spot check) +- [ ] Role trust policy allows `servicecatalog.amazonaws.com` +- [ ] Role inline policy has correct Lambda ARN, CloudFormation, and S3 permissions + +### After Step 3 (Tier 3 — Census product): +- [ ] Portfolio visible in Service Catalog console in the SC admin account +- [ ] Portfolio shared to target OUs (verify in a workload account's SC console) - [ ] Product associated with portfolio - [ ] Launch constraint attached (references `eks-terragrunt-sc-launch-role`) - [ ] Template constraint locks `LambdaFunctionArn` parameter +- [ ] End-to-end test: provision product from a **workload account** (not the central account) - [ ] `scripts/test_service_catalog.py` passes against census-deployed product -- [ ] Old SC resources removed from `lambda-template-repo-generator` Terraform state -- [ ] No duplicate portfolios/products in console + +### After Step 4 (Cleanup): +- [ ] `deploy/service_catalog.tf` deleted +- [ ] SC-related variables and outputs removed +- [ ] `terraform plan` on `lambda-template-repo-generator/deploy/` shows no changes --- -## 9. Timeline Estimate +## 10. Timeline Estimate + +| Step | Work | Duration | +|------|------|----------| +| Step 4 | Delete `deploy/service_catalog.tf` + variables/outputs; `terraform apply` | 0.5 day | +| Step 1 | Update Lambda resource policy in `terraform-aws-template-automation`; redeploy Lambda; test cross-account invocation | 0.5 day | +| Steps 2+3 | Create CFN launch role template + portfolio/product YAMLs; single `terragrunt apply`; end-to-end test from workload account | 1.5 days | +| **Total** | | **2.5 days** | -| Phase | Work | Duration | -|-------|------|----------| -| Phase 1 | Create 3 files in census repo, test in csvd-dev | 1 day | -| Phase 2 | Remove old SC resources from Lambda deploy | 0.5 day | -| Phase 3 | Add to prod/operations-gov for org sharing | 0.5 day | -| Phase 4 (optional) | Create CFN StackSet launch role template | 1 day | -| **Total** | | **2-3 days** | +The fastest path: do Step 4 (dead code removal) immediately since it has no dependencies. Then Steps 1 and 4 can run in parallel (different repos). Steps 2 and 3 are one `terragrunt apply` — StackSet role first, wait for propagation, then product. --- @@ -342,7 +584,7 @@ After census integration is live and validated: - /path/pattern/* tags: {} associated_tag_options: {} - share_ous: [] # OU names for cross-account sharing + share_ous: [] # OU names for cross-account sharing (empty = inherit from terraform.tfvars) ``` ### Product YAML Schema @@ -351,7 +593,7 @@ After census integration is live and validated: name: string # Product name in SC console description: string # Product description type: CLOUD_FORMATION_TEMPLATE # or EXTERNAL - launch_role: string # IAM role NAME (not ARN) for launch constraint + launch_role: string # IAM role NAME (not ARN) — must exist locally in every target account distributor: string # Shown in console template_constraints: # Parameter constraints Parameters: @@ -371,3 +613,112 @@ Templates are static CFN YAML files at: templates/products//.yaml ``` Uploaded to S3 by the `sc-product` module. The module creates its own S3 bucket with prefix specified in `terraform.tfvars`. + +--- + +## Appendix B: Census StackSets Reference + +### StackSets currently deployed by the census repo: + +| StackSet Name | Module | Deployed Resources | Trigger | +|---|---|---|---| +| `CensusServiceCatalog-RoleAndAction-{region}` | `cfn-roles-actions` | IAM roles (from `role-templates/`), Lambda functions, SC actions, action ID SSM params | Entries in `roles.yaml` and `actions.yaml` | +| `CensusServiceCatalog-ActionAssociation-{region}` | `cfn-deployment` | `AWS::ServiceCatalog::ServiceActionAssociation` resources | Product `actions` field in product YAML | +| `CensusServiceCatalog-DyanamoDB-Table-ARN-SSM-Parameter-{region}` | `cfn-deployment` | SSM param: `/enterprise/service-catalog/project_dynamodb_table_arn` | `dynamodb_ssm_parameter_name` variable | +| `CensusServiceCatalog-SSM-Parameter-{region}` | `ssm-parameter` main-module | General-purpose SSM parameters | `ssm_parameters` map in `terraform.tfvars` (currently empty) | + +All StackSets: +- Use `permission_model = SERVICE_MANAGED` +- Use `auto_deployment { enabled = true }` — new OU accounts get stack instances automatically +- Deploy to OUs listed in `ou_names_to_share` (from `terraform.tfvars`) +- Are called as `DELEGATED_ADMIN` (not management account) +- Also create a local CFN stack in the SC admin account itself + +### How our launch role fits in: + +The `cfn-roles-actions` module reads role definitions from YAML files under `templates/role-templates/`, referenced by entries in `roles.yaml.tftpl`. Each role definition is a CFN resource snippet that gets merged into the StackSet's combined template body alongside other roles and actions. Adding our `eks-terragrunt-launch-role.yaml` is a standard operation — no module changes needed, just configuration. + +--- + +## Appendix C: Moving Lambda to a Different AWS Account + +If the central Lambda needs to be relocated to a different AWS account (e.g., promoting from `csvd-dev-gov` to `prod/operations-gov`, or account reorganization), all resources that reference the Lambda ARN by account ID must be updated. The Lambda ARN embeds the account ID: `arn:aws-us-gov:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME`. + +> **Applies post-integration only.** Since the current SC resources have never been deployed, the migration concern in this appendix applies only after the census integration is live and users are actively provisioning the product. + +### What needs to change and why + +| Resource | Where It Lives | What Changes | Why | +|----------|---------------|-------------|-----| +| Lambda function + all Tier 1 infra | `lambda-template-repo-generator/deploy/` | Re-deploy in new account | All central infrastructure moves with the Lambda | +| Lambda resource policy (`aws_lambda_permission.cloudformation_org`) | `terraform-aws-template-automation/main.tf` | No change required | Policy uses `principal_org_id` (org-wide org condition) — it allows CloudFormation from **any org account** to invoke the Lambda regardless of which account the Lambda lives in | +| ECR image URI | `terraform-aws-template-automation/main.tf`, Lambda env | Update `image_uri` to new account's ECR | Lambda container image must be in the same account as the Lambda | +| Launch role `lambda:InvokeFunction` ARN | `templates/role-templates/eks-terragrunt-launch-role.yaml` via `roles.yaml.tftpl` params | Update `CentralAccountId` parameter value | The IAM policy in every workload account has an explicit ARN — if the account ID changes, the policy no longer grants access to the new Lambda | +| Template constraint `LambdaFunctionArn` | `configurations/products/eks-terragrunt-repo/EKS_REPO.yaml.tftpl` | Update the ARN value | The locked `LambdaFunctionArn` CFN parameter will point to the old (now non-existent) Lambda; provisioning will fail with `ResourceNotFoundException` | +| GitHub token in Secrets Manager | New account — manual / separate deploy | Re-create the secret | Lambda reads this at runtime; must exist in the same account as the Lambda | +| SSM parameters | `terraform-aws-template-automation` | Re-deploy in new account | Lambda reads `GITHUB_API`, `GITHUB_ORG_NAME`, etc. at cold-start | +| VPC / subnet config | New account — network team | Configure GHE network access | Lambda requires network path to GHE in whatever VPC it runs in | + +### Migration runbook + +``` +1. DEPLOY to new account (before cutting over) + ├── Push ECR image to new account ECR + │ packer-pipeline build → push to NEW_ACCOUNT_ID.dkr.ecr.us-gov-west-1.amazonaws.com + ├── Re-create Secrets Manager secret in new account + │ /eks-cluster-deployment/github_token + └── Deploy Tier 1 infra in new account + cd lambda-template-repo-generator/deploy/ + # update backend config + aws profile for new account + terraform init -reconfigure + terraform apply + +2. VERIFY new Lambda is functional (before updating StackSet) + └── Test Lambda invocation directly in new account + aws lambda invoke --function-name eks-terragrunt-repo-gen-template-automation ... + +3. UPDATE StackSet launch role ARN (propagates to all shared accounts) + ├── Edit prod/operations-gov/west/configurations/roles.yaml.tftpl + │ change: value: "OLD_ACCOUNT_ID" + │ to: value: "NEW_ACCOUNT_ID" + ├── Edit non-prod/csvd-dev/west/configurations/roles.yaml.tftpl (same change) + └── cd terraform-service-catalog-census/prod/operations-gov/west/service-catalog/ + terragrunt apply + # CensusServiceCatalog-RoleAndAction StackSet updates all workload accounts + # Verify StackSet instances reach CURRENT status before next step + +4. UPDATE template constraint Lambda ARN in census product YAML + ├── Edit prod/operations-gov/west/configurations/products/eks-terragrunt-repo/EKS_REPO.yaml.tftpl + │ change: arn:aws-us-gov:lambda:us-gov-west-1:OLD_ACCOUNT_ID:function:... + │ to: arn:aws-us-gov:lambda:us-gov-west-1:NEW_ACCOUNT_ID:function:... + ├── Edit non-prod/csvd-dev version (same change to csvd-dev ARN if applicable) + └── terragrunt apply + # sc-product updates product version with new template constraint + +5. CUTOVER VALIDATION + ├── Provision the product from a workload account — confirm it invokes new Lambda + ├── Check CloudWatch logs in new account for the invocation + └── Confirm old account Lambda logs show no new invocations + +6. DECOMMISSION old Lambda (after validation window) + └── terraform destroy in old account (straightforward — no state rm needed if + the old deploy/ was cleanly managed) +``` + +> **Why step 3 must precede step 4:** Updating the StackSet role (step 3) takes time to propagate across all shared accounts via CloudFormation. If step 4 is applied first, the template constraint will lock the new ARN but the launch role still has the old ARN — resulting in a `lambda:InvokeFunction` permission denial. Always let the StackSet finish propagating before updating the product constraint. + +### Why parameterizing `CentralAccountId` matters + +The plan in Step 2 recommends parameterizing the account ID in the CFN role template rather than hardcoding it: + +```yaml +# In roles.yaml.tftpl — this is the ONLY place to change the account ID: +- template: eks-terragrunt-launch-role.yaml + parameters: + - parameter: CentralAccountId + value: "NEW_ACCOUNT_ID" # ← one change here propagates to ALL workload accounts + - parameter: LambdaRegion + value: us-gov-west-1 +``` + +Without parameterization, the account ID would be embedded directly in `eks-terragrunt-launch-role.yaml`, and the role template itself would need to be updated. With parameterization, the template file is static and account-agnostic — only the config value changes. This is the same reason the product YAML uses a `template_constraints` lock rather than the Default value in the CFN template. diff --git a/lab_config_packer.hcl b/lab_config_packer.hcl new file mode 100644 index 0000000..945778c --- /dev/null +++ b/lab_config_packer.hcl @@ -0,0 +1,97 @@ +// lab_config_packer.hcl - Packer Pipeline Configuration for lab-ew-operations-nonprod +// Builds the Lambda container that renders Terragrunt HCL files into new GitHub repos. +// Target account: 036728032133 (lab-ew-operations-nonprod), us-gov-west-1 + +packer_pipeline { + // Environment name — used to derive bucket names and tag resources + environment_name = "lab-ew-operations-nonprod" + + // Required parameters + packer_template_file = "packer.pkr.hcl" // Relative path within the repo to the Packer template + s3_bucket = "lab-ew-operations-nonprod-packer-pipeline-builds" + assets_bucket = "lab-ew-operations-nonprod-packer-pipeline-assets" + codebuild_project_name = "eks-terragrunt-repo-generator-builder" + + // Tools configuration + tools = [ + { + name = "packer" + version = "1.13.0" + zip_path = "packer_1.13.0_linux_amd64.zip" + binary_name = "packer" + install_path = "/usr/local/bin" + } + ] + + // AWS Account Configuration + account_number = "036728032133" + partition = "aws-us-gov" + + // Role management + create_role = true + + // Region and partition configuration + aws_region = "us-gov-west-1" + gov_cloud = true + + // Optional parameters with defaults + s3_key_prefix = "packer-builds/eks-terragrunt-repo-generator" + compute_type = "BUILD_GENERAL1_MEDIUM" + image = "aws/codebuild/amazonlinux2-x86_64-standard:3.0" + buildspec_template = "buildspec.yml.j2" + + // Post-build commands to push Docker image to ECR + additional_post_build_commands = "docker push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:${IMAGE_TAG}" + + // Exclude patterns for zip creation + exclude_dirs = [ + "design-docs", + "docs", + "dist", + "events", + "scripts", + "tests" + ] + + // VPC Configuration + // security_group_ids is intentionally empty — packer-pipeline will auto-create + // a security group named "-sg" in this VPC on first run. + vpc_config { + vpc_id = "vpc-0bba9aeb4e8e09ff8" + subnet_ids = ["subnet-020ff5ecc046a3983"] // us-gov-west-1a, 10.129.150.128/25 + security_group_ids = [] // auto-created by packer-pipeline + } + + // Environment variables for the CodeBuild environment + environment_variables = { + REPOSITORY_NAME = "eks-terragrunt-repo-generator-lambda" + ECR_REPOSITORY = "eks-terragrunt-repo-generator/lambda" + AWS_ACCOUNT_ID = "036728032133" + IMAGE_TAG = "latest" + HTTP_PROXY = "http://proxy.tco.census.gov:3128" + HTTPS_PROXY = "http://proxy.tco.census.gov:3128" + // NO_PROXY: things that should bypass the proxy entirely + // - 169.254.* = EC2 metadata / ECS task credentials + // - .s3.*amazonaws.com = S3 via VPC gateway endpoint + // - .dkr.ecr / .ecr = private ECR via internal routing + // - sts / logs = AWS service endpoints via internal routing + // - github.e.it / nexus = internal census hosts + // Everything else (pypi.org, files.pythonhosted.org, public.ecr.aws) goes through proxy + 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 = "036728032133.dkr.ecr.us-gov-west-1.amazonaws.com" + } + + // ECR Image Cloning Configuration + ecr_registry_name = "eks-terragrunt-repo-generator" + + ecr_clone_images = [ + { + name = "lambda-python" + tag = "3.11" + source_registry = "public.ecr.aws" + source_image = "lambda/python" + source_tag = "3.11" + enabled = true + } + ] +}