diff --git a/.header.md b/.header.md index fc14892..0211e5d 100644 --- a/.header.md +++ b/.header.md @@ -61,6 +61,8 @@ service_network = { } ``` +You can share VPC Lattice service networks using AWS RAM with this module. Check the section [Sharing VPC Lattice resources](#sharing-vpc-lattice-resources) for more information. + ### VPC associations (var.vpc_associations) When you associate a VPC with a service network, it enables all the targets within that VPC to be clients and communicate with other services associated to that same service network. You can make use of Security Groups to control the access of the VPC association, allowing some traffic segmentation before the traffic arrives to the Service Network. @@ -299,3 +301,16 @@ services = { } } ``` + +You can share VPC Lattice services using AWS RAM with this module. Check the section [Sharing VPC Lattice resources](#sharing-vpc-lattice-resources) for more information. + +## Sharing VPC Lattice resources + +With [AWS Resource Access Manager](https://aws.amazon.com/ram/) (RAM), you can share VPC Lattice service networks and services. With this module, you can use the variable `var.ram_share` to share VPC Lattice resources. The variable supports the following attributes: + +- `resources_share_arn` = (Optional|string) ARN of an **existing** RAM Resource Share to use to associate principals and VPC Lattice resources. **This attribute and `resource_share_name` cannot be set at the same time.** +- `resources_share_name` = (Optional|string) Name of the RAM Resource Share resource. This attribute creates a **new** resource using the specified name. **This attribute and `resources_share_arn` cannot be set at the same time.** +- `allow_external_principals` = (Optional|boolean) Indicates whether principals outside your organization can be associated with a resource share. **This attribute is allowed only when `resources_share_name` is provided.** +- `principals` = (Optional|list(string)) List of AWS principals to associated the resources with. Possible values are an AWS account ID, an AWS Organizations Organization ARN, or an AWS Organizations Organization Unit ARN. +- `share_service_network` = (Optional|boolean) Indicates whether a created VPC Lattice service network should be associated or not. Defaults to `true`. +- `share_services` = (Optional|list(string)) List of created VPC Lattice services to share. You should use the services' keys defined in `var.services`. diff --git a/README.md b/README.md index e96b16c..98228e5 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ service_network = { } ``` +You can share VPC Lattice service networks using AWS RAM with this module. Check the section [Sharing VPC Lattice resources](#sharing-vpc-lattice-resources) for more information. + ### VPC associations (var.vpc\_associations) When you associate a VPC with a service network, it enables all the targets within that VPC to be clients and communicate with other services associated to that same service network. You can make use of Security Groups to control the access of the VPC association, allowing some traffic segmentation before the traffic arrives to the Service Network. @@ -301,6 +303,19 @@ services = { } ``` +You can share VPC Lattice services using AWS RAM with this module. Check the section [Sharing VPC Lattice resources](#sharing-vpc-lattice-resources) for more information. + +## Sharing VPC Lattice resources + +With [AWS Resource Access Manager](https://aws.amazon.com/ram/) (RAM), you can share VPC Lattice service networks and services. With this module, you can use the variable `var.ram_share` to share VPC Lattice resources. The variable supports the following attributes: + +- `resources_share_arn` = (Optional|string) ARN of an **existing** RAM Resource Share to use to associate principals and VPC Lattice resources. **This attribute and `resource_share_name` cannot be set at the same time.** +- `resources_share_name` = (Optional|string) Name of the RAM Resource Share resource. This attribute creates a **new** resource using the specified name. **This attribute and `resources_share_arn` cannot be set at the same time.** +- `allow_external_principals` = (Optional|boolean) Indicates whether principals outside your organization can be associated with a resource share. **This attribute is allowed only when `resources_share_name` is provided.** +- `principals` = (Optional|list(string)) List of AWS principals to associated the resources with. Possible values are an AWS account ID, an AWS Organizations Organization ARN, or an AWS Organizations Organization Unit ARN. +- `share_service_network` = (Optional|boolean) Indicates whether a created VPC Lattice service network should be associated or not. Defaults to `true`. +- `share_services` = (Optional|list(string)) List of created VPC Lattice services to share. You should use the services' keys defined in `var.services`. + ## Requirements | Name | Version | @@ -326,6 +341,10 @@ services = { | Name | Type | |------|------| +| [aws_ram_principal_association.ram_principal_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_principal_association) | resource | +| [aws_ram_resource_association.ram_service_network_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_association) | resource | +| [aws_ram_resource_association.ram_services_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_association) | resource | +| [aws_ram_resource_share.ram_resource_share](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share) | resource | | [aws_vpclattice_auth_policy.service_auth_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpclattice_auth_policy) | resource | | [aws_vpclattice_auth_policy.service_network_auth_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpclattice_auth_policy) | resource | | [aws_vpclattice_service.lattice_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpclattice_service) | resource | @@ -340,6 +359,7 @@ services = { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [ram\_share](#input\_ram\_share) | Configuration of the resources to share using AWS Resource Access Manager (RAM). VPC Lattice service networks and services can be shared using RAM.
More information about the format of this variable can be found in the "Usage - AWS RAM share" section of the README. | `any` | `{}` | no | | [service\_network](#input\_service\_network) | Amazon VPC Lattice Service Network information. You can either create a new Service Network or reference a current one (to associate Services or VPCs). Setting the `name` attribute will create a **new** service network, while using the attribute `identifier` will reference an **existing** service network.
More information about the format of this variable can be found in the "Usage - Service Network" section of the README. | `any` | `{}` | no | | [services](#input\_services) | Definition of the VPC Lattice Services to create. You can use this module to either create only Lattice services (not associated with any service network), or associated with a service network (if you create one or provide an identifier). You can define 1 or more Service using this module.
More information about the format of this variable can be found in the "Usage - Services" section of the README. | `any` | `{}` | no | | [tags](#input\_tags) | Tags to apply to all the resources created in this module. | `map(string)` | `{}` | no | @@ -351,6 +371,7 @@ services = { | Name | Description | |------|-------------| | [listeners\_by\_service](#output\_listeners\_by\_service) | VPC Lattice Listener and Rules. Per Lattice Service, each Listener is composed by the following attributes:
- `attributes` = Full output of **aws\_vpclattice\_listener**.
- `rules` = Full output of **aws\_vpclattice\_listener\_rule**. | +| [ram\_resource\_share](#output\_ram\_resource\_share) | AWS Resource Access Manager resource share. Full output of **aws\_ram\_resource\_share**. | | [service\_network](#output\_service\_network) | VPC Lattice resource attributes. Full output of **aws\_vpclattice\_service\_network**. | | [services](#output\_services) | VPC Lattice Services. The output is composed by the following attributes (per Service created):
- `attributes` = Full output of **aws\_vpclattice\_service**.
- `service_network_association` = Full output of **aws\_vpclattice\_service\_network\_service\_association**. | | [target\_groups](#output\_target\_groups) | VPC Lattice Target Groups. Full output of **aws\_vpclattice\_target\_group**. | diff --git a/VERSION b/VERSION index b82608c..1474d00 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.1.0 +v0.2.0 diff --git a/data.tf b/data.tf index 54d82d2..4184d82 100644 --- a/data.tf +++ b/data.tf @@ -13,6 +13,7 @@ locals { # Checking if Service Network auth policy should be created sn_auth_policy = (try(var.service_network.auth_type, "NONE") == "AWS_IAM") && (contains(keys(var.service_network), "auth_policy")) + # ---------- VPC Lattice Service variables --------- # Service Association - if Service Network is created or passed create_service_association = local.create_service_network || local.sn_identifier_provided @@ -23,6 +24,20 @@ locals { try({ for k, v in aws_vpclattice_target_group.lambda_lattice_target_group : k => v.id }, {}), try({ for k, v in aws_vpclattice_target_group.lattice_target_group : k => v.id }, {}), ) + + # ---------- AWS RAM SHARE ---------- + # Determining if a RAM resource share has to be created + create_ram_resource_share = contains(keys(var.ram_share), "resource_share_name") + # Determining if any RAM share configuration has to be created + config_ram_share = length(keys(var.ram_share)) > 0 + # Getting RAM resource share ARN + resource_share_arn = local.create_ram_resource_share ? aws_ram_resource_share.ram_resource_share[0].arn : try(var.ram_share.resource_share_arn, null) + # Determining if the service network needs to be shared + share_service_network = local.config_ram_share ? local.create_service_network && try(var.ram_share.share_service_network, true) : false + # Default of var.ram_share.share_services - if not defined, all the created services will be included + share_services = try(var.ram_share.share_services, keys(var.services)) + # Move var.ram_share.principals from list(string) to map(string) + principals_map = { for index, principal in try(var.ram_share.principals, []) : index => principal } } # Sanitizes tags for aws provider diff --git a/examples/ram_share/.header.md b/examples/ram_share/.header.md new file mode 100644 index 0000000..a371f4b --- /dev/null +++ b/examples/ram_share/.header.md @@ -0,0 +1,11 @@ +# Amazon VPC Lattice - Example: AWS RAM share + +This example shows how you can use the VPC Lattice module to share service networks and services using [AWS Resource Access Manager](https://aws.amazon.com/ram/) RAM. The example creates the following: + +* 1 VPC Lattice service network. +* 3 VPC Lattice services - basic configuration (without listeners or targets). +* 2 RAM shares. One is sharing the service network, and the other one is sharing 2 out of the 3 VPC Lattice services created. + +**NOTE**: Given we automate these examples before merging new PRs, there's an [AWS Systems Manager parameter](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) data source configured to obtain an Account ID from a parameter configured in the AWS Account we use for the automated tests. Take that into account when doing your own tests, and please remember to keep this configuration when doing any PR to this repository. + +In the `outputs.tf` file, you can see an example on how to obtain the information about the RAM share created (if applicable). diff --git a/examples/ram_share/README.md b/examples/ram_share/README.md new file mode 100644 index 0000000..e23f51e --- /dev/null +++ b/examples/ram_share/README.md @@ -0,0 +1,50 @@ + +# Amazon VPC Lattice - Example: AWS RAM share + +This example shows how you can use the VPC Lattice module to share service networks and services using [AWS Resource Access Manager](https://aws.amazon.com/ram/) RAM. The example creates the following: + +* 1 VPC Lattice service network. +* 3 VPC Lattice services - basic configuration (without listeners or targets). +* 2 RAM shares. One is sharing the service network, and the other one is sharing 2 out of the 3 VPC Lattice services created. + +**NOTE**: Given we automate these examples before merging new PRs, there's an [AWS Systems Manager parameter](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) data source configured to obtain an Account ID from a parameter configured in the AWS Account we use for the automated tests. Take that into account when doing your own tests, and please remember to keep this configuration when doing any PR to this repository. + +In the `outputs.tf` file, you can see an example on how to obtain the information about the RAM share created (if applicable). + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [aws](#requirement\_aws) | >= 4.66.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 4.66.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [vpclattice\_service\_network\_share](#module\_vpclattice\_service\_network\_share) | ../.. | n/a | +| [vpclattice\_services\_share](#module\_vpclattice\_services\_share) | ../.. | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_ram_resource_share.vpclattice_resource_share](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share) | resource | +| [aws_ssm_parameter.account_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_region](#input\_aws\_region) | AWS Region to use. | `string` | `"eu-west-1"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/examples/ram_share/main.tf b/examples/ram_share/main.tf new file mode 100644 index 0000000..ec67258 --- /dev/null +++ b/examples/ram_share/main.tf @@ -0,0 +1,53 @@ +# --- examples/ram_share/main.tf --- + +# Obtaining the AWS Account ID to share the resources with. +# If you are testing outside the module automation, either change this value with an AWS Account you own, or create a Parameter with this value +data "aws_ssm_parameter" "account_id" { + name = "account_id_share" +} + +module "vpclattice_service_network_share" { + source = "../.." + + service_network = { + name = "service-network" + auth_type = "NONE" + } + + ram_share = { + resource_share_name = "service-network-resource-share" + allow_external_principals = true + principals = [data.aws_ssm_parameter.account_id.value] + } +} + +module "vpclattice_services_share" { + source = "../.." + + services = { + service1 = { + name = "service1" + auth_type = "NONE" + } + service2 = { + name = "service2" + auth_type = "NONE" + } + service3 = { + name = "service3" + auth_type = "NONE" + } + } + + ram_share = { + resource_share_arn = aws_ram_resource_share.vpclattice_resource_share.arn + principals = [data.aws_ssm_parameter.account_id.value] + share_services = ["service1", "service2"] + } +} + +resource "aws_ram_resource_share" "vpclattice_resource_share" { + name = "services-resource-share" + allow_external_principals = true +} + diff --git a/examples/ram_share/outputs.tf b/examples/ram_share/outputs.tf new file mode 100644 index 0000000..1fb19ac --- /dev/null +++ b/examples/ram_share/outputs.tf @@ -0,0 +1 @@ +# --- examples/ram_share/outputs.tf --- \ No newline at end of file diff --git a/examples/ram_share/providers.tf b/examples/ram_share/providers.tf new file mode 100644 index 0000000..62b4839 --- /dev/null +++ b/examples/ram_share/providers.tf @@ -0,0 +1,16 @@ +# --- examples/ram_share/providers.tf --- + +terraform { + required_version = ">= 1.3.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.66.0" + } + } +} + +# Provider definition +provider "aws" { + region = var.aws_region +} \ No newline at end of file diff --git a/examples/ram_share/variablest.tf b/examples/ram_share/variablest.tf new file mode 100644 index 0000000..9e1d7e2 --- /dev/null +++ b/examples/ram_share/variablest.tf @@ -0,0 +1,7 @@ +# --- examples/ram_share/variables.tf --- + +variable "aws_region" { + type = string + description = "AWS Region to use." + default = "eu-west-1" +} \ No newline at end of file diff --git a/examples/target_groups/main.tf b/examples/target_groups/main.tf index 352e45b..297c2b0 100644 --- a/examples/target_groups/main.tf +++ b/examples/target_groups/main.tf @@ -78,7 +78,7 @@ resource "aws_lambda_function" "lambda" { data "archive_file" "python_lambda_package" { type = "zip" - source_file = "./function.py" + source_file = "${path.module}/function.py" output_path = "lambda_function.zip" } diff --git a/lambda_function.zip b/lambda_function.zip new file mode 100644 index 0000000..3a497a3 Binary files /dev/null and b/lambda_function.zip differ diff --git a/main.tf b/main.tf index 30c1043..15bc8b9 100644 --- a/main.tf +++ b/main.tf @@ -158,4 +158,42 @@ module "listeners" { service_identifier = try(each.value.identifier, aws_vpclattice_service.lattice_service[each.key].id) target_groups = local.target_group_ids tags = module.tags.tags_aws +} + +# ---------- AWS RESOURCE ACCESS MANAGER ---------- +# Create AWS RAM Resource Share (if name provided) +resource "aws_ram_resource_share" "ram_resource_share" { + count = local.create_ram_resource_share ? 1 : 0 + + name = var.ram_share.resource_share_name + allow_external_principals = try(var.ram_share.allow_external_principals, false) + + tags = module.tags.tags_aws +} + +# AWS RAM principal association +resource "aws_ram_principal_association" "ram_principal_association" { + for_each = { + for k, v in local.principals_map : k => v + if local.config_ram_share + } + + principal = each.value + resource_share_arn = local.resource_share_arn +} + +# AWS RAM resource association - VPC Lattice service network +resource "aws_ram_resource_association" "ram_service_network_association" { + count = local.share_service_network ? 1 : 0 + + resource_arn = aws_vpclattice_service_network.lattice_service_network[0].arn + resource_share_arn = local.resource_share_arn +} + +# AWS RAM resource association - VPC Lattice services +resource "aws_ram_resource_association" "ram_services_association" { + count = local.config_ram_share ? length(local.share_services) : 0 + + resource_arn = aws_vpclattice_service.lattice_service[local.share_services[count.index]].arn + resource_share_arn = local.resource_share_arn } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index 5dcc7ca..f702033 100644 --- a/outputs.tf +++ b/outputs.tf @@ -40,4 +40,11 @@ output "listeners_by_service" { - `attributes` = Full output of **aws_vpclattice_listener**. - `rules` = Full output of **aws_vpclattice_listener_rule**. EOF +} + +output "ram_resource_share" { + value = try(aws_ram_resource_share.ram_resource_share[0], null) + description = <<-EOF + AWS Resource Access Manager resource share. Full output of **aws_ram_resource_share**. +EOF } \ No newline at end of file diff --git a/tests/03_service_association b/tests/03_service_association.tftest.hcl similarity index 100% rename from tests/03_service_association rename to tests/03_service_association.tftest.hcl diff --git a/tests/04_target_groups b/tests/04_target_groups.tftest.hcl similarity index 100% rename from tests/04_target_groups rename to tests/04_target_groups.tftest.hcl diff --git a/tests/05_vpc_associations b/tests/05_vpc_associations.tftest.hcl similarity index 100% rename from tests/05_vpc_associations rename to tests/05_vpc_associations.tftest.hcl diff --git a/tests/06_ram_share.tftest.hcl b/tests/06_ram_share.tftest.hcl new file mode 100644 index 0000000..ea82fd5 --- /dev/null +++ b/tests/06_ram_share.tftest.hcl @@ -0,0 +1,14 @@ + +run "plan_ram_share" { + command = plan + module { + source = "./examples/ram_share" + } +} + +run "apply_ram_share" { + command = apply + module { + source = "./examples/ram_share" + } +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index 41c6631..4c96f4f 100644 --- a/variables.tf +++ b/variables.tf @@ -10,7 +10,7 @@ EOF default = {} validation { - error_message = "Invalid key in any of the definitions for var.service_network. Valid options include: \"name\", \"auth_type\", \"auth_policy\", \"identifier\"." + error_message = "Invalid key in any of the definitions for var.service_network. Valid options include: \"name\", \"auth_type\", \"auth_policy\", \"identifier\", \"identifier\"." condition = length(setsubtract(keys(try(var.service_network, {})), [ "name", "auth_type", @@ -86,6 +86,28 @@ EOF } } +variable "ram_share" { + type = any + description = <<-EOF + Configuration of the resources to share using AWS Resource Access Manager (RAM). VPC Lattice service networks and services can be shared using RAM. + More information about the format of this variable can be found in the "Usage - AWS RAM share" section of the README. +EOF + + default = {} + + validation { + error_message = "Invalid key in any of the definitions for var.ram_share. Valid options include: \"resource_share_arn\", \"resource_share_name\", \"allow_external_principals\", \"principals\", \"share_service_network\", \"share_services\"." + condition = length(setsubtract(keys(var.ram_share), [ + "resource_share_arn", + "resource_share_name", + "allow_external_principals", + "principals", + "share_service_network", + "share_services" + ])) == 0 + } +} + variable "tags" { description = "Tags to apply to all the resources created in this module." type = map(string)