diff --git a/CHANGELOG.md b/CHANGELOG.md index 52633fa..507b9a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,6 @@ * v1.1 -- 20210223 - add iam policy to terraform-state + +* v1.2 -- 20210223 + - module: access-logging diff --git a/README.md b/README.md index dc81bdb..9e235c9 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ This has no other dependencies, since it has to be created first. Only one is n ### splunk-user -### access-logging-bucket +### [access-logging](access-logging) This sets up the S3 bucket used for access logs. One is needed per region, and the region and account are included -in the bucket names: `inf-log-{account_id}-{region}`. +in the bucket names: `inf-logs-{account_id}-{region}`. ### object-logging ### cloudtrail diff --git a/access-logging/README.md b/access-logging/README.md new file mode 100644 index 0000000..11f4239 --- /dev/null +++ b/access-logging/README.md @@ -0,0 +1,84 @@ +# aws-inf-setup :: access-logging + +This set up the needed components for S3 access log bucket. An access log must exist in each region +where there are components wishing to use access logs (S3, ALB, etc.). + +* S3 bucket +* S3 bucket objects (key prefixes, aka "directories") +* S3 bucket policy + +# Usage +Here is a simple example, the one most commonly expected to be used. + +```hcl +module "logs" { + source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//access-logging" +} +``` + +This one can be used if you need to customize stuff, though really, the defaults are all built +for a reason, and deployment code (i.e., Ansible) will expect these defaults to be used in +variable file generation. + +```hcl +module "logs_full" { + source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//terraform-state" + + # optional + account_alias = "do2-govcloud" + bucket_name = "inf-logs-123456789012" + + # logs is generally not needed and not recommended + component_tags = { + "s3" = { + "SpecialTag1" = "something" + "SpecialTag2" = "somethingElse" + } + } +} +``` + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| aws | n/a | + +## Modules + +No Modules. + +## Resources + +| Name | +|------| +| [aws_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/arn) | +| [aws_caller_identity](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | +| [aws_iam_policy_document](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | +| [aws_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | +| [aws_s3_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | +| [aws_s3_bucket_object](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object) | +| [aws_s3_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | +| [aws_s3_bucket_public_access_block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| account\_alias | AWS Account Alias (required) | `string` | `""` | no | +| account\_id | AWS Account ID (default will pull from current user) | `string` | `""` | no | +| bucket\_name | Logging S3 bucket name | `string` | `""` | no | +| bucket\_name\_prefix | Logging S3 bucket prefix, prepended to the AWS account ID and region to make the bucket name. | `string` | `"inf-logs"` | no | +| component\_tags | Additional tags for Components (s3, kms, ddb) | `map(map(string))` |
{
"ddb": {},
"kms": {},
"s3": {}
} | no |
+| override\_prefixes | Override built-in prefixes by component (efs, s3, ebs, kms, role, policy, security-group). This should be used primarily for common infrastructure things | `map(string)` | `{}` | no |
+| tags | AWS Tags to apply to appropriate resources (S3, KMS). Do not include safeguard tags here, use the data\_safeguard field for such things. | `map(string)` | `{}` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| logs\_bucket\_arn | Logging S3 bucket ARN |
diff --git a/access-logging/data.tf b/access-logging/data.tf
new file mode 120000
index 0000000..995624d
--- /dev/null
+++ b/access-logging/data.tf
@@ -0,0 +1 @@
+../common/data.tf
\ No newline at end of file
diff --git a/access-logging/defaults.tf b/access-logging/defaults.tf
new file mode 120000
index 0000000..a5556ac
--- /dev/null
+++ b/access-logging/defaults.tf
@@ -0,0 +1 @@
+../common/defaults.tf
\ No newline at end of file
diff --git a/access-logging/main.tf b/access-logging/main.tf
new file mode 100644
index 0000000..81f8584
--- /dev/null
+++ b/access-logging/main.tf
@@ -0,0 +1,123 @@
+/*
+* # aws-inf-setup :: access-logging
+*
+* This set up the needed components for S3 access log bucket. An access log must exist in each region
+* where there are components wishing to use access logs (S3, ALB, etc.).
+*
+* * S3 bucket
+* * S3 bucket objects (key prefixes, aka "directories")
+* * S3 bucket policy
+*
+* # Usage
+* Here is a simple example, the one most commonly expected to be used.
+*
+* ```hcl
+* module "logs" {
+* source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//access-logging"
+* }
+* ```
+*
+* This one can be used if you need to customize stuff, though really, the defaults are all built
+* for a reason, and deployment code (i.e., Ansible) will expect these defaults to be used in
+* variable file generation.
+*
+* ```hcl
+* module "logs_full" {
+* source = "git@github.e.it.census.gov:terraform-modules/aws-inf-setup.git//terraform-state"
+*
+* # optional
+* account_alias = "do2-govcloud"
+* bucket_name = "inf-logs-123456789012"
+*
+* # logs is generally not needed and not recommended
+* component_tags = {
+* "s3" = {
+* "SpecialTag1" = "something"
+* "SpecialTag2" = "somethingElse"
+* }
+* }
+* }
+* ```
+*/
+
+locals {
+ account_id = var.account_id != "" ? var.account_id : data.aws_caller_identity.current.account_id
+ logs_region = data.aws_region.current.name
+ account_environment = data.aws_arn.current.partiion == "aws-us-gov" ? "gov" : "ew"
+ logs_alb_accounts = lookup(local._defaults["load-balancer"], local.account_environment, [local.account_id])
+ logs_alb_account = lookup(local._defaults["load-balancer"], local.logs_region, local.account_id)
+
+ bucket_name = var.bucket_name != "" ? var.bucket_name : format("%v-%v-%v", var.bucket_name_prefix, local.account_id, local.logs_region)
+ logs_policy_name = format("%v%v", lookup(local._prefixes, "policy", ""), var.bucket_name_prefix)
+ logs_folders = ["s3", "elasticmapreduce", "alb-logs", "nlb-logs", "inventory"]
+
+ base_tags = {
+ "Organization" = "census:aditcio:csvd"
+ "boc:tf_module_version" = local._module_version
+ "boc:created_by" = "terraform"
+ }
+}
+
+
+#---
+# s3
+#---
+resource "aws_s3_bucket" "logs" {
+ bucket = local.bucket_name
+ acl = "log-delivery-write"
+
+ # uses aws/kms key so log delivery works properly
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "aws:kms"
+ }
+ }
+ }
+
+ versioning {
+ enabled = false
+ }
+
+ lifecycle {
+ prevent_destroy = true
+ }
+
+ # probably want some migration of old data to some other location
+ # like glacier
+
+ tags = merge(
+ var.tags,
+ local.base_tags,
+ lookup(var.component_tags, "s3", {}),
+ map("Name", local.bucket_name),
+ )
+
+ provisioner "local-exec" {
+ command = "sleep 30"
+ }
+}
+
+resource "aws_s3_bucket_public_access_block" "logs" {
+ bucket = aws_s3_bucket.logs.id
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
+
+#---
+# create "directories"
+#---
+resource "aws_s3_bucket_object" "logs" {
+ for_each = toset(local.logs_folders)
+ bucket = aws_s3_bucket.logs.id
+ key = format("%v/", each.key)
+ source = "/dev/null"
+}
+
+resource "aws_s3_bucket_policy" "logs" {
+ bucket = aws_s3_bucket.logs.id
+ policy = data.aws_iam_policy_document.logs_s3.json
+}
+
diff --git a/access-logging/outputs.tf b/access-logging/outputs.tf
new file mode 100644
index 0000000..7661e2f
--- /dev/null
+++ b/access-logging/outputs.tf
@@ -0,0 +1,9 @@
+output "logs_bucket_id" {
+ description = "Logging S3 bucket ID"
+ value = aws_s3_bucket.logs.id
+}
+
+output "logs_bucket_arn" {
+ description = "Logging S3 bucket ARN"
+ value = aws_s3_bucket.logs.arn
+}
diff --git a/access-logging/policy_data.tf b/access-logging/policy_data.tf
new file mode 100644
index 0000000..93f4466
--- /dev/null
+++ b/access-logging/policy_data.tf
@@ -0,0 +1,50 @@
+data "aws_iam_policy_document" "logs_s3" {
+ statement {
+ sid = "AWSLogWrite"
+ effect = "Allow"
+ actions = ["s3:PutObject"]
+ resources = ["${aws_s3_bucket.logs.arn}/*"]
+ principals {
+ type = "AWS"
+ identifiers = [format("arn:%v:iam::%v:root", data.aws_arn.current.partition, local.account_id)]
+ }
+ }
+ statement {
+ sid = "AWSLogDeliveryWrite"
+ effect = "Allow"
+ actions = ["s3:PutObject"]
+ resources = ["${aws_s3_bucket.logs.arn}/*"]
+ principals {
+ type = "Service"
+ identifiers = ["delivery.logs.amazonaws.com"]
+ }
+ condition {
+ test = "StringEquals"
+ variable = "s3:x-amz-acl"
+ values = ["bucket-owner-full-control"]
+ }
+ }
+ statement {
+ sid = "AWSLogDeliveryAclCheck"
+ effect = "Allow"
+ actions = ["s3:GetBucketAcl"]
+ resources = [aws_s3_bucket.logs.arn]
+ principals {
+ type = "Service"
+ identifiers = ["delivery.logs.amazonaws.com"]
+ }
+ }
+
+ # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-logging-bucket-permissions
+ statement {
+ sid = "AWSALBAccessLog"
+ effect = "Allow"
+ actions = ["s3:PutObject"]
+ resources = ["${aws_s3_bucket.logs.arn}/alb-logs/*"]
+ principals {
+ type = "AWS"
+ # identifiers = [ formatlist("arn:%v:iam::%v:root",data.aws_arn.current.partition,local.logs_alb_accounts) ]
+ identifiers = [format("arn:%v:iam::%v:root", data.aws_arn.current.partition, local.logs_alb_account)]
+ }
+ }
+}
diff --git a/access-logging/prefixes.tf b/access-logging/prefixes.tf
new file mode 120000
index 0000000..7e265d5
--- /dev/null
+++ b/access-logging/prefixes.tf
@@ -0,0 +1 @@
+../common/prefixes.tf
\ No newline at end of file
diff --git a/access-logging/variables.common.tf b/access-logging/variables.common.tf
new file mode 120000
index 0000000..7439ed8
--- /dev/null
+++ b/access-logging/variables.common.tf
@@ -0,0 +1 @@
+../common/variables.common.tf
\ No newline at end of file
diff --git a/access-logging/variables.tf b/access-logging/variables.tf
new file mode 100644
index 0000000..2589730
--- /dev/null
+++ b/access-logging/variables.tf
@@ -0,0 +1,18 @@
+variable "bucket_name" {
+ description = "Logging S3 bucket name"
+ type = string
+ # default = "inf-logs-{{ tf_account }}-{{ region }}"
+ default = ""
+}
+
+variable "bucket_name_prefix" {
+ description = "Logging S3 bucket prefix, prepended to the AWS account ID and region to make the bucket name."
+ type = string
+ default = "inf-logs"
+}
+
+variable "component_tags" {
+ description = "Additional tags for Components (s3, kms, ddb)"
+ type = map(map(string))
+ default = { "s3" = {}, "kms" = {}, "ddb" = {} }
+}
diff --git a/access-logging-bucket/version.tf b/access-logging/version.tf
similarity index 100%
rename from access-logging-bucket/version.tf
rename to access-logging/version.tf
diff --git a/common/defaults.tf b/common/defaults.tf
index c67478b..bc32b74 100644
--- a/common/defaults.tf
+++ b/common/defaults.tf
@@ -1,5 +1,19 @@
+# for the accesss logs for load balancers
+# https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-logging-bucket-permissions
locals {
_defaults = {
+ "load-balancer" = {
+ "gov" = ["190560391635", "048591011584"]
+ "us-gov-east-1" = "190560391635"
+ "us-gov-west-1" = "048591011584"
+
+ "ew" = ["127311923021", "033677994240", "027434742980", "797873946194"]
+ "us-east-1" = "127311923021"
+ "us-east-2" = "033677994240"
+ "us-west-1" = "027434742980"
+ "us-west-2" = "797873946194"
+ }
}
}
+
diff --git a/common/variables.common.tf b/common/variables.common.tf
index 2bc450a..2870df4 100644
--- a/common/variables.common.tf
+++ b/common/variables.common.tf
@@ -10,6 +10,7 @@ variable "account_id" {
variable "account_alias" {
description = "AWS Account Alias (required)"
type = string
+ default = ""
}
variable "override_prefixes" {
@@ -23,64 +24,3 @@ variable "tags" {
type = map(string)
default = {}
}
-
-## # s3
-## variable "bucket_name" {
-## description = "AWS Bucket Name. Standard prefix will be applied here, do not include here."
-## type = string
-## }
-##
-## variable "bucket_folders" {
-## description = "List of folders (keys) to create after creation of bucket. They will have object metadata provided based on metadata_tags and data_safeguard labels."
-## type = list(string)
-## default = []
-## }
-##
-## variable "kms_key_id" {
-## description = "AWS KMS Key ID (one per bucket). This is currently ignored."
-## type = string
-## default = ""
-## }
-##
-## variable "metadata_tags" {
-## description = "AWS S3 Custom metadata (prefix x-amzn-meta- automatically included, not needed here). If data_safeguard labels are applied, they will be incorporated on any bucket objects created."
-## type = map(string)
-## default = {}
-## }
-##
-## variable "access_log_bucket_prefix" {
-## description = "Access log bucket prefix, to which the bucket name will be appended to make the target_prefix"
-## type = string
-## default = "s3"
-## }
-##
-## variable "access_log_bucket" {
-## description = "Server Access Logging Bucket ID"
-## type = string
-## # default = null
-## }
-##
-## variable "allowed_cidr" {
-## description = "List of allowed source IPs (NOT from within the VPC). If empty, there will be no restrictions on source IP. If provided, you must also use allowed_endpoints for access within a VPC."
-## type = list(string)
-## default = []
-## }
-##
-## variable "allowed_endpoints" {
-## description = "List of allowed VPC endpoint IDs. If used, it will enable access to the bucket from the specific VPC endpoints."
-## type = list(string)
-## default = []
-## }
-##
-## variable "force_destroy" {
-## description = "Sets force_destroy to allow the bucket and contents to be deleted. The deletion may take a very long time based on the number of objects. You normally want to update this to true, apply, and then destroy the resource."
-## type = bool
-## default = false
-## }
-##
-## # variable "lifecycle_rules" {
-## # description = "Setup lifecycle rules (in-progress, not working)"
-## # type = map()
-## # default = {}
-## # }
-##
diff --git a/common/version.tf b/common/version.tf
index 5190b69..2f4174c 100644
--- a/common/version.tf
+++ b/common/version.tf
@@ -1,3 +1,3 @@
locals {
- _module_version = "1.1"
+ _module_version = "1.2"
}