mirror of
https://github.com/ghndrx/terraform-foundation.git
synced 2026-02-10 14:54:56 +00:00
feat: Terraform Foundation - AWS Landing Zone
Enterprise-grade multi-tenant AWS cloud foundation. Modules: - GitHub OIDC for keyless CI/CD authentication - IAM account settings and security baseline - AWS Config Rules for compliance - ABAC (Attribute-Based Access Control) - SCPs (Service Control Policies) Features: - Multi-account architecture - Cost optimization patterns - Security best practices - Comprehensive documentation Tech: Terraform, AWS Organizations, IAM Identity Center
This commit is contained in:
54
terraform/modules/security-baseline/README.md
Normal file
54
terraform/modules/security-baseline/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# security-baseline
|
||||
|
||||
Security Baseline Module
|
||||
|
||||
## Usage
|
||||
|
||||
```hcl
|
||||
module "security_baseline" {
|
||||
source = "../modules/security-baseline"
|
||||
|
||||
# Required variables
|
||||
name = ""
|
||||
config_bucket_name = ""
|
||||
|
||||
# Optional: see variables.tf for all options
|
||||
}
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.5.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Required |
|
||||
|------|-------------|------|----------|
|
||||
| name | Name prefix for resources | `string` | yes |
|
||||
| enable_guardduty | | `bool` | no |
|
||||
| enable_securityhub | | `bool` | no |
|
||||
| enable_config | | `bool` | no |
|
||||
| enable_access_analyzer | | `bool` | no |
|
||||
| enable_macie | Macie for S3 data classification (additional cost) | `bool` | no |
|
||||
| config_bucket_name | S3 bucket for AWS Config recordings | `string` | yes |
|
||||
| guardduty_finding_publishing_frequency | | `string` | no |
|
||||
| securityhub_standards | Security Hub standards to enable | `list(string)` | no |
|
||||
| config_rules | Additional AWS Config managed rule identifiers to enable | `list(string)` | no |
|
||||
| tags | | `map(string)` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| guardduty_detector_id | |
|
||||
| securityhub_account_id | |
|
||||
| config_recorder_id | |
|
||||
| access_analyzer_arn | |
|
||||
| enabled_services | |
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0 - See LICENSE for details.
|
||||
334
terraform/modules/security-baseline/main.tf
Normal file
334
terraform/modules/security-baseline/main.tf
Normal file
@@ -0,0 +1,334 @@
|
||||
################################################################################
|
||||
# Security Baseline Module
|
||||
#
|
||||
# Enables core AWS security services:
|
||||
# - GuardDuty (threat detection)
|
||||
# - Security Hub (security posture)
|
||||
# - AWS Config (configuration compliance)
|
||||
# - IAM Access Analyzer
|
||||
#
|
||||
# For multi-account: Deploy in management account, then enable delegated admin
|
||||
################################################################################
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
type = string
|
||||
description = "Name prefix for resources"
|
||||
}
|
||||
|
||||
variable "enable_guardduty" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_securityhub" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_config" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_access_analyzer" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_macie" {
|
||||
type = bool
|
||||
default = false
|
||||
description = "Macie for S3 data classification (additional cost)"
|
||||
}
|
||||
|
||||
variable "config_bucket_name" {
|
||||
type = string
|
||||
description = "S3 bucket for AWS Config recordings"
|
||||
}
|
||||
|
||||
variable "guardduty_finding_publishing_frequency" {
|
||||
type = string
|
||||
default = "FIFTEEN_MINUTES"
|
||||
validation {
|
||||
condition = contains(["FIFTEEN_MINUTES", "ONE_HOUR", "SIX_HOURS"], var.guardduty_finding_publishing_frequency)
|
||||
error_message = "Must be FIFTEEN_MINUTES, ONE_HOUR, or SIX_HOURS"
|
||||
}
|
||||
}
|
||||
|
||||
variable "securityhub_standards" {
|
||||
type = list(string)
|
||||
default = [
|
||||
"aws-foundational-security-best-practices/v/1.0.0",
|
||||
"cis-aws-foundations-benchmark/v/1.4.0",
|
||||
]
|
||||
description = "Security Hub standards to enable"
|
||||
}
|
||||
|
||||
variable "config_rules" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "Additional AWS Config managed rule identifiers to enable"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
data "aws_caller_identity" "current" {}
|
||||
data "aws_region" "current" {}
|
||||
|
||||
################################################################################
|
||||
# GuardDuty
|
||||
################################################################################
|
||||
|
||||
resource "aws_guardduty_detector" "main" {
|
||||
count = var.enable_guardduty ? 1 : 0
|
||||
|
||||
enable = true
|
||||
finding_publishing_frequency = var.guardduty_finding_publishing_frequency
|
||||
|
||||
datasources {
|
||||
s3_logs {
|
||||
enable = true
|
||||
}
|
||||
kubernetes {
|
||||
audit_logs {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
malware_protection {
|
||||
scan_ec2_instance_with_findings {
|
||||
ebs_volumes {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags = merge(var.tags, { Name = "${var.name}-guardduty" })
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Security Hub
|
||||
################################################################################
|
||||
|
||||
resource "aws_securityhub_account" "main" {
|
||||
count = var.enable_securityhub ? 1 : 0
|
||||
|
||||
enable_default_standards = false
|
||||
auto_enable_controls = true
|
||||
|
||||
depends_on = [aws_guardduty_detector.main]
|
||||
}
|
||||
|
||||
resource "aws_securityhub_standards_subscription" "standards" {
|
||||
for_each = var.enable_securityhub ? toset(var.securityhub_standards) : []
|
||||
|
||||
standards_arn = "arn:aws:securityhub:${data.aws_region.current.name}::standards/${each.value}"
|
||||
|
||||
depends_on = [aws_securityhub_account.main]
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# AWS Config
|
||||
################################################################################
|
||||
|
||||
resource "aws_config_configuration_recorder" "main" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
|
||||
name = var.name
|
||||
role_arn = aws_iam_role.config[0].arn
|
||||
|
||||
recording_group {
|
||||
all_supported = true
|
||||
include_global_resource_types = true
|
||||
}
|
||||
|
||||
recording_mode {
|
||||
recording_frequency = "CONTINUOUS"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_config_delivery_channel" "main" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
|
||||
name = var.name
|
||||
s3_bucket_name = var.config_bucket_name
|
||||
s3_key_prefix = "config"
|
||||
|
||||
snapshot_delivery_properties {
|
||||
delivery_frequency = "TwentyFour_Hours"
|
||||
}
|
||||
|
||||
depends_on = [aws_config_configuration_recorder.main]
|
||||
}
|
||||
|
||||
resource "aws_config_configuration_recorder_status" "main" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
|
||||
name = aws_config_configuration_recorder.main[0].name
|
||||
is_enabled = true
|
||||
|
||||
depends_on = [aws_config_delivery_channel.main]
|
||||
}
|
||||
|
||||
# IAM Role for Config
|
||||
resource "aws_iam_role" "config" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
name = "${var.name}-config"
|
||||
|
||||
assume_role_policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [{
|
||||
Effect = "Allow"
|
||||
Action = "sts:AssumeRole"
|
||||
Principal = { Service = "config.amazonaws.com" }
|
||||
}]
|
||||
})
|
||||
|
||||
tags = merge(var.tags, { Name = "${var.name}-config" })
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "config" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
role = aws_iam_role.config[0].name
|
||||
policy_arn = "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "config_s3" {
|
||||
count = var.enable_config ? 1 : 0
|
||||
name = "s3-delivery"
|
||||
role = aws_iam_role.config[0].id
|
||||
|
||||
policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [{
|
||||
Effect = "Allow"
|
||||
Action = ["s3:PutObject", "s3:PutObjectAcl"]
|
||||
Resource = "arn:aws:s3:::${var.config_bucket_name}/config/*"
|
||||
Condition = {
|
||||
StringEquals = {
|
||||
"s3:x-amz-acl" = "bucket-owner-full-control"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
Effect = "Allow"
|
||||
Action = ["s3:GetBucketAcl"]
|
||||
Resource = "arn:aws:s3:::${var.config_bucket_name}"
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# AWS Config Rules - Security Best Practices
|
||||
################################################################################
|
||||
|
||||
locals {
|
||||
default_config_rules = [
|
||||
"ENCRYPTED_VOLUMES",
|
||||
"RDS_STORAGE_ENCRYPTED",
|
||||
"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",
|
||||
"S3_BUCKET_SSL_REQUESTS_ONLY",
|
||||
"S3_BUCKET_PUBLIC_READ_PROHIBITED",
|
||||
"S3_BUCKET_PUBLIC_WRITE_PROHIBITED",
|
||||
"RESTRICTED_SSH",
|
||||
"VPC_DEFAULT_SECURITY_GROUP_CLOSED",
|
||||
"VPC_FLOW_LOGS_ENABLED",
|
||||
"CLOUD_TRAIL_ENABLED",
|
||||
"CLOUD_TRAIL_ENCRYPTION_ENABLED",
|
||||
"CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED",
|
||||
"IAM_ROOT_ACCESS_KEY_CHECK",
|
||||
"IAM_USER_MFA_ENABLED",
|
||||
"MFA_ENABLED_FOR_IAM_CONSOLE_ACCESS",
|
||||
"ROOT_ACCOUNT_MFA_ENABLED",
|
||||
"RDS_INSTANCE_PUBLIC_ACCESS_CHECK",
|
||||
"GUARDDUTY_ENABLED_CENTRALIZED",
|
||||
"SECURITYHUB_ENABLED",
|
||||
"EBS_OPTIMIZED_INSTANCE",
|
||||
"EC2_IMDSV2_CHECK",
|
||||
"EKS_SECRETS_ENCRYPTED",
|
||||
"LAMBDA_FUNCTION_PUBLIC_ACCESS_PROHIBITED",
|
||||
"LAMBDA_INSIDE_VPC",
|
||||
]
|
||||
|
||||
all_config_rules = distinct(concat(local.default_config_rules, var.config_rules))
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "rules" {
|
||||
for_each = var.enable_config ? toset(local.all_config_rules) : []
|
||||
|
||||
name = lower(replace(each.value, "_", "-"))
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = each.value
|
||||
}
|
||||
|
||||
depends_on = [aws_config_configuration_recorder_status.main]
|
||||
|
||||
tags = merge(var.tags, { Name = lower(replace(each.value, "_", "-")) })
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# IAM Access Analyzer
|
||||
################################################################################
|
||||
|
||||
resource "aws_accessanalyzer_analyzer" "main" {
|
||||
count = var.enable_access_analyzer ? 1 : 0
|
||||
|
||||
analyzer_name = var.name
|
||||
type = "ACCOUNT"
|
||||
|
||||
tags = merge(var.tags, { Name = "${var.name}-access-analyzer" })
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Macie (Optional)
|
||||
################################################################################
|
||||
|
||||
resource "aws_macie2_account" "main" {
|
||||
count = var.enable_macie ? 1 : 0
|
||||
|
||||
finding_publishing_frequency = "FIFTEEN_MINUTES"
|
||||
status = "ENABLED"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Outputs
|
||||
################################################################################
|
||||
|
||||
output "guardduty_detector_id" {
|
||||
value = var.enable_guardduty ? aws_guardduty_detector.main[0].id : null
|
||||
}
|
||||
|
||||
output "securityhub_account_id" {
|
||||
value = var.enable_securityhub ? aws_securityhub_account.main[0].id : null
|
||||
}
|
||||
|
||||
output "config_recorder_id" {
|
||||
value = var.enable_config ? aws_config_configuration_recorder.main[0].id : null
|
||||
}
|
||||
|
||||
output "access_analyzer_arn" {
|
||||
value = var.enable_access_analyzer ? aws_accessanalyzer_analyzer.main[0].arn : null
|
||||
}
|
||||
|
||||
output "enabled_services" {
|
||||
value = {
|
||||
guardduty = var.enable_guardduty
|
||||
securityhub = var.enable_securityhub
|
||||
config = var.enable_config
|
||||
access_analyzer = var.enable_access_analyzer
|
||||
macie = var.enable_macie
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user