add aws config module
parent
70a5102387
commit
a6e7ef642c
@ -0,0 +1,43 @@
|
||||
# Config
|
||||
|
||||
This modules sets up AWS Config for auditing the account and alerting on insecure conditions.
|
||||
|
||||
There is a list of pre-made Config rules authored by AWS here: https://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html
|
||||
|
||||
I only picked the most obvious ones because there are a ton of available rules but they can cost a lot to turn them all on.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
module "cloudtrail" {
|
||||
source = "github.com/lalanza808/tf-modules.git/security/cloudtrail"
|
||||
force_destroy_bucket = true
|
||||
}
|
||||
|
||||
module "sns_topic" {
|
||||
source = "github.com/lalanza808/tf-modules.git/monitoring/sns-email-topic"
|
||||
sns_emails = ["user@email.com"]
|
||||
}
|
||||
|
||||
module "config" {
|
||||
source = "github.com/lalanza808/tf-modules.git/monitoring/config"
|
||||
|
||||
sns_topic_arn = module.sns_topic.topic_arn
|
||||
s3_buckets_logging_enabled = [
|
||||
module.cloudtrail.s3_bucket
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
The main ones you would want to override are:
|
||||
|
||||
* `sns_topic_arn` - An SNS topic ARN for notifying when a Config rule has breached
|
||||
* `s3_buckets_logging_enabled` - A list of buckets to create Config rules for monitoring Cloudtrail data plane operations log collection
|
||||
|
||||
See the full list of inputs here: [variables.tf](./variables.tf)
|
||||
|
||||
## Outputs
|
||||
|
||||
[output.tf](./output.tf)
|
@ -0,0 +1,144 @@
|
||||
resource "aws_s3_bucket" "config_bucket" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
bucket_prefix = "${var.prefix}-config-"
|
||||
acl = "private"
|
||||
force_destroy = var.force_destroy_bucket
|
||||
|
||||
tags = var.tags
|
||||
|
||||
server_side_encryption_configuration {
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "AES256"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle_rule {
|
||||
id = "archive_glacier"
|
||||
enabled = var.lifecycle_enabled
|
||||
prefix = var.lifecycle_prefix
|
||||
|
||||
transition {
|
||||
days = var.lifecycle_glacier_transition_days
|
||||
storage_class = "GLACIER"
|
||||
}
|
||||
|
||||
expiration {
|
||||
days = var.lifecycle_object_expiration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_policy" "config_bucket_policy" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
bucket = aws_s3_bucket.config_bucket[0].id
|
||||
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AWSConfigAclCheck",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "config.amazonaws.com"
|
||||
},
|
||||
"Action": "s3:GetBucketAcl",
|
||||
"Resource": "${aws_s3_bucket.config_bucket[0].arn}"
|
||||
},
|
||||
{
|
||||
"Sid": "AWSConfigWrite",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "config.amazonaws.com"
|
||||
},
|
||||
"Action": "s3:PutObject",
|
||||
"Resource": "${aws_s3_bucket.config_bucket[0].arn}/*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"s3:x-amz-acl": "bucket-owner-full-control"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_config_delivery_channel" "delivery_channel" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
name = aws_s3_bucket.config_bucket[0].id
|
||||
s3_bucket_name = aws_s3_bucket.config_bucket[0].id
|
||||
sns_topic_arn = var.sns_topic_arn
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_configuration_recorder_status" "config_status" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
name = aws_config_configuration_recorder.config_recorder[0].name
|
||||
is_enabled = true
|
||||
depends_on = [aws_config_delivery_channel.delivery_channel]
|
||||
}
|
||||
|
||||
resource "aws_config_configuration_recorder" "config_recorder" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
name = aws_s3_bucket.config_bucket[0].id
|
||||
role_arn = aws_iam_role.config_recorder_role[0].arn
|
||||
|
||||
recording_group {
|
||||
all_supported = "true"
|
||||
include_global_resource_types = "true"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "config_recorder_role" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
name = aws_s3_bucket.config_bucket[0].id
|
||||
tags = var.tags
|
||||
|
||||
assume_role_policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "config.amazonaws.com"
|
||||
},
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "config_s3" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
name = aws_iam_role.config_recorder_role[0].name
|
||||
role = aws_iam_role.config_recorder_role[0].id
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"s3:*"
|
||||
],
|
||||
"Resource": [
|
||||
"${aws_s3_bucket.config_bucket[0].arn}",
|
||||
"${aws_s3_bucket.config_bucket[0].arn}/*"
|
||||
],
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
// Config service policy attachment
|
||||
resource "aws_iam_role_policy_attachment" "config_role" {
|
||||
count = var.enable_aws_config ? 1 : 0
|
||||
role = aws_iam_role.config_recorder_role[0].name
|
||||
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSConfigRole"
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
resource "aws_config_config_rule" "cloudtrail_enabled" {
|
||||
count = var.enable_aws_config && var.rule_cloudtrail_enabled ? 1 : 0
|
||||
name = "multi-region-cloud-trail-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "MULTI_REGION_CLOUD_TRAIL_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "cloudtrail_validation_enabled" {
|
||||
count = var.enable_aws_config && var.rule_cloudtrail_validation_enabled ? 1 : 0
|
||||
name = "cloud-trail-log-validation-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
|
||||
|
||||
resource "aws_config_config_rule" "cloudtrail_cloudwatch_logs_enabled" {
|
||||
count = var.enable_aws_config && var.rule_cloudtrail_cloudwatch_logs_enabled ? 1 : 0
|
||||
name = "cloud-trail-cloud-watch-logs-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "CLOUD_TRAIL_CLOUD_WATCH_LOGS_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
resource "aws_config_config_rule" "guardduty_enabled" {
|
||||
count = var.enable_aws_config && var.rule_guardduty_enabled ? 1 : 0
|
||||
name = "guardduty-enabled-centralized"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "GUARDDUTY_ENABLED_CENTRALIZED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
resource "aws_config_config_rule" "root_access_keys" {
|
||||
count = var.enable_aws_config && var.rule_root_access_keys ? 1 : 0
|
||||
name = "iam-root-access-key-check"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "IAM_ROOT_ACCESS_KEY_CHECK"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "root_mfa_enabled" {
|
||||
count = var.enable_aws_config && var.rule_root_mfa_enabled ? 1 : 0
|
||||
name = "root-account-mfa-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "ROOT_ACCOUNT_MFA_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "root_hardware_mfa_enabled" {
|
||||
count = var.enable_aws_config && var.rule_root_hardware_mfa_enabled ? 1 : 0
|
||||
name = "root-account-hardware-mfa-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "ROOT_ACCOUNT_HARDWARE_MFA_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "console_mfa_enabled" {
|
||||
count = var.enable_aws_config && var.rule_console_mfa_enabled ? 1 : 0
|
||||
name = "mfa-enabled-for-iam-console-access"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "MFA_ENABLED_FOR_IAM_CONSOLE_ACCESS"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "iam_user_unused" {
|
||||
count = var.enable_aws_config && var.rule_iam_user_unused ? 1 : 0
|
||||
name = "iam-user-unused-credentials-check"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "IAM_USER_UNUSED_CREDENTIALS_CHECK"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"maxCredentialUsageAge": "90"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "iam_password_policy_enabled" {
|
||||
count = var.enable_aws_config && var.rule_iam_password_policy_enabled ? 1 : 0
|
||||
name = "iam-password-policy-enabled"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "IAM_PASSWORD_POLICY"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"MinimumPasswordLength": "14",
|
||||
"RequireUppercaseCharacters": "true",
|
||||
"RequireLowercaseCharacters": "true",
|
||||
"RequireSymbols": "true",
|
||||
"RequireNumbers": "true",
|
||||
"PasswordReusePrevention": "24",
|
||||
"MaxPasswordAge": "90"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "iam_policy_no_admin" {
|
||||
count = var.enable_aws_config && var.rule_iam_policy_no_admin ? 1 : 0
|
||||
name = "iam-policy-no-statements-with-admin-access"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "access_keys_rotated" {
|
||||
count = var.enable_aws_config && var.rule_access_keys_rotated ? 1 : 0
|
||||
name = "access-keys-rotated"
|
||||
maximum_execution_frequency = "TwentyFour_Hours"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "ACCESS_KEYS_ROTATED"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"maxAccessKeyAge": "90"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "iam_user_no_policies" {
|
||||
count = var.enable_aws_config && var.rule_iam_user_no_policies ? 1 : 0
|
||||
name = "iam-user-no-policies-check"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "IAM_USER_NO_POLICIES_CHECK"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
resource "aws_config_config_rule" "s3_public_read_prohibited" {
|
||||
count = var.enable_aws_config && var.rule_s3_public_read_prohibited ? 1 : 0
|
||||
name = "s3-bucket-public-read-prohibited"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "s3_logging_enabled" {
|
||||
name = "s3-bucket-logging-enabled"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "S3_BUCKET_LOGGING_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"targetBucket": "*",
|
||||
"targetPrefix": "/"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
resource "aws_config_config_rule" "vpc_flow_logs_enabled" {
|
||||
count = var.enable_aws_config && var.rule_vpc_flow_logs_enabled ? 1 : 0
|
||||
name = "vpc-flow-logs-enabled"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "VPC_FLOW_LOGS_ENABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"trafficType": "ALL"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "incoming_ssh_enabled" {
|
||||
count = var.enable_aws_config && var.rule_incoming_ssh_enabled ? 1 : 0
|
||||
name = "restricted-ssh"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "INCOMING_SSH_DISABLED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "restricted_common_ports" {
|
||||
count = var.enable_aws_config && var.rule_restricted_common_ports ? 1 : 0
|
||||
name = "restricted-common-ports"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "RESTRICTED_INCOMING_TRAFFIC"
|
||||
}
|
||||
tags = var.tags
|
||||
|
||||
input_parameters = <<EOF
|
||||
{
|
||||
"blockedPort1": "3306",
|
||||
"blockedPort2": "3389"
|
||||
}
|
||||
EOF
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
||||
|
||||
resource "aws_config_config_rule" "default_security_group_closed" {
|
||||
count = var.enable_aws_config && var.rule_default_security_group_closed ? 1 : 0
|
||||
name = "vpc-default-security-group-closed"
|
||||
|
||||
source {
|
||||
owner = "AWS"
|
||||
source_identifier = "VPC_DEFAULT_SECURITY_GROUP_CLOSED"
|
||||
}
|
||||
tags = var.tags
|
||||
depends_on = [aws_config_configuration_recorder.config_recorder]
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
# Get AWS account info
|
||||
data "aws_caller_identity" "current" {}
|
@ -0,0 +1,5 @@
|
||||
// Resource attritbute output
|
||||
|
||||
output "config_bucket" {
|
||||
value = aws_s3_bucket.config_bucket[0].id
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
variable "enable_aws_config" {
|
||||
default = true
|
||||
description = "Whether or not you want Config"
|
||||
}
|
||||
variable "force_destroy_bucket" {
|
||||
default = false
|
||||
description = "Whether or not you want the bucket to force removal of all objects upon deletion - otherwise throws error when deleting"
|
||||
}
|
||||
variable "sns_topic_arn" {
|
||||
default = ""
|
||||
description = "SNS Topic to forward Config messages to"
|
||||
}
|
||||
variable "lifecycle_enabled" {
|
||||
default = true
|
||||
description = "Whether or not to enable lifecycle rules"
|
||||
}
|
||||
variable "lifecycle_prefix" {
|
||||
default = ""
|
||||
description = "S3 object prefix to manage lifecycle - blank is all objects"
|
||||
}
|
||||
variable "lifecycle_glacier_transition_days" {
|
||||
default = 90
|
||||
description = "Number of days to maintain in S3 until transitioning to Glacier"
|
||||
}
|
||||
variable "lifecycle_object_expiration" {
|
||||
default = 365
|
||||
description = "Number of days to expire objects permanently"
|
||||
}
|
||||
variable "s3_buckets_logging_enabled" {
|
||||
type = list
|
||||
default = []
|
||||
description = "A list of S3 buckets you want to run Config checks for ensuring logging is enabled"
|
||||
}
|
||||
variable "rule_cloudtrail_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_cloudtrail_validation_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_guardduty_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_root_access_keys" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_root_mfa_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_root_hardware_mfa_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_console_mfa_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_iam_user_unused" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_iam_password_policy_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_iam_policy_no_admin" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_access_keys_rotated" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_iam_user_no_policies" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_s3_public_read_prohibited" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_cloudtrail_cloudwatch_logs_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_s3_logging_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_vpc_flow_logs_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_incoming_ssh_enabled" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_restricted_common_ports" {
|
||||
default = true
|
||||
}
|
||||
variable "rule_default_security_group_closed" {
|
||||
default = true
|
||||
}
|
||||
variable "tags" {
|
||||
default = {}
|
||||
type = map
|
||||
description = "Optional set of tags to apply to the infrastructure"
|
||||
}
|
||||
variable "prefix" {
|
||||
default = "monitoring"
|
||||
description = "String to prefix to all resources"
|
||||
}
|
Loading…
Reference in New Issue