From 8da4b6740b654a919b7180f2080e24f76de6b0e9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 18 Sep 2025 16:20:48 -0400 Subject: [PATCH 1/2] working on integrating service-catalog --- examples/service-catalog.tfvars | 21 ++++++ main.tf | 126 ++++++++++++++++---------------- outputs.tf | 46 +++++++++--- templates/buildspec.yaml | 0 templates/codebuild.yaml | 0 templates/codepipeline.yaml | 0 templates/main.yml.tftpl | 73 ------------------ variables.tf | 55 ++++++++++++++ 8 files changed, 173 insertions(+), 148 deletions(-) create mode 100644 examples/service-catalog.tfvars create mode 100644 templates/buildspec.yaml create mode 100644 templates/codebuild.yaml create mode 100644 templates/codepipeline.yaml diff --git a/examples/service-catalog.tfvars b/examples/service-catalog.tfvars new file mode 100644 index 0000000..9ec5b53 --- /dev/null +++ b/examples/service-catalog.tfvars @@ -0,0 +1,21 @@ +# Example configuration with Service Catalog enabled +enable_service_catalog = true + +# Service Catalog Portfolio Configuration +portfolio_name = "DevOps Image Pipeline Portfolio" +portfolio_description = "Self-service deployment of standardized AWS image building pipelines" +portfolio_provider_name = "Platform Engineering Team" + +# Service Catalog Product Configuration +product_name = "AWS AMI Builder Pipeline" +product_description = "Automated pipeline for building custom AMIs using Packer, Ansible, and CodePipeline" +product_owner = "DevOps Team" + +# Grant access to specific IAM principals (replace with your actual ARNs) +principal_arns = [ + "arn:aws-us-gov:iam::123456789012:role/DeveloperRole", + "arn:aws-us-gov:iam::123456789012:user/john.doe", + "arn:aws-us-gov:iam::123456789012:group/DevOpsTeam" +] + +# ...existing variables... \ No newline at end of file diff --git a/main.tf b/main.tf index aabc91e..596eab7 100644 --- a/main.tf +++ b/main.tf @@ -23,17 +23,10 @@ data "archive_file" "buildspec" { output_path = "${path.module}/buildspec.zip" } -# Create a zip file containing the Packer configuration -data "archive_file" "packer_config" { - type = "zip" - source_file = "${path.module}/templates/build.pkr.hcl" - output_path = "${path.module}/packer_config.zip" -} - # Upload the nested stack templates to S3 resource "aws_s3_object" "kms_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/kms.yml" + key = "${var.template_prefix}kms.yml" source = "${path.module}/templates/kms.yml" etag = filemd5("${path.module}/templates/kms.yml") content_type = "application/x-yml" @@ -41,7 +34,7 @@ resource "aws_s3_object" "kms_template" { resource "aws_s3_object" "iam_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/iam.yml" + key = "${var.template_prefix}iam.yml" source = "${path.module}/templates/iam.yml" etag = filemd5("${path.module}/templates/iam.yml") content_type = "application/x-yml" @@ -49,7 +42,7 @@ resource "aws_s3_object" "iam_template" { resource "aws_s3_object" "s3_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/s3.yml" + key = "${var.template_prefix}s3.yml" source = "${path.module}/templates/s3.yml" etag = filemd5("${path.module}/templates/s3.yml") content_type = "application/x-yml" @@ -57,7 +50,7 @@ resource "aws_s3_object" "s3_template" { resource "aws_s3_object" "codebuild_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/codebuild.yml" + key = "${var.template_prefix}codebuild.yml" source = "${path.module}/templates/codebuild.yml" etag = filemd5("${path.module}/templates/codebuild.yml") content_type = "application/x-yml" @@ -65,60 +58,32 @@ resource "aws_s3_object" "codebuild_template" { resource "aws_s3_object" "codepipeline_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/codepipeline.yml" + key = "${var.template_prefix}codepipeline.yml" source = "${path.module}/templates/codepipeline.yml" etag = filemd5("${path.module}/templates/codepipeline.yml") content_type = "application/x-yml" } -resource "aws_s3_object" "ssm_template" { - bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/ssm.yml" - source = "${path.module}/templates/ssm.yml" - etag = filemd5("${path.module}/templates/ssm.yml") - content_type = "application/x-yml" -} - resource "aws_s3_object" "buildspec" { - bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/buildspec.zip" + bucket = "image-pipeline-assets-dev" + key = "buildspec.zip" source = data.archive_file.buildspec.output_path etag = filemd5(data.archive_file.buildspec.output_path) content_type = "application/zip" } -# Upload the Packer configuration to the project-specific S3 location -resource "aws_s3_object" "packer_template" { - bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/packer_config.zip" - source = data.archive_file.packer_config.output_path - etag = filemd5(data.archive_file.packer_config.output_path) - content_type = "application/zip" -} - # Generate the main CloudFormation template using templatefile locals { # Use the GovCloud S3 URL format for us-gov-west-1 region - s3_base_url = var.aws_region == "us-gov-west-1" ? "https://s3-${var.aws_region}.amazonaws.com/${var.template_bucket}/" : "https://${var.template_bucket}.s3.amazonaws.com/" - - # Proxy environment variables for CodeBuild - proxy_env_vars = { - HTTP_PROXY = "http://proxy.tco.census.gov:3128" - HTTPS_PROXY = "http://proxy.tco.census.gov:3128" - NO_PROXY = "pypi.org,github.e.it.census.gov,files.pythonhosted.org,nexus.it.census.gov" - } + s3_base_url = var.aws_region == "us-gov-west-1" ? "https://s3-${var.aws_region}.amazonaws.com/${var.template_bucket}/${var.template_prefix}" : "https://${var.template_bucket}.s3.amazonaws.com/${var.template_prefix}" template_vars = { - kms_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/kms.yml" - iam_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/iam.yml" - s3_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/s3.yml" - codebuild_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/codebuild.yml" - codepipeline_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/codepipeline.yml" - ssm_template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/ssm.yml" + kms_template_url = "${local.s3_base_url}kms.yml" + iam_template_url = "${local.s3_base_url}iam.yml" + s3_template_url = "${local.s3_base_url}s3.yml" + codebuild_template_url = "${local.s3_base_url}codebuild.yml" + codepipeline_template_url = "${local.s3_base_url}codepipeline.yml" additional_security_group_id = var.additional_security_group_id - http_proxy = local.proxy_env_vars["HTTP_PROXY"] - https_proxy = local.proxy_env_vars["HTTPS_PROXY"] - no_proxy = local.proxy_env_vars["NO_PROXY"] } main_template_content = templatefile("${path.module}/templates/main.yml.tftpl", local.template_vars) } @@ -126,7 +91,7 @@ locals { # Upload the processed main CloudFormation template to S3 resource "aws_s3_object" "main_template" { bucket = var.template_bucket - key = "image-pipeline-config/${var.project_name}/main.yml" + key = "${var.template_prefix}main.yml" content = local.main_template_content content_type = "application/x-yml" etag = md5(local.main_template_content) @@ -134,10 +99,9 @@ resource "aws_s3_object" "main_template" { # CloudFormation stack resource that wraps the existing CloudFormation template resource "aws_cloudformation_stack" "image_pipeline" { - count = var.deploy_stack ? 1 : 0 name = var.stack_name capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"] - template_url = "${local.s3_base_url}image-pipeline-config/${var.project_name}/main.yml" + template_url = "${local.s3_base_url}main.yml" disable_rollback = var.disable_rollback timeout_in_minutes = var.timeout_in_minutes @@ -149,8 +113,7 @@ resource "aws_cloudformation_stack" "image_pipeline" { aws_s3_object.s3_template, aws_s3_object.codebuild_template, aws_s3_object.codepipeline_template, - aws_s3_object.buildspec, - aws_s3_object.packer_template + aws_s3_object.buildspec ] parameters = { @@ -172,20 +135,53 @@ resource "aws_cloudformation_stack" "image_pipeline" { PipBucketName = var.pip_bucket_name PipBucketKey = var.pip_bucket_key PackerFileName = var.packer_file_name - BuildspecBucketName = var.template_bucket - BuildspecObjectKey = "image-pipeline-config/${var.project_name}/buildspec.zip" + BuildspecBucketName = "image-pipeline-assets-dev" + BuildspecObjectKey = "buildspec.zip" AdditionalSecurityGroupId = var.additional_security_group_id - HttpProxy = local.proxy_env_vars["HTTP_PROXY"] - HttpsProxy = local.proxy_env_vars["HTTPS_PROXY"] - NoProxy = local.proxy_env_vars["NO_PROXY"] - - # Packer SSM Parameters - SourceAmiSsmPath = var.source_ami_ssm_path - InstanceType = var.instance_type - AmiName = var.ami_name - Playbook = var.playbook - SharedAccounts = var.shared_accounts } tags = var.tags +} + +# Service Catalog Resources (conditionally created) +resource "aws_servicecatalog_portfolio" "image_pipeline" { + count = var.enable_service_catalog ? 1 : 0 + name = var.portfolio_name + description = var.portfolio_description + provider_name = var.portfolio_provider_name + tags = var.tags +} + +resource "aws_servicecatalog_product" "image_pipeline" { + count = var.enable_service_catalog ? 1 : 0 + name = var.product_name + owner = var.product_owner + type = "CLOUD_FORMATION_TEMPLATE" + + description = var.product_description + + provisioning_artifact_parameters { + name = "v1.0" + description = "Initial version of the AWS Image Pipeline" + template_url = "${local.s3_base_url}main.yml" + type = "CLOUD_FORMATION_TEMPLATE" + } + + # Ensure the main template is uploaded before creating the product + depends_on = [aws_s3_object.main_template] + + tags = var.tags +} + +resource "aws_servicecatalog_product_portfolio_association" "image_pipeline" { + count = var.enable_service_catalog ? 1 : 0 + portfolio_id = aws_servicecatalog_portfolio.image_pipeline[0].id + product_id = aws_servicecatalog_product.image_pipeline[0].id +} + +resource "aws_servicecatalog_principal_portfolio_association" "image_pipeline" { + count = var.enable_service_catalog ? length(var.principal_arns) : 0 + portfolio_id = aws_servicecatalog_portfolio.image_pipeline[0].id + principal_arn = var.principal_arns[count.index] + principal_type = "IAM" } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index d8dc0a1..fdb7671 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,49 +1,75 @@ output "code_pipeline_name" { description = "Name of the created CodePipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["CodePipelineName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["CodePipelineName"] : null } output "code_pipeline_arn" { description = "ARN of the created CodePipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["CodePipelineArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["CodePipelineArn"] : null } output "artifact_bucket_name" { description = "Name of the S3 bucket storing pipeline artifacts" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ArtifactBucketName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ArtifactBucketName"] : null } output "artifact_bucket_arn" { description = "ARN of the S3 bucket storing pipeline artifacts" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ArtifactBucketArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ArtifactBucketArn"] : null } output "kms_key_arn" { description = "ARN of the KMS key used for encryption" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["KMSKeyArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["KMSKeyArn"] : null } output "iam_role_arn" { description = "ARN of the CodePipeline IAM role" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["IamArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["IamArn"] : null } output "role_name" { description = "Name of the CodePipeline IAM role" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["RoleName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["RoleName"] : null } output "security_group_id" { description = "ID of the security group used by CodeBuild" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["SecurityGroupId"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["SecurityGroupId"] : null } output "managed_parameters_path" { description = "Base path for SSM parameters managed by this pipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ManagedParameters"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ManagedParameters"] : null } output "secrets_path" { description = "Base path for Secrets Manager secrets managed by this pipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["SecretsPath"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["SecretsPath"] : null +} + +# Service Catalog Outputs +output "service_catalog_portfolio_id" { + description = "ID of the Service Catalog portfolio" + value = var.enable_service_catalog ? aws_servicecatalog_portfolio.image_pipeline[0].id : null +} + +output "service_catalog_portfolio_arn" { + description = "ARN of the Service Catalog portfolio" + value = var.enable_service_catalog ? aws_servicecatalog_portfolio.image_pipeline[0].arn : null +} + +output "service_catalog_product_id" { + description = "ID of the Service Catalog product" + value = var.enable_service_catalog ? aws_servicecatalog_product.image_pipeline[0].id : null +} + +output "service_catalog_product_arn" { + description = "ARN of the Service Catalog product" + value = var.enable_service_catalog ? aws_servicecatalog_product.image_pipeline[0].arn : null +} + +output "service_catalog_template_url" { + description = "URL of the CloudFormation template used by Service Catalog" + value = var.enable_service_catalog ? "${local.s3_base_url}main.yml" : null } \ No newline at end of file diff --git a/templates/buildspec.yaml b/templates/buildspec.yaml new file mode 100644 index 0000000..e69de29 diff --git a/templates/codebuild.yaml b/templates/codebuild.yaml new file mode 100644 index 0000000..e69de29 diff --git a/templates/codepipeline.yaml b/templates/codepipeline.yaml new file mode 100644 index 0000000..e69de29 diff --git a/templates/main.yml.tftpl b/templates/main.yml.tftpl index 1a48689..2ad3e53 100644 --- a/templates/main.yml.tftpl +++ b/templates/main.yml.tftpl @@ -106,54 +106,6 @@ Parameters: Type: String Description: ID of an additional pre-existing security group to attach to the CodeBuild job Default: "" - - HttpProxy: - Type: String - Description: HTTP proxy configuration for CodeBuild - Default: "" - - HttpsProxy: - Type: String - Description: HTTPS proxy configuration for CodeBuild - Default: "" - - NoProxy: - Type: String - Description: NO_PROXY configuration for CodeBuild - Default: "" - - # Parameters for Packer SSM Configuration - SourceAmiSsmPath: - Type: String - Description: SSM parameter path to fetch the source AMI ID from - - InstanceType: - Type: String - Description: Instance type to use for building images - Default: "t3.medium" - - AmiName: - Type: String - Description: Name to give the created AMI - Default: "" - - Playbook: - Type: String - Description: Ansible playbook to run during AMI creation - Default: "site.yml" - - SharedAccounts: - Type: String - Description: Comma-separated list of AWS account IDs to share the AMI with - Default: "" - - SecurityGroupIds: - Type: String - Description: Security group IDs to use for building AMIs - Default: "" - -Conditions: - HasAdditionalSecurityGroup: !Not [!Equals [!Ref AdditionalSecurityGroupId, ""]] Resources: KMSStack: @@ -206,31 +158,6 @@ Resources: BuildspecBucketName: !Ref BuildspecBucketName BuildspecObjectKey: !Ref BuildspecObjectKey AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId - HttpProxy: !Ref HttpProxy - HttpsProxy: !Ref HttpsProxy - NoProxy: !Ref NoProxy - - # SSM Parameters for Packer - PackerParameters: - Type: AWS::CloudFormation::Stack - DependsOn: CodeBuildStack - Properties: - TemplateURL: ${ssm_template_url} - Parameters: - ProjectName: !Ref ProjectName - Region: !Ref "AWS::Region" - SubnetIds: !Join [",", !Ref SubnetIds] - VpcId: !Ref VpcId - SourceAmiSsmPath: !Ref SourceAmiSsmPath - InstanceType: !Ref InstanceType - AmiName: !Ref AmiName - Playbook: !Ref Playbook - SharedAccounts: !Ref SharedAccounts - SecurityGroupIds: !If - - HasAdditionalSecurityGroup - - !Join [",", [!GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId, !Ref AdditionalSecurityGroupId]] - - !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId - SSHUser: !Ref SSHUser CodePipelineStack: Type: AWS::CloudFormation::Stack diff --git a/variables.tf b/variables.tf index 0aa994f..824bc39 100644 --- a/variables.tf +++ b/variables.tf @@ -66,6 +66,12 @@ variable "template_bucket" { type = string } +variable "template_prefix" { + description = "Prefix/folder path for CloudFormation templates in S3" + type = string + default = "" +} + variable "docker_build" { description = "Whether to enable Docker image building" type = bool @@ -206,4 +212,53 @@ variable "shared_accounts" { description = "Comma-separated list of AWS account IDs to share the AMI with" type = string default = "" +} + +# Service Catalog Configuration +variable "enable_service_catalog" { + description = "Whether to create Service Catalog resources for self-service deployment" + type = bool + default = false +} + +variable "portfolio_name" { + description = "Name of the Service Catalog portfolio" + type = string + default = "AWS Image Pipeline Portfolio" +} + +variable "portfolio_description" { + description = "Description of the Service Catalog portfolio" + type = string + default = "Self-service deployment of AWS image building pipelines" +} + +variable "portfolio_provider_name" { + description = "Name of the portfolio provider/owner" + type = string + default = "DevOps Team" +} + +variable "product_name" { + description = "Name of the Service Catalog product" + type = string + default = "AWS Image Building Pipeline" +} + +variable "product_description" { + description = "Description of the Service Catalog product" + type = string + default = "Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer" +} + +variable "product_owner" { + description = "Owner of the Service Catalog product" + type = string + default = "Platform Engineering" +} + +variable "principal_arns" { + description = "List of IAM principal ARNs (users, roles, groups) to grant access to the Service Catalog portfolio" + type = list(string) + default = [] } \ No newline at end of file From cde4af094a3d7efa11003e3993985a4d0763f078 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Thu, 4 Jun 2026 13:17:04 -0400 Subject: [PATCH 2/2] chore: end-of-session commit (33 files changed) --- .terraform.lock.hcl | 34 +- .terraform_commits | 174 +++ .vscode/settings.json | 9 + MIGRATION_GUIDE.md | 159 +++ Makefile | 219 ++++ TargetPlan.md | 280 ----- ansible_config.zip | Bin 0 -> 1428 bytes cloud-formation.tf | 55 + data.tf | 3 + examples/service-catalog-migration.tfvars | 66 ++ .../image-pipeline-ansible-playbooks.zip | Bin 0 -> 12703 bytes global-assets/image-pipeline-packer.zip | Bin 0 -> 6736 bytes global-assets/image-pipeline-pip-config.zip | Bin 0 -> 10022 bytes main.tf | 206 +--- outputs.tf | 108 +- pip_config.zip | Bin 0 -> 1428 bytes providers.tf | 17 + s3.tf | 123 ++ scripts/add_service_catalog_permissions.sh | 95 ++ scripts/aws_credentials.py | 68 ++ scripts/clean_buckets.py | 32 + scripts/cloudformation_tester.py | 322 ++++++ scripts/launch_service_catalog_product.py | 475 ++++++++ scripts/provision_service_catalog.py | 48 + scripts/s3_policy_manager.py | 270 +++++ scripts/service_catalog_manager.py | 322 ++++++ service-catalog.tf | 61 + templates/buildspec.yaml | 0 templates/codebuild.yml | 3 +- templates/codepipeline.yml | 4 +- main.yaml.tftpl => templates/main.yaml.tftpl | 0 templates/main.yml.tftpl | 241 ---- terraform.tfstate | 794 +++++++++---- terraform.tfstate.backup | 1007 ++++++++++++++++- terraform.tfvars | 53 +- .../default/modules/modules.json | 1 + .../hashicorp/aws/6.13.0/linux_amd64 | 1 + .../hashicorp/aws/6.14.1/linux_amd64 | 1 + ...ws-image-pipeline-cfn_20250926_131314.json | 1 + ...ws-image-pipeline-cfn_20250926_132116.json | 1 + variables.tf | 37 +- 41 files changed, 4263 insertions(+), 1027 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 MIGRATION_GUIDE.md create mode 100644 Makefile delete mode 100644 TargetPlan.md create mode 100644 ansible_config.zip create mode 100644 cloud-formation.tf create mode 100644 data.tf create mode 100644 examples/service-catalog-migration.tfvars create mode 100644 global-assets/image-pipeline-ansible-playbooks.zip create mode 100644 global-assets/image-pipeline-packer.zip create mode 100644 global-assets/image-pipeline-pip-config.zip create mode 100644 pip_config.zip create mode 100644 providers.tf create mode 100644 s3.tf create mode 100644 scripts/add_service_catalog_permissions.sh create mode 100755 scripts/aws_credentials.py create mode 100644 scripts/clean_buckets.py create mode 100755 scripts/cloudformation_tester.py create mode 100644 scripts/launch_service_catalog_product.py create mode 100644 scripts/provision_service_catalog.py create mode 100755 scripts/s3_policy_manager.py create mode 100755 scripts/service_catalog_manager.py create mode 100644 service-catalog.tf delete mode 100644 templates/buildspec.yaml rename main.yaml.tftpl => templates/main.yaml.tftpl (100%) delete mode 100644 templates/main.yml.tftpl create mode 100644 terraform_data_dirs/default/modules/modules.json create mode 120000 terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.13.0/linux_amd64 create mode 120000 terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.14.1/linux_amd64 create mode 100644 terraform_plan_aws-image-pipeline-cfn_20250926_131314.json create mode 100644 terraform_plan_aws-image-pipeline-cfn_20250926_132116.json diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index fa03247..f15b13f 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -22,24 +22,24 @@ provider "registry.terraform.io/hashicorp/archive" { } provider "registry.terraform.io/hashicorp/aws" { - version = "5.100.0" - constraints = "~> 5.0" + version = "6.14.1" + constraints = "~> 6.0" hashes = [ - "h1:edXOJWE4ORX8Fm+dpVpICzMZJat4AX0VRCAy/xkcOc0=", - "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", - "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", - "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", - "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", - "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", - "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "h1:zhJy/Td/sbOHJ4SuxGYH8PCbTd+KCapfeDD/7Swd6SY=", + "zh:14d0b4b3dffb3368e6257136bbab1f93d419863dd65d99ef80ca2c1dd3c72a1e", + "zh:1de3601251f87a0a989c4b3474baa2efcaf491804f8d7afe15421b728bac5dc5", + "zh:2cfe42b853a3b4117bdbb73e5715035eac9b8d753d6e653fd5f30a807a36b985", + "zh:3dd8a0336face356928faf2396065634739ef2c3ac3dcaa655570df205559fd9", + "zh:42712baca386b84e089b1db8b7844038557f4039b32d8702611aa67eadef7d0f", + "zh:4ffc698099e4d7ffc6b0490a4e78ad66b041afd54e988b8bf8e229bcdd4b3ead", + "zh:52a6a3b01cb34394b0d06b273b27702fb9d795290a02e5824e198315787e8446", + "zh:56eae388c48a844401e44811719dc23be84de538468fd12b7265b06acbf4b51d", + "zh:614a918fdf27416b2ee2ce1737895b791f59f9deff3b61246c62a992eabfb8eb", + "zh:68605e159177b57fdc4a26bb2caff69a7b69593a601145b7ab5a86fd44b28b9f", + "zh:771ac00fd5f211052d735ff0e4b9ec67288abd1e22ffea4ed774aec73c7e5687", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", - "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", - "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", - "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", - "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", - "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", - "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", - "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + "zh:a1355841161e5b53dc3078c88aae1972fd4a9c0d30309b18b1951137b96571fa", + "zh:a3c8ca40c1fa7ad76d3d4c3c0039b66a93cc96399e757d2caa0b5cdedce9d3e8", + "zh:c77e02a72ef9eb0eb65faaf84c33af843520622dbb51ec31d04ca371bd4d4ee8", ] } diff --git a/.terraform_commits b/.terraform_commits index ea0587f..e1fe9b4 100644 --- a/.terraform_commits +++ b/.terraform_commits @@ -262,5 +262,179 @@ "commit_message": "feat: Add customization instructions for Packer and Ansible configurations in README.md", "author": "Your Name", "timestamp": "2025-08-11T14:29:54.295056" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-19T13:54:28.016727" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-19T14:31:29.136264" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-19T14:44:51.628321" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-19T15:04:20.103382" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-19T17:24:31.032435" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-22T13:31:48.921602" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-22T14:32:18.815247" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-23T12:36:26.659427" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-23T12:58:40.290792" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-23T13:34:06.956070" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-23T13:46:15.205040" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T12:59:05.518278" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:05:19.715459" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:13:54.060601" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:16:29.480254" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:22:27.434354" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:25:20.564401" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T13:59:08.624845" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T15:03:40.259641" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T15:18:06.488429" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T15:49:01.712797" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-24T17:16:12.558888" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T12:20:14.274311" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T12:27:41.954264" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T13:26:42.598056" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T13:39:07.040787" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T16:06:06.073376" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T16:16:26.022357" + }, + { + "commit_hash": "8da4b6740b654a919b7180f2080e24f76de6b0e9", + "commit_message": "working on integrating service-catalog", + "author": "Your Name", + "timestamp": "2025-09-25T16:27:24.953407" } ] \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1c49803 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "python-envs.pythonProjects": [ + { + "path": ".", + "envManager": "ms-python.python:venv", + "packageManager": "ms-python.python:pip" + } + ] +} \ No newline at end of file diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 0000000..d6672aa --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,159 @@ +# Migration Guide: Using terraform-cfn-service-catalog Module + +This guide outlines the migration from the existing aws-image-pipeline-cfn implementation to use the dedicated terraform-cfn-service-catalog module. + +## Benefits of Migration + +### 1. **Cleaner Architecture** +- Separation of concerns between CloudFormation stack management and Service Catalog resources +- Reduced code complexity in main.tf (from ~150 lines to ~130 lines with better organization) +- Reusable Service Catalog module across multiple projects + +### 2. **Enhanced Flexibility** +- Support for both creating new portfolios or using existing ones +- Better template source handling (content vs URL) +- More robust validation and error handling +- Improved principal access management + +### 3. **Better Maintainability** +- Service Catalog logic is centralized in a dedicated module +- Easier to update Service Catalog configurations +- Clear separation between infrastructure deployment and self-service catalog + +## Migration Steps + +### Step 1: Update Module Source Path +Ensure the terraform-cfn-service-catalog module is available at the correct relative path: +``` +source = "../terraform-cfn-service-catalog" +``` + +### Step 2: Update Terraform Configuration +The main.tf has been updated to: +- Use the terraform-cfn-service-catalog module instead of direct aws_servicecatalog_* resources +- Pass the generated CloudFormation template content directly to the module +- Maintain backward compatibility with existing variables + +### Step 3: Configure Service Catalog Variables +Set the following variables in your terraform.tfvars: + +```hcl +# Enable Service Catalog +enable_service_catalog = true + +# Portfolio configuration +portfolio_name = "Your Portfolio Name" +portfolio_description = "Portfolio description" +portfolio_provider_name = "Your Team Name" + +# Product configuration +product_name = "Your Product Name" +product_description = "Product description" +product_owner = "Product Owner" + +# Access control +principal_arns = [ + "arn:aws:iam::123456789012:role/YourRole", + "arn:aws:iam::123456789012:group/YourGroup" +] +``` + +### Step 4: Initialize and Apply +```bash +terraform init +terraform plan +terraform apply +``` + +## Key Changes + +### Before (Direct Resources) +- Direct management of aws_servicecatalog_portfolio +- Direct management of aws_servicecatalog_product +- Direct management of aws_servicecatalog_product_portfolio_association +- Direct management of aws_servicecatalog_principal_portfolio_association +- Manual template URL construction + +### After (Module-Based) +- Single module call with all Service Catalog configuration +- Automatic template handling (content passed directly) +- Built-in validation and error handling +- Cleaner variable interface + +## Backward Compatibility + +The migration maintains full backward compatibility: +- All existing variables are preserved +- Service Catalog can still be disabled with `enable_service_catalog = false` +- CloudFormation stack deployment works identically +- All outputs are preserved and enhanced + +## Advanced Configuration Options + +The module supports additional configuration options: + +### Using Existing Portfolio +```hcl +module "service_catalog" { + # ... other configuration ... + + create_portfolio = false + existing_portfolio_id = "port-existing123" +} +``` + +### Custom Provisioning Artifact +```hcl +module "service_catalog" { + # ... other configuration ... + + provisioning_artifact_name = "v2.0" + provisioning_artifact_description = "Updated version with new features" + disable_template_validation = false +} +``` + +### Support Information +```hcl +module "service_catalog" { + # ... other configuration ... + + support_description = "Contact the Platform Engineering team for support" + support_email = "platform-engineering@company.com" + support_url = "https://wiki.company.com/platform-engineering" +} +``` + +## Testing the Migration + +1. **Validate Configuration** + ```bash + terraform validate + ``` + +2. **Review Plan** + ```bash + terraform plan -var-file="examples/service-catalog-migration.tfvars" + ``` + +3. **Test Service Catalog Access** + After deployment, verify that: + - Portfolio is created/accessible + - Product appears in the portfolio + - Specified principals can access the portfolio + - Product can be launched successfully + +## Rollback Strategy + +If you need to rollback: +1. Set `enable_service_catalog = false` +2. Run `terraform apply` to remove Service Catalog resources +3. Revert to the previous main.tf if needed + +## Additional Benefits + +- **Standardization**: All Service Catalog deployments use the same module +- **Testing**: Module can be tested independently +- **Documentation**: Centralized documentation for Service Catalog patterns +- **Updates**: Easy to update Service Catalog logic across all projects +- **Compliance**: Consistent implementation of access controls and tagging \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5d4a7ed --- /dev/null +++ b/Makefile @@ -0,0 +1,219 @@ +# AWS Image Pipeline CloudFormation - Service Catalog Management +# This Makefile provides convenient commands for managing Service Catalog products + +.PHONY: help init plan apply destroy launch check-access debug-s3 clean + +# Default target +help: + @echo "AWS Image Pipeline Service Catalog Management" + @echo "" + @echo "Available targets:" + @echo "" + @echo "Terraform Operations:" + @echo " init - Initialize Terraform" + @echo " plan - Plan Terraform changes" + @echo " apply - Apply Terraform changes" + @echo " destroy - Destroy Terraform resources" + @echo " show-state - Show current Terraform state summary" + @echo "" + @echo "Service Catalog Management:" + @echo " launch - Launch Service Catalog product" + @echo " launch-verbose - Launch Service Catalog product with verbose output" + @echo " launch-no-wait - Launch Service Catalog product (no wait for completion)" + @echo " check-access - Check Service Catalog access and permissions" + @echo " list-products - List Service Catalog products" + @echo "" + @echo "Debugging and Troubleshooting:" + @echo " debug-s3 - Debug S3 access issues" + @echo " check-role - Check Service Catalog launch role permissions" + @echo " investigate-sc-issue - Investigate Service Catalog specific issues" + @echo " investigate-all-s3 - Investigate ALL S3 buckets used by CloudFormation" + @echo " test-cf-direct - Test direct CloudFormation stack creation (bypass Service Catalog)" + @echo " test-cf-s3-access - Test CloudFormation S3 access for nested templates" + @echo " test-service-role - Test Service Catalog launch role permissions" + @echo " troubleshoot - Run complete troubleshooting sequence" + @echo " check-required-files - Check all required files for CloudFormation template" + @echo "" + @echo "Fix Commands:" + @echo " fix-s3-policy - Fix S3 bucket policy to include Service Catalog launch role" + @echo " fix-all-s3-policies - Fix S3 bucket policies for ALL buckets" + @echo " cleanup-constraints - Clean up manually created Service Catalog constraints" + @echo " fix-launch-constraint - Fix Service Catalog launch constraint configuration" + @echo " fix-terraform-constraint - Let Terraform fix the launch constraint" + @echo " upload-missing-files - Upload missing S3 files required by CloudFormation" + @echo " quick-fix - Run complete fix and test sequence" + @echo "" + @echo "Utility and Information:" + @echo " show-fix-command - Show manual command to fix S3 bucket policy" + @echo " install-deps - Install Python dependencies" + @echo " clean - Clean up temporary files" + @echo "" + @echo "Environment variables:" + @echo " STACK_NAME - Name for the launched stack (default: auto-generated)" + @echo " AWS_REGION - AWS region (default: from AWS config)" + @echo " PROJECT_NAME - Project name parameter (default: from STACK_NAME)" + @echo "" + @echo "Examples:" + @echo " make launch STACK_NAME=my-pipeline" + @echo " make launch-verbose STACK_NAME=test-pipeline" + @echo " make debug-s3" + @echo " make check-access" + @echo " make troubleshoot" + @echo "" + @echo "Quick Start After tf apply:" + @echo " 1. make check-access # Verify Service Catalog setup" + @echo " 2. make launch-verbose # Test Service Catalog product launch" + @echo " 3. make troubleshoot # If issues occur" + +# Variables +STACK_NAME ?= image-pipeline-$(shell date +%Y%m%d-%H%M%S) +PROJECT_NAME ?= $(STACK_NAME) +AWS_REGION ?= $(shell aws configure get region 2>/dev/null || echo "us-gov-west-1") +PYTHON_SCRIPT = launch_service_catalog_product.py +SCRIPTS_DIR = ./scripts + +# tf operations +init: + @echo "Initializing tf..." + tf init + +plan: + @echo "Planning tf changes..." + tf plan + +apply: + @echo "Applying tf changes..." + tf apply + +destroy: + @echo "Destroying tf resources..." + tf destroy + +# Service Catalog operations +launch: check-deps + @echo "Launching Service Catalog product: $(STACK_NAME)" + python3 $(PYTHON_SCRIPT) --region $(AWS_REGION) --stack-name $(STACK_NAME) --param ProjectName=$(PROJECT_NAME) + +launch-verbose: check-deps + @echo "Launching Service Catalog product with verbose output: $(STACK_NAME)" + python3 $(PYTHON_SCRIPT) --region $(AWS_REGION) --stack-name $(STACK_NAME) --param ProjectName=$(PROJECT_NAME) --verbose + +launch-no-wait: check-deps + @echo "Launching Service Catalog product (no wait): $(STACK_NAME)" + python3 $(PYTHON_SCRIPT) --region $(AWS_REGION) --stack-name $(STACK_NAME) --param ProjectName=$(PROJECT_NAME) --no-wait + +# Access and permission checks +check-access: check-deps + @echo "Checking Service Catalog access and permissions..." + python3 $(SCRIPTS_DIR)/service_catalog_manager.py --check-access --region $(AWS_REGION) + +debug-s3: check-deps + @echo "Debugging S3 access for Service Catalog..." + python3 $(SCRIPTS_DIR)/s3_policy_manager.py --bucket --region $(AWS_REGION) + +check-role: check-deps + @echo "Checking Service Catalog launch role permissions..." + python3 $(SCRIPTS_DIR)/service_catalog_manager.py --check-access --region $(AWS_REGION) + +list-products: check-deps + @echo "Listing Service Catalog products..." + @PORTFOLIO_ID=$$(tf output -raw service_catalog_portfolio_id 2>/dev/null || echo ""); \ + if [ -z "$$PORTFOLIO_ID" ]; then \ + echo "❌ Portfolio ID not found in tf state"; \ + exit 1; \ + fi; \ + echo "Portfolio: $$PORTFOLIO_ID"; \ + aws servicecatalog search-products --region $(AWS_REGION) --query 'ProductViewSummaries[].[ProductId,Name,ShortDescription]' --output table + +# Troubleshooting and debugging +investigate-sc-issue: check-deps + @echo "Investigating Service Catalog specific issues..." + python3 $(SCRIPTS_DIR)/service_catalog_manager.py --investigate --region $(AWS_REGION) + +test-cf-s3-access: check-deps + @echo "Testing CloudFormation S3 access for nested templates..." + python3 $(SCRIPTS_DIR)/cloudformation_tester.py --test-s3-access --region $(AWS_REGION) + +test-cf-direct: check-deps + @echo "Testing direct CloudFormation stack creation..." + @echo "Note: You will need to specify VPC and subnet IDs for testing." + python3 $(SCRIPTS_DIR)/cloudformation_tester.py --test-direct --region $(AWS_REGION) + +check-required-files: check-deps + @echo "Checking for required template files in S3..." + python3 $(SCRIPTS_DIR)/cloudformation_tester.py --check-files --region $(AWS_REGION) + +# Fix commands +fix-s3-policy: check-deps + @echo "Fixing S3 bucket policy to include Service Catalog launch role..." + python3 $(SCRIPTS_DIR)/s3_policy_manager.py --region $(AWS_REGION) + +fix-all-s3-policies: check-deps + @echo "Fixing ALL S3 bucket policies for CloudFormation templates..." + python3 $(SCRIPTS_DIR)/s3_policy_manager.py --all-buckets --region $(AWS_REGION) + +cleanup-constraints: check-deps + @echo "Cleaning up Service Catalog constraints..." + python3 $(SCRIPTS_DIR)/service_catalog_manager.py --cleanup-constraints --region $(AWS_REGION) + +fix-launch-constraint: check-deps + @echo "Fixing Service Catalog launch constraint..." + python3 $(SCRIPTS_DIR)/service_catalog_manager.py --fix-constraint --region $(AWS_REGION) + +fix-terraform-constraint: cleanup-constraints + @echo "🔧 Letting Terraform fix the launch constraint..." + @echo "After cleanup, Terraform will recreate the constraint properly." + @echo "" + @echo "Running: tf apply -target=module.service_catalog[0].aws_servicecatalog_constraint.launch[0]" + tf apply -target=module.service_catalog[0].aws_servicecatalog_constraint.launch[0] -auto-approve + +upload-missing-files: check-deps + @echo "Uploading missing template files to S3..." + python3 $(SCRIPTS_DIR)/cloudformation_tester.py --upload-files --region $(AWS_REGION) + +quick-fix: fix-launch-constraint launch-verbose + @echo "🚀 Running complete fix and test sequence..." + +# Utility targets +check-aws-creds: check-deps + @echo "Checking AWS credentials and region..." + python3 $(SCRIPTS_DIR)/aws_credentials.py --region $(AWS_REGION) + +check-deps: + @python3 --version > /dev/null || (echo "❌ Python 3 not found" && exit 1) + @test -d $(SCRIPTS_DIR) || (echo "❌ Scripts directory not found" && exit 1) + @python3 -c "import boto3" 2>/dev/null || \ + (echo "❌ boto3 not installed. Run 'make install-deps'" && exit 1) + +clean: + @echo "Cleaning up temporary files..." + @rm -f buildspec.zip packer_config.zip + @rm -f tf.tfplan + @echo "✅ Cleanup complete" + +# Development helpers +show-state: + @echo "Current tf state summary:" + @echo "Service Catalog Portfolio ID: $$(tf output -raw service_catalog_portfolio_id 2>/dev/null || echo 'Not found')" + @echo "Service Catalog Product ID: $$(tf output -raw service_catalog_product_id 2>/dev/null || echo 'Not found')" + @echo "Launch Role ARN: $$(tf output -raw service_catalog_launch_role_arn 2>/dev/null || echo 'Not found')" + @echo "Template Bucket: $$(tf output -raw template_bucket 2>/dev/null || echo 'Not found')" + @echo "Current User ARN: $$(tf output -raw service_catalog_current_user_arn 2>/dev/null || echo 'Not found')" + +install-deps: + @echo "Installing Python dependencies..." + @pip3 install boto3 --user + @echo "✅ Dependencies installed" + +# Quick troubleshooting +troubleshoot: check-access debug-s3 check-role + @echo "" + @echo "🔍 Troubleshooting Summary:" + @echo "If you're still getting S3 errors, check:" + @echo "1. Launch role has S3 permissions for all required buckets" + @echo "2. S3 bucket policy doesn't deny access to the launch role" + @echo "3. All nested CloudFormation templates are uploaded to S3" + @echo "4. Launch constraint is properly configured" + @echo "" + @echo "To launch with detailed error reporting:" + @echo " make launch-verbose STACK_NAME=your-stack-name" \ No newline at end of file diff --git a/TargetPlan.md b/TargetPlan.md deleted file mode 100644 index 0f709df..0000000 --- a/TargetPlan.md +++ /dev/null @@ -1,280 +0,0 @@ -# AWS Image Pipeline: Architecture and Implementation Plan - -## Project Purpose and Goals - -This project implements an automated AMI (Amazon Machine Image) factory using AWS services. The pipeline creates standardized, secure, and compliant machine images through a consistent and repeatable process. - -### Core Features and Requirements - -1. **Automated AMI Building Pipeline** - - Creates machine images using HashiCorp Packer - - Supports customization through configuration files - - Implements secure practices for image creation - - Ensures consistent, repeatable builds - -2. **Configuration Management** - - Uses Ansible for system configuration and hardening - - Applies roles and playbooks from a central repository - - Supports customization of software packages and system settings - - Maintains separation of configuration from build process - -3. **Testing and Validation** - - Implements Goss testing framework for image validation - - Verifies system configuration meets requirements - - Ensures security controls are properly applied - - Validates system functionality post-configuration - -4. **Security Features** - - KMS encryption for artifacts and secrets - - IAM role-based access control - - VPC isolation for build process - - Secure handling of SSH keys and credentials - - Support for existing IAM roles and profiles - -5. **Resource Organization** - - Source artifacts stored in S3 buckets: - - Packer templates - - Ansible playbooks - - Goss test suites - - Pip requirements (Python dependencies) - - Separate buckets for build artifacts - - Proper encryption and access controls - -6. **Pipeline Workflow** - 1. Source Stage: - - Retrieves Packer templates - - Pulls Ansible playbooks - - Gets Goss test files - - Fetches Python requirements - 2. Build Stage: - - Executes Packer build process - - Applies Ansible configuration - - Creates base AMI - 3. Test Stage: - - Runs Goss validation tests - - Verifies image compliance - - Ensures quality standards - -7. **Operational Features** - - Support for troubleshooting mode - - Configurable compute resources - - VPC networking integration - - Logging and monitoring - - Build caching for efficiency - -### Implementation Requirements - -1. **Required Parameters** - - Project naming for resource identification - - Build environment specifications - - VPC networking configuration - - Source artifact locations - - SSH access configuration - - Role and permission settings - -2. **Mandatory Outputs** - - Pipeline identifiers (name/ARN) - - IAM role information - - KMS key details - - S3 bucket references - - Security group IDs - -3. **Security Requirements** - - KMS encryption for artifacts - - IAM least privilege access - - Network isolation in VPC - - Secure credential handling - - Support for custom IAM roles - -4. **Operational Requirements** - - Consistent tagging strategy - - Resource cleanup procedures - - Error handling and reporting - - Build status monitoring - - Artifact version tracking - -## Scope Decision: AMI-Only Pipeline - -**Important Note:** We have decided to restrict the scope of this implementation to AMI building only. Docker container image building support will not be implemented. This decision simplifies the implementation while still meeting the primary use case of creating machine images. - -## Core Components Comparison - -### 1. S3 Bucket for Artifacts - -#### Terraform Implementation -- Creates S3 bucket with bucket_prefix based on project name -- Implements server-side encryption with KMS -- Configures bucket versioning -- Sets up bucket logging -- Configures bucket policies and access controls -- Blocks public access - -#### CloudFormation Implementation -- Has equivalent functionality in `s3.yml` -- Needs verification of bucket policy permissions to ensure they match Terraform - -### 2. IAM Roles and Policies - -#### Terraform Implementation -- Creates CodePipeline role with: - - Assume role policy for CodePipeline and CodeBuild - - Permissions for S3, KMS, CodeBuild, etc. - - Optional VPC access permissions -- Creates build user role with permissions for: - - SSM Parameters - - EC2 operations - - KMS operations - - S3 access - - Secrets Manager access - -#### CloudFormation Implementation -- Implements IAM roles in `iam.yml` -- May need expanded permissions to match Terraform implementation, particularly: - - Access to all source buckets (including pip_bucket) - - SSM parameter permissions - - Shared KMS key access - -### 3. CodeBuild Projects - -#### Terraform Implementation -- Creates build and test projects with: - - Environment variables based on parameters - - Buildspec templates with conditional logic - - VPC configurations - - Cache settings - - Support for "troubleshoot" mode - -#### CloudFormation Implementation -- Implements build and test projects in `codebuild.yml` -- Limited environment variables (only PACKER_VERSION and PROJECT_NAME) -- Needs enhancement to buildspec templates to match Terraform functionality -- Needs support for all parameter inputs - -### 4. CodePipeline - -#### Terraform Implementation -- Creates pipeline with: - - Source actions for Packer, Ansible, Goss, and Pip - - Build and test stages - - S3 artifact storage with KMS encryption - -#### CloudFormation Implementation -- Implements pipeline in `codepipeline.yml` -- Need to verify pip_bucket source action is properly implemented -- Needs consistent naming for input/output artifacts to match Terraform - -### 5. KMS Key - -#### Terraform Implementation -- Creates KMS key for encryption -- Configures key policies with proper permissions -- Enables key rotation - -#### CloudFormation Implementation -- Implements KMS key in `kms.yml` -- Needs verification of key policy permissions - -## Parameter Comparison - -### Terraform Variables vs CloudFormation Parameters - -| Terraform Variable | Type | CloudFormation Parameter | Status | -|-------------------|------|--------------------------|--------| -| project_name | string | ProjectName | ✓ Present | -| builder_image | string | BuilderImage | ✓ Present | -| builder_compute_type | string | BuilderComputeType | ✓ Present | -| packer_version | string | PackerVersion | ✓ Present | -| vpc_config | object | VpcId, SubnetIds | ✓ Present | -| create_new_role | bool | N/A | Missing | -| packer_bucket | object | PackerBucketName, PackerBucketKey | ✓ Present | -| ansible_bucket | object | AnsibleBucketName, AnsibleBucketKey | ✓ Present | -| goss_bucket | object | GossBucketName, GossBucketKey | ✓ Present | -| pip_bucket | object | PipBucketName, PipBucketKey | ✓ Present | -| docker_build | bool | DockerBuild | ✓ Present (Set to false)* | -| state | object | N/A | Not applicable** | -| ssh_user | string | N/A | Missing | -| troubleshoot | bool | N/A | Missing | -| assets_bucket_name | string | AssetsBucketName | ✓ Present | -| build_projects | list | N/A | Omit intentionally*** | -| builder_image_pull_credentials_type | string | N/A | Missing | -| builder_type | string | N/A | Implicitly "LINUX_CONTAINER" | -| image | object | N/A | Omit intentionally**** | -| instance_profile | string | N/A | Missing (Conditional)****** | -| tags | map(string) | N/A | Implementation difference***** | - -*Note: The `docker_build` parameter will always be set to false as we're focusing exclusively on AMI building. - -**Note: The `state` parameter in Terraform is for configuring the remote backend to store Terraform's own state file (.tfstate). CloudFormation manages its state automatically within the AWS service. This parameter is specific to Terraform's operational model and does not have a functional equivalent in CloudFormation. - -***Note: The `build_projects` parameter will remain static in the CloudFormation implementation as changing it would greatly impact the structure of the pipeline we are trying to build. - -****Note: The `image` parameter is specific to Docker container image building, which is outside the scope of this implementation. We are focusing exclusively on AMI building. - -*****Note: The `tags` variable in Terraform applies tags to all created resources. In the CloudFormation implementation, tags are handled differently through the deployment script's `convert_tags` function. This approach is functionally equivalent but implemented differently. - -******Note: The `instance_profile` parameter is conditionally used in Terraform. It is only required when `create_new_role` is set to `false`, allowing the user to specify a pre-existing IAM instance profile. Implementing this would require adding it as a parameter to be used when a new role is not being created. - -### CloudFormation Parameter Extensions -CloudFormation has implemented some parameters that aren't in the Terraform module: -- None identified - -## Outputs Comparison - -| Terraform Output | CloudFormation Output | Status | -|-----------------|----------------------|--------| -| codepipeline_name | CodePipelineName | ✓ Present | -| codepipeline_arn | CodePipelineArn | ✓ Present | -| iam_arn | CodeBuildRoleArn | ❌ Incorrect mapping | -| kms_arn | KMSKeyArn | ✓ Present | -| s3_arn | Not present | Missing | -| s3_bucket | ArtifactBucketName | ✓ Present | -| role_name | Not present | Missing | -| managed_parameters | Not present | Missing | -| secrets | Not present | Missing | -| sec_group | Not present | Missing | - -Note: The `iam_arn` output in the Terraform module refers to the CodePipeline role ARN, not the CodeBuild role ARN. The CloudFormation stack should output the ARN of the CodePipelineRole to be a true functional equivalent. Currently, the mapping to `CodeBuildRoleArn` is incorrect. - -## Recommendations - -### 1. Parameter Updates -- Add support for missing parameters in `main.yml`: - - `create_new_role` (with default true) - - `ssh_user` - - `troubleshoot` (with default false) - - Ensure tags handling in `deploy_stacks.py` is sufficient to meet the Terraform module's tagging requirements - - Ensure `docker_build` parameter is always set to false - -### 2. CodeBuild Enhancements -- Update buildspec templates in `codebuild.yml` to match Terraform functionality: - - Add support for troubleshooting mode - - Expand environment variables - - Update build steps to match Terraform templates - - Remove any Docker-specific build steps or parameters - -### 3. IAM Permissions -- Verify and expand IAM permissions in `iam.yml` to match Terraform: - - Access to all buckets - - SSM parameter permissions - - Shared KMS key access - -### 4. Output Extensions -- Add missing outputs to CloudFormation templates: - - `s3_arn` - - `role_name` -- Correct the mapping of the `iam_arn` output to refer to the CodePipeline role ARN instead of the CodeBuild role ARN - -### 5. Script Updates -- Update `deploy_stacks.py` to handle all parameters and pass them correctly to CloudFormation - -## Implementation Priority -1. Add missing parameters to ensure interface compatibility (excluding Docker-related parameters) -2. Update buildspec templates to match Terraform functionality for AMI building -3. Verify and update IAM permissions -4. Add missing outputs and correct output mappings -5. Update deployment script - -## Conclusion -The CloudFormation implementation is structurally similar to the Terraform module but needs several updates to achieve functional equivalence for AMI building. Most of the core components are already implemented, but parameter definitions, permissions, and buildspec templates need to be enhanced to match the Terraform implementation. Special attention should be paid to the correct mapping of outputs and handling of Terraform-specific concepts like state management. - -By focusing exclusively on AMI building, we simplify the implementation while still delivering the core functionality needed by users. \ No newline at end of file diff --git a/ansible_config.zip b/ansible_config.zip new file mode 100644 index 0000000000000000000000000000000000000000..dce7735e4ad70c41693bbd15fddebb9b236c17a1 GIT binary patch literal 1428 zcmV;F1#9|HO9KQH00;mG0000XiU0rr000000000001W^D0Ah7%Y-DqAWn(URZEUnw zQB&Kv6MxUA*vUWBw4JeCn*Mup%;dohZtDY*OdROklPcr|tFbL1$v_TrpZ!L*`Jq?>imLul73tS5$F&mZG*l0Heu4K%&`*9E7ud=(^of z8bx2pbQYfa^MD)%zmw15QD9F!trN1qr7JP(b~-Ylx&q?4HZ)BuOjYEDXXw=YH4}hb zn#8&@aQF5~5ffQP^SDv?A4F&h36e`-B0uLBg`$Rw9L|-j)XrwS900NnS^fd*2enjBs@A;2TUSSC}#0SCEKJhvM?)8a_L(BZjI9j z;O-8PB?7vQBo_wGMUltA^Twg>KVWtkDpMvHJT&Z{$nxtV7XJZk6V^uhOlXzG^ub-# zwSY0`f-%(kyhzh!D<#xCp4YK}Mp$yM?V1t^D|k?NS#X6hNXi!U0(C=hop6>|n1RJ* zg-RhYM(TafI}^faqo{P{Qc{--?*ffu8RZfj0h_-^(5f09K-dP}T9cN0?hh?; z=-Rf~_q@H2zq;@L|H0k+<(>Q9djV75*2emkK+tGF;e~xHdKPOId$1Z=mH8ks`V^0jd^ zDo+}QXYpIkM!{$n%v(MWUkdt|)7nmIV#EUT#^HJS_Z;FqH=`(=jLCd*7>tL13x>t; z_&i&Wu}WioxY}xz2#v9wW|xVAoBj6v05FTt1&ydEJ_+?CzoiE|;9HfI=HTcjI?S&&gLR`Rk)po0lvR?L zD`ZBfrQHZ?o6TmpDWvx3pR^#*<`E#R{#J2|Nl@+2MA1nP{RlX0018j z002-+0Rj{Q6aWYS2mk;8A&N|ZP{RlX0018j000dD0000000000006Xs00000Vs&Y3 iWOHz3V=j4ZY*0%D1^@s60096206PEx07C@;00023=AmQ& literal 0 HcmV?d00001 diff --git a/cloud-formation.tf b/cloud-formation.tf new file mode 100644 index 0000000..7a33f21 --- /dev/null +++ b/cloud-formation.tf @@ -0,0 +1,55 @@ + +# CloudFormation stack resource (conditionally deployed) +resource "aws_cloudformation_stack" "image_pipeline" { + count = var.deploy_stack ? 1 : 0 + name = var.stack_name + capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"] + template_body = local.main_template_content + disable_rollback = var.disable_rollback + timeout_in_minutes = var.timeout_in_minutes + + # Ensure the templates are uploaded before creating the stack + depends_on = [ + aws_s3_object.main_template, + aws_s3_object.kms_template, + aws_s3_object.iam_template, + aws_s3_object.s3_template, + aws_s3_object.codebuild_template, + aws_s3_object.codepipeline_template, + aws_s3_object.buildspec, + aws_s3_object.packer_config, + aws_s3_bucket_policy.service_catalog + ] + + parameters = { + ProjectName = var.project_name + CreateNewRole = var.create_new_role ? "true" : "false" + SSHUser = var.ssh_user + Troubleshoot = var.troubleshoot ? "true" : "false" + BuilderComputeType = var.builder_compute_type + BuilderImage = var.builder_image + PackerVersion = var.packer_version + AssetsBucketName = local.service_catalog_bucket_name + DockerBuild = var.docker_build ? "true" : "false" + VpcId = var.vpc_id + SubnetIds = join(",", var.subnet_ids) + # For direct CloudFormation deployment, use shared bucket + PackerBucketName = var.global_assets_bucket + PackerBucketKey = local.packer_config_s3_key + PackerFileName = var.packer_file_name + AnsibleBucketName = var.global_assets_bucket + AnsibleBucketKey = local.ansible_config_s3_key + PipBucketName = var.global_assets_bucket + PipBucketKey = local.pip_config_s3_key + + BuildspecBucketName = local.service_catalog_bucket_name + BuildspecObjectKey = "${var.template_prefix}/buildspec.yml" + AdditionalSecurityGroupId = var.additional_security_group_id + # Add missing proxy parameters + HttpProxy = var.http_proxy + HttpsProxy = var.https_proxy + NoProxy = var.no_proxy + } + + tags = var.tags +} diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..44bbc8d --- /dev/null +++ b/data.tf @@ -0,0 +1,3 @@ +# Get current AWS account information +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} diff --git a/examples/service-catalog-migration.tfvars b/examples/service-catalog-migration.tfvars new file mode 100644 index 0000000..354b199 --- /dev/null +++ b/examples/service-catalog-migration.tfvars @@ -0,0 +1,66 @@ +# Example configuration using the terraform-cfn-service-catalog module +# This shows how to enable Service Catalog with the new module-based approach + +# Basic required variables +aws_region = "us-gov-west-1" +project_name = "my-image-pipeline" + +# Template and artifact storage +template_bucket = "my-cfn-templates-bucket" +template_prefix = "image-pipeline/" +assets_bucket_name = "my-pipeline-assets" +buildspec_bucket_name = "my-pipeline-assets" +buildspec_bucket_key = "buildspec.zip" + +# Network configuration +vpc_id = "vpc-12345678" +subnet_ids = ["subnet-12345678", "subnet-87654321"] + +# Packer configuration +packer_bucket_name = "my-packer-configs" +packer_bucket_key = "packer-templates.zip" +packer_file_name = "build.pkr.hcl" + +# Ansible configuration +ansible_bucket_name = "my-ansible-roles" +ansible_bucket_key = "ansible-roles.zip" + +# Pip configuration +pip_bucket_name = "my-pip-configs" +pip_bucket_key = "pip-config.zip" + +# SSM parameters for Packer +source_ami_ssm_path = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" +instance_type = "t3.medium" +ami_name = "custom-linux-image" +playbook = "setup-server.yaml" +shared_accounts = "123456789012,210987654321" + +# Enable Service Catalog with the new module +enable_service_catalog = true + +# Service Catalog Portfolio Configuration +portfolio_name = "Custom Image Building Portfolio" +portfolio_description = "Self-service AMI building using standardized pipelines" +portfolio_provider_name = "Platform Engineering Team" + +# Service Catalog Product Configuration +product_name = "Custom AMI Builder" +product_description = "Automated AMI building pipeline with Packer, Ansible, and CodePipeline" +product_owner = "DevOps Team" + +# Grant access to specific IAM principals +principal_arns = [ + "arn:aws-us-gov:iam::123456789012:role/DevelopersRole", + "arn:aws-us-gov:iam::123456789012:group/ImageBuilders", + "arn:aws-us-gov:iam::123456789012:user/john.doe" +] + +# Resource tagging +tags = { + Environment = "production" + Project = "image-pipeline" + ManagedBy = "terraform" + CostCenter = "platform-engineering" + ServiceCatalog = "enabled" +} \ No newline at end of file diff --git a/global-assets/image-pipeline-ansible-playbooks.zip b/global-assets/image-pipeline-ansible-playbooks.zip new file mode 100644 index 0000000000000000000000000000000000000000..7f621964581064d3cb1bf972e924ea09af0fc1c2 GIT binary patch literal 12703 zcma)C1yo$wvc(;OySux)yE_4byGtX%J!tR%!3j=)pusIza0#x#9RdW0-!t=Oc z|HC@#cK2Gf?~$rHC0kVi5(*Ox3=9rTCC}xhs;^JrJUAHGI3ySt0`OO6D;swkD@P|+ z3qy@hjvK5<%MVzB?i{a=U#%5=4~HOXA;FAn_(q#ADkt}FCG%DJyL(ba{}nOG9?dnW z9Rw0|`iQJA#15VV+0V3=_JF32)(gWc$^kYU4OD3oOqaG*6^Wj)TX?FKmvES;=aV^HtWdLY6&)fxL_25@Ux9%I%N*~a3_#cNTi zlg`8Dgd|J@w991-LPsQFH7(6c>tm>1obs7T4{&^2BUKNAl;^|AMH?NM*MKt7R4O99 zAiY#@`%o4?(4XijjDZ!?tH3fenn%C$`a01dMY$zSDKiubLwaWeikxyf@a!=CyPRxz zYDu4q0FqI9zU5D0DReIMw};Ez(Xc*TvzGam?(|+E?3QKr(8TUPAZ(6hb?cQSsyP-4 zl5ge=hrV<^w&L$S9p#WXiezDPqldc}mdTh9+i)-?#iQ}@4!AoBSgRu_cp9}W+S**^ zev1{Te1A?69!Ad_9R2PgX*AXj+@Rk(%VGrI=SyiRjfNy6!XC>#cQNK^USpOno(8K+ z68ftSF4`Wu7n%xX4nd4r%85q@l~v)_Oz|QNv8Rr%RpV7Tw}!S(Bq#fx7aA5C(+{^S z%ONI<%Myu00jj?!KtJ~+1^{^Q$-wcO0!XMxN~!25OQ~yc#j>Gvv!X)XwVG1#Q?4N< zCu5!l_RJe2_BV{mFg_87e5n&ym|x%4i(Epl&kw^rBOS)z!10#3Q&G@%F7P-f6GEF* zQBU>#A|y3~Ack3BiseR3&7zH2xG}uRdvvzto1lKHHO#YDoL3%maGARVu}G^#^6TUb zNTS4bfRl0r4tU^DmlBgyl45o+=ZX)sLQU*C?gK>0x%_|{jzfd(8VCeB8#7FITH?iQ}h-X;$ASOaXpSs+QTXKCEy>_X2G zDsj5FaUx@rm5NsM9Yinskf8C2uWJZW`^(GXZlftU<~PC382r4=fK;zv6x6LB>+(#r zizf7suAnxoDl=_|6*YD|hWvFBW4cCp>cE#<0tY&90PWKnV9MkQaCH37EQF%FkUL3{ zzC0?rAesj;hJZnrNJb`i7A(H=zpZ6Te*=+M&SLd}4I;j9mnlZ(zVWkRj7ix+U8*)t zG*`+=na$@+TmCOMV4~Ku`vOTve7)U>zs|tWA7SVl@XZrIH-QR#T3guLJ281Wx!Rlm zz6)8ZVzxc3sI3I|5rdGLJB+)f#Vfav1p{_NlBr*h5jIwNY|+uDGU-ueYg;&K&0=f_ zLgJ-*yL;!jJ0pEx4VY4R``(d%!OpDJc6P;ob2o9r&)ZC^x&Hdwpq{-SILx3{*;~=a z7&eY}Ze%{ga0`k-RWr9^Z^^vrbPsOEkCDX>HF+JLD#HTU{Jcl^iGhaX#6|t zX7C}k#R_0=@9-g9z{IL!4;y0}7H_cgVd{kHT}9&Cnm4ENxJ6!h?Q=y4mVRxh*}GuUxBpU-lcun)9K)v5Y}UqB&`+N6!$+FY}fKCNXZTp3RKCv&kd7!3@A2dMl>q%&mj=2_T%U{_ex$3#&e8DD#wywwIJZQ+>+u7QpoD8&p8f#uBF7=cXbg3M zcPPaGTgwmp*NvB$qkWkL-0%(Hzy=Oipz{5F)3xG+fSw8|>?*q(-R%vOK6iXPuJIl; zeQ}L-Xp*K!)bwIfGBaaCPRC9TWat|fcDJ-h3GxuRkevl%1HVzHdUiB|WNX3wZN5s} zCXRU4#E?gSpU%R7Za_a#XL5ZBq)DAR3>Y`NEs@0$IVKo=BEV}DTyTnNE`j0s>0aC8U!u0y}; zkApHBN(d{`l6S8ksp*(DV0WRAgS`tCN=el|^x7|}!M0R$D8$cdHH)o?{Zvhp(K?$U z*8=Cn{!^`QgC&+SHl6gyoajCumr&D>Z&Qq!6HD^!kt2}Cs3j$tLM`xqil2}7&Abvt z^GC$>FvHcV68AljE?os(vb#GCYrRp7-l+@4o*R*$u|}nSsGQ?=YReHVmU1!ab=Z@= z!HvM?lCYe?IS2dojKr-j)7F7Y8Uro~3;6W3aWr@Gboy$e?1Uw5WiAod?&{YP+Mv9M84UKD!#LJs+xJls7)i3PPl>KUK2tsZjN9BhQQt5WD#L&*?uWEAtrK$5X2;GR!?52$!YVta5UxdQ*WO9s zrQ9I=LR|X3Sz{Hw{2PF>A!xon0pk5|(&OB#5B&0F5u_7fGEXy!Gg+C_ACq)db_c&l z%Mrm2cDyNRq#_MudWnZ;ElXff%J51LZge|mn}0H`V2OaCui5fYG463=i~xS+C0_;O?-vaTo!d?VU{i@S(9uPAZG6 zsC}zf8kvDQQxNzT_M2FSrQD&M)av0yHc^B-3tmb`!&Z$4xT}6v#Z2JHL7MfYepf!( zcS(l0I#Gcl5C~%O-IH_kAGj5qVdyIebn#wjxQi<5Mo=-PlpB*~v1hz~Im{MT@nTlV zL2~{8FY6~5zKYg0G;PIrjkx@}z~OM%q`+wii-(D7Eu0iTgI-k^G>!gE)A+0DO9bkf z;Tsg5j5W!wP$lD6^tPc%YE}J9K9Yg#uFUdKtAXi(6L5XqOS+*sMaJ4xgtB>NjO#3K z7fNY|Oyngf7@vBYaq_3EeeXMqI2T;B@&Z0w)WsQ4yQ;$rgy{g9dTh?}j$}zmKWl|_ zp&i)PeSE8GKJconIW9aV4)0zTo`<{c^z?M|`eCu4An9?ir6I)t5IsW34TVh*{lx-G z<`XGiSZ3~g^U44V>M4&ri8MVe=Dw-!0U0?RnEq6dNQLU?+#635TW(rB_0c&jFGE)} zACj^DoJx^Ro_9Jp^Y6NxFYpKIJ~?P`!qFvotuAF`1Qu5l_8cC}ch$*D3T#NiFlqA} z5`Lrr*G%u;_VvMSU|W9N7?DtjG9YJ4Jz`83UUxbaqLAD5O|sVbzL)<*Ng^&<14nN{ z?i6=IgF1e6$NG8Dc+K##vsqW2xjBM}!1rBf%hYMOU}dKDww0VZpL>}q9M0(l4$gvnSZMKuF$`!f_67#>iUU7hSL+*p9Y z5R1Eso1GhrgNcpf@4o9}QkUZ*D^mE0H$omxRp)+Pj|bbh#9L_YicXjdT2}O=k_0NT zoTRlj7cV(^Az*3GpL|Ac$Fv-1?^aWk5BaSvOD1;M>6Pdg^y=u z-XfB9Cg|ze>&(xY8@w;r)5Rv2S&WQ+hhx&Vx^Y{MFs$D`}^yG@jxu3+=q!_16e}djT9Vs;V;e~N*c&NIG;xzmY zO*;AqMZ!w&k2#f2)Gk|>?aT-{8c=+qA6{=~)m+YKB&LM2C%HiC-+aztj`Ba;rd$bK zcZ(GjSe56<`9sR!B@(0ma zRVQ|%RFJnBZOUUBvUFJCVdAIrrjOTAi;IvgiUFJhUIC>RL9C_hW! zfvW)>7|mY?{!8G=Vrlc65?DC8yLvl2**Lm0yIC8m4FQiIwe_5#p{Ag;&%}wGiJE*4}IPbqPBV zH%z!LaKmp@>P+_aDMV6}f6Jq_1~5(Gn1aa*L%iV!noa9LcoDkXbFs?M0~B;zw$8IZ0ME#Xp>hcbBYkCmhLA_i4|pHtW- z{EE_IH-v-=?d@(v{6g!I*pFQKL7LCRCUv42MLgS@tw%)tO*`-VJRB^mg4XN=4=wMx zF!#7=YA<%3v4pX=NZtqyJ9N{->qxjifyPJsoW#DsV-ki11EcttqXMzg6fFfOpp~{? z>7c@dJHqPES33p<5k&!ZQI;VQ!-ZSEyd+ug0o4B2KozS~ZGL*8*hA;nHd zE8I^gjK7Hzq@!$Yp|O!74q4Bt%jcj?17@J7CO<6C@&SYXJ$xkJJUIXHf-g%l7SDn~ zgxvug-)a{`+Chf>;O4`;o~vu3G}gOa(Zoi8Gu@JvQTI(Cf(VQlB4_F-g{ytE`nEI9 zID-@A2M&R@;17VxT0XN@3_S{igQ1E^H_Pg&RH+HZC~n#W{W^QpgifOSN66Bkso}Gt zU8(HEk3Uc*_m$)gU(dER zx5v5LyZHFfGSpViBzHatE&A1HB5b|e`?0)uvBz5$Hki>Nr>dioa?~YNrGzES zltuQgAbJgpM~eab(@;fe_U1f#?E$JI(rA4Td0@r3qvk_yG<3JbNHt71LsPO$-F?9H zm%g1ssV(jpm+6;Eei{NFEqcqbbGYmjJ>!nR1wChcab6~VNY^S3bLAALm`*v?)_+lb z(q8FZwR`HCd5hT5XGqyeHL2-hD$M<0Ht6pGFmgPwQ;J0rnt_A96h;7uhE|%gv8Va) z`~Z?FdX4`Q_*V9{L%GGb9QgcnZ+|PigUAEe`I`Gh^IJ-rIrfJs1(6=Ni45u?JH-2 z4eml@l>+HYdns5Bho4WbpUbXfHr~X^TART~xGgA4j6nA1{kTlu?ja!fHql~BbdV8O z`PSWc^ASXO;VyLU+<{7)4;*BFDer%!m!KDn(y$l;Fu8&rZ(Ad3XGVNQ8t>;cZjnwc zk*v&_W}dKkpqj^Q^%xM)EuVnQ&Na+fgX{Q=p>(c$ILa&02m)Bc{hwxTH> z&i02UFM~Z-#(}?pE63tb#K*Ft>LjZY#m#n1M@@#GL2ixJScXinzq-b6dT$r*fUZ#l z7}q`9+n?#+f4t(KUzuG^nQhrq)D@fxSW(;085pNM%O9_}f>6;_b%wyZcvj5>H@+b}OhOFe*Hc+h-O|<5ci~ODlBvSTLRwIbK!uhB z%oxu%<6CdYl++s6i;H}aCWc53DKtnMO&h%JL@f3;BrQu`tFx^36#fP#2q>F;X^}m1 zV8D*?iqOs0X22Y4$@Vl%klII?>L5Pd?AXYbfW0KPAJO}Zn5tizbgOAe3&$GIMGT52 z?&q~a&Yv-lUHm*BILNH5^6M`AyYUb+s+G!!oJ4y`7~R9YoF;=mnG?L$lVy0F$mK9L zVtjE=BsD?(&>Cv+a(QQ-53%Fo#VgXoEN~%<5xFS*Dfz5buh>*@I9o<5m=epa?!lA& z>3LV|eZN#|BPy1%@SDr~bLTq;G;1pZ);mW6OWl4oHrH}en?B`};?_LCS4lLvvr(;w zJ5+ejMhxATa)dHDSLu&SJ`A_A-x!gOU*bCzfA41` zPY!+>F}sZ~oN&Y`Hu<&$@LF8?@={Jnmu9cW<0aoKjjHqZR03F(?P%YdjJvUv(cbfP zfHd(=+hAk=av&xKWr+of2@33fXqJH`Mc5aoDqUIW-tot2hFcL6Hnh=Hp_$1$bv8Ps zxBT6MP;H4x9lz?1W7Lf2Z{?)yU)23iWnr;4aWuELaQ&}%${}U~K9Chj@<~7ndjMjY zI{r=AjC>-wqZ6Gr=Doo2vXCSa9068jZXyF4quf?*CS+jNwmR=mxGQUQ;w-+Kb4(N# z9hrUAvg2~jyLU=aOn!h3MqdycEIyJD@&R5Ty)a;4#DCe~Uz7Ud?l8A;v->^5OVMnK z177h*$k!w=2i;1Wc5f-g4WI@c8L*H~)hxW_24x#2Y%XO*@421(g;Bl)%L2?XlYIV2=ZRQhGwk#fnz z%)xA>^xn6qDfo71nhf@%(n1?yJxG_Pk-SWcqCJa4-v!kPM7Q|eTU;_XeR0Ax@8qox z5sWlLUcK-x_a@@qCJ5IMhQ>8On&P)w@pk*ny}JTy_<}&bx0Gcf*ijz9gtY^+)BZ7q zAr!pzr?KvtnU$c0%J}||!{{4o;tA{~biN@ra1Xs#O?opQ7B*ow{78 zlEhr=B_Wy$eFuJI3xMeuex)OQD7s5@KQR+o7W|&7VZyGuv!jFOQB5t{s=(}1KxQg);D>^zCIz-x{ zait4GQ*pP-KA~;kD$Y|RBJ+RIHSATvK0CJki7Drk^oW#TiY9?r4I#QK zBof!oPciFIUsP!E%7Nxjw?hqZ?MvWD*W)u&#|EiuZi%79o=bIf)s(5}VXh1e4Oo^^ z8s;^UH}Ty>^}OXJ{b{9vOXsZ&Y7znArRtD-Q|?wPIr$G=2!5GQ*?OZ*AwQr#NG^`t z9R+Qbt~cfq*%n4S9#_SVYE2|M$Cxz5OXF=$N3)^6Ey;tl8qo?9iis#%YKN1y*@FHGB({aZTpJ>?`o{{LesRa$&zURRL^Hjnb38lmaCY8T>;7Ee z=||ERD{@GUzGPZyL?rXZOx7$)(>OX&+K9W7QSw1X<3$II9G?#NnQA%M(bjp&BRJ%nS6% zR>1MEzWJ~0d+OV_Ep_eFVTDmTB{?nGLB`RUa>e11^+~OPVWt5V`bZWz#!==5@kBB8 z>~tN2#I&RkL)a)vkYb)p9Cl+g@O@9fAcy%M?gI-4XL}QOVCwg$tufgv+*(uOILa-_L0B||L-6%w>hi1RCvWUC6hRwnR z<1`EWZ1dOm4Sr2);ZKN|+$#X1;CSogyAaAcZ*q$6r0?bj@$21dzJEf<1zb`C&}Xpy zzn0}@VdiS#?)JO$0In=nwM!kivbHM*kI%Ug);7>=Jd&7Jl2#R-)DAcUiVLENY4GxoX z6CVz%?^yUii2r^>4Y&C0v-TQ^dgdGPruUW~d7MmI9K5p8To?@-K4X4Z_C`V(Z5lYm zzj}Shg$I_Ja^AL+hdwj-C7*ThP`#+Q^9ue=_tDVk2Z8r5j`5{xV2hAU)Btcq0THo&V&pbObX#Ii7QDvp(n2!?k{@%2R&FVd@(oWYWVRs zb?&Fk7_2EdmildK2S_IiZ2GMH4RG(*fdluiGjO(X{!iEp{KRbLczd6nT!a?&#%qG}S`=PJ&p;9l#@Wb}xlL-p`vy(FIxBX=kth?G}>#>$&i z2J=-bp48kx7jwoq8C`&CUXBpvttm(qY)+QRQW2;@S3nJVu7dqGd(iw^ZAkgIcGx*q zxvNJ^?)P|+wP9Gz$~L76>V_@D;xhTCETzeD1T1ix6EhD>s|UD;l^Z1d`Te@91^nJ7 zRJ$lD{b}ksZp+CR2*G=w+Sjyhd*A|N{hWgDW~bkwlf8rT>6rtdFV&}5U8 zn0YZxPFo)nOVek-Ld=~MQ7#s-IO%H#LHH6$VJrzsfMh%<(}fwq{PlsH2dl{WVp?3h zZzAcTFUNxn|EOEC1G2y>nT?nxg=v`pWhKj1%g25R+^kJps}`j=s^v{T_x$UN=2u3S zs}P^|nq8o~D9x^ly7c^EK2S8WwU*$KDty9CaFy=v^o+#LI8#qtsrjf(a~dO*IaYoa zm%TWWHnsE;rvE3+uSOho$&;-B-2MV!@T+q ztRIAo%W6D78fMGEjds8$=aGT^aFVq71<=CS%lxx{RwfGb5+-JU+_I>bxor!ZqyMPS zGC0XxfVsK07LyW3w;O@Ty5QI&(3P~{gXo^|TKM(HVqVByS@Jxk)`l6dILiX<lQ0 zEumQrZzKFNPIYXEPWV}`TWCV+NsQ~)l`?yY<3ipXqlLXfrlekqe}CH0MI)B4kfolL z#o5+MLqwIsg=9!jx9)$h^_IF#@Fm1Sd7vv>bXXrSxu}imd!~M_{l)C^HwmY$U@hKZbxt#TiI+ws6#Zb52Q#^Y^=Uv z0LA=jZvy~4#V!B!MOjWqRvgr=p|mrC|HJ(z)FUT{qfk$#MGrxxzDS`TIw9MPyFB_@K9aVzmP2(i2cK8n%WKi( zEJr@sR9X6q;OVT{_d2RDO!d2bG|F0;|2AklPRw5NUa|brD|Kc~C_wuXqj>5(v!O$; zTG*)W!2TAug)+_ge!41t%?(;)roi#rV*ElpQv_9qL(LeI4-w+iRQ}o3=Ekz|#a56i z{=P{u8$ACYd*$jFH?pw55?X3y&G_gWRK;M2>hSc@S$D*rELk%W%hr298zXcQB8gD|pi#HKKZ&bKd$q8Wyox2dy>6Ge} z8uzsaKAsqyjzYpuDjd8GOkFNvLTojPgyIN3oyRdx1yg~3;w?$lR&;hw2bRi_&DWis zAMGnfG^6ghyEMVLUn8AqB`rBTcclX9U(%B6rFF9gf|DxbCodp_aaErbc%F>+=Ds<> zXveGBsP-~m&Wj#+c-MO3p^yqkXw?Vt)xS2~zPgSXX*+PY5c)KTgUK@qLhuwUnl<>G zp6}A9pNiBC%|_P>+C4VkZ#Y19oOl+I@fs@d1XG9mM1Pl@d}*5}6Ry%kOn2AH-{k4O zpw+mwwe#x`6OPej>Z^29yGqqIg7Ye2$f zqkczOaK$d(9!_1n)FVrx7vyGd^q9vJ&c#n>DSs@FwVi?M_lND|huct%Q|Id6OD?vw zT(KiLw5h^!+Sb;kyHyOxYAIi~fKGwp(r~llx0Z+-}WXAAsovZ34^0=!nA!-c( z33g2#(Rwn07YY|JizNN)Lh*322RK+5Is8L|OKZ?^Q531|jzRY>7pmlF6BP<|Tx05D zS|c!DR0GZ|vZg3q3OBBmbFkxGL4w1e@&x(FAnUvSei;<5AOg82!@Q8Nnj1*W&xw5K za2kOPv1gna!D#pzpHu8>VEERvP1Ty|UX=4OED(u?y*m>ZyCj@`@N8)@169%^J3+ z0J?ewY#wj*ocKJ%r%Z#JcvSD?%|@ZQD#6dtD-Ke6rt(G0%7#hwgq|lEN+{bPbtw^ydR`*HVAO~@%&iY_DznV+VhjPeqLL@sJQz$ zXOug$QaL;Xdm8)Fp26Jvb9g|rb&}W6wH$megY1j(c-`;q31hotPML_8uN|}H!sO3p zQdvL3q(rlqKYEC?jLDIl=;$U!?|*eczdfF5o}hA|e84}X zz`*K)z=4+X%nk&V1EuOc%Vh)Q{vz&yih*+Mp2Y}(H|*aScc9{+?6_y~JfQe5Ez93C zIZ$~}Zrigw1+d%wU#*CLlm?}RJxfyqL)5=A3}`F+ z83q&OPnch{_dW(F9B9ws8SXcZ9|#;s2Lcoev=ID^ z)d;LH{3F(XmxV#$Kud1VaG3=E0{2$|4ipQtl=h5;O89rI|GlsViVa%NddA-Qe_?}E zw?N@ROEu5%cECd9AG`YZ!VM@2XvyRmg$|fDJ)`^|)&ZLKKf_dz{t5H1MF7w_f#z<{ wV4T2y?jLjd*Gvu+3^aax2793X6YSrkNmT`CpmzsSL4p4@Kp#Cz_uIGs0nG3*DF6Tf literal 0 HcmV?d00001 diff --git a/global-assets/image-pipeline-packer.zip b/global-assets/image-pipeline-packer.zip new file mode 100644 index 0000000000000000000000000000000000000000..b294d9004fa7ebe478ca3e0338f41960cd58c34b GIT binary patch literal 6736 zcmai(1xy_6x5gKDDZaQnEKsz#EEI>u-QBG~kphdfxH~NlU0jM&qcUjFwc z_siGh=Fa3~l1Y9iZ|2Or^PK0XDIy>e0000~fNGwbzMMF1MgtrG;E4bLpugPZw6XKF zvvGEDw=&Y;cHZK`Jh~wiDSUmMEhYh5iv+M#i8JFlv9U!Vv-obVMkKa7oO%`VWdpIc znQo~a;Oo&cl;uQ1E~EKh`6X*iiJUTxjqLv}98gJ=N6o=Oayz_%RWu3k^GM_dA}mZc zF1ToEI3PXWHP8qn;z!0f^Rpig04t%52qdzo&mm^PGNvqyn{=qM=YwOYqx2rggGj6j zg1`i}8sQ&3ft=c)Cg!Y9*vwc1ZybP0^=IA^lJUXruDC2+Ob3EYx!Bg0=LC|#C`Jvn z_v3d(Z&+bm332k+VoVAoNwcl&C=p=2i`}#x{k+@qlD zd<(J9&KCA-x>d57ANn^VoV`hBkDqP4@-So94z6NKg*Rb?23w77b;-80*DW$7QS$dh z1&PnyF0WPKsD9&^f6WT{l$CsO&sT}(Dw>;JY?$U~M}GATs_ys`d0P=bn$3YW%t&~1=(qZZtf9nj+5Qqi?O)aH=byy)dZ}viOZ=z0(yB6GRUH*D zM1wDe8@rne7xAIZoZ$`q8b)$5!CBCcc~gx3hEX~8Ka|j(df|on^&P!WOL*V%!${7l zhw)z%`^r72Dr&nHyt||keKn~HN%ij$1<#;M5)_yddQdWgv!Nf~7@r<0|I_Q2pUTgCXuu(Fcs zG{*q@TcnHN=$@^kU$mTnf9KfZwqUnK0RVs`007oY4s$O%M@vpu2X{_e3&#rGMQ1Vr z+<;jfOnziXgh^J8do>a@bUAI(0u@IYl_**+qFU{^r>Jt*e)vm-kS950T7tG2A3Mu1O{Pi`U8{+%ehO$udZo0j$n?XGEzXhtia+vSb<`;tw{3Sl^md z>#cMjB>6TTXgsP2(lJBZiao(X@9nlzgIv*pIR!s!#Xd3`!N0=hT_=qEowqY>BccdN z47m$@(Y=Q0CcT)iOwRFWf-B(bAJ6b%$@y!l4 zk%+m8WnBYwvwE#n`~|b0%D%0PSD*1Or#$+Go4tyIVTDq#*a$`EN^t7An!)7)O@~b> zF%Cjmo|!)Rwq!P?_8bPje+7NZ)p0-BP(CH{dpG4M+k)CM0thEQ?z3du8=DLI1Gxav z*gjzk+Le!sx^W97UyN6}P><76der$sOxC6-vY(jV_7eO+&~f9P66=&)=6Yg>@f6sl zOeEnpkQtuKy7pQNb2|$^5jf?^dCwH5I12pH$uihWI57mZSPaiV^KA^?TXIZge59`R z@GEp_2pC74Rq%jO`Z0~QVN4wzQT$#nYKh4G_N_@Z*vA(N#a-_EMwL%@s_v+I(07c_ zEW1+nP>BzdlZ#WO79@n$P?C%CWBt??&&jSVSZ?N>#EBQVHW&(CoPL_#0hd&t5n&~;cFkeLbM zf7Y{k!u>8&uqFwd_o##Lak!X_bb?VYkF(yTWpteWw)1wk9Zqt*OlTeKjJcd?@iToO zp}K%2{?OGRAJyI8`6DSP0gdnu#?2@utM9ow8}vLMb4ubw*7^{kU{9MSw%MTeO^M*U zJDz?eUNU|j{@AK2$izfBasRmYs(;baKhW#y-v4oNFPNY?03Q)@TGc+p3Cd0SuOXm@hHA3j8&FLJ7cx()4Uz9nwaqC1pr zY5E2%$gC0yKPde6iNVB`_lNS5&9U@yP*&T?)Rgm9GdaVr~pL0ID5VlJB zql~)QfCLkxJRNE6lfL*5(_AC3$Kjh%Zq~g@Uy*5x(EADyN~{X@&K(v?wjW8G5Oh<{ zPgL%7we$X#K)q(kEuhRyPwMpfFU>Lj%l-fZ9suY;{GVU4rHi+-ql=lPl{=@aZum9n-d|Gw976~tjY zz>c;$8t$=Acx%%use$;N@^!j<)6cc(b-5*C(M!~f3Twt4smV!Jq6{p(>+|TPvlgs- zI={%ZvVf!t^`L^yG2tdP?j@JsL?Pi|)KXSmbjf96^9)ZPUAy|?E{^ZFKgRQhUw;|* z`L*(ULeRiUV|>Z&NLU*a#BgNQxtD{4wrU*cAF(jsM~)2oq!rDfq!Om7Ffc(o#-C+S zOg1?@vvyV0Is64)6X*K%BT1Qb^BAc%XThbySuM}IcKCsM84<;2xA#{R{%BzE-6 zpum8@$c{aw*GU&bR`RwD(XThi03;bmc^Et#K9J!qPDc83`R(<1%k6{M+0N73i$0%> z=f8wp8y_th#)}Hfqy_+pUWA;Ji@U3>m6r#{zZ6}Oo|DU>Al~zdNtXsXJ)EPE(`gVG za7v@xYU?`BZ(Dm)go>!2@5G;2%E02?{`Jqp$Qd}_vLDpm5EV97p`HjF1Kx2q&y>@*(NlfZKXagAb6-wqE!u7?_K+PFGhY4N z55>o^$^C{alz|3F!`%8Qv<_tBQ?*k;&*bzOLO-Zrf6UxAYm%11LEP0 zNOba3Sq@uBaXR9-T(qFZkZhfkF3og=5qrMJ%((@SPaZj7|For3T zA@@S+NVIB_#{_+#nJFnWlWciWq}z>P%rupOnClH9DA8{hK(Q6_9~Q9@1Kqk>#&T=I zKShZe@o*g{^NI2wCns@Uu>uF@Fr`wlKEbAt@`j*{kf4EhO^84A8$AQZTzs|rU=cIM z$J=qA5+Xn%1FtgJ$UeUDT*Oi!eZlYFWP1mi_{Oz(j8mH~YyLO_) zd0lZq@o41y;4)+dZl`31EDvITEmg&0{1bs1$>+0^6<U zUbL!gG2hs0Mhhi)*Iq`6>JL`dODBk3C_(BO9=e||KRbl^>2ZH;j@l8HX^aI*2Xriz zdKK}Yy>X`ursH)TjJvmLZQHiWoCOYbssx`i=-`Snri>Uv(2C@^u$|dxKod;(MMys{ z)jkij$b2}GVU2{pGBZmggy#v4YCiN zpr?G8@X^|G+gnEMy;y-~x9yh?Gp60G;aBNXB`;xAF)$K!>baAjxeL#GPcxr4`%;UH#Ucm1?dQMoppS(nVsBj0fk zvh?uFnB*0TWkL2-p0=Ct)^8sD$4~~eAQpo_l*91xcD+;C!-o++@!e(bvhzkP$D^ecQCSt_Ccj@KVj@rI8p&kK@97dP7sS zDR2%-$Z{76((tGxzTyo}CI!VWX;9zP^wv%~xU_jtIqG`X8H|8T`p<4mH;G{1zEhT? zAV^EkRH<+8Ytgi}JT;o}?Bfhr)Rh%P>aa(g#hHjA)b*|h)KLnz+fw;^?326Xsq@Lc z)609DFbGJQ*%H_N>3*EDdTmtk!1`dlkz!i!#?J*pJ$uS!4gud9FtG z%VNEKLkwYr!mS*xs!1TGwfEO~^V0OHLu^rJ_xqILqEa^Mo-fr+a5b}~Y=Ag{ZGszM z(81&GWGCCnYLUK$aJ&-m*H^>G9>_gv-kv#aN`B(rH|L zlN?O!&=MZK=t^=;>jPzu5fH_^dr$co)!(OIK=J-v(EA!vp%_lgVpIZUMP@j>r4dHX z*7d%Y(!OA0!X2fvJv2}-UlvSCXrGg$Uvoh=ELG6j{(@=23- zy~R{P_J?*KdVDSebgXdN3zv(l1jA>O_%##PvEUD@$;_`)BcpSU0S;aw*wz}24GVkj z$d#iX$r-a?A7v^tJ}Q+jaF+eCkdI?o9Gsa-H!O@UTuCQFg%?IH~;yY>{#fRU{=o|NgJt92x zK!b~4XJ91yg9j#og+;|e+jL-A^!Hd&Htm^Gp$m1~`q+i6s3_O(-aIwUUsq&DU9mBg zWHLH=FpL*QThK&l%9XZZ-7~dW<|?L6X&+Lo$obAwMv%KexK*DB%cDx@7YIKNfZ?5& zLnSX)vP)A%p`x7>q=ZsHAJfNt&r(jw~fx~c3H6+UFf7h7j3 zAu_FtzoTserPnSB1`S{l#SU`PiqkhQdna$Lrg!V=q3$$!VfLA1x*(g2G;QlROxRY9 zk|QX8Hwrc*mxUwXw1Lgkz34??@*#r;Uf==z7!V~sRLqbdJQF+of2V3@QY zYqHs+GlvJRei><7lPR~tF3fkVxsIWx)uuafK^(^l*zh$QI~JN~(Wn&_&z|*|-U{2g}m^F^C!NT@|zICfdAt zZ9%amQ?VWtU0oN|AA_efS7~dWrTFk8If99ElnErGKXYBw^yhjduIz)Aqm;wy(^K=O zKD>hU=qISy>KzdqTDH;dzs$`Fl%yfVbDvm%&IPU*03dfP4R^yX(ue zL20Ivb@Y2h#Y{D!sv4F95)vn|E9G~UO`u~PF-+Wj@07W43jyu9WFN%C8eil$l?wfi z-Cbd7EgV(e+B0G(tzYcl1*F!Ppf>~rcVQlH$iyf5BbUtCd==#o15;q#c_Y*UEhOi|7_Y0svkV)PLK!wqE8SZx?q5YeyGv50J-e6ED~Q=x|P7 zGbhKGBp201F5JG=8;xxAs$wMGp}7IJ7Kjrn8Y3jU*e=p=cfm*5X>7ONGy3#<-BfB& zU%F;dY{0YV*wY|(v;w$O9L_>gp?k7vzK}=p3|XO^y<7=Pp*A3MdcM&Xf5@ zf0#S09A&nFCx6c~T16PpP|Wj)5S=q#E2FSZ=D91i&*{GlrP$M9mr58_sGM1YCRIEd z?&)hzqce^U-(d=5uJxv)Wp%cxS%#&lSN&K*kqP2)=R^-(2+0VVK<(>V5)7rX9xjLY z#7p(-c7NfsugYhSV8PNB4EzDZ&!4jO|2N=lzXpD&HZ{PG*W)V6>&ho8C z#IBIu;0-BAkB^oz9(T-f*@}C0Mr1{y&&o`HV4=H7L(2jnn+g_ZRv(>vdn`R`sK!&+ z=Ehd))g^xvC_)y{@*KZvXq;p7|8w_!mK4@}jLf=#5c`oqM*p-UfD zH=eOFt!&bW@AfYIea@*Q(6PqaGxD&j#nlwy;0X}^?_tEti~Qe5eei!S|BNR7=Ki+1 z|Aztq>VsEaMjQW_-hXp{JJA1delOqB|N7B?V}F~@|6m<2*uNT>*9;+;vU=`F28qG@9tjJ z&D2zP*UY!8y8oM*&v%87aJVoqFi0@kxlTHVnHFpO|01b>3;EwtlM<6ul47$nQ~xQ; z!oDyuuB50k&pON^J25i;k;^6F`g(?QwiT8W6&KVyK9e^PKmH;V)bK(LuM!Ikf++#A z!F>OJ@=wFlv?I~Nz_csFz@Yuh?`ZAFYHIH6!scjhcM6hA$d_HHy622|cf8jkq5S4Q z*ld&)ml{GAFd&37aB*BMV-}^Yv8Jzor+?hFV4R#>5aCD)g?MJ)^Nn`DqQ7u-Fp#{5 z?6Jz=nSzpvJ`B#jtfGmI2 z3VsIWPH5!t@52LYZjyKcK(0lTZFv5(KG$hhS)H_l9TL2Yw>ty- zR0nBAL)F2y)Vo7Y4Wqlk;3@VHX`%_Y2XRZ;IBET?^_!{dn-?&-nSq$7vh^`u+QiaG znz-4zkqZJQUkJSm+ZuWZ*fnI`!2ok*H+z){$UEhu#JB#z{R8=@jOM19W(;k6Zo7Gr zD6{j5ZSTx4zSl(RBuXzIwUfa7Hga$Nl&l)s6Uy?hD6j zW|f6@=M>(LM(k>v^aB9gY^B9`nl+qC`ktp6d+>SFc+BF<%o$C0nYwVLTgV=%E?O>1 zG+s^KFYEl_(ywy5T!tai9GHRj@RCVCg*ol3MWVytmEn*^A;a^c4QbJwa^L{+(@>nBz5JGwB!yF{$7&Vs@~Wy6Op~u_jovhk}Y1K zvO|o#s-)dwDzf2y@Q;zzIfeFeC7D7EO=k9`U%_4OxWBKG-&oJU%-T~tt?Su}8a^O1 zeM%CCRA#Qo*Lz*ep`NA5ST{fXq4Gz|cFC(_Vj%$`P7G)Z4zQJ^Sh#4GvLya!)MD~ zS$w`@xvNMCKm%j1K!BGZ7q54)Q$day2Ny7VFuvB-hj{R9KlaG(iBAsC&i{n_3qNEw zHxildeV+IAw{}#Q-|+Ski$^EBxpKJ)uMbG*S>83~w_4adzyB|)SxC}e(g;awLst;% zIs@T}lgN-XM)W37Q|FfHv=mahyL@}Qy(7sayOPU$Nd6=aB^_L=uI5TN@JQ0@L`6uk zf$w~t)}k?Nw_zC1FnZ;DIAuGB9A_Z)0(&-XKlsr=HqfW?n@cl{1T z#8@3^dI)EI9kK+<1!e5qTBV}OB15SuK4jIX1D}}3d1Bv3C%)bjE8C_HFV07wJ2wa( z4<5RKaYp#!ic0QXtlZf<1BO?g!4@Ll$I_OdE~;1-z>d|(;08AXIt@(&a8Z7W&9 z&5K&lv%mb6aA8`yo2YX0zPXC#LE5Ay?9Tyu`8#*rDO=3Sn2`N4%bV98YgKj?3% zXjk(k9=KC5CSEijcZ+!r%Fz#H4=*Oq<9i>^W5u3vh?cVT#NO|kb#oV3y^;>A+jkx& zuA!M*)Y*J>Fi^3B(>V5=>>YUb-b>r8>q2E3YTKARR(e82**`q`=|kqhxn|i30h0GDA&|2kWCUp_{Lp~ZoEpzGPKrrM zrQ2Mcc9BK+mqMg0vGMfjphaATOCI&^4K$0RfFUIT64SyY01`vuhQU|kq#vE7V?qW? z^<+#8rb5ze72%4ne0#9_h*g}QQ|NLRt$Ykk8J+FeWd$kNmYx{1O_~1={!zNVQu|zL zQmd(FB1Pe8#YN&r9~KBVcVSXwb5ogUh;ATig4Dm}?;)Ec^gVqbx%34}+2HEQly8)70j~bFOZj6z~%OpjJ+Mt_?q{q2k z{q2l!g6t^MIz=&OJF2LSMiwf;Cwj#@nU(FS`RY}3@<=LP{QwdRRRfG}1=sbqbpI9W zSnRdi+eUdhEgXDj)6`f37hT<*-#WLJZfLWWd`wq6yLmLg4I>Rpn;P;zKhrm_H2%)C zmMVCvv@-|HSHe)o^;fpjE z<325n0c>~qL0vtCU2@+Abahx|2p;BJIiw-%d8Y)jbkhWO#S0I5>}ggVjTELP^lfmc zy$NutZI(izbICwj7Wjqk_G3}3%Y)09TGVLxy-XvEe9b=*c6suvDvO`eax1E+C`~kB z&BmWGa1Q;M>rM{1oZ$C!mhubT@(y6Ra;>D;zPx^jnEH_IOYXaeJs8(Zs2FG{t|-?}!lPIyI%@Ck;xgU;~NO8@YMv+tZlkn2nwZ(h!}j4TXGEZZ#Dh zZ_XV90lFt8{#Lx;Sfw5H`}p{ZCZ##V=>D1*>bFR3kW5&^xFCt04alYD!U~}#?_bIv zR6rym);%b(@0R(Lab)^Y!MM`eyt)bC0YJ4PS){Ich$!b_-1A_H2klH|0Q9CJXN21h z^F-(j(0M%8dVV3C>zYkd1%b{j#hS!z6m3NE4TFql1Lpz{j$_TR-$J!4tHTD}i1|4y zTgMv5!ovl%=Ea<(tRB(l@uZXgej{#4S!5q+#;Vr)!UIM{3W)eb<>@iK)UQ#_lFmrf z{aJvxOn@)|xS*E~rStt}_EBf{7hn6CBySe$Wxv!lRlmQGwf!fYmSv_Kswe&X1;Nut zpGk`8*PXd&m85V2)V`N^K=I0K^l!`#(C&32(fCwAHb&8(J|ohN`Xze+Ef2npHxL|>x!jfsUrHVRA-eyl?2|VdW!`Qv^kW#%PM{mN}4dJA+ z2)KT5+h(e#pvNbY;4BW}>XTCMGo;i04Fc18Em;7^ufpXBZqZn8j)iM}niulHG4QA= z8Ipi_;{uS{zox{`W)$`ZlLw90j+jD+wsfYSFO)$?pC<}Lz%}l7*Ou)ox=v2`(p7)18-P-#t^($1ZH(Q2Iv^ z&b{uwaqMQ&!<&g4hQ0;gwkxfA5~JN;isS43wxf8Rii=m z1L-?#bvYmH-kCH<%Mahyefq%88HEx0SWcbZh?FwLjcFK5pm3kq&(}{{tH!sz>lOE* zwOeYt8ZbaRGwwtGmG(|rhVCKRIo0?lS7o8^1Xgn{AoH4)mfg&qsCgliX-eYGMetYG zYYNR94xc~z#N9S4JF8GZX4~;F8RSH#PQT}b|Hg@0N$X!Zfx$9+Xe3t+ImRS%XUc6~ zc=q2EL~1kz)*@R#JR1OSSeJ1cgH37(35tW-MltWe6&;Zc90J1;i9%%OfT$9o-8&?_kNp#0^pUj ztF_Gv`d)3stD9R>CZelHX|l%T)AfrJkc)0G_u(5FVhVEHh=JIU)n88J;6l1=I)wT< zkup9%L(NC&$w$BHe6dkdk!wW}*kbA%F1)4Dp6NK;G7_q%^|GeH7Lly4g3%57a`@IB zPD+-9hQ)NwwT}{LWR^mf5r&E1`W;qtO6o+6hh6dv}`UD){oi^Q;YS@pfs-21KgZ zwhS+QJTW~;OxBXwy=n_(+vQ)8&j-3257@rtH|f=tmT#a$P2PSvt`fib;N(pUhD2;~ zK!%~y!_a7KR?{KF#Ob3GF$*jeW|k=zQ{#B|C|0#fH097a-!_@<%d1~np4yvM4By)h z|F-*Itfyw6l(ka zX*D6|-?UM^mIFNY+9uvm$dkUe4^vjy>uz zk3QUu+`L1dV_V<2kyv!xUPKk(4WA9VxBdS)J?`FMc;93c5#l3X4Dg-Y=U?{08}ZSm~60`7FurO})N z`{4cg>(nALeR_Ej3^C_4^Fne&sJzB+G5eR3u1Jxz&I}~M6CQcUkj@QMJ?y9ACrKTo z-?J3x&>=~+j$SR1kslbIo~MuzDYMZzZIn_Y;I1DRQB>y!;*m<{abisV{O@>A(Yq;T z@EW3@ch|$Y$vYnrnuriU7B@>dprX(WlhH<)$oS|v48lZR zSZKbJW9%a=f4J|SLQyNG4hd7FV(3EkIsy=#sAk;INM11P*SaQyczf45m3L$a!wS7E z6`T7XiSRe4zLoOcY2w1E3WJ39Zx5i^asbc}qRvliKyu>f5*|@@7)>Cx~te;I(FV68u%i}u;YVzJw*Rr;DR^YfW3!F z8+lNjnz=!>zx79mn#4RyMKiq!QBRjc$Yt(Y(E*i5a9y3#YCR)%1sF32MC>wMq<{lh z0Tc#L?eNxJJVMy#u;x6{63jB7D>-UZS+rL7T4~h9K%$=;FtiPlYdQ8$d`=2ohcOX@ z7%f;FJj6zhI@$!0rLJx@?bmdi#lc*BJ)gtECuZd7r=sPyT4yAgwP5k75OJbLdC0vI*&v za*tth*O6eJ4E{0Nkjl?luDzR+dA4hlDo5m+kriKPn`^^;S{r+Mm#aJ>s0oAPyfFzC z$_xZaRcEgXEV4i_vL3@6uL;4qxU0z#2b&W(aWmh{6*-PY%nUwe9VwSd{x5Gj7fRJP zvwN>5E13cDDJL>F+T2E``$LA`E{u;^4u#i6Q(fAtJ>6y;`2MYYGzTIIUJg0ttxUp&W7*Gk z)=P*ET^N1UE6;42;$(z~)``rOOQZe>TwJq2{Cd*RvoWXE*6sPIcW3i0cOw5SNn1t? z?)#_95HgfE_jUXy6%!N6Q!q0XtC_yckUqJ%9aQz(@K>m&8#n0)mStB23xb=|~dcNpb;+yN#nu z9ezEo%AOVn2F}Mu8W##-;SyBBV~8ewN9EZjwjOMsb(&wNo41cDER98<95(~=H$ zLRdtbu@gd=$QBrk3SdB$>^-c;NO~v%na)|esGEK;HFN63y~*;}BS&(`M&!C}Q)WR# z9esG*+OdY%lX0x>iraS**~I`ehh7~9;(VQ1?&0c*;-@wsD(oH>-6;nyyCQS+@YHh_ z{+i4}Uf@D5YUBR1zy|v-&JH3K<X(nc%$w=-2C)dW8~)AYv1oxp+kw1%41Dr<8W3D_4#v{(kkn@}yv zgi(7L(>r?5XrD2;>+G6ia8Axl+W(}VZTRYb*?C`s9MVM2w2Txb~4DaFxUOc}b@L3hdOw?@OZL)eLjFoK>#qFjT{ zfXh^&cQ0~S(<0_I8F?0M+0k1Ebkm|Gy4VXvwk?%MF@M@@pD69Uz#ON5rLo6!rOkCKp?Gd=S? zp5DfLqt|5mS zcqd}+^Z%B7>Ui>uNA9F&>D4AiSk2(Oej7MI<*j*wFX2MIz8Xkv4$<+j*5{z)3Fy#+ zqwh8N>1+Gi%st3@JRltE_6Qdl<7y*RC9y)To2adha+ajdG@ozz{tz(St5?FWc}3&YG~S_1 z%^A?*NCqUt>^uI^iyWcp!0w2O2_^eAHL|rNypJ9bjz-(ztp4a^qvJ*Sx}Uma;L`D& zAIX_aZo=1kdx-?E`Czw+eK6FBjr{W3I&wTMoD{f|V*ABY$Wb2BFw{3_K?i6**@9va zZ=A}Ff2t z82ySxg{yO3;+1$)VOw)PO|tZX(sWy$*N_=Cat`^hYq&c6fV`t{cH?W7xy$lp(Ce0i z)J%GYhu40O3i%;fmlJ_I*jH^jdvD_d0;q71qHB`SGw(k9+m(_RuF^^o%12w-Nw`@3 zvZ$VJnvfV*Isz3@t9tlf`{%8>=!ZQ!DRGeW4#=~#vHV8e`caDYdB`F)jK^-q)`jKT zbezLxu5aTJRK?Dg`~$6s)!xnNx_F4akWBN#Ei)jaC$cIC3jrlAv=3I6`tc^guvzo4 z$r2~}r_WeXv0?IO7hMDMC&Zi;V&1D}Iw5r~jv58D;LNZI!J``}zYObxd%o@~5Zkv5 zfTZ!DkMKI0jfW}3{Wezm!-^RWqL?F^y?jry>{~=?5`$)(ZIHrjZ&+Y|NQ|URc2cCo zw#p_@Ce1#4iu^`fFg?Bf^bteej|Fpjoy)jLqgVc}lTI100=tXO{#9e04KrE#Ty>K@ zMXOc#_RgNR1YdM_F>*9&0wZZvW_L<2))LPK&{wYc*Gy0Vs+1OTVdk+(7nj#b8ZO`Gi-VP)`V^xk1Gopn5USg?B%&rZ+AB@;55=br487lv&EU6?R)b zdmmuTQ^YELwtV^rz({WDC~5=c8e8;cQak_mGvwT>9zI^Ko%o|c1kmoRYuM+(_L6Mj z#yXSO(}pqm(A9>?c@D_+yB6|fe=FcI7{f2tuoG};S=Axzz227;B@mZ9!y(T`jCyA{ zY?J7Ay#tjK02xM46sAx z-^oF*20z~-6<5r-`wKT`?eZZ`$w<9AGw?*D^}$C&xBDXg59a0d6Sqj>=j==5D2b>x z&7vo+{i*fT6A-!T931anaDJT*Uq@Gq7TAs|Sp3)Mez`*H*7BNSW$|Q)+24Fn>L6T4 zsCr$N$QOrwt=AW`G0j_ptPGg|^|>rc2jpb-quP_AEtV~+>FPbAGE996r#n?nxtZA* zkX`V1#xVKmbalGa>7Lf|SN}6eAobGUbs_bEeybzuAsG|X$lPPk-ui%G71$Yrpz>f> zQe9pWpl@yQ4hUcHJkZK#7OjJ_nO z;|T0_n~&B*<1fO-wDoo3nUZB){Z^M|`0lZzpLR`2D{iXflWa+q7}tzG#iBf`dMG%A zvM@G!^DHMMuon4{+x0elZ9NI6@1n0IMb06#nTy^e^h;3ikLtIrZ#D7!lRre*AMI=0 zgbB~_j9PH-wNkNfxm=N}5nr1a67SdSBH6i78{7 zSBqiN*eO=E?X+K8$IY({OE)&IpEvKZLn#}A>ztvn{7B)ldf%Y+xb)fn?%h=4(0da2 zh25mIG+9Bz+C5-?ouAD1Xq-*r?@!aoyS&Z>I@9-Ms5twao^iNt9oq|Jn(TFT&;g{I z3qTsh(~o8_g|D{AbF#S8TYU>V3KP6kB-&4IP@!JvMtsA##8{S94V~n5ip9Da5zxD) zhkiC*A%wqwS_r1$h5183>qByxQuL(MC8FHu1Eirdy(h;P??UrPx2=kh&M+v;&76^* z4M}L$0iW>onxpu!5^Ae?JwK<{>0l{JKKRf+o2ymnFvD;LP4N!0{Zg#R z#<9}lF$?Am$Z%v)pY8VXsG)@WEUbfESEiO~G5?ifefhaFfsC~?Wr zu(quFTV2H%KI6Xl@)n+5EgpQn`-}9*q2lQ{1e;i;nL(BaKRU$)Fo7mljlmy10p>Qv zHgddPlRf~n2h4|6qjht8HtBor7Rc}yaaHUm*<~E&{3%tggAmx z8M_%>TT00T;BB12IFB8;*V1xR&MDhf7rhlaYDqZ#3=$dc=1u7r`Dp<6~Rt<@NE3i=*QnSgdk?^ZFI2qxbTAk6~$|dczj31^%};m7oC%oO`FDX*KG+p41hD*|>E-69s45!$+t{zz^$rcq zlz?OA#t1@zF8msnH%>~Lpr4IC!a_eiQz823FCSG*(O3tu?} zGG>!DE(#^3V%2@$4r>PL!SqlIxBBLo7CR|#z{cWR}4eMBQ+6V z&OJ_eDO1X3wf3H(*q-rgx4`{-<76ktt*6{>GF^rx9G#o-!Ph4Kh|Ji{ov$Z2a{1AU zSobf4Rz9hN9wD9JG&zIBt5z&mikRq)YIuctX^%_6y1J%$d=xn`SI9?Gn5xy$6mhC; z0^tS_w3Y-VMJn=ft=yKvdvQHTR|Ls1A?3G6q`l^<1_8NU4Yq|6#QL zioN4W&7Wd=-A2s_|+kcG)zyFy32G9Pd z?0*tu|62qD)8J?H&;7r7vj3_4pPl?a%J_do+CSxg_4T^~Ji>o=KK`4<|Ex9Lf1>{d Dgd(L7 literal 0 HcmV?d00001 diff --git a/main.tf b/main.tf index 596eab7..9e0cdad 100644 --- a/main.tf +++ b/main.tf @@ -1,187 +1,35 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 5.0" - } - archive = { - source = "hashicorp/archive" - version = "~> 2.0" - } - } - required_version = ">= 1.2.0" -} - -provider "aws" { - region = var.aws_region -} - -# Create a zip file containing the buildspec -data "archive_file" "buildspec" { - type = "zip" - source_file = "${path.module}/templates/buildspec.yml" - output_path = "${path.module}/buildspec.zip" -} - -# Upload the nested stack templates to S3 -resource "aws_s3_object" "kms_template" { - bucket = var.template_bucket - key = "${var.template_prefix}kms.yml" - source = "${path.module}/templates/kms.yml" - etag = filemd5("${path.module}/templates/kms.yml") - content_type = "application/x-yml" -} - -resource "aws_s3_object" "iam_template" { - bucket = var.template_bucket - key = "${var.template_prefix}iam.yml" - source = "${path.module}/templates/iam.yml" - etag = filemd5("${path.module}/templates/iam.yml") - content_type = "application/x-yml" -} -resource "aws_s3_object" "s3_template" { - bucket = var.template_bucket - key = "${var.template_prefix}s3.yml" - source = "${path.module}/templates/s3.yml" - etag = filemd5("${path.module}/templates/s3.yml") - content_type = "application/x-yml" -} - -resource "aws_s3_object" "codebuild_template" { - bucket = var.template_bucket - key = "${var.template_prefix}codebuild.yml" - source = "${path.module}/templates/codebuild.yml" - etag = filemd5("${path.module}/templates/codebuild.yml") - content_type = "application/x-yml" -} - -resource "aws_s3_object" "codepipeline_template" { - bucket = var.template_bucket - key = "${var.template_prefix}codepipeline.yml" - source = "${path.module}/templates/codepipeline.yml" - etag = filemd5("${path.module}/templates/codepipeline.yml") - content_type = "application/x-yml" -} - -resource "aws_s3_object" "buildspec" { - bucket = "image-pipeline-assets-dev" - key = "buildspec.zip" - source = data.archive_file.buildspec.output_path - etag = filemd5(data.archive_file.buildspec.output_path) - content_type = "application/zip" -} # Generate the main CloudFormation template using templatefile locals { - # Use the GovCloud S3 URL format for us-gov-west-1 region - s3_base_url = var.aws_region == "us-gov-west-1" ? "https://s3-${var.aws_region}.amazonaws.com/${var.template_bucket}/${var.template_prefix}" : "https://${var.template_bucket}.s3.amazonaws.com/${var.template_prefix}" - - template_vars = { - kms_template_url = "${local.s3_base_url}kms.yml" - iam_template_url = "${local.s3_base_url}iam.yml" - s3_template_url = "${local.s3_base_url}s3.yml" - codebuild_template_url = "${local.s3_base_url}codebuild.yml" - codepipeline_template_url = "${local.s3_base_url}codepipeline.yml" - additional_security_group_id = var.additional_security_group_id - } - main_template_content = templatefile("${path.module}/templates/main.yml.tftpl", local.template_vars) -} - -# Upload the processed main CloudFormation template to S3 -resource "aws_s3_object" "main_template" { - bucket = var.template_bucket - key = "${var.template_prefix}main.yml" - content = local.main_template_content - content_type = "application/x-yml" - etag = md5(local.main_template_content) -} - -# CloudFormation stack resource that wraps the existing CloudFormation template -resource "aws_cloudformation_stack" "image_pipeline" { - name = var.stack_name - capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"] - template_url = "${local.s3_base_url}main.yml" - disable_rollback = var.disable_rollback - timeout_in_minutes = var.timeout_in_minutes - - # Ensure the templates are uploaded before creating the stack - depends_on = [ - aws_s3_object.main_template, - aws_s3_object.kms_template, - aws_s3_object.iam_template, - aws_s3_object.s3_template, - aws_s3_object.codebuild_template, - aws_s3_object.codepipeline_template, - aws_s3_object.buildspec + # Use consistent path-style S3 URL format for all regions + # S3 keys for project-specific files (template_prefix already includes project directory) + ansible_config_s3_key = "image-pipeline-ansible-playbooks.zip" + pip_config_s3_key = "image-pipeline-pip-config.zip" + packer_config_s3_key = "image-pipeline-packer.zip" + + # Dynamically generate Service Catalog bucket name and principal ARNs + service_catalog_bucket_name = "csvd-${data.aws_caller_identity.current.account_id}-${var.project_name}-service-catalog-templates" + dynamic_principal_arns = [ + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0", + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0" ] - parameters = { - ProjectName = var.project_name - CreateNewRole = var.create_new_role ? "true" : "false" - SSHUser = var.ssh_user - Troubleshoot = var.troubleshoot ? "true" : "false" - BuilderComputeType = var.builder_compute_type - BuilderImage = var.builder_image - PackerVersion = var.packer_version - AssetsBucketName = var.assets_bucket_name - DockerBuild = var.docker_build ? "true" : "false" - VpcId = var.vpc_id - SubnetIds = join(",", var.subnet_ids) - PackerBucketName = var.packer_bucket_name - PackerBucketKey = var.packer_bucket_key - AnsibleBucketName = var.ansible_bucket_name - AnsibleBucketKey = var.ansible_bucket_key - PipBucketName = var.pip_bucket_name - PipBucketKey = var.pip_bucket_key - PackerFileName = var.packer_file_name - BuildspecBucketName = "image-pipeline-assets-dev" - BuildspecObjectKey = "buildspec.zip" - AdditionalSecurityGroupId = var.additional_security_group_id - } - - tags = var.tags -} - -# Service Catalog Resources (conditionally created) -resource "aws_servicecatalog_portfolio" "image_pipeline" { - count = var.enable_service_catalog ? 1 : 0 - name = var.portfolio_name - description = var.portfolio_description - provider_name = var.portfolio_provider_name - tags = var.tags -} - -resource "aws_servicecatalog_product" "image_pipeline" { - count = var.enable_service_catalog ? 1 : 0 - name = var.product_name - owner = var.product_owner - type = "CLOUD_FORMATION_TEMPLATE" - - description = var.product_description - - provisioning_artifact_parameters { - name = "v1.0" - description = "Initial version of the AWS Image Pipeline" - template_url = "${local.s3_base_url}main.yml" - type = "CLOUD_FORMATION_TEMPLATE" + # Service Catalog S3 base URL for templates + # https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml + service_catalog_s3_base_url = "https://${local.service_catalog_bucket_name}.s3.${var.aws_region}.amazonaws.com/${var.template_prefix}" + + # Template variables for Service Catalog bucket templates (point to dedicated bucket) + # s3://csvd-229685449397-aws-linux-service-catalog-templates/kms.yml + service_catalog_template_vars = { + kms_template_url = "${local.service_catalog_s3_base_url}/kms.yml" + buildspec_template_url = "${local.service_catalog_s3_base_url}/buildspec.yml" + iam_template_url = "${local.service_catalog_s3_base_url}/iam.yml" + s3_template_url = "${local.service_catalog_s3_base_url}/s3.yml" + codebuild_template_url = "${local.service_catalog_s3_base_url}/codebuild.yml" + codepipeline_template_url = "${local.service_catalog_s3_base_url}/codepipeline.yml" + main_template_url = "${local.service_catalog_s3_base_url}/main.yml" + additional_security_group_id = var.additional_security_group_id } - - # Ensure the main template is uploaded before creating the product - depends_on = [aws_s3_object.main_template] - - tags = var.tags -} - -resource "aws_servicecatalog_product_portfolio_association" "image_pipeline" { - count = var.enable_service_catalog ? 1 : 0 - portfolio_id = aws_servicecatalog_portfolio.image_pipeline[0].id - product_id = aws_servicecatalog_product.image_pipeline[0].id + main_template_content = templatefile("${path.module}/templates/main.yaml.tftpl", local.service_catalog_template_vars) } - -resource "aws_servicecatalog_principal_portfolio_association" "image_pipeline" { - count = var.enable_service_catalog ? length(var.principal_arns) : 0 - portfolio_id = aws_servicecatalog_portfolio.image_pipeline[0].id - principal_arn = var.principal_arns[count.index] - principal_type = "IAM" -} \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index fdb7671..eac099c 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,75 +1,139 @@ +# CloudFormation Stack Outputs +output "stack_id" { + description = "ID of the CloudFormation stack" + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].id : null +} + +output "stack_outputs" { + description = "A map of outputs from the CloudFormation stack" + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs : {} +} + +output "template_url" { + description = "URL of the main CloudFormation template in S3" + value = "${local.service_catalog_s3_base_url}/main.yml" +} + output "code_pipeline_name" { description = "Name of the created CodePipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["CodePipelineName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["CodePipelineName"] : null } output "code_pipeline_arn" { description = "ARN of the created CodePipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["CodePipelineArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["CodePipelineArn"] : null } output "artifact_bucket_name" { description = "Name of the S3 bucket storing pipeline artifacts" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ArtifactBucketName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ArtifactBucketName"] : null } output "artifact_bucket_arn" { description = "ARN of the S3 bucket storing pipeline artifacts" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ArtifactBucketArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ArtifactBucketArn"] : null } output "kms_key_arn" { description = "ARN of the KMS key used for encryption" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["KMSKeyArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["KMSKeyArn"] : null } output "iam_role_arn" { description = "ARN of the CodePipeline IAM role" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["IamArn"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["IamArn"] : null } output "role_name" { description = "Name of the CodePipeline IAM role" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["RoleName"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["RoleName"] : null } output "security_group_id" { description = "ID of the security group used by CodeBuild" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["SecurityGroupId"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["SecurityGroupId"] : null } output "managed_parameters_path" { description = "Base path for SSM parameters managed by this pipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["ManagedParameters"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["ManagedParameters"] : null } output "secrets_path" { description = "Base path for Secrets Manager secrets managed by this pipeline" - value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline.outputs["SecretsPath"] : null + value = var.deploy_stack ? aws_cloudformation_stack.image_pipeline[0].outputs["SecretsPath"] : null } -# Service Catalog Outputs +# Service Catalog Outputs (when enabled) output "service_catalog_portfolio_id" { - description = "ID of the Service Catalog portfolio" - value = var.enable_service_catalog ? aws_servicecatalog_portfolio.image_pipeline[0].id : null + description = "ID of the Service Catalog portfolio (if Service Catalog is enabled)" + value = module.service_catalog.portfolio_id } output "service_catalog_portfolio_arn" { - description = "ARN of the Service Catalog portfolio" - value = var.enable_service_catalog ? aws_servicecatalog_portfolio.image_pipeline[0].arn : null + description = "ARN of the Service Catalog portfolio (if Service Catalog is enabled)" + value = module.service_catalog.portfolio_arn } output "service_catalog_product_id" { - description = "ID of the Service Catalog product" - value = var.enable_service_catalog ? aws_servicecatalog_product.image_pipeline[0].id : null + description = "ID of the Service Catalog product (if Service Catalog is enabled)" + value = module.service_catalog.product_id } output "service_catalog_product_arn" { - description = "ARN of the Service Catalog product" - value = var.enable_service_catalog ? aws_servicecatalog_product.image_pipeline[0].arn : null + description = "ARN of the Service Catalog product (if Service Catalog is enabled)" + value = module.service_catalog.product_arn +} + +output "service_catalog_launch_role_arn" { + description = "ARN of the IAM role used for Service Catalog launch constraint (if enabled)" + value = module.service_catalog.launch_role_arn +} + +output "service_catalog_launch_constraint_id" { + description = "ID of the Service Catalog launch constraint (if enabled)" + value = module.service_catalog.launch_constraint_id +} + +output "service_catalog_launch_role_name" { + description = "Name of the IAM role used for Service Catalog launch constraint (if enabled and created)" + value = module.service_catalog.launch_role_name +} + +output "service_catalog_current_user_arn" { + description = "ARN of the current authenticated user that was automatically granted access (if Service Catalog is enabled)" + value = module.service_catalog.current_user_arn +} + +output "service_catalog_all_principals" { + description = "List of all principal ARNs with access to the Service Catalog portfolio (if enabled)" + value = module.service_catalog.principal_associations +} + +output "service_catalog_principal_count" { + description = "Total number of principals with access to the Service Catalog portfolio (if enabled)" + value = module.service_catalog.principal_association_count +} + +output "template_prefix" { + description = "Prefix/folder path for CloudFormation templates in S3" + value = var.template_prefix +} + +output "uploaded_templates" { + description = "List of uploaded template files" + value = [ + aws_s3_object.main_template.key, + aws_s3_object.kms_template.key, + aws_s3_object.iam_template.key, + aws_s3_object.s3_template.key, + aws_s3_object.codebuild_template.key, + aws_s3_object.codepipeline_template.key + ] } -output "service_catalog_template_url" { - description = "URL of the CloudFormation template used by Service Catalog" - value = var.enable_service_catalog ? "${local.s3_base_url}main.yml" : null +# Buildspec Information +output "buildspec_location" { + description = "Location of the buildspec file in S3" + value = "s3://${local.service_catalog_bucket_name}/${var.template_prefix}/buildspec.yml" } \ No newline at end of file diff --git a/pip_config.zip b/pip_config.zip new file mode 100644 index 0000000000000000000000000000000000000000..dce7735e4ad70c41693bbd15fddebb9b236c17a1 GIT binary patch literal 1428 zcmV;F1#9|HO9KQH00;mG0000XiU0rr000000000001W^D0Ah7%Y-DqAWn(URZEUnw zQB&Kv6MxUA*vUWBw4JeCn*Mup%;dohZtDY*OdROklPcr|tFbL1$v_TrpZ!L*`Jq?>imLul73tS5$F&mZG*l0Heu4K%&`*9E7ud=(^of z8bx2pbQYfa^MD)%zmw15QD9F!trN1qr7JP(b~-Ylx&q?4HZ)BuOjYEDXXw=YH4}hb zn#8&@aQF5~5ffQP^SDv?A4F&h36e`-B0uLBg`$Rw9L|-j)XrwS900NnS^fd*2enjBs@A;2TUSSC}#0SCEKJhvM?)8a_L(BZjI9j z;O-8PB?7vQBo_wGMUltA^Twg>KVWtkDpMvHJT&Z{$nxtV7XJZk6V^uhOlXzG^ub-# zwSY0`f-%(kyhzh!D<#xCp4YK}Mp$yM?V1t^D|k?NS#X6hNXi!U0(C=hop6>|n1RJ* zg-RhYM(TafI}^faqo{P{Qc{--?*ffu8RZfj0h_-^(5f09K-dP}T9cN0?hh?; z=-Rf~_q@H2zq;@L|H0k+<(>Q9djV75*2emkK+tGF;e~xHdKPOId$1Z=mH8ks`V^0jd^ zDo+}QXYpIkM!{$n%v(MWUkdt|)7nmIV#EUT#^HJS_Z;FqH=`(=jLCd*7>tL13x>t; z_&i&Wu}WioxY}xz2#v9wW|xVAoBj6v05FTt1&ydEJ_+?CzoiE|;9HfI=HTcjI?S&&gLR`Rk)po0lvR?L zD`ZBfrQHZ?o6TmpDWvx3pR^#*<`E#R{#J2|Nl@+2MA1nP{RlX0018j z002-+0Rj{Q6aWYS2mk;8A&N|ZP{RlX0018j000dD0000000000006Xs00000Vs&Y3 iWOHz3V=j4ZY*0%D1^@s60096206PEx07C@;00023=AmQ& literal 0 HcmV?d00001 diff --git a/providers.tf b/providers.tf new file mode 100644 index 0000000..81c1901 --- /dev/null +++ b/providers.tf @@ -0,0 +1,17 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 6.0" + } + archive = { + source = "hashicorp/archive" + version = "~> 2.0" + } + } + required_version = ">= 1.2.0" +} + +provider "aws" { + region = var.aws_region +} diff --git a/s3.tf b/s3.tf new file mode 100644 index 0000000..1b8c49f --- /dev/null +++ b/s3.tf @@ -0,0 +1,123 @@ +resource "aws_s3_bucket" "service_catalog" { + bucket = local.service_catalog_bucket_name + + tags = merge(var.tags, { + Name = "${var.project_name}-service-catalog-templates" + Project = var.project_name + }) +} + +resource "aws_s3_bucket_policy" "service_catalog" { + bucket = aws_s3_bucket.service_catalog.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowServiceCatalogAccess" + Effect = "Allow" + Principal = { + Service = [ + "servicecatalog.amazonaws.com", + "cloudformation.amazonaws.com" + ] + } + Action = [ + "s3:*" + ] + Resource = [ + aws_s3_bucket.service_catalog.arn, + "${aws_s3_bucket.service_catalog.arn}/*" + ] + } + ] + }) +} + +# Upload the nested stack templates to S3 (use bucket's default encryption) +resource "aws_s3_object" "kms_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/kms.yml" + source = "${path.module}/templates/kms.yml" + etag = filemd5("${path.module}/templates/kms.yml") + content_type = "application/x-yml" + # Use bucket's default KMS encryption + depends_on = [aws_s3_bucket.service_catalog] +} + +resource "aws_s3_object" "iam_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/iam.yml" + source = "${path.module}/templates/iam.yml" + etag = filemd5("${path.module}/templates/iam.yml") + content_type = "application/x-yml" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +resource "aws_s3_object" "s3_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/s3.yml" + source = "${path.module}/templates/s3.yml" + etag = filemd5("${path.module}/templates/s3.yml") + content_type = "application/x-yml" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +resource "aws_s3_object" "codebuild_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/codebuild.yml" + source = "${path.module}/templates/codebuild.yml" + etag = filemd5("${path.module}/templates/codebuild.yml") + content_type = "application/x-yml" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +resource "aws_s3_object" "codepipeline_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/codepipeline.yml" + source = "${path.module}/templates/codepipeline.yml" + etag = filemd5("${path.module}/templates/codepipeline.yml") + content_type = "application/x-yml" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +# Upload project-specific files to project directory in template bucket (use bucket's default encryption) +resource "aws_s3_object" "buildspec" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/buildspec.yml" + source = "${path.module}/templates/buildspec.yml" + etag = filemd5("${path.module}/templates/buildspec.yml") + content_type = "application/x-yml" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +# Upload the existing packer config zip file to project directory (keep default encryption) +resource "aws_s3_object" "packer_config" { + bucket = local.service_catalog_bucket_name + key = local.packer_config_s3_key + source = "${path.module}/packer_config.zip" + etag = filemd5("${path.module}/packer_config.zip") + content_type = "application/zip" + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption +} + +# Upload the processed main CloudFormation template to S3 (use bucket's default encryption) +resource "aws_s3_object" "main_template" { + bucket = local.service_catalog_bucket_name + key = "${var.template_prefix}/main.yml" + content = local.main_template_content + content_type = "application/x-yml" + etag = md5(local.main_template_content) + depends_on = [aws_s3_bucket.service_catalog] + # Use bucket's default KMS encryption + provisioner "local-exec" { + command = "echo 'Uploaded main CloudFormation template to s3://${local.service_catalog_bucket_name}/${var.template_prefix}/main.yml'" + } +} + diff --git a/scripts/add_service_catalog_permissions.sh b/scripts/add_service_catalog_permissions.sh new file mode 100644 index 0000000..29c882b --- /dev/null +++ b/scripts/add_service_catalog_permissions.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# Script to add supplemental permissions to the Service Catalog launch role +# This script should be run after terraform apply + +# Configuration +ROLE_NAME="aws-linux-service-catalog-launch-role" +POLICY_NAME="ServiceCatalogSupplementalPermissions" + +# Create the policy document +cat > supplemental-policy.json << 'EOL' +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "CodeBuildExecution", + "Effect": "Allow", + "Action": [ + "codebuild:StartBuild", + "codebuild:StopBuild", + "codebuild:ListBuildsForProject", + "codebuild:BatchGetBuilds" + ], + "Resource": "*" + }, + { + "Sid": "CodePipelineExecution", + "Effect": "Allow", + "Action": [ + "codepipeline:StartPipelineExecution", + "codepipeline:StopPipelineExecution", + "codepipeline:ListPipelineExecutions", + "codepipeline:PutApprovalResult" + ], + "Resource": "*" + }, + { + "Sid": "EC2ImageManagement", + "Effect": "Allow", + "Action": [ + "ec2:CreateTags", + "ec2:DeleteTags", + "ec2:DescribeTags", + "ec2:DescribeImages", + "ec2:DescribeInstances", + "ec2:RunInstances", + "ec2:TerminateInstances", + "ec2:CreateImage", + "ec2:DeregisterImage" + ], + "Resource": "*" + }, + { + "Sid": "SSMParameterAccess", + "Effect": "Allow", + "Action": [ + "ssm:GetParameter", + "ssm:GetParameters", + "ssm:DescribeParameters", + "ssm:PutParameter" + ], + "Resource": "*" + } + ] +} +EOL + +echo "Creating IAM policy $POLICY_NAME..." +POLICY_ARN=$(aws iam create-policy --policy-name $POLICY_NAME --policy-document file://supplemental-policy.json --query 'Policy.Arn' --output text) + +if [ $? -ne 0 ]; then + echo "Error creating policy. The policy might already exist." + # Try to get the policy ARN + POLICY_ARN=$(aws iam list-policies --query "Policies[?PolicyName=='$POLICY_NAME'].Arn" --output text) + + if [ -z "$POLICY_ARN" ]; then + echo "Could not find or create the policy. Exiting." + exit 1 + fi +fi + +echo "Attaching policy $POLICY_ARN to role $ROLE_NAME..." +aws iam attach-role-policy --role-name $ROLE_NAME --policy-arn $POLICY_ARN + +if [ $? -eq 0 ]; then + echo "Successfully attached policy to role." +else + echo "Failed to attach policy to role. Please check if the role exists." + exit 1 +fi + +# Clean up +rm -f supplemental-policy.json + +echo "Supplemental permissions have been added to the Service Catalog launch role." \ No newline at end of file diff --git a/scripts/aws_credentials.py b/scripts/aws_credentials.py new file mode 100755 index 0000000..98ad57a --- /dev/null +++ b/scripts/aws_credentials.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +AWS Credentials Checker +Verifies AWS credentials and region settings +""" + +import argparse +import os +import sys +import json +import subprocess +import boto3 + +def check_aws_region(): + """Check if AWS region is properly configured""" + region = os.environ.get('AWS_REGION') + if not region: + try: + # Try to get region from AWS CLI config + result = subprocess.run(['aws', 'configure', 'get', 'region'], + capture_output=True, text=True, check=False) + region = result.stdout.strip() + except Exception: + pass + + if not region: + print("❌ AWS region not configured") + print(" Please set AWS_REGION environment variable or configure AWS CLI") + print(" Example: export AWS_REGION=us-gov-west-1") + sys.exit(1) + + print(f"Using AWS region: {region}") + return region + +def verify_aws_credentials(region): + """Verify AWS credentials are valid""" + try: + # Try to get caller identity to verify credentials + sts = boto3.client('sts', region_name=region) + identity = sts.get_caller_identity() + print("✅ AWS credentials verified") + return identity + except Exception as e: + print("❌ AWS credentials not configured or expired") + print(f" Error: {str(e)}") + print(" Please run 'source ~/aws-creds' or configure AWS CLI") + sys.exit(1) + +def main(): + """Main function""" + parser = argparse.ArgumentParser(description='Check AWS credentials and region') + parser.add_argument('--verbose', action='store_true', help='Show detailed identity information') + args = parser.parse_args() + + print("Checking AWS credentials and region...") + region = check_aws_region() + identity = verify_aws_credentials(region) + + if args.verbose: + print("\nCurrent AWS identity:") + print(f"Account: {identity['Account']}") + print(f"ARN: {identity['Arn']}") + print(f"User ID: {identity['UserId']}") + + return 0 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/scripts/clean_buckets.py b/scripts/clean_buckets.py new file mode 100644 index 0000000..dce0e0c --- /dev/null +++ b/scripts/clean_buckets.py @@ -0,0 +1,32 @@ +import boto3 + +client = boto3.client('s3') + +buckets = client.list_buckets().get('Buckets', []) +for bucket_info in buckets: + bucket_name = bucket_info['Name'] + if bucket_name.startswith('aws-linux'): + print(f"Processing bucket: {bucket_name}") + try: + # If versioning is enabled, delete all versions + bucket_versioning = client.get_bucket_versioning(Bucket=bucket_name) + if bucket_versioning.get('Status') == 'Enabled': + paginator = client.get_paginator('list_object_versions') + for page in paginator.paginate(Bucket=bucket_name): + for version in page.get('Versions', []) + page.get('DeleteMarkers', []): + client.delete_object( + Bucket=bucket_name, + Key=version['Key'], + VersionId=version['VersionId'] + ) + else: + # Delete all objects (non-versioned) + paginator = client.get_paginator('list_objects_v2') + for page in paginator.paginate(Bucket=bucket_name): + for obj in page.get('Contents', []) or []: + client.delete_object(Bucket=bucket_name, Key=obj['Key']) + # Delete the bucket + client.delete_bucket(Bucket=bucket_name) + print(f"Deleted bucket: {bucket_name}") + except Exception as e: + print(f"Error deleting bucket {bucket_name}: {e}") \ No newline at end of file diff --git a/scripts/cloudformation_tester.py b/scripts/cloudformation_tester.py new file mode 100755 index 0000000..ad6f473 --- /dev/null +++ b/scripts/cloudformation_tester.py @@ -0,0 +1,322 @@ +#!/usr/bin/env python3 +""" +CloudFormation Tester +Tests and validates CloudFormation templates and S3 access for nested stacks +""" + +import argparse +import json +import sys +import time +import boto3 +from botocore.exceptions import ClientError + +def get_terraform_output(output_name): + """Get Terraform output value by name""" + try: + import subprocess + result = subprocess.run(['tf', 'output', '-raw', output_name], + capture_output=True, text=True, check=False) + if result.returncode != 0: + print(f"❌ Could not get {output_name} from Terraform state") + if result.stderr: + print(f" Error: {result.stderr.strip()}") + return None + return result.stdout.strip() + except Exception as e: + print(f"❌ Error getting Terraform output '{output_name}': {str(e)}") + return None + +def test_cf_s3_access(s3_client, template_bucket, template_prefix, region): + """Test S3 access for CloudFormation nested templates""" + print("🧪 Testing CloudFormation S3 access for nested templates...") + + bucket_ok = False + try: + s3_client.list_objects_v2(Bucket=template_bucket, MaxKeys=1) + print(f"✅ Current user can list S3 bucket: {template_bucket}") + bucket_ok = True + except Exception as e: + print(f"❌ Current user cannot list S3 bucket: {template_bucket}") + print(f" Error: {str(e)}") + + if not bucket_ok: + return False + + # Test accessing the template prefix directory + prefix_ok = False + try: + response = s3_client.list_objects_v2( + Bucket=template_bucket, + Prefix=template_prefix, + MaxKeys=10 + ) + + if 'Contents' in response and len(response['Contents']) > 0: + print(f"✅ Templates found in S3 prefix: {template_prefix}") + prefix_ok = True + + # Print the templates that were found + print("\nTemplates found:") + for obj in response['Contents']: + print(f" - {obj['Key']}") + else: + print(f"❌ No templates found in S3 prefix: {template_prefix}") + except Exception as e: + print(f"❌ Error listing S3 prefix: {template_prefix}") + print(f" Error: {str(e)}") + + if not prefix_ok: + return False + + # Test individual nested template access + templates = ["kms.yml", "iam.yml", "s3.yml", "codebuild.yml", "codepipeline.yml"] + print("\nTesting individual nested template access:") + all_templates_ok = True + + for template in templates: + template_key = f"{template_prefix}{template}" + try: + s3_client.head_object(Bucket=template_bucket, Key=template_key) + print(f" ✅ {template_key}: Accessible") + except Exception as e: + print(f" ❌ {template_key}: Access denied") + print(f" Error: {str(e)}") + all_templates_ok = False + + # Test CloudFormation template validation + print("\nTesting CloudFormation template validation...") + try: + cf_client = boto3.client('cloudformation', region_name=region) + + # Construct the template URL based on region + if region == "us-gov-west-1": + template_url = f"https://s3-{region}.amazonaws.com/{template_bucket}/{template_prefix}main.yml" + else: + template_url = f"https://{template_bucket}.s3.amazonaws.com/{template_prefix}main.yml" + + print(f"Main template URL: {template_url}") + + # Validate the template + cf_client.validate_template(TemplateURL=template_url) + print("✅ CloudFormation template validation successful") + except Exception as e: + print("❌ CloudFormation template validation failed") + print(f" Error: {str(e)}") + all_templates_ok = False + + return all_templates_ok + +def test_cf_direct(cf_client, template_bucket, template_prefix, region, vpc_id, subnet_id, stack_name=None): + """Test direct CloudFormation stack creation (bypassing Service Catalog)""" + print("🧪 Testing direct CloudFormation stack creation (bypassing Service Catalog)...") + + # Generate a stack name if not provided + if not stack_name: + import datetime + timestamp = datetime.datetime.now().strftime("%H%M%S") + stack_name = f"direct-test-{timestamp}" + + # Construct template URL based on region + if region == "us-gov-west-1": + template_url = f"https://s3-{region}.amazonaws.com/{template_bucket}/{template_prefix}main.yml" + else: + template_url = f"https://{template_bucket}.s3.amazonaws.com/{template_prefix}main.yml" + + print(f"Template URL: {template_url}") + print(f"Test stack name: {stack_name}") + + # Create CloudFormation stack + try: + response = cf_client.create_stack( + StackName=stack_name, + TemplateURL=template_url, + Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'], + OnFailure='DELETE', + Parameters=[ + {'ParameterKey': 'ProjectName', 'ParameterValue': 'direct-test'}, + {'ParameterKey': 'CreateNewRole', 'ParameterValue': 'true'}, + {'ParameterKey': 'SSHUser', 'ParameterValue': 'ec2-user'}, + {'ParameterKey': 'Troubleshoot', 'ParameterValue': 'false'}, + {'ParameterKey': 'BuilderComputeType', 'ParameterValue': 'BUILD_GENERAL1_MEDIUM'}, + {'ParameterKey': 'BuilderImage', 'ParameterValue': 'aws/codebuild/amazonlinux2-x86_64-standard:3.0'}, + {'ParameterKey': 'PackerVersion', 'ParameterValue': '1.7.8'}, + {'ParameterKey': 'AssetsBucketName', 'ParameterValue': 'image-pipeline-assets-dev'}, + {'ParameterKey': 'DockerBuild', 'ParameterValue': 'false'}, + {'ParameterKey': 'VpcId', 'ParameterValue': vpc_id}, + {'ParameterKey': 'SubnetIds', 'ParameterValue': subnet_id}, + {'ParameterKey': 'PackerBucketName', 'ParameterValue': 'image-pipeline-assets-dev'}, + {'ParameterKey': 'PackerBucketKey', 'ParameterValue': 'packer-config.zip'}, + {'ParameterKey': 'AnsibleBucketName', 'ParameterValue': 'image-pipeline-assets-dev'}, + {'ParameterKey': 'AnsibleBucketKey', 'ParameterValue': 'ansible-config.zip'}, + {'ParameterKey': 'PipBucketName', 'ParameterValue': 'image-pipeline-assets-dev'}, + {'ParameterKey': 'PipBucketKey', 'ParameterValue': 'pip-config.zip'}, + {'ParameterKey': 'PackerFileName', 'ParameterValue': 'build.pkr.hcl'}, + {'ParameterKey': 'BuildspecBucketName', 'ParameterValue': 'image-pipeline-assets-dev'}, + {'ParameterKey': 'BuildspecObjectKey', 'ParameterValue': 'buildspec.yml'} + ] + ) + print(f"✅ Direct CloudFormation stack creation started: {stack_name}") + print(f" Stack ID: {response['StackId']}") + print("\nCheck stack events with:") + print(f"aws cloudformation describe-stack-events --stack-name {stack_name} --region {region}") + return True + except Exception as e: + print("❌ Direct CloudFormation creation failed") + print(f" Error: {str(e)}") + return False + +def check_template_files(s3_client, template_bucket, template_prefix, files_to_check): + """Check if required template files exist in S3""" + print("🔍 Checking for required template files in S3...") + + all_files_exist = True + + for file_key in files_to_check: + full_key = f"{template_prefix}{file_key}" + try: + s3_client.head_object(Bucket=template_bucket, Key=full_key) + print(f"✅ {full_key}: Found") + except Exception as e: + print(f"❌ {full_key}: Not found") + print(f" Error: {str(e)}") + all_files_exist = False + + return all_files_exist + +def upload_missing_files(s3_client, template_bucket, template_prefix, local_dir, files_to_upload): + """Upload missing template files to S3""" + print("📤 Uploading missing files to S3...") + + all_uploads_ok = True + + for file_name in files_to_upload: + local_path = f"{local_dir}/{file_name}" + s3_key = f"{template_prefix}{file_name}" + + try: + with open(local_path, 'rb') as f: + print(f"Uploading {local_path} to s3://{template_bucket}/{s3_key}...") + s3_client.upload_fileobj(f, template_bucket, s3_key) + print(f"✅ {file_name}: Uploaded successfully") + except FileNotFoundError: + print(f"❌ {file_name}: Local file not found at {local_path}") + all_uploads_ok = False + except Exception as e: + print(f"❌ {file_name}: Upload failed") + print(f" Error: {str(e)}") + all_uploads_ok = False + + return all_uploads_ok + +def main(): + """Main function""" + parser = argparse.ArgumentParser(description='CloudFormation Tester') + parser.add_argument('--region', help='AWS region') + parser.add_argument('--test-s3-access', action='store_true', + help='Test S3 access for CloudFormation templates') + parser.add_argument('--test-direct', action='store_true', + help='Test direct CloudFormation stack creation') + parser.add_argument('--check-files', action='store_true', + help='Check required files in S3') + parser.add_argument('--upload-files', action='store_true', + help='Upload missing files to S3') + parser.add_argument('--bucket', help='S3 bucket name (defaults to Terraform output)') + parser.add_argument('--prefix', help='S3 prefix/directory (defaults to Terraform output)') + parser.add_argument('--vpc-id', help='VPC ID for testing') + parser.add_argument('--subnet-id', help='Subnet ID for testing') + parser.add_argument('--stack-name', help='Optional stack name for direct testing') + args = parser.parse_args() + + # Get region from args or environment + region = args.region + if not region: + import os + region = os.environ.get('AWS_REGION') + if not region: + try: + import subprocess + result = subprocess.run(['aws', 'configure', 'get', 'region'], + capture_output=True, text=True, check=False) + region = result.stdout.strip() + except Exception: + pass + + if not region: + print("❌ AWS region not specified") + print(" Please set --region argument or AWS_REGION environment variable") + return 1 + + # Create AWS clients + try: + s3_client = boto3.client('s3', region_name=region) + cf_client = boto3.client('cloudformation', region_name=region) + except Exception as e: + print(f"❌ Failed to create AWS clients: {str(e)}") + return 1 + + # Get bucket and prefix from args or Terraform output + template_bucket = args.bucket + if not template_bucket: + template_bucket = get_terraform_output('template_bucket') + if not template_bucket: + print("❌ S3 bucket name not specified and not found in Terraform state") + return 1 + + template_prefix = args.prefix + if not template_prefix: + template_prefix = get_terraform_output('template_prefix') + if not template_prefix: + print("❌ S3 prefix not specified and not found in Terraform state") + return 1 + + print(f"S3 Bucket: {template_bucket}") + print(f"S3 Prefix: {template_prefix}") + + # Execute requested operation(s) + if args.test_s3_access: + if not test_cf_s3_access(s3_client, template_bucket, template_prefix, region): + return 1 + + if args.test_direct: + vpc_id = args.vpc_id or "vpc-12345" # Use a default if not provided + subnet_id = args.subnet_id or "subnet-12345" # Use a default if not provided + if not test_cf_direct(cf_client, template_bucket, template_prefix, region, vpc_id, subnet_id, args.stack_name): + return 1 + + if args.check_files: + files_to_check = [ + "main.yml", + "kms.yml", + "iam.yml", + "s3.yml", + "codebuild.yml", + "codepipeline.yml", + "buildspec.yml", + "packer-config.zip" + ] + if not check_template_files(s3_client, template_bucket, template_prefix, files_to_check): + return 1 + + if args.upload_files: + files_to_upload = [ + "main.yml", + "kms.yml", + "iam.yml", + "s3.yml", + "codebuild.yml", + "codepipeline.yml", + "buildspec.yml" + ] + if not upload_missing_files(s3_client, template_bucket, template_prefix, "./templates", files_to_upload): + return 1 + + # If no operation specified, show usage + if not any([args.test_s3_access, args.test_direct, args.check_files, args.upload_files]): + parser.print_help() + return 1 + + return 0 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/scripts/launch_service_catalog_product.py b/scripts/launch_service_catalog_product.py new file mode 100644 index 0000000..e685b24 --- /dev/null +++ b/scripts/launch_service_catalog_product.py @@ -0,0 +1,475 @@ +#!/usr/bin/env python3 +""" +Service Catalog Product Launch Script + +This script launches a Service Catalog product and provides detailed error reporting. +It can auto-discover resources from Terraform state or accept manual configuration. +""" + +import argparse +import json +import subprocess +import sys +import time +from datetime import datetime +from pathlib import Path +from typing import Dict, Optional, Tuple + +import boto3 +from botocore.exceptions import ClientError, NoCredentialsError + +# Color codes for terminal output +class Colors: + RED = '\033[0;31m' + GREEN = '\033[0;32m' + YELLOW = '\033[0;33m' + BLUE = '\033[0;34m' + NC = '\033[0m' # No Color + + +class ServiceCatalogLauncher: + """Class to handle Service Catalog product launches with detailed error reporting.""" + + def __init__(self, region: str, verbose: bool = False): + self.region = region + self.verbose = verbose + self.session = boto3.Session(region_name=region) + self.servicecatalog = self.session.client('servicecatalog') + self.cloudformation = self.session.client('cloudformation') + + def print_status(self, message: str): + """Print status message in blue.""" + print(f"{Colors.BLUE}[INFO]{Colors.NC} {message}") + + def print_success(self, message: str): + """Print success message in green.""" + print(f"{Colors.GREEN}[SUCCESS]{Colors.NC} {message}") + + def print_warning(self, message: str): + """Print warning message in yellow.""" + print(f"{Colors.YELLOW}[WARNING]{Colors.NC} {message}") + + def print_error(self, message: str): + """Print error message in red.""" + print(f"{Colors.RED}[ERROR]{Colors.NC} {message}") + + def get_terraform_output(self, output_name: str) -> Optional[str]: + """Get Terraform output value.""" + try: + result = subprocess.run( + ['tf', 'output', '-raw', output_name], + capture_output=True, + text=True, + check=False + ) + if result.returncode == 0: + return result.stdout.strip() + return None + except (subprocess.SubprocessError, FileNotFoundError): + return None + + def auto_discover_resources(self) -> Tuple[Optional[str], Optional[str]]: + """Auto-discover Service Catalog resources from Terraform state.""" + self.print_status("Auto-discovering Service Catalog resources from Terraform state...") + + if not Path("terraform.tfstate").exists(): + self.print_error("terraform.tfstate not found. Please run terraform apply first or provide IDs manually.") + return None, None + + portfolio_id = self.get_terraform_output("service_catalog_portfolio_id") + product_id = self.get_terraform_output("service_catalog_product_id") + + if portfolio_id and product_id: + self.print_success(f"Discovered Portfolio ID: {portfolio_id}") + self.print_success(f"Discovered Product ID: {product_id}") + return portfolio_id, product_id + else: + self.print_warning("Could not find Service Catalog resources in Terraform state") + return None, None + + def get_latest_artifact(self, product_id: str) -> Optional[str]: + """Get the latest provisioning artifact for a product.""" + try: + self.print_status(f"Finding latest provisioning artifact for product {product_id}...") + + response = self.servicecatalog.describe_product(Id=product_id) + artifacts = response.get('ProvisioningArtifacts', []) + + if not artifacts: + self.print_error("No provisioning artifacts found for this product") + return None + + # Get the first (latest) artifact + latest_artifact = artifacts[0] + artifact_id = latest_artifact['Id'] + artifact_name = latest_artifact.get('Name', 'Unknown') + + self.print_success(f"Found artifact: {artifact_name} ({artifact_id})") + return artifact_id + + except ClientError as e: + self.print_error(f"Failed to get provisioning artifact: {e}") + return None + + def verify_access(self, portfolio_id: str, product_id: str) -> bool: + """Verify access to Service Catalog resources.""" + try: + # Verify portfolio access + self.print_status("Verifying Service Catalog access...") + self.servicecatalog.describe_portfolio(Id=portfolio_id) + self.print_success("Portfolio access verified") + + # Verify product access + self.servicecatalog.describe_product(Id=product_id) + self.print_success("Product access verified") + + # Check launch paths + launch_paths = self.servicecatalog.list_launch_paths(ProductId=product_id) + if not launch_paths.get('LaunchPathSummaries'): + self.print_warning("No launch paths available for this product") + return False + + # Check constraints + constraints = self.servicecatalog.list_constraints_for_portfolio(PortfolioId=portfolio_id) + launch_constraints = [c for c in constraints.get('ConstraintDetails', []) if c.get('Type') == 'LAUNCH'] + + if launch_constraints: + self.print_success(f"Found {len(launch_constraints)} launch constraint(s)") + if self.verbose: + for constraint in launch_constraints: + self.print_status(f" Constraint: {constraint.get('Description', 'No description')}") + else: + self.print_warning("No launch constraints found - this may cause permission issues") + + return True + + except ClientError as e: + error_code = e.response['Error']['Code'] + if error_code == 'AccessDeniedException': + self.print_error("Access denied. Please check your IAM permissions for Service Catalog.") + else: + self.print_error(f"Failed to verify access: {e}") + return False + + def get_launch_parameters(self, product_id: str, artifact_id: str) -> Dict: + """Get available launch parameters for the product.""" + try: + response = self.servicecatalog.describe_provisioning_parameters( + ProductId=product_id, + ProvisioningArtifactId=artifact_id + ) + + parameters = response.get('ProvisioningArtifactParameters', []) + if self.verbose and parameters: + self.print_status("Available parameters:") + for param in parameters: + param_info = f" {param['ParameterKey']}" + if param.get('DefaultValue'): + param_info += f" (default: {param['DefaultValue']})" + if param.get('Description'): + param_info += f" - {param['Description']}" + print(param_info) + + return {param['ParameterKey']: param for param in parameters} + + except ClientError as e: + self.print_error(f"Failed to get launch parameters: {e}") + return {} + + def launch_product(self, product_id: str, artifact_id: str, stack_name: str, + parameters: Dict[str, str]) -> Optional[str]: + """Launch the Service Catalog product.""" + try: + # Generate unique provisioned product name + timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") + provisioned_product_name = f"{stack_name}-{timestamp}" + + self.print_status("Launching Service Catalog product...") + self.print_status(f"Product ID: {product_id}") + self.print_status(f"Artifact ID: {artifact_id}") + self.print_status(f"Provisioned Product Name: {provisioned_product_name}") + + # Convert parameters to the required format + provisioning_parameters = [ + {'Key': key, 'Value': value} + for key, value in parameters.items() + ] + + if self.verbose and provisioning_parameters: + self.print_status("Parameters:") + for param in provisioning_parameters: + print(f" {param['Key']}: {param['Value']}") + + # Launch the product + response = self.servicecatalog.provision_product( + ProductId=product_id, + ProvisioningArtifactId=artifact_id, + ProvisionedProductName=provisioned_product_name, + ProvisioningParameters=provisioning_parameters + ) + + record_id = response['RecordDetail']['RecordId'] + self.print_success(f"Product launch initiated. Record ID: {record_id}") + + return record_id + + except ClientError as e: + self.print_error(f"Failed to launch Service Catalog product: {e}") + + # Try to provide more specific error information + error_code = e.response['Error']['Code'] + error_message = e.response['Error']['Message'] + + if 'S3' in error_message: + self.print_error("This appears to be an S3 access issue.") + self.print_error("Check that the Service Catalog launch role has proper S3 permissions.") + elif 'cloudformation:GetTemplateSummary' in error_message: + self.print_error("Missing CloudFormation permissions.") + self.print_error("The launch role needs cloudformation:GetTemplateSummary permission.") + elif error_code == 'InvalidParametersException': + self.print_error("Invalid parameters provided.") + self.print_error("Use --verbose to see available parameters.") + + return None + + def monitor_provisioning(self, record_id: str) -> bool: + """Monitor the provisioning process and return success status.""" + self.print_status("Monitoring provisioning progress...") + + while True: + try: + response = self.servicecatalog.describe_record(Id=record_id) + record_detail = response['RecordDetail'] + + status = record_detail['Status'] + updated_time = record_detail['UpdatedTime'].strftime("%Y-%m-%d %H:%M:%S") + + self.print_status(f"Status: {status} (Updated: {updated_time})") + + if status == 'SUCCEEDED': + self.print_success("Product provisioning completed successfully!") + + # Show outputs if available + outputs = record_detail.get('RecordOutputs', []) + if outputs: + self.print_status("Outputs:") + for output in outputs: + print(f" {output['OutputKey']}: {output['OutputValue']}") + + return True + + elif status == 'FAILED': + self.print_error("Product provisioning failed!") + + # Show detailed error information + errors = record_detail.get('RecordErrors', []) + for error in errors: + self.print_error(f"Error Code: {error.get('Code', 'Unknown')}") + self.print_error(f"Description: {error.get('Description', 'No description')}") + + # Try to get CloudFormation stack events + self._show_cloudformation_errors(record_detail) + return False + + elif status == 'IN_PROGRESS': + if self.verbose: + self._show_recent_stack_events(record_detail) + + time.sleep(10) + + except ClientError as e: + self.print_error(f"Failed to get provisioning status: {e}") + return False + except KeyboardInterrupt: + self.print_warning("Monitoring interrupted. Use the following command to check status:") + self.print_status(f"aws servicecatalog describe-record --id {record_id} --region {self.region}") + return False + + def _show_cloudformation_errors(self, record_detail: Dict): + """Show CloudFormation stack errors if available.""" + try: + # Look for CloudFormation stack ARN in outputs + stack_arn = None + for output in record_detail.get('RecordOutputs', []): + if output['OutputKey'] == 'CloudformationStackArn': + stack_arn = output['OutputValue'] + break + + if not stack_arn: + return + + self.print_status("CloudFormation Stack Events (Failed Resources):") + + response = self.cloudformation.describe_stack_events(StackName=stack_arn) + failed_events = [ + event for event in response['StackEvents'] + if event.get('ResourceStatus', '').endswith('_FAILED') + ] + + if failed_events: + for event in failed_events[:10]: # Show last 10 failed events + timestamp = event['Timestamp'].strftime("%Y-%m-%d %H:%M:%S") + resource_type = event.get('ResourceType', 'Unknown') + logical_id = event.get('LogicalResourceId', 'Unknown') + reason = event.get('ResourceStatusReason', 'No reason provided') + + print(f" {timestamp} | {resource_type} | {logical_id}") + print(f" Reason: {reason}") + else: + self.print_status("No failed CloudFormation events found") + + except ClientError as e: + self.print_warning(f"Could not retrieve CloudFormation events: {e}") + + def _show_recent_stack_events(self, record_detail: Dict): + """Show recent CloudFormation stack events.""" + try: + # Look for CloudFormation stack ARN in outputs + stack_arn = None + for output in record_detail.get('RecordOutputs', []): + if output['OutputKey'] == 'CloudformationStackArn': + stack_arn = output['OutputValue'] + break + + if not stack_arn: + return + + response = self.cloudformation.describe_stack_events(StackName=stack_arn) + recent_events = response['StackEvents'][:5] # Last 5 events + + self.print_status("Recent CloudFormation Events:") + for event in recent_events: + timestamp = event['Timestamp'].strftime("%H:%M:%S") + resource_type = event.get('ResourceType', 'Unknown') + logical_id = event.get('LogicalResourceId', 'Unknown') + status = event.get('ResourceStatus', 'Unknown') + + print(f" {timestamp} | {status} | {resource_type} | {logical_id}") + + except ClientError: + pass # Silently ignore errors in verbose mode + + +def main(): + """Main function to parse arguments and launch the product.""" + parser = argparse.ArgumentParser( + description='Launch a Service Catalog product and monitor for errors.', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Auto-discover portfolio and product from Terraform state + python3 launch_service_catalog_product.py --stack-name my-image-pipeline + + # Launch with specific IDs + python3 launch_service_catalog_product.py -p port-abc123 -d prod-def456 -n my-pipeline + + # Launch and don't wait for completion + python3 launch_service_catalog_product.py -p port-abc123 -d prod-def456 -n my-pipeline --no-wait + + # Launch with custom parameters + python3 launch_service_catalog_product.py --stack-name my-pipeline --param ProjectName=MyProject --param VpcId=vpc-123 + """ + ) + + parser.add_argument('-r', '--region', help='AWS region (default: from AWS config)') + parser.add_argument('-p', '--portfolio-id', help='Service Catalog Portfolio ID') + parser.add_argument('-d', '--product-id', help='Service Catalog Product ID') + parser.add_argument('-a', '--artifact-id', help='Provisioning Artifact ID (optional, uses latest)') + parser.add_argument('-n', '--stack-name', help='CloudFormation stack name for the provisioned product') + parser.add_argument('--no-wait', action='store_true', help="Don't wait for completion") + parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output') + parser.add_argument('--param', action='append', metavar='KEY=VALUE', + help='CloudFormation parameter (can be used multiple times)') + + args = parser.parse_args() + + # Determine region + region = args.region + if not region: + try: + session = boto3.Session() + region = session.region_name + except Exception: + print(f"{Colors.RED}[ERROR]{Colors.NC} No region specified and no default region configured") + sys.exit(1) + + try: + launcher = ServiceCatalogLauncher(region, args.verbose) + launcher.print_status(f"Using AWS region: {region}") + + # Verify AWS credentials + launcher.print_status("Verifying AWS access...") + sts = launcher.session.client('sts') + caller_identity = sts.get_caller_identity() + launcher.print_success(f"Authenticated as: {caller_identity.get('Arn', 'Unknown')}") + + except NoCredentialsError: + print(f"{Colors.RED}[ERROR]{Colors.NC} AWS credentials not found. Please configure AWS CLI or set credentials.") + sys.exit(1) + except Exception as e: + print(f"{Colors.RED}[ERROR]{Colors.NC} Failed to initialize AWS session: {e}") + sys.exit(1) + + # Auto-discover or use provided IDs + portfolio_id = args.portfolio_id + product_id = args.product_id + + if not portfolio_id or not product_id: + discovered_portfolio, discovered_product = launcher.auto_discover_resources() + if not discovered_portfolio or not discovered_product: + launcher.print_error("Please provide --portfolio-id and --product-id manually") + sys.exit(1) + portfolio_id = discovered_portfolio + product_id = discovered_product + + # Verify access to resources + if not launcher.verify_access(portfolio_id, product_id): + sys.exit(1) + + # Get artifact ID + artifact_id = args.artifact_id + if not artifact_id: + artifact_id = launcher.get_latest_artifact(product_id) + if not artifact_id: + sys.exit(1) + + # Get launch parameters + available_params = launcher.get_launch_parameters(product_id, artifact_id) + + # Parse custom parameters + parameters = {} + if args.param: + for param_str in args.param: + if '=' not in param_str: + launcher.print_error(f"Invalid parameter format: {param_str}. Use KEY=VALUE") + sys.exit(1) + key, value = param_str.split('=', 1) + parameters[key] = value + + # Set default stack name if not provided + stack_name = args.stack_name + if not stack_name: + timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") + stack_name = f"image-pipeline-{timestamp}" + launcher.print_status(f"Using default stack name: {stack_name}") + + # Add ProjectName parameter if not provided + if 'ProjectName' not in parameters: + parameters['ProjectName'] = stack_name + + # Launch the product + record_id = launcher.launch_product(product_id, artifact_id, stack_name, parameters) + if not record_id: + sys.exit(1) + + # Monitor or exit + if not args.no_wait: + success = launcher.monitor_provisioning(record_id) + sys.exit(0 if success else 1) + else: + launcher.print_status("Use the following command to monitor progress:") + launcher.print_status(f"aws servicecatalog describe-record --id {record_id} --region {region}") + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/scripts/provision_service_catalog.py b/scripts/provision_service_catalog.py new file mode 100644 index 0000000..ac46262 --- /dev/null +++ b/scripts/provision_service_catalog.py @@ -0,0 +1,48 @@ +import subprocess +import json + +# Set these to your values +PRODUCT_ID = "prod-glqdmbxcfjg36" +PATH_ID = "lpv3-7zyqonur3isme" +PROVISIONED_PRODUCT_NAME = "my-image-pipeline" + +def aws_cli(cmd): + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode != 0: + print("Error:", result.stderr) + exit(1) + return json.loads(result.stdout) + +# 1. Get the provisioning artifact ID +artifacts = aws_cli([ + "aws", "servicecatalog", "list-provisioning-artifacts", + "--product-id", PRODUCT_ID +]) +artifact_id = artifacts["ProvisioningArtifactDetails"][0]["Id"] + +# 2. Get the required parameters (include artifact ID!) +params = aws_cli([ + "aws", "servicecatalog", "describe-provisioning-parameters", + "--product-id", PRODUCT_ID, + "--provisioning-artifact-id", artifact_id, + "--path-id", PATH_ID +]) +param_list = [] +for p in params["ProvisioningArtifactParameters"]: + if p.get("IsRequired", False): + key = p["ParameterKey"] + default = p.get("DefaultValue", "") + # You may want to prompt for values here instead of using defaults + value = default or f"<{key}_value>" + param_list.append(f"Key={key},Value={value}") + +param_str = " ".join(param_list) + +# 3. Print the sample CLI command +print("\nSample AWS CLI command to provision the product:\n") +print(f"aws servicecatalog provision-product \\") +print(f" --product-id {PRODUCT_ID} \\") +print(f" --provisioned-product-name {PROVISIONED_PRODUCT_NAME} \\") +print(f" --provisioning-artifact-id {artifact_id} \\") +print(f" --path-id {PATH_ID} \\") +print(f" --provisioning-parameters {param_str}") \ No newline at end of file diff --git a/scripts/s3_policy_manager.py b/scripts/s3_policy_manager.py new file mode 100755 index 0000000..44eef54 --- /dev/null +++ b/scripts/s3_policy_manager.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +""" +S3 Bucket Policy Manager +Manages S3 bucket policies for Service Catalog launch roles +""" + +import argparse +import json +import sys +import boto3 +from botocore.exceptions import ClientError + +def get_terraform_output(output_name): + """Get Terraform output value by name""" + try: + import subprocess + result = subprocess.run(['tf', 'output', '-raw', output_name], + capture_output=True, text=True, check=False) + if result.returncode != 0: + print(f"❌ Could not get {output_name} from Terraform state") + if result.stderr: + print(f" Error: {result.stderr.strip()}") + return None + return result.stdout.strip() + except Exception as e: + print(f"❌ Error getting Terraform output '{output_name}': {str(e)}") + return None + +def get_bucket_policy(s3_client, bucket_name): + """Get existing bucket policy or return empty policy structure""" + try: + response = s3_client.get_bucket_policy(Bucket=bucket_name) + return json.loads(response['Policy']) + except ClientError as e: + if e.response['Error']['Code'] == 'NoSuchBucketPolicy': + print(f"ℹ️ No existing bucket policy for {bucket_name}") + return { + "Version": "2012-10-17", + "Statement": [] + } + else: + print(f"❌ Error getting bucket policy: {str(e)}") + return None + except Exception as e: + print(f"❌ Error: {str(e)}") + return None + +def update_or_create_policy(policy, launch_role_arn, bucket_name, aws_partition="aws-us-gov"): + """Update existing policy or create a new one with launch role access""" + if not policy: + # Create new policy + return { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowServiceCatalogLaunchRole", + "Effect": "Allow", + "Principal": { + "AWS": [launch_role_arn] + }, + "Action": [ + "s3:GetObject", + "s3:GetObjectVersion", + "s3:ListBucket" + ], + "Resource": [ + f"arn:{aws_partition}:s3:::{bucket_name}", + f"arn:{aws_partition}:s3:::{bucket_name}/*" + ] + } + ] + } + + # Check if launch role already exists in policy + role_exists = False + for statement in policy.get("Statement", []): + if statement.get("Effect") == "Allow" and "Principal" in statement: + principals = statement.get("Principal", {}) + if "AWS" in principals: + aws_principals = principals["AWS"] + if isinstance(aws_principals, str): + if aws_principals == launch_role_arn: + role_exists = True + print(f"✅ Launch role already exists in bucket policy") + break + else: + # Convert to list for consistency + principals["AWS"] = [aws_principals] + + if isinstance(aws_principals, list) and launch_role_arn in aws_principals: + role_exists = True + print(f"✅ Launch role already exists in bucket policy") + break + + if not role_exists: + # Add launch role to first Allow statement or create new statement + found_allow = False + for statement in policy.get("Statement", []): + if statement.get("Effect") == "Allow" and "Principal" in statement: + principals = statement.get("Principal", {}) + if "AWS" in principals: + found_allow = True + aws_principals = principals["AWS"] + if isinstance(aws_principals, str): + principals["AWS"] = [aws_principals, launch_role_arn] + elif isinstance(aws_principals, list): + aws_principals.append(launch_role_arn) + break + + if not found_allow: + # No suitable Allow statement found, create new one + policy.setdefault("Statement", []).append({ + "Sid": "AllowServiceCatalogLaunchRole", + "Effect": "Allow", + "Principal": { + "AWS": [launch_role_arn] + }, + "Action": [ + "s3:GetObject", + "s3:GetObjectVersion", + "s3:ListBucket" + ], + "Resource": [ + f"arn:{aws_partition}:s3:::{bucket_name}", + f"arn:{aws_partition}:s3:::{bucket_name}/*" + ] + }) + + return policy + +def apply_bucket_policy(s3_client, bucket_name, policy, dry_run=False): + """Apply the policy to the bucket""" + if dry_run: + print("\nWould apply the following bucket policy:") + print(json.dumps(policy, indent=2)) + return True + + try: + s3_client.put_bucket_policy( + Bucket=bucket_name, + Policy=json.dumps(policy) + ) + print(f"✅ Successfully updated bucket policy for {bucket_name}") + return True + except Exception as e: + print(f"❌ Failed to update bucket policy: {str(e)}") + return False + +def check_bucket_access(s3_client, bucket_name): + """Check if current user has access to the bucket""" + try: + s3_client.list_objects_v2(Bucket=bucket_name, MaxKeys=1) + print(f"✅ Current user can list S3 bucket: {bucket_name}") + return True + except Exception as e: + print(f"❌ Current user cannot list S3 bucket: {bucket_name}") + print(f" Error: {str(e)}") + return False + +def main(): + """Main function""" + parser = argparse.ArgumentParser(description='Manage S3 bucket policies for Service Catalog') + parser.add_argument('--bucket', help='S3 bucket name (defaults to Terraform output)') + parser.add_argument('--role-arn', help='Launch role ARN (defaults to Terraform output)') + parser.add_argument('--all-buckets', action='store_true', + help='Fix policies for all buckets used by CloudFormation') + parser.add_argument('--dry-run', action='store_true', + help='Show changes without applying them') + parser.add_argument('--region', help='AWS region') + parser.add_argument('--partition', default='aws-us-gov', + help='AWS partition (aws, aws-us-gov, etc)') + args = parser.parse_args() + + # Get region from args or environment + region = args.region + if not region: + import os + region = os.environ.get('AWS_REGION') + if not region: + try: + import subprocess + result = subprocess.run(['aws', 'configure', 'get', 'region'], + capture_output=True, text=True, check=False) + region = result.stdout.strip() + except Exception: + pass + + if not region: + print("❌ AWS region not specified") + print(" Please set --region argument or AWS_REGION environment variable") + return 1 + + # Create AWS clients + try: + s3_client = boto3.client('s3', region_name=region) + except Exception as e: + print(f"❌ Failed to create AWS S3 client: {str(e)}") + return 1 + + # Get role ARN from args or Terraform output + launch_role_arn = args.role_arn + if not launch_role_arn: + launch_role_arn = get_terraform_output('service_catalog_launch_role_arn') + if not launch_role_arn: + print("❌ Launch role ARN not specified and not found in Terraform state") + return 1 + + print(f"Launch role ARN: {launch_role_arn}") + + # Determine which buckets to process + buckets = [] + if args.all_buckets: + # Handle all buckets used by CloudFormation + buckets = ["image-pipeline-assets-dev"] # Add any additional known buckets here + print(f"Processing all S3 buckets: {', '.join(buckets)}") + else: + # Just handle the specified or default bucket + bucket_name = args.bucket + if not bucket_name: + bucket_name = get_terraform_output('template_bucket') + if not bucket_name: + print("❌ Bucket name not specified and not found in Terraform state") + return 1 + buckets = [bucket_name] + + # Process each bucket + success = True + for bucket_name in buckets: + print(f"\n📦 Processing bucket: {bucket_name}") + + # Check bucket access + if not check_bucket_access(s3_client, bucket_name): + print(f"⚠️ Warning: Cannot access bucket {bucket_name}, but attempting policy update anyway") + + # Get current policy + current_policy = get_bucket_policy(s3_client, bucket_name) + if current_policy is None: + print(f"❌ Skipping bucket {bucket_name} due to errors") + success = False + continue + + # Update policy to include launch role + new_policy = update_or_create_policy( + current_policy, launch_role_arn, bucket_name, args.partition + ) + + # Print policy changes + if args.dry_run or current_policy != new_policy: + print("\nNew bucket policy:") + print(json.dumps(new_policy, indent=2)) + + if not args.dry_run: + confirm = input("\nApply this bucket policy? [y/N]: ") + if confirm.lower() != 'y': + print(f"Skipped bucket {bucket_name} policy update") + continue + + # Apply the updated policy + if not apply_bucket_policy(s3_client, bucket_name, new_policy, args.dry_run): + success = False + else: + print(f"No policy changes needed for bucket {bucket_name}") + + if success: + return 0 + else: + return 1 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/scripts/service_catalog_manager.py b/scripts/service_catalog_manager.py new file mode 100755 index 0000000..0fc0929 --- /dev/null +++ b/scripts/service_catalog_manager.py @@ -0,0 +1,322 @@ +#!/usr/bin/env python3 +""" +Service Catalog Manager +Manages and troubleshoots Service Catalog portfolios, products, and constraints +""" + +import argparse +import json +import sys +import time +import boto3 +from botocore.exceptions import ClientError + +def get_terraform_output(output_name): + """Get Terraform output value by name""" + try: + import subprocess + result = subprocess.run(['tf', 'output', '-raw', output_name], + capture_output=True, text=True, check=False) + if result.returncode != 0: + print(f"❌ Could not get {output_name} from Terraform state") + if result.stderr: + print(f" Error: {result.stderr.strip()}") + return None + return result.stdout.strip() + except Exception as e: + print(f"❌ Error getting Terraform output '{output_name}': {str(e)}") + return None + +def check_service_catalog_access(sc_client, portfolio_id, product_id): + """Check if current user has access to Service Catalog resources""" + try: + sc_client.describe_portfolio(Id=portfolio_id) + print("✅ Portfolio access verified") + except Exception as e: + print(f"❌ Cannot access portfolio - check IAM permissions") + print(f" Error: {str(e)}") + return False + + try: + sc_client.describe_product(Id=product_id) + print("✅ Product access verified") + except Exception as e: + print(f"❌ Cannot access product - check IAM permissions") + print(f" Error: {str(e)}") + return False + + return True + +def check_launch_constraints(sc_client, portfolio_id): + """Check for launch constraints on the portfolio""" + try: + response = sc_client.list_constraints_for_portfolio( + PortfolioId=portfolio_id, + ) + constraints = [c for c in response.get('ConstraintDetails', []) + if c.get('Type') == 'LAUNCH'] + + if constraints: + print(f"✅ Found {len(constraints)} launch constraint(s):") + for c in constraints: + desc = c.get('Description', 'No description') + print(f" - {desc}") + + # Check if constraint parameters contain a valid RoleArn + if 'Parameters' in c: + try: + params = json.loads(c['Parameters']) + if 'RoleArn' in params: + print(f" Role ARN: {params['RoleArn']}") + else: + print(" ⚠️ No RoleArn in constraint parameters") + except json.JSONDecodeError: + print(" ⚠️ Could not parse constraint parameters") + return constraints + else: + print("⚠️ No launch constraints found - this may cause permission issues") + print(" This could be why you're getting S3 access denied errors") + return [] + + except Exception as e: + print(f"❌ Error checking launch constraints: {str(e)}") + return [] + +def cleanup_constraints(sc_client, portfolio_id, constraint_type='LAUNCH', dry_run=False): + """Clean up constraints of the specified type from a portfolio""" + try: + response = sc_client.list_constraints_for_portfolio( + PortfolioId=portfolio_id, + ) + constraints = [c for c in response.get('ConstraintDetails', []) + if c.get('Type') == constraint_type] + + if constraints: + print(f"Found {len(constraints)} {constraint_type} constraint(s):") + for c in constraints: + desc = c.get('Description', 'No description') + constraint_id = c.get('ConstraintId') + print(f" - {constraint_id}: {desc}") + + if not dry_run: + try: + sc_client.delete_constraint(Id=constraint_id) + print(f" ✅ Deleted constraint {constraint_id}") + except Exception as e: + print(f" ❌ Error deleting constraint {constraint_id}: {str(e)}") + return False + + if dry_run: + print("\n⚠️ DRY RUN: No constraints were actually deleted") + else: + print("\n✅ All constraints deleted successfully") + return True + else: + print(f"No {constraint_type} constraints found to clean up") + return True + + except Exception as e: + print(f"❌ Error cleaning up constraints: {str(e)}") + return False + +def fix_launch_constraint(sc_client, portfolio_id, product_id, role_arn, dry_run=False): + """Fix launch constraint by recreating it with proper role ARN""" + # First, clean up existing launch constraints + if not cleanup_constraints(sc_client, portfolio_id, 'LAUNCH', dry_run): + return False + + if dry_run: + print(f"\n⚠️ DRY RUN: Would create launch constraint with role ARN: {role_arn}") + return True + + # Wait a bit to ensure constraints are deleted + print("Waiting 5 seconds for constraint deletion to complete...") + time.sleep(5) + + # Now create new launch constraint + try: + response = sc_client.create_constraint( + PortfolioId=portfolio_id, + ProductId=product_id, + Type='LAUNCH', + Description=f"Launch constraint for Service Catalog product (created by script)", + Parameters=json.dumps({'RoleArn': role_arn}) + ) + print(f"\n✅ Successfully created new launch constraint: {response['ConstraintDetail']['ConstraintId']}") + return True + except Exception as e: + print(f"\n❌ Error creating launch constraint: {str(e)}") + return False + +def investigate_service_catalog(sc_client, portfolio_id, product_id, role_arn): + """Investigate Service Catalog specific issues""" + print("🔍 Investigating Service Catalog specific issue...") + print("We know direct CloudFormation works, so this is a Service Catalog configuration problem.") + print("") + + print("1. Checking Service Catalog launch constraints in detail...") + constraints = check_launch_constraints(sc_client, portfolio_id) + + print("\n2. Checking launch constraint parameters...") + launch_constraint = next((c for c in constraints if c.get('Type') == 'LAUNCH'), None) + if launch_constraint: + if 'Parameters' in launch_constraint: + try: + params = json.loads(launch_constraint['Parameters']) + if 'RoleArn' in params: + constraint_role_arn = params['RoleArn'] + if constraint_role_arn != role_arn: + print(f"⚠️ WARNING: Launch constraint role ({constraint_role_arn}) differs from expected role ({role_arn})") + else: + print("✅ Launch constraint role matches expected role") + else: + print("❌ No RoleArn found in launch constraint parameters") + except json.JSONDecodeError: + print("❌ Could not parse launch constraint parameters") + else: + print("❌ No parameters found in launch constraint") + else: + print("❌ No launch constraint found") + + # Check role trust policy + print("\n3. Testing Service Catalog launch role trust policy...") + try: + import re + role_name = re.search(r'role/([^/]+)$', role_arn).group(1) + + iam_client = boto3.client('iam') + response = iam_client.get_role(RoleName=role_name) + trust_policy = response['Role']['AssumeRolePolicyDocument'] + + print("Trust policy:") + print(json.dumps(trust_policy, indent=2)) + + # Check if Service Catalog is trusted + sc_trusted = False + for statement in trust_policy.get('Statement', []): + if statement.get('Effect') == 'Allow': + principal = statement.get('Principal', {}) + services = principal.get('Service', []) + if isinstance(services, str): + services = [services] + if 'servicecatalog.amazonaws.com' in services: + sc_trusted = True + break + + if sc_trusted: + print("✅ Service Catalog can assume the launch role") + else: + print("❌ Service Catalog CANNOT assume the launch role - this is likely the issue!") + except Exception as e: + print(f"❌ Error checking role trust policy: {str(e)}") + + # Print recommendations + print("\n5. RECOMMENDATION:") + print("Since direct CloudFormation works but Service Catalog fails, the issue is likely:") + print(" a) Service Catalog launch constraint configuration") + print(" b) Service Catalog service permissions vs direct CloudFormation permissions") + print(" c) Parameter validation differences between Service Catalog and CloudFormation") + + print("\nNext steps:") + print("1. Try recreating the Service Catalog launch constraint: python scripts/service_catalog_manager.py --fix-constraint") + print("2. Check CloudTrail logs for detailed Service Catalog API errors") + print("3. Test with minimal parameters to isolate parameter-specific issues") + +def main(): + """Main function""" + parser = argparse.ArgumentParser(description='Service Catalog Manager') + parser.add_argument('--region', help='AWS region') + parser.add_argument('--check-access', action='store_true', + help='Check Service Catalog access and permissions') + parser.add_argument('--investigate', action='store_true', + help='Investigate Service Catalog specific issues') + parser.add_argument('--cleanup-constraints', action='store_true', + help='Clean up Service Catalog constraints') + parser.add_argument('--fix-constraint', action='store_true', + help='Fix Service Catalog launch constraint') + parser.add_argument('--portfolio-id', help='Portfolio ID (defaults to Terraform output)') + parser.add_argument('--product-id', help='Product ID (defaults to Terraform output)') + parser.add_argument('--role-arn', help='Launch role ARN (defaults to Terraform output)') + parser.add_argument('--dry-run', action='store_true', + help='Show changes without applying them') + args = parser.parse_args() + + # Get region from args or environment + region = args.region + if not region: + import os + region = os.environ.get('AWS_REGION') + if not region: + try: + import subprocess + result = subprocess.run(['aws', 'configure', 'get', 'region'], + capture_output=True, text=True, check=False) + region = result.stdout.strip() + except Exception: + pass + + if not region: + print("❌ AWS region not specified") + print(" Please set --region argument or AWS_REGION environment variable") + return 1 + + # Create AWS clients + try: + sc_client = boto3.client('servicecatalog', region_name=region) + except Exception as e: + print(f"❌ Failed to create AWS Service Catalog client: {str(e)}") + return 1 + + # Get resource IDs from args or Terraform output + portfolio_id = args.portfolio_id + if not portfolio_id: + portfolio_id = get_terraform_output('service_catalog_portfolio_id') + if not portfolio_id: + print("❌ Portfolio ID not specified and not found in Terraform state") + return 1 + + product_id = args.product_id + if not product_id: + product_id = get_terraform_output('service_catalog_product_id') + if not product_id: + print("❌ Product ID not specified and not found in Terraform state") + return 1 + + role_arn = args.role_arn + if not role_arn: + role_arn = get_terraform_output('service_catalog_launch_role_arn') + if not role_arn and (args.fix_constraint or args.investigate): + print("❌ Launch role ARN not specified and not found in Terraform state") + return 1 + + print(f"Portfolio ID: {portfolio_id}") + print(f"Product ID: {product_id}") + if role_arn: + print(f"Launch role ARN: {role_arn}") + + # Execute requested operation(s) + if args.check_access: + if not check_service_catalog_access(sc_client, portfolio_id, product_id): + return 1 + check_launch_constraints(sc_client, portfolio_id) + + if args.cleanup_constraints: + if not cleanup_constraints(sc_client, portfolio_id, 'LAUNCH', args.dry_run): + return 1 + + if args.fix_constraint: + if not fix_launch_constraint(sc_client, portfolio_id, product_id, role_arn, args.dry_run): + return 1 + + if args.investigate: + investigate_service_catalog(sc_client, portfolio_id, product_id, role_arn) + + # If no operation specified, show usage + if not any([args.check_access, args.cleanup_constraints, args.fix_constraint, args.investigate]): + parser.print_help() + return 1 + + return 0 + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/service-catalog.tf b/service-catalog.tf new file mode 100644 index 0000000..b4d89e5 --- /dev/null +++ b/service-catalog.tf @@ -0,0 +1,61 @@ + +# Service Catalog Resources using the dedicated module +module "service_catalog" { + source = "../terraform-cfn-service-catalog" + + # Product configuration + product_name = var.product_name + product_description = var.product_description + product_owner = var.product_owner + + # Template configuration - use the dedicated Service Catalog bucket + template_bucket = aws_s3_bucket.service_catalog.id + template_url = local.service_catalog_template_vars.main_template_url + + # AWS region for proper S3 URL construction + aws_region = var.aws_region + + # Portfolio configuration + create_portfolio = true + portfolio_name = var.portfolio_name + portfolio_description = var.portfolio_description + portfolio_provider_name = var.portfolio_provider_name + + # Access control - use dynamically generated principal ARNs + include_current_user = false + principal_arns = local.dynamic_principal_arns + + # Launch constraint configuration - let the module create the role + create_launch_role = true + launch_role_name = "${var.project_name}-service-catalog-launch-role" + + # S3 bucket access for the launch role - only include dedicated Service Catalog bucket + additional_s3_buckets = [ + aws_s3_bucket.service_catalog.id # New dedicated bucket for Service Catalog templates and global assets + ] + + # Disable S3 bucket policy for Service Catalog service access since we're using AES256 encryption + enable_service_catalog_s3_access = false + + # Provisioning artifact + provisioning_artifact_name = "v1.0" + provisioning_artifact_description = "AWS Image Building Pipeline v1.0" + + # Tags + tags = var.tags + + # Ensure Service Catalog bucket and templates are ready before creating Service Catalog resources + depends_on = [ + aws_s3_bucket.service_catalog, + aws_s3_object.main_template, + aws_s3_object.kms_template, + aws_s3_object.iam_template, + aws_s3_object.s3_template, + aws_s3_object.codebuild_template, + aws_s3_object.codepipeline_template, + aws_s3_object.buildspec, + # aws_s3_object.global_packer, + # aws_s3_object.global_ansible, + # aws_s3_object.global_pip + ] +} \ No newline at end of file diff --git a/templates/buildspec.yaml b/templates/buildspec.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/templates/codebuild.yml b/templates/codebuild.yml index f4eb004..b0d3012 100644 --- a/templates/codebuild.yml +++ b/templates/codebuild.yml @@ -154,7 +154,8 @@ Resources: Location: !Sub ${ArtifactBucketName}/cache Source: Type: CODEPIPELINE - BuildSpec: "buildspec.yml" + # Use the buildspec path in the template bucket + BuildSpec: !Ref BuildspecObjectKey VpcConfig: VpcId: !Ref VpcId Subnets: !Split [",", !Ref SubnetIds] diff --git a/templates/codepipeline.yml b/templates/codepipeline.yml index 69267a5..dd9e7bb 100644 --- a/templates/codepipeline.yml +++ b/templates/codepipeline.yml @@ -90,8 +90,8 @@ Resources: Version: 1 Provider: S3 Configuration: - S3Bucket: !Ref BuildspecBucketName - S3ObjectKey: !Sub image-pipeline-config/${ProjectName}/packer_config.zip + S3Bucket: !Ref PackerBucketName + S3ObjectKey: !Ref PackerBucketKey PollForSourceChanges: false OutputArtifacts: - Name: SourceOutput diff --git a/main.yaml.tftpl b/templates/main.yaml.tftpl similarity index 100% rename from main.yaml.tftpl rename to templates/main.yaml.tftpl diff --git a/templates/main.yml.tftpl b/templates/main.yml.tftpl deleted file mode 100644 index 2ad3e53..0000000 --- a/templates/main.yml.tftpl +++ /dev/null @@ -1,241 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: | - AWS Image Pipeline - Automated AMI and Container Image Building Pipeline - Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services. - -Parameters: - ProjectName: - Type: String - Description: Unique name for this project - AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$ - ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens - - CreateNewRole: - Type: String - Description: Whether to create a new IAM role (true) or use existing roles (false) - Default: "true" - AllowedValues: ["true", "false"] - - SSHUser: - Type: String - Description: SSH username for connecting to build instances - Default: ec2-user - - Troubleshoot: - Type: String - Description: Enable troubleshooting mode for builds - Default: "false" - AllowedValues: ["true", "false"] - - BuilderComputeType: - Type: String - Description: CodeBuild compute resources type - Default: BUILD_GENERAL1_SMALL - AllowedValues: - - BUILD_GENERAL1_SMALL - - BUILD_GENERAL1_MEDIUM - - BUILD_GENERAL1_LARGE - - BuilderImage: - Type: String - Description: Docker image to use for CodeBuild - Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0 - - PackerVersion: - Type: String - Description: Version of HashiCorp Packer to use - Default: 1.10.3 - - AssetsBucketName: - Type: String - Description: Name of the S3 bucket to store deployment artifacts - Default: image-pipeline-assets-dev - - DockerBuild: - Type: String - Description: Whether to enable Docker image building - Default: "false" - AllowedValues: ["true", "false"] - - VpcId: - Type: AWS::EC2::VPC::Id - Description: VPC where resources will be created - - SubnetIds: - Type: List - Description: Subnets where CodeBuild will run - - PackerBucketName: - Type: String - Description: Name of the S3 bucket containing Packer templates - - PackerBucketKey: - Type: String - Description: Key (path) to the Packer templates archive in S3 - - AnsibleBucketName: - Type: String - Description: Name of the S3 bucket containing Ansible roles - - AnsibleBucketKey: - Type: String - Description: Key (path) to the Ansible roles archive in S3 - - PipBucketName: - Type: String - Description: Name of the S3 bucket containing pip configuration - - PipBucketKey: - Type: String - Description: Key (path) to the pip configuration archive in S3 - - PackerFileName: - Type: String - Description: Name of the Packer file to build - Default: "build.pkr.hcl" - - BuildspecBucketName: - Type: String - Description: S3 bucket containing the buildspec file - - BuildspecObjectKey: - Type: String - Description: S3 object key for the buildspec file - - AdditionalSecurityGroupId: - Type: String - Description: ID of an additional pre-existing security group to attach to the CodeBuild job - Default: "" - -Resources: - KMSStack: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: ${kms_template_url} - Parameters: - ProjectName: !Ref ProjectName - - IAMStack: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: ${iam_template_url} - Parameters: - ProjectName: !Ref ProjectName - KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn - CreateNewRole: !Ref CreateNewRole - AssetsBucketName: !Ref AssetsBucketName - - S3Stack: - Type: AWS::CloudFormation::Stack - DependsOn: IAMStack - Properties: - TemplateURL: ${s3_template_url} - Parameters: - ProjectName: !Ref ProjectName - KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn - CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn - - CodeBuildStack: - Type: AWS::CloudFormation::Stack - DependsOn: [S3Stack, IAMStack] - Properties: - TemplateURL: ${codebuild_template_url} - Parameters: - ProjectName: !Ref ProjectName - BuilderImage: !Ref BuilderImage - BuilderComputeType: !Ref BuilderComputeType - CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn - ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName - KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn - VpcId: !Ref VpcId - SubnetIds: !Join [",", !Ref SubnetIds] - PackerVersion: !Ref PackerVersion - DockerBuild: !Ref DockerBuild - SSHUser: !Ref SSHUser - Troubleshoot: !Ref Troubleshoot - PackerFileName: !Ref PackerFileName - AssetsBucketName: !Ref AssetsBucketName - BuildspecBucketName: !Ref BuildspecBucketName - BuildspecObjectKey: !Ref BuildspecObjectKey - AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId - - CodePipelineStack: - Type: AWS::CloudFormation::Stack - DependsOn: [CodeBuildStack, S3Stack] - Properties: - TemplateURL: ${codepipeline_template_url} - Parameters: - ProjectName: !Ref ProjectName - CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn - ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName - KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn - BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName - AnsibleBucketName: !Ref AnsibleBucketName - AnsibleBucketKey: !Ref AnsibleBucketKey - PackerBucketName: !Ref PackerBucketName - PackerBucketKey: !Ref PackerBucketKey - PipBucketName: !Ref PipBucketName - PipBucketKey: !Ref PipBucketKey - BuildspecBucketName: !Ref BuildspecBucketName - BuildspecObjectKey: !Ref BuildspecObjectKey - -Outputs: - CodePipelineName: - Description: Name of the created CodePipeline - Value: !GetAtt CodePipelineStack.Outputs.PipelineName - Export: - Name: !Sub $${AWS::StackName}-pipeline-name - - CodePipelineArn: - Description: ARN of the created CodePipeline - Value: !GetAtt CodePipelineStack.Outputs.PipelineArn - Export: - Name: !Sub $${AWS::StackName}-pipeline-arn - - ArtifactBucketName: - Description: Name of the S3 bucket storing pipeline artifacts - Value: !GetAtt S3Stack.Outputs.ArtifactBucketName - Export: - Name: !Sub $${AWS::StackName}-bucket-name - - ArtifactBucketArn: - Description: ARN of the S3 bucket storing pipeline artifacts - Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn - Export: - Name: !Sub $${AWS::StackName}-bucket-arn - - KMSKeyArn: - Description: ARN of the KMS key used for encryption - Value: !GetAtt KMSStack.Outputs.KMSKeyArn - Export: - Name: !Sub $${AWS::StackName}-kms-key-arn - - IamArn: - Description: ARN of the CodePipeline IAM role - Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn - Export: - Name: !Sub $${AWS::StackName}-pipeline-role-arn - - RoleName: - Description: Name of the CodePipeline IAM role - Value: !Sub $${ProjectName}-pipeline-role - Export: - Name: !Sub $${AWS::StackName}-pipeline-role-name - - SecurityGroupId: - Description: ID of the security group used by CodeBuild - Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId - Export: - Name: !Sub $${AWS::StackName}-security-group-id - - ManagedParameters: - Description: Base path for SSM parameters managed by this pipeline - Value: !Sub /image-pipeline/$${ProjectName} - Export: - Name: !Sub $${AWS::StackName}-ssm-path - - SecretsPath: - Description: Base path for Secrets Manager secrets managed by this pipeline - Value: !Sub image-pipeline/$${ProjectName} - Export: - Name: !Sub $${AWS::StackName}-secrets-path \ No newline at end of file diff --git a/terraform.tfstate b/terraform.tfstate index b1ed609..1f92d31 100644 --- a/terraform.tfstate +++ b/terraform.tfstate @@ -1,78 +1,87 @@ { "version": 4, "terraform_version": "1.9.1", - "serial": 1323, - "lineage": "711db70b-e400-b85a-a4cc-d392b3e4bca9", + "serial": 318, + "lineage": "abad5d20-db36-5594-357e-eb275732a608", "outputs": { - "artifact_bucket_arn": { - "value": "arn:aws-us-gov:s3:::aws-linux-s3stack-ot8z92cro1u3-artifactbucket-2vnzw4ewaayq", + "buildspec_location": { + "value": "s3://csvd-229685449397-aws-linux-service-catalog-templates//buildspec.yml", "type": "string" }, - "artifact_bucket_name": { - "value": "aws-linux-s3stack-ot8z92cro1u3-artifactbucket-2vnzw4ewaayq", - "type": "string" + "service_catalog_all_principals": { + "value": [ + "arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0", + "arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0" + ], + "type": [ + "list", + "string" + ] }, - "code_pipeline_arn": { - "value": "arn:aws-us-gov:codepipeline:us-gov-west-1:229685449397:aws-linux-pipeline", + "service_catalog_launch_role_arn": { + "value": "arn:aws-us-gov:iam::229685449397:role/aws-linux-service-catalog-launch-role", "type": "string" }, - "code_pipeline_name": { - "value": "aws-linux-pipeline", + "service_catalog_launch_role_name": { + "value": "aws-linux-service-catalog-launch-role", "type": "string" }, - "iam_role_arn": { - "value": "arn:aws-us-gov:iam::229685449397:role/aws-linux-pipeline-role", + "service_catalog_portfolio_arn": { + "value": "arn:aws-us-gov:catalog:us-gov-west-1:229685449397:portfolio/port-xoyjh6eru6k5m", "type": "string" }, - "kms_key_arn": { - "value": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/d2f10e61-6637-4a4d-b12b-a50bd23c249f", + "service_catalog_portfolio_id": { + "value": "port-xoyjh6eru6k5m", "type": "string" }, - "managed_parameters_path": { - "value": "/image-pipeline/aws-linux", - "type": "string" + "service_catalog_principal_count": { + "value": 2, + "type": "number" }, - "role_name": { - "value": "aws-linux-pipeline-role", + "template_prefix": { + "value": "", "type": "string" }, - "secrets_path": { - "value": "image-pipeline/aws-linux", + "template_url": { + "value": "https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//main.yml", "type": "string" }, - "security_group_id": { - "value": "sg-0e8425fc36ce6e3b3", - "type": "string" + "uploaded_templates": { + "value": [ + "/main.yml", + "/kms.yml", + "/iam.yml", + "/s3.yml", + "/codebuild.yml", + "/codepipeline.yml" + ], + "type": [ + "tuple", + [ + "string", + "string", + "string", + "string", + "string", + "string" + ] + ] } }, "resources": [ { "mode": "data", - "type": "archive_file", - "name": "buildspec", - "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 0, "attributes": { - "exclude_symlink_directories": null, - "excludes": null, - "id": "f7794c78b1dd1db12cbd69abf93ae4e25f8478ae", - "output_base64sha256": "4jkh7rnmCoBBVVy4gFnnhN3zFl+8w++gQLowLNyst0s=", - "output_base64sha512": "dCfv1FolaMxUCXMbibrawtggq7Mwc/2EtaEMbGGaqthP3P5DOh0j7zXfm9DdCHpAyVbtvlRRZElMQ1kcGNDdHA==", - "output_file_mode": null, - "output_md5": "d94c584b11e7e234c07ff52fb1cee0d1", - "output_path": "./buildspec.zip", - "output_sha": "f7794c78b1dd1db12cbd69abf93ae4e25f8478ae", - "output_sha256": "e23921eeb9e60a8041555cb88059e784ddf3165fbcc3efa040ba302cdcacb74b", - "output_sha512": "7427efd45a2568cc5409731b89badac2d820abb33073fd84b5a10c6c619aaad84fdcfe433a1d23ef35df9bd0dd087a40c956edbe545164494c43591c18d0dd1c", - "output_size": 1428, - "source": [], - "source_content": null, - "source_content_filename": null, - "source_dir": null, - "source_file": "./templates/buildspec.yml", - "type": "zip" + "account_id": "229685449397", + "arn": "arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov", + "id": "229685449397", + "user_id": "AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov" }, "sensitive_attributes": [] } @@ -80,31 +89,17 @@ }, { "mode": "data", - "type": "archive_file", - "name": "packer_config", - "provider": "provider[\"registry.terraform.io/hashicorp/archive\"]", + "type": "aws_partition", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 0, "attributes": { - "exclude_symlink_directories": null, - "excludes": null, - "id": "0fa805172f7339e92bdb4da20dadaa8383d9e73f", - "output_base64sha256": "ybgYy3mwYt86Q1iR2hmBrgCSKcmldMPW9JAflswiKrk=", - "output_base64sha512": "60RVHCGhul7ZHUGqL7KNfZ1eNRnterDzGuA/kcYKNQlZIQyK9qh91AtJ/312qbdbKhOwmJ5vKE0BKEJwGgtHfA==", - "output_file_mode": null, - "output_md5": "53b73a7348956feca12db71b78520160", - "output_path": "./packer_config.zip", - "output_sha": "0fa805172f7339e92bdb4da20dadaa8383d9e73f", - "output_sha256": "c9b818cb79b062df3a435891da1981ae009229c9a574c3d6f4901f96cc222ab9", - "output_sha512": "eb44551c21a1ba5ed91d41aa2fb28d7d9d5e3519ed7ab0f31ae03f91c60a350959210c8af6a87dd40b49ff7d76a9b75b2a13b0989e6f284d012842701a0b477c", - "output_size": 1983, - "source": [], - "source_content": null, - "source_content_filename": null, - "source_dir": null, - "source_file": "./templates/build.pkr.hcl", - "type": "zip" + "dns_suffix": "amazonaws.com", + "id": "aws-us-gov", + "partition": "aws-us-gov", + "reverse_dns_prefix": "com.amazonaws" }, "sensitive_attributes": [] } @@ -118,6 +113,7 @@ "instances": [ { "index_key": 0, + "status": "tainted", "schema_version": 0, "attributes": { "capabilities": [ @@ -125,56 +121,41 @@ "CAPABILITY_NAMED_IAM" ], "disable_rollback": false, - "iam_role_arn": "", - "id": "arn:aws-us-gov:cloudformation:us-gov-west-1:229685449397:stack/aws-linux/71349a30-76e0-11f0-9052-0aa060a0cf91", + "iam_role_arn": null, + "id": "arn:aws-us-gov:cloudformation:us-gov-west-1:229685449397:stack/aws-linux/0fa54930-9d6a-11f0-84ff-0682260bc0d1", "name": "aws-linux", "notification_arns": null, "on_failure": null, - "outputs": { - "ArtifactBucketArn": "arn:aws-us-gov:s3:::aws-linux-s3stack-ot8z92cro1u3-artifactbucket-2vnzw4ewaayq", - "ArtifactBucketName": "aws-linux-s3stack-ot8z92cro1u3-artifactbucket-2vnzw4ewaayq", - "CodePipelineArn": "arn:aws-us-gov:codepipeline:us-gov-west-1:229685449397:aws-linux-pipeline", - "CodePipelineName": "aws-linux-pipeline", - "IamArn": "arn:aws-us-gov:iam::229685449397:role/aws-linux-pipeline-role", - "KMSKeyArn": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/d2f10e61-6637-4a4d-b12b-a50bd23c249f", - "ManagedParameters": "/image-pipeline/aws-linux", - "RoleName": "aws-linux-pipeline-role", - "SecretsPath": "image-pipeline/aws-linux", - "SecurityGroupId": "sg-0e8425fc36ce6e3b3" - }, + "outputs": null, "parameters": { "AdditionalSecurityGroupId": "sg-0641c697588b9aa6b", - "AmiName": "aws-linux-2-image", "AnsibleBucketKey": "image-pipeline-ansible-playbooks.zip", "AnsibleBucketName": "image-pipeline-assets-dev", - "AssetsBucketName": "image-pipeline-assets-dev", + "AssetsBucketName": "csvd-229685449397-aws-linux-service-catalog-templates", "BuilderComputeType": "BUILD_GENERAL1_SMALL", "BuilderImage": "aws/codebuild/standard:7.0", - "BuildspecBucketName": "image-pipeline-assets-dev", - "BuildspecObjectKey": "image-pipeline-config/aws-linux/buildspec.zip", + "BuildspecBucketName": "csvd-229685449397-aws-linux-service-catalog-templates", + "BuildspecObjectKey": "/buildspec.yml", "CreateNewRole": "true", "DockerBuild": "false", - "HttpProxy": "http://proxy.tco.census.gov:3128", - "HttpsProxy": "http://proxy.tco.census.gov:3128", - "InstanceType": "t3.medium", - "NoProxy": "pypi.org,github.e.it.census.gov,files.pythonhosted.org,nexus.it.census.gov", + "HttpProxy": "", + "HttpsProxy": "", + "NoProxy": "", "PackerBucketKey": "image-pipeline-packer.zip", "PackerBucketName": "image-pipeline-assets-dev", "PackerFileName": "build.pkr.hcl", "PackerVersion": "1.10.3", "PipBucketKey": "image-pipeline-pip-config.zip", "PipBucketName": "image-pipeline-assets-dev", - "Playbook": "hello-world.yaml", "ProjectName": "aws-linux", "SSHUser": "ec2-user", - "SharedAccounts": "", - "SourceAmiSsmPath": "/enterprise/ami/rhel9", "SubnetIds": "subnet-04b80d7ce5199f82b", "Troubleshoot": "false", "VpcId": "vpc-00576a396ec570b94" }, "policy_body": null, "policy_url": null, + "region": "us-gov-west-1", "tags": { "Environment": "dev", "Owner": "platform-team" @@ -183,24 +164,133 @@ "Environment": "dev", "Owner": "platform-team" }, - "template_body": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n \n # Parameters for Packer SSM Configuration\n SourceAmiSsmPath:\n Type: String\n Description: SSM parameter path to fetch the source AMI ID from\n \n InstanceType:\n Type: String\n Description: Instance type to use for building images\n Default: \"t3.medium\"\n \n AmiName:\n Type: String\n Description: Name to give the created AMI\n Default: \"\"\n \n Playbook:\n Type: String\n Description: Ansible playbook to run during AMI creation\n Default: \"site.yml\"\n \n SharedAccounts:\n Type: String\n Description: Comma-separated list of AWS account IDs to share the AMI with\n Default: \"\"\n \n SecurityGroupIds:\n Type: String\n Description: Security group IDs to use for building AMIs\n Default: \"\"\n\nConditions:\n HasAdditionalSecurityGroup: !Not [!Equals [!Ref AdditionalSecurityGroupId, \"\"]]\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n # SSM Parameters for Packer\n PackerParameters:\n Type: AWS::CloudFormation::Stack\n DependsOn: CodeBuildStack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/ssm.yml\n Parameters:\n ProjectName: !Ref ProjectName\n Region: !Ref \"AWS::Region\"\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n VpcId: !Ref VpcId\n SourceAmiSsmPath: !Ref SourceAmiSsmPath\n InstanceType: !Ref InstanceType\n AmiName: !Ref AmiName\n Playbook: !Ref Playbook\n SharedAccounts: !Ref SharedAccounts\n SecurityGroupIds: !If \n - HasAdditionalSecurityGroup\n - !Join [\",\", [!GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId, !Ref AdditionalSecurityGroupId]]\n - !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n SSHUser: !Ref SSHUser\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", - "template_url": "https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/main.yml", + "template_body": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", + "template_url": null, "timeout_in_minutes": 30, "timeouts": null }, "sensitive_attributes": [], "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInVwZGF0ZSI6MTgwMDAwMDAwMDAwMH19", "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_bucket_policy.service_catalog", "aws_s3_object.buildspec", "aws_s3_object.codebuild_template", "aws_s3_object.codepipeline_template", "aws_s3_object.iam_template", "aws_s3_object.kms_template", "aws_s3_object.main_template", - "aws_s3_object.packer_template", + "aws_s3_object.packer_config", "aws_s3_object.s3_template", - "data.archive_file.buildspec", - "data.archive_file.packer_config" + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "service_catalog", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acceleration_status": "", + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_domain_name": "csvd-229685449397-aws-linux-service-catalog-templates.s3.amazonaws.com", + "bucket_prefix": "", + "bucket_region": "us-gov-west-1", + "bucket_regional_domain_name": "csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com", + "cors_rule": [], + "force_destroy": false, + "grant": [ + { + "id": "1cdbccee29c5305ac377a789c6f924db69ec7da804ad7d8303a495cf5eef9084", + "permissions": [ + "FULL_CONTROL" + ], + "type": "CanonicalUser", + "uri": "" + } + ], + "hosted_zone_id": "Z31GFT0UA1I2HV", + "id": "csvd-229685449397-aws-linux-service-catalog-templates", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "object_lock_enabled": false, + "policy": "{\"Statement\":[{\"Action\":\"s3:*\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"servicecatalog.amazonaws.com\",\"cloudformation.amazonaws.com\"]},\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates\",\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/*\"],\"Sid\":\"AllowServiceCatalogAccess\"}],\"Version\":\"2012-10-17\"}", + "region": "us-gov-west-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [ + { + "rule": [ + { + "apply_server_side_encryption_by_default": [ + { + "kms_master_key_id": "", + "sse_algorithm": "AES256" + } + ], + "bucket_key_enabled": false + } + ] + } + ], + "tags": { + "Environment": "dev", + "Name": "aws-linux-service-catalog-templates", + "Owner": "platform-team", + "Project": "aws-linux" + }, + "tags_all": { + "Environment": "dev", + "Name": "aws-linux-service-catalog-templates", + "Owner": "platform-team", + "Project": "aws-linux" + }, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "service_catalog", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "id": "csvd-229685449397-aws-linux-service-catalog-templates", + "policy": "{\"Statement\":[{\"Action\":[\"s3:*\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"servicecatalog.amazonaws.com\",\"cloudformation.amazonaws.com\"]},\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates\",\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/*\"],\"Sid\":\"AllowServiceCatalogAccess\"}],\"Version\":\"2012-10-17\"}", + "region": "us-gov-west-1" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" ] } ] @@ -215,8 +305,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/buildspec.zip", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/buildspec.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -230,30 +320,32 @@ "content_disposition": "", "content_encoding": "", "content_language": "", - "content_type": "application/zip", - "etag": "69d26dd593e4dfa7a804d59f9da56e2c", + "content_type": "application/x-yml", + "etag": "57c6bd18a9b8abae3de1fed9f1d8b6fc", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/buildspec.zip", - "key": "image-pipeline-config/aws-linux/buildspec.zip", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//buildspec.yml", + "key": "/buildspec.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", - "source": "./buildspec.zip", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/buildspec.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "G1k5s1FUcS6oSvEvQVX4bdulope8rDHC", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], "private": "bnVsbA==", "dependencies": [ - "data.archive_file.buildspec" + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" ] } ] @@ -268,8 +360,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/codebuild.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/codebuild.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -284,27 +376,32 @@ "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "2beec97729e2ae40244d29285314a287", + "etag": "f46d968aeec31a56e047fe8df1241f61", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/codebuild.yml", - "key": "image-pipeline-config/aws-linux/codebuild.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//codebuild.yml", + "key": "/codebuild.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./templates/codebuild.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "2FxzybFbH3_R9qUEpd2PkSbM33wMAr9f", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] } ] }, @@ -318,8 +415,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/codepipeline.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/codepipeline.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -334,27 +431,32 @@ "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "6238572957b94089cfaf8ebad6931620", + "etag": "156f48bdaed0a3e6598fecc4e344efe4", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/codepipeline.yml", - "key": "image-pipeline-config/aws-linux/codepipeline.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//codepipeline.yml", + "key": "/codepipeline.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./templates/codepipeline.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "BuQFJDLnVG22ft_x9Yrd14AXJow7QRWs", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] } ] }, @@ -368,8 +470,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/iam.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/iam.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -384,27 +486,32 @@ "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "333c6467917646e191e9f4e8a3cf7fa2", + "etag": "7aa982e1ce5827b21aab9881cc8e33a3", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/iam.yml", - "key": "image-pipeline-config/aws-linux/iam.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//iam.yml", + "key": "/iam.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./templates/iam.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "Az8UFPxm3fX7XWXQ_inn7L08.X14Yz.s", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] } ] }, @@ -418,8 +525,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/kms.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/kms.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -434,27 +541,32 @@ "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "3b6683e26130bf3a8e5cf47a0e395031", + "etag": "e844ff64293d224a748374b63e223d8d", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/kms.yml", - "key": "image-pipeline-config/aws-linux/kms.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//kms.yml", + "key": "/kms.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./templates/kms.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "8qrqAOzQcdWdy_fMA53kC01PQtKuOf_8", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] } ] }, @@ -468,8 +580,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/main.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/main.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -478,48 +590,53 @@ "checksum_crc64nvme": "", "checksum_sha1": "", "checksum_sha256": "", - "content": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n \n # Parameters for Packer SSM Configuration\n SourceAmiSsmPath:\n Type: String\n Description: SSM parameter path to fetch the source AMI ID from\n \n InstanceType:\n Type: String\n Description: Instance type to use for building images\n Default: \"t3.medium\"\n \n AmiName:\n Type: String\n Description: Name to give the created AMI\n Default: \"\"\n \n Playbook:\n Type: String\n Description: Ansible playbook to run during AMI creation\n Default: \"site.yml\"\n \n SharedAccounts:\n Type: String\n Description: Comma-separated list of AWS account IDs to share the AMI with\n Default: \"\"\n \n SecurityGroupIds:\n Type: String\n Description: Security group IDs to use for building AMIs\n Default: \"\"\n\nConditions:\n HasAdditionalSecurityGroup: !Not [!Equals [!Ref AdditionalSecurityGroupId, \"\"]]\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n # SSM Parameters for Packer\n PackerParameters:\n Type: AWS::CloudFormation::Stack\n DependsOn: CodeBuildStack\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/ssm.yml\n Parameters:\n ProjectName: !Ref ProjectName\n Region: !Ref \"AWS::Region\"\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n VpcId: !Ref VpcId\n SourceAmiSsmPath: !Ref SourceAmiSsmPath\n InstanceType: !Ref InstanceType\n AmiName: !Ref AmiName\n Playbook: !Ref Playbook\n SharedAccounts: !Ref SharedAccounts\n SecurityGroupIds: !If \n - HasAdditionalSecurityGroup\n - !Join [\",\", [!GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId, !Ref AdditionalSecurityGroupId]]\n - !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n SSHUser: !Ref SSHUser\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://s3-us-gov-west-1.amazonaws.com/image-pipeline-assets-dev/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", + "content": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", "content_base64": null, "content_disposition": "", "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "1298525814a9061035d8be03765ebba6", + "etag": "760e87504162e1719b03d89a3df7829f", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/main.yml", - "key": "image-pipeline-config/aws-linux/main.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//main.yml", + "key": "/main.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": null, "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "q3sOE3gRUD_QdJapDX01Spyq3WMyh4js", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] } ] }, { "mode": "managed", "type": "aws_s3_object", - "name": "packer_template", + "name": "packer_config", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/packer_config.zip", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/image-pipeline-packer.zip", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -534,29 +651,31 @@ "content_encoding": "", "content_language": "", "content_type": "application/zip", - "etag": "1dc8612cc132d0ba99bd3928eec05943", + "etag": "53b73a7348956feca12db71b78520160", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/packer_config.zip", - "key": "image-pipeline-config/aws-linux/packer_config.zip", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates/image-pipeline-packer.zip", + "key": "image-pipeline-packer.zip", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./packer_config.zip", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "PkDV4uKWYa0Sgnnf0g89g6gaIR4GhyrB", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], "private": "bnVsbA==", "dependencies": [ - "data.archive_file.packer_config" + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" ] } ] @@ -571,8 +690,8 @@ "schema_version": 0, "attributes": { "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/s3.yml", - "bucket": "image-pipeline-assets-dev", + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/s3.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", "bucket_key_enabled": false, "cache_control": "", "checksum_algorithm": null, @@ -587,82 +706,303 @@ "content_encoding": "", "content_language": "", "content_type": "application/x-yml", - "etag": "0f0c8d3e05d690aad1643044345ce884", + "etag": "71b0638e9b13090eb68502fec3eb6b07", "force_destroy": false, - "id": "image-pipeline-config/aws-linux/s3.yml", - "key": "image-pipeline-config/aws-linux/s3.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//s3.yml", + "key": "/s3.yml", + "kms_key_id": null, + "metadata": {}, "object_lock_legal_hold_status": "", "object_lock_mode": "", "object_lock_retain_until_date": "", "override_provider": [], - "server_side_encryption": "aws:kms", + "region": "us-gov-west-1", + "server_side_encryption": "AES256", "source": "./templates/s3.yml", "source_hash": null, "storage_class": "STANDARD", - "tags": null, + "tags": {}, "tags_all": {}, - "version_id": "ubI7_9r6tbTniwzMQLeGFi5VtEDKPV_3", + "version_id": "", "website_redirect": "" }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "account_id": "229685449397", + "arn": "arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov", + "id": "229685449397", + "user_id": "AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov" + }, + "sensitive_attributes": [] } ] }, { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_partition", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "dns_suffix": "amazonaws.com", + "id": "aws-us-gov", + "partition": "aws-us-gov", + "reverse_dns_prefix": "com.amazonaws" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_servicecatalog_portfolio", + "name": "existing", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [] + }, + { + "module": "module.service_catalog", "mode": "managed", - "type": "aws_s3_object", - "name": "ssm_template", + "type": "aws_iam_policy", + "name": "service_catalog_launch_policy", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { + "index_key": 0, "schema_version": 0, "attributes": { - "acl": null, - "arn": "arn:aws-us-gov:s3:::image-pipeline-assets-dev/image-pipeline-config/aws-linux/ssm.yml", - "bucket": "image-pipeline-assets-dev", - "bucket_key_enabled": false, - "cache_control": "", - "checksum_algorithm": null, - "checksum_crc32": "", - "checksum_crc32c": "", - "checksum_crc64nvme": "", - "checksum_sha1": "", - "checksum_sha256": "", - "content": null, - "content_base64": null, - "content_disposition": "", - "content_encoding": "", - "content_language": "", - "content_type": "application/x-yml", - "etag": "3865efc2d4cc99dd9393df77274d76c6", - "force_destroy": false, - "id": "image-pipeline-config/aws-linux/ssm.yml", - "key": "image-pipeline-config/aws-linux/ssm.yml", - "kms_key_id": "arn:aws-us-gov:kms:us-gov-west-1:229685449397:key/93beafaa-3398-491d-a168-c9c97cd09109", - "metadata": null, - "object_lock_legal_hold_status": "", - "object_lock_mode": "", - "object_lock_retain_until_date": "", - "override_provider": [], - "server_side_encryption": "aws:kms", - "source": "./templates/ssm.yml", - "source_hash": null, - "storage_class": "STANDARD", - "tags": null, - "tags_all": {}, - "version_id": "6fellBj1R_E9IVB8LZ36vF65KZ0WkDzA", - "website_redirect": "" + "arn": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "attachment_count": 1, + "description": "Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks", + "id": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "name": "aws-linux-service-catalog-launch-role-policy", + "name_prefix": "", + "path": "/", + "policy": "{\"Statement\":[{\"Action\":[\"s3:GetObject\",\"s3:GetObjectVersion\",\"s3:GetObjectAcl\",\"s3:GetObjectVersionAcl\",\"s3:GetObjectTagging\",\"s3:GetObjectVersionTagging\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/*\"],\"Sid\":\"S3TemplateAccess\"},{\"Action\":[\"kms:Decrypt\",\"kms:DescribeKey\",\"kms:GenerateDataKey\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"KMSDecryptAccess\"},{\"Action\":[\"s3:ListBucket\",\"s3:GetBucketLocation\",\"s3:GetBucketVersioning\",\"s3:GetBucketAcl\",\"s3:GetBucketPolicy\",\"s3:GetBucketPolicyStatus\",\"s3:GetBucketCORS\",\"s3:GetBucketWebsite\",\"s3:GetBucketLogging\",\"s3:GetBucketNotification\",\"s3:GetBucketTagging\",\"s3:GetEncryptionConfiguration\",\"s3:GetBucketOwnershipControls\",\"s3:GetBucketPublicAccessBlock\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates\"],\"Sid\":\"S3BucketAccess\"},{\"Action\":[\"cloudformation:CreateStack\",\"cloudformation:UpdateStack\",\"cloudformation:DeleteStack\",\"cloudformation:DescribeStacks\",\"cloudformation:DescribeStackEvents\",\"cloudformation:DescribeStackResource\",\"cloudformation:DescribeStackResources\",\"cloudformation:GetTemplate\",\"cloudformation:GetTemplateSummary\",\"cloudformation:ValidateTemplate\",\"cloudformation:ListStacks\",\"cloudformation:ListStackResources\",\"cloudformation:EstimateTemplateCost\",\"cloudformation:DescribeStackDriftDetectionStatus\",\"cloudformation:DetectStackDrift\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"CloudFormationAccess\"},{\"Action\":[\"iam:PassRole\"],\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":[\"cloudformation.amazonaws.com\",\"codebuild.amazonaws.com\",\"codepipeline.amazonaws.com\"]}},\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"IAMPassRole\"},{\"Action\":[\"iam:CreateRole\",\"iam:DeleteRole\",\"iam:GetRole\",\"iam:UpdateRole\",\"iam:PutRolePolicy\",\"iam:DeleteRolePolicy\",\"iam:GetRolePolicy\",\"iam:AttachRolePolicy\",\"iam:DetachRolePolicy\",\"iam:ListAttachedRolePolicies\",\"iam:ListRolePolicies\",\"kms:CreateKey\",\"kms:CreateAlias\",\"kms:DeleteAlias\",\"kms:DescribeKey\",\"kms:GetKeyPolicy\",\"kms:PutKeyPolicy\",\"kms:ScheduleKeyDeletion\",\"kms:TagResource\",\"kms:UntagResource\",\"s3:CreateBucket\",\"s3:DeleteBucket\",\"s3:GetBucketLocation\",\"s3:GetBucketVersioning\",\"s3:PutBucketVersioning\",\"s3:GetBucketPolicy\",\"s3:PutBucketPolicy\",\"s3:DeleteBucketPolicy\",\"s3:GetBucketNotification\",\"s3:PutBucketNotification\",\"s3:GetBucketTagging\",\"s3:PutBucketTagging\",\"s3:GetEncryptionConfiguration\",\"s3:PutEncryptionConfiguration\",\"codebuild:CreateProject\",\"codebuild:UpdateProject\",\"codebuild:DeleteProject\",\"codebuild:BatchGetProjects\",\"codebuild:StartBuild\",\"codebuild:StopBuild\",\"codebuild:ListBuildsForProject\",\"codebuild:BatchGetBuilds\",\"codepipeline:CreatePipeline\",\"codepipeline:UpdatePipeline\",\"codepipeline:DeletePipeline\",\"codepipeline:GetPipeline\",\"codepipeline:GetPipelineState\",\"codepipeline:StartPipelineExecution\",\"codepipeline:StopPipelineExecution\",\"codepipeline:ListPipelineExecutions\",\"codepipeline:PutApprovalResult\",\"ec2:CreateSecurityGroup\",\"ec2:DeleteSecurityGroup\",\"ec2:DescribeSecurityGroups\",\"ec2:AuthorizeSecurityGroupIngress\",\"ec2:AuthorizeSecurityGroupEgress\",\"ec2:RevokeSecurityGroupIngress\",\"ec2:RevokeSecurityGroupEgress\",\"ec2:DescribeVpcs\",\"ec2:DescribeSubnets\",\"ec2:CreateTags\",\"ec2:DeleteTags\",\"ec2:DescribeTags\",\"ec2:DescribeImages\",\"ec2:DescribeInstances\",\"ec2:RunInstances\",\"ec2:TerminateInstances\",\"ec2:CreateImage\",\"ec2:DeregisterImage\",\"ssm:GetParameter\",\"ssm:GetParameters\",\"ssm:DescribeParameters\",\"ssm:PutParameter\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ResourceCreationPermissions\"}],\"Version\":\"2012-10-17\"}", + "policy_id": "ANPATK6SR2K22RTKWYXYI", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + } }, "sensitive_attributes": [], - "private": "bnVsbA==" + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current", + "module.service_catalog.data.aws_partition.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_iam_role", + "name": "service_catalog_launch_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws-us-gov:iam::229685449397:role/aws-linux-service-catalog-launch-role", + "assume_role_policy": "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}", + "create_date": "2025-09-26T21:05:42Z", + "description": "", + "force_detach_policies": false, + "id": "aws-linux-service-catalog-launch-role", + "inline_policy": [], + "managed_policy_arns": [ + "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy" + ], + "max_session_duration": 3600, + "name": "aws-linux-service-catalog-launch-role", + "name_prefix": "", + "path": "/", + "permissions_boundary": "", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + }, + "unique_id": "AROATK6SR2K237KCMGRTO" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "service_catalog_launch_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "aws-linux-service-catalog-launch-role/arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "policy_arn": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "role": "aws-linux-service-catalog-launch-role" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current", + "module.service_catalog.aws_iam_policy.service_catalog_launch_policy", + "module.service_catalog.aws_iam_role.service_catalog_launch_role", + "module.service_catalog.data.aws_partition.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_servicecatalog_portfolio", + "name": "main", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws-us-gov:catalog:us-gov-west-1:229685449397:portfolio/port-xoyjh6eru6k5m", + "created_time": "2025-09-26T21:05:42Z", + "description": "Self-service deployment of AWS image building pipelines", + "id": "port-xoyjh6eru6k5m", + "name": "AWS Image Pipeline Portfolio", + "provider_name": "DevOps Team", + "region": "us-gov-west-1", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + }, + "timeouts": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxODAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current" + ] } ] } ], "check_results": [ + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.launch_role_arn", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.launch_role_arn", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.product_name", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.product_name", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.principal_arns", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.principal_arns", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.existing_portfolio_id", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.existing_portfolio_id", + "status": "pass" + } + ] + }, { "object_kind": "var", "config_addr": "var.builder_compute_type", diff --git a/terraform.tfstate.backup b/terraform.tfstate.backup index c92a7ea..b09e1e3 100644 --- a/terraform.tfstate.backup +++ b/terraform.tfstate.backup @@ -1,19 +1,1014 @@ { "version": 4, "terraform_version": "1.9.1", - "serial": 1312, - "lineage": "711db70b-e400-b85a-a4cc-d392b3e4bca9", - "outputs": {}, - "resources": [], + "serial": 314, + "lineage": "abad5d20-db36-5594-357e-eb275732a608", + "outputs": { + "buildspec_location": { + "value": "s3://csvd-229685449397-aws-linux-service-catalog-templates//buildspec.yml", + "type": "string" + }, + "service_catalog_all_principals": { + "value": [ + "arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0", + "arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0" + ], + "type": [ + "list", + "string" + ] + }, + "service_catalog_launch_role_arn": { + "value": "arn:aws-us-gov:iam::229685449397:role/aws-linux-service-catalog-launch-role", + "type": "string" + }, + "service_catalog_launch_role_name": { + "value": "aws-linux-service-catalog-launch-role", + "type": "string" + }, + "service_catalog_portfolio_arn": { + "value": "arn:aws-us-gov:catalog:us-gov-west-1:229685449397:portfolio/port-xoyjh6eru6k5m", + "type": "string" + }, + "service_catalog_portfolio_id": { + "value": "port-xoyjh6eru6k5m", + "type": "string" + }, + "service_catalog_principal_count": { + "value": 2, + "type": "number" + }, + "template_prefix": { + "value": "", + "type": "string" + }, + "template_url": { + "value": "https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//main.yml", + "type": "string" + }, + "uploaded_templates": { + "value": [ + "/main.yml", + "/kms.yml", + "/iam.yml", + "/s3.yml", + "/codebuild.yml", + "/codepipeline.yml" + ], + "type": [ + "tuple", + [ + "string", + "string", + "string", + "string", + "string", + "string" + ] + ] + } + }, + "resources": [ + { + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "account_id": "229685449397", + "arn": "arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov", + "id": "229685449397", + "user_id": "AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov" + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "data", + "type": "aws_partition", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "dns_suffix": "amazonaws.com", + "id": "aws-us-gov", + "partition": "aws-us-gov", + "reverse_dns_prefix": "com.amazonaws" + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "managed", + "type": "aws_cloudformation_stack", + "name": "image_pipeline", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "status": "tainted", + "schema_version": 0, + "attributes": { + "capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM" + ], + "disable_rollback": false, + "iam_role_arn": null, + "id": "arn:aws-us-gov:cloudformation:us-gov-west-1:229685449397:stack/aws-linux/8fbea170-9b1c-11f0-a6a5-0a956eea4b2f", + "name": "aws-linux", + "notification_arns": null, + "on_failure": null, + "outputs": null, + "parameters": { + "AdditionalSecurityGroupId": "sg-0641c697588b9aa6b", + "AnsibleBucketKey": "image-pipeline-ansible-playbooks.zip", + "AnsibleBucketName": "image-pipeline-assets-dev", + "AssetsBucketName": "csvd-229685449397-aws-linux-service-catalog-templates", + "BuilderComputeType": "BUILD_GENERAL1_SMALL", + "BuilderImage": "aws/codebuild/standard:7.0", + "BuildspecBucketName": "csvd-229685449397-aws-linux-service-catalog-templates", + "BuildspecObjectKey": "/buildspec.yml", + "CreateNewRole": "true", + "DockerBuild": "false", + "HttpProxy": "", + "HttpsProxy": "", + "NoProxy": "", + "PackerBucketKey": "image-pipeline-packer.zip", + "PackerBucketName": "image-pipeline-assets-dev", + "PackerFileName": "build.pkr.hcl", + "PackerVersion": "1.10.3", + "PipBucketKey": "image-pipeline-pip-config.zip", + "PipBucketName": "image-pipeline-assets-dev", + "ProjectName": "aws-linux", + "SSHUser": "ec2-user", + "SubnetIds": "subnet-04b80d7ce5199f82b", + "Troubleshoot": "false", + "VpcId": "vpc-00576a396ec570b94" + }, + "policy_body": null, + "policy_url": null, + "region": "us-gov-west-1", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + }, + "template_body": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", + "template_url": null, + "timeout_in_minutes": 30, + "timeouts": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInVwZGF0ZSI6MTgwMDAwMDAwMDAwMH19", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_bucket_policy.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.packer_config", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket", + "name": "service_catalog", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acceleration_status": "", + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_domain_name": "csvd-229685449397-aws-linux-service-catalog-templates.s3.amazonaws.com", + "bucket_prefix": "", + "bucket_region": "us-gov-west-1", + "bucket_regional_domain_name": "csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com", + "cors_rule": [], + "force_destroy": false, + "grant": [ + { + "id": "1cdbccee29c5305ac377a789c6f924db69ec7da804ad7d8303a495cf5eef9084", + "permissions": [ + "FULL_CONTROL" + ], + "type": "CanonicalUser", + "uri": "" + } + ], + "hosted_zone_id": "Z31GFT0UA1I2HV", + "id": "csvd-229685449397-aws-linux-service-catalog-templates", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "object_lock_enabled": false, + "policy": "", + "region": "us-gov-west-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [ + { + "rule": [ + { + "apply_server_side_encryption_by_default": [ + { + "kms_master_key_id": "", + "sse_algorithm": "AES256" + } + ], + "bucket_key_enabled": false + } + ] + } + ], + "tags": { + "Environment": "dev", + "Name": "aws-linux-service-catalog-templates", + "Owner": "platform-team", + "Project": "aws-linux" + }, + "tags_all": { + "Environment": "dev", + "Name": "aws-linux-service-catalog-templates", + "Owner": "platform-team", + "Project": "aws-linux" + }, + "timeouts": null, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjM2MDAwMDAwMDAwMDAsInJlYWQiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19", + "dependencies": [ + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_bucket_policy", + "name": "service_catalog", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "id": "csvd-229685449397-aws-linux-service-catalog-templates", + "policy": "{\"Statement\":[{\"Action\":[\"s3:*\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"servicecatalog.amazonaws.com\",\"cloudformation.amazonaws.com\"]},\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates\",\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/*\"],\"Sid\":\"AllowServiceCatalogAccess\"}],\"Version\":\"2012-10-17\"}", + "region": "us-gov-west-1" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "buildspec", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/buildspec.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "57c6bd18a9b8abae3de1fed9f1d8b6fc", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//buildspec.yml", + "key": "/buildspec.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/buildspec.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "codebuild_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/codebuild.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "f46d968aeec31a56e047fe8df1241f61", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//codebuild.yml", + "key": "/codebuild.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/codebuild.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "codepipeline_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/codepipeline.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "156f48bdaed0a3e6598fecc4e344efe4", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//codepipeline.yml", + "key": "/codepipeline.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/codepipeline.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "iam_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/iam.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "7aa982e1ce5827b21aab9881cc8e33a3", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//iam.yml", + "key": "/iam.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/iam.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "kms_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/kms.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "e844ff64293d224a748374b63e223d8d", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//kms.yml", + "key": "/kms.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/kms.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "main_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/main.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": "AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com//codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path", + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "760e87504162e1719b03d89a3df7829f", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//main.yml", + "key": "/main.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": null, + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "packer_config", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/image-pipeline-packer.zip", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/zip", + "etag": "53b73a7348956feca12db71b78520160", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates/image-pipeline-packer.zip", + "key": "image-pipeline-packer.zip", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./packer_config.zip", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "mode": "managed", + "type": "aws_s3_object", + "name": "s3_template", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "acl": null, + "arn": "arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/s3.yml", + "bucket": "csvd-229685449397-aws-linux-service-catalog-templates", + "bucket_key_enabled": false, + "cache_control": "", + "checksum_algorithm": null, + "checksum_crc32": "", + "checksum_crc32c": "", + "checksum_crc64nvme": "", + "checksum_sha1": "", + "checksum_sha256": "", + "content": null, + "content_base64": null, + "content_disposition": "", + "content_encoding": "", + "content_language": "", + "content_type": "application/x-yml", + "etag": "71b0638e9b13090eb68502fec3eb6b07", + "force_destroy": false, + "id": "csvd-229685449397-aws-linux-service-catalog-templates//s3.yml", + "key": "/s3.yml", + "kms_key_id": null, + "metadata": null, + "object_lock_legal_hold_status": "", + "object_lock_mode": "", + "object_lock_retain_until_date": "", + "override_provider": [], + "region": "us-gov-west-1", + "server_side_encryption": "AES256", + "source": "./templates/s3.yml", + "source_hash": null, + "storage_class": "STANDARD", + "tags": null, + "tags_all": {}, + "version_id": "", + "website_redirect": "" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_caller_identity", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "account_id": "229685449397", + "arn": "arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov", + "id": "229685449397", + "user_id": "AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_partition", + "name": "current", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "dns_suffix": "amazonaws.com", + "id": "aws-us-gov", + "partition": "aws-us-gov", + "reverse_dns_prefix": "com.amazonaws" + }, + "sensitive_attributes": [] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "data", + "type": "aws_servicecatalog_portfolio", + "name": "existing", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_iam_policy", + "name": "service_catalog_launch_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "attachment_count": 0, + "description": "Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks", + "id": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "name": "aws-linux-service-catalog-launch-role-policy", + "name_prefix": "", + "path": "/", + "policy": "{\"Statement\":[{\"Action\":[\"s3:GetObject\",\"s3:GetObjectVersion\",\"s3:GetObjectAcl\",\"s3:GetObjectVersionAcl\",\"s3:GetObjectTagging\",\"s3:GetObjectVersionTagging\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates/*\"],\"Sid\":\"S3TemplateAccess\"},{\"Action\":[\"kms:Decrypt\",\"kms:DescribeKey\",\"kms:GenerateDataKey\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"KMSDecryptAccess\"},{\"Action\":[\"s3:ListBucket\",\"s3:GetBucketLocation\",\"s3:GetBucketVersioning\",\"s3:GetBucketAcl\",\"s3:GetBucketPolicy\",\"s3:GetBucketPolicyStatus\",\"s3:GetBucketCORS\",\"s3:GetBucketWebsite\",\"s3:GetBucketLogging\",\"s3:GetBucketNotification\",\"s3:GetBucketTagging\",\"s3:GetEncryptionConfiguration\",\"s3:GetBucketOwnershipControls\",\"s3:GetBucketPublicAccessBlock\"],\"Effect\":\"Allow\",\"Resource\":[\"arn:aws-us-gov:s3:::csvd-229685449397-aws-linux-service-catalog-templates\"],\"Sid\":\"S3BucketAccess\"},{\"Action\":[\"cloudformation:CreateStack\",\"cloudformation:UpdateStack\",\"cloudformation:DeleteStack\",\"cloudformation:DescribeStacks\",\"cloudformation:DescribeStackEvents\",\"cloudformation:DescribeStackResource\",\"cloudformation:DescribeStackResources\",\"cloudformation:GetTemplate\",\"cloudformation:GetTemplateSummary\",\"cloudformation:ValidateTemplate\",\"cloudformation:ListStacks\",\"cloudformation:ListStackResources\",\"cloudformation:EstimateTemplateCost\",\"cloudformation:DescribeStackDriftDetectionStatus\",\"cloudformation:DetectStackDrift\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"CloudFormationAccess\"},{\"Action\":[\"iam:PassRole\"],\"Condition\":{\"StringEquals\":{\"iam:PassedToService\":[\"cloudformation.amazonaws.com\",\"codebuild.amazonaws.com\",\"codepipeline.amazonaws.com\"]}},\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"IAMPassRole\"},{\"Action\":[\"iam:CreateRole\",\"iam:DeleteRole\",\"iam:GetRole\",\"iam:UpdateRole\",\"iam:PutRolePolicy\",\"iam:DeleteRolePolicy\",\"iam:GetRolePolicy\",\"iam:AttachRolePolicy\",\"iam:DetachRolePolicy\",\"iam:ListAttachedRolePolicies\",\"iam:ListRolePolicies\",\"kms:CreateKey\",\"kms:CreateAlias\",\"kms:DeleteAlias\",\"kms:DescribeKey\",\"kms:GetKeyPolicy\",\"kms:PutKeyPolicy\",\"kms:ScheduleKeyDeletion\",\"kms:TagResource\",\"kms:UntagResource\",\"s3:CreateBucket\",\"s3:DeleteBucket\",\"s3:GetBucketLocation\",\"s3:GetBucketVersioning\",\"s3:PutBucketVersioning\",\"s3:GetBucketPolicy\",\"s3:PutBucketPolicy\",\"s3:DeleteBucketPolicy\",\"s3:GetBucketNotification\",\"s3:PutBucketNotification\",\"s3:GetBucketTagging\",\"s3:PutBucketTagging\",\"s3:GetEncryptionConfiguration\",\"s3:PutEncryptionConfiguration\",\"codebuild:CreateProject\",\"codebuild:UpdateProject\",\"codebuild:DeleteProject\",\"codebuild:BatchGetProjects\",\"codebuild:StartBuild\",\"codebuild:StopBuild\",\"codebuild:ListBuildsForProject\",\"codebuild:BatchGetBuilds\",\"codepipeline:CreatePipeline\",\"codepipeline:UpdatePipeline\",\"codepipeline:DeletePipeline\",\"codepipeline:GetPipeline\",\"codepipeline:GetPipelineState\",\"codepipeline:StartPipelineExecution\",\"codepipeline:StopPipelineExecution\",\"codepipeline:ListPipelineExecutions\",\"codepipeline:PutApprovalResult\",\"ec2:CreateSecurityGroup\",\"ec2:DeleteSecurityGroup\",\"ec2:DescribeSecurityGroups\",\"ec2:AuthorizeSecurityGroupIngress\",\"ec2:AuthorizeSecurityGroupEgress\",\"ec2:RevokeSecurityGroupIngress\",\"ec2:RevokeSecurityGroupEgress\",\"ec2:DescribeVpcs\",\"ec2:DescribeSubnets\",\"ec2:CreateTags\",\"ec2:DeleteTags\",\"ec2:DescribeTags\",\"ec2:DescribeImages\",\"ec2:DescribeInstances\",\"ec2:RunInstances\",\"ec2:TerminateInstances\",\"ec2:CreateImage\",\"ec2:DeregisterImage\",\"ssm:GetParameter\",\"ssm:GetParameters\",\"ssm:DescribeParameters\",\"ssm:PutParameter\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"ResourceCreationPermissions\"}],\"Version\":\"2012-10-17\"}", + "policy_id": "ANPATK6SR2K22RTKWYXYI", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + } + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current", + "module.service_catalog.data.aws_partition.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_iam_role", + "name": "service_catalog_launch_role", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws-us-gov:iam::229685449397:role/aws-linux-service-catalog-launch-role", + "assume_role_policy": "{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}", + "create_date": "2025-09-26T21:05:42Z", + "description": "", + "force_detach_policies": false, + "id": "aws-linux-service-catalog-launch-role", + "inline_policy": [], + "managed_policy_arns": [], + "max_session_duration": 3600, + "name": "aws-linux-service-catalog-launch-role", + "name_prefix": "", + "path": "/", + "permissions_boundary": "", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + }, + "unique_id": "AROATK6SR2K237KCMGRTO" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_iam_role_policy_attachment", + "name": "service_catalog_launch_policy", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "id": "aws-linux-service-catalog-launch-role/arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "policy_arn": "arn:aws-us-gov:iam::229685449397:policy/aws-linux-service-catalog-launch-role-policy", + "role": "aws-linux-service-catalog-launch-role" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current", + "module.service_catalog.aws_iam_policy.service_catalog_launch_policy", + "module.service_catalog.aws_iam_role.service_catalog_launch_role", + "module.service_catalog.data.aws_partition.current" + ] + } + ] + }, + { + "module": "module.service_catalog", + "mode": "managed", + "type": "aws_servicecatalog_portfolio", + "name": "main", + "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", + "instances": [ + { + "index_key": 0, + "schema_version": 0, + "attributes": { + "arn": "arn:aws-us-gov:catalog:us-gov-west-1:229685449397:portfolio/port-xoyjh6eru6k5m", + "created_time": "2025-09-26T21:05:42Z", + "description": "Self-service deployment of AWS image building pipelines", + "id": "port-xoyjh6eru6k5m", + "name": "AWS Image Pipeline Portfolio", + "provider_name": "DevOps Team", + "region": "us-gov-west-1", + "tags": { + "Environment": "dev", + "Owner": "platform-team" + }, + "tags_all": { + "Environment": "dev", + "Owner": "platform-team" + }, + "timeouts": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxODAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "aws_s3_bucket.service_catalog", + "aws_s3_object.buildspec", + "aws_s3_object.codebuild_template", + "aws_s3_object.codepipeline_template", + "aws_s3_object.iam_template", + "aws_s3_object.kms_template", + "aws_s3_object.main_template", + "aws_s3_object.s3_template", + "data.aws_caller_identity.current" + ] + } + ] + } + ], "check_results": [ { "object_kind": "var", "config_addr": "var.builder_compute_type", - "status": "unknown", + "status": "pass", "objects": [ { "object_addr": "var.builder_compute_type", - "status": "unknown" + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.launch_role_arn", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.launch_role_arn", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.existing_portfolio_id", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.existing_portfolio_id", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.product_name", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.product_name", + "status": "pass" + } + ] + }, + { + "object_kind": "var", + "config_addr": "module.service_catalog.var.principal_arns", + "status": "pass", + "objects": [ + { + "object_addr": "module.service_catalog.var.principal_arns", + "status": "pass" } ] } diff --git a/terraform.tfvars b/terraform.tfvars index 4f1522a..8a68b47 100644 --- a/terraform.tfvars +++ b/terraform.tfvars @@ -1,35 +1,42 @@ -aws_region = "us-gov-west-1" -stack_name = "aws-linux" -project_name = "aws-linux" -create_new_role = true -ssh_user = "ec2-user" -troubleshoot = false -builder_compute_type = "BUILD_GENERAL1_SMALL" -builder_image = "aws/codebuild/standard:7.0" -packer_version = "1.10.3" -assets_bucket_name = "image-pipeline-assets-dev" -docker_build = false -packer_file_name = "build.pkr.hcl" # Parameterized Packer file name -disable_rollback = false -timeout_in_minutes = 30 -buildspec_bucket_name = "image-pipeline-assets-dev" -buildspec_bucket_key = "buildspec.yml" +aws_region = "us-gov-west-1" +stack_name = "aws-linux" +project_name = "aws-linux" +create_new_role = true +ssh_user = "ec2-user" +troubleshoot = false +builder_compute_type = "BUILD_GENERAL1_SMALL" +builder_image = "aws/codebuild/standard:7.0" +packer_version = "1.10.3" +docker_build = false +packer_file_name = "build.pkr.hcl" # Parameterized Packer file name +disable_rollback = false +timeout_in_minutes = 30 +buildspec_bucket_key = "buildspec.yml" # S3 bucket for CloudFormation templates template_bucket = "image-pipeline-assets-dev" +template_prefix = "" source_ami_ssm_path = "/enterprise/ami/rhel9" # VPC and subnet configuration from amazon-linux.yml -vpc_id = "vpc-00576a396ec570b94" -subnet_ids = ["subnet-04b80d7ce5199f82b"] - +vpc_id = "vpc-00576a396ec570b94" +subnet_ids = ["subnet-04b80d7ce5199f82b"] +global_assets_bucket = "image-pipeline-assets-dev" # Source buckets configuration from amazon-linux.yml -packer_bucket_name = "image-pipeline-assets-dev" packer_bucket_key = "image-pipeline-packer.zip" -ansible_bucket_name = "image-pipeline-assets-dev" ansible_bucket_key = "image-pipeline-ansible-playbooks.zip" -pip_bucket_name = "image-pipeline-assets-dev" pip_bucket_key = "image-pipeline-pip-config.zip" additional_security_group_id = "sg-0641c697588b9aa6b" tags = { Environment = "dev" Owner = "platform-team" -} \ No newline at end of file +} + +# Service Catalog Configuration +enable_service_catalog = true +portfolio_name = "AWS Image Pipeline Portfolio" +portfolio_description = "Self-service deployment of AWS image building pipelines" +portfolio_provider_name = "DevOps Team" +product_name = "AWS Image Building Pipeline" +product_description = "Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer" +product_owner = "Platform Engineering" +# Note: service_catalog_bucket_name will be dynamically generated in main.tf using data.aws_caller_identity +# Note: principal_arns will be dynamically generated in main.tf using data.aws_caller_identity \ No newline at end of file diff --git a/terraform_data_dirs/default/modules/modules.json b/terraform_data_dirs/default/modules/modules.json new file mode 100644 index 0000000..9ce9641 --- /dev/null +++ b/terraform_data_dirs/default/modules/modules.json @@ -0,0 +1 @@ +{"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"service_catalog","Source":"../terraform-cfn-service-catalog","Dir":"../terraform-cfn-service-catalog"}]} \ No newline at end of file diff --git a/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.13.0/linux_amd64 b/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.13.0/linux_amd64 new file mode 120000 index 0000000..1ac1742 --- /dev/null +++ b/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.13.0/linux_amd64 @@ -0,0 +1 @@ +/data/terraform/workspaces/arnol377/terraform-plugin-cache/registry.terraform.io/hashicorp/aws/6.13.0/linux_amd64 \ No newline at end of file diff --git a/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.14.1/linux_amd64 b/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.14.1/linux_amd64 new file mode 120000 index 0000000..4788624 --- /dev/null +++ b/terraform_data_dirs/default/providers/registry.terraform.io/hashicorp/aws/6.14.1/linux_amd64 @@ -0,0 +1 @@ +/data/terraform/workspaces/arnol377/terraform-plugin-cache/registry.terraform.io/hashicorp/aws/6.14.1/linux_amd64 \ No newline at end of file diff --git a/terraform_plan_aws-image-pipeline-cfn_20250926_131314.json b/terraform_plan_aws-image-pipeline-cfn_20250926_131314.json new file mode 100644 index 0000000..64e745e --- /dev/null +++ b/terraform_plan_aws-image-pipeline-cfn_20250926_131314.json @@ -0,0 +1 @@ +{"format_version":"1.2","terraform_version":"1.9.1","variables":{"additional_security_group_id":{"value":"sg-0641c697588b9aa6b"},"ami_name":{"value":"aws-linux-2-image"},"ansible_bucket_key":{"value":"image-pipeline-ansible-playbooks.zip"},"ansible_bucket_name":{"value":"image-pipeline-assets-dev"},"assets_bucket_name":{"value":"image-pipeline-assets-dev"},"aws_region":{"value":"us-gov-west-1"},"builder_compute_type":{"value":"BUILD_GENERAL1_SMALL"},"builder_image":{"value":"aws/codebuild/standard:7.0"},"buildspec_bucket_key":{"value":"buildspec.yml"},"buildspec_bucket_name":{"value":"image-pipeline-assets-dev"},"create_new_role":{"value":true},"deploy_stack":{"value":true},"disable_rollback":{"value":false},"docker_build":{"value":false},"enable_service_catalog":{"value":true},"http_proxy":{"value":""},"https_proxy":{"value":""},"instance_type":{"value":"t3.medium"},"no_proxy":{"value":""},"packer_bucket_key":{"value":"image-pipeline-packer.zip"},"packer_bucket_name":{"value":"image-pipeline-assets-dev"},"packer_file_name":{"value":"build.pkr.hcl"},"packer_version":{"value":"1.10.3"},"pip_bucket_key":{"value":"image-pipeline-pip-config.zip"},"pip_bucket_name":{"value":"image-pipeline-assets-dev"},"playbook":{"value":"hello-world.yaml"},"portfolio_description":{"value":"Self-service deployment of AWS image building pipelines"},"portfolio_name":{"value":"AWS Image Pipeline Portfolio"},"portfolio_provider_name":{"value":"DevOps Team"},"principal_arns":{"value":[]},"product_description":{"value":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer"},"product_name":{"value":"AWS Image Building Pipeline"},"product_owner":{"value":"Platform Engineering"},"project_name":{"value":"aws-linux"},"shared_accounts":{"value":""},"source_ami_ssm_path":{"value":"/enterprise/ami/rhel9"},"ssh_user":{"value":"ec2-user"},"stack_name":{"value":"aws-linux"},"subnet_ids":{"value":["subnet-04b80d7ce5199f82b"]},"tags":{"value":{"Environment":"dev","Owner":"platform-team"}},"template_bucket":{"value":"image-pipeline-assets-dev"},"template_prefix":{"value":"image-pipeline-config/aws-linux"},"timeout_in_minutes":{"value":30},"troubleshoot":{"value":false},"vpc_id":{"value":"vpc-00576a396ec570b94"}},"planned_values":{"outputs":{"artifact_bucket_arn":{"sensitive":false},"artifact_bucket_name":{"sensitive":false},"buildspec_location":{"sensitive":false,"type":"string","value":"s3://image-pipeline-assets-dev/buildspec.yml"},"code_pipeline_arn":{"sensitive":false},"code_pipeline_name":{"sensitive":false},"iam_role_arn":{"sensitive":false},"kms_key_arn":{"sensitive":false},"managed_parameters_path":{"sensitive":false},"role_name":{"sensitive":false},"secrets_path":{"sensitive":false},"security_group_id":{"sensitive":false},"service_catalog_all_principals":{"sensitive":false,"type":["list","string"],"value":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"]},"service_catalog_current_user_arn":{"sensitive":false,"type":"dynamic","value":null},"service_catalog_launch_constraint_id":{"sensitive":false},"service_catalog_launch_role_arn":{"sensitive":false},"service_catalog_launch_role_name":{"sensitive":false,"type":"string","value":"aws-linux-service-catalog-launch-role"},"service_catalog_portfolio_arn":{"sensitive":false},"service_catalog_portfolio_id":{"sensitive":false},"service_catalog_principal_count":{"sensitive":false,"type":"number","value":2},"service_catalog_product_arn":{"sensitive":false},"service_catalog_product_id":{"sensitive":false},"service_catalog_template_url":{"sensitive":false,"type":"string","value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml"},"stack_id":{"sensitive":false},"stack_outputs":{"sensitive":false},"template_bucket":{"sensitive":false,"type":"string","value":"image-pipeline-assets-dev"},"template_prefix":{"sensitive":false,"type":"string","value":"image-pipeline-config/aws-linux"},"template_url":{"sensitive":false,"type":"string","value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml"},"uploaded_templates":{"sensitive":false,"type":["tuple",["string","string","string","string","string","string"]],"value":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linuxkms.yml","image-pipeline-config/aws-linuxiam.yml","image-pipeline-config/aws-linuxs3.yml","image-pipeline-config/aws-linuxcodebuild.yml","image-pipeline-config/aws-linuxcodepipeline.yml"]}},"root_module":{"resources":[{"address":"aws_cloudformation_stack.image_pipeline[0]","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"capabilities":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],"disable_rollback":false,"iam_role_arn":null,"name":"aws-linux","notification_arns":null,"on_failure":null,"parameters":{"AdditionalSecurityGroupId":"sg-0641c697588b9aa6b","AnsibleBucketKey":"image-pipeline-ansible-playbooks.zip","AnsibleBucketName":"image-pipeline-assets-dev","AssetsBucketName":"image-pipeline-assets-dev","BuilderComputeType":"BUILD_GENERAL1_SMALL","BuilderImage":"aws/codebuild/standard:7.0","BuildspecBucketName":"image-pipeline-assets-dev","BuildspecObjectKey":"image-pipeline-config/aws-linuxbuildspec.yml","CreateNewRole":"true","DockerBuild":"false","HttpProxy":"","HttpsProxy":"","NoProxy":"","PackerBucketKey":"image-pipeline-packer.zip","PackerBucketName":"image-pipeline-assets-dev","PackerFileName":"build.pkr.hcl","PackerVersion":"1.10.3","PipBucketKey":"image-pipeline-pip-config.zip","PipBucketName":"image-pipeline-assets-dev","ProjectName":"aws-linux","SSHUser":"ec2-user","SubnetIds":"subnet-04b80d7ce5199f82b","Troubleshoot":"false","VpcId":"vpc-00576a396ec570b94"},"policy_url":null,"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"template_body":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","template_url":null,"timeout_in_minutes":30,"timeouts":null},"sensitive_values":{"capabilities":[false,false],"outputs":{},"parameters":{},"tags":{},"tags_all":{}}},{"address":"aws_s3_bucket.service_catalog[0]","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","force_destroy":false,"region":"us-gov-west-1","tags":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"tags_all":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"timeouts":null},"sensitive_values":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{},"tags_all":{},"versioning":[],"website":[]}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"57c6bd18a9b8abae3de1fed9f1d8b6fc","force_destroy":false,"key":"image-pipeline-config/aws-linuxbuildspec.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/buildspec.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"f46d968aeec31a56e047fe8df1241f61","force_destroy":false,"key":"image-pipeline-config/aws-linuxcodebuild.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codebuild.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"156f48bdaed0a3e6598fecc4e344efe4","force_destroy":false,"key":"image-pipeline-config/aws-linuxcodepipeline.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codepipeline.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"7aa982e1ce5827b21aab9881cc8e33a3","force_destroy":false,"key":"image-pipeline-config/aws-linuxiam.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/iam.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"e844ff64293d224a748374b63e223d8d","force_destroy":false,"key":"image-pipeline-config/aws-linuxkms.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/kms.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"3c7f48a47fddc5a6cf8dccc0fa26d8fd","force_destroy":false,"key":"image-pipeline-config/aws-linuxmain.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":null,"source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/zip","etag":"53b73a7348956feca12db71b78520160","force_destroy":false,"key":"image-pipeline-config/aws-linuxpacker-config.zip","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./packer_config.zip","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"71b0638e9b13090eb68502fec3eb6b07","force_destroy":false,"key":"image-pipeline-config/aws-linuxs3.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/s3.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}}],"child_modules":[{"resources":[{"address":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"description":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks","name":"aws-linux-service-catalog-launch-role-policy","path":"/","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"sensitive_values":{"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"assume_role_policy":"{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}","description":null,"force_detach_policies":false,"max_session_duration":3600,"name":"aws-linux-service-catalog-launch-role","path":"/","permissions_boundary":null,"tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"sensitive_values":{"inline_policy":[],"managed_policy_arns":[],"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_iam_role_policy_attachment.service_catalog_launch_policy[0]","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"role":"aws-linux-service-catalog-launch-role"},"sensitive_values":{}},{"address":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","description":"Launch constraint for AWS Image Building Pipeline","region":"us-gov-west-1","timeouts":null,"type":"LAUNCH"},"sensitive_values":{}},{"address":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"description":"Self-service deployment of AWS image building pipelines","name":"AWS Image Pipeline Portfolio","provider_name":"DevOps Team","region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null},"sensitive_values":{"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_product.main","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","description":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","name":"AWS Image Building Pipeline","owner":"Platform Engineering","provisioning_artifact_parameters":[{"description":"AWS Image Building Pipeline v1.0","disable_template_validation":false,"name":"v1.0","template_physical_id":null,"template_url":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"CLOUD_FORMATION_TEMPLATE"}],"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null,"type":"CLOUD_FORMATION_TEMPLATE"},"sensitive_values":{"provisioning_artifact_parameters":[{}],"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","region":"us-gov-west-1","source_portfolio_id":null,"timeouts":null},"sensitive_values":{}},{"address":"module.service_catalog[0].data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"sensitive_values":{}},{"address":"module.service_catalog[0].data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"sensitive_values":{}}],"address":"module.service_catalog[0]"}]}},"resource_changes":[{"address":"aws_cloudformation_stack.image_pipeline[0]","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"capabilities":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],"disable_rollback":false,"iam_role_arn":null,"name":"aws-linux","notification_arns":null,"on_failure":null,"parameters":{"AdditionalSecurityGroupId":"sg-0641c697588b9aa6b","AnsibleBucketKey":"image-pipeline-ansible-playbooks.zip","AnsibleBucketName":"image-pipeline-assets-dev","AssetsBucketName":"image-pipeline-assets-dev","BuilderComputeType":"BUILD_GENERAL1_SMALL","BuilderImage":"aws/codebuild/standard:7.0","BuildspecBucketName":"image-pipeline-assets-dev","BuildspecObjectKey":"image-pipeline-config/aws-linuxbuildspec.yml","CreateNewRole":"true","DockerBuild":"false","HttpProxy":"","HttpsProxy":"","NoProxy":"","PackerBucketKey":"image-pipeline-packer.zip","PackerBucketName":"image-pipeline-assets-dev","PackerFileName":"build.pkr.hcl","PackerVersion":"1.10.3","PipBucketKey":"image-pipeline-pip-config.zip","PipBucketName":"image-pipeline-assets-dev","ProjectName":"aws-linux","SSHUser":"ec2-user","SubnetIds":"subnet-04b80d7ce5199f82b","Troubleshoot":"false","VpcId":"vpc-00576a396ec570b94"},"policy_url":null,"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"template_body":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","template_url":null,"timeout_in_minutes":30,"timeouts":null},"after_unknown":{"capabilities":[false,false],"id":true,"outputs":true,"parameters":{},"policy_body":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"capabilities":[false,false],"outputs":{},"parameters":{},"tags":{},"tags_all":{}}}},{"address":"aws_s3_bucket.service_catalog[0]","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","force_destroy":false,"region":"us-gov-west-1","tags":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"tags_all":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"timeouts":null},"after_unknown":{"acceleration_status":true,"acl":true,"arn":true,"bucket_domain_name":true,"bucket_prefix":true,"bucket_region":true,"bucket_regional_domain_name":true,"cors_rule":true,"grant":true,"hosted_zone_id":true,"id":true,"lifecycle_rule":true,"logging":true,"object_lock_configuration":true,"object_lock_enabled":true,"policy":true,"replication_configuration":true,"request_payer":true,"server_side_encryption_configuration":true,"tags":{},"tags_all":{},"versioning":true,"website":true,"website_domain":true,"website_endpoint":true},"before_sensitive":false,"after_sensitive":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{},"tags_all":{},"versioning":[],"website":[]}}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"57c6bd18a9b8abae3de1fed9f1d8b6fc","force_destroy":false,"key":"image-pipeline-config/aws-linuxbuildspec.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/buildspec.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"f46d968aeec31a56e047fe8df1241f61","force_destroy":false,"key":"image-pipeline-config/aws-linuxcodebuild.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codebuild.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"156f48bdaed0a3e6598fecc4e344efe4","force_destroy":false,"key":"image-pipeline-config/aws-linuxcodepipeline.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codepipeline.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"7aa982e1ce5827b21aab9881cc8e33a3","force_destroy":false,"key":"image-pipeline-config/aws-linuxiam.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/iam.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"e844ff64293d224a748374b63e223d8d","force_destroy":false,"key":"image-pipeline-config/aws-linuxkms.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/kms.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"3c7f48a47fddc5a6cf8dccc0fa26d8fd","force_destroy":false,"key":"image-pipeline-config/aws-linuxmain.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":null,"source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/zip","etag":"53b73a7348956feca12db71b78520160","force_destroy":false,"key":"image-pipeline-config/aws-linuxpacker-config.zip","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./packer_config.zip","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"71b0638e9b13090eb68502fec3eb6b07","force_destroy":false,"key":"image-pipeline-config/aws-linuxs3.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/s3.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"module.service_catalog[0].data.aws_caller_identity.current","module_address":"module.service_catalog[0]","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["read"],"before":null,"after":{},"after_unknown":{"account_id":true,"arn":true,"id":true,"user_id":true},"before_sensitive":false,"after_sensitive":{}},"action_reason":"read_because_dependency_pending"},{"address":"module.service_catalog[0].data.aws_partition.current","module_address":"module.service_catalog[0]","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["read"],"before":null,"after":{},"after_unknown":{"dns_suffix":true,"id":true,"partition":true,"reverse_dns_prefix":true},"before_sensitive":false,"after_sensitive":{}},"action_reason":"read_because_dependency_pending"},{"address":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"description":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks","name":"aws-linux-service-catalog-launch-role-policy","path":"/","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"after_unknown":{"arn":true,"attachment_count":true,"id":true,"name_prefix":true,"policy":true,"policy_id":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"assume_role_policy":"{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}","description":null,"force_detach_policies":false,"max_session_duration":3600,"name":"aws-linux-service-catalog-launch-role","path":"/","permissions_boundary":null,"tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"after_unknown":{"arn":true,"create_date":true,"id":true,"inline_policy":true,"managed_policy_arns":true,"name_prefix":true,"tags":{},"tags_all":{},"unique_id":true},"before_sensitive":false,"after_sensitive":{"inline_policy":[],"managed_policy_arns":[],"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_iam_role_policy_attachment.service_catalog_launch_policy[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"role":"aws-linux-service-catalog-launch-role"},"after_unknown":{"id":true,"policy_arn":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","description":"Launch constraint for AWS Image Building Pipeline","region":"us-gov-west-1","timeouts":null,"type":"LAUNCH"},"after_unknown":{"id":true,"owner":true,"parameters":true,"portfolio_id":true,"product_id":true,"status":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"description":"Self-service deployment of AWS image building pipelines","name":"AWS Image Pipeline Portfolio","provider_name":"DevOps Team","region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null},"after_unknown":{"arn":true,"created_time":true,"id":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_servicecatalog_product.main","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","description":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","name":"AWS Image Building Pipeline","owner":"Platform Engineering","provisioning_artifact_parameters":[{"description":"AWS Image Building Pipeline v1.0","disable_template_validation":false,"name":"v1.0","template_physical_id":null,"template_url":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"CLOUD_FORMATION_TEMPLATE"}],"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null,"type":"CLOUD_FORMATION_TEMPLATE"},"after_unknown":{"arn":true,"created_time":true,"distributor":true,"has_default_path":true,"id":true,"provisioning_artifact_parameters":[{}],"status":true,"support_description":true,"support_email":true,"support_url":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"provisioning_artifact_parameters":[{}],"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","region":"us-gov-west-1","source_portfolio_id":null,"timeouts":null},"after_unknown":{"id":true,"portfolio_id":true,"product_id":true},"before_sensitive":false,"after_sensitive":{}}}],"output_changes":{"artifact_bucket_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"artifact_bucket_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"buildspec_location":{"actions":["create"],"before":null,"after":"s3://image-pipeline-assets-dev/buildspec.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"code_pipeline_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"code_pipeline_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"iam_role_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"kms_key_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"managed_parameters_path":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"role_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"secrets_path":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"security_group_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_all_principals":{"actions":["create"],"before":null,"after":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"],"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_current_user_arn":{"actions":["no-op"],"before":null,"after":null,"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_constraint_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_role_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_role_name":{"actions":["create"],"before":null,"after":"aws-linux-service-catalog-launch-role","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_portfolio_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_portfolio_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_principal_count":{"actions":["create"],"before":null,"after":2,"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_product_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_product_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_template_url":{"actions":["create"],"before":null,"after":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"stack_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"stack_outputs":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"template_bucket":{"actions":["create"],"before":null,"after":"image-pipeline-assets-dev","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"template_prefix":{"actions":["create"],"before":null,"after":"image-pipeline-config/aws-linux","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"template_url":{"actions":["create"],"before":null,"after":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"uploaded_templates":{"actions":["create"],"before":null,"after":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linuxkms.yml","image-pipeline-config/aws-linuxiam.yml","image-pipeline-config/aws-linuxs3.yml","image-pipeline-config/aws-linuxcodebuild.yml","image-pipeline-config/aws-linuxcodepipeline.yml"],"after_unknown":false,"before_sensitive":false,"after_sensitive":false}},"prior_state":{"format_version":"1.0","terraform_version":"1.9.1","values":{"outputs":{"buildspec_location":{"sensitive":false,"value":"s3://image-pipeline-assets-dev/buildspec.yml","type":"string"},"service_catalog_all_principals":{"sensitive":false,"value":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"],"type":["list","string"]},"service_catalog_launch_role_name":{"sensitive":false,"value":"aws-linux-service-catalog-launch-role","type":"string"},"service_catalog_principal_count":{"sensitive":false,"value":2,"type":"number"},"service_catalog_template_url":{"sensitive":false,"value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"string"},"template_bucket":{"sensitive":false,"value":"image-pipeline-assets-dev","type":"string"},"template_prefix":{"sensitive":false,"value":"image-pipeline-config/aws-linux","type":"string"},"template_url":{"sensitive":false,"value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"string"},"uploaded_templates":{"sensitive":false,"value":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linuxkms.yml","image-pipeline-config/aws-linuxiam.yml","image-pipeline-config/aws-linuxs3.yml","image-pipeline-config/aws-linuxcodebuild.yml","image-pipeline-config/aws-linuxcodepipeline.yml"],"type":["tuple",["string","string","string","string","string","string"]]}},"root_module":{"resources":[{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"account_id":"229685449397","arn":"arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov","id":"229685449397","user_id":"AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov"},"sensitive_values":{}},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"dns_suffix":"amazonaws.com","id":"aws-us-gov","partition":"aws-us-gov","reverse_dns_prefix":"com.amazonaws"},"sensitive_values":{}}]}}},"configuration":{"provider_config":{"archive":{"name":"archive","full_name":"registry.terraform.io/hashicorp/archive","version_constraint":"~\u003e 2.0"},"aws":{"name":"aws","full_name":"registry.terraform.io/hashicorp/aws","version_constraint":"~\u003e 6.0","expressions":{"region":{"references":["var.aws_region"]}}}},"root_module":{"outputs":{"artifact_bucket_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ArtifactBucketArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the S3 bucket storing pipeline artifacts"},"artifact_bucket_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ArtifactBucketName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the S3 bucket storing pipeline artifacts"},"buildspec_location":{"expression":{"references":["var.buildspec_bucket_name","var.buildspec_bucket_key"]},"description":"Location of the buildspec file in S3"},"code_pipeline_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"CodePipelineArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the created CodePipeline"},"code_pipeline_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"CodePipelineName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the created CodePipeline"},"iam_role_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"IamArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the CodePipeline IAM role"},"kms_key_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"KMSKeyArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the KMS key used for encryption"},"managed_parameters_path":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ManagedParameters\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Base path for SSM parameters managed by this pipeline"},"role_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"RoleName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the CodePipeline IAM role"},"secrets_path":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"SecretsPath\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Base path for Secrets Manager secrets managed by this pipeline"},"security_group_id":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"SecurityGroupId\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ID of the security group used by CodeBuild"},"service_catalog_all_principals":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].principal_associations","module.service_catalog[0]"]},"description":"List of all principal ARNs with access to the Service Catalog portfolio (if enabled)"},"service_catalog_current_user_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].current_user_arn","module.service_catalog[0]"]},"description":"ARN of the current authenticated user that was automatically granted access (if Service Catalog is enabled)"},"service_catalog_launch_constraint_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_constraint_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog launch constraint (if enabled)"},"service_catalog_launch_role_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_role_arn","module.service_catalog[0]"]},"description":"ARN of the IAM role used for Service Catalog launch constraint (if enabled)"},"service_catalog_launch_role_name":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_role_name","module.service_catalog[0]"]},"description":"Name of the IAM role used for Service Catalog launch constraint (if enabled and created)"},"service_catalog_portfolio_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].portfolio_arn","module.service_catalog[0]"]},"description":"ARN of the Service Catalog portfolio (if Service Catalog is enabled)"},"service_catalog_portfolio_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].portfolio_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog portfolio (if Service Catalog is enabled)"},"service_catalog_principal_count":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].principal_association_count","module.service_catalog[0]"]},"description":"Total number of principals with access to the Service Catalog portfolio (if enabled)"},"service_catalog_product_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].product_arn","module.service_catalog[0]"]},"description":"ARN of the Service Catalog product (if Service Catalog is enabled)"},"service_catalog_product_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].product_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog product (if Service Catalog is enabled)"},"service_catalog_template_url":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].template_url","module.service_catalog[0]"]},"description":"URL of the CloudFormation template used by Service Catalog (if enabled)"},"stack_id":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].id","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ID of the CloudFormation stack"},"stack_outputs":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"A map of outputs from the CloudFormation stack"},"template_bucket":{"expression":{"references":["var.template_bucket"]},"description":"S3 bucket containing the CloudFormation templates"},"template_prefix":{"expression":{"references":["var.template_prefix"]},"description":"Prefix/folder path for CloudFormation templates in S3"},"template_url":{"expression":{"references":["local.service_catalog_s3_base_url"]},"description":"URL of the main CloudFormation template in S3"},"uploaded_templates":{"expression":{"references":["aws_s3_object.main_template.key","aws_s3_object.main_template","aws_s3_object.kms_template.key","aws_s3_object.kms_template","aws_s3_object.iam_template.key","aws_s3_object.iam_template","aws_s3_object.s3_template.key","aws_s3_object.s3_template","aws_s3_object.codebuild_template.key","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template.key","aws_s3_object.codepipeline_template"]},"description":"List of uploaded template files"}},"resources":[{"address":"aws_cloudformation_stack.image_pipeline","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","provider_config_key":"aws","expressions":{"capabilities":{"constant_value":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"]},"disable_rollback":{"references":["var.disable_rollback"]},"name":{"references":["var.stack_name"]},"parameters":{"references":["var.project_name","var.create_new_role","var.ssh_user","var.troubleshoot","var.builder_compute_type","var.builder_image","var.packer_version","var.assets_bucket_name","var.docker_build","var.vpc_id","var.subnet_ids","var.assets_bucket_name","local.available_packer_zip","var.assets_bucket_name","local.ansible_config_s3_key","var.assets_bucket_name","local.pip_config_s3_key","var.packer_file_name","var.template_bucket","local.buildspec_s3_key","var.additional_security_group_id","var.http_proxy","var.https_proxy","var.no_proxy"]},"tags":{"references":["var.tags"]},"template_body":{"references":["local.main_template_content"]},"timeout_in_minutes":{"references":["var.timeout_in_minutes"]}},"schema_version":0,"count_expression":{"references":["var.deploy_stack"]},"depends_on":["aws_s3_object.main_template","aws_s3_object.kms_template","aws_s3_object.iam_template","aws_s3_object.s3_template","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template","aws_s3_object.buildspec","aws_s3_object.packer_config"]},{"address":"aws_s3_bucket.service_catalog","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"tags":{"references":["var.tags","var.project_name","var.project_name"]}},"schema_version":0,"count_expression":{"references":["var.enable_service_catalog"]}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["local.buildspec_s3_key"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content":{"references":["local.main_template_content"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["local.main_template_content"]},"key":{"references":["var.template_prefix"]}},"schema_version":0},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/zip"},"etag":{"references":["path.module"]},"key":{"references":["local.packer_config_s3_key"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_config_key":"aws","schema_version":0}],"module_calls":{"service_catalog":{"source":"../terraform-cfn-service-catalog","expressions":{"additional_s3_buckets":{"references":["var.enable_service_catalog","aws_s3_bucket.service_catalog[0].id","aws_s3_bucket.service_catalog[0]","aws_s3_bucket.service_catalog","var.assets_bucket_name"]},"aws_region":{"references":["var.aws_region"]},"create_launch_role":{"constant_value":true},"create_portfolio":{"constant_value":true},"enable_service_catalog_s3_access":{"constant_value":false},"include_current_user":{"constant_value":false},"launch_role_name":{"references":["var.project_name"]},"portfolio_description":{"references":["var.portfolio_description"]},"portfolio_name":{"references":["var.portfolio_name"]},"portfolio_provider_name":{"references":["var.portfolio_provider_name"]},"principal_arns":{"references":["local.dynamic_principal_arns"]},"product_description":{"references":["var.product_description"]},"product_name":{"references":["var.product_name"]},"product_owner":{"references":["var.product_owner"]},"provisioning_artifact_description":{"constant_value":"AWS Image Building Pipeline v1.0"},"provisioning_artifact_name":{"constant_value":"v1.0"},"tags":{"references":["var.tags"]},"template_bucket":{"references":["var.enable_service_catalog","aws_s3_bucket.service_catalog[0].id","aws_s3_bucket.service_catalog[0]","aws_s3_bucket.service_catalog","var.template_bucket"]},"template_url":{"references":["local.service_catalog_template_vars.main_template_url","local.service_catalog_template_vars"]}},"count_expression":{"references":["var.enable_service_catalog"]},"module":{"outputs":{"additional_principals":{"expression":{"references":["var.principal_arns"]},"description":"List of additional principal ARNs (manual association required)"},"current_user_account_id":{"expression":{"references":["data.aws_caller_identity.current.account_id","data.aws_caller_identity.current"]},"description":"Account ID of the current authenticated user"},"current_user_arn":{"expression":{"references":["var.include_current_user","data.aws_caller_identity.current.arn","data.aws_caller_identity.current"]},"description":"ARN of the current authenticated user/role (if include_current_user is enabled)"},"launch_constraint_id":{"expression":{"references":["var.create_launch_role","var.launch_role_arn","aws_servicecatalog_constraint.launch[0].id","aws_servicecatalog_constraint.launch[0]","aws_servicecatalog_constraint.launch"]},"description":"ID of the Service Catalog launch constraint (if launch_role_arn was provided)"},"launch_role_arn":{"expression":{"references":["local.final_launch_role_arn"]},"description":"ARN of the IAM role used for the launch constraint"},"launch_role_created":{"expression":{"references":["var.create_launch_role"]},"description":"Whether the launch role was created by this module"},"launch_role_name":{"expression":{"references":["var.create_launch_role","aws_iam_role.service_catalog_launch_role[0].name","aws_iam_role.service_catalog_launch_role[0]","aws_iam_role.service_catalog_launch_role"]},"description":"Name of the IAM role used for the launch constraint (if created by this module)"},"launch_role_policy_arn":{"expression":{"references":["var.create_launch_role","aws_iam_policy.service_catalog_launch_policy[0].arn","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"description":"ARN of the managed policy attached to the launch role (if created by this module)"},"launch_role_policy_name":{"expression":{"references":["var.create_launch_role","aws_iam_policy.service_catalog_launch_policy[0].name","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"description":"Name of the managed policy attached to the launch role (if created by this module)"},"manual_association_instructions":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main"]},"description":"Instructions for manually associating principals with the portfolio"},"portfolio_arn":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].arn","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].arn","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"ARN of the Service Catalog portfolio (created or existing)"},"portfolio_created_time":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].created_time","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].created_time","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Time when the portfolio was created (null for existing portfolios)"},"portfolio_creation_mode":{"expression":{"references":["var.create_portfolio"]},"description":"Whether the portfolio was created by this module or was existing"},"portfolio_description":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].description","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].description","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Description of the Service Catalog portfolio"},"portfolio_id":{"expression":{"references":["local.portfolio_id"]},"description":"ID of the Service Catalog portfolio (created or existing)"},"portfolio_name":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].name","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Name of the Service Catalog portfolio (created or existing)"},"portfolio_product_association_id":{"expression":{"references":["aws_servicecatalog_product_portfolio_association.main.id","aws_servicecatalog_product_portfolio_association.main"]},"description":"ID of the portfolio-product association"},"portfolio_provider_name":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].provider_name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].provider_name","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Provider name of the Service Catalog portfolio"},"principal_association_count":{"expression":{"references":["local.all_principal_arns"]},"description":"Total number of principals that need manual association"},"principal_associations":{"expression":{"references":["local.all_principal_arns"]},"description":"List of all principal ARNs that would have access to the portfolio (manual association required)"},"product_arn":{"expression":{"references":["aws_servicecatalog_product.main.arn","aws_servicecatalog_product.main"]},"description":"ARN of the Service Catalog product"},"product_created_time":{"expression":{"references":["aws_servicecatalog_product.main.created_time","aws_servicecatalog_product.main"]},"description":"Time when the Service Catalog product was created"},"product_has_default_path":{"expression":{"references":["aws_servicecatalog_product.main.has_default_path","aws_servicecatalog_product.main"]},"description":"Whether the product has a default path"},"product_id":{"expression":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]},"description":"ID of the Service Catalog product"},"product_name":{"expression":{"references":["aws_servicecatalog_product.main.name","aws_servicecatalog_product.main"]},"description":"Name of the Service Catalog product"},"product_status":{"expression":{"references":["aws_servicecatalog_product.main.status","aws_servicecatalog_product.main"]},"description":"Status of the Service Catalog product"},"s3_access_policy_arn":{"expression":{"references":["var.grant_s3_access_to_principals","aws_iam_policy.principal_s3_access[0].arn","aws_iam_policy.principal_s3_access[0]","aws_iam_policy.principal_s3_access"]},"description":"ARN of the optional S3 access policy for principals (if created)"},"template_s3_etag":{"expression":{"references":["var.template_content","aws_s3_object.cloudformation_template[0].etag","aws_s3_object.cloudformation_template[0]","aws_s3_object.cloudformation_template"]},"description":"ETag of the uploaded CloudFormation template (if template_content was used)"},"template_s3_key":{"expression":{"references":["var.template_content","local.template_key"]},"description":"S3 key of the uploaded CloudFormation template (if template_content was used)"},"template_url":{"expression":{"references":["local.final_template_url"]},"description":"URL of the CloudFormation template used by the Service Catalog product"}},"resources":[{"address":"aws_iam_policy.principal_s3_access","mode":"managed","type":"aws_iam_policy","name":"principal_s3_access","provider_config_key":"aws","expressions":{"description":{"constant_value":"Allows Service Catalog principals to read CloudFormation templates from S3"},"name":{"references":["local.sanitized_product_name"]},"policy":{"references":["local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current","local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.grant_s3_access_to_principals"]}},{"address":"aws_iam_policy.service_catalog_launch_policy","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","provider_config_key":"aws","expressions":{"description":{"constant_value":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks"},"name":{"references":["local.launch_role_name"]},"policy":{"references":["local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current","local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_iam_role.service_catalog_launch_role","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","provider_config_key":"aws","expressions":{"assume_role_policy":{},"name":{"references":["local.launch_role_name"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_iam_role_policy_attachment.service_catalog_launch_policy","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","provider_config_key":"aws","expressions":{"policy_arn":{"references":["aws_iam_policy.service_catalog_launch_policy[0].arn","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"role":{"references":["aws_iam_role.service_catalog_launch_role[0].name","aws_iam_role.service_catalog_launch_role[0]","aws_iam_role.service_catalog_launch_role"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_s3_object.cloudformation_template","mode":"managed","type":"aws_s3_object","name":"cloudformation_template","provider_config_key":"aws","expressions":{"bucket":{"references":["var.template_bucket"]},"content":{"references":["var.template_content"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["var.template_content"]},"key":{"references":["local.template_key"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.template_content"]}},{"address":"aws_servicecatalog_constraint.launch","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","provider_config_key":"aws","expressions":{"description":{"references":["var.product_name"]},"parameters":{"references":["local.final_launch_role_arn"]},"portfolio_id":{"references":["local.portfolio_id"]},"product_id":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]},"type":{"constant_value":"LAUNCH"}},"schema_version":0,"count_expression":{"references":["var.create_launch_role","var.launch_role_arn"]},"depends_on":["aws_servicecatalog_product_portfolio_association.main","aws_iam_role.service_catalog_launch_role"]},{"address":"aws_servicecatalog_portfolio.main","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","provider_config_key":"aws","expressions":{"description":{"references":["var.portfolio_description"]},"name":{"references":["var.portfolio_name"]},"provider_name":{"references":["var.portfolio_provider_name"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_portfolio"]}},{"address":"aws_servicecatalog_product.main","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_config_key":"aws","expressions":{"description":{"references":["var.product_description"]},"distributor":{"references":["var.product_distributor"]},"name":{"references":["var.product_name"]},"owner":{"references":["var.product_owner"]},"provisioning_artifact_parameters":[{"description":{"references":["var.provisioning_artifact_description"]},"disable_template_validation":{"references":["var.disable_template_validation"]},"name":{"references":["var.provisioning_artifact_name"]},"template_url":{"references":["local.final_template_url"]},"type":{"constant_value":"CLOUD_FORMATION_TEMPLATE"}}],"support_description":{"references":["var.support_description"]},"support_email":{"references":["var.support_email"]},"support_url":{"references":["var.support_url"]},"tags":{"references":["var.tags"]},"type":{"constant_value":"CLOUD_FORMATION_TEMPLATE"}},"schema_version":0,"depends_on":["aws_s3_object.cloudformation_template"]},{"address":"aws_servicecatalog_product_portfolio_association.main","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_config_key":"aws","expressions":{"portfolio_id":{"references":["local.portfolio_id"]},"product_id":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]}},"schema_version":0},{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_servicecatalog_portfolio.existing","mode":"data","type":"aws_servicecatalog_portfolio","name":"existing","provider_config_key":"aws","expressions":{"id":{"references":["var.existing_portfolio_id"]}},"schema_version":0,"count_expression":{"references":["var.create_portfolio"]}}],"variables":{"additional_s3_buckets":{"default":[],"description":"List of additional S3 bucket names that the launch role should have access to (for buildspec, packer, ansible, etc.)"},"auto_detect_current_user":{"default":true,"description":"Whether to automatically detect and include the current user only if it's a permanent IAM role (not AWS SSO/temporary credentials)."},"aws_region":{"default":null,"description":"AWS region for S3 URL construction (required for GovCloud compatibility)"},"create_launch_role":{"default":true,"description":"Whether to create a Service Catalog launch role. If false, launch_role_arn must be provided."},"create_portfolio":{"default":true,"description":"Whether to create a new portfolio (true) or use an existing one (false)"},"disable_template_validation":{"default":false,"description":"Whether to disable CloudFormation template validation"},"enable_service_catalog_s3_access":{"default":true,"description":"Enable S3 bucket policy to grant Service Catalog service access to templates"},"existing_portfolio_id":{"default":null,"description":"ID of existing Service Catalog portfolio to use. Required when create_portfolio is false."},"grant_s3_access_to_principals":{"default":false,"description":"Whether to create an IAM policy granting principals read access to CloudFormation templates in S3"},"include_current_user":{"default":false,"description":"Whether to automatically include the current authenticated user/role in the portfolio access. Set to false when using AWS SSO or roles with limited CloudFormation permissions."},"launch_role_arn":{"default":null,"description":"ARN of IAM role for Service Catalog launch constraint. Required for CloudFormation products with nested stacks."},"launch_role_name":{"default":null,"description":"Name for the Service Catalog launch role when create_launch_role is true"},"portfolio_description":{"default":"Self-service deployment of standardized infrastructure components","description":"Description of the Service Catalog portfolio (used only when creating new portfolio)"},"portfolio_name":{"default":"Self-Service Infrastructure","description":"Name of the Service Catalog portfolio (used only when creating new portfolio)"},"portfolio_provider_name":{"default":"Platform Engineering","description":"Name of the portfolio provider/owner (used only when creating new portfolio)"},"principal_arns":{"default":[],"description":"List of additional IAM principal ARNs (users, roles, groups) to grant access to the portfolio. The current authenticated role is automatically included when possible."},"product_description":{"default":"","description":"Description of the Service Catalog product"},"product_distributor":{"default":null,"description":"Distributor (vendor) of the Service Catalog product"},"product_name":{"description":"Name of the Service Catalog product"},"product_owner":{"default":"Platform Team","description":"Owner of the Service Catalog product"},"provisioning_artifact_description":{"default":"Initial version","description":"Description of the provisioning artifact"},"provisioning_artifact_name":{"default":"v1.0","description":"Name of the provisioning artifact (version)"},"support_description":{"default":null,"description":"Support information about the product"},"support_email":{"default":null,"description":"Support email for the product"},"support_url":{"default":null,"description":"Support URL for the product"},"tags":{"default":{},"description":"A map of tags to assign to all resources"},"template_bucket":{"description":"S3 bucket name where CloudFormation templates will be stored"},"template_content":{"default":null,"description":"CloudFormation template content as a string. Mutually exclusive with template_url."},"template_prefix":{"default":"","description":"Prefix/folder path for CloudFormation templates in S3"},"template_url":{"default":null,"description":"S3 URL to existing CloudFormation template. Mutually exclusive with template_content."}}},"depends_on":["aws_s3_bucket.service_catalog","aws_s3_object.main_template","aws_s3_object.kms_template","aws_s3_object.iam_template","aws_s3_object.s3_template","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template","aws_s3_object.buildspec"]}},"variables":{"additional_security_group_id":{"default":"","description":"ID of an additional pre-existing security group to attach to the CodeBuild job"},"ami_name":{"default":"aws-linux-2-image","description":"Name to give the created AMI"},"ansible_bucket_key":{"description":"Key (path) to the Ansible roles archive in S3"},"ansible_bucket_name":{"description":"Name of the S3 bucket containing Ansible roles"},"assets_bucket_name":{"default":"image-pipeline-assets-dev","description":"Name of the S3 bucket to store deployment artifacts"},"aws_region":{"default":"us-gov-west-1","description":"The AWS region to deploy resources"},"builder_compute_type":{"default":"BUILD_GENERAL1_SMALL","description":"CodeBuild compute resources type"},"builder_image":{"default":"aws/codebuild/amazonlinux2-x86_64-standard:3.0","description":"Docker image to use for CodeBuild"},"buildspec_bucket_key":{"default":"buildspec.yml","description":"Key (path) to the buildspec file in S3"},"buildspec_bucket_name":{"default":"image-pipeline-assets-dev","description":"Name of the S3 bucket containing the buildspec file"},"create_new_role":{"default":true,"description":"Whether to create a new IAM role (true) or use existing roles (false)"},"deploy_stack":{"default":true,"description":"Whether to deploy the CloudFormation stack"},"disable_rollback":{"default":false,"description":"Set to true to disable rollback of the stack if stack creation failed"},"docker_build":{"default":false,"description":"Whether to enable Docker image building"},"enable_service_catalog":{"default":true,"description":"Whether to create Service Catalog resources for self-service deployment"},"http_proxy":{"default":"","description":"HTTP proxy configuration for CodeBuild"},"https_proxy":{"default":"","description":"HTTPS proxy configuration for CodeBuild"},"instance_type":{"default":"t3.medium","description":"Instance type to use for building images"},"no_proxy":{"default":"","description":"NO_PROXY configuration for CodeBuild"},"packer_bucket_key":{"description":"Key (path) to the Packer templates archive in S3"},"packer_bucket_name":{"description":"Name of the S3 bucket containing Packer templates"},"packer_file_name":{"default":"build.pkr.hcl","description":"Name of the Packer file to build"},"packer_version":{"default":"1.10.3","description":"Version of HashiCorp Packer to use"},"pip_bucket_key":{"description":"Key (path) to the pip configuration archive in S3"},"pip_bucket_name":{"description":"Name of the S3 bucket containing pip configuration"},"playbook":{"default":"hello-world.yaml","description":"Ansible playbook to run during AMI creation"},"portfolio_description":{"default":"Self-service deployment of AWS image building pipelines","description":"Description of the Service Catalog portfolio"},"portfolio_name":{"default":"AWS Image Pipeline Portfolio","description":"Name of the Service Catalog portfolio"},"portfolio_provider_name":{"default":"DevOps Team","description":"Name of the portfolio provider/owner"},"principal_arns":{"default":[],"description":"List of IAM principal ARNs (users, roles, groups) to grant access to the Service Catalog portfolio"},"product_description":{"default":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","description":"Description of the Service Catalog product"},"product_name":{"default":"AWS Image Building Pipeline","description":"Name of the Service Catalog product"},"product_owner":{"default":"Platform Engineering","description":"Owner of the Service Catalog product"},"project_name":{"description":"Unique name for this project"},"shared_accounts":{"default":"","description":"Comma-separated list of AWS account IDs to share the AMI with"},"source_ami_ssm_path":{"description":"SSM parameter path to fetch the source AMI ID from"},"ssh_user":{"default":"ec2-user","description":"SSH username for connecting to build instances"},"stack_name":{"default":"image-pipeline","description":"Name of the CloudFormation stack"},"subnet_ids":{"description":"Subnets where CodeBuild will run"},"tags":{"default":{},"description":"A map of tags to assign to resources"},"template_bucket":{"description":"S3 bucket containing the packaged CloudFormation templates"},"template_prefix":{"default":"","description":"Prefix/folder path for CloudFormation templates in S3"},"timeout_in_minutes":{"default":30,"description":"The amount of time that can pass before the stack status becomes CREATE_FAILED"},"troubleshoot":{"default":false,"description":"Enable troubleshooting mode for builds"},"vpc_id":{"description":"VPC where resources will be created"}}}},"relevant_attributes":[{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["id"]},{"resource":"aws_s3_object.iam_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["created_time"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ArtifactBucketName"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","KMSKeyArn"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs"]},{"resource":"module.service_catalog[0].data.aws_partition.current","attribute":["partition"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["arn"]},{"resource":"aws_s3_bucket.service_catalog[0]","attribute":["id"]},{"resource":"data.aws_partition.current","attribute":["partition"]},{"resource":"aws_s3_object.main_template","attribute":["key"]},{"resource":"aws_s3_object.codebuild_template","attribute":["key"]},{"resource":"aws_s3_object.codepipeline_template","attribute":["key"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["name"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","CodePipelineArn"]},{"resource":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","attribute":["arn"]},{"resource":"aws_s3_object.kms_template","attribute":["key"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["description"]},{"resource":"module.service_catalog[0].data.aws_caller_identity.current","attribute":["arn"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["id"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["status"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ArtifactBucketArn"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","SecurityGroupId"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["created_time"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","RoleName"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","IamArn"]},{"resource":"aws_s3_object.s3_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["description"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["arn"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["has_default_path"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","attribute":["id"]},{"resource":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","attribute":["id"]},{"resource":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","attribute":["arn"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["provider_name"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["provider_name"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ManagedParameters"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["id"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["id"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","CodePipelineName"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","SecretsPath"]},{"resource":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","attribute":["name"]},{"resource":"module.service_catalog[0].data.aws_caller_identity.current","attribute":["account_id"]},{"resource":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","attribute":["name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["arn"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["created_time"]},{"resource":"data.aws_caller_identity.current","attribute":["account_id"]}],"checks":[{"address":{"kind":"var","module":"module.service_catalog","name":"existing_portfolio_id","to_display":"module.service_catalog.var.existing_portfolio_id"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.existing_portfolio_id"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"launch_role_arn","to_display":"module.service_catalog.var.launch_role_arn"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.launch_role_arn"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"principal_arns","to_display":"module.service_catalog.var.principal_arns"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.principal_arns"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"product_name","to_display":"module.service_catalog.var.product_name"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.product_name"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"template_url","to_display":"module.service_catalog.var.template_url"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.template_url"},"status":"pass"}]},{"address":{"kind":"var","name":"builder_compute_type","to_display":"var.builder_compute_type"},"status":"pass","instances":[{"address":{"to_display":"var.builder_compute_type"},"status":"pass"}]}],"timestamp":"2025-09-26T17:13:29Z","applyable":true,"complete":true,"errored":false} diff --git a/terraform_plan_aws-image-pipeline-cfn_20250926_132116.json b/terraform_plan_aws-image-pipeline-cfn_20250926_132116.json new file mode 100644 index 0000000..4e3114e --- /dev/null +++ b/terraform_plan_aws-image-pipeline-cfn_20250926_132116.json @@ -0,0 +1 @@ +{"format_version":"1.2","terraform_version":"1.9.1","variables":{"additional_security_group_id":{"value":"sg-0641c697588b9aa6b"},"ami_name":{"value":"aws-linux-2-image"},"ansible_bucket_key":{"value":"image-pipeline-ansible-playbooks.zip"},"ansible_bucket_name":{"value":"image-pipeline-assets-dev"},"assets_bucket_name":{"value":"image-pipeline-assets-dev"},"aws_region":{"value":"us-gov-west-1"},"builder_compute_type":{"value":"BUILD_GENERAL1_SMALL"},"builder_image":{"value":"aws/codebuild/standard:7.0"},"buildspec_bucket_key":{"value":"buildspec.yml"},"buildspec_bucket_name":{"value":"image-pipeline-assets-dev"},"create_new_role":{"value":true},"deploy_stack":{"value":true},"disable_rollback":{"value":false},"docker_build":{"value":false},"enable_service_catalog":{"value":true},"http_proxy":{"value":""},"https_proxy":{"value":""},"instance_type":{"value":"t3.medium"},"no_proxy":{"value":""},"packer_bucket_key":{"value":"image-pipeline-packer.zip"},"packer_bucket_name":{"value":"image-pipeline-assets-dev"},"packer_file_name":{"value":"build.pkr.hcl"},"packer_version":{"value":"1.10.3"},"pip_bucket_key":{"value":"image-pipeline-pip-config.zip"},"pip_bucket_name":{"value":"image-pipeline-assets-dev"},"playbook":{"value":"hello-world.yaml"},"portfolio_description":{"value":"Self-service deployment of AWS image building pipelines"},"portfolio_name":{"value":"AWS Image Pipeline Portfolio"},"portfolio_provider_name":{"value":"DevOps Team"},"principal_arns":{"value":[]},"product_description":{"value":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer"},"product_name":{"value":"AWS Image Building Pipeline"},"product_owner":{"value":"Platform Engineering"},"project_name":{"value":"aws-linux"},"shared_accounts":{"value":""},"source_ami_ssm_path":{"value":"/enterprise/ami/rhel9"},"ssh_user":{"value":"ec2-user"},"stack_name":{"value":"aws-linux"},"subnet_ids":{"value":["subnet-04b80d7ce5199f82b"]},"tags":{"value":{"Environment":"dev","Owner":"platform-team"}},"template_bucket":{"value":"image-pipeline-assets-dev"},"template_prefix":{"value":"image-pipeline-config/aws-linux"},"timeout_in_minutes":{"value":30},"troubleshoot":{"value":false},"vpc_id":{"value":"vpc-00576a396ec570b94"}},"planned_values":{"outputs":{"artifact_bucket_arn":{"sensitive":false},"artifact_bucket_name":{"sensitive":false},"buildspec_location":{"sensitive":false,"type":"string","value":"s3://image-pipeline-assets-dev/buildspec.yml"},"code_pipeline_arn":{"sensitive":false},"code_pipeline_name":{"sensitive":false},"iam_role_arn":{"sensitive":false},"kms_key_arn":{"sensitive":false},"managed_parameters_path":{"sensitive":false},"role_name":{"sensitive":false},"secrets_path":{"sensitive":false},"security_group_id":{"sensitive":false},"service_catalog_all_principals":{"sensitive":false,"type":["list","string"],"value":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"]},"service_catalog_current_user_arn":{"sensitive":false,"type":"dynamic","value":null},"service_catalog_launch_constraint_id":{"sensitive":false},"service_catalog_launch_role_arn":{"sensitive":false},"service_catalog_launch_role_name":{"sensitive":false,"type":"string","value":"aws-linux-service-catalog-launch-role"},"service_catalog_portfolio_arn":{"sensitive":false},"service_catalog_portfolio_id":{"sensitive":false},"service_catalog_principal_count":{"sensitive":false,"type":"number","value":2},"service_catalog_product_arn":{"sensitive":false},"service_catalog_product_id":{"sensitive":false},"service_catalog_template_url":{"sensitive":false,"type":"string","value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml"},"stack_id":{"sensitive":false},"stack_outputs":{"sensitive":false},"template_bucket":{"sensitive":false,"type":"string","value":"image-pipeline-assets-dev"},"template_prefix":{"sensitive":false,"type":"string","value":"image-pipeline-config/aws-linux"},"template_url":{"sensitive":false,"type":"string","value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml"},"uploaded_templates":{"sensitive":false,"type":["tuple",["string","string","string","string","string","string"]],"value":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linux/kms.yml","image-pipeline-config/aws-linux/iam.yml","image-pipeline-config/aws-linux/s3.yml","image-pipeline-config/aws-linux/codebuild.yml","image-pipeline-config/aws-linux/codepipeline.yml"]}},"root_module":{"resources":[{"address":"aws_cloudformation_stack.image_pipeline[0]","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"capabilities":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],"disable_rollback":false,"iam_role_arn":null,"name":"aws-linux","notification_arns":null,"on_failure":null,"parameters":{"AdditionalSecurityGroupId":"sg-0641c697588b9aa6b","AnsibleBucketKey":"image-pipeline-config/aws-linux/image-pipeline-ansible-playbooks.zip","AnsibleBucketName":"image-pipeline-assets-dev","AssetsBucketName":"image-pipeline-assets-dev","BuilderComputeType":"BUILD_GENERAL1_SMALL","BuilderImage":"aws/codebuild/standard:7.0","BuildspecBucketName":"image-pipeline-assets-dev","BuildspecObjectKey":"image-pipeline-config/aws-linux/buildspec.yml","CreateNewRole":"true","DockerBuild":"false","HttpProxy":"","HttpsProxy":"","NoProxy":"","PackerBucketKey":"image-pipeline-config/aws-linux/image-pipeline-packer.zip","PackerBucketName":"image-pipeline-assets-dev","PackerFileName":"build.pkr.hcl","PackerVersion":"1.10.3","PipBucketKey":"image-pipeline-config/aws-linux/image-pipeline-pip-config.zip","PipBucketName":"image-pipeline-assets-dev","ProjectName":"aws-linux","SSHUser":"ec2-user","SubnetIds":"subnet-04b80d7ce5199f82b","Troubleshoot":"false","VpcId":"vpc-00576a396ec570b94"},"policy_url":null,"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"template_body":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","template_url":null,"timeout_in_minutes":30,"timeouts":null},"sensitive_values":{"capabilities":[false,false],"outputs":{},"parameters":{},"tags":{},"tags_all":{}}},{"address":"aws_s3_bucket.service_catalog[0]","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","force_destroy":false,"region":"us-gov-west-1","tags":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"tags_all":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"timeouts":null},"sensitive_values":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{},"tags_all":{},"versioning":[],"website":[]}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"57c6bd18a9b8abae3de1fed9f1d8b6fc","force_destroy":false,"key":"image-pipeline-config/aws-linux/buildspec.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/buildspec.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"f46d968aeec31a56e047fe8df1241f61","force_destroy":false,"key":"image-pipeline-config/aws-linux/codebuild.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codebuild.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"156f48bdaed0a3e6598fecc4e344efe4","force_destroy":false,"key":"image-pipeline-config/aws-linux/codepipeline.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codepipeline.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"7aa982e1ce5827b21aab9881cc8e33a3","force_destroy":false,"key":"image-pipeline-config/aws-linux/iam.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/iam.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"e844ff64293d224a748374b63e223d8d","force_destroy":false,"key":"image-pipeline-config/aws-linux/kms.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/kms.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"3c7f48a47fddc5a6cf8dccc0fa26d8fd","force_destroy":false,"key":"image-pipeline-config/aws-linuxmain.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":null,"source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/zip","etag":"53b73a7348956feca12db71b78520160","force_destroy":false,"key":"image-pipeline-config/aws-linux/image-pipeline-packer.zip","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./packer_config.zip","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"71b0638e9b13090eb68502fec3eb6b07","force_destroy":false,"key":"image-pipeline-config/aws-linux/s3.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/s3.yml","source_hash":null,"tags":null,"website_redirect":null},"sensitive_values":{"override_provider":[],"tags_all":{}}}],"child_modules":[{"resources":[{"address":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"description":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks","name":"aws-linux-service-catalog-launch-role-policy","path":"/","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"sensitive_values":{"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"assume_role_policy":"{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}","description":null,"force_detach_policies":false,"max_session_duration":3600,"name":"aws-linux-service-catalog-launch-role","path":"/","permissions_boundary":null,"tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"sensitive_values":{"inline_policy":[],"managed_policy_arns":[],"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_iam_role_policy_attachment.service_catalog_launch_policy[0]","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"role":"aws-linux-service-catalog-launch-role"},"sensitive_values":{}},{"address":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","description":"Launch constraint for AWS Image Building Pipeline","region":"us-gov-west-1","timeouts":null,"type":"LAUNCH"},"sensitive_values":{}},{"address":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"description":"Self-service deployment of AWS image building pipelines","name":"AWS Image Pipeline Portfolio","provider_name":"DevOps Team","region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null},"sensitive_values":{"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_product.main","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","description":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","name":"AWS Image Building Pipeline","owner":"Platform Engineering","provisioning_artifact_parameters":[{"description":"AWS Image Building Pipeline v1.0","disable_template_validation":false,"name":"v1.0","template_physical_id":null,"template_url":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"CLOUD_FORMATION_TEMPLATE"}],"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null,"type":"CLOUD_FORMATION_TEMPLATE"},"sensitive_values":{"provisioning_artifact_parameters":[{}],"tags":{},"tags_all":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"accept_language":"en","region":"us-gov-west-1","source_portfolio_id":null,"timeouts":null},"sensitive_values":{}},{"address":"module.service_catalog[0].data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"sensitive_values":{}},{"address":"module.service_catalog[0].data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"sensitive_values":{}}],"address":"module.service_catalog[0]"}]}},"resource_changes":[{"address":"aws_cloudformation_stack.image_pipeline[0]","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"capabilities":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"],"disable_rollback":false,"iam_role_arn":null,"name":"aws-linux","notification_arns":null,"on_failure":null,"parameters":{"AdditionalSecurityGroupId":"sg-0641c697588b9aa6b","AnsibleBucketKey":"image-pipeline-config/aws-linux/image-pipeline-ansible-playbooks.zip","AnsibleBucketName":"image-pipeline-assets-dev","AssetsBucketName":"image-pipeline-assets-dev","BuilderComputeType":"BUILD_GENERAL1_SMALL","BuilderImage":"aws/codebuild/standard:7.0","BuildspecBucketName":"image-pipeline-assets-dev","BuildspecObjectKey":"image-pipeline-config/aws-linux/buildspec.yml","CreateNewRole":"true","DockerBuild":"false","HttpProxy":"","HttpsProxy":"","NoProxy":"","PackerBucketKey":"image-pipeline-config/aws-linux/image-pipeline-packer.zip","PackerBucketName":"image-pipeline-assets-dev","PackerFileName":"build.pkr.hcl","PackerVersion":"1.10.3","PipBucketKey":"image-pipeline-config/aws-linux/image-pipeline-pip-config.zip","PipBucketName":"image-pipeline-assets-dev","ProjectName":"aws-linux","SSHUser":"ec2-user","SubnetIds":"subnet-04b80d7ce5199f82b","Troubleshoot":"false","VpcId":"vpc-00576a396ec570b94"},"policy_url":null,"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"template_body":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","template_url":null,"timeout_in_minutes":30,"timeouts":null},"after_unknown":{"capabilities":[false,false],"id":true,"outputs":true,"parameters":{},"policy_body":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"capabilities":[false,false],"outputs":{},"parameters":{},"tags":{},"tags_all":{}}}},{"address":"aws_s3_bucket.service_catalog[0]","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","force_destroy":false,"region":"us-gov-west-1","tags":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"tags_all":{"Environment":"dev","Name":"aws-linux-service-catalog-templates","Owner":"platform-team","Project":"aws-linux"},"timeouts":null},"after_unknown":{"acceleration_status":true,"acl":true,"arn":true,"bucket_domain_name":true,"bucket_prefix":true,"bucket_region":true,"bucket_regional_domain_name":true,"cors_rule":true,"grant":true,"hosted_zone_id":true,"id":true,"lifecycle_rule":true,"logging":true,"object_lock_configuration":true,"object_lock_enabled":true,"policy":true,"replication_configuration":true,"request_payer":true,"server_side_encryption_configuration":true,"tags":{},"tags_all":{},"versioning":true,"website":true,"website_domain":true,"website_endpoint":true},"before_sensitive":false,"after_sensitive":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{},"tags_all":{},"versioning":[],"website":[]}}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"57c6bd18a9b8abae3de1fed9f1d8b6fc","force_destroy":false,"key":"image-pipeline-config/aws-linux/buildspec.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/buildspec.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"f46d968aeec31a56e047fe8df1241f61","force_destroy":false,"key":"image-pipeline-config/aws-linux/codebuild.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codebuild.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"156f48bdaed0a3e6598fecc4e344efe4","force_destroy":false,"key":"image-pipeline-config/aws-linux/codepipeline.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/codepipeline.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"7aa982e1ce5827b21aab9881cc8e33a3","force_destroy":false,"key":"image-pipeline-config/aws-linux/iam.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/iam.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"e844ff64293d224a748374b63e223d8d","force_destroy":false,"key":"image-pipeline-config/aws-linux/kms.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/kms.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":"AWSTemplateFormatVersion: '2010-09-09'\nDescription: |\n AWS Image Pipeline - Automated AMI and Container Image Building Pipeline\n Creates a complete pipeline for building and testing machine images using CodePipeline, CodeBuild, and associated services.\n\nParameters:\n ProjectName:\n Type: String\n Description: Unique name for this project\n AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$$\n ConstraintDescription: Project name must start with a letter and can contain letters, numbers, and hyphens\n\n CreateNewRole:\n Type: String\n Description: Whether to create a new IAM role (true) or use existing roles (false)\n Default: \"true\"\n AllowedValues: [\"true\", \"false\"]\n\n SSHUser:\n Type: String\n Description: SSH username for connecting to build instances\n Default: ec2-user\n\n Troubleshoot:\n Type: String\n Description: Enable troubleshooting mode for builds\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n BuilderComputeType:\n Type: String\n Description: CodeBuild compute resources type\n Default: BUILD_GENERAL1_SMALL\n AllowedValues:\n - BUILD_GENERAL1_SMALL\n - BUILD_GENERAL1_MEDIUM\n - BUILD_GENERAL1_LARGE\n\n BuilderImage:\n Type: String\n Description: Docker image to use for CodeBuild\n Default: aws/codebuild/amazonlinux2-x86_64-standard:3.0\n\n PackerVersion:\n Type: String\n Description: Version of HashiCorp Packer to use\n Default: 1.10.3\n\n AssetsBucketName:\n Type: String\n Description: Name of the S3 bucket to store deployment artifacts\n Default: image-pipeline-assets-dev\n\n DockerBuild:\n Type: String\n Description: Whether to enable Docker image building\n Default: \"false\"\n AllowedValues: [\"true\", \"false\"]\n\n VpcId:\n Type: AWS::EC2::VPC::Id\n Description: VPC where resources will be created\n\n SubnetIds:\n Type: List\u003cAWS::EC2::Subnet::Id\u003e\n Description: Subnets where CodeBuild will run\n\n PackerBucketName:\n Type: String\n Description: Name of the S3 bucket containing Packer templates\n\n PackerBucketKey:\n Type: String\n Description: Key (path) to the Packer templates archive in S3\n\n AnsibleBucketName:\n Type: String\n Description: Name of the S3 bucket containing Ansible roles\n\n AnsibleBucketKey:\n Type: String\n Description: Key (path) to the Ansible roles archive in S3\n \n PipBucketName:\n Type: String\n Description: Name of the S3 bucket containing pip configuration\n\n PipBucketKey:\n Type: String\n Description: Key (path) to the pip configuration archive in S3\n \n PackerFileName:\n Type: String\n Description: Name of the Packer file to build\n Default: \"build.pkr.hcl\"\n \n BuildspecBucketName:\n Type: String\n Description: S3 bucket containing the buildspec file\n \n BuildspecObjectKey:\n Type: String\n Description: S3 object key for the buildspec file\n \n AdditionalSecurityGroupId:\n Type: String\n Description: ID of an additional pre-existing security group to attach to the CodeBuild job\n Default: \"\"\n \n HttpProxy:\n Type: String\n Description: HTTP proxy configuration for CodeBuild\n Default: \"\"\n \n HttpsProxy:\n Type: String\n Description: HTTPS proxy configuration for CodeBuild\n Default: \"\"\n \n NoProxy:\n Type: String\n Description: NO_PROXY configuration for CodeBuild\n Default: \"\"\n\nResources:\n KMSStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/kms.yml\n Parameters:\n ProjectName: !Ref ProjectName\n\n IAMStack:\n Type: AWS::CloudFormation::Stack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/iam.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CreateNewRole: !Ref CreateNewRole\n AssetsBucketName: !Ref AssetsBucketName\n\n S3Stack:\n Type: AWS::CloudFormation::Stack\n DependsOn: IAMStack\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/s3.yml\n Parameters:\n ProjectName: !Ref ProjectName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n\n CodeBuildStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [S3Stack, IAMStack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codebuild.yml\n Parameters:\n ProjectName: !Ref ProjectName\n BuilderImage: !Ref BuilderImage\n BuilderComputeType: !Ref BuilderComputeType\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n VpcId: !Ref VpcId\n SubnetIds: !Join [\",\", !Ref SubnetIds]\n PackerVersion: !Ref PackerVersion\n DockerBuild: !Ref DockerBuild\n SSHUser: !Ref SSHUser\n Troubleshoot: !Ref Troubleshoot\n PackerFileName: !Ref PackerFileName\n AssetsBucketName: !Ref AssetsBucketName\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n AdditionalSecurityGroupId: !Ref AdditionalSecurityGroupId\n HttpProxy: !Ref HttpProxy\n HttpsProxy: !Ref HttpsProxy\n NoProxy: !Ref NoProxy\n\n CodePipelineStack:\n Type: AWS::CloudFormation::Stack\n DependsOn: [CodeBuildStack, S3Stack]\n Properties:\n TemplateURL: https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/codepipeline.yml\n Parameters:\n ProjectName: !Ref ProjectName\n CodePipelineRoleArn: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n ArtifactBucketName: !GetAtt S3Stack.Outputs.ArtifactBucketName\n KMSKeyArn: !GetAtt KMSStack.Outputs.KMSKeyArn\n BuildProjectName: !GetAtt CodeBuildStack.Outputs.BuildProjectName\n AnsibleBucketName: !Ref AnsibleBucketName\n AnsibleBucketKey: !Ref AnsibleBucketKey\n PackerBucketName: !Ref PackerBucketName\n PackerBucketKey: !Ref PackerBucketKey\n PipBucketName: !Ref PipBucketName\n PipBucketKey: !Ref PipBucketKey\n BuildspecBucketName: !Ref BuildspecBucketName\n BuildspecObjectKey: !Ref BuildspecObjectKey\n\nOutputs:\n CodePipelineName:\n Description: Name of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineName\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-name\n\n CodePipelineArn:\n Description: ARN of the created CodePipeline\n Value: !GetAtt CodePipelineStack.Outputs.PipelineArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-arn\n\n ArtifactBucketName:\n Description: Name of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketName\n Export:\n Name: !Sub ${AWS::StackName}-bucket-name\n\n ArtifactBucketArn:\n Description: ARN of the S3 bucket storing pipeline artifacts\n Value: !GetAtt S3Stack.Outputs.ArtifactBucketArn\n Export:\n Name: !Sub ${AWS::StackName}-bucket-arn\n\n KMSKeyArn:\n Description: ARN of the KMS key used for encryption\n Value: !GetAtt KMSStack.Outputs.KMSKeyArn\n Export:\n Name: !Sub ${AWS::StackName}-kms-key-arn\n\n IamArn:\n Description: ARN of the CodePipeline IAM role\n Value: !GetAtt IAMStack.Outputs.CodePipelineRoleArn\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-arn\n\n RoleName:\n Description: Name of the CodePipeline IAM role\n Value: !Sub ${ProjectName}-pipeline-role\n Export:\n Name: !Sub ${AWS::StackName}-pipeline-role-name\n\n SecurityGroupId:\n Description: ID of the security group used by CodeBuild\n Value: !GetAtt CodeBuildStack.Outputs.BuildSecurityGroupId\n Export:\n Name: !Sub ${AWS::StackName}-security-group-id\n\n ManagedParameters:\n Description: Base path for SSM parameters managed by this pipeline\n Value: !Sub /image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-ssm-path\n\n SecretsPath:\n Description: Base path for Secrets Manager secrets managed by this pipeline\n Value: !Sub image-pipeline/${ProjectName}\n Export:\n Name: !Sub ${AWS::StackName}-secrets-path","content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"3c7f48a47fddc5a6cf8dccc0fa26d8fd","force_destroy":false,"key":"image-pipeline-config/aws-linuxmain.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":null,"source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/zip","etag":"53b73a7348956feca12db71b78520160","force_destroy":false,"key":"image-pipeline-config/aws-linux/image-pipeline-packer.zip","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./packer_config.zip","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"csvd-229685449397-aws-linux-service-catalog-templates","cache_control":null,"checksum_algorithm":null,"content":null,"content_base64":null,"content_disposition":null,"content_encoding":null,"content_language":null,"content_type":"application/x-yml","etag":"71b0638e9b13090eb68502fec3eb6b07","force_destroy":false,"key":"image-pipeline-config/aws-linux/s3.yml","metadata":null,"object_lock_legal_hold_status":null,"object_lock_mode":null,"object_lock_retain_until_date":null,"override_provider":[],"region":"us-gov-west-1","source":"./templates/s3.yml","source_hash":null,"tags":null,"website_redirect":null},"after_unknown":{"acl":true,"arn":true,"bucket_key_enabled":true,"checksum_crc32":true,"checksum_crc32c":true,"checksum_crc64nvme":true,"checksum_sha1":true,"checksum_sha256":true,"id":true,"kms_key_id":true,"override_provider":[],"server_side_encryption":true,"storage_class":true,"tags_all":true,"version_id":true},"before_sensitive":false,"after_sensitive":{"override_provider":[],"tags_all":{}}}},{"address":"module.service_catalog[0].data.aws_caller_identity.current","module_address":"module.service_catalog[0]","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["read"],"before":null,"after":{},"after_unknown":{"account_id":true,"arn":true,"id":true,"user_id":true},"before_sensitive":false,"after_sensitive":{}},"action_reason":"read_because_dependency_pending"},{"address":"module.service_catalog[0].data.aws_partition.current","module_address":"module.service_catalog[0]","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["read"],"before":null,"after":{},"after_unknown":{"dns_suffix":true,"id":true,"partition":true,"reverse_dns_prefix":true},"before_sensitive":false,"after_sensitive":{}},"action_reason":"read_because_dependency_pending"},{"address":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"description":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks","name":"aws-linux-service-catalog-launch-role-policy","path":"/","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"after_unknown":{"arn":true,"attachment_count":true,"id":true,"name_prefix":true,"policy":true,"policy_id":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"assume_role_policy":"{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"servicecatalog.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}","description":null,"force_detach_policies":false,"max_session_duration":3600,"name":"aws-linux-service-catalog-launch-role","path":"/","permissions_boundary":null,"tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"}},"after_unknown":{"arn":true,"create_date":true,"id":true,"inline_policy":true,"managed_policy_arns":true,"name_prefix":true,"tags":{},"tags_all":{},"unique_id":true},"before_sensitive":false,"after_sensitive":{"inline_policy":[],"managed_policy_arns":[],"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_iam_role_policy_attachment.service_catalog_launch_policy[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"role":"aws-linux-service-catalog-launch-role"},"after_unknown":{"id":true,"policy_arn":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","description":"Launch constraint for AWS Image Building Pipeline","region":"us-gov-west-1","timeouts":null,"type":"LAUNCH"},"after_unknown":{"id":true,"owner":true,"parameters":true,"portfolio_id":true,"product_id":true,"status":true},"before_sensitive":false,"after_sensitive":{}}},{"address":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","index":0,"provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"description":"Self-service deployment of AWS image building pipelines","name":"AWS Image Pipeline Portfolio","provider_name":"DevOps Team","region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null},"after_unknown":{"arn":true,"created_time":true,"id":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_servicecatalog_product.main","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","description":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","name":"AWS Image Building Pipeline","owner":"Platform Engineering","provisioning_artifact_parameters":[{"description":"AWS Image Building Pipeline v1.0","disable_template_validation":false,"name":"v1.0","template_physical_id":null,"template_url":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"CLOUD_FORMATION_TEMPLATE"}],"region":"us-gov-west-1","tags":{"Environment":"dev","Owner":"platform-team"},"tags_all":{"Environment":"dev","Owner":"platform-team"},"timeouts":null,"type":"CLOUD_FORMATION_TEMPLATE"},"after_unknown":{"arn":true,"created_time":true,"distributor":true,"has_default_path":true,"id":true,"provisioning_artifact_parameters":[{}],"status":true,"support_description":true,"support_email":true,"support_url":true,"tags":{},"tags_all":{}},"before_sensitive":false,"after_sensitive":{"provisioning_artifact_parameters":[{}],"tags":{},"tags_all":{}}}},{"address":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","module_address":"module.service_catalog[0]","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"accept_language":"en","region":"us-gov-west-1","source_portfolio_id":null,"timeouts":null},"after_unknown":{"id":true,"portfolio_id":true,"product_id":true},"before_sensitive":false,"after_sensitive":{}}}],"output_changes":{"artifact_bucket_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"artifact_bucket_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"buildspec_location":{"actions":["create"],"before":null,"after":"s3://image-pipeline-assets-dev/buildspec.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"code_pipeline_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"code_pipeline_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"iam_role_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"kms_key_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"managed_parameters_path":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"role_name":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"secrets_path":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"security_group_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_all_principals":{"actions":["create"],"before":null,"after":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"],"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_current_user_arn":{"actions":["no-op"],"before":null,"after":null,"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_constraint_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_role_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_launch_role_name":{"actions":["create"],"before":null,"after":"aws-linux-service-catalog-launch-role","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_portfolio_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_portfolio_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_principal_count":{"actions":["create"],"before":null,"after":2,"after_unknown":false,"before_sensitive":false,"after_sensitive":false},"service_catalog_product_arn":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_product_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"service_catalog_template_url":{"actions":["create"],"before":null,"after":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"stack_id":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"stack_outputs":{"actions":["create"],"before":null,"after_unknown":true,"before_sensitive":false,"after_sensitive":false},"template_bucket":{"actions":["create"],"before":null,"after":"image-pipeline-assets-dev","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"template_prefix":{"actions":["create"],"before":null,"after":"image-pipeline-config/aws-linux","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"template_url":{"actions":["create"],"before":null,"after":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","after_unknown":false,"before_sensitive":false,"after_sensitive":false},"uploaded_templates":{"actions":["create"],"before":null,"after":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linux/kms.yml","image-pipeline-config/aws-linux/iam.yml","image-pipeline-config/aws-linux/s3.yml","image-pipeline-config/aws-linux/codebuild.yml","image-pipeline-config/aws-linux/codepipeline.yml"],"after_unknown":false,"before_sensitive":false,"after_sensitive":false}},"prior_state":{"format_version":"1.0","terraform_version":"1.9.1","values":{"outputs":{"buildspec_location":{"sensitive":false,"value":"s3://image-pipeline-assets-dev/buildspec.yml","type":"string"},"service_catalog_all_principals":{"sensitive":false,"value":["arn:aws-us-gov:iam::229685449397:role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0","arn:aws-us-gov:iam::229685449397:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0"],"type":["list","string"]},"service_catalog_launch_role_name":{"sensitive":false,"value":"aws-linux-service-catalog-launch-role","type":"string"},"service_catalog_principal_count":{"sensitive":false,"value":2,"type":"number"},"service_catalog_template_url":{"sensitive":false,"value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"string"},"template_bucket":{"sensitive":false,"value":"image-pipeline-assets-dev","type":"string"},"template_prefix":{"sensitive":false,"value":"image-pipeline-config/aws-linux","type":"string"},"template_url":{"sensitive":false,"value":"https://csvd-229685449397-aws-linux-service-catalog-templates.s3.us-gov-west-1.amazonaws.com/image-pipeline-config/aws-linux/main.yml","type":"string"},"uploaded_templates":{"sensitive":false,"value":["image-pipeline-config/aws-linuxmain.yml","image-pipeline-config/aws-linux/kms.yml","image-pipeline-config/aws-linux/iam.yml","image-pipeline-config/aws-linux/s3.yml","image-pipeline-config/aws-linux/codebuild.yml","image-pipeline-config/aws-linux/codepipeline.yml"],"type":["tuple",["string","string","string","string","string","string"]]}},"root_module":{"resources":[{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"account_id":"229685449397","arn":"arn:aws-us-gov:sts::229685449397:assumed-role/AWSReservedSSO_inf-admin-t2_4e0c6446aecbe4a0/david.j.arnold.jr@census.gov","id":"229685449397","user_id":"AROATK6SR2K22ZVVMKHBO:david.j.arnold.jr@census.gov"},"sensitive_values":{}},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"dns_suffix":"amazonaws.com","id":"aws-us-gov","partition":"aws-us-gov","reverse_dns_prefix":"com.amazonaws"},"sensitive_values":{}}]}}},"configuration":{"provider_config":{"archive":{"name":"archive","full_name":"registry.terraform.io/hashicorp/archive","version_constraint":"~\u003e 2.0"},"aws":{"name":"aws","full_name":"registry.terraform.io/hashicorp/aws","version_constraint":"~\u003e 6.0","expressions":{"region":{"references":["var.aws_region"]}}}},"root_module":{"outputs":{"artifact_bucket_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ArtifactBucketArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the S3 bucket storing pipeline artifacts"},"artifact_bucket_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ArtifactBucketName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the S3 bucket storing pipeline artifacts"},"buildspec_location":{"expression":{"references":["var.buildspec_bucket_name","var.buildspec_bucket_key"]},"description":"Location of the buildspec file in S3"},"code_pipeline_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"CodePipelineArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the created CodePipeline"},"code_pipeline_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"CodePipelineName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the created CodePipeline"},"iam_role_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"IamArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the CodePipeline IAM role"},"kms_key_arn":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"KMSKeyArn\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ARN of the KMS key used for encryption"},"managed_parameters_path":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"ManagedParameters\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Base path for SSM parameters managed by this pipeline"},"role_name":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"RoleName\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Name of the CodePipeline IAM role"},"secrets_path":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"SecretsPath\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"Base path for Secrets Manager secrets managed by this pipeline"},"security_group_id":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs[\"SecurityGroupId\"]","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ID of the security group used by CodeBuild"},"service_catalog_all_principals":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].principal_associations","module.service_catalog[0]"]},"description":"List of all principal ARNs with access to the Service Catalog portfolio (if enabled)"},"service_catalog_current_user_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].current_user_arn","module.service_catalog[0]"]},"description":"ARN of the current authenticated user that was automatically granted access (if Service Catalog is enabled)"},"service_catalog_launch_constraint_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_constraint_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog launch constraint (if enabled)"},"service_catalog_launch_role_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_role_arn","module.service_catalog[0]"]},"description":"ARN of the IAM role used for Service Catalog launch constraint (if enabled)"},"service_catalog_launch_role_name":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].launch_role_name","module.service_catalog[0]"]},"description":"Name of the IAM role used for Service Catalog launch constraint (if enabled and created)"},"service_catalog_portfolio_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].portfolio_arn","module.service_catalog[0]"]},"description":"ARN of the Service Catalog portfolio (if Service Catalog is enabled)"},"service_catalog_portfolio_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].portfolio_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog portfolio (if Service Catalog is enabled)"},"service_catalog_principal_count":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].principal_association_count","module.service_catalog[0]"]},"description":"Total number of principals with access to the Service Catalog portfolio (if enabled)"},"service_catalog_product_arn":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].product_arn","module.service_catalog[0]"]},"description":"ARN of the Service Catalog product (if Service Catalog is enabled)"},"service_catalog_product_id":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].product_id","module.service_catalog[0]"]},"description":"ID of the Service Catalog product (if Service Catalog is enabled)"},"service_catalog_template_url":{"expression":{"references":["var.enable_service_catalog","module.service_catalog[0].template_url","module.service_catalog[0]"]},"description":"URL of the CloudFormation template used by Service Catalog (if enabled)"},"stack_id":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].id","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"ID of the CloudFormation stack"},"stack_outputs":{"expression":{"references":["var.deploy_stack","aws_cloudformation_stack.image_pipeline[0].outputs","aws_cloudformation_stack.image_pipeline[0]","aws_cloudformation_stack.image_pipeline"]},"description":"A map of outputs from the CloudFormation stack"},"template_bucket":{"expression":{"references":["var.template_bucket"]},"description":"S3 bucket containing the CloudFormation templates"},"template_prefix":{"expression":{"references":["var.template_prefix"]},"description":"Prefix/folder path for CloudFormation templates in S3"},"template_url":{"expression":{"references":["local.service_catalog_s3_base_url"]},"description":"URL of the main CloudFormation template in S3"},"uploaded_templates":{"expression":{"references":["aws_s3_object.main_template.key","aws_s3_object.main_template","aws_s3_object.kms_template.key","aws_s3_object.kms_template","aws_s3_object.iam_template.key","aws_s3_object.iam_template","aws_s3_object.s3_template.key","aws_s3_object.s3_template","aws_s3_object.codebuild_template.key","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template.key","aws_s3_object.codepipeline_template"]},"description":"List of uploaded template files"}},"resources":[{"address":"aws_cloudformation_stack.image_pipeline","mode":"managed","type":"aws_cloudformation_stack","name":"image_pipeline","provider_config_key":"aws","expressions":{"capabilities":{"constant_value":["CAPABILITY_IAM","CAPABILITY_NAMED_IAM"]},"disable_rollback":{"references":["var.disable_rollback"]},"name":{"references":["var.stack_name"]},"parameters":{"references":["var.project_name","var.create_new_role","var.ssh_user","var.troubleshoot","var.builder_compute_type","var.builder_image","var.packer_version","var.assets_bucket_name","var.docker_build","var.vpc_id","var.subnet_ids","var.assets_bucket_name","local.packer_config_s3_key","var.assets_bucket_name","local.ansible_config_s3_key","var.assets_bucket_name","local.pip_config_s3_key","var.packer_file_name","var.template_bucket","local.buildspec_s3_key","var.additional_security_group_id","var.http_proxy","var.https_proxy","var.no_proxy"]},"tags":{"references":["var.tags"]},"template_body":{"references":["local.main_template_content"]},"timeout_in_minutes":{"references":["var.timeout_in_minutes"]}},"schema_version":0,"count_expression":{"references":["var.deploy_stack"]},"depends_on":["aws_s3_object.main_template","aws_s3_object.kms_template","aws_s3_object.iam_template","aws_s3_object.s3_template","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template","aws_s3_object.buildspec","aws_s3_object.packer_config"]},{"address":"aws_s3_bucket.service_catalog","mode":"managed","type":"aws_s3_bucket","name":"service_catalog","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"tags":{"references":["var.tags","var.project_name","var.project_name"]}},"schema_version":0,"count_expression":{"references":["var.enable_service_catalog"]}},{"address":"aws_s3_object.buildspec","mode":"managed","type":"aws_s3_object","name":"buildspec","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.codebuild_template","mode":"managed","type":"aws_s3_object","name":"codebuild_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.codepipeline_template","mode":"managed","type":"aws_s3_object","name":"codepipeline_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.iam_template","mode":"managed","type":"aws_s3_object","name":"iam_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.kms_template","mode":"managed","type":"aws_s3_object","name":"kms_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.main_template","mode":"managed","type":"aws_s3_object","name":"main_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content":{"references":["local.main_template_content"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["local.main_template_content"]},"key":{"references":["var.template_prefix"]}},"schema_version":0},{"address":"aws_s3_object.packer_config","mode":"managed","type":"aws_s3_object","name":"packer_config","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/zip"},"etag":{"references":["path.module"]},"key":{"references":["local.packer_config_s3_key"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"aws_s3_object.s3_template","mode":"managed","type":"aws_s3_object","name":"s3_template","provider_config_key":"aws","expressions":{"bucket":{"references":["local.service_catalog_bucket_name"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["path.module"]},"key":{"references":["var.template_prefix"]},"source":{"references":["path.module"]}},"schema_version":0},{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_config_key":"aws","schema_version":0}],"module_calls":{"service_catalog":{"source":"../terraform-cfn-service-catalog","expressions":{"additional_s3_buckets":{"references":["var.enable_service_catalog","aws_s3_bucket.service_catalog[0].id","aws_s3_bucket.service_catalog[0]","aws_s3_bucket.service_catalog","var.assets_bucket_name"]},"aws_region":{"references":["var.aws_region"]},"create_launch_role":{"constant_value":true},"create_portfolio":{"constant_value":true},"enable_service_catalog_s3_access":{"constant_value":false},"include_current_user":{"constant_value":false},"launch_role_name":{"references":["var.project_name"]},"portfolio_description":{"references":["var.portfolio_description"]},"portfolio_name":{"references":["var.portfolio_name"]},"portfolio_provider_name":{"references":["var.portfolio_provider_name"]},"principal_arns":{"references":["local.dynamic_principal_arns"]},"product_description":{"references":["var.product_description"]},"product_name":{"references":["var.product_name"]},"product_owner":{"references":["var.product_owner"]},"provisioning_artifact_description":{"constant_value":"AWS Image Building Pipeline v1.0"},"provisioning_artifact_name":{"constant_value":"v1.0"},"tags":{"references":["var.tags"]},"template_bucket":{"references":["var.enable_service_catalog","aws_s3_bucket.service_catalog[0].id","aws_s3_bucket.service_catalog[0]","aws_s3_bucket.service_catalog","var.template_bucket"]},"template_url":{"references":["local.service_catalog_template_vars.main_template_url","local.service_catalog_template_vars"]}},"count_expression":{"references":["var.enable_service_catalog"]},"module":{"outputs":{"additional_principals":{"expression":{"references":["var.principal_arns"]},"description":"List of additional principal ARNs (manual association required)"},"current_user_account_id":{"expression":{"references":["data.aws_caller_identity.current.account_id","data.aws_caller_identity.current"]},"description":"Account ID of the current authenticated user"},"current_user_arn":{"expression":{"references":["var.include_current_user","data.aws_caller_identity.current.arn","data.aws_caller_identity.current"]},"description":"ARN of the current authenticated user/role (if include_current_user is enabled)"},"launch_constraint_id":{"expression":{"references":["var.create_launch_role","var.launch_role_arn","aws_servicecatalog_constraint.launch[0].id","aws_servicecatalog_constraint.launch[0]","aws_servicecatalog_constraint.launch"]},"description":"ID of the Service Catalog launch constraint (if launch_role_arn was provided)"},"launch_role_arn":{"expression":{"references":["local.final_launch_role_arn"]},"description":"ARN of the IAM role used for the launch constraint"},"launch_role_created":{"expression":{"references":["var.create_launch_role"]},"description":"Whether the launch role was created by this module"},"launch_role_name":{"expression":{"references":["var.create_launch_role","aws_iam_role.service_catalog_launch_role[0].name","aws_iam_role.service_catalog_launch_role[0]","aws_iam_role.service_catalog_launch_role"]},"description":"Name of the IAM role used for the launch constraint (if created by this module)"},"launch_role_policy_arn":{"expression":{"references":["var.create_launch_role","aws_iam_policy.service_catalog_launch_policy[0].arn","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"description":"ARN of the managed policy attached to the launch role (if created by this module)"},"launch_role_policy_name":{"expression":{"references":["var.create_launch_role","aws_iam_policy.service_catalog_launch_policy[0].name","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"description":"Name of the managed policy attached to the launch role (if created by this module)"},"manual_association_instructions":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main"]},"description":"Instructions for manually associating principals with the portfolio"},"portfolio_arn":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].arn","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].arn","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"ARN of the Service Catalog portfolio (created or existing)"},"portfolio_created_time":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].created_time","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].created_time","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Time when the portfolio was created (null for existing portfolios)"},"portfolio_creation_mode":{"expression":{"references":["var.create_portfolio"]},"description":"Whether the portfolio was created by this module or was existing"},"portfolio_description":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].description","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].description","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Description of the Service Catalog portfolio"},"portfolio_id":{"expression":{"references":["local.portfolio_id"]},"description":"ID of the Service Catalog portfolio (created or existing)"},"portfolio_name":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].name","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Name of the Service Catalog portfolio (created or existing)"},"portfolio_product_association_id":{"expression":{"references":["aws_servicecatalog_product_portfolio_association.main.id","aws_servicecatalog_product_portfolio_association.main"]},"description":"ID of the portfolio-product association"},"portfolio_provider_name":{"expression":{"references":["var.create_portfolio","aws_servicecatalog_portfolio.main[0].provider_name","aws_servicecatalog_portfolio.main[0]","aws_servicecatalog_portfolio.main","data.aws_servicecatalog_portfolio.existing[0].provider_name","data.aws_servicecatalog_portfolio.existing[0]","data.aws_servicecatalog_portfolio.existing"]},"description":"Provider name of the Service Catalog portfolio"},"principal_association_count":{"expression":{"references":["local.all_principal_arns"]},"description":"Total number of principals that need manual association"},"principal_associations":{"expression":{"references":["local.all_principal_arns"]},"description":"List of all principal ARNs that would have access to the portfolio (manual association required)"},"product_arn":{"expression":{"references":["aws_servicecatalog_product.main.arn","aws_servicecatalog_product.main"]},"description":"ARN of the Service Catalog product"},"product_created_time":{"expression":{"references":["aws_servicecatalog_product.main.created_time","aws_servicecatalog_product.main"]},"description":"Time when the Service Catalog product was created"},"product_has_default_path":{"expression":{"references":["aws_servicecatalog_product.main.has_default_path","aws_servicecatalog_product.main"]},"description":"Whether the product has a default path"},"product_id":{"expression":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]},"description":"ID of the Service Catalog product"},"product_name":{"expression":{"references":["aws_servicecatalog_product.main.name","aws_servicecatalog_product.main"]},"description":"Name of the Service Catalog product"},"product_status":{"expression":{"references":["aws_servicecatalog_product.main.status","aws_servicecatalog_product.main"]},"description":"Status of the Service Catalog product"},"s3_access_policy_arn":{"expression":{"references":["var.grant_s3_access_to_principals","aws_iam_policy.principal_s3_access[0].arn","aws_iam_policy.principal_s3_access[0]","aws_iam_policy.principal_s3_access"]},"description":"ARN of the optional S3 access policy for principals (if created)"},"template_s3_etag":{"expression":{"references":["var.template_content","aws_s3_object.cloudformation_template[0].etag","aws_s3_object.cloudformation_template[0]","aws_s3_object.cloudformation_template"]},"description":"ETag of the uploaded CloudFormation template (if template_content was used)"},"template_s3_key":{"expression":{"references":["var.template_content","local.template_key"]},"description":"S3 key of the uploaded CloudFormation template (if template_content was used)"},"template_url":{"expression":{"references":["local.final_template_url"]},"description":"URL of the CloudFormation template used by the Service Catalog product"}},"resources":[{"address":"aws_iam_policy.principal_s3_access","mode":"managed","type":"aws_iam_policy","name":"principal_s3_access","provider_config_key":"aws","expressions":{"description":{"constant_value":"Allows Service Catalog principals to read CloudFormation templates from S3"},"name":{"references":["local.sanitized_product_name"]},"policy":{"references":["local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current","local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.grant_s3_access_to_principals"]}},{"address":"aws_iam_policy.service_catalog_launch_policy","mode":"managed","type":"aws_iam_policy","name":"service_catalog_launch_policy","provider_config_key":"aws","expressions":{"description":{"constant_value":"Policy for Service Catalog launch role to access S3 templates and create CloudFormation stacks"},"name":{"references":["local.launch_role_name"]},"policy":{"references":["local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current","local.all_s3_buckets","data.aws_partition.current.partition","data.aws_partition.current"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_iam_role.service_catalog_launch_role","mode":"managed","type":"aws_iam_role","name":"service_catalog_launch_role","provider_config_key":"aws","expressions":{"assume_role_policy":{},"name":{"references":["local.launch_role_name"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_iam_role_policy_attachment.service_catalog_launch_policy","mode":"managed","type":"aws_iam_role_policy_attachment","name":"service_catalog_launch_policy","provider_config_key":"aws","expressions":{"policy_arn":{"references":["aws_iam_policy.service_catalog_launch_policy[0].arn","aws_iam_policy.service_catalog_launch_policy[0]","aws_iam_policy.service_catalog_launch_policy"]},"role":{"references":["aws_iam_role.service_catalog_launch_role[0].name","aws_iam_role.service_catalog_launch_role[0]","aws_iam_role.service_catalog_launch_role"]}},"schema_version":0,"count_expression":{"references":["var.create_launch_role"]}},{"address":"aws_s3_object.cloudformation_template","mode":"managed","type":"aws_s3_object","name":"cloudformation_template","provider_config_key":"aws","expressions":{"bucket":{"references":["var.template_bucket"]},"content":{"references":["var.template_content"]},"content_type":{"constant_value":"application/x-yml"},"etag":{"references":["var.template_content"]},"key":{"references":["local.template_key"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.template_content"]}},{"address":"aws_servicecatalog_constraint.launch","mode":"managed","type":"aws_servicecatalog_constraint","name":"launch","provider_config_key":"aws","expressions":{"description":{"references":["var.product_name"]},"parameters":{"references":["local.final_launch_role_arn"]},"portfolio_id":{"references":["local.portfolio_id"]},"product_id":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]},"type":{"constant_value":"LAUNCH"}},"schema_version":0,"count_expression":{"references":["var.create_launch_role","var.launch_role_arn"]},"depends_on":["aws_servicecatalog_product_portfolio_association.main","aws_iam_role.service_catalog_launch_role"]},{"address":"aws_servicecatalog_portfolio.main","mode":"managed","type":"aws_servicecatalog_portfolio","name":"main","provider_config_key":"aws","expressions":{"description":{"references":["var.portfolio_description"]},"name":{"references":["var.portfolio_name"]},"provider_name":{"references":["var.portfolio_provider_name"]},"tags":{"references":["var.tags"]}},"schema_version":0,"count_expression":{"references":["var.create_portfolio"]}},{"address":"aws_servicecatalog_product.main","mode":"managed","type":"aws_servicecatalog_product","name":"main","provider_config_key":"aws","expressions":{"description":{"references":["var.product_description"]},"distributor":{"references":["var.product_distributor"]},"name":{"references":["var.product_name"]},"owner":{"references":["var.product_owner"]},"provisioning_artifact_parameters":[{"description":{"references":["var.provisioning_artifact_description"]},"disable_template_validation":{"references":["var.disable_template_validation"]},"name":{"references":["var.provisioning_artifact_name"]},"template_url":{"references":["local.final_template_url"]},"type":{"constant_value":"CLOUD_FORMATION_TEMPLATE"}}],"support_description":{"references":["var.support_description"]},"support_email":{"references":["var.support_email"]},"support_url":{"references":["var.support_url"]},"tags":{"references":["var.tags"]},"type":{"constant_value":"CLOUD_FORMATION_TEMPLATE"}},"schema_version":0,"depends_on":["aws_s3_object.cloudformation_template"]},{"address":"aws_servicecatalog_product_portfolio_association.main","mode":"managed","type":"aws_servicecatalog_product_portfolio_association","name":"main","provider_config_key":"aws","expressions":{"portfolio_id":{"references":["local.portfolio_id"]},"product_id":{"references":["aws_servicecatalog_product.main.id","aws_servicecatalog_product.main"]}},"schema_version":0},{"address":"data.aws_caller_identity.current","mode":"data","type":"aws_caller_identity","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_partition.current","mode":"data","type":"aws_partition","name":"current","provider_config_key":"aws","schema_version":0},{"address":"data.aws_servicecatalog_portfolio.existing","mode":"data","type":"aws_servicecatalog_portfolio","name":"existing","provider_config_key":"aws","expressions":{"id":{"references":["var.existing_portfolio_id"]}},"schema_version":0,"count_expression":{"references":["var.create_portfolio"]}}],"variables":{"additional_s3_buckets":{"default":[],"description":"List of additional S3 bucket names that the launch role should have access to (for buildspec, packer, ansible, etc.)"},"auto_detect_current_user":{"default":true,"description":"Whether to automatically detect and include the current user only if it's a permanent IAM role (not AWS SSO/temporary credentials)."},"aws_region":{"default":null,"description":"AWS region for S3 URL construction (required for GovCloud compatibility)"},"create_launch_role":{"default":true,"description":"Whether to create a Service Catalog launch role. If false, launch_role_arn must be provided."},"create_portfolio":{"default":true,"description":"Whether to create a new portfolio (true) or use an existing one (false)"},"disable_template_validation":{"default":false,"description":"Whether to disable CloudFormation template validation"},"enable_service_catalog_s3_access":{"default":true,"description":"Enable S3 bucket policy to grant Service Catalog service access to templates"},"existing_portfolio_id":{"default":null,"description":"ID of existing Service Catalog portfolio to use. Required when create_portfolio is false."},"grant_s3_access_to_principals":{"default":false,"description":"Whether to create an IAM policy granting principals read access to CloudFormation templates in S3"},"include_current_user":{"default":false,"description":"Whether to automatically include the current authenticated user/role in the portfolio access. Set to false when using AWS SSO or roles with limited CloudFormation permissions."},"launch_role_arn":{"default":null,"description":"ARN of IAM role for Service Catalog launch constraint. Required for CloudFormation products with nested stacks."},"launch_role_name":{"default":null,"description":"Name for the Service Catalog launch role when create_launch_role is true"},"portfolio_description":{"default":"Self-service deployment of standardized infrastructure components","description":"Description of the Service Catalog portfolio (used only when creating new portfolio)"},"portfolio_name":{"default":"Self-Service Infrastructure","description":"Name of the Service Catalog portfolio (used only when creating new portfolio)"},"portfolio_provider_name":{"default":"Platform Engineering","description":"Name of the portfolio provider/owner (used only when creating new portfolio)"},"principal_arns":{"default":[],"description":"List of additional IAM principal ARNs (users, roles, groups) to grant access to the portfolio. The current authenticated role is automatically included when possible."},"product_description":{"default":"","description":"Description of the Service Catalog product"},"product_distributor":{"default":null,"description":"Distributor (vendor) of the Service Catalog product"},"product_name":{"description":"Name of the Service Catalog product"},"product_owner":{"default":"Platform Team","description":"Owner of the Service Catalog product"},"provisioning_artifact_description":{"default":"Initial version","description":"Description of the provisioning artifact"},"provisioning_artifact_name":{"default":"v1.0","description":"Name of the provisioning artifact (version)"},"support_description":{"default":null,"description":"Support information about the product"},"support_email":{"default":null,"description":"Support email for the product"},"support_url":{"default":null,"description":"Support URL for the product"},"tags":{"default":{},"description":"A map of tags to assign to all resources"},"template_bucket":{"description":"S3 bucket name where CloudFormation templates will be stored"},"template_content":{"default":null,"description":"CloudFormation template content as a string. Mutually exclusive with template_url."},"template_prefix":{"default":"","description":"Prefix/folder path for CloudFormation templates in S3"},"template_url":{"default":null,"description":"S3 URL to existing CloudFormation template. Mutually exclusive with template_content."}}},"depends_on":["aws_s3_bucket.service_catalog","aws_s3_object.main_template","aws_s3_object.kms_template","aws_s3_object.iam_template","aws_s3_object.s3_template","aws_s3_object.codebuild_template","aws_s3_object.codepipeline_template","aws_s3_object.buildspec"]}},"variables":{"additional_security_group_id":{"default":"","description":"ID of an additional pre-existing security group to attach to the CodeBuild job"},"ami_name":{"default":"aws-linux-2-image","description":"Name to give the created AMI"},"ansible_bucket_key":{"description":"Key (path) to the Ansible roles archive in S3"},"ansible_bucket_name":{"description":"Name of the S3 bucket containing Ansible roles"},"assets_bucket_name":{"default":"image-pipeline-assets-dev","description":"Name of the S3 bucket to store deployment artifacts"},"aws_region":{"default":"us-gov-west-1","description":"The AWS region to deploy resources"},"builder_compute_type":{"default":"BUILD_GENERAL1_SMALL","description":"CodeBuild compute resources type"},"builder_image":{"default":"aws/codebuild/amazonlinux2-x86_64-standard:3.0","description":"Docker image to use for CodeBuild"},"buildspec_bucket_key":{"default":"buildspec.yml","description":"Key (path) to the buildspec file in S3"},"buildspec_bucket_name":{"default":"image-pipeline-assets-dev","description":"Name of the S3 bucket containing the buildspec file"},"create_new_role":{"default":true,"description":"Whether to create a new IAM role (true) or use existing roles (false)"},"deploy_stack":{"default":true,"description":"Whether to deploy the CloudFormation stack"},"disable_rollback":{"default":false,"description":"Set to true to disable rollback of the stack if stack creation failed"},"docker_build":{"default":false,"description":"Whether to enable Docker image building"},"enable_service_catalog":{"default":true,"description":"Whether to create Service Catalog resources for self-service deployment"},"http_proxy":{"default":"","description":"HTTP proxy configuration for CodeBuild"},"https_proxy":{"default":"","description":"HTTPS proxy configuration for CodeBuild"},"instance_type":{"default":"t3.medium","description":"Instance type to use for building images"},"no_proxy":{"default":"","description":"NO_PROXY configuration for CodeBuild"},"packer_bucket_key":{"description":"Key (path) to the Packer templates archive in S3"},"packer_bucket_name":{"description":"Name of the S3 bucket containing Packer templates"},"packer_file_name":{"default":"build.pkr.hcl","description":"Name of the Packer file to build"},"packer_version":{"default":"1.10.3","description":"Version of HashiCorp Packer to use"},"pip_bucket_key":{"description":"Key (path) to the pip configuration archive in S3"},"pip_bucket_name":{"description":"Name of the S3 bucket containing pip configuration"},"playbook":{"default":"hello-world.yaml","description":"Ansible playbook to run during AMI creation"},"portfolio_description":{"default":"Self-service deployment of AWS image building pipelines","description":"Description of the Service Catalog portfolio"},"portfolio_name":{"default":"AWS Image Pipeline Portfolio","description":"Name of the Service Catalog portfolio"},"portfolio_provider_name":{"default":"DevOps Team","description":"Name of the portfolio provider/owner"},"principal_arns":{"default":[],"description":"List of IAM principal ARNs (users, roles, groups) to grant access to the Service Catalog portfolio"},"product_description":{"default":"Automated AWS image building pipeline using CodeBuild, CodePipeline, and Packer","description":"Description of the Service Catalog product"},"product_name":{"default":"AWS Image Building Pipeline","description":"Name of the Service Catalog product"},"product_owner":{"default":"Platform Engineering","description":"Owner of the Service Catalog product"},"project_name":{"description":"Unique name for this project"},"shared_accounts":{"default":"","description":"Comma-separated list of AWS account IDs to share the AMI with"},"source_ami_ssm_path":{"description":"SSM parameter path to fetch the source AMI ID from"},"ssh_user":{"default":"ec2-user","description":"SSH username for connecting to build instances"},"stack_name":{"default":"image-pipeline","description":"Name of the CloudFormation stack"},"subnet_ids":{"description":"Subnets where CodeBuild will run"},"tags":{"default":{},"description":"A map of tags to assign to resources"},"template_bucket":{"description":"S3 bucket containing the packaged CloudFormation templates"},"template_prefix":{"default":"","description":"Prefix/folder path for CloudFormation templates in S3"},"timeout_in_minutes":{"default":30,"description":"The amount of time that can pass before the stack status becomes CREATE_FAILED"},"troubleshoot":{"default":false,"description":"Enable troubleshooting mode for builds"},"vpc_id":{"description":"VPC where resources will be created"}}}},"relevant_attributes":[{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","IamArn"]},{"resource":"data.aws_caller_identity.current","attribute":["account_id"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["arn"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["provider_name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["has_default_path"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs"]},{"resource":"module.service_catalog[0].data.aws_partition.current","attribute":["partition"]},{"resource":"aws_s3_object.codepipeline_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["created_time"]},{"resource":"module.service_catalog[0].data.aws_caller_identity.current","attribute":["account_id"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["arn"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["created_time"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ArtifactBucketName"]},{"resource":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","attribute":["name"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["id"]},{"resource":"aws_s3_object.codebuild_template","attribute":["key"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["id"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","SecurityGroupId"]},{"resource":"module.service_catalog[0].aws_iam_role.service_catalog_launch_role[0]","attribute":["arn"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["id"]},{"resource":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","attribute":["name"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","SecretsPath"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","CodePipelineName"]},{"resource":"aws_s3_bucket.service_catalog[0]","attribute":["id"]},{"resource":"module.service_catalog[0].data.aws_caller_identity.current","attribute":["arn"]},{"resource":"aws_s3_object.main_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["description"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["description"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["arn"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ArtifactBucketArn"]},{"resource":"module.service_catalog[0].aws_iam_policy.service_catalog_launch_policy[0]","attribute":["arn"]},{"resource":"aws_s3_object.kms_template","attribute":["key"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["created_time"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","CodePipelineArn"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","RoleName"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product_portfolio_association.main","attribute":["id"]},{"resource":"data.aws_partition.current","attribute":["partition"]},{"resource":"aws_s3_object.s3_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_portfolio.main[0]","attribute":["name"]},{"resource":"module.service_catalog[0].data.aws_servicecatalog_portfolio.existing[0]","attribute":["provider_name"]},{"resource":"aws_s3_object.iam_template","attribute":["key"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["status"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","ManagedParameters"]},{"resource":"module.service_catalog[0].aws_servicecatalog_constraint.launch[0]","attribute":["id"]},{"resource":"module.service_catalog[0].aws_servicecatalog_product.main","attribute":["name"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["outputs","KMSKeyArn"]},{"resource":"aws_cloudformation_stack.image_pipeline[0]","attribute":["id"]}],"checks":[{"address":{"kind":"var","module":"module.service_catalog","name":"existing_portfolio_id","to_display":"module.service_catalog.var.existing_portfolio_id"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.existing_portfolio_id"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"launch_role_arn","to_display":"module.service_catalog.var.launch_role_arn"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.launch_role_arn"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"principal_arns","to_display":"module.service_catalog.var.principal_arns"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.principal_arns"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"product_name","to_display":"module.service_catalog.var.product_name"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.product_name"},"status":"pass"}]},{"address":{"kind":"var","module":"module.service_catalog","name":"template_url","to_display":"module.service_catalog.var.template_url"},"status":"pass","instances":[{"address":{"module":"module.service_catalog[0]","to_display":"module.service_catalog[0].var.template_url"},"status":"pass"}]},{"address":{"kind":"var","name":"builder_compute_type","to_display":"var.builder_compute_type"},"status":"pass","instances":[{"address":{"to_display":"var.builder_compute_type"},"status":"pass"}]}],"timestamp":"2025-09-26T17:21:30Z","applyable":true,"complete":true,"errored":false} diff --git a/variables.tf b/variables.tf index 824bc39..59ecf53 100644 --- a/variables.tf +++ b/variables.tf @@ -55,12 +55,6 @@ variable "packer_version" { default = "1.10.3" } -variable "assets_bucket_name" { - description = "Name of the S3 bucket to store deployment artifacts" - type = string - default = "image-pipeline-assets-dev" -} - variable "template_bucket" { description = "S3 bucket containing the packaged CloudFormation templates" type = string @@ -88,31 +82,16 @@ variable "subnet_ids" { type = list(string) } -variable "packer_bucket_name" { - description = "Name of the S3 bucket containing Packer templates" - type = string -} - variable "packer_bucket_key" { description = "Key (path) to the Packer templates archive in S3" type = string } -variable "ansible_bucket_name" { - description = "Name of the S3 bucket containing Ansible roles" - type = string -} - variable "ansible_bucket_key" { description = "Key (path) to the Ansible roles archive in S3" type = string } -variable "pip_bucket_name" { - description = "Name of the S3 bucket containing pip configuration" - type = string -} - variable "pip_bucket_key" { description = "Key (path) to the pip configuration archive in S3" type = string @@ -142,16 +121,10 @@ variable "tags" { default = {} } -variable buildspec_bucket_name { - description = "Name of the S3 bucket containing the buildspec file" - type = string - default = "image-pipeline-assets-dev" -} - variable buildspec_bucket_key { description = "Key (path) to the buildspec file in S3" type = string - default = "buildspec.zip" + default = "buildspec.yml" } variable "additional_security_group_id" { @@ -218,7 +191,7 @@ variable "shared_accounts" { variable "enable_service_catalog" { description = "Whether to create Service Catalog resources for self-service deployment" type = bool - default = false + default = true } variable "portfolio_name" { @@ -261,4 +234,10 @@ variable "principal_arns" { description = "List of IAM principal ARNs (users, roles, groups) to grant access to the Service Catalog portfolio" type = list(string) default = [] +} + +variable global_assets_bucket { + description = "Name of the S3 bucket containing global assets like Packer, Ansible, and pip configurations" + type = string + default = "image-pipeline-assets-dev" } \ No newline at end of file