Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ sync by `node tools/ravion-modules/dist/src/cli.js readme` (enforced in CI, and
| `rvn-aws-alb` | AWS Application Load Balancer | v1.3.0 | `networking/alb/` |
| `rvn-aws-alternat` | alterNAT | v0.1.2 | `networking/alternat/` |
| `rvn-aws-ami` | AMI | v0.3.1 | `compute/ami/` |
| `rvn-aws-compliance` | AWS Compliance | v0.2.0 | `security/compliance/` |
| `rvn-aws-compliance` | AWS Compliance | v0.3.0 | `security/compliance/` |
| `rvn-aws-iam-policy` | AWS IAM Policy | v1.1.1 | `security/iam_policy/` |
| `rvn-aws-iam-role` | AWS IAM Role | v1.1.1 | `security/iam/` |
| `rvn-aws-kms` | AWS KMS Key | v0.2.0 | `security/kms/` |
Expand Down
23 changes: 20 additions & 3 deletions security/compliance/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# AWS compliance module

Manages GuardDuty threat detection and registry-wide Basic ECR image scanning on push for one AWS account across a shared list of Regions. Deploy `rvn-aws-compliance` once per account with all required Regions. These settings support threat-detection and vulnerability-scanning controls; application alarms, log retention, and other compliance controls remain in their respective modules.
Manages GuardDuty threat detection, registry-wide Basic ECR image scanning on push, and regional CloudTrail audit trails for one AWS account. Deploy `rvn-aws-compliance` once per account with all required Regions. The Regions list controls all three services; the runner Region hosts the shared log bucket.

## Features

- Registry-wide ECR Basic `SCAN_ON_PUSH` with a `*` filter for all current and future private repositories, including Lambda image repositories.
- One validated single-Region CloudTrail management-event trail per selected Region, sharing private, versioned log storage in the runner Region.
- One `aws_guardduty_detector` per Region, driven by the AWS provider's per-resource `region` argument (no provider alias per Region).
- Fails at plan time when a requested Region is not enabled (opted in) for the account.
- Explicit per-Region protection plans: S3 Protection, EKS Protection, Malware Protection for EC2, RDS Protection, Lambda Protection, and Runtime Monitoring with automated agent management for EKS, ECS Fargate, and EC2.
Expand Down Expand Up @@ -67,9 +68,22 @@ The AWS provider 6.x per-resource `region` argument is required. The credentials

## Inputs

CloudTrail is enabled by default: a single-Region trail in each selected Region records read/write management events with log file validation and no data events. The dedicated shared S3 bucket stays in the runner Region, with versioning, bucket-owner-enforced ownership and SSE-S3 encryption by default.

Include us-east-1 in Regions to capture IAM changes and other global service events (CloudFront and the STS global endpoint). Only that trail includes global service events; us-east-1 is never added automatically. STS regional-endpoint events are recorded in their respective Regions.

The first copy of management events per Region is free; an existing trail recording those events makes this a paid additional copy in that Region. Disable CloudTrail when an organization trail already provides coverage. S3 storage and optional KMS usage incur charges.

Current and noncurrent versions expire after the configured retention period (365 days by default); 0 disables expiry. Current-object expiry creates a delete marker before noncurrent expiry applies. Destroy, including disabling CloudTrail, fails while logs or versions remain in the bucket because force deletion is disabled.

A supplied KMS key encrypts trail deliveries and bucket objects. It must be in the bucket's runner Region, even for trails in other Regions. Its key policy must allow cloudtrail.amazonaws.com for every selected trail; this module does not manage that policy.

| Name | Description | Type | Default | Required |
| ---- | ----------- | ---- | ------- | :------: |
| `regions` | AWS Regions where GuardDuty and ECR scan-on-push are enabled. Each must be enabled for the account. | `list(string)` | n/a | yes |
| `regions` | Regions for GuardDuty, ECR scanning and CloudTrail. Include us-east-1 for IAM changes. Each must be enabled for the account. | `list(string)` | n/a | yes |
| `cloudtrail_enabled` | Create a single-Region management-event trail in each selected Region. | `bool` | `true` | no |
| `cloudtrail_log_retention_days` | Current and noncurrent log expiry; 0 keeps logs forever. | `number` | `365` | no |
| `cloudtrail_kms_key_arn` | Key in the bucket's runner Region whose policy permits encryption for every trail; null uses SSE-S3. | `string` | `null` | no |
| `finding_publishing_frequency` | Export cadence for updated findings: `FIFTEEN_MINUTES`, `ONE_HOUR`, or `SIX_HOURS`. | `string` | `"FIFTEEN_MINUTES"` | no |
| `s3_protection_enabled` | Enable S3 Protection (`S3_DATA_EVENTS`). | `bool` | `true` | no |
| `eks_protection_enabled` | Enable EKS Protection (`EKS_AUDIT_LOGS`). | `bool` | `true` | no |
Expand All @@ -84,7 +98,10 @@ The AWS provider 6.x per-resource `region` argument is required. The credentials

| Name | Description |
| ---- | ----------- |
| `regions` | Sorted list of Regions covered by GuardDuty and ECR scanning. |
| `regions` | Sorted list of Regions covered by GuardDuty, ECR scanning and optional CloudTrail. |
| `cloudtrail_arns` | Map of Region to trail ARN, empty when disabled. |
| `cloudtrail_bucket_name` | Audit log bucket name, or null when disabled. |
| `cloudtrail_bucket_arn` | Audit log bucket ARN, or null when disabled. |
| `detector_ids` | Map of Region to detector ID. |
| `detector_arns` | Map of Region to detector ARN. |
| `account_id` | AWS account ID where the baseline is managed. |
Expand Down
33 changes: 33 additions & 0 deletions security/compliance/cloudtrail.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
locals {
cloudtrail_name = "ravion-compliance"
cloudtrail_arns = {
for region in local.regions : region => "arn:${data.aws_partition.current.partition}:cloudtrail:${region}:${data.aws_caller_identity.current.account_id}:trail/${local.cloudtrail_name}"
if var.cloudtrail_enabled
}
}

resource "aws_cloudtrail" "this" {
for_each = var.cloudtrail_enabled ? local.regions : toset([])
region = each.key

name = local.cloudtrail_name
s3_bucket_name = aws_s3_bucket.cloudtrail[0].id
is_multi_region_trail = false
include_global_service_events = each.key == "us-east-1"
enable_log_file_validation = true
enable_logging = true
kms_key_id = var.cloudtrail_kms_key_arn

event_selector {
read_write_type = "All"
include_management_events = true
}

tags = local.tags

depends_on = [
aws_s3_bucket_policy.cloudtrail,
aws_s3_bucket_server_side_encryption_configuration.cloudtrail,
aws_s3_bucket_versioning.cloudtrail,
]
}
106 changes: 106 additions & 0 deletions security/compliance/cloudtrail_bucket.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
resource "aws_s3_bucket" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket_prefix = "ravion-cloudtrail-${data.aws_caller_identity.current.account_id}-"
force_destroy = false
tags = local.tags
}

resource "aws_s3_bucket_public_access_block" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

resource "aws_s3_bucket_ownership_controls" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
rule {
object_ownership = "BucketOwnerEnforced"
}
}

resource "aws_s3_bucket_server_side_encryption_configuration" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = var.cloudtrail_kms_key_arn == null ? "AES256" : "aws:kms"
kms_master_key_id = var.cloudtrail_kms_key_arn
}
}
}

resource "aws_s3_bucket_versioning" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
versioning_configuration {
status = "Enabled"
}
}

resource "aws_s3_bucket_lifecycle_configuration" "cloudtrail" {
count = var.cloudtrail_enabled && var.cloudtrail_log_retention_days > 0 ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
rule {
id = "audit-log-retention"
status = "Enabled"
filter {}
expiration {
days = var.cloudtrail_log_retention_days
}
noncurrent_version_expiration {
noncurrent_days = var.cloudtrail_log_retention_days
}
}
depends_on = [aws_s3_bucket_versioning.cloudtrail]
}

resource "aws_s3_bucket_policy" "cloudtrail" {
count = var.cloudtrail_enabled ? 1 : 0

bucket = aws_s3_bucket.cloudtrail[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "CloudTrailAclCheck"
Effect = "Allow"
Principal = { Service = "cloudtrail.amazonaws.com" }
Action = "s3:GetBucketAcl"
Resource = aws_s3_bucket.cloudtrail[0].arn
Condition = { StringEquals = { "aws:SourceArn" = values(local.cloudtrail_arns) } }
},
{
Sid = "CloudTrailWrite"
Effect = "Allow"
Principal = { Service = "cloudtrail.amazonaws.com" }
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.cloudtrail[0].arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"
Condition = {
StringEquals = {
"aws:SourceArn" = values(local.cloudtrail_arns)
"s3:x-amz-acl" = "bucket-owner-full-control"
}
}
},
{
Sid = "DenyInsecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [aws_s3_bucket.cloudtrail[0].arn, "${aws_s3_bucket.cloudtrail[0].arn}/*"]
Condition = { Bool = { "aws:SecureTransport" = "false" } }
},
]
})
depends_on = [aws_s3_bucket_public_access_block.cloudtrail, aws_s3_bucket_ownership_controls.cloudtrail]
}
4 changes: 3 additions & 1 deletion security/compliance/data.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
data "aws_caller_identity" "current" {}

# Both services require the selected Regions to be enabled for the account.
data "aws_partition" "current" {}

# All services require the selected Regions to be enabled for the account.
data "aws_regions" "enabled" {
all_regions = false
}
17 changes: 16 additions & 1 deletion security/compliance/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@
################################################################################

output "regions" {
description = "AWS Regions where GuardDuty and registry-wide Basic ECR scan-on-push are enabled."
description = "AWS Regions covered by GuardDuty, registry-wide Basic ECR scan-on-push and optional CloudTrail."
value = sort(var.regions)
}

output "cloudtrail_arns" {
description = "Map of Region to CloudTrail trail ARN, empty when disabled."
value = { for region, trail in aws_cloudtrail.this : region => trail.arn }
}

output "cloudtrail_bucket_name" {
description = "CloudTrail audit log bucket name, or null when disabled."
value = var.cloudtrail_enabled ? aws_s3_bucket.cloudtrail[0].id : null
}

output "cloudtrail_bucket_arn" {
description = "CloudTrail audit log bucket ARN, or null when disabled."
value = var.cloudtrail_enabled ? aws_s3_bucket.cloudtrail[0].arn : null
}

output "detector_ids" {
description = "Map of Region to GuardDuty detector ID."
value = { for region, detector in aws_guardduty_detector.this : region => detector.id }
Expand Down
61 changes: 52 additions & 9 deletions security/compliance/rvn-aws-compliance-definition.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
definition:
type: rvn-aws-compliance
name: AWS Compliance
description: Manages an AWS compliance baseline with GuardDuty threat detection and registry-wide ECR image scanning across selected Regions.
description: Manages an AWS compliance baseline with GuardDuty, ECR image scanning, and regional CloudTrail audit trails.
release:
version: 0.2.0
description: Add Terraform plan and apply IAM policy inputs to scope stack runner permissions.
version: 0.3.0
description: Record management events in each selected Region with CloudTrail trails sharing a private, versioned log bucket and configurable retention.
module:
inputs:
- $include: ../../partials/inputs/aws-account.yml
Expand All @@ -15,12 +15,35 @@ module:
label: Compliance regions
type: section
- add_button_label: Add Region
description: AWS Regions where GuardDuty and Basic ECR scan-on-push are enabled. ECR scanning covers every repository and replaces existing Enhanced scanning or custom filters. Use one module per account with all required Regions; each Region must already be enabled.
description: Regions for GuardDuty, ECR scanning and CloudTrail. Include us-east-1 for IAM changes; each Region must be enabled.
id: regions
label: Regions
required: true
type: string_array
values: $values:aws/regions
- id: section_cloudtrail
label: CloudTrail
type: section
- id: cloudtrail_enabled
label: CloudTrail
type: boolean
default: true
description: One trail per selected Region. Turn off if an organization trail already covers them.
- id: cloudtrail_log_retention_days
label: Log retention (days)
type: number
default: 365
min: 0
description: S3 lifecycle expiry; 0 keeps logs forever.
show_when:
cloudtrail_enabled: true
- id: cloudtrail_kms_key_arn
label: KMS key ARN
type: string
required: false
description: Leave blank for SSE-S3. Use a bucket-Region key whose policy allows cloudtrail.amazonaws.com for every trail.
show_when:
cloudtrail_enabled: true
- id: section_protection_plans
label: GuardDuty protection plans
type: section
Expand Down Expand Up @@ -96,6 +119,9 @@ module:
base_path: security/compliance
terraform_variables:
...overrides: << module.input.advanced_terraform_variables >>
cloudtrail_enabled: << module.input.cloudtrail_enabled >>
cloudtrail_log_retention_days: "<< module.input.cloudtrail_log_retention_days != nil ? module.input.cloudtrail_log_retention_days : 365 >>"
cloudtrail_kms_key_arn: << module.input.cloudtrail_kms_key_arn || nil >>
eks_protection_enabled: << module.input.eks_protection_enabled >>
finding_publishing_frequency: << module.input.finding_publishing_frequency || "FIFTEEN_MINUTES" >>
lambda_protection_enabled: << module.input.lambda_protection_enabled >>
Expand All @@ -116,13 +142,13 @@ module:
}) : []
>>
readme: |
Manages an AWS compliance baseline with GuardDuty threat detection and Basic ECR image scanning on push across selected Regions.
Manages an AWS compliance baseline with GuardDuty, ECR image scanning, and regional CloudTrail audit trails.

## Account-level setup

Deploy one module for an AWS account and select every Region you want covered. The runner Region controls where Terraform executes; the Regions list controls where both services are configured. Every selected Region must already be enabled for the account.
Deploy one module for an AWS account and select every Region you want covered. The runner Region controls where Terraform executes and hosts the shared CloudTrail bucket; the Regions list controls GuardDuty, ECR scanning and CloudTrail trails. Every selected Region must already be enabled for the account.

Each Region receives a GuardDuty detector with explicitly managed protection plans and an ECR registry scanning rule covering all existing and future private repositories. The module supports threat-detection and vulnerability-scanning controls; application alarms, log retention, and other compliance controls remain in their respective modules.
Each selected Region receives a GuardDuty detector with explicitly managed protection plans, an ECR registry scanning rule covering all existing and future private repositories, and a CloudTrail trail when enabled. Application alarms and application log retention remain in their respective modules.

## GuardDuty

Expand All @@ -136,6 +162,20 @@ module:

Basic scans check operating-system vulnerabilities on new image pushes. They do not provide continuous scanning or automatically scan all images pushed before this configuration was enabled.

## CloudTrail

CloudTrail is enabled by default and creates one single-Region trail in each selected Region. Each records read and write management events with log file validation and no data events. The trails share one bucket in the runner Region.

Include us-east-1 in Regions to capture IAM changes and other global service events (CloudFront and the STS global endpoint). Only that trail includes global service events; us-east-1 is not added automatically. STS regional-endpoint events are recorded in their respective Regions.

Logs go to a dedicated private S3 bucket with public access blocked, bucket-owner-enforced ownership, versioning, and encryption. Log retention (days) sets lifecycle expiry for current and noncurrent object versions; 365 is the default and 0 keeps them forever. With versioning, current-object expiry makes a version noncurrent, then noncurrent expiry applies.

Leave KMS key ARN blank for SSE-S3, or supply a key in the bucket's runner Region, even for trails in other Regions. Its policy must allow cloudtrail.amazonaws.com to encrypt logs for every selected trail. This module does not manage the key policy.

The first copy of management events per Region is free; S3 storage and optional KMS usage incur charges. If an existing trail already records those events in a Region, the additional copy is paid. Turn CloudTrail off if an organization trail already provides coverage.

Destroy fails while the bucket contains logs or object versions: force deletion is disabled. Disabling CloudTrail also attempts to remove its bucket, so preserve or explicitly remove retained logs before doing so.

## Existing resources and ownership

GuardDuty detectors and ECR scanning configurations are shared by the whole account in each Region. Keep exactly one Terraform owner per account and Region; do not deploy overlapping instances or also manage them from a VPC or service module.
Expand All @@ -152,13 +192,16 @@ module:
| --- | --- | --- |
| AWS account | Required | Account whose regional security settings are managed. |
| Region | Required | Terraform runner Region. |
| Regions | Required | Regions covered by both GuardDuty and ECR scanning. |
| Regions | Required | Regions covered by GuardDuty, ECR scanning and CloudTrail. Include us-east-1 for IAM changes. |
| ECR scanning | Basic scan-on-push for all repositories | Always enabled by this module. |
| CloudTrail | Enabled | One single-Region management-event trail in each selected Region, sharing a runner-Region bucket. |
| Log retention (days) | 365 | S3 lifecycle expiry; 0 keeps logs forever. |
| KMS key ARN | None (SSE-S3) | Key in the bucket's runner Region whose policy permits encryption for every trail. |
| S3, EKS, malware, RDS, Lambda protection | Enabled | GuardDuty protection plans. |
| Runtime monitoring | Disabled | Optional workload security agents. |
| Automated agent management | EKS, ECS Fargate, EC2 | Used when Runtime Monitoring is enabled. |
| Finding publishing frequency | Every 15 minutes | Export cadence for updated GuardDuty findings. |
| Tags | Standard Ravion tags | Additional tags for GuardDuty detectors; ECR registry scanning does not support tags. |
| Tags | Standard Ravion tags | Additional tags for GuardDuty, CloudTrail and its bucket; ECR registry scanning does not support tags. |

## Learn more

Expand Down
Loading
Loading