| 1 | mock_provider "aws" { |
| 2 | mock_data "aws_ec2_instance_type_offerings" { defaults = { locations = ["eu-west-1a", "eu-west-1b"] } } |
| 3 | mock_data "aws_region" { defaults = { region = "eu-west-1" } } |
| 4 | mock_data "aws_availability_zones" { defaults = { names = ["eu-west-1a", "eu-west-1b"] } } |
| 5 | mock_data "aws_ami" { defaults = { id = "ami-0123456789abcdef0" } } |
| 6 | mock_resource "aws_s3_bucket" { defaults = { arn = "arn:aws:s3:::mock-test-bucket", id = "mock-test-bucket" } } |
| 7 | mock_resource "aws_iam_role" { defaults = { arn = "arn:aws:iam::123456789012:role/test" } } |
| 8 | } |
| 9 | |
| 10 | variables { name = "test-bucket" } |
| 11 | run "storage_security" { |
| 12 | assert { |
| 13 | condition = jsondecode(aws_s3_bucket_policy.this.policy).Statement[0].Effect == "Deny" && jsondecode(aws_s3_bucket_policy.this.policy).Statement[0].Condition.Bool["aws:SecureTransport"] == "false" && jsondecode(aws_s3_bucket_policy.this.policy).Statement[0].Principal == "*" |
| 14 | error_message = "Require TLS for all bucket access." |
| 15 | } |
| 16 | assert { |
| 17 | condition = length(aws_s3_bucket_lifecycle_configuration.this.rule) == 1 && one(aws_s3_bucket_lifecycle_configuration.this.rule).abort_incomplete_multipart_upload[0].days_after_initiation == 7 |
| 18 | error_message = "Data buckets must retain database versions and clean abandoned uploads only." |
| 19 | } |
| 20 | command = plan |
| 21 | assert { |
| 22 | condition = aws_s3_bucket_versioning.this.versioning_configuration[0].status == "Enabled" && !aws_s3_bucket.this.force_destroy |
| 23 | error_message = "Retain object versions and refuse non-empty bucket destruction." |
| 24 | } |
| 25 | assert { |
| 26 | condition = aws_s3_bucket_public_access_block.this.block_public_acls && aws_s3_bucket_public_access_block.this.block_public_policy && aws_s3_bucket_public_access_block.this.ignore_public_acls && aws_s3_bucket_public_access_block.this.restrict_public_buckets |
| 27 | error_message = "All S3 public access controls must remain enabled." |
| 28 | } |
| 29 | assert { |
| 30 | condition = one(aws_s3_bucket_server_side_encryption_configuration.this.rule).apply_server_side_encryption_by_default[0].sse_algorithm == "AES256" |
| 31 | error_message = "Encrypt stored objects." |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | run "control_cleanup" { |
| 36 | command = plan |
| 37 | variables { control_plane = true } |
| 38 | assert { |
| 39 | condition = length(aws_s3_bucket_lifecycle_configuration.this.rule) == 4 |
| 40 | error_message = "Control buckets need the Platform cleanup rules." |
| 41 | } |
| 42 | assert { |
| 43 | condition = alltrue([for r in aws_s3_bucket_lifecycle_configuration.this.rule : r.expiration[0].days == 1 && r.noncurrent_version_expiration[0].noncurrent_days == 1 if r.id == "db-reads-expire"]) |
| 44 | error_message = "Forwarded database reads must expire current and old versions." |
| 45 | } |
| 46 | } |
| 47 | |