From f9bdc746ef6beaeddb5e9bc9f340321c4cb97cae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 10:19:18 +0200 Subject: [PATCH 1/6] build(deps): bump hashicorp/archive in /infra/environments/dev (#1) Bumps [hashicorp/archive](https://github.com/hashicorp/terraform-provider-archive) from 2.7.1 to 2.8.0. - [Release notes](https://github.com/hashicorp/terraform-provider-archive/releases) - [Changelog](https://github.com/hashicorp/terraform-provider-archive/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-provider-archive/compare/v2.7.1...v2.8.0) --- updated-dependencies: - dependency-name: hashicorp/archive dependency-version: 2.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- infra/environments/dev/.terraform.lock.hcl | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/infra/environments/dev/.terraform.lock.hcl b/infra/environments/dev/.terraform.lock.hcl index a3683ad..debe0df 100644 --- a/infra/environments/dev/.terraform.lock.hcl +++ b/infra/environments/dev/.terraform.lock.hcl @@ -2,22 +2,23 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/archive" { - version = "2.7.1" + version = "2.8.0" constraints = "~> 2.0" hashes = [ - "h1:A7EnRBVm4h9ryO9LwxYnKr4fy7ExPMwD5a1DsY7m1Y0=", - "zh:19881bb356a4a656a865f48aee70c0b8a03c35951b7799b6113883f67f196e8e", - "zh:2fcfbf6318dd514863268b09bbe19bfc958339c636bcbcc3664b45f2b8bf5cc6", - "zh:3323ab9a504ce0a115c28e64d0739369fe85151291a2ce480d51ccbb0c381ac5", - "zh:362674746fb3da3ab9bd4e70c75a3cdd9801a6cf258991102e2c46669cf68e19", - "zh:7140a46d748fdd12212161445c46bbbf30a3f4586c6ac97dd497f0c2565fe949", + "h1:WB6H5ksIZiyq1lQlD/PWeh+tn4FLsbSjVnRW3+4xe2Y=", + "zh:0d14713fdc259fb377d0b899ad3c650a34194bd52194c863303ef22a65a580e2", + "zh:369b56040c7a8085d04e7e8ffac1e2b321a3170e502f788819bc34b868ec016f", + "zh:4d1a3b983ed6af5a52bfe12794674ae55cbadfa6021b37106ade68b433ad216a", + "zh:5c547549e26e083573c78a966ca68ce6d7df6bb8f3948f66a575f07da46b74ea", + "zh:6de093e62a975eb19a5e3017ce38e6e3cb639c17b79648d2000e0a8348f0e997", + "zh:7267936c2cdbc448efeb594d73e6b56a53d6a7ae14fe88cdd2a4133adc3302f0", + "zh:7482f023050ed426b4b45116e1761643bc33b1fd4ce4a6fab207ae2571f35940", + "zh:76bbd93b234e5a2927d98b511d86565700f549b570871a194c35f944b96cefb7", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:875e6ce78b10f73b1efc849bfcc7af3a28c83a52f878f503bb22776f71d79521", - "zh:b872c6ed24e38428d817ebfb214da69ea7eefc2c38e5a774db2ccd58e54d3a22", - "zh:cd6a44f731c1633ae5d37662af86e7b01ae4c96eb8b04144255824c3f350392d", - "zh:e0600f5e8da12710b0c52d6df0ba147a5486427c1a2cc78f31eea37a47ee1b07", - "zh:f21b2e2563bbb1e44e73557bcd6cdbc1ceb369d471049c40eb56cb84b6317a60", - "zh:f752829eba1cc04a479cf7ae7271526b402e206d5bcf1fcce9f535de5ff9e4e6", + "zh:c6afc4bc1f002bac9c173007dd4da05fde788cd14c2916089f958c33fedb0dfa", + "zh:d3ba40bd806a3a08e9237dece679193c99afb2085de6b45d7f5d1f673cfcd368", + "zh:e1ad7ded53ecd6f0e5b473a3b44eae2b2e885653a56050ab583d387332be02e4", + "zh:e93e78575ce82be6084cc153c24ba8f385dc8d6880888ee66e918460c870953d", ] } From b0fe817ac04a8537aa7245f006c88929b9edafd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 10:19:23 +0200 Subject: [PATCH 2/6] build(deps): bump hashicorp/aws in /infra/environments/dev (#2) Bumps [hashicorp/aws](https://github.com/hashicorp/terraform-provider-aws) from 6.38.0 to 6.50.0. - [Release notes](https://github.com/hashicorp/terraform-provider-aws/releases) - [Changelog](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-provider-aws/compare/v6.38.0...v6.50.0) --- updated-dependencies: - dependency-name: hashicorp/aws dependency-version: 6.50.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- infra/environments/dev/.terraform.lock.hcl | 33 +++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/infra/environments/dev/.terraform.lock.hcl b/infra/environments/dev/.terraform.lock.hcl index debe0df..4788d58 100644 --- a/infra/environments/dev/.terraform.lock.hcl +++ b/infra/environments/dev/.terraform.lock.hcl @@ -23,24 +23,25 @@ provider "registry.terraform.io/hashicorp/archive" { } provider "registry.terraform.io/hashicorp/aws" { - version = "6.38.0" + version = "6.50.0" constraints = "~> 6.0" hashes = [ - "h1:RDoKIzXmt7H1mNFcNIyRT+nA/gTJyO3+iW9QGN5I2eQ=", - "zh:143f118ae71059a7a7026c6b950da23fef04a06e2362ffa688bef75e43e869ed", - "zh:29ee220a017306effd877e1280f8b2934dc957e16e0e72ca0222e5514d0db522", - "zh:3a31baabf7aea7aa7669f5a3d76f3445e0e6cce5e9aea0279992765c0df12aee", - "zh:4c1908e62040dbc9901d4426ffb253f53e5dae9e3e1a9125311291ee265c8d8c", - "zh:550f4789f5f5b00e16118d4c17770be3ef4535d6b6928af1cf91ebd30f2c263b", - "zh:6537b7b70bf2c127771b0b84e4b726c834d10666b6104f017edae50c67ebae37", + "h1:D8uNiOpl3UkAX4zI5T47ALMiRFXTa1XfdQC+TBu3RmE=", + "zh:0072806bb262c6d86bc25b4a75750e469881144c14818afdba7b82db840e1588", + "zh:1ebc2dae335dad7a8b16a1985b69a63a14954282bb44fdba7d5103f77551ac7b", + "zh:2dab48fe8f3193b8216d578ac1e3674fa566435cc7dbce2953d55b72e31d0241", + "zh:2fc3d3029c2b7429472391ef339672e1fca8e6ff32c8a519bf3acedafa7e24fe", + "zh:38a36e64e7212f6cedac861ea4d449cce07131b3378de601bf9d49a99e000208", + "zh:3ac70758ed251ce78b7f541a5a79cc6fe56474412783ae1decef719bdd0f30bf", + "zh:4385d3903e685bddb2b8005b4eb7db89f030267d4d03c7d792d2f5e739cc874a", + "zh:4cce0760b87fbafd51f30faec2a737f4183b7c615f4a86557f7d3c893a610dc5", + "zh:4feaeed18694239b896c6415d9a1e5ef89e1da4f4ad60924aa0522adeb1f6599", + "zh:502fca2be1c95f443c3e67d0555601d1de65b4ca82d197c059e9c868360e3a0a", + "zh:57d037f6fdd045f2660909c3bdface9622d81165ce647479cba98d1f353c5eab", + "zh:5dc5a0b915c2ac5256d909458f5c8e40b35f78b3a36ea893c86624eaf6c54e37", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:af2f9cea0c8bdf5b2a2391f2d179a946c117196f7c829b919673cae3b71d2943", - "zh:c53ffa685381aa4e73158fd9f529239f95938dea330e7aca0b32e7b2a1210432", - "zh:d0995e1d64a7ec8bbc79fc3fbec3749f989e07f211a318705c37cd6a7c7d19e4", - "zh:d2348ffcffc1282983d7a5838dd5d61f372152fe6c0d10868cd6473352318750", - "zh:e449312efb73e4747165e689302a68a1df8ba5755e7f59097069acf82c94f011", - "zh:ec3a538d264ef79380e56fdf107ffb6c0446814f07fc5890c36855fe1e03196b", - "zh:f441e69699b22e32c96a8cdd3bbe694ed302c0dcfe867cd9bd683a16df362714", - "zh:f6f8eaa605ff902234d7e9bdab4fda977185fce14f8576f7b622c914c7d98008", + "zh:b84c87c58a320adbb2c74a4cad03ae5aac7f2eae21db26f00fdde98c8c4d4523", + "zh:c895f1d5cbcbeff77850ac99efd36bde0048d4e909b296882331b9b9ebf48cfa", + "zh:ead82831683619124597a1f170dd31e9b293e9cf22f558cb166d5e734fcd11e4", ] } From 22bd60a8680f3628b02ca21f604896ae5c04594a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 10:19:27 +0200 Subject: [PATCH 3/6] build(deps): bump hashicorp/setup-terraform from 3 to 4 (#3) Bumps [hashicorp/setup-terraform](https://github.com/hashicorp/setup-terraform) from 3 to 4. - [Release notes](https://github.com/hashicorp/setup-terraform/releases) - [Changelog](https://github.com/hashicorp/setup-terraform/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/setup-terraform/compare/v3...v4) --- updated-dependencies: - dependency-name: hashicorp/setup-terraform dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59cffc4..5d48216 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: pip install black flake8 - name: Setup Terraform - uses: hashicorp/setup-terraform@v3 + uses: hashicorp/setup-terraform@v4 with: terraform_version: 1.5.7 From 7528eb3c46692aecb75cc50c5296a79d139b5127 Mon Sep 17 00:00:00 2001 From: Giselle Evita Koch <117114437+giselleevita@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:22:20 +0200 Subject: [PATCH 4/6] ci: add tfsec and tflint scanning (#6) * ci: add tfsec and tflint scanning jobs Makes the profile's tfsec/tflint claim enforceable in CI. Co-Authored-By: Claude Fable 5 * fix(security): encrypt CloudTrail + DynamoDB, enable PITR; gate tfsec at HIGH - CMK with CloudTrail and CloudWatch Logs key policy; trail and log group encrypted - DynamoDB server-side encryption and point-in-time recovery - tfsec gates HIGH/CRITICAL; remaining medium/low findings visible in scan output Co-Authored-By: Claude Fable 5 * fix(security): encrypt the observability CloudTrail trail with the storage CMK The key policy for CloudTrail already existed on the storage CMK; the trail was simply never pointed at it. Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- .github/workflows/ci.yml | 16 ++++++ infra/environments/dev/observability.tf | 1 + infra/environments/dev/security/cloudtrail.tf | 50 +++++++++++++++++++ infra/modules/dynamodb/main.tf | 8 +++ 4 files changed, 75 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d48216..88b5da7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,22 @@ jobs: - name: Terraform validate run: terraform -chdir=infra/environments/dev validate + + - name: Setup tflint + uses: terraform-linters/setup-tflint@v4 + + - name: tflint + run: | + cd infra + tflint --init + tflint --recursive --minimum-failure-severity=error + + - name: tfsec + uses: aquasecurity/tfsec-action@v1.0.3 + with: + working_directory: infra + additional_args: --minimum-severity HIGH + - name: Secrets and hygiene check run: sh scripts/security/check_secrets.sh diff --git a/infra/environments/dev/observability.tf b/infra/environments/dev/observability.tf index 2c51828..fda166b 100644 --- a/infra/environments/dev/observability.tf +++ b/infra/environments/dev/observability.tf @@ -114,6 +114,7 @@ resource "aws_kms_key_policy" "cloudtrail" { resource "aws_cloudtrail" "secure_docs" { name = "secure-docs-trail" s3_bucket_name = module.storage.bucket_name + kms_key_id = module.storage.kms_key_arn enable_log_file_validation = true include_global_service_events = true is_multi_region_trail = true diff --git a/infra/environments/dev/security/cloudtrail.tf b/infra/environments/dev/security/cloudtrail.tf index 900ab74..ac1f697 100644 --- a/infra/environments/dev/security/cloudtrail.tf +++ b/infra/environments/dev/security/cloudtrail.tf @@ -20,14 +20,64 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "cloudtrail_logs" } } +resource "aws_kms_key" "cloudtrail" { + description = "CMK for CloudTrail trail and log-group encryption" + deletion_window_in_days = 7 + enable_key_rotation = true + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "EnableRootAccountAdmin" + Effect = "Allow" + Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" } + Action = "kms:*" + Resource = "*" + }, + { + Sid = "AllowCloudTrailEncrypt" + Effect = "Allow" + Principal = { Service = "cloudtrail.amazonaws.com" } + Action = ["kms:GenerateDataKey*", "kms:DescribeKey"] + Resource = "*" + Condition = { + StringLike = { + "kms:EncryptionContext:aws:cloudtrail:arn" = "arn:aws:cloudtrail:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:trail/secure-docs-aws-trail" + } + } + }, + { + Sid = "AllowCloudWatchLogsUse" + Effect = "Allow" + Principal = { Service = "logs.${data.aws_region.current.name}.amazonaws.com" } + Action = ["kms:Encrypt*", "kms:Decrypt*", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:Describe*"] + Resource = "*" + Condition = { + ArnLike = { + "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/cloudtrail/secure-docs-aws" + } + } + } + ] + }) +} + +resource "aws_kms_alias" "cloudtrail" { + name = "alias/secure-docs-cloudtrail" + target_key_id = aws_kms_key.cloudtrail.key_id +} + resource "aws_cloudwatch_log_group" "secure_docs_cloudtrail" { name = "/aws/cloudtrail/secure-docs-aws" retention_in_days = 365 + kms_key_id = aws_kms_key.cloudtrail.arn } resource "aws_cloudtrail" "secure_docs" { name = "secure-docs-aws-trail" s3_bucket_name = aws_s3_bucket.cloudtrail_logs.id + kms_key_id = aws_kms_key.cloudtrail.arn include_global_service_events = true is_multi_region_trail = false enable_log_file_validation = true diff --git a/infra/modules/dynamodb/main.tf b/infra/modules/dynamodb/main.tf index 9152363..f790369 100644 --- a/infra/modules/dynamodb/main.tf +++ b/infra/modules/dynamodb/main.tf @@ -14,6 +14,14 @@ resource "aws_dynamodb_table" "users" { type = "S" } + server_side_encryption { + enabled = true + } + + point_in_time_recovery { + enabled = true + } + tags = { Project = "secure-docs" Environment = var.environment From b53dc6c07f1e435edc2e6e3c30f9accd1c293864 Mon Sep 17 00:00:00 2001 From: Giselle Evita Koch <117114437+giselleevita@users.noreply.github.com> Date: Tue, 21 Jul 2026 13:14:34 +0200 Subject: [PATCH 5/6] README diagram + CI badge, fill empty overview, honest test docs, drop scratch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Mermaid request-flow diagram and CI status badge above the fold - Write docs/architecture/overview.md (was 0 bytes but linked first in docs/index.md) - tests/README referenced scripts/verification/*.sh that don't exist — replaced with the real manual curl verification and the existing check_secrets.sh - Remove scratch files infra/SECRETS_PATTERN.py, infra/environments/dev/LAMBDA_VPC_PATCH.txt Co-Authored-By: Claude Fable 5 --- README.md | 14 +++ docs/architecture/overview.md | 35 ++++++ infra/SECRETS_PATTERN.py | 113 -------------------- infra/environments/dev/LAMBDA_VPC_PATCH.txt | 53 --------- tests/README.md | 16 ++- 5 files changed, 60 insertions(+), 171 deletions(-) delete mode 100644 infra/SECRETS_PATTERN.py delete mode 100644 infra/environments/dev/LAMBDA_VPC_PATCH.txt diff --git a/README.md b/README.md index 9a9ac96..5338ea8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ # SecureDocs AWS +[![CI](https://github.com/giselleevita/secure-docs-aws/actions/workflows/ci.yml/badge.svg)](https://github.com/giselleevita/secure-docs-aws/actions/workflows/ci.yml) + _A security-focused document storage service on AWS that teaches IAM, S3, KMS, CloudTrail, and ownership-enforcement patterns._ +```mermaid +flowchart LR + U["Client"] -->|"JWT"| APIGW["API Gateway
(Cognito JWT authorizer)"] + APIGW --> UP["Lambda: upload"] + APIGW --> LS["Lambda: list"] + APIGW --> DL["Lambda: download"] + APIGW --> DEL["Lambda: delete"] + UP & LS & DL & DEL -->|"owner_id check"| DDB[("DynamoDB
metadata")] + UP & DL & DEL -->|"presigned URL (5 min)"| S3[("S3
private + SSE-KMS + versioned")] + APIGW & UP & LS & DL & DEL -->|"logs"| CT["CloudTrail + CloudWatch Logs"] +``` + ## Overview SecureDocs AWS is a serverless document service where authenticated users can upload, list, download, and delete only their own files. The project is deliberately small, but it exercises the core security controls that matter in a multi-user cloud system. diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index e69de29..4dec908 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -0,0 +1,35 @@ +# System Overview + +SecureDocs AWS is a serverless, single-tenant-per-user document store. Every +request is authenticated and every object access is authorized against the +caller's identity before any data is returned. + +## Request flow + +1. **Authenticate** — the client presents a Cognito-issued JWT. API Gateway's + JWT authorizer validates it before any Lambda runs. +2. **Route** — API Gateway dispatches to one of four purpose-built Lambdas: + `upload`, `list`, `download`, `delete`. Each has its own IAM role scoped to + only the actions it needs. +3. **Authorize ownership** — the Lambda looks up file metadata in DynamoDB + keyed by `owner_id` + `object_key`, and refuses (403) any access to an object + the caller does not own. +4. **Access storage** — instead of proxying bytes or handing out S3 credentials, + the Lambda returns a short-lived (5-minute) presigned URL. The bucket blocks + public access, encrypts at rest with SSE-KMS, and keeps object versions. +5. **Audit** — API Gateway, Lambda, and S3 activity is captured by CloudTrail + and CloudWatch Logs. + +## Components + +| Component | Role | +|---|---| +| Cognito | User identity and JWT issuance | +| API Gateway | JWT authorizer, routing | +| Lambda (×4) | Per-operation handlers, least-privilege IAM roles | +| DynamoDB | Ownership metadata (`owner_id`, `object_key`) | +| S3 | Encrypted, private, versioned object storage | +| KMS | Encryption keys for S3 objects | +| CloudTrail + CloudWatch | Audit trail | + +See [decisions.md](./decisions.md) for the security rationale behind each choice. diff --git a/infra/SECRETS_PATTERN.py b/infra/SECRETS_PATTERN.py deleted file mode 100644 index 27db67a..0000000 --- a/infra/SECRETS_PATTERN.py +++ /dev/null @@ -1,113 +0,0 @@ -# Python Lambda Handler — Secrets Manager Integration Pattern -# -# This snippet demonstrates how to read a secret from AWS Secrets Manager -# without storing credentials in code or environment files. -# -# Usage: Place the secret ARN in a Lambda environment variable, then call -# get_secret() at the beginning of your handler. -# -# Example Lambda deployment with secret ARN: -# environment { -# variables = { -# SECRET_ARN = aws_secretsmanager_secret.example.arn -# } -# } - -import json -import os -import boto3 - -secrets_client = boto3.client("secretsmanager") - -def get_secret(secret_arn: str) -> dict: - """ - Retrieve a secret from AWS Secrets Manager using its ARN. - - Args: - secret_arn: ARN of the secret to retrieve - - Returns: - dict: Parsed secret value (assumes JSON format) - """ - try: - response = secrets_client.get_secret_value(SecretId=secret_arn) - secret_value = json.loads(response["SecretString"]) - return secret_value - except Exception as e: - print(f"Error retrieving secret: {e}") - raise - - -def handler(event, context): - """ - Lambda handler that reads a database password from Secrets Manager. - """ - # Get the secret ARN from environment variable - secret_arn = os.environ.get("DB_SECRET_ARN") - - # Retrieve the secret (API key, database password, etc.) - secret = get_secret(secret_arn) - - # Extract specific key from secret - db_password = secret.get("password") - - # Use the secret in your business logic - # DO NOT log or print the secret value - - return { - "statusCode": 200, - "body": json.dumps({"message": "Secret retrieved successfully"}) - } - - -# ───────────────────────────────────────────────────────────────────────────── -# Corresponding Terraform Definitions: -# -# # Create a secret in AWS Secrets Manager -# resource "aws_secretsmanager_secret" "db_password" { -# name = "secure-docs/db-password" -# description = "Database password for SecureDocs" -# recovery_window_in_days = 7 -# } -# -# # Store the actual secret value -# resource "aws_secretsmanager_secret_version" "db_password" { -# secret_id = aws_secretsmanager_secret.db_password.id -# secret_string = jsonencode({ -# password = var.db_password # Injected via terraform apply -var or .tfvars -# username = "dbuser" -# }) -# } -# -# # Add permission to Lambda IAM role to read this secret -# resource "aws_iam_role_policy" "lambda_secrets_access" { -# name = "lambda-secrets-access" -# role = module.lambda_roles.upload_role_arn -# policy = jsonencode({ -# Version = "2012-10-17" -# Statement = [ -# { -# Effect = "Allow" -# Action = [ -# "secretsmanager:GetSecretValue" -# ] -# Resource = aws_secretsmanager_secret.db_password.arn -# } -# ] -# }) -# } -# -# # Lambda function with secret ARN in environment -# resource "aws_lambda_function" "example" { -# function_name = "lambda-example" -# runtime = "python3.12" -# handler = "lambda_function.handler" -# role = module.lambda_roles.upload_role_arn -# filename = "lambda_function.zip" -# -# environment { -# variables = { -# SECRET_ARN = aws_secretsmanager_secret.db_password.arn -# } -# } -# } diff --git a/infra/environments/dev/LAMBDA_VPC_PATCH.txt b/infra/environments/dev/LAMBDA_VPC_PATCH.txt deleted file mode 100644 index aec8a0b..0000000 --- a/infra/environments/dev/LAMBDA_VPC_PATCH.txt +++ /dev/null @@ -1,53 +0,0 @@ -# V3 Production Layer — Lambda VPC Integration -# -# Add the following subnet_ids and security_groups parameters to each -# aws_lambda_function resource in lambda.tf to place functions in the VPC: -# -# Example patch for lambda.tf: -# -# resource "aws_lambda_function" "upload_presigned" { -# # ... existing configuration ... -# vpc_config { -# subnet_ids = [aws_subnet.lambda_1.id, aws_subnet.lambda_2.id] -# security_group_ids = [aws_security_group.lambda.id] -# } -# } -# -# resource "aws_lambda_function" "list_files" { -# # ... existing configuration ... -# vpc_config { -# subnet_ids = [aws_subnet.lambda_1.id, aws_subnet.lambda_2.id] -# security_group_ids = [aws_security_group.lambda.id] -# } -# } -# -# resource "aws_lambda_function" "download_file" { -# # ... existing configuration ... -# vpc_config { -# subnet_ids = [aws_subnet.lambda_1.id, aws_subnet.lambda_2.id] -# security_group_ids = [aws_security_group.lambda.id] -# } -# } -# -# resource "aws_lambda_function" "delete_file" { -# # ... existing configuration ... -# vpc_config { -# subnet_ids = [aws_subnet.lambda_1.id, aws_subnet.lambda_2.id] -# security_group_ids = [aws_security_group.lambda.id] -# } -# } -# -# ───────────────────────────────────────────────────────────────────────────── -# -# The vpc_config placement allows Lambda to: -# - Access VPC endpoints for S3, DynamoDB, KMS, CloudWatch Logs, STS, Secrets Manager -# - Remain completely private (no internet connectivity) -# - Route all AWS API calls through the VPC endpoint security group -# -# Impact on cold start: -# - First invocation: +100-300ms (ENI attachment) -# - Subsequent calls: negligible latency increase -# -# Monitoring: -# - Check VPC Flow Logs in CloudWatch: /aws/vpc/secure-docs-flow-logs -# - Verify endpoint traffic in VPC Endpoint metrics (CloudWatch) diff --git a/tests/README.md b/tests/README.md index 72d95a7..ff6e9e3 100644 --- a/tests/README.md +++ b/tests/README.md @@ -11,14 +11,20 @@ All tests use synthetic, public-safe data and no real customer data or credentia ## How to run -- Run end-to-end verification scripts from the repository root: +Verification is manual against a deployed environment. Read the endpoint, +Cognito pool, and bucket values from `terraform output` for the target +environment (e.g. `infra/environments/dev`), obtain a Cognito JWT for a test +user, then exercise the API with `curl`: ```bash -sh scripts/verification/verify_secure_docs.sh -sh scripts/verification/test_secure_docs.sh -``` +# happy path — own file +curl -H "Authorization: Bearer $JWT" "$API/files" # 200, lists caller's files +# denial path — another user's object +curl -H "Authorization: Bearer $JWT" "$API/files/$OTHER_KEY" # 403 -- Use environment-specific values from `terraform output` for the target environment (e.g., `infra/environments/dev`). +# repo hygiene check (no deploy needed) +sh scripts/security/check_secrets.sh +``` - Confirm expected success paths and denial paths (e.g., cross-user access must return 403). ## Pass criteria From 877c6ac21163b81361fd8d701593968b6c714c4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:06:18 +0000 Subject: [PATCH 6/6] build(deps): bump terraform-linters/setup-tflint from 4 to 6 Bumps [terraform-linters/setup-tflint](https://github.com/terraform-linters/setup-tflint) from 4 to 6. - [Release notes](https://github.com/terraform-linters/setup-tflint/releases) - [Commits](https://github.com/terraform-linters/setup-tflint/compare/v4...v6) --- updated-dependencies: - dependency-name: terraform-linters/setup-tflint dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88b5da7..b3ac582 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: - name: Setup tflint - uses: terraform-linters/setup-tflint@v4 + uses: terraform-linters/setup-tflint@v6 - name: tflint run: |