diff --git a/README.md b/README.md index 57c5ef2..5f7bada 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,109 @@ - Supports two main uses cases: * Creates and configures a single private S3 bucket for storing logs from various AWS services, which are nested as bucket prefixes. Logs will expire after a default of 90 days, with option to configure retention value. * Creates and configures a single private S3 bucket for a single AWS service. Logs will expire after a default of 90 days, with option to configure retention value. -Logging from the following services is supported for both cases: +Logging from the following services is supported for both cases as well as in AWS GovCloud: +* [Application Load Balancer(ALB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/application) +* [Classic Elastic Load Balancer(ELB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic) +* [Network Load Balancer(NLB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/network) * [CloudTrail](https://aws.amazon.com/cloudtrail/) * [Config](https://aws.amazon.com/config/) -* [Classic Load Balancer (ELB) and Application Load Balancer (ALB)](https://aws.amazon.com/elasticloadbalancing/) * [RedShift](https://aws.amazon.com/redshift/) * [S3](https://aws.amazon.com/s3/) ## Terraform Versions -Terraform 0.12. Pin module version to ~> 5.1.0. Submit pull-requests to master branch. +Terraform 0.12. Pin module version to ~> 5.1.0 . Submit pull-requests to master branch. -Terraform 0.11. Pin module version to ~> 3.5.0. Submit pull-requests to terraform011 branch. +Terraform 0.11. Pin module version to ~> 3.5.0 . Submit pull-requests to terraform011 branch. ## Usage for a single log bucket storing logs from all services - # Allows all services to log to bucket - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs" - region = "us-west-2" - } - -## Usage for a single log bucket storing logs from a single service - - # Allows only the service specified (elb in this case) to log to the bucket - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs-elb" - region = "us-west-2" - default\_allow = false - allow\_elb = true - } - -## Usage for a single log bucket storing logs from multiple specified services - - # Allows only the services specified (alb and elb in this case) to log to the bucket - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs-elb" - region = "us-west-2" - default\_allow = false - allow\_alb = true - allow\_elb = true - } +```hcl +# Allows all services to log to bucket +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs" + region = "us-west-2" +} +``` + +## Usage for a single log bucket storing logs from a single service (ELB in this case) + +```hcl +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs-elb" + region = "us-west-2" + default_allow = false + allow_elb = true +} +``` + +## Usage for a single log bucket storing logs from multiple specified services (ALB and ELB in this case) + +```hcl +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs-lb" + region = "us-west-2" + default_allow = false + allow_alb = true + allow_elb = true +} +``` ## Usage for a private bucket with no policies - # Allows no services to log to the bucket - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs-elb" - s3\_bucket\_acl = "private" - region = "us-west-2" - default\_allow = false - } - -## Usage for a single log bucket storing logs from multiple accounts - - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs-elb" - region = "us-west-2" - default\_allow = false - allow\_cloudtrail = true - cloudtrail\_accounts = ["${data.aws\_caller\_identity.current.account\_id}", "${aws\_organizations\_account.example.id}"] - } - -## Usage for a single log bucket storing logs from multiple application load balancers and network load balancers - - module "aws\_logs" { - source = "trussworks/logs/aws" - s3\_bucket\_name = "my-company-aws-logs-alb" +```hcl +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs" + s3_bucket_acl = "private" + region = "us-west-2" + default_allow = false +} +``` + +## Usage for a single log bucket storing CloudTrail logs from multiple accounts + +```hcl +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs-cloudtrail" + region = "us-west-2" + default_allow = false + allow_cloudtrail = true + cloudtrail_accounts = [data.aws_caller_identity.current.account_id, aws_organizations_account.example.id] +} +``` + +## Usage for a single log bucket storing logs from multiple application load balancers (ALB) and network load balancers (NLB) + +```hcl +module "aws_logs" { + source = "trussworks/logs/aws" + s3_bucket_name = "my-company-aws-logs-lb" region = "us-west-2" - default\_allow = false - allow\_alb = true - allow\_nlb = true - alb\_logs\_prefixes = formatlist(format("alb/%%s/AWSLogs/%s", data.aws\_caller\_identity.current.account\_id), [ + default_allow = false + allow_alb = true + allow_nlb = true + alb_logs_prefixes = formatlist(format("alb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ "alb-hello-world-prod", "alb-hello-world-staging", "alb-hello-world-experimental", ]) - nlb\_logs\_prefixes = formatlist(format("nlb/%%s/AWSLogs/%s", data.aws\_caller\_identity.current.account\_id), [ + nlb_logs_prefixes = formatlist(format("nlb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ "nlb-hello-world-prod", "nlb-hello-world-staging", "nlb-hello-world-experimental", ]) } +``` + ## Providers | Name | Version | @@ -148,11 +159,13 @@ Version 5.1.0 removed the `nlb_logs_prefix` and `nlb_accounts` variables and now Use the `format` and `formatlist` functions in the caller module to support more complex logging that does limit by account id. For example: +```hcl nlb_logs_prefixes = formatlist(format("nlb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ "hello-world-prod", "hello-world-staging", "hello-world-experimental", ]) +``` ### Upgrading from 4.0.0 to 4.1.x @@ -171,11 +184,13 @@ Version 3.5.0 removed the `alb_logs_prefix` and `alb_accounts` variables and now Use the `format` and `formatlist` functions in the caller module to support more complex logging that does limit by account id. For example: +```hcl alb_logs_prefixes = formatlist(format("alb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ "hello-world-prod", "hello-world-staging", "hello-world-experimental", ]) +``` ### Upgrading from 2.1.X to 3.X.X @@ -197,7 +212,9 @@ The new module explicitly adds all resource policies as `Deny` and leaves it up Install dependencies (macOS) - brew install pre-commit go terraform terraform-docs +```shell +brew install pre-commit go terraform terraform-docs +``` ### Testing @@ -205,8 +222,12 @@ Install dependencies (macOS) automated testing with this module. Tests in the `test` folder can be run locally by running the following command: - make test +```shell +make test +``` Or with aws-vault: - AWS_VAULT_KEYCHAIN_NAME=YOUR-KEYCHAIN-NAME aws-vault exec YOUR-AWS-PROFILE -- make test +```shell +AWS_VAULT_KEYCHAIN_NAME=login aws-vault exec YOUR-AWS-PROFILE -- make test +``` diff --git a/go.sum b/go.sum index a4166e0..682751b 100644 --- a/go.sum +++ b/go.sum @@ -174,8 +174,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gruntwork-io/gruntwork-cli v0.5.1/go.mod h1:IBX21bESC1/LGoV7jhXKUnTQTZgQ6dYRsoj/VqxUSZQ= -github.com/gruntwork-io/terratest v0.23.4 h1:3H8/gS4XJvy3AwPyvil3yMMeiBB6FrGP9IvJI6e2uis= -github.com/gruntwork-io/terratest v0.23.4/go.mod h1:ds4v1EDndcBq3zNUPs1uot0YGWDbk++I5KPSOSJ6df4= github.com/gruntwork-io/terratest v0.24.2 h1:ZL7s7ZaVPRds+HqtPFh8gXjFVpKRNAAbwyVPYx3lH50= github.com/gruntwork-io/terratest v0.24.2/go.mod h1:0MCPUGIgQaAXOmw0qRLqyIXs8q6yoNPB3aZt4SkdH0M= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= diff --git a/main.tf b/main.tf index bc2dd3b..ffb431d 100644 --- a/main.tf +++ b/main.tf @@ -1,99 +1,3 @@ -/** - * Supports two main uses cases: - * - * * Creates and configures a single private S3 bucket for storing logs from various AWS services, which are nested as bucket prefixes. Logs will expire after a default of 90 days, with option to configure retention value. - * * Creates and configures a single private S3 bucket for a single AWS service. Logs will expire after a default of 90 days, with option to configure retention value. - * - * Logging from the following services is supported for both cases: - * - * * [CloudTrail](https://aws.amazon.com/cloudtrail/) - * * [Config](https://aws.amazon.com/config/) - * * [Classic Load Balancer (ELB) and Application Load Balancer (ALB)](https://aws.amazon.com/elasticloadbalancing/) - * * [RedShift](https://aws.amazon.com/redshift/) - * * [S3](https://aws.amazon.com/s3/) - * - * ## Terraform Versions - * - * Terraform 0.12. Pin module version to ~> 5.1.0. Submit pull-requests to master branch. - * - * Terraform 0.11. Pin module version to ~> 3.5.0. Submit pull-requests to terraform011 branch. - * - * ## Usage for a single log bucket storing logs from all services - * - * # Allows all services to log to bucket - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs" - * region = "us-west-2" - * } - * - * ## Usage for a single log bucket storing logs from a single service - * - * # Allows only the service specified (elb in this case) to log to the bucket - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs-elb" - * region = "us-west-2" - * default_allow = false - * allow_elb = true - * } - * - * ## Usage for a single log bucket storing logs from multiple specified services - * - * # Allows only the services specified (alb and elb in this case) to log to the bucket - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs-elb" - * region = "us-west-2" - * default_allow = false - * allow_alb = true - * allow_elb = true - * } - * - * ## Usage for a private bucket with no policies - * - * # Allows no services to log to the bucket - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs-elb" - * s3_bucket_acl = "private" - * region = "us-west-2" - * default_allow = false - * } - * - * ## Usage for a single log bucket storing logs from multiple accounts - * - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs-elb" - * region = "us-west-2" - * default_allow = false - * allow_cloudtrail = true - * cloudtrail_accounts = ["${data.aws_caller_identity.current.account_id}", "${aws_organizations_account.example.id}"] - * } - * - * ## Usage for a single log bucket storing logs from multiple application load balancers and network load balancers - * - * module "aws_logs" { - * source = "trussworks/logs/aws" - * s3_bucket_name = "my-company-aws-logs-alb" - * region = "us-west-2" - * default_allow = false - * allow_alb = true - * allow_nlb = true - * alb_logs_prefixes = formatlist(format("alb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ - * "alb-hello-world-prod", - * "alb-hello-world-staging", - * "alb-hello-world-experimental", - * ]) - * nlb_logs_prefixes = formatlist(format("nlb/%%s/AWSLogs/%s", data.aws_caller_identity.current.account_id), [ - * "nlb-hello-world-prod", - * "nlb-hello-world-staging", - * "nlb-hello-world-experimental", - * ]) - * } - */ - # Get the account id of the AWS ELB service account in a given region for the # purpose of whitelisting in a S3 bucket policy. data "aws_elb_service_account" "main" { @@ -112,6 +16,10 @@ data "aws_region" "current" { data "aws_caller_identity" "current" { } +# The AWS partition for differentiating between AWS commercial and GovCloud +data "aws_partition" "current" { +} + # # S3 Bucket # @@ -256,19 +164,19 @@ JSON vars = { region = var.region - bucket_arn = format("arn:aws:s3:::%s", var.s3_bucket_name) + bucket_arn = format("arn:${data.aws_partition.current.partition}:s3:::%s", var.s3_bucket_name) alb_principal = data.aws_elb_service_account.main.arn alb_effect = var.default_allow || var.allow_alb ? "Allow" : "Deny" alb_resources = jsonencode( formatlist( - format("arn:aws:s3:::%s/%%s/*", var.s3_bucket_name), + format("arn:${data.aws_partition.current.partition}:s3:::%s/%%s/*", var.s3_bucket_name), var.alb_logs_prefixes, ), ) cloudwatch_effect = var.default_allow || var.allow_cloudwatch ? "Allow" : "Deny" cloudwatch_resources = jsonencode( format( - "arn:aws:s3:::%s/%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/*", var.s3_bucket_name, var.cloudwatch_logs_prefix, ), @@ -278,7 +186,7 @@ JSON sort( formatlist( format( - "arn:aws:s3:::%s/%s/AWSLogs/%%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%%s/*", var.s3_bucket_name, var.cloudtrail_logs_prefix, ), @@ -287,7 +195,7 @@ JSON ), ) : jsonencode( format( - "arn:aws:s3:::%s/%s/AWSLogs/%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%s/*", var.s3_bucket_name, var.cloudtrail_logs_prefix, data.aws_caller_identity.current.account_id, @@ -298,7 +206,7 @@ JSON sort( formatlist( format( - "arn:aws:s3:::%s/%s/AWSLogs/%%s/Config/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%%s/Config/*", var.s3_bucket_name, var.config_logs_prefix, ), @@ -307,7 +215,7 @@ JSON ), ) : jsonencode( format( - "arn:aws:s3:::%s/%s/AWSLogs/%s/Config/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%s/Config/*", var.s3_bucket_name, var.config_logs_prefix, data.aws_caller_identity.current.account_id, @@ -319,7 +227,7 @@ JSON sort( formatlist( format( - "arn:aws:s3:::%s/%s/AWSLogs/%%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%%s/*", var.s3_bucket_name, var.elb_logs_prefix, ), @@ -328,7 +236,7 @@ JSON ), ) : jsonencode( format( - "arn:aws:s3:::%s/%s/AWSLogs/%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/AWSLogs/%s/*", var.s3_bucket_name, var.elb_logs_prefix, data.aws_caller_identity.current.account_id, @@ -337,18 +245,18 @@ JSON nlb_effect = var.default_allow || var.allow_nlb ? "Allow" : "Deny" nlb_resources = jsonencode( formatlist( - format("arn:aws:s3:::%s/%%s/*", var.s3_bucket_name), + format("arn:${data.aws_partition.current.partition}:s3:::%s/%%s/*", var.s3_bucket_name), var.nlb_logs_prefixes, ), ) redshift_effect = var.default_allow || var.allow_redshift ? "Allow" : "Deny" redshift_principal = format( - "arn:aws:iam::%s:user/logs", + "arn:${data.aws_partition.current.partition}:iam::%s:user/logs", data.aws_redshift_service_account.main.id, ) redshift_resources = jsonencode( format( - "arn:aws:s3:::%s/%s/*", + "arn:${data.aws_partition.current.partition}:s3:::%s/%s/*", var.s3_bucket_name, var.redshift_logs_prefix, ),