Răsfoiți Sursa

Enabled Centralized Cloudtrail and AWS Config

Centralizes cloudtrail logs in the C2 account.
* Cloudtrail configured to store locally in a 7-day cloudwatch log and
  centrally in the s3 bucket.
* KMS key for cloudtrail created and appropriately shared across accounts
* SNS and SQS queues set up for SQS-based-S3 retrieval of cloudwatch by splunk (Splunk account/role still needs to be configured)
* AWS Config enabled on all accounts
* AWS Config central S3 bucket created
* AWS Aggregated input created in C2

Borrows some third party modules to do some heavy lifting.

To be tagged *v0.5.0*
Fred Damstra 5 ani în urmă
părinte
comite
b19d7fe518
51 a modificat fișierele cu 1635 adăugiri și 67 ștergeri
  1. 16 0
      base/account_standards/cloudtrail.tf
  2. 102 0
      base/account_standards/config.tf
  3. 14 58
      base/account_standards/vars.tf
  4. 4 0
      base/account_standards_c2/README.md
  5. 44 0
      base/account_standards_c2/config_aggregator.tf
  6. 157 0
      base/account_standards_c2/config_bucket.tf
  7. 219 0
      base/account_standards_c2/main.tf
  8. 7 0
      base/account_standards_c2/outputs.tf
  9. 16 0
      base/account_standards_c2/vars.tf
  10. 3 0
      base/account_standards_c2/version.tf
  11. 9 0
      base/account_standards_regional/main.tf
  12. 0 0
      base/account_standards_regional/outputs.tf
  13. 22 0
      base/account_standards_regional/vars.tf
  14. 3 0
      base/account_standards_regional/version.tf
  15. 1 9
      thirdparty/README.md
  16. 13 0
      thirdparty/terraform-aws-cloudtrail-bucket/.pre-commit-config.yaml
  17. 1 0
      thirdparty/terraform-aws-cloudtrail-bucket/.terraform-version
  18. 21 0
      thirdparty/terraform-aws-cloudtrail-bucket/LICENSE
  19. 39 0
      thirdparty/terraform-aws-cloudtrail-bucket/README.md
  20. 6 0
      thirdparty/terraform-aws-cloudtrail-bucket/SOURCE
  21. 75 0
      thirdparty/terraform-aws-cloudtrail-bucket/kms.tf
  22. 123 0
      thirdparty/terraform-aws-cloudtrail-bucket/main.tf
  23. 14 0
      thirdparty/terraform-aws-cloudtrail-bucket/outputs.tf
  24. 41 0
      thirdparty/terraform-aws-cloudtrail-bucket/variables.tf
  25. 4 0
      thirdparty/terraform-aws-cloudtrail-bucket/versions.tf
  26. 13 0
      thirdparty/terraform-aws-cloudtrail-logging/.pre-commit-config.yaml
  27. 1 0
      thirdparty/terraform-aws-cloudtrail-logging/.terraform-version
  28. 21 0
      thirdparty/terraform-aws-cloudtrail-logging/LICENSE
  29. 42 0
      thirdparty/terraform-aws-cloudtrail-logging/README.md
  30. 6 0
      thirdparty/terraform-aws-cloudtrail-logging/SOURCE
  31. 102 0
      thirdparty/terraform-aws-cloudtrail-logging/main.tf
  32. 9 0
      thirdparty/terraform-aws-cloudtrail-logging/output.tf
  33. 50 0
      thirdparty/terraform-aws-cloudtrail-logging/variables.tf
  34. 4 0
      thirdparty/terraform-aws-cloudtrail-logging/versions.tf
  35. 9 0
      thirdparty/terraform-aws-s3logging-bucket/.gitignore
  36. 71 0
      thirdparty/terraform-aws-s3logging-bucket/.pre-commit-config.yaml
  37. 45 0
      thirdparty/terraform-aws-s3logging-bucket/.tflint.hcl
  38. 2 0
      thirdparty/terraform-aws-s3logging-bucket/.yamllint.yml
  39. 21 0
      thirdparty/terraform-aws-s3logging-bucket/LICENSE
  40. 56 0
      thirdparty/terraform-aws-s3logging-bucket/README.md
  41. 4 0
      thirdparty/terraform-aws-s3logging-bucket/SOURCE
  42. 18 0
      thirdparty/terraform-aws-s3logging-bucket/bin/install-macos.sh
  43. 23 0
      thirdparty/terraform-aws-s3logging-bucket/bin/install-ubuntu.sh
  44. 2 0
      thirdparty/terraform-aws-s3logging-bucket/examples/basic/README.md
  45. 19 0
      thirdparty/terraform-aws-s3logging-bucket/examples/basic/main.tf
  46. 2 0
      thirdparty/terraform-aws-s3logging-bucket/examples/multiple-prefixes/README.md
  47. 40 0
      thirdparty/terraform-aws-s3logging-bucket/examples/multiple-prefixes/main.tf
  48. 67 0
      thirdparty/terraform-aws-s3logging-bucket/main.tf
  49. 14 0
      thirdparty/terraform-aws-s3logging-bucket/outputs.tf
  50. 37 0
      thirdparty/terraform-aws-s3logging-bucket/variables.tf
  51. 3 0
      thirdparty/terraform-aws-s3logging-bucket/versions.tf

+ 16 - 0
base/account_standards/cloudtrail.tf

@@ -0,0 +1,16 @@
+# Sets up a cloudtrail that keeps 7 days locally in cloudwatch logs and also sends everything to a bucket in C2
+module "cloudtrail-logging" {
+  source            = "../../thirdparty/terraform-aws-cloudtrail-logging"
+  region            = var.aws_region
+  cloudtrail_name   = "xdr-centralized-cloudtrail"
+  cloudtrail_bucket = "xdr-cloudtrail-logs-${local.logging_environment}"
+  iam_path          = "/aws_services/"
+  kms_key_id        = var.cloudtrail_key_arn
+  log_group_name    = "cloudtrail-local-account"
+  retention_in_days = 7 # Days available in the local account cloudtrail logs. See the S3 bucket for retention there.
+  # Uncomment to enable object level logging. If specifying individual buckets, be sure to end with a `/'
+  # This is not enabled by default due to the recursive nature: A log is written, splunk reads it, which results in a log being written.
+  # This is not a CIS requirement.
+  #s3_object_level_buckets = [ "arn:${var.aws_partition}:s3:::"  ]
+  lambda_functions        = [ "arn:${var.aws_partition}:lambda" ]
+}

+ 102 - 0
base/account_standards/config.tf

@@ -0,0 +1,102 @@
+# Approve the aggregator in C2
+resource "aws_config_aggregate_authorization" "authorization" {
+  account_id = local.c2_account
+  region     = var.aws_region
+  tags       = merge(var.standard_tags, var.tags)
+}
+
+output authorizations {
+  value = aws_config_aggregate_authorization.authorization
+}
+
+########### IAM Role for AWS Config
+data "aws_iam_policy_document" "awsconfig" {
+  statement {
+    effect  = "Allow"
+    actions = ["s3:PutObject"]
+    resources = [
+      "arn:${var.aws_partition}:s3:::xdr-config-${var.environment}/*",
+    ]
+    condition {
+      test     = "StringEquals"
+      variable = "s3:x-amz-acl"
+      values   = ["bucket-owner-full-control"]
+    }
+  }
+  statement {
+    effect  = "Allow"
+    actions = ["s3:GetBucketAcl"]
+    resources = [
+      "arn:${var.aws_partition}:s3:::xdr-config-${var.environment}/*",
+    ]
+  }
+
+  statement {
+    effect = "Allow"
+    actions = [ "sns:Publish" ]
+    resources = [ "arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts" ]
+  }
+}
+
+resource "aws_iam_policy" "awsconfig" {
+  name_prefix = "awsconfig-"
+  policy      = data.aws_iam_policy_document.awsconfig.json
+}
+
+data "aws_iam_policy_document" "assume" {
+  statement {
+    effect  = "Allow"
+    actions = ["sts:AssumeRole"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["config.amazonaws.com"]
+    }
+  }
+}
+
+resource "aws_iam_role" "awsconfig" {
+  name_prefix        = "aws-config-role"
+  path               = "/aws_services/"
+  assume_role_policy = data.aws_iam_policy_document.assume.json
+}
+
+resource "aws_iam_role_policy_attachment" "awsconfig_managed_policy" {
+  role       = aws_iam_role.awsconfig.name
+  policy_arn = "arn:${var.aws_partition}:iam::aws:policy/service-role/AWSConfigRole"
+}
+
+resource "aws_iam_role_policy_attachment" "awsconfig_local_policy" {
+  role       = aws_iam_role.awsconfig.name
+  policy_arn = aws_iam_policy.awsconfig.arn
+}
+
+################ Config Recorder
+resource "aws_config_configuration_recorder" "awsconfig_recorder" {
+  name     = "xdr-config-recorder"
+  role_arn = aws_iam_role.awsconfig.arn
+
+  recording_group {
+    all_supported                 = true
+    include_global_resource_types = true
+  }
+}
+
+resource "aws_config_delivery_channel" "awsconfig_delivery_channel" {
+  name           = "xdr-config-delivery-channel"
+  s3_bucket_name = "xdr-config-${var.environment}"
+  sns_topic_arn  = "arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"
+
+  snapshot_delivery_properties {
+    delivery_frequency = "One_Hour"
+  }
+
+  depends_on = [aws_config_configuration_recorder.awsconfig_recorder]
+}
+
+resource "aws_config_configuration_recorder_status" "awsconfig_recorder_status" {
+  name       = "xdr-config-recorder"
+  is_enabled = true
+
+  depends_on = [aws_config_delivery_channel.awsconfig_delivery_channel]
+}

+ 14 - 58
base/account_standards/vars.tf

@@ -1,77 +1,33 @@
-variable "key_pairs" {
-  description = "Public SSH keys"
-  type = map
-}
-
 variable "tags" {
-  description = "Extra tags for the module."
   type = map
   default = { } 
 }
 
+variable "cloudtrail_key_arn" {
+  # Unfortunately, if we use the alias, it modifies it every time, so we have to grab the actual arn
+  type = string
+}
+
 # ----------------------------------
 # Below this line are variables inherited from higher levels, so they
 # do not need to be explicitly passed to this module.
 variable "standard_tags" { type = map }
+variable "account_list" { type = list }
 variable "aws_account_id" { type = string }
 variable "aws_partition" { type = string }
+variable "aws_region" { type = string }
 variable "environment" { type = string }
+variable "key_pairs" { type = map }
+variable "c2_accounts" { type = map }
 
-# ----------------------------------
-# Below this line are variables from the CIS standards
+# Calculate some local variables
 locals {
-  workspace-cis-hardening-policy = {
-    "default"     = "cis_hardening_iam_role_policy.json.tpl"
-    "prod"        = "cis_hardening_iam_role_policy_prod.json.tpl"
-    "common"      = "cis_hardening_iam_role_policy_prod.json.tpl"
-    "test"        = "cis_hardening_iam_role_policy_test.json.tpl"
-  }
-  workspace-dps-s3-cloudtrail-bucket = {
-    "default"     = "dps-mdr-cloudtrail"
-    "prod"        = "dps-mdr-cloudtrail-prod"
-    "common"      = "dps-mdr-cloudtrail-prod"
-    "test"        = "dps-mdr-cloudtrail-test"
-    "description" = "S3 bucket name for CloudTrail Logs"
-  }
-  workspace-dps-s3-cloudtrail-bucket-policy = { 
-    "default"     = "cloudtrail_s3_policy.json.tpl"
-    "prod"        = "cloudtrail_s3_policy_prod.json.tpl"
-    "common"      = "cloudtrail_s3_policy_prod.json.tpl"
-    "test"        = "cloudtrail_s3_policy_test.json.tpl"
-    "description" = "S3 IAM Policy for Cloudtrail Bucket" 
-  }
-
-  workspace-dps-cloudtrail-cloudwatch-logs-role = {
-    "default"     = "cloudtrail_cloudwatch_logs_role_policy.json.tpl"
-    "prod"        = "cloudtrail_cloudwatch_logs_role_policy_prod.json.tpl"
-    "common"      = "cloudtrail_cloudwatch_logs_role_policy_prod.json.tpl"
-    "test"        = "cloudtrail_cloudwatch_logs_role_policy_test.json.tpl"
-    "description" = "IAM Role for Cloudtrails Cloudwatch Logs" 
-  }
-
-  workspace-dps-cloudtrail-cloudwatch-logs-policy = {
-    "default"     = "cloudtrail_cloudwatch_logs_inline_policy.json.tpl"
-    "prod"        = "cloudtrail_cloudwatch_logs_inline_policy_prod.json.tpl"
-    "common"      = "cloudtrail_cloudwatch_logs_inline_policy_prod.json.tpl"
-    "test"        = "cloudtrail_cloudwatch_logs_inline_policy_test.json.tpl"
-    "description" = "IAM Role for Cloudtrails Cloudwatch Logs" 
-  }
-
-  workspace-billing-s3-bucket-name = {
-    "default"     = "dps-mdr-billing"
-    "prod"        = "dps-mdr-billing-prod"
-    "common"      = "dps-mdr-billing-prod"
-    "test"        = "dps-mdr-billing-test"
-    "description" = "S3 bucket name for Billing Logs"
-  }
- 
-  workspace-ebs-kms-key-encryption-policy = {
-    "prod"        = "ebs_root_encrypt_decrypt_policy_prod.json.tpl"
-    "common"      = "ebs_root_encrypt_decrypt_policy_prod.json.tpl"
-    "test"        = "ebs_root_encrypt_decrypt_policy_test.json.tpl"
-  }
+  logging_environment = var.environment == "common" ? "prod" : var.environment # common logs to prod
+  c2_account = var.c2_accounts[var.aws_partition]
+  is_c2 = var.aws_account_id == local.c2_account ? true : false
 }
 
+# Carried over from TF11, may not be used or accurate:
 variable "alarm_namespace" {
   description = "The namespace in which all alarms are set up."
   default     = "dps-alarm-benchmark"

+ 4 - 0
base/account_standards_c2/README.md

@@ -0,0 +1,4 @@
+# Account Standards
+
+Creates elements that are standard in all accounts, such as access keys, kms keys, etc.
+

+ 44 - 0
base/account_standards_c2/config_aggregator.tf

@@ -0,0 +1,44 @@
+resource "aws_config_configuration_aggregator" "account" {
+  name = "xdr-aggregator-${var.environment}"
+
+  account_aggregation_source {
+    account_ids = var.responsible_accounts[var.environment]
+    all_regions = true
+  }
+}
+
+resource "aws_sns_topic" "account-alerts" {
+  name              = "account-alerts"
+  #kms_master_key_id = "alias/aws/sns" # TODO
+}
+
+resource "aws_sns_topic_policy" "account-alerts" {
+  arn    = aws_sns_topic.account-alerts.arn
+  policy = data.aws_iam_policy_document.config-sns.json
+}
+
+data "aws_iam_policy_document" "config-sns" {
+  statement {
+    sid = "AllowConfig"
+    actions = [ "SNS:Publish" ]
+    effect = "Allow"
+    resources = [ aws_sns_topic.account-alerts.arn ]
+    principals {
+      type = "AWS"
+      identifiers = var.responsible_accounts[var.environment]
+    }
+  }
+
+# This is for a service-linked role, but from https://docs.aws.amazon.com/config/latest/developerguide/sns-topic-policy.html:
+#   "AWS Config does not recommend using a service-linked role when using Amazon SNS topic from other accounts."
+#  statement {
+#    sid = "AllowConfigServer"
+#    effect = "Allow",
+#    principals {
+#      type = "AWS"
+#      resources = [ ]
+#    }
+#    actions = [ "SNS:Publish", ]
+#    resources = [ aws_sns_topic.account-alerts.arn ]
+#  }
+}

+ 157 - 0
base/account_standards_c2/config_bucket.tf

@@ -0,0 +1,157 @@
+# The centralized bucket for AWS config
+module "xdr_config_logging_bucket" {
+  source = "../../thirdparty/terraform-aws-s3logging-bucket"
+
+  bucket_name = "xdr-config-${var.environment}-access-logs"
+  lifecycle_rules = list(
+    {
+      id                            = "expire-old-logs"
+      enabled                       = true
+      prefix                        = ""
+      expiration                    = 30
+      noncurrent_version_expiration = 30
+      abort_incomplete_multipart_upload_days = 7
+  })
+  tags = merge(var.standard_tags, var.tags)
+  versioning_enabled = true
+}
+
+resource "aws_s3_bucket" "xdr_config_bucket" {
+  bucket = "xdr-config-${var.environment}"
+  acl    = "private"
+  tags   = merge(var.standard_tags, var.tags)
+
+  versioning {
+    enabled = true
+  }
+
+  logging {
+    target_bucket = module.xdr_config_logging_bucket.s3_bucket_name
+    target_prefix = "${var.aws_account_id}-${var.aws_region}-awsconfig/"
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm = "aws:kms"
+        kms_master_key_id = aws_kms_key.config_encryption.arn
+      }
+    }
+  }
+}
+
+resource "aws_s3_bucket_public_access_block" "awsconfig_bucket_block_public_access" {
+  block_public_acls       = true
+  block_public_policy     = true
+  bucket                  = aws_s3_bucket.xdr_config_bucket.id
+  ignore_public_acls      = true
+  restrict_public_buckets = true
+}
+
+data "aws_iam_policy_document" "awsconfig_bucket_policy" {
+  statement {
+    sid = "AWSConfigBucketPermissionsCheck"
+    effect = "Allow"
+    principals {
+      type = "Service"
+      identifiers = [ "config.amazonaws.com" ]
+    }
+    actions = [ "s3:GetBucketAcl" ]
+    resources = [ aws_s3_bucket.xdr_config_bucket.arn ]
+  }
+  statement {
+    sid = "AWSConfigBucketExistenceCheck"
+    effect = "Allow"
+    principals {
+      type = "Service"
+      identifiers = [ "config.amazonaws.com" ]
+    }
+    actions = [ "s3:ListBucket" ]
+    resources = [ aws_s3_bucket.xdr_config_bucket.arn ]
+  }
+  statement {
+    sid = "AWSConfigBucketDelivery"
+    effect = "Allow"
+    principals {
+      type = "Service"
+      identifiers = [ "config.amazonaws.com" ]
+    }
+    actions = [ "s3:PutObject" ]
+    resources = [ "${aws_s3_bucket.xdr_config_bucket.arn}/AWSLogs/*" ]
+    condition {
+      test = "StringEquals"
+      variable = "s3:x-amz-acl"
+      values = [ "bucket-owner-full-control" ]
+    }
+  }
+}
+
+resource "aws_s3_bucket_policy" "awsconfig_bucket_policy" {
+  bucket = aws_s3_bucket.xdr_config_bucket.id
+  policy = data.aws_iam_policy_document.awsconfig_bucket_policy.json
+}
+
+resource "aws_kms_key" "config_encryption" {
+  description             = "This key is used to encrypt AWS config"
+  deletion_window_in_days = 30
+  policy = data.aws_iam_policy_document.config_encryption_key_policy.json
+  enable_key_rotation = true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_kms_alias" "config_encryption" {
+  name          = "alias/aws_config"
+  target_key_id = aws_kms_key.config_encryption.key_id
+}
+
+data "aws_iam_policy_document" "config_encryption_key_policy" {
+  statement {
+    actions   = ["kms:*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "AWS"
+      identifiers = ["arn:${var.aws_partition}:iam::${var.aws_account_id}:root"]
+    }
+  }
+
+  statement {
+    actions   = ["kms:GenerateDataKey*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["config.amazonaws.com"]
+    }
+  }
+
+  statement {
+    actions = [
+      "kms:Encrypt*",
+      "kms:Decrypt*",
+      "kms:ReEncrypt*",
+      "kms:GenerateDataKey*",
+      "kms:Describe*",
+    ]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["config.amazonaws.com"]
+    }
+  }
+
+  statement {
+    actions   = ["kms:Describe*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["config.amazonaws.com"]
+    }
+  }
+}

+ 219 - 0
base/account_standards_c2/main.tf

@@ -0,0 +1,219 @@
+# Contains cloudtrail configuration for the c2 account only
+module "s3_logging_bucket" {
+  source = "../../thirdparty/terraform-aws-s3logging-bucket"
+
+  bucket_name = "xdr-cloudtrail-logs-${var.environment}-access-logs"
+  lifecycle_rules = list(
+    {
+      id                            = "expire-old-logs"
+      enabled                       = true
+      prefix                        = ""
+      expiration                    = 30
+      noncurrent_version_expiration = 30
+      abort_incomplete_multipart_upload_days = 7
+  })
+  tags = merge(var.standard_tags, var.tags)
+  versioning_enabled = true
+}
+
+module "cloudtrail_logging_bucket" {
+  source = "../../thirdparty/terraform-aws-cloudtrail-bucket"
+
+  allowed_account_ids = var.account_list
+  bucket_name = "xdr-cloudtrail-logs-${var.environment}"
+  logging_bucket = module.s3_logging_bucket.s3_bucket_name
+  region = var.aws_region
+  tags = merge(var.standard_tags, var.tags)
+  lifecycle_rules = list(
+    {
+      id                            = "expire-old-logs"
+      enabled                       = true
+      prefix                        = ""
+      expiration                    = 30
+      noncurrent_version_expiration = 30
+      abort_incomplete_multipart_upload_days = 7
+  })
+}
+
+resource "aws_s3_bucket_notification" "on_new_object" {
+  bucket = module.cloudtrail_logging_bucket.s3_bucket_name
+
+  topic {
+    topic_arn = aws_sns_topic.new_object_event.arn
+
+    events = [
+      "s3:ObjectCreated:*",
+    ]
+
+    # TODO: Can we filter out the digests?
+    filter_suffix = ""
+  }
+}
+
+resource "aws_sns_topic" "new_object_event" {
+  name = "s3-notification-topic-${module.cloudtrail_logging_bucket.s3_bucket_name}"
+  kms_master_key_id = aws_kms_key.new_object_key.id
+}
+
+resource "aws_sns_topic_policy" "this" {
+  arn    = aws_sns_topic.new_object_event.arn
+  policy = data.aws_iam_policy_document.bucket_can_publish.json
+}
+
+data "aws_iam_policy_document" "bucket_can_publish" {
+  statement {
+    actions = [
+      "SNS:Publish",
+    ]
+
+    effect = "Allow"
+
+    condition {
+      test     = "ArnLike"
+      variable = "aws:SourceArn"
+
+      values = [
+        module.cloudtrail_logging_bucket.s3_bucket_arn
+      ]
+    }
+
+    principals {
+      type        = "AWS"
+      identifiers = ["*"]
+    }
+
+    resources = [
+      aws_sns_topic.new_object_event.arn
+    ]
+
+    sid = "allowpublish"
+  }
+
+  statement {
+    actions = [
+      "SNS:Subscribe",
+      "SNS:Receive",
+    ]
+
+    effect = "Allow"
+
+    principals {
+      type        = "AWS"
+      identifiers = ["*"]
+    }
+
+    condition {
+      test     = "ArnEquals"
+      values   = [ aws_sqs_queue.new_s3_object.arn ]
+      variable = "aws:SourceArn"
+    }
+
+    resources = [
+      aws_sns_topic.new_object_event.arn
+    ]
+
+    sid = "sid_allow_subscribe"
+  }
+}
+
+# This is the queue for splunk to subscribe to
+resource "aws_sqs_queue" "new_s3_object" {
+  name                       = "new-objects-for-${module.cloudtrail_logging_bucket.s3_bucket_name}"
+  visibility_timeout_seconds = 300 # wait 5 minutes before allowing a different splunk instance to process the same message
+  message_retention_seconds  = 604800 # Keep a message in the queue for 7 days
+  receive_wait_time_seconds  = 0 # how long to wait for a message before returning
+  redrive_policy             = "{\"deadLetterTargetArn\":\"${aws_sqs_queue.dlq.arn}\",\"maxReceiveCount\":4}"
+  tags                       = merge(var.standard_tags, var.tags)
+  kms_master_key_id = aws_kms_key.new_object_key.id
+  kms_data_key_reuse_period_seconds = 3600
+}
+
+data "aws_iam_policy_document" "sns_topic_can_publish" {
+  statement {
+    effect = "Allow"
+
+    principals {
+      identifiers = [
+        "*",
+      ]
+
+      type = "AWS"
+    }
+
+    actions = [
+      "SQS:SendMessage",
+    ]
+
+    resources = [
+      aws_sqs_queue.new_s3_object.arn
+    ]
+
+    condition {
+      test = "ArnEquals"
+
+      values = [
+        aws_sns_topic.new_object_event.arn
+      ]
+
+      variable = "aws:SourceArn"
+    }
+  }
+}
+
+// Dead Letter queue, use same parameters as main queue
+resource "aws_sqs_queue" "dlq" {
+  name                      = "new-objects-for-${module.cloudtrail_logging_bucket.s3_bucket_name}-dlq"
+  message_retention_seconds = 300
+  receive_wait_time_seconds = 0
+  tags                      = merge(var.standard_tags, var.tags)
+  kms_master_key_id = aws_kms_key.new_object_key.id
+  kms_data_key_reuse_period_seconds = 3600
+}
+
+resource "aws_sqs_queue_policy" "bucket_can_publish" {
+  policy    = data.aws_iam_policy_document.sns_topic_can_publish.json
+  queue_url = aws_sqs_queue.new_s3_object.id
+}
+
+resource "aws_sns_topic_subscription" "bucket_change_notification_to_queue" {
+  topic_arn = aws_sns_topic.new_object_event.arn
+  protocol  = "sqs"
+  endpoint  = aws_sqs_queue.new_s3_object.arn
+}
+
+resource "aws_kms_key" "new_object_key" {
+  description             = "Encryption of SNS and SQS queues on new S3 objects"
+  policy                  = data.aws_iam_policy_document.new_object_key_kms_policy.json
+}
+
+data "aws_iam_policy_document" "new_object_key_kms_policy" {
+  statement {
+    effect = "Allow"
+    principals {
+      identifiers = ["s3.amazonaws.com", "sns.amazonaws.com", "sqs.amazonaws.com"]
+      type = "Service"
+    }
+    actions = [
+      "kms:GenerateDataKey",
+      "kms:Decrypt"
+    ]
+    resources = [ "*" ]
+  }
+  # allow account to modify/manage key
+  statement {
+    effect = "Allow"
+    principals {
+      identifiers = ["arn:${var.aws_partition}:iam::${var.aws_account_id}:root"]
+      type = "AWS"
+    }
+    actions = [
+      "kms:*"
+    ]
+    resources = ["*"]
+  }
+}
+
+resource "aws_kms_alias" "new_object_key_alias" {
+  name          = "alias/new_object_key"
+  target_key_id = aws_kms_key.new_object_key.key_id
+}

+ 7 - 0
base/account_standards_c2/outputs.tf

@@ -0,0 +1,7 @@
+output "s3_logging_bucket" {
+  value = module.s3_logging_bucket
+}
+
+output "cloudtrail_logging_bucket" {
+  value = module.cloudtrail_logging_bucket
+}

+ 16 - 0
base/account_standards_c2/vars.tf

@@ -0,0 +1,16 @@
+variable "tags" {
+  type = map
+  default = { } 
+}
+
+# ----------------------------------
+# Below this line are variables inherited from higher levels, so they
+# do not need to be explicitly passed to this module.
+variable "standard_tags" { type = map }
+variable "account_list" { type = list }
+variable "responsible_accounts" { type = map(list(string)) }
+variable "aws_account_id" { type = string }
+variable "aws_partition" { type = string }
+variable "aws_region" { type = string }
+variable "environment" { type = string }
+variable "key_pairs" { type = map }

+ 3 - 0
base/account_standards_c2/version.tf

@@ -0,0 +1,3 @@
+terraform {
+  required_version = "~> 0.12"
+}

+ 9 - 0
base/account_standards_regional/main.tf

@@ -0,0 +1,9 @@
+resource "aws_config_aggregate_authorization" "authorization" {
+  account_id = local.c2_account
+  region     = var.aws_region
+  tags       = merge(var.standard_tags, var.tags)
+}
+
+output authorizations {
+  value = aws_config_aggregate_authorization.authorization
+}

+ 0 - 0
base/account_standards_regional/outputs.tf


+ 22 - 0
base/account_standards_regional/vars.tf

@@ -0,0 +1,22 @@
+variable "tags" {
+  type = map
+  default = { } 
+}
+
+# ----------------------------------
+# Below this line are variables inherited from higher levels, so they
+# do not need to be explicitly passed to this module.
+variable "standard_tags" { type = map }
+variable "account_list" { type = list }
+variable "aws_account_id" { type = string }
+variable "aws_partition" { type = string }
+variable "aws_region" { type = string }
+variable "environment" { type = string }
+variable "key_pairs" { type = map }
+variable "c2_accounts" { type = map }
+
+locals {
+  logging_environment = var.environment == "common" ? "prod" : var.environment # common logs to prod
+  c2_account = var.c2_accounts[var.aws_partition]
+  is_c2 = var.aws_account_id == local.c2_account ? true : false
+}

+ 3 - 0
base/account_standards_regional/version.tf

@@ -0,0 +1,3 @@
+terraform {
+  required_version = "~> 0.12"
+}

+ 1 - 9
thirdparty/README.md

@@ -6,12 +6,4 @@ This directory contains modules developed by third parties. Please be sure to in
 * The date of the copy
 * Any custom changes
 
-## terraform-aws-panos-bootstrap
-
-Creates the bootstrap S3 bucket and instance profile for a PA
-
-Original URL: https://github.com/PaloAltoNetworks/terraform-aws-panos-bootstrap
-Version: latest master
-Date: 2020-06-29
-
-
+This information should be placed in a file named `SOURCE` within each directory.

+ 13 - 0
thirdparty/terraform-aws-cloudtrail-bucket/.pre-commit-config.yaml

@@ -0,0 +1,13 @@
+---
+repos:
+- repo: git://github.com/antonbabenko/pre-commit-terraform
+  rev: v1.24.0
+  hooks:
+    - id: terraform_fmt
+    - id: terraform_docs
+- repo: https://github.com/pre-commit/pre-commit-hooks
+  rev: v2.4.0
+  hooks:
+    - id: end-of-file-fixer
+    - id: trailing-whitespace
+    - id: no-commit-to-branch

+ 1 - 0
thirdparty/terraform-aws-cloudtrail-bucket/.terraform-version

@@ -0,0 +1 @@
+0.12.20

+ 21 - 0
thirdparty/terraform-aws-cloudtrail-bucket/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Rhythmic Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 39 - 0
thirdparty/terraform-aws-cloudtrail-bucket/README.md

@@ -0,0 +1,39 @@
+# terraform-aws-cloudtrail-bucket
+
+[![](https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket/workflows/check/badge.svg)](https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket/actions)
+
+Create and manage a bucket suitable for encrypted CloudTrail logging. Supports inbound logging from multiple accounts through the `allowed_account_ids` var.
+
+## Usage
+```
+module "cloudtrail-bucket" {
+  source         = "git::https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket"
+  logging_bucket = module.s3logging-bucket.s3logging_bucket_name
+  region         = var.region
+}
+
+```
+
+<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|:----:|:-----:|:-----:|
+| allowed\_account\_ids | Optional list of AWS Account IDs that are permitted to write to the bucket | list(string) | `[]` | no |
+| logging\_bucket | S3 bucket with suitable access for logging requests to the cloudtrail bucket | string | n/a | yes |
+| region | Region to create KMS key in | string | n/a | yes |
+| tags | Mapping of any extra tags you want added to resources | map(string) | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| kms\_key\_id | KMS key used by cloudtrail |
+| s3\_bucket\_arn | The ARN of the bucket |
+| s3\_bucket\_name | The name of the bucket |
+
+<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+
+## Related Projects
+* [CloudTrail Logging module](https://github.com/rhythmictech/terraform-aws-cloudtrail-logging)
+* [S3 Logging Module](https://github.com/rhythmictech/terraform-aws-s3logging-bucket)

+ 6 - 0
thirdparty/terraform-aws-cloudtrail-bucket/SOURCE

@@ -0,0 +1,6 @@
+Our version: https://github.com/fdamstra/terraform-aws-cloudtrail-bucket/tree/dynamic_aws_partition
+Upstream:    https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket
+
+PR to upstream: https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket/pull/5
+
+Last date updated: 2020-07-24

+ 75 - 0
thirdparty/terraform-aws-cloudtrail-bucket/kms.tf

@@ -0,0 +1,75 @@
+data "aws_iam_policy_document" "key" {
+  statement {
+    actions   = ["kms:*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "AWS"
+      identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"]
+    }
+  }
+
+  statement {
+    actions   = ["kms:GenerateDataKey*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    condition {
+      test     = "StringLike"
+      variable = "kms:EncryptionContext:aws:cloudtrail:arn"
+      values   = local.kms_key_encrypt_resources
+    }
+
+    principals {
+      type        = "Service"
+      identifiers = ["cloudtrail.amazonaws.com"]
+    }
+  }
+
+  statement {
+    actions = [
+      "kms:Encrypt*",
+      "kms:Decrypt*",
+      "kms:ReEncrypt*",
+      "kms:GenerateDataKey*",
+      "kms:Describe*",
+    ]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["logs.${var.region}.amazonaws.com"]
+    }
+  }
+
+  statement {
+    actions   = ["kms:Describe*"]
+    effect    = "Allow"
+    resources = ["*"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["cloudtrail.amazonaws.com"]
+    }
+  }
+}
+
+resource "aws_kms_key" "this" {
+  deletion_window_in_days = 7
+  description             = "CloudTrail Encryption Key"
+  enable_key_rotation     = true
+  policy                  = data.aws_iam_policy_document.key.json
+  tags = merge(
+    {
+      "Name" = "cloudtrail-key"
+    },
+    var.tags
+  )
+}
+
+resource "aws_kms_alias" "this" {
+  name          = "alias/cloudtrail_key"
+  target_key_id = aws_kms_key.this.id
+}

+ 123 - 0
thirdparty/terraform-aws-cloudtrail-bucket/main.tf

@@ -0,0 +1,123 @@
+data "aws_caller_identity" "current" {
+}
+
+data "aws_partition" "current" {
+}
+
+locals {
+  account_id = data.aws_caller_identity.current.account_id
+  partition  = data.aws_partition.current.partition
+
+  bucket_name = var.bucket_name == "" ? "${local.account_id}-${var.region}-cloudtrail" : var.bucket_name
+
+  # Account IDs that will have access to stream CloudTrail logs
+  account_ids = concat([local.account_id], var.allowed_account_ids)
+
+  # Format account IDs into necessary resource lists.
+  bucket_policy_put_resources = formatlist("${aws_s3_bucket.this.arn}/AWSLogs/%s/*", local.account_ids)
+  kms_key_encrypt_resources   = formatlist("arn:${local.partition}:cloudtrail:*:%s:trail/*", local.account_ids)
+}
+
+resource "aws_s3_bucket" "this" {
+  bucket = local.bucket_name
+  acl    = "private"
+  tags   = var.tags
+
+  # If we want to PR this upstream, we have to find a way to leave this enabled, but we don't need/want
+  # it since we import into Splunk.
+  #lifecycle_rule {
+  #  enabled = true
+  #
+  #  transition {
+  #    days          = 30
+  #    storage_class = "STANDARD_IA"
+  #  }
+  #
+  #}
+
+  dynamic "lifecycle_rule" {
+    iterator = rule
+    for_each = var.lifecycle_rules
+
+    content {
+      id      = rule.value.id
+      enabled = rule.value.enabled
+      prefix  = lookup(rule.value, "prefix", null)
+      abort_incomplete_multipart_upload_days = lookup(rule.value, "abort_incomplete_multipart_upload_days", 0)
+
+      expiration {
+        days = lookup(rule.value, "expiration", 2147483647)
+      }
+
+      noncurrent_version_expiration {
+        days = lookup(rule.value, "noncurrent_version_expiration", 2147483647)
+      }
+    }
+  }
+
+  logging {
+    target_bucket = var.logging_bucket
+    target_prefix = "${local.account_id}-${var.region}-cloudtrail/"
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm     = "aws:kms"
+        kms_master_key_id = aws_kms_key.this.arn
+      }
+    }
+  }
+
+  versioning {
+    enabled = true
+  }
+
+  lifecycle {
+    prevent_destroy = true
+  }
+
+}
+
+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
+}
+
+data "aws_iam_policy_document" "this" {
+  statement {
+    actions   = ["s3:GetBucketAcl"]
+    effect    = "Allow"
+    resources = [aws_s3_bucket.this.arn]
+
+    principals {
+      type        = "Service"
+      identifiers = ["cloudtrail.amazonaws.com"]
+    }
+  }
+  statement {
+    actions   = ["s3:PutObject"]
+    effect    = "Allow"
+    resources = local.bucket_policy_put_resources
+
+    condition {
+      test     = "StringEquals"
+      variable = "s3:x-amz-acl"
+      values   = ["bucket-owner-full-control"]
+    }
+
+    principals {
+      type        = "Service"
+      identifiers = ["cloudtrail.amazonaws.com"]
+    }
+  }
+
+}
+
+resource "aws_s3_bucket_policy" "this" {
+  bucket = aws_s3_bucket.this.id
+  policy = data.aws_iam_policy_document.this.json
+}

+ 14 - 0
thirdparty/terraform-aws-cloudtrail-bucket/outputs.tf

@@ -0,0 +1,14 @@
+output "s3_bucket_arn" {
+  description = "The ARN of the bucket"
+  value       = aws_s3_bucket.this.arn
+}
+
+output "s3_bucket_name" {
+  description = "The name of the bucket"
+  value       = aws_s3_bucket.this.bucket
+}
+
+output "kms_key_id" {
+  description = "KMS key used by cloudtrail"
+  value       = aws_kms_key.this.arn
+}

+ 41 - 0
thirdparty/terraform-aws-cloudtrail-bucket/variables.tf

@@ -0,0 +1,41 @@
+variable "allowed_account_ids" {
+  default     = []
+  description = "Optional list of AWS Account IDs that are permitted to write to the bucket"
+  type        = list(string)
+}
+
+variable "bucket_name" {
+  default     = "" # can't dynamically build the bucket name here
+  description = "Name of the S3 bucket to create. Defaults to {account_id}-{region}-cloudtrail."
+  type        = string
+}
+
+variable "lifecycle_rules" {
+  default     = []
+  description = "lifecycle rules to apply to the bucket"
+  type = list(object(
+    {
+      id                            = string
+      enabled                       = bool
+      prefix                        = string
+      expiration                    = number
+      noncurrent_version_expiration = number
+      abort_incomplete_multipart_upload_days = number
+  }))
+}
+
+variable "logging_bucket" {
+  description = "S3 bucket with suitable access for logging requests to the cloudtrail bucket"
+  type        = string
+}
+
+variable "region" {
+  description = "Region to create KMS key in"
+  type        = string
+}
+
+variable "tags" {
+  default     = {}
+  description = "Mapping of any extra tags you want added to resources"
+  type        = map(string)
+}

+ 4 - 0
thirdparty/terraform-aws-cloudtrail-bucket/versions.tf

@@ -0,0 +1,4 @@
+
+terraform {
+  required_version = ">= 0.12"
+}

+ 13 - 0
thirdparty/terraform-aws-cloudtrail-logging/.pre-commit-config.yaml

@@ -0,0 +1,13 @@
+---
+repos:
+- repo: git://github.com/antonbabenko/pre-commit-terraform
+  rev: v1.24.0
+  hooks:
+    - id: terraform_fmt
+    - id: terraform_docs
+- repo: https://github.com/pre-commit/pre-commit-hooks
+  rev: v2.4.0
+  hooks:
+    - id: end-of-file-fixer
+    - id: trailing-whitespace
+    - id: no-commit-to-branch

+ 1 - 0
thirdparty/terraform-aws-cloudtrail-logging/.terraform-version

@@ -0,0 +1 @@
+0.12.13

+ 21 - 0
thirdparty/terraform-aws-cloudtrail-logging/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Rhythmic Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 42 - 0
thirdparty/terraform-aws-cloudtrail-logging/README.md

@@ -0,0 +1,42 @@
+# terraform-aws-cloudtrail-logging
+[![](https://github.com/rhythmictech/terraform-aws-cloudtrail-logging/workflows/check/badge.svg)](https://github.com/rhythmictech/terraform-aws-cloudtrail-logging/actions)
+
+Configure CloudTrail logging to CloudWatch Logs and S3. When used with [CloudTrail Bucket module](https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket), this properly configures CloudTrail logging with a KMS CMK as required by CIS.
+
+Logs can easily be centralized to a central security logging account by creating a bucket in a single account and referencing the bucket and KMS key.
+
+## Usage
+```
+
+module "cloudtrail-logging" {
+  source            = "git::https://github.com/rhythmictech/terraform-cloudtrail-logging"
+  region            = var.region
+  cloudtrail_bucket = module.cloudtrail-bucket.bucket_name
+  kms_key_id        = module.cloudtrail-bucket.kms_key_id
+}
+
+```
+
+<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|:----:|:-----:|:-----:|
+| cloudtrail\_bucket | Name of bucket for CloudTrail logs | string | n/a | yes |
+| cloudtrail\_name | Name for the CloudTrail | string | `"cloudtrail-all"` | no |
+| kms\_key\_id | KMS key ARN to use for encrypting CloudTrail logs | string | n/a | yes |
+| log\_group\_name | Name for CloudTrail log group | string | `"cloudtrail2cwl"` | no |
+| region | Region that CloudWatch logging and the S3 bucket will live in | string | n/a | yes |
+| retention\_in\_days | How long should CloudTrail logs be retained in CloudWatch \(does not affect S3 storage\). Set to -1 for indefinite storage. | number | `"7"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| cloudwatch\_loggroup\_arn | The arn of the CloudWatch log group |
+| cloudwatch\_loggroup\_name | The name of the CloudWatch log group |
+
+<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+
+## Related Projects
+* [CloudTrail Bucket module](https://github.com/rhythmictech/terraform-aws-cloudtrail-bucket)

+ 6 - 0
thirdparty/terraform-aws-cloudtrail-logging/SOURCE

@@ -0,0 +1,6 @@
+Our version: https://github.com/fdamstra/terraform-aws-cloudtrail-logging/tree/dynamic_aws_partition
+Upstream:    https://github.com/rhythmictech/terraform-aws-cloudtrail-logging
+
+PR to upstream: https://github.com/rhythmictech/terraform-aws-cloudtrail-logging/pull/4
+
+Last date updated: 2020-07-24

+ 102 - 0
thirdparty/terraform-aws-cloudtrail-logging/main.tf

@@ -0,0 +1,102 @@
+data "aws_caller_identity" "current" {
+}
+
+data "aws_partition" "current" {
+}
+
+locals {
+  account_id = data.aws_caller_identity.current.account_id
+  partition  = data.aws_partition.current.partition
+
+  # Need a list to work with for_each, but don't actually want to for_each
+  log_s3     = length(var.s3_object_level_buckets) > 0 ? [ true ] : [ ]
+  log_lambda = length(var.lambda_functions)        > 0 ? [ true ] : [ ]
+}
+
+resource "aws_cloudtrail" "trail" {
+  cloud_watch_logs_role_arn  = aws_iam_role.cloudtrail_cloudwatch_events_role.arn
+  cloud_watch_logs_group_arn = aws_cloudwatch_log_group.cwl_loggroup.arn
+  enable_log_file_validation = "true"
+  enable_logging             = "true"
+  is_multi_region_trail      = "true"
+  kms_key_id                 = var.kms_key_id
+  name                       = var.cloudtrail_name
+  s3_bucket_name             = var.cloudtrail_bucket
+
+  # S3 object logging:
+  event_selector{
+    read_write_type           = "All"
+    include_management_events = true
+
+    dynamic "data_resource" {
+      for_each = local.log_s3
+      content {
+        type   = "AWS::S3::Object"
+        values = var.s3_object_level_buckets
+      }
+    }
+
+    dynamic "data_resource" {
+      for_each = local.log_lambda
+      content {
+        type   = "AWS::Lambda::Function"
+        values = var.lambda_functions
+      }
+    }
+  }
+}
+
+resource "aws_iam_role" "cloudtrail_cloudwatch_events_role" {
+  name_prefix        = "cloudtrail_events_role"
+  path               = var.iam_path
+  assume_role_policy = data.aws_iam_policy_document.cwl_assume_policy.json
+}
+
+resource "aws_iam_role_policy" "cwl_policy" {
+  name_prefix = "cloudtrail_cloudwatch_events_policy"
+  role        = aws_iam_role.cloudtrail_cloudwatch_events_role.id
+  policy      = data.aws_iam_policy_document.cwl_policy.json
+}
+
+data "aws_iam_policy_document" "cwl_assume_policy" {
+  statement {
+    effect  = "Allow"
+    actions = ["sts:AssumeRole"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["cloudtrail.amazonaws.com"]
+    }
+  }
+}
+
+data "aws_iam_policy_document" "cwl_policy" {
+  statement {
+    effect  = "Allow"
+    actions = ["logs:CreateLogStream"]
+
+    resources = [
+      "arn:${local.partition}:logs:${var.region}:${local.account_id}:log-group:${aws_cloudwatch_log_group.cwl_loggroup.name}:log-stream:*",
+    ]
+  }
+
+  statement {
+    effect  = "Allow"
+    actions = ["logs:PutLogEvents"]
+
+    resources = [
+      "arn:${local.partition}:logs:${var.region}:${local.account_id}:log-group:${aws_cloudwatch_log_group.cwl_loggroup.name}:log-stream:*",
+    ]
+  }
+}
+
+resource "aws_cloudwatch_log_group" "cwl_loggroup" {
+  name              = var.log_group_name
+  kms_key_id        = var.kms_key_id
+  retention_in_days = var.retention_in_days == -1 ? null : var.retention_in_days
+}
+
+resource "aws_cloudwatch_log_stream" "cwl_stream" {
+  name           = local.account_id
+  log_group_name = aws_cloudwatch_log_group.cwl_loggroup.name
+}

+ 9 - 0
thirdparty/terraform-aws-cloudtrail-logging/output.tf

@@ -0,0 +1,9 @@
+output "cloudwatch_loggroup_arn" {
+  description = "The arn of the CloudWatch log group"
+  value       = aws_cloudwatch_log_group.cwl_loggroup.arn
+}
+
+output "cloudwatch_loggroup_name" {
+  description = "The name of the CloudWatch log group"
+  value       = aws_cloudwatch_log_group.cwl_loggroup.name
+}

+ 50 - 0
thirdparty/terraform-aws-cloudtrail-logging/variables.tf

@@ -0,0 +1,50 @@
+variable "cloudtrail_bucket" {
+  description = "Name of bucket for CloudTrail logs"
+  type        = string
+}
+
+variable "cloudtrail_name" {
+  default     = "cloudtrail-all"
+  description = "Name for the CloudTrail"
+  type        = string
+}
+
+variable "iam_path" {
+  default     = "/"
+  description = "Path under which to put the IAM role. Should begin and end with a '/'."
+  type        = string
+}
+
+variable "kms_key_id" {
+  description = "KMS key ARN to use for encrypting CloudTrail logs"
+  type        = string
+}
+
+variable "lambda_functions" {
+  default     = [ ]
+  description = "Lambda functions to log. Specify `[\"arn:aws:lambda\"]` for all, or `[ ]` for none."
+  type        = list
+}
+
+variable "log_group_name" {
+  default     = "cloudtrail2cwl"
+  description = "Name for CloudTrail log group"
+  type        = string
+}
+
+variable "region" {
+  description = "Region that CloudWatch logging and the S3 bucket will live in"
+  type        = string
+}
+
+variable "retention_in_days" {
+  default     = 7
+  description = "How long should CloudTrail logs be retained in CloudWatch (does not affect S3 storage). Set to -1 for indefinite storage."
+  type        = number
+}
+
+variable "s3_object_level_buckets" {
+  default     = [ ]
+  description = "ARNs of buckets for which to enable object level logging. Specify `[\"arn:aws:s3:::\"]` for all, or `[ ]` for none. If listing ARNs, make sure to end each one with a `/`."
+  type        = list
+}

+ 4 - 0
thirdparty/terraform-aws-cloudtrail-logging/versions.tf

@@ -0,0 +1,4 @@
+
+terraform {
+  required_version = ">= 0.12"
+}

+ 9 - 0
thirdparty/terraform-aws-s3logging-bucket/.gitignore

@@ -0,0 +1,9 @@
+#  Local .terraform directories
+**/.terraform/*
+
+# .tfstate files
+*.tfstate
+*.tfstate.*
+
+# .tfvars files
+*.tfvars

+ 71 - 0
thirdparty/terraform-aws-s3logging-bucket/.pre-commit-config.yaml

@@ -0,0 +1,71 @@
+repos:
+  - repo: https://github.com/antonbabenko/pre-commit-terraform
+    rev: v1.31.0
+    hooks:
+      - id: terraform_docs
+        always_run: true
+        args:
+          - --args=--sort-by-required
+      - id: terraform_fmt
+      - id: terraform_tflint
+        alias: terraform_tflint_deep
+        name: terraform_tflint_deep
+        args:
+          - --args=--deep
+      - id: terraform_tflint
+        alias: terraform_tflint_nocreds
+        name: terraform_tflint_nocreds
+      - id: terraform_tfsec
+  - repo: local
+    hooks:
+      - id: terraform_validate
+        name: terraform_validate
+        entry: |
+          bash -c '
+            AWS_DEFAULT_REGION=us-east-1
+            declare -a DIRS
+            for FILE in "$@"
+            do
+              DIRS+=($(dirname "$FILE"))
+            done
+            for DIR in $(printf "%s\n" "${DIRS[@]}" | sort -u)
+            do
+              cd $(dirname "$FILE")
+              terraform init --backend=false
+              terraform validate .
+            done
+          '
+        language: system
+        verbose: true
+        files: \.tf(vars)?$
+        exclude: examples
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v3.0.0
+    hooks:
+      - id: check-case-conflict
+      - id: check-json
+      - id: check-merge-conflict
+      - id: check-symlinks
+      - id: check-yaml
+        args:
+          - --unsafe
+      - id: end-of-file-fixer
+      - id: mixed-line-ending
+        args:
+          - --fix=lf
+      - id: no-commit-to-branch
+        args:
+          - --branch
+          - main
+          - --branch
+          - master
+          - --branch
+          - prod
+      - id: pretty-format-json
+        args:
+          - --autofix
+          - --top-keys=name,Name
+      - id: trailing-whitespace
+        args:
+          - --markdown-linebreak-ext=md
+        exclude: README.md

+ 45 - 0
thirdparty/terraform-aws-s3logging-bucket/.tflint.hcl

@@ -0,0 +1,45 @@
+config {
+  module     = true
+  deep_check = false
+}
+
+rule "terraform_deprecated_interpolation" {
+  enabled = true
+}
+
+rule "terraform_unused_declarations" {
+  enabled = true
+}
+
+rule "terraform_comment_syntax" {
+  enabled = true
+}
+
+rule "terraform_documented_outputs" {
+  enabled = true
+}
+
+rule "terraform_documented_variables" {
+  enabled = true
+}
+
+rule "terraform_typed_variables" {
+  enabled = true
+}
+
+rule "terraform_module_pinned_source" {
+  enabled = true
+}
+
+rule "terraform_naming_convention" {
+  enabled = true
+  format  = "snake_case"
+}
+
+rule "terraform_required_version" {
+  enabled = true
+}
+
+rule "terraform_required_providers" {
+  enabled = true
+}

+ 2 - 0
thirdparty/terraform-aws-s3logging-bucket/.yamllint.yml

@@ -0,0 +1,2 @@
+truthy:
+  check-keys: false

+ 21 - 0
thirdparty/terraform-aws-s3logging-bucket/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Rhythmic Technologies, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 56 - 0
thirdparty/terraform-aws-s3logging-bucket/README.md

@@ -0,0 +1,56 @@
+# terraform-aws-s3logging-bucket
+[![](https://github.com/rhythmictech/terraform-aws-s3logging-bucket/workflows/check/badge.svg)](https://github.com/rhythmictech/terraform-aws-s3logging-bucket/actions)
+
+Create and manage a bucket suitable for access logging for other S3 buckets.
+
+Note that due to the way S3 pricing works on IA and Glacier tiers, this module does not support automatic transition policies in the lifecycle rules. It is always cheaper to store ELB access logs in the standard tier.
+
+## Usage
+```
+module "s3logging-bucket" {
+  source        = "rhythmictech/s3logging-bucket/aws"
+}
+```
+
+<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+## Requirements
+
+| Name | Version |
+|------|---------|
+| terraform | >= 0.12.19 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| aws | n/a |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| bucket\_name | Name to apply to bucket (use `bucket_name` or `bucket_suffix`) | `string` | `null` | no |
+| bucket\_suffix | Suffix to apply to the bucket (use `bucket_name` or `bucket_suffix`). When using `bucket_suffix`, the bucket name will be `[account_id]-[region]-s3logging-[bucket_suffix].` | `string` | `"default"` | no |
+| lifecycle\_rules | lifecycle rules to apply to the bucket | <pre>list(object(<br>    {<br>      id                            = string<br>      enabled                       = bool<br>      prefix                        = string<br>      expiration                    = number<br>      noncurrent_version_expiration = number<br>  }))</pre> | `[]` | no |
+| tags | Tags to add to supported resources | `map(string)` | `{}` | no |
+| versioning\_enabled | Whether or not to use versioning on the bucket. This can be useful for audit purposes since objects in a logging bucket should not be updated. | `bool` | `true` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| s3\_bucket\_arn | The ARN of the bucket |
+| s3\_bucket\_domain\_name | The domain name of the bucket |
+| s3\_bucket\_name | The name of the bucket |
+
+<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+
+## History
+Between versions 1.x and 2.x, there were breaking changes. In particular, resource names were changed to follow a `this` convention. The following commands (with some customization for naming) will automatically migrate existing states:
+
+```
+terraform state mv module.s3logging-bucket.aws_s3_bucket.s3logging_bucket module.s3logging-bucket.aws_s3_bucket.this
+terraform state mv module.s3logging-bucket.aws_s3_bucket_public_access_block.block_public_access module.s3logging-bucket.aws_s3_bucket_public_access_block.this
+```
+
+The `region` var was also been removed.

+ 4 - 0
thirdparty/terraform-aws-s3logging-bucket/SOURCE

@@ -0,0 +1,4 @@
+Our version: No changes made
+Upstream:    https://github.com/rhythmictech/terraform-aws-s3logging-bucket.git
+
+Last date updated: 2020-07-24

+ 18 - 0
thirdparty/terraform-aws-s3logging-bucket/bin/install-macos.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+
+echo 'installing brew packages'
+brew update
+brew tap liamg/tfsec
+brew install tfenv tflint terraform-docs pre-commit liamg/tfsec/tfsec coreutils
+brew upgrade tfenv tflint terraform-docs pre-commit liamg/tfsec/tfsec coreutils
+
+echo 'installing pre-commit hooks'
+pre-commit install
+
+echo 'setting pre-commit hooks to auto-install on clone in the future'
+git config --global init.templateDir ~/.git-template
+pre-commit init-templatedir ~/.git-template
+
+echo 'installing terraform with tfenv'
+tfenv install min-required
+tfenv use min-required

+ 23 - 0
thirdparty/terraform-aws-s3logging-bucket/bin/install-ubuntu.sh

@@ -0,0 +1,23 @@
+#!/bin/bash
+
+echo 'installing dependencies'
+sudo apt install python3-pip gawk &&\
+pip3 install pre-commit
+curl -L "$(curl -sL https://api.github.com/repos/segmentio/terraform-docs/releases/latest | grep -o -E "https://.+?-linux-amd64")" > terraform-docs && chmod +x terraform-docs && sudo mv terraform-docs /usr/bin/
+curl -L "$(curl -sL https://api.github.com/repos/terraform-linters/tflint/releases/latest | grep -o -E "https://.+?_linux_amd64.zip")" > tflint.zip && unzip tflint.zip && rm tflint.zip && sudo mv tflint /usr/bin/
+env GO111MODULE=on go get -u github.com/liamg/tfsec/cmd/tfsec
+git clone https://github.com/tfutils/tfenv.git ~/.tfenv || true
+mkdir -p ~/.local/bin/
+. ~/.profile
+ln -s ~/.tfenv/bin/* ~/.local/bin
+
+echo 'installing pre-commit hooks'
+pre-commit install
+
+echo 'setting pre-commit hooks to auto-install on clone in the future'
+git config --global init.templateDir ~/.git-template
+pre-commit init-templatedir ~/.git-template
+
+echo 'installing terraform with tfenv'
+tfenv install min-required
+tfenv use min-required

+ 2 - 0
thirdparty/terraform-aws-s3logging-bucket/examples/basic/README.md

@@ -0,0 +1,2 @@
+# basic example
+Create a simple S3 logging bucket intended for account-wide logging buckets like CloudTrail, VPC Flow Logs, etc.

+ 19 - 0
thirdparty/terraform-aws-s3logging-bucket/examples/basic/main.tf

@@ -0,0 +1,19 @@
+module "s3logging-bucket" {
+  source = "../.."
+
+  bucket_suffix = "system"
+
+  # store logs for 1 year
+  lifecycle_rules = [{
+    id                            = "expire"
+    enabled                       = true
+    prefix                        = null
+    expiration                    = 365
+    noncurrent_version_expiration = 365
+  }]
+
+  tags = {
+    terraform_managed = true
+    owner             = "IT Operations"
+  }
+}

+ 2 - 0
thirdparty/terraform-aws-s3logging-bucket/examples/multiple-prefixes/README.md

@@ -0,0 +1,2 @@
+# multiple-prefixes example
+Demonstrates how to set different retention policies based on the type of access log.

+ 40 - 0
thirdparty/terraform-aws-s3logging-bucket/examples/multiple-prefixes/main.tf

@@ -0,0 +1,40 @@
+module "s3logging-bucket" {
+  source = "../.."
+
+  bucket_suffix = "system"
+
+  lifecycle_rules = [{
+    id      = "cloudtrail-expire"
+    enabled = true
+    prefix  = "1111111111111-us-east-1-cloudtrail"
+
+    # keep all cloudtrail logs for 5 years
+    expiration                    = 1825
+    noncurrent_version_expiration = 1825
+    },
+
+    {
+      id      = "vpcflowlog-expire"
+      enabled = true
+      prefix  = "1111111111111-us-east-1-vpcflowlog"
+
+      # keep flow logs for 90 days
+      expiration                    = 90
+      noncurrent_version_expiration = 90
+    },
+
+    {
+      id      = "tfstate-expire"
+      enabled = true
+      prefix  = "tfstate-s3-logs"
+
+      # keep logs for tfstate access for 5 years
+      expiration                    = 1825
+      noncurrent_version_expiration = 1825
+  }]
+
+  tags = {
+    terraform_managed = true
+    owner             = "IT Operations"
+  }
+}

+ 67 - 0
thirdparty/terraform-aws-s3logging-bucket/main.tf

@@ -0,0 +1,67 @@
+data "aws_caller_identity" "current" {
+}
+
+data "aws_region" "current" {
+}
+
+locals {
+  account_id = data.aws_caller_identity.current.account_id
+  bucket_name = coalesce(
+    var.bucket_name,
+    "${local.account_id}-${local.region}-s3logging-${var.bucket_suffix}"
+  )
+
+  region = data.aws_region.current.name
+}
+
+# Ignore logging requirement - access logging for a logging bucket is a little meta
+#tfsec:ignore:AWS002
+resource "aws_s3_bucket" "this" {
+  bucket = local.bucket_name
+  acl    = "log-delivery-write"
+  tags   = var.tags
+
+  dynamic "lifecycle_rule" {
+    iterator = rule
+    for_each = var.lifecycle_rules
+
+    content {
+      id      = rule.value.id
+      enabled = rule.value.enabled
+      prefix  = lookup(rule.value, "prefix", null)
+      abort_incomplete_multipart_upload_days = lookup(rule.value, "abort_incomplete_multipart_upload_days", 0)
+
+      expiration {
+        days = lookup(rule.value, "expiration", 2147483647)
+      }
+
+      noncurrent_version_expiration {
+        days = lookup(rule.value, "noncurrent_version_expiration", 2147483647)
+      }
+    }
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm = "aws:kms"
+      }
+    }
+  }
+
+  versioning {
+    enabled = var.versioning_enabled
+  }
+
+  lifecycle {
+    ignore_changes = [versioning[0].mfa_delete]
+  }
+}
+
+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
+}

+ 14 - 0
thirdparty/terraform-aws-s3logging-bucket/outputs.tf

@@ -0,0 +1,14 @@
+output "s3_bucket_arn" {
+  description = "The ARN of the bucket"
+  value       = aws_s3_bucket.this.arn
+}
+
+output "s3_bucket_domain_name" {
+  description = "The domain name of the bucket"
+  value       = aws_s3_bucket.this.bucket_domain_name
+}
+
+output "s3_bucket_name" {
+  description = "The name of the bucket"
+  value       = aws_s3_bucket.this.bucket
+}

+ 37 - 0
thirdparty/terraform-aws-s3logging-bucket/variables.tf

@@ -0,0 +1,37 @@
+variable "bucket_name" {
+  default     = null
+  description = "Name to apply to bucket (use `bucket_name` or `bucket_suffix`)"
+  type        = string
+}
+
+variable "bucket_suffix" {
+  default     = "default"
+  description = "Suffix to apply to the bucket (use `bucket_name` or `bucket_suffix`). When using `bucket_suffix`, the bucket name will be `[account_id]-[region]-s3logging-[bucket_suffix]."
+  type        = string
+}
+
+variable "lifecycle_rules" {
+  default     = []
+  description = "lifecycle rules to apply to the bucket"
+  type = list(object(
+    {
+      id                            = string
+      enabled                       = bool
+      prefix                        = string
+      expiration                    = number
+      noncurrent_version_expiration = number
+      abort_incomplete_multipart_upload_days = number
+  }))
+}
+
+variable "tags" {
+  default     = {}
+  description = "Tags to add to supported resources"
+  type        = map(string)
+}
+
+variable "versioning_enabled" {
+  default     = true
+  description = "Whether or not to use versioning on the bucket. This can be useful for audit purposes since objects in a logging bucket should not be updated."
+  type        = bool
+}

+ 3 - 0
thirdparty/terraform-aws-s3logging-bucket/versions.tf

@@ -0,0 +1,3 @@
+terraform {
+  required_version = ">= 0.12.19"
+}