add cloudtrail module
parent
fc6de54755
commit
6dc0deb490
@ -0,0 +1,26 @@
|
||||
# Cloudtrail
|
||||
|
||||
Configure AWS Cloudtrail in a given AWS account. Logs all S3 bucket data plane operations by default; see inputs for more info.
|
||||
|
||||
https://aws.amazon.com/cloudtrail/
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
module "cloudtrail" {
|
||||
source = "github.com/lalanza808/tf-modules.git/security/cloudtrail"
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
There are a few variables that can be tweaked here. You can also override the default behavior of logging all S3 bucket data plane operations to either log nothing or log some buckets.
|
||||
|
||||
* `default_log_bucket` - set to empty string to remove all bucket logging
|
||||
* `activity_log_buckets` - list of bucket names to setup extra logging for
|
||||
|
||||
See the full list of inputs here: [variables.tf](./variables.tf)
|
||||
|
||||
## Outputs
|
||||
|
||||
[output.tf](./output.tf)
|
@ -0,0 +1,42 @@
|
||||
resource "aws_iam_role" "cloudtrail_log_group_role" {
|
||||
name = aws_s3_bucket.cloudtrail_bucket.id
|
||||
tags = var.tags
|
||||
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "cloudtrail.amazonaws.com"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "cloudtrail_log_group_role_policy" {
|
||||
name = aws_s3_bucket.cloudtrail_bucket.id
|
||||
role = aws_iam_role.cloudtrail_log_group_role.id
|
||||
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "logs:CreateLogStream",
|
||||
"Resource": "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}",
|
||||
"Effect": "Allow"
|
||||
},
|
||||
{
|
||||
"Action": "logs:PutLogEvents",
|
||||
"Resource": "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}",
|
||||
"Effect": "Allow"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
resource "aws_kms_key" "cloudtrail" {
|
||||
description = var.prefix
|
||||
enable_key_rotation = var.enable_key_rotation
|
||||
tags = var.tags
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"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 CloudTrail to encrypt logs",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": ["cloudtrail.amazonaws.com"]
|
||||
},
|
||||
"Action": "kms:GenerateDataKey*",
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:${data.aws_caller_identity.current.account_id}:trail/*"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "Allow CloudTrail to describe keys",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": ["cloudtrail.amazonaws.com"]},
|
||||
"Action": "kms:DescribeKey",
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "Allow principals in the account to decrypt log files",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": [
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncryptFrom"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"kms:CallerAccount": "${data.aws_caller_identity.current.account_id}"
|
||||
},
|
||||
"StringLike": {
|
||||
"kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:${data.aws_caller_identity.current.account_id}:trail/*"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "Allow alias creation during setup",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "kms:CreateAlias",
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"kms:ViaService": "ec2.region.amazonaws.com",
|
||||
"kms:CallerAccount": "${data.aws_caller_identity.current.account_id}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Sid": "Enable cross account log decryption",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": [
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncryptFrom"
|
||||
],
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"kms:CallerAccount": "${data.aws_caller_identity.current.account_id}"
|
||||
},
|
||||
"StringLike": {
|
||||
"kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:${data.aws_caller_identity.current.account_id}:trail/*"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_kms_alias" "kms" {
|
||||
name = "alias/${var.prefix}-cloudtrail"
|
||||
target_key_id = aws_kms_key.cloudtrail.key_id
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
data "aws_caller_identity" "current" {}
|
||||
|
||||
resource "aws_cloudtrail" "cloudtrail_bucket_logging" {
|
||||
name = aws_s3_bucket.cloudtrail_bucket.id
|
||||
s3_bucket_name = aws_s3_bucket.cloudtrail_bucket.id
|
||||
include_global_service_events = var.include_global_service_events
|
||||
is_multi_region_trail = var.is_multi_region_trail
|
||||
enable_logging = var.enable_logging
|
||||
enable_log_file_validation = var.enable_log_file_validation
|
||||
cloud_watch_logs_role_arn = aws_iam_role.cloudtrail_log_group_role.arn
|
||||
cloud_watch_logs_group_arn = aws_cloudwatch_log_group.cloudtrail_log_group.arn
|
||||
kms_key_id = aws_kms_key.cloudtrail.arn
|
||||
tags = var.tags
|
||||
|
||||
event_selector {
|
||||
read_write_type = "All"
|
||||
include_management_events = var.include_management_events
|
||||
|
||||
data_resource {
|
||||
type = "AWS::S3::Object"
|
||||
values = compact(concat(
|
||||
[var.default_log_bucket],
|
||||
formatlist("arn:aws:s3:::%s/", var.activity_log_buckets)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
// Resource attritbute output
|
||||
|
||||
output "s3_bucket" {
|
||||
value = aws_s3_bucket.cloudtrail_bucket.id
|
||||
}
|
||||
|
||||
output "trail_name" {
|
||||
value = aws_cloudtrail.cloudtrail_bucket_logging.id
|
||||
}
|
||||
|
||||
output "log_group_name" {
|
||||
value = aws_cloudwatch_log_group.cloudtrail_log_group.name
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
resource "aws_s3_bucket" "cloudtrail_bucket" {
|
||||
bucket_prefix = "${var.prefix}-cloudtrail-"
|
||||
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" "cloudtrail_bucket_policy" {
|
||||
bucket = aws_s3_bucket.cloudtrail_bucket.id
|
||||
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AWSCloudTrailAclCheck",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "cloudtrail.amazonaws.com"
|
||||
},
|
||||
"Action": "s3:GetBucketAcl",
|
||||
"Resource": "${aws_s3_bucket.cloudtrail_bucket.arn}"
|
||||
},
|
||||
{
|
||||
"Sid": "AWSCloudTrailWrite",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "cloudtrail.amazonaws.com"
|
||||
},
|
||||
"Action": "s3:PutObject",
|
||||
"Resource": "${aws_s3_bucket.cloudtrail_bucket.arn}/*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"s3:x-amz-acl": "bucket-owner-full-control"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "cloudtrail_log_group" {
|
||||
name = aws_s3_bucket.cloudtrail_bucket.id
|
||||
retention_in_days = var.cloudwatch_log_retention
|
||||
tags = var.tags
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
variable "include_management_events" {
|
||||
default = true
|
||||
description = "Whether or not you want to include management events"
|
||||
}
|
||||
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 = 365
|
||||
description = "Number of days to maintain in S3 until transitioning to Glacier"
|
||||
}
|
||||
variable "enable_key_rotation" {
|
||||
default = true
|
||||
}
|
||||
variable "lifecycle_object_expiration" {
|
||||
default = 1825
|
||||
description = "Number of days to expire objects permanently"
|
||||
}
|
||||
variable "cloudwatch_log_retention" {
|
||||
default = 90
|
||||
description = "Number of days to maintain Cloudtrail events in Cloudwatch Logs"
|
||||
}
|
||||
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 "include_global_service_events" {
|
||||
default = true
|
||||
description = "Whether or not to include global service events"
|
||||
}
|
||||
variable "is_multi_region_trail" {
|
||||
default = true
|
||||
description = "Whether or not to use all regions"
|
||||
}
|
||||
variable "enable_logging" {
|
||||
default = true
|
||||
description = "Whether or not to enable logging"
|
||||
}
|
||||
variable "enable_log_file_validation" {
|
||||
default = true
|
||||
description = "Whether or not to enable log validation"
|
||||
}
|
||||
variable "tags" {
|
||||
default = {}
|
||||
type = map
|
||||
description = "Optional set of tags to apply to the infrastructure"
|
||||
}
|
||||
variable "prefix" {
|
||||
default = "security"
|
||||
description = "String to prefix to all resources"
|
||||
}
|
||||
variable "activity_log_buckets" {
|
||||
description = "List of bucket ARNs to collect data plane operation logs for in addition to API events"
|
||||
type = list
|
||||
default = []
|
||||
}
|
||||
variable "default_log_bucket" {
|
||||
default = "arn:aws:s3:::"
|
||||
description = "The default buckets to log - all buckets in the account - override to empty string"
|
||||
}
|
Loading…
Reference in New Issue