Skip to content
Merged
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
12 changes: 12 additions & 0 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ description: |-
1) Set `s3_force_destroy` to `true` and apply
2) Set `enabled` to `false` and apply, or run `terraform destroy`

## CloudTrail KMS Encryption

By default, this component creates a KMS key to encrypt CloudTrail logs for compliance and security. The KMS encryption can be configured using these variables:

- `cloudtrail_enable_kms_encryption` (default: `true`) - Enable/disable KMS encryption for CloudTrail logs
- `cloudtrail_kms_key_arn` (default: `null`) - Provide an existing KMS key ARN to use instead of creating a new one
- `cloudtrail_create_kms_key` (default: `true`) - Create a new KMS key when `cloudtrail_kms_key_arn` is not provided
- `cloudtrail_kms_key_deletion_window_in_days` (default: `10`) - KMS key deletion window (7-30 days)
- `cloudtrail_kms_key_enable_rotation` (default: `true`) - Enable automatic KMS key rotation

The created KMS key includes the required policy statements for CloudTrail to encrypt logs and for authorized principals to decrypt them.

## Sponsorship

<picture>
Expand Down
29 changes: 26 additions & 3 deletions src/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

129 changes: 129 additions & 0 deletions src/kms.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# KMS key policy document for CloudTrail encryption
data "aws_iam_policy_document" "cloudtrail_kms_key_policy" {
count = local.enabled && var.cloudtrail_enable_kms_encryption && var.cloudtrail_create_kms_key && var.cloudtrail_kms_key_arn == null ? 1 : 0

# Enable IAM User Permissions
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:${local.aws_partition}:iam::${local.aws_account_id}:root"]
}
actions = [
"kms:*"
]
resources = ["*"]
}

# Allow CloudTrail to encrypt logs
statement {
sid = "Allow CloudTrail to encrypt logs"
effect = "Allow"
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
actions = [
"kms:GenerateDataKey*"
]
resources = ["*"]
condition {
test = "StringLike"
variable = "aws:SourceArn"
values = ["arn:${local.aws_partition}:cloudtrail:*:${local.aws_account_id}:trail/${module.this.id}"]
}
condition {
test = "StringEquals"
variable = "kms:EncryptionContext:aws:cloudtrail:arn"
values = ["arn:${local.aws_partition}:cloudtrail:${var.region}:${local.aws_account_id}:trail/${module.this.id}"]
}
}

# Allow CloudTrail to describe key
statement {
sid = "Allow CloudTrail to describe key"
effect = "Allow"
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
actions = [
"kms:DescribeKey"
]
resources = ["*"]
}

# Allow principals in the account to decrypt log files
statement {
sid = "Allow principals in the account to decrypt log files"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:${local.aws_partition}:iam::${local.aws_account_id}:root"]
}
actions = [
"kms:Decrypt",
"kms:ReEncryptFrom"
]
resources = ["*"]
condition {
test = "StringEquals"
variable = "kms:CallerAccount"
values = [local.aws_account_id]
}
condition {
test = "StringLike"
variable = "kms:EncryptionContext:aws:cloudtrail:arn"
values = ["arn:${local.aws_partition}:cloudtrail:*:${local.aws_account_id}:trail/*"]
}
}

# Allow alias creation during resource creation
statement {
sid = "Allow alias creation during resource creation"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:${local.aws_partition}:iam::${local.aws_account_id}:root"]
}
actions = [
"kms:CreateAlias"
]
resources = ["*"]
condition {
test = "StringEquals"
variable = "kms:CallerAccount"
values = [local.aws_account_id]
}
}
}

# KMS key for CloudTrail encryption
resource "aws_kms_key" "cloudtrail" {
count = local.enabled && var.cloudtrail_enable_kms_encryption && var.cloudtrail_create_kms_key && var.cloudtrail_kms_key_arn == null ? 1 : 0

description = "KMS key for CloudTrail log encryption - ${module.this.id}"
deletion_window_in_days = var.cloudtrail_kms_key_deletion_window_in_days
enable_key_rotation = var.cloudtrail_kms_key_enable_rotation
policy = data.aws_iam_policy_document.cloudtrail_kms_key_policy[0].json

tags = merge(
module.this.tags,
{
Name = "${module.this.id}-cloudtrail"
managed-by = "terraform"
env = var.stage
service = "datadog-logs-archive"
part-of = "observability"
}
)
}

# KMS key alias for easier identification
resource "aws_kms_alias" "cloudtrail" {
count = local.enabled && var.cloudtrail_enable_kms_encryption && var.cloudtrail_create_kms_key && var.cloudtrail_kms_key_arn == null ? 1 : 0

name = "alias/${module.this.id}-cloudtrail"
target_key_id = aws_kms_key.cloudtrail[0].key_id
}
11 changes: 10 additions & 1 deletion src/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ locals {
# default datadog_logs_archive query.
default_query = join(" OR ", concat([join(":", ["env", var.stage]), join(":", ["account", local.aws_account_id])], var.additional_query_tags))
query = var.query_override == null ? local.default_query : var.query_override

# CloudTrail KMS key ARN selection
cloudtrail_kms_key_arn = (
var.cloudtrail_enable_kms_encryption == false ? null :
var.cloudtrail_kms_key_arn != null ? var.cloudtrail_kms_key_arn :
var.cloudtrail_create_kms_key && local.enabled ? try(aws_kms_key.cloudtrail[0].arn, null) :
null
)
}

# We use the http data source due to lack of a data source for datadog_logs_archive_order
Expand Down Expand Up @@ -304,7 +312,7 @@ module "cloudtrail" {
# dependency on the attachment of the bucket policy, leading to
# insufficient permissions issues on cloudtrail creation if it
# happens to be attempted prior to completion of the policy attachment.
depends_on = [module.cloudtrail_s3_bucket]
depends_on = [module.cloudtrail_s3_bucket, aws_kms_key.cloudtrail]
source = "cloudposse/cloudtrail/aws"
version = "0.24.0"

Expand All @@ -314,6 +322,7 @@ module "cloudtrail" {
enabled = local.enabled
enable_logging = true
s3_bucket_name = module.cloudtrail_s3_bucket[0].bucket_id
kms_key_arn = local.cloudtrail_kms_key_arn

event_selector = [
{
Expand Down
15 changes: 15 additions & 0 deletions src/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,18 @@ output "catchall_id" {
value = local.enabled && var.catchall_enabled ? datadog_logs_archive.catchall_archive[0].id : ""
description = "The ID of the catchall log archive"
}

output "cloudtrail_kms_key_arn" {
value = local.cloudtrail_kms_key_arn
description = "The ARN of the KMS key used for CloudTrail log encryption"
}

output "cloudtrail_kms_key_id" {
value = local.enabled && var.cloudtrail_enable_kms_encryption && var.cloudtrail_create_kms_key && var.cloudtrail_kms_key_arn == null ? aws_kms_key.cloudtrail[0].key_id : ""
description = "The ID of the KMS key used for CloudTrail log encryption (only if created by this module)"
}

output "cloudtrail_kms_key_alias" {
value = local.enabled && var.cloudtrail_enable_kms_encryption && var.cloudtrail_create_kms_key && var.cloudtrail_kms_key_arn == null ? aws_kms_alias.cloudtrail[0].name : ""
description = "The alias of the KMS key used for CloudTrail log encryption (only if created by this module)"
}
31 changes: 31 additions & 0 deletions src/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,35 @@ variable "s3_force_destroy" {
default = false
}

variable "cloudtrail_enable_kms_encryption" {
type = bool
description = "Enable KMS encryption for CloudTrail logs"
default = true
}

variable "cloudtrail_kms_key_arn" {
type = string
description = "ARN of an existing KMS key to use for CloudTrail log encryption. If not provided and cloudtrail_enable_kms_encryption is true, a new key will be created"
default = null
nullable = true
}

variable "cloudtrail_create_kms_key" {
type = bool
description = "Create a new KMS key for CloudTrail encryption. Only used if cloudtrail_kms_key_arn is not provided and cloudtrail_enable_kms_encryption is true"
default = true
}

variable "cloudtrail_kms_key_deletion_window_in_days" {
type = number
description = "Duration in days after which the KMS key is deleted after destruction of the resource, must be between 7 and 30 days"
default = 10
}

variable "cloudtrail_kms_key_enable_rotation" {
type = bool
description = "Enable automatic rotation of the KMS key"
default = true
}


Loading