From 182da9589df32cd2c8b67c2cfaee753b6cf03597 Mon Sep 17 00:00:00 2001 From: badra001 Date: Fri, 24 Feb 2023 12:09:15 -0500 Subject: [PATCH] initial submodule --- share-resources/credentials.org_master.tf.off | 5 + share-resources/data.org_master.tf | 8 ++ share-resources/data.tf | 1 + share-resources/defaults.tf | 1 + share-resources/main.tf | 17 +++ share-resources/module_name.tf | 3 + share-resources/orgs.tf | 57 ++++++++++ share-resources/prefixes.tf | 1 + share-resources/share.tf | 100 ++++++++++++++++++ share-resources/variables.common.tf | 1 + share-resources/variables.common.vpc.tf | 1 + share-resources/variables.create.tf | 1 + share-resources/variables.org_master.tf | 11 ++ share-resources/variables.subnets.tf | 14 +++ share-resources/variables.tf | 37 +++++++ share-resources/version.tf | 1 + share-resources/versions.tf | 30 ++++++ 17 files changed, 289 insertions(+) create mode 100644 share-resources/credentials.org_master.tf.off create mode 100644 share-resources/data.org_master.tf create mode 120000 share-resources/data.tf create mode 120000 share-resources/defaults.tf create mode 100644 share-resources/main.tf create mode 100644 share-resources/module_name.tf create mode 100644 share-resources/orgs.tf create mode 120000 share-resources/prefixes.tf create mode 100644 share-resources/share.tf create mode 120000 share-resources/variables.common.tf create mode 120000 share-resources/variables.common.vpc.tf create mode 120000 share-resources/variables.create.tf create mode 100644 share-resources/variables.org_master.tf create mode 100644 share-resources/variables.subnets.tf create mode 100644 share-resources/variables.tf create mode 120000 share-resources/version.tf create mode 100644 share-resources/versions.tf diff --git a/share-resources/credentials.org_master.tf.off b/share-resources/credentials.org_master.tf.off new file mode 100644 index 0000000..12baf92 --- /dev/null +++ b/share-resources/credentials.org_master.tf.off @@ -0,0 +1,5 @@ +provider "aws" { + alias = "org_master" + region = var.org_master_region + profile = var.org_master_profile +} diff --git a/share-resources/data.org_master.tf b/share-resources/data.org_master.tf new file mode 100644 index 0000000..900769e --- /dev/null +++ b/share-resources/data.org_master.tf @@ -0,0 +1,8 @@ +data "aws_caller_identity" "org_master_account" { + provider = aws.org_master +} + +data "aws_arn" "org_master_account" { + provider = aws.org_master + arn = data.aws_caller_identity.org_master_account.arn +} diff --git a/share-resources/data.tf b/share-resources/data.tf new file mode 120000 index 0000000..995624d --- /dev/null +++ b/share-resources/data.tf @@ -0,0 +1 @@ +../common/data.tf \ No newline at end of file diff --git a/share-resources/defaults.tf b/share-resources/defaults.tf new file mode 120000 index 0000000..a5556ac --- /dev/null +++ b/share-resources/defaults.tf @@ -0,0 +1 @@ +../common/defaults.tf \ No newline at end of file diff --git a/share-resources/main.tf b/share-resources/main.tf new file mode 100644 index 0000000..feb6a63 --- /dev/null +++ b/share-resources/main.tf @@ -0,0 +1,17 @@ +/* +* # About aws-vpc-setup :: share-resources +* +*/ + +locals { + account_id = var.account_id != "" ? var.account_id : data.aws_caller_identity.current.account_id + account_environment = data.aws_arn.current.partition == "aws-us-gov" ? "gov" : "ew" + region = data.aws_region.current.name + region_short = join("", [for c in split("-", local.region) : substr(c, 0, 1)]) + + base_tags = { + "boc:tf_module_version" = local._module_version + "boc:tf_module_name" = lookup(local._module_names, local._module_name, local._module_names["_main_"]) + "boc:created_by" = "terraform" + } +} diff --git a/share-resources/module_name.tf b/share-resources/module_name.tf new file mode 100644 index 0000000..d7a6e20 --- /dev/null +++ b/share-resources/module_name.tf @@ -0,0 +1,3 @@ +locals { + _module_name = "share-resources" +} diff --git a/share-resources/orgs.tf b/share-resources/orgs.tf new file mode 100644 index 0000000..0f7ae9d --- /dev/null +++ b/share-resources/orgs.tf @@ -0,0 +1,57 @@ +# because we cannot delegate an orgs administrator in govcloud, we have to use the org master account and west region +# https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-organizations.html + +data "aws_organizations_organization" "org" { + provider = aws.org_master +} + +data "aws_organizations_organizational_unit_descendant_accounts" "accounts" { + provider = aws.org_master + parent_id = data.aws_organizations_organization.org.roots[0].id +} + +data "aws_organizations_resource_tags" "accounts" { + provider = aws.org_master + for_each = { for a in data.aws_organizations_organizational_unit_descendant_accounts.accounts.accounts : a.id => a } + resource_id = each.key +} + +# data "aws_organizations_organizational_units" "ou1" { +# provider = aws.org_master +# parent_id = data.aws_organizations_organization.org.roots[0].id +# } +# +# data "aws_organizations_organizational_units" "ou2" { +# provider = aws.org_master +# for_each = { for ou in data.aws_organizations_organizational_units.ou1.children: ou.id => ou } +# parent_id = each.key +# } +# +# no apparent way to get an ARN from a single ID, so we will construct it +# we need the account_id of the org_master, the org id, and the OU +# { +# "arn" = "arn:aws-us-gov:organizations::252903981224:ou/o-8qizkt65j8/ou-9go7-6am3aund" +# "id" = "ou-9go7-6am3aund" +# "name" = "DAS" +# }, + + +## data "aws_organizations_organizational_units" "ou3" { +## provider = aws.org_master +## for_each = [ for k,v in data.aws_organizations_organizational_units.ou2: { for x,y in v.children: y.id => merge(y,{parent_id=k,parent_name=v.name}) } ] +## parent_id = each.key +## } + +## output "org" { +## value = data.aws_organizations_organization.org +## } +## output "org_ou1" { +## value = data.aws_organizations_organizational_units.ou1 +## } +## output "org_ou2" { +## value = data.aws_organizations_organizational_units.ou2 +## } +## # output "org_ou3" { +## # # value = data.aws_organizations_organizational_units.ou2 +## # value = [ for k,v in data.aws_organizations_organizational_units.ou2: { for x,y in v.children: y.id => merge(y,{parent_id=k,parent_name=y.name}) } ] +## # } diff --git a/share-resources/prefixes.tf b/share-resources/prefixes.tf new file mode 120000 index 0000000..7e265d5 --- /dev/null +++ b/share-resources/prefixes.tf @@ -0,0 +1 @@ +../common/prefixes.tf \ No newline at end of file diff --git a/share-resources/share.tf b/share-resources/share.tf new file mode 100644 index 0000000..f909785 --- /dev/null +++ b/share-resources/share.tf @@ -0,0 +1,100 @@ +locals { + share_ou_arns = { for ou in var.share_organizational_unit_list : ou => + format("arn:%v:organizations::%v:ou/%v/%v", data.aws_arn.org_master_account.partition, data.aws_caller_identity.org_master_account.account_id, data.aws_organizations_organization.org.id, ou) } + subnets = { for sn in var.private_subnets_ids : sn.id => + merge( + { share = lookup(sn.tags, "boc:vpc:route-table", null) != "attachment" && lookup(sn.tags, "share", true) ? true : false }, + sn, + ) } +} + +data "aws_organizations_resource_tags" "accounts" { + provider = aws.org_master + for_each = var.share_enabled ? toset(var.share_account_list) : toset([]) + resource_id = each.key +} + +data "aws_organizations_resource_tags" "organizational_units" { + provider = aws.org_master + for_each = var.share_enabled ? toset(var.share_organizational_unit_list) : toset([]) + resource_id = each.key +} + +resource "aws_ram_resource_share" "subnets" { + for_each = var.share_enabled ? local.subnets : {} + name = format("%v_%v", var.vpc_full_name, each.value.label) + allow_external_principals = false + + tags = merge( + local.base_tags, + { + Environment = "csvd:infrastructure" + CostAllocation = "csvd:infrastructure:network" + Name = format("%v_%v", var.vpc_full_name, each.value.label) + "boc:vpc:subnet_label" = each.value.label + "boc:vpc:account" = data.aws_caller_identity.current.account_id + }, + var.tags, + ) +} + +## resource "aws_ram_principal_association" "subnets" { +## for_each = false && local.organizations_enabled ? { for sn in module.subnets.private_subnets_ids : sn.id => sn if lookup(sn.tags, "boc:vpc:route-table", null) != "attachment" } : {} +## principal = data.aws_organizations_organization.org[0].arn +## resource_share_arn = aws_ram_resource_share.subnets[each.key].arn +## } +## +## resource "aws_ram_resource_association" "subnets" { +## for_each = false && local.organizations_enabled ? { for sn in module.subnets.private_subnets_ids : sn.id => sn if lookup(sn.tags, "boc:vpc:route-table", null) != "attachment" } : {} +## resource_arn = each.value.arn +## resource_share_arn = aws_ram_resource_share.subnets[each.key].arn +## } + +#--- +# accounts +#--- +locals { + share_account_map = { for p in setproduct(keys(local.subnets), var.share_account_list) : format("%v:%v", p[0], p[1]) => { + label = format("%v:%v", p[0], p[1]) + subnet_id = p[0] + subnet_arn = local.subnets[p[0]].arn + account_id = p[1] + } } +} + +resource "aws_ram_principal_association" "subnets_accounts" { + for_each = var.share_enabled ? local.share_account_map : {} + principal = each.value.account_id + resource_share_arn = aws_ram_resource_share.subnets[each.value.subnet_id].arn +} + +resource "aws_ram_resource_association" "subnets_accounts" { + for_each = var.share_enabled ? local.share_account_map : {} + resource_arn = each.value.subnet_arn + resource_share_arn = aws_ram_resource_share.subnets[each.value.subnet_id].arn +} + +#--- +# organizational units +#--- +locals { + share_organizatonal_unit_map = { for p in setproduct(keys(local.subnets), keys(local.share_ou_arns)) : format("%v:%v", p[0], p[1]) => { + label = format("%v:%v", p[0], p[1]) + subnet_id = p[0] + subnet_arn = local.subnets[p[0]].arn + organization_unit_id = p[1] + organization_unit_arn = local.share_ou_arns[p[1]] + } } +} + +resource "aws_ram_principal_association" "subnets_organizational_units" { + for_each = var.share_enabled ? local.share_organizatonal_unit_map : {} + principal = each.value.organization_unit_arn + resource_share_arn = aws_ram_resource_share.subnets[each.value.subnet_id].arn +} + +resource "aws_ram_resource_association" "subnets_organizational_units" { + for_each = var.share_enabled ? local.share_organizational_unit_map : {} + resource_arn = each.value.subnet_arn + resource_share_arn = aws_ram_resource_share.subnets[each.value.subnet_id].arn +} diff --git a/share-resources/variables.common.tf b/share-resources/variables.common.tf new file mode 120000 index 0000000..7439ed8 --- /dev/null +++ b/share-resources/variables.common.tf @@ -0,0 +1 @@ +../common/variables.common.tf \ No newline at end of file diff --git a/share-resources/variables.common.vpc.tf b/share-resources/variables.common.vpc.tf new file mode 120000 index 0000000..5e77d37 --- /dev/null +++ b/share-resources/variables.common.vpc.tf @@ -0,0 +1 @@ +../common/variables.common.vpc.tf \ No newline at end of file diff --git a/share-resources/variables.create.tf b/share-resources/variables.create.tf new file mode 120000 index 0000000..de1275b --- /dev/null +++ b/share-resources/variables.create.tf @@ -0,0 +1 @@ +../common/variables.create.tf \ No newline at end of file diff --git a/share-resources/variables.org_master.tf b/share-resources/variables.org_master.tf new file mode 100644 index 0000000..012e965 --- /dev/null +++ b/share-resources/variables.org_master.tf @@ -0,0 +1,11 @@ +variable "org_master_profile" { + description = "AWS Organization Master account profile" + type = string + default = "252903981224-ma5-gov" +} + +variable "org_master_region" { + description = "AWS Organization Master region (see docs: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-organizations.html)" + type = string + default = "us-gov-west-1" +} diff --git a/share-resources/variables.subnets.tf b/share-resources/variables.subnets.tf new file mode 100644 index 0000000..dc6bb9d --- /dev/null +++ b/share-resources/variables.subnets.tf @@ -0,0 +1,14 @@ +# from routing/variables.f + +variable "private_subnets_ids" { + description = "List of private subnet objects including: subnet, label, availability_zone, id, arn, tags" + type = list(object({ + subnet = string + label = string + availability_zone = string + id = string + arn = optional(string, null) + tags = optional(map(string), {}) + })) + default = [] +} diff --git a/share-resources/variables.tf b/share-resources/variables.tf new file mode 100644 index 0000000..4ee7a96 --- /dev/null +++ b/share-resources/variables.tf @@ -0,0 +1,37 @@ +variable "org_master_profile" { + description = "AWS Organization Master account profile" + type = string + default = null + # default = "252903981224-ma5-gov" +} + +variable "org_master_region" { + description = "AWS Organization Master region (see docs: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-organizations.html)" + type = string + default = null + # default = "us-gov-west-1" +} + +variable "share_enabled" { + description = "Flag indiciating whether to share resources to other accounts and OUs" + type = bool + default = false +} + +variable "share_account_list" { + description = "List of AWS Account IDs to share VPC/subnets into. If the account is not part of the organziation, this will produce an error." + type = list(string) + default = [] +} + +variable "share_organizational_unit_list" { + description = "List of Organizational Unit IDs to share VPC/subnets into. This does not check if they are OUs." + type = list(string) + default = [] +} + +## variable "share_organization" { +## description = "Flag to share to entire Organization" +## type = bool +## default = false +## } diff --git a/share-resources/version.tf b/share-resources/version.tf new file mode 120000 index 0000000..b83c5b7 --- /dev/null +++ b/share-resources/version.tf @@ -0,0 +1 @@ +../common/version.tf \ No newline at end of file diff --git a/share-resources/versions.tf b/share-resources/versions.tf new file mode 100644 index 0000000..59690ce --- /dev/null +++ b/share-resources/versions.tf @@ -0,0 +1,30 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.0.0" + configuration_aliases = [aws.org_master] + } + null = { + source = "hashicorp/null" + version = ">= 3.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.0" + } + template = { + source = "hashicorp/template" + version = ">= 2.0" + } + ldap = { + source = "trevex/ldap" + version = ">= 0.5.4" + } + local = { + source = "hashicorp/local" + version = ">= 1.0.0" + } + } + required_version = ">= 1.0.0" +}