From 8f745ce898f8334461505fc1d4e18e4a3bdb070e Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 5 Aug 2026 12:01:05 -0400 Subject: [PATCH 1/3] feat(iac): add hcp terraform config for prod migration Migrate afi-backup-monitor deploy path from SAM CD to HCP Terraform parity config; freeze mgmt by removing push-to-main SAM deploy. --- .github/workflows/ci-terraform.yaml | 32 ++++++++++++++ .github/workflows/deploy.yaml | 22 ---------- .gitignore | 6 +++ README.md | 25 ++++++----- terraform/.terraform.lock.hcl | 46 +++++++++++++++++++ terraform/events.tf | 41 +++++++++++++++++ terraform/iam.tf | 47 ++++++++++++++++++++ terraform/lambda.tf | 68 +++++++++++++++++++++++++++++ terraform/locals.tf | 24 ++++++++++ terraform/outputs.tf | 14 ++++++ terraform/providers.tf | 11 +++++ terraform/terraform.tfvars.example | 6 +++ terraform/variables.tf | 37 ++++++++++++++++ terraform/versions.tf | 22 ++++++++++ 14 files changed, 367 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/ci-terraform.yaml delete mode 100644 .github/workflows/deploy.yaml create mode 100644 terraform/.terraform.lock.hcl create mode 100644 terraform/events.tf create mode 100644 terraform/iam.tf create mode 100644 terraform/lambda.tf create mode 100644 terraform/locals.tf create mode 100644 terraform/outputs.tf create mode 100644 terraform/providers.tf create mode 100644 terraform/terraform.tfvars.example create mode 100644 terraform/variables.tf create mode 100644 terraform/versions.tf diff --git a/.github/workflows/ci-terraform.yaml b/.github/workflows/ci-terraform.yaml new file mode 100644 index 0000000..e286816 --- /dev/null +++ b/.github/workflows/ci-terraform.yaml @@ -0,0 +1,32 @@ +name: Terraform CI +on: + pull_request: + branches: [main] + paths: + - "terraform/**" + - ".github/workflows/ci-terraform.yaml" + +permissions: + contents: read + +jobs: + terraform: + runs-on: ubuntu-latest + defaults: + run: + working-directory: terraform + steps: + - uses: actions/checkout@v4 + + - uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "1.9.8" + + - name: Terraform fmt + run: terraform fmt -check -recursive + + - name: Terraform init + run: terraform init -backend=false + + - name: Terraform validate + run: terraform validate diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml deleted file mode 100644 index 20df579..0000000 --- a/.github/workflows/deploy.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Deploy -on: - push: - branches: [main] - -permissions: - id-token: write - contents: read - -concurrency: - group: deploy - cancel-in-progress: false - -jobs: - deploy: - uses: Sea-Haven-Industries/.github/.github/workflows/cd-sam.yaml@3f746774229d41770727e2e4fd63ed5f5555a8b3 # v1.0.3 - with: - stack-name: afi-backup-monitor - cfn-role-arn: arn:aws:iam::328440206208:role/github-cfn-execution-role - secrets: - deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} - parameter-overrides: ${{ secrets.SAM_PARAMETER_OVERRIDES }} diff --git a/.gitignore b/.gitignore index bbb6e3b..b2469e1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,9 @@ __pycache__/ *.pyc .env samconfig.toml +terraform/build/ +terraform/.terraform/ +*.tfvars +!terraform/*.tfvars.example +.terraform.tfstate* +crash.log diff --git a/README.md b/README.md index 8b9e9b1..cbf6444 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,12 @@ ![CI](https://github.com/Sea-Haven-Industries/afi-backup-monitor/actions/workflows/ci.yaml/badge.svg) ![Python](https://img.shields.io/badge/Python-3776AB?logo=python&logoColor=white) -![AWS SAM](https://img.shields.io/badge/AWS-SAM-FF9900?logo=amazonaws&logoColor=white) +![Terraform](https://img.shields.io/badge/Terraform-844FBA?logo=terraform&logoColor=white) ![Slack](https://img.shields.io/badge/Slack-integration-4A154B?logo=slack&logoColor=white) -AWS SAM stack with two Lambda functions that integrate the Afi.ai backup API with Slack. +HCP Terraform stack with two Lambda functions that integrate the Afi.ai backup API with Slack. Deployed to **seahaven-prod** via workspace `afi-backup-monitor-prod` (PLAT-56). + +`template.yaml` remains as the historical SAM reference for the mgmt stack during cutover; deploy path is HCP Terraform only. ## Functions @@ -16,14 +18,17 @@ AWS SAM stack with two Lambda functions that integrate the Afi.ai backup API wit ## Architecture - **Runtime:** Python 3.12 (arm64) +- **IaC:** Terraform under `terraform/` (HCP remote apply, Manual until sealed) - **Shared Layer:** Afi API client + Slack webhook helper -- **Secrets:** Afi API key and Slack webhook URL stored in AWS Secrets Manager +- **Secrets:** Afi API key and Slack webhook URL in Secrets Manager (ARNs as Terraform variables; values never in state) - **Scheduling:** EventBridge cron rules (default: Mondays 10am ET) +- **IAM:** Execution roles under path `/tf-managed/` with `seahaven-lambda-execution-boundary` ## Repository Structure ``` -template.yaml # SAM stack: Lambdas, shared layer, IAM, EventBridge schedules +terraform/ # HCP Terraform config (sole deploy path) +template.yaml # Historical SAM reference (mgmt cutover / rollback) src/ auto_protect/app.py # afi-auto-protect handler health_digest/app.py # afi-health-digest handler @@ -32,8 +37,7 @@ src/ slack.py # Slack webhook helper ``` -Deployment parameters (secret ARNs, tenant ID, policy ID, schedules) are defined in -`template.yaml` and supplied at deploy time via `samconfig.toml`. +Workspace Terraform variables: secret ARNs, tenant ID, policy ID (see `terraform/terraform.tfvars.example`). ## Documentation @@ -43,18 +47,15 @@ The canonical map of Sea Haven's AWS infrastructure lives in Confluence. This pr ## Setup -1. Store the Afi API key and Slack webhook URL in Secrets Manager: +1. Create secrets in seahaven-prod (exact ARNs are wired into the Lambda boundary and Terraform variables): ```bash aws secretsmanager create-secret --name afi-api-key --secret-string "appkey-YOUR_KEY" aws secretsmanager create-secret --name afi-slack-webhook --secret-string "https://hooks.slack.com/services/YOUR/WEBHOOK/URL" ``` -2. Update `samconfig.toml` with your Secret ARNs (`AfiApiKeySecretArn`, `SlackWebhookSecretArn`), Tenant ID, and Policy ID. +2. Set workspace variables in HCP (`afi-backup-monitor-prod`) from `terraform/terraform.tfvars.example`. -3. Build and deploy: - ```bash - sam build && sam deploy - ``` +3. Apply from the HCP workspace (Manual apply until the stack is sealed). Do not use local `terraform apply` against prod. ## Manual Testing diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..9e09f82 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,46 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/archive" { + version = "2.8.0" + constraints = "~> 2.0" + hashes = [ + "h1:WB6H5ksIZiyq1lQlD/PWeh+tn4FLsbSjVnRW3+4xe2Y=", + "zh:0d14713fdc259fb377d0b899ad3c650a34194bd52194c863303ef22a65a580e2", + "zh:369b56040c7a8085d04e7e8ffac1e2b321a3170e502f788819bc34b868ec016f", + "zh:4d1a3b983ed6af5a52bfe12794674ae55cbadfa6021b37106ade68b433ad216a", + "zh:5c547549e26e083573c78a966ca68ce6d7df6bb8f3948f66a575f07da46b74ea", + "zh:6de093e62a975eb19a5e3017ce38e6e3cb639c17b79648d2000e0a8348f0e997", + "zh:7267936c2cdbc448efeb594d73e6b56a53d6a7ae14fe88cdd2a4133adc3302f0", + "zh:7482f023050ed426b4b45116e1761643bc33b1fd4ce4a6fab207ae2571f35940", + "zh:76bbd93b234e5a2927d98b511d86565700f549b570871a194c35f944b96cefb7", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:c6afc4bc1f002bac9c173007dd4da05fde788cd14c2916089f958c33fedb0dfa", + "zh:d3ba40bd806a3a08e9237dece679193c99afb2085de6b45d7f5d1f673cfcd368", + "zh:e1ad7ded53ecd6f0e5b473a3b44eae2b2e885653a56050ab583d387332be02e4", + "zh:e93e78575ce82be6084cc153c24ba8f385dc8d6880888ee66e918460c870953d", + ] +} + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.100.0" + constraints = "~> 5.0" + hashes = [ + "h1:Ijt7pOlB7Tr7maGQIqtsLFbl7pSMIj06TVdkoSBcYOw=", + "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", + "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", + "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", + "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", + "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", + "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", + "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", + "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", + "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", + "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", + "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", + "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", + "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + ] +} diff --git a/terraform/events.tf b/terraform/events.tf new file mode 100644 index 0000000..7c83b89 --- /dev/null +++ b/terraform/events.tf @@ -0,0 +1,41 @@ +resource "aws_cloudwatch_event_rule" "auto_protect" { + name = "afi-auto-protect-weekly" + description = "Weekly check for unprotected users" + schedule_expression = var.auto_protect_schedule + state = "ENABLED" +} + +resource "aws_cloudwatch_event_target" "auto_protect" { + rule = aws_cloudwatch_event_rule.auto_protect.name + target_id = "afi-auto-protect" + arn = aws_lambda_function.auto_protect.arn +} + +resource "aws_lambda_permission" "auto_protect_events" { + statement_id = "AllowExecutionFromEventBridge" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.auto_protect.function_name + principal = "events.amazonaws.com" + source_arn = aws_cloudwatch_event_rule.auto_protect.arn +} + +resource "aws_cloudwatch_event_rule" "health_digest" { + name = "afi-health-digest-weekly" + description = "Weekly backup health digest to Slack" + schedule_expression = var.health_digest_schedule + state = "ENABLED" +} + +resource "aws_cloudwatch_event_target" "health_digest" { + rule = aws_cloudwatch_event_rule.health_digest.name + target_id = "afi-health-digest" + arn = aws_lambda_function.health_digest.arn +} + +resource "aws_lambda_permission" "health_digest_events" { + statement_id = "AllowExecutionFromEventBridge" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.health_digest.function_name + principal = "events.amazonaws.com" + source_arn = aws_cloudwatch_event_rule.health_digest.arn +} diff --git a/terraform/iam.tf b/terraform/iam.tf new file mode 100644 index 0000000..6fdcce9 --- /dev/null +++ b/terraform/iam.tf @@ -0,0 +1,47 @@ +data "aws_iam_policy_document" "lambda_assume" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "auto_protect" { + name = "afi-auto-protect" + path = "/tf-managed/" + assume_role_policy = data.aws_iam_policy_document.lambda_assume.json + permissions_boundary = local.boundary_arn +} + +resource "aws_iam_role_policy_attachment" "auto_protect_basic" { + role = aws_iam_role.auto_protect.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +resource "aws_iam_role_policy" "auto_protect_secrets" { + name = "secretsmanager-get" + role = aws_iam_role.auto_protect.id + policy = local.secrets_policy_json +} + +resource "aws_iam_role" "health_digest" { + name = "afi-health-digest" + path = "/tf-managed/" + assume_role_policy = data.aws_iam_policy_document.lambda_assume.json + permissions_boundary = local.boundary_arn +} + +resource "aws_iam_role_policy_attachment" "health_digest_basic" { + role = aws_iam_role.health_digest.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + +resource "aws_iam_role_policy" "health_digest_secrets" { + name = "secretsmanager-get" + role = aws_iam_role.health_digest.id + policy = local.secrets_policy_json +} diff --git a/terraform/lambda.tf b/terraform/lambda.tf new file mode 100644 index 0000000..39978cf --- /dev/null +++ b/terraform/lambda.tf @@ -0,0 +1,68 @@ +data "archive_file" "shared_layer" { + type = "zip" + source_dir = "${path.module}/../src/shared" + output_path = "${path.module}/build/afi-shared-layer.zip" +} + +data "archive_file" "auto_protect" { + type = "zip" + source_dir = "${path.module}/../src/auto_protect" + output_path = "${path.module}/build/afi-auto-protect.zip" + excludes = ["requirements.txt"] +} + +data "archive_file" "health_digest" { + type = "zip" + source_dir = "${path.module}/../src/health_digest" + output_path = "${path.module}/build/afi-health-digest.zip" + excludes = ["requirements.txt"] +} + +resource "aws_lambda_layer_version" "shared" { + layer_name = "afi-shared" + description = "Shared Afi API client and utilities" + filename = data.archive_file.shared_layer.output_path + source_code_hash = data.archive_file.shared_layer.output_base64sha256 + compatible_runtimes = ["python3.12"] + compatible_architectures = ["arm64"] +} + +resource "aws_lambda_function" "auto_protect" { + function_name = "afi-auto-protect" + role = aws_iam_role.auto_protect.arn + handler = "app.handler" + runtime = "python3.12" + architectures = ["arm64"] + memory_size = 256 + timeout = 120 + + filename = data.archive_file.auto_protect.output_path + source_code_hash = data.archive_file.auto_protect.output_base64sha256 + + layers = [aws_lambda_layer_version.shared.arn] + + environment { + variables = merge(local.common_env, { + AFI_POLICY_ID = var.afi_policy_id + }) + } +} + +resource "aws_lambda_function" "health_digest" { + function_name = "afi-health-digest" + role = aws_iam_role.health_digest.arn + handler = "app.handler" + runtime = "python3.12" + architectures = ["arm64"] + memory_size = 256 + timeout = 120 + + filename = data.archive_file.health_digest.output_path + source_code_hash = data.archive_file.health_digest.output_base64sha256 + + layers = [aws_lambda_layer_version.shared.arn] + + environment { + variables = local.common_env + } +} diff --git a/terraform/locals.tf b/terraform/locals.tf new file mode 100644 index 0000000..cb5deac --- /dev/null +++ b/terraform/locals.tf @@ -0,0 +1,24 @@ +locals { + account_id = "011934824531" + boundary_arn = "arn:aws:iam::${local.account_id}:policy/seahaven-lambda-execution-boundary" + + common_env = { + AFI_API_KEY_SECRET_ARN = var.afi_api_key_secret_arn + AFI_TENANT_ID = var.afi_tenant_id + SLACK_WEBHOOK_SECRET_ARN = var.slack_webhook_secret_arn + } + + secrets_policy_json = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = ["secretsmanager:GetSecretValue"] + Resource = [ + var.afi_api_key_secret_arn, + var.slack_webhook_secret_arn, + ] + } + ] + }) +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..5505cc0 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,14 @@ +output "auto_protect_function_arn" { + description = "Auto-protect Lambda ARN" + value = aws_lambda_function.auto_protect.arn +} + +output "health_digest_function_arn" { + description = "Health digest Lambda ARN" + value = aws_lambda_function.health_digest.arn +} + +output "shared_layer_arn" { + description = "Shared Lambda layer ARN" + value = aws_lambda_layer_version.shared.arn +} diff --git a/terraform/providers.tf b/terraform/providers.tf new file mode 100644 index 0000000..f90371e --- /dev/null +++ b/terraform/providers.tf @@ -0,0 +1,11 @@ +provider "aws" { + region = var.aws_region + + default_tags { + tags = { + Project = "afi-backup-monitor" + ManagedBy = "terraform" + Workspace = "afi-backup-monitor-prod" + } + } +} diff --git a/terraform/terraform.tfvars.example b/terraform/terraform.tfvars.example new file mode 100644 index 0000000..318abe0 --- /dev/null +++ b/terraform/terraform.tfvars.example @@ -0,0 +1,6 @@ +# Wire these as HCP workspace Terraform variables (never commit real .tfvars). +# Prod ARNs created 2026-08-05 (PLAT-56): +afi_api_key_secret_arn = "arn:aws:secretsmanager:us-east-1:011934824531:secret:afi-api-key-w0E02a" +slack_webhook_secret_arn = "arn:aws:secretsmanager:us-east-1:011934824531:secret:afi-slack-webhook-T4oR3G" +afi_tenant_id = "01KNHTNY89N7ZM6YETP4R083PB" +afi_policy_id = "01KNHTNY8GCQ0988BFSY6DR13B" diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..2fc9d59 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,37 @@ +variable "aws_region" { + type = string + description = "AWS region for all resources" + default = "us-east-1" +} + +variable "afi_api_key_secret_arn" { + type = string + description = "Secrets Manager ARN for the Afi API key (exact ARN, including suffix)" +} + +variable "slack_webhook_secret_arn" { + type = string + description = "Secrets Manager ARN for the Slack webhook URL (exact ARN, including suffix)" +} + +variable "afi_tenant_id" { + type = string + description = "Afi tenant ID for Google Workspace" +} + +variable "afi_policy_id" { + type = string + description = "Afi backup policy ID to assign to new users" +} + +variable "auto_protect_schedule" { + type = string + description = "EventBridge schedule for auto-protect (default Monday 10am ET)" + default = "cron(0 14 ? * MON *)" +} + +variable "health_digest_schedule" { + type = string + description = "EventBridge schedule for health digest (default Monday 10am ET)" + default = "cron(0 14 ? * MON *)" +} diff --git a/terraform/versions.tf b/terraform/versions.tf new file mode 100644 index 0000000..788f9b5 --- /dev/null +++ b/terraform/versions.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 1.7.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + archive = { + source = "hashicorp/archive" + version = "~> 2.0" + } + } + + cloud { + organization = "seahaven" + + workspaces { + name = "afi-backup-monitor-prod" + } + } +} From d853ae8eafb9cbffd51f0dfced6e1470e7927d83 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 5 Aug 2026 12:18:30 -0400 Subject: [PATCH 2/3] fix(iac): ship lambda zips via s3 for hcp plan/apply split HCP plan and apply workers do not share disk; carry archive bytes in the plan with content_base64 and add IAM depends_on before function create. --- terraform/artifacts.tf | 37 +++++++++++++++++++++++++++++++++++++ terraform/lambda.tf | 23 ++++++++++++++++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 terraform/artifacts.tf diff --git a/terraform/artifacts.tf b/terraform/artifacts.tf new file mode 100644 index 0000000..c6874f0 --- /dev/null +++ b/terraform/artifacts.tf @@ -0,0 +1,37 @@ +# HCP plan and apply run on separate workers. archive_file paths from plan are +# not on the apply worker, so zip bytes are carried in the plan via +# content_base64 and uploaded to S3 at apply time for Lambda to consume. + +resource "aws_s3_bucket" "artifacts" { + bucket = "afi-backup-monitor-artifacts-${local.account_id}" +} + +resource "aws_s3_bucket_public_access_block" "artifacts" { + bucket = aws_s3_bucket.artifacts.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_object" "shared_layer" { + bucket = aws_s3_bucket.artifacts.id + key = "afi-shared-layer.zip" + content_base64 = filebase64(data.archive_file.shared_layer.output_path) + source_hash = data.archive_file.shared_layer.output_base64sha256 +} + +resource "aws_s3_object" "auto_protect" { + bucket = aws_s3_bucket.artifacts.id + key = "afi-auto-protect.zip" + content_base64 = filebase64(data.archive_file.auto_protect.output_path) + source_hash = data.archive_file.auto_protect.output_base64sha256 +} + +resource "aws_s3_object" "health_digest" { + bucket = aws_s3_bucket.artifacts.id + key = "afi-health-digest.zip" + content_base64 = filebase64(data.archive_file.health_digest.output_path) + source_hash = data.archive_file.health_digest.output_base64sha256 +} diff --git a/terraform/lambda.tf b/terraform/lambda.tf index 39978cf..05a7b09 100644 --- a/terraform/lambda.tf +++ b/terraform/lambda.tf @@ -21,10 +21,13 @@ data "archive_file" "health_digest" { resource "aws_lambda_layer_version" "shared" { layer_name = "afi-shared" description = "Shared Afi API client and utilities" - filename = data.archive_file.shared_layer.output_path + s3_bucket = aws_s3_bucket.artifacts.id + s3_key = aws_s3_object.shared_layer.key source_code_hash = data.archive_file.shared_layer.output_base64sha256 compatible_runtimes = ["python3.12"] compatible_architectures = ["arm64"] + + depends_on = [aws_s3_object.shared_layer] } resource "aws_lambda_function" "auto_protect" { @@ -36,7 +39,8 @@ resource "aws_lambda_function" "auto_protect" { memory_size = 256 timeout = 120 - filename = data.archive_file.auto_protect.output_path + s3_bucket = aws_s3_bucket.artifacts.id + s3_key = aws_s3_object.auto_protect.key source_code_hash = data.archive_file.auto_protect.output_base64sha256 layers = [aws_lambda_layer_version.shared.arn] @@ -46,6 +50,12 @@ resource "aws_lambda_function" "auto_protect" { AFI_POLICY_ID = var.afi_policy_id }) } + + depends_on = [ + aws_s3_object.auto_protect, + aws_iam_role_policy_attachment.auto_protect_basic, + aws_iam_role_policy.auto_protect_secrets, + ] } resource "aws_lambda_function" "health_digest" { @@ -57,7 +67,8 @@ resource "aws_lambda_function" "health_digest" { memory_size = 256 timeout = 120 - filename = data.archive_file.health_digest.output_path + s3_bucket = aws_s3_bucket.artifacts.id + s3_key = aws_s3_object.health_digest.key source_code_hash = data.archive_file.health_digest.output_base64sha256 layers = [aws_lambda_layer_version.shared.arn] @@ -65,4 +76,10 @@ resource "aws_lambda_function" "health_digest" { environment { variables = local.common_env } + + depends_on = [ + aws_s3_object.health_digest, + aws_iam_role_policy_attachment.health_digest_basic, + aws_iam_role_policy.health_digest_secrets, + ] } From ef3b2d000dab4f45f6310a309e18978b5ba371b9 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Wed, 5 Aug 2026 12:20:46 -0400 Subject: [PATCH 3/3] chore(ci): pin checkout and setup-terraform actions to release SHA Signed-off-by: Adam Moussa --- .github/workflows/ci-terraform.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-terraform.yaml b/.github/workflows/ci-terraform.yaml index e286816..76ea937 100644 --- a/.github/workflows/ci-terraform.yaml +++ b/.github/workflows/ci-terraform.yaml @@ -16,9 +16,9 @@ jobs: run: working-directory: terraform steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: hashicorp/setup-terraform@v3 + - uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # v3.0.0 with: terraform_version: "1.9.8"