diff --git a/cloudtrail/README.md b/cloudtrail/README.md index a5f32ab..37b4092 100644 --- a/cloudtrail/README.md +++ b/cloudtrail/README.md @@ -58,21 +58,24 @@ No modules. | Name | Type | |------|------| | [aws_cloudtrail.cloudtrail](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudtrail) | resource | -| [aws_cloudtrail.trail](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudtrail) | resource | +| [aws_cloudtrail.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudtrail) | resource | | [aws_cloudwatch_log_group.inf-cloudtrail](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | | [aws_iam_policy.cloudtrail_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_role.cloudtrail](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_kms_key.cloudtrail_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | -| [aws_s3_bucket.trail](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | | [aws_s3_bucket_policy.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | | [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | | [null_resource.policy_delay](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | | [aws_arn.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | data source | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.cloudtrail_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.cloudtrail_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.cloudtrail_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.cloudwatch_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_kms_key.incoming_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_key) | data source | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs @@ -87,6 +90,7 @@ No modules. | [component\_tags](#input\_component\_tags) | Additional tags for Components (s3, kms, ddb) | `map(map(string))` |
{
"ddb": {},
"kms": {},
"s3": {}
} | no |
| [enable\_sns](#input\_enable\_sns) | Flag to enable or disable the creation of SNS for Cloudtrail (TBD) | `bool` | `false` | no |
| [enable\_sqs](#input\_enable\_sqs) | Flag to enable or disable the creation of SQS attached to SNS for Cloudtrail, used for Splunk ingestion (TBD) | `bool` | `false` | no |
+| [kms\_key\_arn](#input\_kms\_key\_arn) | AWS CloudTrail KMS ARN to be used for encrypting the ClouldTrail, S3 Bucket, and SQS | `string` | n/a | yes |
| [kms\_key\_management\_identifiers](#input\_kms\_key\_management\_identifiers) | AWS IAM ARNs (roles, groups, users) for full access to the created KMS Key for this bucket | `list(string)` | `[]` | no |
| [name](#input\_name) | Name to apply to Cloudtrail, S3, SNS and SQS | `string` | `null` | no |
| [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component (efs, s3, ebs, kms, role, policy, security-group). This should be used primarily for common infrastructure things | `map(string)` | `{}` | no |
diff --git a/cloudtrail/cloudtrail.tf b/cloudtrail/cloudtrail.tf
new file mode 100644
index 0000000..2661a1c
--- /dev/null
+++ b/cloudtrail/cloudtrail.tf
@@ -0,0 +1,20 @@
+resource "aws_cloudtrail" "this" {
+ name = local.name
+ s3_bucket_name = aws_s3_bucket.this.id
+ s3_key_prefix = var.cloudtrail_bucket_prefix
+ include_global_service_events = true
+ is_multi_region_trail = false
+ enable_log_file_validation = true
+ enable_logging = true
+ kms_key_id = var.kms_key_arn
+ # sns_topic_name = aws_sns_topic.cloudtrail.arn
+ # cloud_watch_logs_group_arn = aws_cloudwatch_log_group.inf-cloudtrail.arn
+ # cloud_watch_logs_role_arn = aws_iam_role.inf-cloudtrail.arn
+
+ tags = merge(
+ local.base_tags,
+ var.tags,
+ { "Name" = local.name },
+ )
+ depends_on = [aws_s3_bucket_policy.bucket_policy]
+}
diff --git a/cloudtrail/cloudwatch.tf b/cloudtrail/cloudwatch.tf
new file mode 100644
index 0000000..f885d17
--- /dev/null
+++ b/cloudtrail/cloudwatch.tf
@@ -0,0 +1,29 @@
+data "aws_iam_policy_document" "cloudwatch_policy" {
+ statement {
+ sid = "AWSCloudTrailCreateLogStream"
+ effect = "Allow"
+ actions = ["logs:CreateLogStream"]
+ resources = [local.cloudwatch_resources]
+ }
+
+ statement {
+ sid = "AWSCloudTrailPutLogEvents"
+ effect = "Allow"
+ actions = ["logs:PutLogEvents"]
+ resources = [local.cloudwatch_resources]
+ }
+}
+
+resource "aws_cloudwatch_log_group" "this" {
+ name = local.name
+
+ # kms_key_id = var.kms_key_id
+ # kms_key_id = var.kms_key_arn
+ kms_key_id = data.aws_kms_key.incoming_key.id
+ retention_in_days = 7
+
+ tags = merge(
+ local.common_tags,
+ map("Name", local.name),
+ )
+}
diff --git a/cloudtrail/kms.tf.off b/cloudtrail/kms.tf.off
new file mode 100644
index 0000000..63f49fa
--- /dev/null
+++ b/cloudtrail/kms.tf.off
@@ -0,0 +1,166 @@
+#---
+# kms key
+#---
+resource "aws_kms_key" "key" {
+ description = "Encrypt CloudTrail objects and streams"
+ enable_key_rotation = true
+ policy = data.aws_iam_policy_document.key.json
+
+ tags = merge(
+ local.common_tags,
+ map("boc:aws:region", local.region),
+ map("Name", var.kms_key),
+ )
+ lifecycle {
+ ignore_changes = [tags["boc:tf_module_version"]]
+ }
+}
+
+resource "aws_kms_alias" "key" {
+ name = "alias/${var.kms_key}"
+ target_key_id = aws_kms_key.key.key_id
+}
+
+output "kms_key_id" {
+ description = "Cloudtrail Key ID"
+ value = aws_kms_key.key.id
+}
+output "kms_key_arn" {
+ description = "Cloudtrail Key ARN"
+ value = aws_kms_key.key.arn
+}
+
+data "aws_iam_policy_document" "key" {
+ policy_id = "inf-cloudtrail KMS access"
+ statement {
+ sid = "EnableIAMUserPermissions"
+ effect = "Allow"
+ actions = ["kms:*"]
+ resources = ["*"]
+ principals {
+ type = "AWS"
+
+ identifiers = [
+ # data.aws_caller_identity.current.arn,
+ "arn:${data.aws_arn.current.partition}:iam::${var.account_id}:root",
+ # "arn:${data.aws_arn.current.partition}:sts::${var.account_id}:assumed-role/r-inf-cloud-admin/${var.tag_creator}",
+ ]
+ }
+ }
+
+ statement {
+ sid = "AllowCloudTrailEncryptLogs"
+ effect = "Allow"
+ actions = ["kms:GenerateDataKey*"]
+ resources = ["*"]
+
+ principals {
+ type = "Service"
+ # identifiers = ["cloudtrail.amazonaws.com"]
+ identifiers = ["cloudtrail.amazonaws.com", "logs.amazonaws.com", "logs.${local.region}.amazonaws.com"]
+ }
+
+ condition {
+ test = "StringLike"
+ variable = "kms:EncryptionContext:aws:cloudtrail:arn"
+ values = ["arn:${data.aws_arn.current.partition}:cloudtrail:*:${var.account_id}:trail/*"]
+ }
+ }
+
+ statement {
+ sid = "AllowCloudTrailKeyActivities"
+ effect = "Allow"
+ actions = [
+ "kms:Describe*",
+ "log:AssociateKmsKey",
+ "log:DisassociateKmsKey"
+ ]
+ resources = ["*"]
+
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com", "logs.amazonaws.com", "logs.${local.region}.amazonaws.com"]
+ }
+ }
+
+ statement {
+ sid = "AllowPrincipalsDecryptLogFiles"
+ effect = "Allow"
+
+ principals {
+ type = "AWS"
+ identifiers = ["*"]
+ }
+ actions = [
+ "kms:Encrypt",
+ "kms:Decrypt",
+ "kms:ReEncryptFrom"
+ ]
+ resources = ["*"]
+
+ condition {
+ test = "StringEquals"
+ variable = "kms:CallerAccount"
+ values = [var.account_id]
+ }
+
+ condition {
+ test = "StringLike"
+ variable = "kms:EncryptionContext:aws:cloudtrail:arn"
+ values = ["arn:${data.aws_arn.current.partition}:cloudtrail:*:${var.account_id}:trail/*"]
+ }
+ }
+
+ statement {
+ sid = "EnableCrossAccountDecryptLogFiles"
+ effect = "Allow"
+
+ principals {
+ type = "AWS"
+ identifiers = ["*"]
+ }
+
+ actions = [
+ "kms:Encrypt",
+ "kms:Decrypt",
+ "kms:ReEncryptFrom"
+ ]
+ resources = ["*"]
+
+ condition {
+ test = "StringEquals"
+ variable = "kms:CallerAccount"
+ values = [var.account_id]
+ }
+
+ condition {
+ test = "StringLike"
+ variable = "kms:EncryptionContext:aws:cloudtrail:arn"
+ values = ["arn:${data.aws_arn.current.partition}:cloudtrail:*:${var.account_id}:trail/*"]
+ }
+ }
+
+ statement {
+ sid = "AllowAliasCreationDuringSetup"
+ effect = "Allow"
+ actions = ["kms:CreateAlias"]
+ resources = ["*"]
+
+ principals {
+ type = "AWS"
+ identifiers = ["*"]
+ }
+
+ condition {
+ test = "StringEquals"
+ variable = "kms:CallerAccount"
+ values = [var.account_id]
+ }
+
+ condition {
+ test = "StringEquals"
+ variable = "kms:ViaService"
+ values = ["ec2.${local.region}.amazonaws.com}"]
+ }
+ }
+}
diff --git a/cloudtrail/main.tf b/cloudtrail/main.tf
index 1157b2a..e6df390 100644
--- a/cloudtrail/main.tf
+++ b/cloudtrail/main.tf
@@ -55,120 +55,14 @@ locals {
partition = data.aws_arn.current.partition
name = var.name == null ? format("%v-%v", lookup(local._defaults["cloudtrail"], "name"), local.region) : var.name
- kms_key_arn = var.kms_key_arn
kms_key_name = format("k-%v", local.name)
kms_admin_root = format("arn:%v:iam::%v:root", local.partition, local.account_id)
- kms_admin_roles = compact(concat([local.kms_admin_root], var.kms_admin_roles))
+ kms_admin_roles = compact(concat([var.kms_admin_root], var.kms_admin_roles))
kms_policy_document = var.kms_policy_document != null ? var.kms_policy_document : data.aws_iam_policy_document.empty.json
bucket_name = var.name == null ? format("%v-%v-%v", lookup(local._defaults["cloudtrail"], "name"), local.account_id, local.region) : var.name
}
-
-resource "aws_cloudtrail" "trail" {
- name = local.name
- s3_bucket_name = aws_s3_bucket.trail.id
- s3_key_prefix = var.cloudtrail_bucket_prefix
- include_global_service_events = rue
- is_multi_region_trail = false
- kms_key_id = local.kms_key_arn
- enable_log_file_validation = true
-
- tags = merge(
- local.base_tags,
- var.tags,
- { "Name" = local.name },
- )
- depends_on = [aws_s3_bucket_policy.policy]
-}
-
-
-resource "aws_s3_bucket" "trail" {
- bucket = local.bucket_name
- acl = "private"
- force_destroy = false
-
- logging {
- target_bucket = var.access_log_bucket
- target_prefix = format("%s/%s/", var.access_log_bucket_prefix, local.name)
- }
-
- tags = merge(
- local.base_tags,
- var.tags,
- { "Name" = local.name },
- )
-
- server_side_encryption_configuration {
- rule {
- apply_server_side_encryption_by_default {
- kms_master_key_id = local.kms_key_arn
- sse_algorithm = "aws:kms"
- }
- }
- }
-}
-
-#---
-# bucket policy (apply also encryption key usage here?)
-# deny unencrypted uploads policy statement removed for default encryption
-#---
-data "aws_iam_policy_document" "policy" {
- statement {
- sid = "AWSCloudTrailAclCheck"
- effect = "Allow"
- actions = ["s3:GetBucketAcl"]
- principals {
- type = "Service"
- identifiers = ["cloudtrail.amazonaws.com"]
- }
- resources = [aws_s3_bucket.this.arn]
- }
- statement {
- sid = "AWSCloudTrailWrite"
- effect = "Allow"
- actions = ["s3:PutObject"]
- principals {
- type = "Service"
- identifiers = ["cloudtrail.amazonaws.com"]
- }
- resources = ["${aws_s3_bucket.this.arn}/${var.cloudtrail_bucket_prefix}/*"]
- condition {
- test = "StringEquals"
- variable = "s3:x-amz-acl"
- values = ["bucket-owner-full-control"]
- }
- }
-}
-
-#---
-# apply policy to bucket and public access block policy to bucket
-#---
-resource "aws_s3_bucket_policy" "policy" {
- bucket = aws_s3_bucket.this.bucket
- policy = data.aws_iam_policy_document.policy.json
- depends_on = [null_resource.policy_delay]
-}
-
-resource "aws_s3_bucket_public_access_block" "this" {
- bucket = aws_s3_bucket.this.id
- block_public_acls = true
- block_public_policy = true
- ignore_public_acls = true
- restrict_public_buckets = true
-}
-
-#---
-# 180s delay needed for bucket to create and policy to apply, before
-# creating a cloudtrail to point to it
-#---
-resource "null_resource" "policy_delay" {
- triggers = {
- bucket = aws_s3_bucket.this.id
- # policy = aws_s3_bucket_policy.policy.id
- }
- provisioner "local-exec" {
- when = create
- command = "sleep 180"
- }
+data "aws_kms_key" "incoming_key" {
+ key_id = var.kms_key_arn
}
diff --git a/cloudtrail/s3-bucket-policy.tf.off b/cloudtrail/s3-bucket-policy.tf.off
new file mode 100644
index 0000000..e092555
--- /dev/null
+++ b/cloudtrail/s3-bucket-policy.tf.off
@@ -0,0 +1,31 @@
+data "aws_iam_policy_document" "cloudtrail_s3" {
+ statement {
+ sid = "AWSCloudTrailWrite"
+ effect = "Allow"
+ resources = ["${aws_s3_bucket.cloudtrail.arn}/*"]
+ actions = ["s3:PutObject"]
+
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+
+ condition {
+ test = "StringLike"
+ variable = "s3:x-amz-acl"
+ values = ["bucket-owner-full-control"]
+ }
+ }
+
+ statement {
+ sid = "AWSCloudTrailAclCheck"
+ effect = "Allow"
+ resources = [aws_s3_bucket.cloudtrail.arn]
+ actions = ["s3:GetBucketAcl"]
+
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+ }
+}
diff --git a/cloudtrail/s3.tf b/cloudtrail/s3.tf
new file mode 100644
index 0000000..134b874
--- /dev/null
+++ b/cloudtrail/s3.tf
@@ -0,0 +1,88 @@
+resource "aws_s3_bucket" "this" {
+ bucket = local.bucket_name
+ acl = "private"
+ force_destroy = false
+
+ logging {
+ target_bucket = var.access_log_bucket
+ target_prefix = format("%s/%s/", var.access_log_bucket_prefix, local.name)
+ }
+
+ tags = merge(
+ local.base_tags,
+ var.tags,
+ { "Name" = local.name },
+ )
+
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ kms_master_key_id = var.kms_key_arn
+ sse_algorithm = "aws:kms"
+ }
+ }
+ }
+}
+
+#---
+# bucket policy (apply also encryption key usage here?)
+# deny unencrypted uploads policy statement removed for default encryption
+#---
+data "aws_iam_policy_document" "bucket_policy" {
+ statement {
+ sid = "AWSCloudTrailAclCheck"
+ effect = "Allow"
+ actions = ["s3:GetBucketAcl"]
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+ resources = [aws_s3_bucket.this.arn]
+ }
+ statement {
+ sid = "AWSCloudTrailWrite"
+ effect = "Allow"
+ actions = ["s3:PutObject"]
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+ resources = [format("%v/%v/*", aws_s3_bucket.this.arn, var.cloudtrail_bucket_prefix)]
+ condition {
+ test = "StringEquals"
+ variable = "s3:x-amz-acl"
+ values = ["bucket-owner-full-control"]
+ }
+ }
+}
+
+#---
+# apply policy to bucket and public access block policy to bucket
+#---
+resource "aws_s3_bucket_policy" "policy" {
+ bucket = aws_s3_bucket.this.bucket
+ policy = data.aws_iam_policy_document.bucket_policy.json
+ depends_on = [null_resource.policy_delay]
+}
+
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
+
+#---
+# 180s delay needed for bucket to create and policy to apply, before
+# creating a cloudtrail to point to it
+#---
+resource "null_resource" "policy_delay" {
+ triggers = {
+ bucket = aws_s3_bucket.this.id
+ }
+ provisioner "local-exec" {
+ when = create
+ command = "sleep 180"
+ }
+}
diff --git a/cloudtrail/s3.tf.off b/cloudtrail/s3.tf.off
new file mode 100644
index 0000000..dc5ee5b
--- /dev/null
+++ b/cloudtrail/s3.tf.off
@@ -0,0 +1,92 @@
+#---
+# s3 object logging bucket, with encryption
+#---
+resource "aws_s3_bucket" "this" {
+ bucket = local.name
+ acl = "private"
+ force_destroy = false
+
+ logging {
+ target_bucket = var.access_log_bucket
+ target_prefix = format("%s/%s/", var.access_log_bucket_prefix, local.name)
+ }
+
+ tags = merge(
+ local.base_tags,
+ var.tags,
+ { "Name" = local.name },
+ )
+
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ kms_master_key_id = aws_kms_key.key.arn
+ sse_algorithm = "aws:kms"
+ }
+ }
+ }
+}
+
+#---
+# bucket policy (apply also encryption key usage here?)
+# deny unencrypted uploads policy statement removed for default encryption
+#---
+data "aws_iam_policy_document" "policy" {
+ statement {
+ sid = "AWSCloudTrailAclCheck"
+ effect = "Allow"
+ actions = ["s3:GetBucketAcl"]
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+ resources = [aws_s3_bucket.this.arn]
+ }
+ statement {
+ sid = "AWSCloudTrailWrite"
+ effect = "Allow"
+ actions = ["s3:PutObject"]
+ principals {
+ type = "Service"
+ identifiers = ["cloudtrail.amazonaws.com"]
+ }
+ resources = ["${aws_s3_bucket.this.arn}/${var.cloudtrail_bucket_prefix}/*"]
+ condition {
+ test = "StringEquals"
+ variable = "s3:x-amz-acl"
+ values = ["bucket-owner-full-control"]
+ }
+ }
+}
+
+#---
+# apply policy to bucket and public access block policy to bucket
+#---
+resource "aws_s3_bucket_policy" "policy" {
+ bucket = aws_s3_bucket.this.bucket
+ policy = data.aws_iam_policy_document.policy.json
+ depends_on = [null_resource.policy_delay]
+}
+
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
+
+#---
+# 180s delay needed for bucket to create and policy to apply, before
+# creating a cloudtrail to point to it
+#---
+resource "null_resource" "policy_delay" {
+ triggers = {
+ bucket = aws_s3_bucket.this.id
+ # policy = aws_s3_bucket_policy.policy.id
+ }
+ provisioner "local-exec" {
+ when = create
+ command = "sleep 180"
+ }
+}
diff --git a/cloudtrail/variables.tf b/cloudtrail/variables.tf
index b8cb955..3775f86 100644
--- a/cloudtrail/variables.tf
+++ b/cloudtrail/variables.tf
@@ -49,6 +49,11 @@ variable "kms_key_management_identifiers" {
default = []
}
+variable "kms_key_arn" {
+ description = "AWS CloudTrail KMS ARN to be used for encrypting the ClouldTrail, S3 Bucket, and SQS"
+ type = string
+}
+
variable "enable_sns" {
description = "Flag to enable or disable the creation of SNS for Cloudtrail (TBD)"
type = bool