- Newest
- Most votes
- Most comments
I suggest you use open source tools such as checkov or tfsec to scan your terraform code for misconfigurations and to discover security risks.
You can also incorporate such tools in your CI/CD pipeline and follow the "Shift left" DevSecOps practice to fail/abort IaC deployment if security findings above a certain severity level are discovered (e.g., HIGH or CRITICAL).
Hello,
Your terraform configuration looks almost correct. Additionally use KMS to apply customer managed Keys and encrypt S3 bucket and you need to create a new IAM role to allow enhanced monitoring, and cross-region replication setup is mostly correct, but you need to ensure that the IAM role has the correct policy attached for replication.
# Enable VPC Flow Logging to VPC
resource "aws_flow_log" "centralized" {
log_destination = "arn:aws:s3:::centralized-vpc-flow-logs-<log_archive_account_id>" # S3 bucket ARN for storing logs
log_destination_type = "s3"
traffic_type = "ALL" # Capture all traffic
vpc_id = var.vpc_id
log_format = local.custom_log_format_v5 # Custom log format
tags = {
Name = "centralized_flow_log"
}
}
# Apply bucket versioning to S3 bucket
resource "aws_s3_bucket" "my_bucket" {
bucket = "example-bucket"
}
resource "aws_s3_bucket_acl" "example" {
bucket = aws_s3_bucket.my_bucket.id
acl = "private" # Ensure the bucket is private
}
resource "aws_s3_bucket_versioning" "bucket_version" {
bucket = aws_s3_bucket.my_bucket.id
versioning_configuration {
status = "Enabled" # Enable versioning
}
}
# Create individual Terraform resources for destination bucket for replication
resource "aws_s3_bucket" "destination" {
bucket = "tf-bucket-destination"
region = "us-west-2"
versioning {
enabled = true
}
}
# IAM Role for S3 bucket replication
resource "aws_iam_role" "s3_replication_role" {
name = "s3_replication_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "s3.amazonaws.com"
}
}
]
})
}
# IAM Role Policy for S3 bucket replication
resource "aws_iam_role_policy" "s3_replication_policy" {
role = aws_iam_role.s3_replication_role.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = [
"s3:GetReplicationConfiguration",
"s3:ListBucket",
"s3:GetObjectVersion",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTagging"
],
Effect = "Allow",
Resource = [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
]
},
{
Action = [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags",
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAclForReplication",
"s3:GetObjectVersionTaggingForReplication"
],
Effect = "Allow",
Resource = "arn:aws:s3:::tf-bucket-destination/*"
}
]
})
}
# Enable replication for cross-region
resource "aws_s3_bucket_replication_configuration" "example" {
bucket = aws_s3_bucket.my_bucket.id
role = aws_iam_role.s3_replication_role.arn
rules {
id = "replication-rule"
status = "Enabled"
destination {
bucket = aws_s3_bucket.destination.arn
storage_class = "STANDARD"
}
}
}
# Encrypt Amazon FSx with KMS via customer managed key
resource "aws_fsx_windows_file_system" "example" {
active_directory_id = aws_directory_service_directory.example.id
kms_key_id = aws_kms_key.example.arn
storage_capacity = 300
subnet_ids = [aws_subnet.example.id]
throughput_capacity = 1024
}
# Create and manage my KMS key
resource "aws_kms_key" "example" {
description = "My encryption KMS key"
enable_key_rotation = true
deletion_window_in_days = 30
policy = jsonencode({
Version = "2012-10-17"
Id = "key-default-1"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
},
Action = "kms:*"
Resource = "*"
},
{
Sid = "Allow administration of the key"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/Alice"
},
Action = [
"kms:ReplicateKey",
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
Resource = "*"
},
{
Sid = "Allow use of the key"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/Bob"
},
Action = [
"kms:DescribeKey",
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey",
"kms:GenerateDataKeyWithoutPlaintext"
],
Resource = "*"
}
]
})
}
# Apply encryption to S3 bucket using KMS
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.my_bucket.id
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.example.arn
sse_algorithm = "aws:kms"
}
}
}
# Encrypting AWS Secrets Manager via KMS with a customer managed key
resource "aws_secretsmanager_secret" "example" {
name = "example"
kms_key_id = aws_kms_key.example.arn
}
# Set default security group to restrict all traffic
resource "aws_security_group" "default" {
name = "default_security_group"
vpc_id = var.vpc_id
description = "Default security group with no traffic allowed"
ingress {
from_port = 0
to_port = 0
self = true
protocol = "-1"
}
}
# Create IAM role for RDS enhanced monitoring
resource "aws_iam_role" "rds_enhanced_monitoring" {
name = "rds_enhanced_monitoring_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "monitoring.rds.amazonaws.com"
}
}
]
})
}
# Attach policy to IAM role for RDS enhanced monitoring
resource "aws_iam_role_policy" "rds_enhanced_monitoring_policy" {
role = aws_iam_role.rds_enhanced_monitoring.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = [
"cloudwatch:PutMetricData",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
Effect = "Allow",
Resource = "*"
}
]
})
}
# Enable enhanced monitoring for AWS RDS MySQL database
resource "aws_db_instance" "example" {
identifier = "example"
engine = "mysql"
instance_class = "db.t2.micro"
username = "foo"
password = "barbarbar"
allocated_storage = 10
monitoring_interval = 30 # Monitoring interval in seconds
monitoring_role_arn = aws_iam_role.rds_enhanced_monitoring.arn # ARN of the monitoring role
}
A bit late to the party, but still... The suggestions above about checkov and tfsec are good for scanning your Terraform code before deployment. To answer your specific question about what to configure:
For S3 - enable server-side encryption with KMS (aws:kms), turn on versioning, block all public access (block_public_acls, block_public_policy, ignore_public_acls, restrict_public_buckets all set to true), and enable access logging to a separate bucket.
For RDS - enable storage encryption, set multi-az to true for production, configure automated backups with at least 7 days retention, enable deletion protection, and restrict the security group to only your application subnets.
For VPC - enable flow logs to CloudWatch or S3 for audit trail, use private subnets for your application and database tiers, and restrict the default security group to deny all traffic.
One thing the scanning tools will not do for you - they detect problems but can not fix them. If you want these settings enforced by default so developers do not need to remember each one, consider baking them directly into your Terraform modules. A module that has encryption and logging enabled by default is more reliable than scanning for it after the fact.
answered 3 months ago
