From 998e29833def3aed429699cd3e657018343e2468 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Tue, 5 Mar 2024 20:42:26 +0200 Subject: [PATCH] chore: address review suggestion --- README.md | 66 ++++++++----------- data.tf | 11 ++++ examples/complete/.terraform.lock.hcl | 39 +++++++++++ examples/complete/example.yaml | 8 +-- ....us-east-1.tfvars => fixtures.auto.tfvars} | 12 ++-- examples/complete/main.tf | 4 +- .../complete/providers.tf | 0 examples/complete/secrets.sops.tf | 4 +- examples/complete/variables.tf | 2 +- main.tf | 20 ++---- outputs.tf | 5 +- secrets.sops.tf | 25 ------- variables.tf | 2 +- 13 files changed, 105 insertions(+), 93 deletions(-) create mode 100644 data.tf create mode 100644 examples/complete/.terraform.lock.hcl rename examples/complete/{fixtures.us-east-1.tfvars => fixtures.auto.tfvars} (75%) rename providers.tf => examples/complete/providers.tf (100%) delete mode 100644 secrets.sops.tf diff --git a/README.md b/README.md index 994a58c..b89d891 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,13 @@ [![Release](https://img.shields.io/github/release/masterpointio/terraform-datadog-users.svg)](https://github.com/masterpointio/terraform-datadog-users/releases/latest) -This Terraform module is designed to create and manage Datadog user accounts, with a specific focus on security and sensitive data handling. +This Terraform module is designed to create and manage Datadog user accounts. -To ensure the secure handling of DataDog sensitive data for datadog/datadog provider, the module is designed to work with the [SOPS (Secrets OPerationS) provider](https://github.com/mozilla/sops). SOPS is a tool for encrypting and decrypting files containing sensitive data, often used in conjunction with Terraform to manage secrets. +The users are associated with one of the three [out-of-the-box roles](https://docs.datadoghq.com/account_management/rbac/permissions/): -The module utilizes [terraform-secrets-helper](https://github.com/masterpointio/terraform-secrets-helper/tree/main) module - a helper that provides a standard way of managing secrets from different sources, incuding SOPS files. +- Datadog Admin +- Datadog Standard +- Datadog Read Only ## Usage @@ -18,8 +20,10 @@ module "datadog_users" { users = [ { access_roles = { - "datadog" = true, - "aws" = true, + "datadog" = { + enabled = true, + role = "standard" + }, }, email = "jane.smith@example.com", name = "Jane Smith", @@ -27,45 +31,28 @@ module "datadog_users" { username = "janesmith" } ] - - secret_mapping = [ - { - name = "datadog_api_key" - file = "example.yaml" - type = "sops" - }, - { - name = "datadog_app_key" - file = "example.yaml" - type = "sops" - } - ] } ``` Check out [examples/complete](examples/complete) for the full example. +To ensure the secure handling of DataDog sensitive data for datadog/datadog provider, the module's example is designed to work with the [SOPS (Secrets OPerationS)](https://github.com/mozilla/sops) provider. SOPS is a tool for encrypting and decrypting files containing sensitive data, often used in conjunction with Terraform to manage secrets. The example also utilizes [terraform-secrets-helper](https://github.com/masterpointio/terraform-secrets-helper/tree/main) module - a helper that provides a standard way of managing secrets from different sources, incuding SOPS files. + ❗ We recommend to use AWS KMS, GCP KMS, Azure Key Vault for SOPS files encryption. Don't use the secrets from the example in your real configuration! Here are some basic SOPS operations that help you to work with the example: -- SOPS provider configuration for the example: +- Pass `age` key to SOPS provider configuration: ```sh cd ./example/complete export SOPS_AGE_KEY_FILE=key.txt ``` -- Encryption - -```sh -sops --encrypt --age age1uafwjn52f8qvdeyqgn5epens4nwpqaqld8ln47xs8an003r3gudqxpzt7m example.raw.yaml > example.yaml -``` - -- Decryption +- Encryption/decryption via SOPS editior ```sh -sops --age age1uafwjn52f8qvdeyqgn5epens4nwpqaqld8ln47xs8an003r3gudqxpzt7m example.yaml +sops example.yaml ``` @@ -86,27 +73,28 @@ sops --age age1uafwjn52f8qvdeyqgn5epens4nwpqaqld8ln47xs8an003r3gudqxpzt7m exampl ## Modules -| Name | Source | Version | -| -------------------------------------------------------- | ---------------------------- | ------- | -| [secrets](#module_secrets) | masterpointio/helper/secrets | 0.2.0 | +No modules. ## Resources -| Name | Type | -| -------------------------------------------------------------------------------------------------------------- | ----------- | -| [datadog_user.users](https://registry.terraform.io/providers/datadog/datadog/latest/docs/resources/user) | resource | -| [datadog_role.standard](https://registry.terraform.io/providers/datadog/datadog/latest/docs/data-sources/role) | data source | +| Name | Type | +| --------------------------------------------------------------------------------------------------------------- | ----------- | +| [datadog_user.users](https://registry.terraform.io/providers/datadog/datadog/latest/docs/resources/user) | resource | +| [datadog_role.admin](https://registry.terraform.io/providers/datadog/datadog/latest/docs/data-sources/role) | data source | +| [datadog_role.read_only](https://registry.terraform.io/providers/datadog/datadog/latest/docs/data-sources/role) | data source | +| [datadog_role.standard](https://registry.terraform.io/providers/datadog/datadog/latest/docs/data-sources/role) | data source | ## Inputs -| Name | Description | Type | Default | Required | -| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | :------: | -| [secret_mapping](#input_secret_mapping) | The list of secret mappings the application will need.
This creates secret values for the component to consume at `local.secrets[name]`. |
list(object({
name = string
type = string
path = optional(string, null)
file = string
}))
| `[]` | no | -| [users](#input_users) | n/a |
list(object({
access_roles = map(bool)
disabled = optional(bool, false)
email = string
name = string
role = string
send_user_invitation = optional(bool, true)
username = string
}))
| n/a | yes | +| Name | Description | Type | Default | Required | +| ------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | :------: | +| [users](#input_users) | n/a |
list(object({
access_roles = map(any)
disabled = optional(bool, false)
email = string
name = string
role = string
send_user_invitation = optional(bool, true)
username = string
}))
| n/a | yes | ## Outputs -No outputs. +| Name | Description | +| -------------------------------------------------------------------------- | ------------------------------------------------------ | +| [datadog_users](#output_datadog_users) | A map of all Datadog user resources keyed by username. | diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..78430ac --- /dev/null +++ b/data.tf @@ -0,0 +1,11 @@ +data "datadog_role" "standard" { + filter = "Datadog Standard Role" +} + +data "datadog_role" "admin" { + filter = "Datadog Admin Role" +} + +data "datadog_role" "read_only" { + filter = "Datadog Read Only Role" +} diff --git a/examples/complete/.terraform.lock.hcl b/examples/complete/.terraform.lock.hcl new file mode 100644 index 0000000..9cc73da --- /dev/null +++ b/examples/complete/.terraform.lock.hcl @@ -0,0 +1,39 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/carlpett/sops" { + version = "0.7.2" + constraints = ">= 0.5.0, ~> 0.5, >= 0.7.0" + hashes = [ + "h1:nWrLW+9JjGLwfss4T7pTaE+JiZlBJQGoYxt4pDe5OE8=", + "zh:43f218054ea3a72c9756bf989aeebb9d0f23b66fd08e9fb4ae75d4f921295e82", + "zh:57fd326388042a6b7ecd60f740f81e5ef931546c4f068f054e7df34acf65d190", + "zh:87b970db8c137f4c2fcbff7a5705419a0aea9268ae0ac94f1ec5b978e42ab0d2", + "zh:9e3b67b89ac919f01731eb0466baa08ce0721e6cf962fe6752e7cc526ac0cba0", + "zh:c028f67ef330be0d15ce4d7ac7649a2e07a98ed3003fca52e0c72338b5f481f8", + "zh:c29362e36a44480d0d9cb7d90d1efba63fe7e0e94706b2a07884bc067c46cbc7", + "zh:d5bcfa836244718a1d564aa96eb7d733b4d361b6ecb961f7c5bcd0cadb1dfd05", + ] +} + +provider "registry.terraform.io/datadog/datadog" { + version = "3.37.0" + constraints = ">= 3.14.0, ~> 3.14" + hashes = [ + "h1:D5lzAUqnEF3458Fu5wxNc4KaCy46CgcPIHM+b1e71YU=", + "zh:0bf149256e2166d77a7cea60adcf1486bf18c65120caccba3f9caf643a0937a7", + "zh:246c40bbb198f918a7380c059ac2e9110832215e0e00c06fdd8a5c34fb01f797", + "zh:3ff8667f41e9f787de6dae59c3ee447177c062613787368e7f8ae0b1efdbe25f", + "zh:47e9008c9aa0e58e0c7eb71cac0408a74399180961cd9f23807fedb3a52b4df9", + "zh:620f32bfcdfbc0ce2316d5e3b5587cdbace901706d08be70f591ef22f0cda40b", + "zh:760fc52ff88ff34f2e7ed9f2d78dc2f7509c06faa133b811bd74fdb92032ae19", + "zh:805ae94bbec4a213859bbb0f3d98a013792f55b782996fecc40b39933b83afed", + "zh:88b040e6cd964e9bef62b5eaeed8330377a40fc197de43df842741fea241bc78", + "zh:8dee6c95f23479bb7469c2648351a8f42f696deeab59287385f2ac32868e444f", + "zh:bb0c18c9e85d19cf176999e0e636a5461c2a041ed7cfe560632b9bba3eb3085b", + "zh:d4f133a24d0881c772d73ab4b4b5e7f28a02a26eca1674c5c77a9bd983151ad7", + "zh:dc488ef450760162f3d4306497a065649fe65967eadd2a7a9a2239f4ba751a9c", + "zh:dcd88c3747c9a348c317b4a1ecadb7756de879085c6014cf368d63ce60526176", + "zh:f0b1eb479c13fd0a4f724e7ada1bd08fc69032ecc866619800e2742e23882730", + ] +} diff --git a/examples/complete/example.yaml b/examples/complete/example.yaml index 7557c70..1a63f89 100644 --- a/examples/complete/example.yaml +++ b/examples/complete/example.yaml @@ -1,5 +1,5 @@ -datadog_api_key: ENC[AES256_GCM,data:joPOPI58VO5E2g==,iv:G3BamrS3ANDMhJqjyZbn1YhAqf2GJ7g7DdVivrYVzDw=,tag:k2sGvVtoxznn7U8x8I7oUw==,type:int] -datadog_app_key: ENC[AES256_GCM,data:GeerHEomnls2Cg==,iv:9uiNp5vvv/8/6sqNix28FRm1btWy6CF3fnGD3RV3oMI=,tag:LbGRJu7Bz8HdJYR+6iO/vQ==,type:int] +datadog_api_key: ENC[AES256_GCM,data:cGxuKLw01YXMzg==,iv:sqCip8ibQM10cZqPlb3H9xRojvtD45RU5ZP+3WmlWFQ=,tag:wyIH0RnYdraYyFl3BlGEhw==,type:int] +datadog_app_key: ENC[AES256_GCM,data:tjZKfOL4Keulow==,iv:qaVRDuuDa5EY/dvqg1eH5ZtBcuvAIdyRO2FItl+7Rok=,tag:EUql9eObFKKtolab/Zi1MA==,type:int] sops: kms: [] gcp_kms: [] @@ -15,8 +15,8 @@ sops: ejRyZCthYkxvcnN0bHRJVG5RZlo1UEEKDoY/9Bf5OnbMQoOk7wdsTMhTHfmVLHUz bYEgOsOwxlL+YEgme0vRFhL3MXGCRJwZISDdGTkFFYz0Rfp4CWksew== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-03-05T15:02:14Z" - mac: ENC[AES256_GCM,data:PlVVXBdphDgl1AkQEk4ZS/EV5KXT6IqPDmzQz7LQvrrXQstuXmpY/7TABWJDEF8Y+SS92J4FKfjFropK3Uf5GG5FnD06xjp0TEVAN6gG7LtyCBqGfYe0rYLRxD3cFmFa/DHitNnnHbfM4545UJgQxVFgLAHcRrP4hOhtqCBXpiI=,iv:qfqqIqyqxEW2zH47STMPR9S83Ky5PQ9owvuLo8VJRKE=,tag:VeAfgPnZwwvnTmE7SgbZww==,type:str] + lastmodified: "2024-03-05T18:39:37Z" + mac: ENC[AES256_GCM,data:T1ziXhQOuU7pvRVVA9kewyn5efhrrLZ1TYarfVCjF/HL09iRXTTlF0ZkRTOjyqoRoXd+0MEfaVvKlRptcE1WxoR4saOCyju+k3zVQ0i1suOvfmwueHfpZvAetClC2Bwg09iOrR+lE8wz7WnqIBkup53tshjJhpXif9TknnSP2vI=,iv:LovT/poawV4dHPAs0GkZ9tyrY/ClHPAah6xDqa67/J0=,tag:LyZaZ0cHN9namt8PvhOMdg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 diff --git a/examples/complete/fixtures.us-east-1.tfvars b/examples/complete/fixtures.auto.tfvars similarity index 75% rename from examples/complete/fixtures.us-east-1.tfvars rename to examples/complete/fixtures.auto.tfvars index 9e0c8e8..008e224 100644 --- a/examples/complete/fixtures.us-east-1.tfvars +++ b/examples/complete/fixtures.auto.tfvars @@ -1,8 +1,10 @@ users = [ { access_roles = { - "datadog" = true, - "aws" = false, + "datadog" = { + enabled = true, + role = "standard" + }, }, email = "john.doe@example.com", name = "John Doe", @@ -11,8 +13,10 @@ users = [ }, { access_roles = { - "datadog" = true, - "aws" = true, + "datadog" = { + enabled = true, + role = "read_only" + }, }, email = "jane.smith@example.com", name = "Jane Smith", diff --git a/examples/complete/main.tf b/examples/complete/main.tf index ae45019..f2b0872 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -1,6 +1,4 @@ module "datadog_user" { source = "../.." - - users = var.users - secret_mapping = var.secret_mapping + users = var.users } diff --git a/providers.tf b/examples/complete/providers.tf similarity index 100% rename from providers.tf rename to examples/complete/providers.tf diff --git a/examples/complete/secrets.sops.tf b/examples/complete/secrets.sops.tf index 7f4b6f6..983782a 100644 --- a/examples/complete/secrets.sops.tf +++ b/examples/complete/secrets.sops.tf @@ -1,6 +1,6 @@ module "secrets" { - source = "masterpointio/helper/secrets" - version = "0.2.0" + source = "../../../terraform-secrets-helper/" #"masterpointio/helper/secrets" + #version = "0.2.0" secret_mapping = var.secret_mapping } diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 6438ea6..e86074f 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -1,6 +1,6 @@ variable "users" { type = list(object({ - access_roles = map(bool) + access_roles = map(any) disabled = optional(bool, false) email = string name = string diff --git a/main.tf b/main.tf index 0d794b2..840c9f4 100644 --- a/main.tf +++ b/main.tf @@ -1,23 +1,17 @@ locals { - dd_team = { - for member in var.users : - member.username => member if member.access_roles["datadog"] + users = { for u in var.users : u.username => u } + roles = { + "standard" = data.datadog_role.standard.id + "admin" = data.datadog_role.admin.id + "read_only" = data.datadog_role.read_only.id } } -data "datadog_role" "standard" { - filter = "Datadog Standard Role" -} - resource "datadog_user" "users" { - for_each = local.dd_team + for_each = local.users disabled = each.value.disabled email = each.value.email name = each.value.name - roles = [data.datadog_role.standard.id] + roles = [local.roles[each.value.access_roles["datadog"].role]] send_user_invitation = each.value.send_user_invitation - - lifecycle { - ignore_changes = [name] - } } diff --git a/outputs.tf b/outputs.tf index 8b13789..dc40a86 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1 +1,4 @@ - +output "datadog_users" { + value = resource.datadog_user.users + description = "A map of all Datadog user resources keyed by username." +} diff --git a/secrets.sops.tf b/secrets.sops.tf deleted file mode 100644 index 7f4b6f6..0000000 --- a/secrets.sops.tf +++ /dev/null @@ -1,25 +0,0 @@ -module "secrets" { - source = "masterpointio/helper/secrets" - version = "0.2.0" - secret_mapping = var.secret_mapping -} - -variable "secret_mapping" { - type = list(object({ - name = string - type = string - path = optional(string, null) - file = string - })) - default = [] - description = <<-EOT - The list of secret mappings the application will need. - This creates secret values for the component to consume at `local.secrets[name]`. - EOT -} - -# Reference your secrets using the module output -locals { - # tflint-ignore: terraform_unused_declarations - secrets = module.secrets.all -} diff --git a/variables.tf b/variables.tf index 6438ea6..e86074f 100644 --- a/variables.tf +++ b/variables.tf @@ -1,6 +1,6 @@ variable "users" { type = list(object({ - access_roles = map(bool) + access_roles = map(any) disabled = optional(bool, false) email = string name = string