diff --git a/README.md b/README.md index 0a2d99807..96e8267a0 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ module "vpc" { } ``` +> [!WARNING] +> v6.x of the module still supports creating a VPC Flow Log within the root (VPC) module. However, this is deprecated behavior and will be removed in v7.0.0. Please use the [standalone flow log](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/modules/flow-log) module instead. + ## External NAT Gateway IPs By default this module will provision new Elastic IPs for the VPC's NAT Gateways. @@ -116,24 +119,6 @@ If you need private subnets that should have no Internet routing (in the sense o Since AWS Lambda functions allocate Elastic Network Interfaces in proportion to the traffic received ([read more](https://docs.aws.amazon.com/lambda/latest/dg/vpc.html)), it can be useful to allocate a large private subnet for such allocations, while keeping the traffic they generate entirely internal to the VPC. -You can add additional tags with `intra_subnet_tags` as with other subnet types. - -## VPC Flow Log - -VPC Flow Log allows to capture IP traffic for a specific network interface (ENI), subnet, or entire VPC. This module supports enabling or disabling VPC Flow Logs for entire VPC. If you need to have VPC Flow Logs for subnet or ENI, you have to manage it outside of this module with [aws_flow_log resource](https://www.terraform.io/docs/providers/aws/r/flow_log.html). - -### VPC Flow Log Examples - -By default `file_format` is `plain-text`. You can also specify `parquet` to have logs written in Apache Parquet format. - -``` -flow_log_file_format = "parquet" -``` - -### Permissions Boundary - -If your organization requires a permissions boundary to be attached to the VPC Flow Log role, make sure that you specify an ARN of the permissions boundary policy as `vpc_flow_log_permissions_boundary` argument. Read more about required [IAM policy for publishing flow logs](https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-cwl.html#flow-logs-iam). - ## Conditional creation Prior to Terraform 0.13, you were unable to specify `count` in a module block. If you wish to toggle the creation of the module's resources in an older (pre 0.13) version of Terraform, you can use the `create_vpc` argument. @@ -231,19 +216,18 @@ module "vpc_cidr_from_ipam" { ## Examples -- [Complete VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/complete) with VPC Endpoints. +- [Block Public Access](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/block-public-access) +- [Complete VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/complete) w/ VPC Endpoints +- [VPC w/ Flow Log](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/flow-log) - [VPC using IPAM](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/ipam) - [Dualstack IPv4/IPv6 VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/ipv6-dualstack) -- [IPv6 only subnets/VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/ipv6-only) +- [IPv6 only subnets VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/ipv6-only) - [Manage Default VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/manage-default-vpc) -- [Network ACL](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/network-acls) -- [VPC with Outpost](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/outpost) -- [VPC with secondary CIDR blocks](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/secondary-cidr-blocks) -- [VPC with unique route tables](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/separate-route-tables) +- [VPC w/ Network ACL](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/network-acls) +- [VPC w/ Outpost](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/outpost) +- [VPC w/ secondary CIDR blocks](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/secondary-cidr-blocks) +- [VPC w/ unique route tables](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/separate-route-tables) - [Simple VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/simple) -- [VPC Flow Logs](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/vpc-flow-logs) -- [VPC Block Public Access](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/block-public-access) -- [Few tests and edge case examples](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issues) ## Contributing diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..8d54b3db3 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +# Examples + +The examples provided demonstrate different cluster configurations that users can create with the modules provided. + +Please do not mistake the examples provided as "best practices". It is up to users to consult the AWS service documentation for best practices, usage recommendations, etc. diff --git a/examples/complete/README.md b/examples/complete/README.md index 22d7ae80d..8909d97d0 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -154,10 +154,6 @@ No inputs. | [vpc\_endpoints](#output\_vpc\_endpoints) | Array containing the full resource object and attributes for all endpoints created | | [vpc\_endpoints\_security\_group\_arn](#output\_vpc\_endpoints\_security\_group\_arn) | Amazon Resource Name (ARN) of the security group | | [vpc\_endpoints\_security\_group\_id](#output\_vpc\_endpoints\_security\_group\_id) | ID of the security group | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 0ac5553e6..7a25e467c 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -72,14 +72,6 @@ module "vpc" { dhcp_options_domain_name = "service.consul" dhcp_options_domain_name_servers = ["127.0.0.1", "10.10.0.2"] - # VPC Flow Logs (Cloudwatch log group and IAM role will be created) - vpc_flow_log_iam_role_name = "vpc-complete-example-role" - vpc_flow_log_iam_role_use_name_prefix = false - enable_flow_log = true - create_flow_log_cloudwatch_log_group = true - create_flow_log_cloudwatch_iam_role = true - flow_log_max_aggregation_interval = 60 - tags = local.tags } diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 24be1a37c..5b2dd50bf 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -513,27 +513,6 @@ output "elasticache_network_acl_arn" { value = module.vpc.elasticache_network_acl_arn } -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} - # VPC endpoints output "vpc_endpoints" { description = "Array containing the full resource object and attributes for all endpoints created" diff --git a/examples/flow-log/README.md b/examples/flow-log/README.md new file mode 100644 index 000000000..38816f749 --- /dev/null +++ b/examples/flow-log/README.md @@ -0,0 +1,72 @@ +# AWS Flow Logs to S3 and CloudWatch logs + +Configuration in this directory creates a set of VPC resources with VPC Flow Logs enabled in different configurations: + +- Flow log to CloudWatch logs using module created CloudWatch log group and IAM role +- Flow log to CloudWatch logs using external CloudWatch log group and IAM role +- Flow log to S3 bucket in text format +- Flow log to S3 bucket in Parquet format + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which can cost money (AWS Elastic IP, for example). Run `terraform destroy` when you don't need these resources. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [aws](#requirement\_aws) | >= 6.5 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 6.5 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [disabled](#module\_disabled) | ../../modules/flow-log | n/a | +| [flow\_log](#module\_flow\_log) | ../../modules/flow-log | n/a | +| [flow\_log\_cloudwatch\_external](#module\_flow\_log\_cloudwatch\_external) | ../../modules/flow-log | n/a | +| [flow\_log\_s3](#module\_flow\_log\_s3) | ../../modules/flow-log | n/a | +| [flow\_log\_s3\_parquet](#module\_flow\_log\_s3\_parquet) | ../../modules/flow-log | n/a | +| [s3\_bucket](#module\_s3\_bucket) | terraform-aws-modules/s3-bucket/aws | ~> 5.0 | +| [vpc](#module\_vpc) | ../../ | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.flow_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | The ARN of the Flow Log | +| [cloudwatch\_log\_group\_arn](#output\_cloudwatch\_log\_group\_arn) | ARN of CloudWatch log group created | +| [cloudwatch\_log\_group\_name](#output\_cloudwatch\_log\_group\_name) | Name of CloudWatch log group created | +| [iam\_role\_arn](#output\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | +| [iam\_role\_name](#output\_iam\_role\_name) | The name of the IAM role | +| [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | +| [id](#output\_id) | The ID of the Flow Log | + diff --git a/examples/flow-log/main.tf b/examples/flow-log/main.tf new file mode 100644 index 000000000..7549866cf --- /dev/null +++ b/examples/flow-log/main.tf @@ -0,0 +1,162 @@ +provider "aws" { + region = local.region +} + +data "aws_availability_zones" "available" {} + +locals { + name = "ex-${basename(path.cwd)}" + region = "eu-west-1" + + vpc_cidr = "10.0.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) + + tags = { + Example = local.name + GithubRepo = "terraform-aws-vpc" + GithubOrg = "terraform-aws-modules" + } +} + +################################################################################ +# Flow Log +################################################################################ + +module "flow_log" { + source = "../../modules/flow-log" + + name = local.name + vpc_id = module.vpc.vpc_id + + tags = local.tags +} + +module "flow_log_cloudwatch_external" { + source = "../../modules/flow-log" + + name = "${local.name}-cloudwatch-external" + vpc_id = module.vpc.vpc_id + + create_cloudwatch_log_group = false + log_destination = aws_cloudwatch_log_group.flow_log.arn + + create_iam_role = false + iam_role_arn = aws_iam_role.flow_log_cloudwatch.arn + + tags = local.tags +} + +module "flow_log_s3" { + source = "../../modules/flow-log" + + name = "${local.name}-s3" + vpc_id = module.vpc.vpc_id + + log_destination_type = "s3" + log_destination = module.s3_bucket.s3_bucket_arn + + tags = local.tags +} + +module "flow_log_s3_parquet" { + source = "../../modules/flow-log" + + name = "${local.name}-s3-parquet" + vpc_id = module.vpc.vpc_id + + log_destination_type = "s3" + log_destination = module.s3_bucket.s3_bucket_arn + destination_options = { + file_format = "parquet" + hive_compatible_partitions = true + per_hour_partition = true + } + + tags = local.tags +} + +module "disabled" { + source = "../../modules/flow-log" + + create = false +} + +################################################################################ +# Supporting Resources +################################################################################ + +module "vpc" { + source = "../../" + + name = local.name + cidr = local.vpc_cidr + + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] + public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] + + tags = local.tags +} + +module "s3_bucket" { + source = "terraform-aws-modules/s3-bucket/aws" + version = "~> 5.0" + + bucket_prefix = "${local.name}-" + force_destroy = true + + # Policy works for flow logs as well + attach_waf_log_delivery_policy = true + + tags = local.tags +} + +resource "aws_cloudwatch_log_group" "flow_log" { + name_prefix = "/aws/flow-log/vpc/${module.vpc.vpc_id}/${local.name}-external-" + + retention_in_days = 7 + + tags = local.tags +} + +resource "aws_iam_role" "flow_log_cloudwatch" { + name_prefix = "${local.name}-external-" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "VPCFlowLogsAssume" + Principal = { + Service = "vpc-flow-logs.amazonaws.com" + } + }, + ] + }) + + tags = local.tags +} + +resource "aws_iam_role_policy" "flow_log_cloudwatch" { + name_prefix = "${local.name}-external-" + role = aws_iam_role.flow_log_cloudwatch.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + ] + Effect = "Allow" + Resource = aws_cloudwatch_log_group.flow_log.arn + }, + ] + }) +} diff --git a/examples/flow-log/outputs.tf b/examples/flow-log/outputs.tf new file mode 100644 index 000000000..7619d4529 --- /dev/null +++ b/examples/flow-log/outputs.tf @@ -0,0 +1,46 @@ +################################################################################ +# Flow Log +################################################################################ + +output "id" { + description = "The ID of the Flow Log" + value = module.flow_log.id +} + +output "arn" { + description = "The ARN of the Flow Log" + value = module.flow_log.arn +} + +################################################################################ +# CloudWatch Log Group +################################################################################ + +output "cloudwatch_log_group_name" { + description = "Name of CloudWatch log group created" + value = module.flow_log.cloudwatch_log_group_name +} + +output "cloudwatch_log_group_arn" { + description = "ARN of CloudWatch log group created" + value = module.flow_log.cloudwatch_log_group_arn +} + +################################################################################ +# IAM Role +################################################################################ + +output "iam_role_name" { + description = "The name of the IAM role" + value = module.flow_log.iam_role_name +} + +output "iam_role_arn" { + description = "The Amazon Resource Name (ARN) specifying the IAM role" + value = module.flow_log.iam_role_arn +} + +output "iam_role_unique_id" { + description = "Stable and unique string identifying the IAM role" + value = module.flow_log.iam_role_unique_id +} diff --git a/examples/vpc-flow-logs/variables.tf b/examples/flow-log/variables.tf similarity index 100% rename from examples/vpc-flow-logs/variables.tf rename to examples/flow-log/variables.tf diff --git a/examples/flow-log/versions.tf b/examples/flow-log/versions.tf new file mode 100644 index 000000000..1548bda1a --- /dev/null +++ b/examples/flow-log/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.5.7" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.5" + } + } +} diff --git a/examples/ipam/README.md b/examples/ipam/README.md index 84435afd6..de12c57b3 100644 --- a/examples/ipam/README.md +++ b/examples/ipam/README.md @@ -160,10 +160,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/ipam/outputs.tf b/examples/ipam/outputs.tf index 47ca2117c..8bebededb 100644 --- a/examples/ipam/outputs.tf +++ b/examples/ipam/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc_ipam_set_netmask.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc_ipam_set_netmask.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc_ipam_set_netmask.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc_ipam_set_netmask.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc_ipam_set_netmask.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/ipv6-dualstack/README.md b/examples/ipv6-dualstack/README.md index 8e485fb6f..c44e63143 100644 --- a/examples/ipv6-dualstack/README.md +++ b/examples/ipv6-dualstack/README.md @@ -144,10 +144,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/ipv6-dualstack/outputs.tf b/examples/ipv6-dualstack/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/ipv6-dualstack/outputs.tf +++ b/examples/ipv6-dualstack/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/ipv6-only/README.md b/examples/ipv6-only/README.md index 29a8f6e57..54393d068 100644 --- a/examples/ipv6-only/README.md +++ b/examples/ipv6-only/README.md @@ -144,10 +144,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/ipv6-only/outputs.tf b/examples/ipv6-only/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/ipv6-only/outputs.tf +++ b/examples/ipv6-only/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/manage-default-vpc/README.md b/examples/manage-default-vpc/README.md index 73aac3d16..46735b9a5 100644 --- a/examples/manage-default-vpc/README.md +++ b/examples/manage-default-vpc/README.md @@ -142,10 +142,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/manage-default-vpc/outputs.tf b/examples/manage-default-vpc/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/manage-default-vpc/outputs.tf +++ b/examples/manage-default-vpc/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/network-acls/README.md b/examples/network-acls/README.md index 47cfbc5a3..b9a64332e 100644 --- a/examples/network-acls/README.md +++ b/examples/network-acls/README.md @@ -148,10 +148,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/network-acls/outputs.tf b/examples/network-acls/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/network-acls/outputs.tf +++ b/examples/network-acls/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/outpost/README.md b/examples/outpost/README.md index d40465bf0..5950759c6 100644 --- a/examples/outpost/README.md +++ b/examples/outpost/README.md @@ -149,10 +149,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/outpost/outputs.tf b/examples/outpost/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/outpost/outputs.tf +++ b/examples/outpost/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/secondary-cidr-blocks/README.md b/examples/secondary-cidr-blocks/README.md index dfecae31a..fa62056cb 100644 --- a/examples/secondary-cidr-blocks/README.md +++ b/examples/secondary-cidr-blocks/README.md @@ -146,10 +146,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/secondary-cidr-blocks/outputs.tf b/examples/secondary-cidr-blocks/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/secondary-cidr-blocks/outputs.tf +++ b/examples/secondary-cidr-blocks/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/separate-route-tables/README.md b/examples/separate-route-tables/README.md index faef6b100..09bb9cd07 100644 --- a/examples/separate-route-tables/README.md +++ b/examples/separate-route-tables/README.md @@ -146,10 +146,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/separate-route-tables/outputs.tf b/examples/separate-route-tables/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/separate-route-tables/outputs.tf +++ b/examples/separate-route-tables/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/simple/README.md b/examples/simple/README.md index 357f997b8..2d2338dc0 100644 --- a/examples/simple/README.md +++ b/examples/simple/README.md @@ -150,10 +150,6 @@ No inputs. | [vpc\_cidr\_block](#output\_vpc\_cidr\_block) | The CIDR block of the VPC | | [vpc\_enable\_dns\_hostnames](#output\_vpc\_enable\_dns\_hostnames) | Whether or not the VPC has DNS hostname support | | [vpc\_enable\_dns\_support](#output\_vpc\_enable\_dns\_support) | Whether or not the VPC has DNS support | -| [vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_log\_id](#output\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | | [vpc\_id](#output\_vpc\_id) | The ID of the VPC | | [vpc\_instance\_tenancy](#output\_vpc\_instance\_tenancy) | Tenancy of instances spin up within VPC | | [vpc\_ipv6\_association\_id](#output\_vpc\_ipv6\_association\_id) | The association ID for the IPv6 CIDR block | diff --git a/examples/simple/outputs.tf b/examples/simple/outputs.tf index 77f244a90..90c54ad2f 100644 --- a/examples/simple/outputs.tf +++ b/examples/simple/outputs.tf @@ -512,24 +512,3 @@ output "elasticache_network_acl_arn" { description = "ARN of the elasticache network ACL" value = module.vpc.elasticache_network_acl_arn } - -# VPC flow log -output "vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc.vpc_flow_log_id -} - -output "vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_arn -} - -output "vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc.vpc_flow_log_destination_type -} - -output "vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc.vpc_flow_log_cloudwatch_iam_role_arn -} diff --git a/examples/vpc-flow-logs/README.md b/examples/vpc-flow-logs/README.md deleted file mode 100644 index 88b51876e..000000000 --- a/examples/vpc-flow-logs/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# VPC with enabled VPC flow log to S3 and CloudWatch logs - -Configuration in this directory creates a set of VPC resources with VPC Flow Logs enabled in different configurations: - -1. `cloud-watch-logs.tf` - Push logs to a new AWS CloudWatch Log group. -1. `cloud-watch-logs.tf` - Push logs to an existing AWS CloudWatch Log group using existing IAM role (created outside of this module). -1. `s3.tf` - Push logs to an existing S3 bucket (created outside of this module). - -## Usage - -To run this example you need to execute: - -```bash -$ terraform init -$ terraform plan -$ terraform apply -``` - -Note that this example may create resources which can cost money (AWS Elastic IP, for example). Run `terraform destroy` when you don't need these resources. - - -## Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 6.0 | -| [random](#requirement\_random) | >= 2.0 | - -## Providers - -| Name | Version | -|------|---------| -| [aws](#provider\_aws) | >= 6.0 | -| [random](#provider\_random) | >= 2.0 | - -## Modules - -| Name | Source | Version | -|------|--------|---------| -| [s3\_bucket](#module\_s3\_bucket) | terraform-aws-modules/s3-bucket/aws | ~> 3.0 | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs](#module\_vpc\_with\_flow\_logs\_cloudwatch\_logs) | ../../ | n/a | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_default](#module\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_default) | ../../ | n/a | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_prefix](#module\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_prefix) | ../../ | n/a | -| [vpc\_with\_flow\_logs\_s3\_bucket](#module\_vpc\_with\_flow\_logs\_s3\_bucket) | ../../ | n/a | -| [vpc\_with\_flow\_logs\_s3\_bucket\_parquet](#module\_vpc\_with\_flow\_logs\_s3\_bucket\_parquet) | ../../ | n/a | - -## Resources - -| Name | Type | -|------|------| -| [aws_cloudwatch_log_group.flow_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_policy.vpc_flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | -| [aws_iam_role.vpc_flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy_attachment.vpc_flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource | -| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | -| [aws_iam_policy_document.flow_log_cloudwatch_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.flow_log_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.vpc_flow_log_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | - -## Inputs - -No inputs. - -## Outputs - -| Name | Description | -|------|-------------| -| [vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_destination\_arn](#output\_vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_destination\_type](#output\_vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_id](#output\_vpc\_flow\_logs\_s3\_bucket\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_destination\_arn](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_destination\_type](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_id](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_default\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_cloudwatch\_iam\_role\_arn) | The ARN of the IAM role used when pushing logs to Cloudwatch log group | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_destination\_arn](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_destination\_arn) | The ARN of the destination for VPC Flow Logs | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_destination\_type](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_destination\_type) | The type of the destination for VPC Flow Logs | -| [vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_id](#output\_vpc\_with\_flow\_logs\_cloudwatch\_logs\_vpc\_flow\_log\_id) | The ID of the Flow Log resource | - diff --git a/examples/vpc-flow-logs/main.tf b/examples/vpc-flow-logs/main.tf deleted file mode 100644 index 7cd35d34f..000000000 --- a/examples/vpc-flow-logs/main.tf +++ /dev/null @@ -1,227 +0,0 @@ -provider "aws" { - region = local.region -} - -data "aws_availability_zones" "available" {} - -locals { - name = "ex-${basename(path.cwd)}" - region = "eu-west-1" - - vpc_cidr = "10.0.0.0/16" - azs = slice(data.aws_availability_zones.available.names, 0, 3) - - tags = { - Example = local.name - GithubRepo = "terraform-aws-vpc" - GithubOrg = "terraform-aws-modules" - } - - s3_bucket_name = "vpc-flow-logs-to-s3-${random_pet.this.id}" -} - -################################################################################ -# VPC Module -################################################################################ - -module "vpc_with_flow_logs_s3_bucket" { - source = "../../" - - name = local.name - cidr = local.vpc_cidr - - azs = local.azs - private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] - public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] - - enable_flow_log = true - flow_log_destination_type = "s3" - flow_log_destination_arn = module.s3_bucket.s3_bucket_arn - - vpc_flow_log_tags = local.tags -} - -module "vpc_with_flow_logs_s3_bucket_parquet" { - source = "../../" - - name = "${local.name}-parquet" - cidr = local.vpc_cidr - - azs = local.azs - private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] - public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] - - enable_flow_log = true - flow_log_destination_type = "s3" - flow_log_destination_arn = module.s3_bucket.s3_bucket_arn - flow_log_file_format = "parquet" - - vpc_flow_log_tags = local.tags -} - -# CloudWatch Log Group and IAM role created automatically -module "vpc_with_flow_logs_cloudwatch_logs_default" { - source = "../../" - - name = "${local.name}-cloudwatch-logs-default" - cidr = local.vpc_cidr - - azs = local.azs - private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] - public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] - - # Cloudwatch log group and IAM role will be created - enable_flow_log = true - create_flow_log_cloudwatch_log_group = true - create_flow_log_cloudwatch_iam_role = true - - flow_log_max_aggregation_interval = 60 - flow_log_cloudwatch_log_group_name_prefix = "/aws/my-amazing-vpc-flow-logz/" - flow_log_cloudwatch_log_group_name_suffix = "my-test" - flow_log_cloudwatch_log_group_class = "INFREQUENT_ACCESS" - - vpc_flow_log_tags = local.tags -} - -# CloudWatch Log Group and IAM prefix -module "vpc_with_flow_logs_cloudwatch_logs_prefix" { - source = "../../" - - name = "${local.name}-cloudwatch-logs-prefix" - cidr = local.vpc_cidr - - azs = local.azs - private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] - public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] - - # Cloudwatch log group and IAM role will be created - enable_flow_log = true - create_flow_log_cloudwatch_log_group = true - create_flow_log_cloudwatch_iam_role = true - - vpc_flow_log_iam_role_name = "vpc-iam-prefix-example" - vpc_flow_log_iam_role_use_name_prefix = true - vpc_flow_log_iam_policy_name = "vpc-iam-prefix-example" - vpc_flow_log_iam_policy_use_name_prefix = true - - flow_log_max_aggregation_interval = 60 - flow_log_cloudwatch_log_group_name_prefix = "/aws/my-amazing-vpc-flow-logz/" - flow_log_cloudwatch_log_group_name_suffix = "my-test" - flow_log_cloudwatch_log_group_class = "INFREQUENT_ACCESS" - - vpc_flow_log_tags = local.tags -} - -# CloudWatch Log Group and IAM role created separately -module "vpc_with_flow_logs_cloudwatch_logs" { - source = "../../" - - name = "${local.name}-cloudwatch-logs" - cidr = local.vpc_cidr - - azs = local.azs - private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] - public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 4)] - - enable_flow_log = true - flow_log_destination_type = "cloud-watch-logs" - flow_log_destination_arn = aws_cloudwatch_log_group.flow_log.arn - flow_log_cloudwatch_iam_role_arn = aws_iam_role.vpc_flow_log_cloudwatch.arn - - vpc_flow_log_tags = local.tags -} - -################################################################################ -# Supporting Resources -################################################################################ - -resource "random_pet" "this" { - length = 2 -} - -# S3 Bucket -module "s3_bucket" { - source = "terraform-aws-modules/s3-bucket/aws" - version = "~> 3.0" - - bucket = local.s3_bucket_name - policy = data.aws_iam_policy_document.flow_log_s3.json - force_destroy = true - - tags = local.tags -} - -data "aws_iam_policy_document" "flow_log_s3" { - statement { - sid = "AWSLogDeliveryWrite" - - principals { - type = "Service" - identifiers = ["delivery.logs.amazonaws.com"] - } - - actions = ["s3:PutObject"] - - resources = ["arn:aws:s3:::${local.s3_bucket_name}/AWSLogs/*"] - } - - statement { - sid = "AWSLogDeliveryAclCheck" - - principals { - type = "Service" - identifiers = ["delivery.logs.amazonaws.com"] - } - - actions = ["s3:GetBucketAcl"] - - resources = ["arn:aws:s3:::${local.s3_bucket_name}"] - } -} - -# Cloudwatch logs -resource "aws_cloudwatch_log_group" "flow_log" { - name = "vpc-flow-logs-to-cloudwatch-${random_pet.this.id}" -} - -resource "aws_iam_role" "vpc_flow_log_cloudwatch" { - name_prefix = "vpc-flow-log-role-" - assume_role_policy = data.aws_iam_policy_document.flow_log_cloudwatch_assume_role.json -} - -data "aws_iam_policy_document" "flow_log_cloudwatch_assume_role" { - statement { - principals { - type = "Service" - identifiers = ["vpc-flow-logs.amazonaws.com"] - } - - actions = ["sts:AssumeRole"] - } -} - -resource "aws_iam_role_policy_attachment" "vpc_flow_log_cloudwatch" { - role = aws_iam_role.vpc_flow_log_cloudwatch.name - policy_arn = aws_iam_policy.vpc_flow_log_cloudwatch.arn -} - -resource "aws_iam_policy" "vpc_flow_log_cloudwatch" { - name_prefix = "vpc-flow-log-cloudwatch-" - policy = data.aws_iam_policy_document.vpc_flow_log_cloudwatch.json -} - -data "aws_iam_policy_document" "vpc_flow_log_cloudwatch" { - statement { - sid = "AWSVPCFlowLogsPushToCloudWatch" - - actions = [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - ] - - resources = ["*"] - } -} diff --git a/examples/vpc-flow-logs/outputs.tf b/examples/vpc-flow-logs/outputs.tf deleted file mode 100644 index 4f7794230..000000000 --- a/examples/vpc-flow-logs/outputs.tf +++ /dev/null @@ -1,57 +0,0 @@ -# VPC flow log - Cloudwatch logs (default) -output "vpc_with_flow_logs_cloudwatch_logs_default_vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc_with_flow_logs_cloudwatch_logs_default.vpc_flow_log_id -} - -output "vpc_with_flow_logs_cloudwatch_logs_default_vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_cloudwatch_logs_default.vpc_flow_log_destination_arn -} - -output "vpc_with_flow_logs_cloudwatch_logs_default_vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_cloudwatch_logs_default.vpc_flow_log_destination_type -} - -output "vpc_with_flow_logs_cloudwatch_logs_default_vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc_with_flow_logs_cloudwatch_logs_default.vpc_flow_log_cloudwatch_iam_role_arn -} - -# VPC flow log - Cloudwatch logs (created separately) -output "vpc_with_flow_logs_cloudwatch_logs_vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc_with_flow_logs_cloudwatch_logs.vpc_flow_log_id -} - -output "vpc_with_flow_logs_cloudwatch_logs_vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_cloudwatch_logs.vpc_flow_log_destination_arn -} - -output "vpc_with_flow_logs_cloudwatch_logs_vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_cloudwatch_logs.vpc_flow_log_destination_type -} - -output "vpc_with_flow_logs_cloudwatch_logs_vpc_flow_log_cloudwatch_iam_role_arn" { - description = "The ARN of the IAM role used when pushing logs to Cloudwatch log group" - value = module.vpc_with_flow_logs_cloudwatch_logs.vpc_flow_log_cloudwatch_iam_role_arn -} - -# VPC flow log - S3 bucket -output "vpc_flow_logs_s3_bucket_vpc_flow_log_id" { - description = "The ID of the Flow Log resource" - value = module.vpc_with_flow_logs_s3_bucket.vpc_flow_log_id -} - -output "vpc_flow_logs_s3_bucket_vpc_flow_log_destination_arn" { - description = "The ARN of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_s3_bucket.vpc_flow_log_destination_arn -} - -output "vpc_flow_logs_s3_bucket_vpc_flow_log_destination_type" { - description = "The type of the destination for VPC Flow Logs" - value = module.vpc_with_flow_logs_s3_bucket.vpc_flow_log_destination_type -} diff --git a/examples/vpc-flow-logs/versions.tf b/examples/vpc-flow-logs/versions.tf deleted file mode 100644 index 1a6fb6cfb..000000000 --- a/examples/vpc-flow-logs/versions.tf +++ /dev/null @@ -1,15 +0,0 @@ -terraform { - required_version = ">= 1.0" - - required_providers { - aws = { - source = "hashicorp/aws" - version = ">= 6.0" - } - - random = { - source = "hashicorp/random" - version = ">= 2.0" - } - } -} diff --git a/modules/flow-log/README.md b/modules/flow-log/README.md new file mode 100644 index 000000000..524a13fff --- /dev/null +++ b/modules/flow-log/README.md @@ -0,0 +1,132 @@ +# AWS Flow Log Terraform Module + +Terraform module which creates AWS Flow Log resources. + +## Usage + +See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples) directory for working examples to reference: + +### CloudWatch Logs + +```hcl +module "flow_log" { + source = "terraform-aws-modules/vpc/aws//modules/flow-log" + + name = "example" + vpc_id = "vpc-12345678" + + tags = { + Owner = "user" + Environment = "dev" + } +} +``` + +### S3 Bucket + +```hcl +module "flow_log" { + source = "terraform-aws-modules/vpc/aws//modules/flow-log" + + name = "example" + vpc_id = "vpc-12345678" + + log_destination_type = "s3" + log_destination = "arn:aws:s3:::example-20250602150510701600000001" + + tags = { + Owner = "user" + Environment = "dev" + } +} +``` + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [aws](#requirement\_aws) | >= 6.5 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 6.5 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_flow_log.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource | +| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cloudwatch\_log\_group\_class](#input\_cloudwatch\_log\_group\_class) | Specified the log class of the log group. Possible values are: `STANDARD` or `INFREQUENT_ACCESS` | `string` | `null` | no | +| [cloudwatch\_log\_group\_kms\_key\_id](#input\_cloudwatch\_log\_group\_kms\_key\_id) | If a KMS Key ARN is set, this key will be used to encrypt the corresponding log group. Please be sure that the KMS Key has an appropriate key policy (https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html) | `string` | `null` | no | +| [cloudwatch\_log\_group\_name](#input\_cloudwatch\_log\_group\_name) | Name of the created CloudWatch log group | `string` | `null` | no | +| [cloudwatch\_log\_group\_retention\_in\_days](#input\_cloudwatch\_log\_group\_retention\_in\_days) | Number of days to retain log events. Set to `0` to keep logs indefinitely | `number` | `90` | no | +| [cloudwatch\_log\_group\_tags](#input\_cloudwatch\_log\_group\_tags) | Map of additional tags to add to the CloudWatch log group | `map(string)` | `{}` | no | +| [cloudwatch\_log\_group\_use\_name\_prefix](#input\_cloudwatch\_log\_group\_use\_name\_prefix) | Determines whether the log group name should be used as a prefix | `bool` | `true` | no | +| [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | +| [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Determines whether to create a CloudWatch log group for the Flow Logs | `bool` | `true` | no | +| [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no | +| [deliver\_cross\_account\_role](#input\_deliver\_cross\_account\_role) | ARN of the IAM role in the destination account used for cross-account delivery of flow logs | `string` | `null` | no | +| [destination\_options](#input\_destination\_options) | Describes the destination options for a flow log |
object({
file_format = optional(string)
hive_compatible_partitions = optional(bool)
per_hour_partition = optional(bool)
})
| `null` | no | +| [eni\_id](#input\_eni\_id) | Elastic Network Interface ID to attach to | `string` | `null` | no | +| [flow\_log\_tags](#input\_flow\_log\_tags) | Map of additional tags to add to the flow log | `map(string)` | `{}` | no | +| [iam\_role\_arn](#input\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | +| [iam\_role\_description](#input\_iam\_role\_description) | Description of the role | `string` | `null` | no | +| [iam\_role\_name](#input\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | +| [iam\_role\_path](#input\_iam\_role\_path) | IAM role path | `string` | `null` | no | +| [iam\_role\_permissions](#input\_iam\_role\_permissions) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for inline policy permissions |
map(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string, "Allow")
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
variable = string
values = list(string)
})))
}))
| `null` | no | +| [iam\_role\_permissions\_boundary](#input\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | +| [iam\_role\_tags](#input\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | +| [iam\_role\_trust\_policy\_permissions](#input\_iam\_role\_trust\_policy\_permissions) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom trust policy permissions |
map(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string, "Allow")
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
variable = string
values = list(string)
})))
}))
| `null` | no | +| [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | +| [kinesis\_data\_firehose\_arn](#input\_kinesis\_data\_firehose\_arn) | ARN of the existing Kinesis Data Firehose delivery stream. Required when `log_destination_type` is `kinesis-data-firehose` | `string` | `null` | no | +| [log\_destination](#input\_log\_destination) | ARN of the logging destination | `string` | `null` | no | +| [log\_destination\_type](#input\_log\_destination\_type) | Logging destination type. Valid values: `cloud-watch-logs`, `s3`, `kinesis-data-firehose`. Default: `cloud-watch-logs` | `string` | `"cloud-watch-logs"` | no | +| [log\_format](#input\_log\_format) | The fields to include in the flow log record | `string` | `null` | no | +| [max\_aggregation\_interval](#input\_max\_aggregation\_interval) | The maximum interval of time during which a flow of packets is captured and aggregated into a flow log record. Valid Values: `60` seconds (1 minute) or `600` seconds (10 minutes). Default: `600`. When `transit_gateway_id` or `transit_gateway_attachment_id` is specified, `max_aggregation_interval` must be 60 seconds (1 minute) | `number` | `null` | no | +| [name](#input\_name) | Name to use across resources created | `string` | `""` | no | +| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | +| [subnet\_id](#input\_subnet\_id) | Subnet ID to attach to | `string` | `null` | no | +| [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | +| [traffic\_type](#input\_traffic\_type) | The type of traffic to capture. Valid values: `ACCEPT`, `REJECT`, `ALL` | `string` | `"ALL"` | no | +| [transit\_gateway\_attachment\_id](#input\_transit\_gateway\_attachment\_id) | Transit Gateway Attachment ID to attach to | `string` | `null` | no | +| [transit\_gateway\_id](#input\_transit\_gateway\_id) | Transit Gateway ID to attach to | `string` | `null` | no | +| [vpc\_id](#input\_vpc\_id) | VPC ID to attach to | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | The ARN of the Flow Log | +| [cloudwatch\_log\_group\_arn](#output\_cloudwatch\_log\_group\_arn) | ARN of CloudWatch log group created | +| [cloudwatch\_log\_group\_name](#output\_cloudwatch\_log\_group\_name) | Name of CloudWatch log group created | +| [iam\_role\_arn](#output\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | +| [iam\_role\_name](#output\_iam\_role\_name) | The name of the IAM role | +| [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | +| [id](#output\_id) | The ID of the Flow Log | + + +## License + +Apache 2 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/LICENSE) for full details. diff --git a/modules/flow-log/main.tf b/modules/flow-log/main.tf new file mode 100644 index 000000000..30d51335a --- /dev/null +++ b/modules/flow-log/main.tf @@ -0,0 +1,328 @@ +data "aws_region" "current" { + count = var.create && var.log_destination_type != "s3" ? 1 : 0 + + region = var.region +} + +data "aws_caller_identity" "current" { + count = var.create && var.log_destination_type != "s3" ? 1 : 0 +} + +data "aws_partition" "current" { + count = var.create && var.log_destination_type != "s3" ? 1 : 0 +} + +locals { + region = try(data.aws_region.current[0].region, "") + account_id = try(data.aws_caller_identity.current[0].account_id, "") + partition = try(data.aws_partition.current[0].partition, "aws") + + destination_is_cloudwatch = var.log_destination_type == "cloud-watch-logs" + destination_is_kinesis = var.log_destination_type == "kinesis-data-firehose" + destination_is_s3 = var.log_destination_type == "s3" +} + +################################################################################ +# Flow Log +################################################################################ + +resource "aws_flow_log" "this" { + count = var.create ? 1 : 0 + + region = var.region + + deliver_cross_account_role = var.deliver_cross_account_role + + dynamic "destination_options" { + for_each = var.destination_options != null ? [var.destination_options] : [] + + content { + file_format = destination_options.value.file_format + hive_compatible_partitions = destination_options.value.hive_compatible_partitions + per_hour_partition = destination_options.value.per_hour_partition + } + } + + eni_id = var.eni_id + iam_role_arn = try(aws_iam_role.this[0].arn, var.iam_role_arn) + log_destination_type = var.log_destination_type + log_destination = try(aws_cloudwatch_log_group.this[0].arn, var.log_destination) + log_format = var.log_format + max_aggregation_interval = var.transit_gateway_attachment_id != null || var.transit_gateway_id != null ? 60 : var.max_aggregation_interval + subnet_id = var.subnet_id + traffic_type = var.traffic_type + transit_gateway_attachment_id = var.transit_gateway_attachment_id + transit_gateway_id = var.transit_gateway_id + vpc_id = var.vpc_id + + tags = merge( + var.tags, + { for k, v in { Name = var.name } : k => v if v != "" }, + var.flow_log_tags, + ) +} + +################################################################################ +# CloudWatch Log Group +################################################################################ + +locals { + create_cloudwatch_log_group = var.create && var.create_cloudwatch_log_group && local.destination_is_cloudwatch + + # Try to create a "sane" default log group name based on the resource the flow log is attached to + eni_suffix = var.eni_id != null ? "eni/${var.eni_id}" : null + subnet_suffix = var.subnet_id != null ? "subnet/${var.subnet_id}" : null + tgw_attach_suffix = var.transit_gateway_attachment_id != null ? "tgw-attachment/${var.transit_gateway_attachment_id}" : null + tgw_suffix = var.transit_gateway_id != null ? "tgw/${var.transit_gateway_id}" : null + vpc_suffix = var.vpc_id != null ? "vpc/${var.vpc_id}" : null + log_group_suffix = coalesce(local.eni_suffix, local.subnet_suffix, local.tgw_attach_suffix, local.tgw_suffix, local.vpc_suffix, "unknown") + + cloudwatch_log_group_name = coalesce(var.cloudwatch_log_group_name, var.name != "" ? "/aws/flow-log/${var.name}" : "/aws/flow-log/${local.log_group_suffix}") +} + +resource "aws_cloudwatch_log_group" "this" { + count = local.create_cloudwatch_log_group ? 1 : 0 + + region = var.region + + name = var.cloudwatch_log_group_use_name_prefix ? null : local.cloudwatch_log_group_name + name_prefix = var.cloudwatch_log_group_use_name_prefix ? "${local.cloudwatch_log_group_name}-" : null + log_group_class = var.cloudwatch_log_group_class + retention_in_days = var.cloudwatch_log_group_retention_in_days + kms_key_id = var.cloudwatch_log_group_kms_key_id + + tags = merge( + var.tags, + var.cloudwatch_log_group_tags, + ) +} + +################################################################################ +# IAM Role +################################################################################ + +locals { + create_iam_role = var.create && var.create_iam_role && !local.destination_is_s3 + + iam_role_name = coalesce(var.iam_role_name, var.name, replace(local.log_group_suffix, "/", "-")) +} + +data "aws_iam_policy_document" "assume_role" { + count = local.create_iam_role ? 1 : 0 + + dynamic "statement" { + for_each = local.destination_is_cloudwatch ? [1] : [] + + content { + sid = "VPCFlowLogs" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["vpc-flow-logs.amazonaws.com"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:${local.partition}:ec2:${local.region}:${local.account_id}:vpc-flow-log/*"] + } + } + } + + dynamic "statement" { + for_each = local.destination_is_kinesis ? [1] : [] + + content { + sid = "KinesisDataFirehose" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["firehose.amazonaws.com"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [local.account_id] + } + + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = ["arn:${local.partition}:ec2:${local.region}:${local.account_id}:vpc-flow-log/*"] + } + } + } + + dynamic "statement" { + for_each = var.iam_role_trust_policy_permissions != null ? var.iam_role_trust_policy_permissions : {} + + content { + sid = try(coalesce(statement.value.sid, statement.key)) + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources + + dynamic "principals" { + for_each = statement.value.principals != null ? statement.value.principals : [] + + content { + type = principals.value.type + identifiers = principals.value.identifiers + } + } + + dynamic "not_principals" { + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] + + content { + type = not_principals.value.type + identifiers = not_principals.value.identifiers + } + } + + dynamic "condition" { + for_each = statement.value.condition != null ? statement.value.condition : [] + + content { + test = condition.value.test + values = condition.value.values + variable = condition.value.variable + } + } + } + } +} + +resource "aws_iam_role" "this" { + count = local.create_iam_role ? 1 : 0 + + name = var.iam_role_use_name_prefix ? null : local.iam_role_name + name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null + path = var.iam_role_path + description = var.iam_role_description + + assume_role_policy = data.aws_iam_policy_document.assume_role[0].json + permissions_boundary = var.iam_role_permissions_boundary + force_detach_policies = true + + tags = merge( + var.tags, + var.iam_role_tags, + ) +} + +################################################################################ +# IAM Policy +################################################################################ + +resource "aws_iam_policy" "this" { + count = local.create_iam_role ? 1 : 0 + + name = var.iam_role_use_name_prefix ? null : local.iam_role_name + name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null + path = var.iam_role_path + description = var.iam_role_description + + policy = data.aws_iam_policy_document.this[0].json + + tags = merge( + var.tags, + var.iam_role_tags, + ) +} + +data "aws_iam_policy_document" "this" { + count = local.create_iam_role ? 1 : 0 + + dynamic "statement" { + for_each = local.destination_is_cloudwatch ? [1] : [] + + content { + sid = "CloudWatch" + actions = [ + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + ] + + resources = local.create_cloudwatch_log_group ? aws_cloudwatch_log_group.this[*].arn : [var.log_destination] + } + } + + dynamic "statement" { + for_each = local.destination_is_kinesis && var.kinesis_data_firehose_arn != null ? [1] : [] + + content { + sid = "KinesisDataFirehose" + actions = [ + "logs:CreateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:GetLogDelivery", + "firehose:TagDeliveryStream", + ] + + resources = [var.kinesis_data_firehose_arn] + } + } + + dynamic "statement" { + for_each = var.iam_role_permissions != null ? var.iam_role_permissions : {} + + content { + sid = try(coalesce(statement.value.sid, statement.key)) + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources + + dynamic "principals" { + for_each = statement.value.principals != null ? statement.value.principals : [] + + content { + type = principals.value.type + identifiers = principals.value.identifiers + } + } + + dynamic "not_principals" { + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] + + content { + type = not_principals.value.type + identifiers = not_principals.value.identifiers + } + } + + dynamic "condition" { + for_each = statement.value.condition != null ? statement.value.condition : [] + + content { + test = condition.value.test + values = condition.value.values + variable = condition.value.variable + } + } + } + } +} + +resource "aws_iam_role_policy_attachment" "this" { + count = local.create_iam_role ? 1 : 0 + + role = aws_iam_role.this[0].name + policy_arn = aws_iam_policy.this[0].arn +} diff --git a/modules/flow-log/outputs.tf b/modules/flow-log/outputs.tf new file mode 100644 index 000000000..38bf21190 --- /dev/null +++ b/modules/flow-log/outputs.tf @@ -0,0 +1,46 @@ +################################################################################ +# Flow Log +################################################################################ + +output "id" { + description = "The ID of the Flow Log" + value = try(aws_flow_log.this[0].id, null) +} + +output "arn" { + description = "The ARN of the Flow Log" + value = try(aws_flow_log.this[0].arn, null) +} + +################################################################################ +# CloudWatch Log Group +################################################################################ + +output "cloudwatch_log_group_name" { + description = "Name of CloudWatch log group created" + value = try(aws_cloudwatch_log_group.this[0].name, null) +} + +output "cloudwatch_log_group_arn" { + description = "ARN of CloudWatch log group created" + value = try(aws_cloudwatch_log_group.this[0].arn, null) +} + +################################################################################ +# IAM Role +################################################################################ + +output "iam_role_name" { + description = "The name of the IAM role" + value = try(aws_iam_role.this[0].name, null) +} + +output "iam_role_arn" { + description = "The Amazon Resource Name (ARN) specifying the IAM role" + value = try(aws_iam_role.this[0].arn, null) +} + +output "iam_role_unique_id" { + description = "Stable and unique string identifying the IAM role" + value = try(aws_iam_role.this[0].unique_id, null) +} diff --git a/modules/flow-log/variables.tf b/modules/flow-log/variables.tf new file mode 100644 index 000000000..8e0f6adbc --- /dev/null +++ b/modules/flow-log/variables.tf @@ -0,0 +1,265 @@ +variable "create" { + description = "Determines whether resources will be created (affects all resources)" + type = bool + default = true +} + +variable "region" { + description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration" + type = string + default = null +} + +variable "tags" { + description = "A map of tags to add to all resources" + type = map(string) + default = {} +} + +################################################################################ +# Flow Log +################################################################################ + +variable "name" { + description = "Name to use across resources created" + type = string + default = "" +} + +variable "deliver_cross_account_role" { + description = "ARN of the IAM role in the destination account used for cross-account delivery of flow logs" + type = string + default = null +} + +variable "destination_options" { + description = "Describes the destination options for a flow log" + type = object({ + file_format = optional(string) + hive_compatible_partitions = optional(bool) + per_hour_partition = optional(bool) + }) + default = null +} + +variable "eni_id" { + description = "Elastic Network Interface ID to attach to" + type = string + default = null +} + +variable "log_destination_type" { + description = "Logging destination type. Valid values: `cloud-watch-logs`, `s3`, `kinesis-data-firehose`. Default: `cloud-watch-logs`" + type = string + default = "cloud-watch-logs" +} + +variable "log_destination" { + description = "ARN of the logging destination" + type = string + default = null +} + +variable "log_format" { + description = "The fields to include in the flow log record" + type = string + default = null +} + +variable "max_aggregation_interval" { + description = "The maximum interval of time during which a flow of packets is captured and aggregated into a flow log record. Valid Values: `60` seconds (1 minute) or `600` seconds (10 minutes). Default: `600`. When `transit_gateway_id` or `transit_gateway_attachment_id` is specified, `max_aggregation_interval` must be 60 seconds (1 minute)" + type = number + default = null +} + +variable "subnet_id" { + description = "Subnet ID to attach to" + type = string + default = null +} + +variable "traffic_type" { + description = "The type of traffic to capture. Valid values: `ACCEPT`, `REJECT`, `ALL`" + type = string + default = "ALL" +} + +variable "transit_gateway_attachment_id" { + description = "Transit Gateway Attachment ID to attach to" + type = string + default = null +} + +variable "transit_gateway_id" { + description = "Transit Gateway ID to attach to" + type = string + default = null +} + +variable "vpc_id" { + description = "VPC ID to attach to" + type = string + default = null +} + +variable "flow_log_tags" { + description = "Map of additional tags to add to the flow log " + type = map(string) + default = {} +} + +################################################################################ +# CloudWatch Log Group +################################################################################ + +variable "create_cloudwatch_log_group" { + description = "Determines whether to create a CloudWatch log group for the Flow Logs" + type = bool + default = true +} + +variable "cloudwatch_log_group_name" { + description = "Name of the created CloudWatch log group" + type = string + default = null +} + +variable "cloudwatch_log_group_use_name_prefix" { + description = "Determines whether the log group name should be used as a prefix" + type = bool + default = true +} + +variable "cloudwatch_log_group_class" { + description = "Specified the log class of the log group. Possible values are: `STANDARD` or `INFREQUENT_ACCESS`" + type = string + default = null +} + +variable "cloudwatch_log_group_retention_in_days" { + description = "Number of days to retain log events. Set to `0` to keep logs indefinitely" + type = number + default = 90 +} + +variable "cloudwatch_log_group_kms_key_id" { + description = "If a KMS Key ARN is set, this key will be used to encrypt the corresponding log group. Please be sure that the KMS Key has an appropriate key policy (https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html)" + type = string + default = null +} + +variable "cloudwatch_log_group_tags" { + description = "Map of additional tags to add to the CloudWatch log group" + type = map(string) + default = {} +} + +################################################################################ +# IAM Role +################################################################################ + +variable "create_iam_role" { + description = "Determines whether the ECS service IAM role should be created" + type = bool + default = true +} + +variable "iam_role_arn" { + description = "Existing IAM role ARN" + type = string + default = null +} + +variable "iam_role_name" { + description = "Name to use on IAM role created" + type = string + default = null +} + +variable "iam_role_use_name_prefix" { + description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix" + type = bool + default = true +} + +variable "iam_role_path" { + description = "IAM role path" + type = string + default = null +} + +variable "iam_role_description" { + description = "Description of the role" + type = string + default = null +} + +variable "iam_role_permissions_boundary" { + description = "ARN of the policy that is used to set the permissions boundary for the IAM role" + type = string + default = null +} + +variable "iam_role_tags" { + description = "A map of additional tags to add to the IAM role created" + type = map(string) + default = {} +} + +variable "iam_role_trust_policy_permissions" { + description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom trust policy permissions" + type = map(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string, "Allow") + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + variable = string + values = list(string) + }))) + })) + default = null +} + +variable "iam_role_permissions" { + description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for inline policy permissions" + type = map(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string, "Allow") + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + variable = string + values = list(string) + }))) + })) + default = null +} + +variable "kinesis_data_firehose_arn" { + description = "ARN of the existing Kinesis Data Firehose delivery stream. Required when `log_destination_type` is `kinesis-data-firehose`" + type = string + default = null +} diff --git a/modules/flow-log/versions.tf b/modules/flow-log/versions.tf new file mode 100644 index 000000000..1548bda1a --- /dev/null +++ b/modules/flow-log/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.5.7" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.5" + } + } +}