diff --git a/tags/main.tf b/tags/main.tf index 1c14966..2b4dcec 100644 --- a/tags/main.tf +++ b/tags/main.tf @@ -1,4 +1,110 @@ +/* boc-nts :: tags +* # About +* +* This submodule allows one to easily set a number of tags, primarily the [finops tags](https://github.e.it.census.gov/terraform/cloud-information/blob/master/aws/documentation/naming-tagging-standard/tags/finops.md). +* Use of this module is **highly** recommended as it reduces errors from the wrong number of zeros in the finops project number, and does some validation +* checking as well. This takes as input a YAML file, but may also take the values in environment variables. A YAML file is recommended. +* +* ## Features +* * Formatting of FinOps Tags +* * project number +* * project name +* * project role +* * Merging legacy FinOps tags into new tag +* * Project Number +* * Project Name +* * ProjectRole +* * and many combinations +* * Migration Acceleration Program (MAP) Tagging +* +* These features are in progress. +* +* * CostAllocation +* * Environment +* * infrastructure +* * aws_organization +* +* ## YAML Fields +* ### finops +* This section takes four attributes +* * number: an integer corresponding to the assigned FinOps Project Number (>= 0) +* * name: string with the assigned FinOps Project Name (lowercase, underscores) +* * role: a string to append to the finops project name when used with a prefix of +, or to use verbatim. There is no need to +* repeat the same string in project name, simply use the + preix. +* * roles: a list of strings for which the module output `finops_roles[key]` will be created. We use this when we need +* to define a number of roles and make them selectable in the resource `tags()` attributes. +* +* ## Usage +* +* Create a terraform file such as `tags.tf` with the module call. +* +* ```hcl +* # tags.tf +* module "tags" { +* source = "git@github.e.it.census.gov:terraform-modules/boc-nts//tags" +* filename = format("%v/%v", path.root, "tags.yml") +* +* # optional, use to convert old finops and preserve Environemnt and CostAllocation tags +* legacy_tags = merge( +* var.account_tags, +* var.infrastructure_tags, +* var.application_tags, +* ) +* } +* ``` +* +* The module uses `tags.yml`, which looks like this: +* +* ```yaml +* # tags.yml +* finops: +* number: 31415 +* name: org_app_env_sample +* roles: +* - lambda +* - log +* - parameter +* - role +* - s3 +* - securitygroup +* ``` +* +* Then, you'd use a couple of outputs of the module where tags would be present. Here is an example: +* +* ```hcl +* resource "aws_ssm_parameter" "config" { +* name = local.ssm_parameter_name +* description = format("Configuration parameter for %v", "my-parameter" +* type = "String" +* value = jsonencode({parameter="value"}) +* +* tags = merge( +* local.base_tags, +* module.tags.tags, +* module.tags.finops_roles["parameter"], +* ) +* } +* ``` +* +* This will create a resoruce withe the following tags (assumes CostAllocation, Organization +* and Environment are set in the `var.*_tags` variables already: +* +* ```hcl +* tags = { +* "CostAllocation" = "directorate:org:app" +* "Organization" = "census:directorate:org" +* "boc:created_by" = "terraform" +* "finops_project_name" = "org_app_env_sample" +* "finops_project_number" = "fs0000031415" +* "finops_project_role" = "org_app_env_sample_parameter" +* } +* ``` +*/ + locals { tags_in = var.filename != null && try(fileexists(var.filename), false) ? yamldecode(file(var.filename)) : yamldecode("{}") tags_filenames_in = length(var.filenames) > 0 ? { for f in var.filenames : f => yamldecode(file(f)) if fileexists(f) } : {} + validity_checks = yamldecode(file("${path.module}/validity.yml")) } + + diff --git a/tags/tags.finops.tf b/tags/tags.finops.tf index 804c037..c14b16b 100644 --- a/tags/tags.finops.tf +++ b/tags/tags.finops.tf @@ -7,7 +7,7 @@ locals { project_role = local._finops.role != null ? replace(replace(local._finops.role, "+", format("%v_", local._finops.name)), "/[^a-z0-9_]/", "") : null } finops_tags = { for k, v in local._finops_tags : k => v if v != null && k != "prefix" } - finops_roles = [for r in try(local.tags_in.finops["roles"], try(var.finops["roles"],[])) : lower(r)] + finops_roles = [for r in try(local.tags_in.finops["roles"], try(var.finops["roles"], [])) : lower(r)] } resource "terraform_data" "finops" { diff --git a/tags/tags.tf b/tags/tags.tf new file mode 100644 index 0000000..5511570 --- /dev/null +++ b/tags/tags.tf @@ -0,0 +1,54 @@ +locals { + _infrastructure = length(try(local.tags_in.infrastructure, 0)) == 0 ? null : local.tags_in.infrastructure + _aws_organization = length(try(local.tags_in.aws_organization, 0)) == 0 ? null : local.tags_in.aws_organization + _cost_allocation = length(try(local.tags_in.cost_allocation, 0)) == 0 ? null : local.tags_in.cost_allocation + _environment = length(try(local.tags_in.environment, 0)) == 0 ? null : local.tags_in.environment +} + +resource "terraform_data" "infrastructure" { + count = local._infrastructure != null ? 1 : 0 + input = local._infrastructure + + lifecycle { + precondition { + condition = contains(local.validity_checks.infrastructure, local._infrastructure) + error_message = "Invalid infrastructure organization." + } + } +} + +resource "terraform_data" "aws_organization" { + count = local._aws_organization != null ? 1 : 0 + input = local._aws_organization + + lifecycle { + precondition { + condition = contains(local.validity_checks.aws_organization, local._aws_organization) + error_message = "Invalid AWS organization." + } + } +} + +resource "terraform_data" "cost_allocation" { + count = local._cost_allocation != null ? 1 : 0 + input = local._cost_allocation + + lifecycle { + precondition { + condition = contains(local.validity_checks.cost_allocation, local._cost_allocation) + error_message = "Invalid AWS organization." + } + } +} + +resource "terraform_data" "environment" { + count = local._environment != null ? 1 : 0 + input = local._environment + + lifecycle { + precondition { + condition = contains(local.validity_checks.environment, local._environment) + error_message = "Invalid AWS organization." + } + } +} diff --git a/tags/validity.yml b/tags/validity.yml new file mode 100644 index 0000000..f7164f3 --- /dev/null +++ b/tags/validity.yml @@ -0,0 +1,41 @@ +aws_organization: + - ent-ew: 0 + - ent-gov: 0 + - lab-gov: 1 +infrastructure: + - csvd: 0 + - tco: 1 + - ois: 2 +environment: + - common + - cre + - dev + - ite + - prod + - qa + - sa + - services + - stage + - test + - uat +cost_allocation: + directorate: + - adcom + - addcp + - addp + - adep + - adfo + - adrm + - dir + - ocao + - ocfo + - ocio + - ppsi + category: + - core + - multi + - external + - shared + - cedsci + division: +