Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage users on Datadog with Terraform #318

Merged
merged 21 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions terraform/team-members-datadog/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions terraform/team-members-datadog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Team Members on Datadog

This Terraform configuration manages user accounts on Datadog. When a user is
added to [`users.tf`](users.tf), they get invited to join our Datadog account.

## Usage

Applying the Terraform configuration requires an API key as well as an app key.
Both can be found on the [Datadog API keys page][api-keys].

```shell
export DD_API_KEY="datadog-api-key"
export DD_APP_KEY="datadog-app-key"
terraform plan
```

### Add a user

Adding a user is a two-step process. First, add the user to the `users.tf` file.
Then, add them to their respective team, referencing the user in `users.tf`.

For example, `jdn` has first been added as a users in `users.tf`:

```hcl
locals {
users = {
"jdn" = {
// ...
}
}
}
```

And then to the `infra` team in `infra.tf`:

```hcl
locals {
infra = {
"jdn" = local.users.jdn
}
}
```

### Add a Team

The easiest way to add a team is to copy an existing team and update its
resources. Go through the following steps before applying the configuration:

1. At the top of the file, update the `locals` block to include the correct team
members.
2. Then update the `datadog_role` for the team and assign the appropriate
permissions to the team.
3. Update the `datadog_team` with the proper name and description.

Then, register the team in `users.tf` in the `_do_not_use_all_teams` local.
Without this step, no team memberships will be assigned and users won't be
created.

[api-keys]: https://app.datadoghq.com/organization-settings/api-keys
2 changes: 2 additions & 0 deletions terraform/team-members-datadog/_data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Fetch all available permissions
data "datadog_permissions" "all" {}
22 changes: 22 additions & 0 deletions terraform/team-members-datadog/_terraform.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Configuration for Terraform itself.

terraform {
required_version = "~> 1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it a better idea to pin it to something before the BUSL license was introduced? e.g. ~> 1.5

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK the license change doesn't impact us as end-users of Terraform, since we're not embedding Terraform or its source code in a commercial product that we're selling. At least that's how I understand their FAQ.


required_providers {
datadog = {
source = "datadog/datadog"
version = "3.30.0"
}
}

backend "s3" {
bucket = "rust-terraform"
key = "simpleinfra/team-members-datadog.tfstate"
region = "us-west-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
Comment on lines +13 to +20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wander, doesn't simpleinfra use Terragrunt? Wouldn't it be better to use the DRY it offers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terragrunt is really handy for things that have multiple environments like production and staging. The team access will only ever have a single instance, so we haven't bothered moving it over to Terragrunt yet. And since the other rest of the team access is managed with Terraform as well, I didn't want to make this a one-off configuration in a different place.


provider "datadog" {}
34 changes: 34 additions & 0 deletions terraform/team-members-datadog/crater.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
locals {
crater = {
"walter" = local.users.walter
}
}

resource "datadog_role" "crater" {
name = "crater"

dynamic "permission" {
for_each = toset([
data.datadog_permissions.all.permissions.dashboards_write,
data.datadog_permissions.all.permissions.api_keys_read,
data.datadog_permissions.all.permissions.user_app_keys,
])

content {
id = permission.value
}
}
}

resource "datadog_team" "crater" {
name = "crater"
description = "The team maintaining crater"
handle = "crater"
}

resource "datadog_team_membership" "crater" {
for_each = local.crater

team_id = datadog_team.crater.id
user_id = datadog_user.users[each.key].id
}
37 changes: 37 additions & 0 deletions terraform/team-members-datadog/crates-io.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
locals {
crates_io = {
"adam" = local.users.adam
"tobias" = local.users.tobias
}
}

resource "datadog_role" "crates_io" {
name = "crates.io"

dynamic "permission" {
for_each = toset([
data.datadog_permissions.all.permissions.logs_read_index_data,
data.datadog_permissions.all.permissions.logs_read_data,
data.datadog_permissions.all.permissions.logs_live_tail,
data.datadog_permissions.all.permissions.logs_read_archives,
data.datadog_permissions.all.permissions.dashboards_write,
])

content {
id = permission.value
}
}
}

resource "datadog_team" "crates_io" {
name = "crates.io"
description = "The team working on crates.io"
handle = "crates-io"
}

resource "datadog_team_membership" "crates_io" {
for_each = local.crates_io

team_id = datadog_team.crates_io.id
user_id = datadog_user.users[each.key].id
}
34 changes: 34 additions & 0 deletions terraform/team-members-datadog/foundation-board.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
locals {
foundation_board = {
"nell" = local.users.nell
"peixin" = local.users.peixin
"seth" = local.users.seth
}
}

resource "datadog_role" "board_member" {
name = "Board Member"

dynamic "permission" {
for_each = toset([
data.datadog_permissions.all.permissions.dashboards_write,
])

content {
id = permission.value
}
}
}

resource "datadog_team" "foundation_board" {
name = "Rust Foundation Board"
description = "The board of the Rust Foundation"
handle = "foundation-board"
}

resource "datadog_team_membership" "foundation_board" {
for_each = local.foundation_board

team_id = datadog_team.foundation_board.id
user_id = datadog_user.users[each.key].id
}
38 changes: 38 additions & 0 deletions terraform/team-members-datadog/foundation.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
locals {
foundation = {
"adam" = local.users.adam
"jdn" = local.users.jdn
"joel" = local.users.joel
"paullenz" = local.users.paullenz
"rustfoundation" = local.users.rustfoundation
"tobias" = local.users.tobias
"walter" = local.users.walter
}
}

resource "datadog_role" "foundation" {
name = "Rust Foundation"

dynamic "permission" {
for_each = toset([
data.datadog_permissions.all.permissions.dashboards_write,
])

content {
id = permission.value
}
}
}

resource "datadog_team" "foundation" {
name = "Rust Foundation"
description = "The staff of the Rust Foundation"
handle = "foundation"
}

resource "datadog_team_membership" "foundation" {
for_each = local.foundation

team_id = datadog_team.foundation.id
user_id = datadog_user.users[each.key].id
}
23 changes: 23 additions & 0 deletions terraform/team-members-datadog/infra-admins.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
locals {
infra_admins = {
"admin" = local.users.admin
"jdn" = local.users.jdn
"joel" = local.users.joel
"mark" = local.users.mark
"pietro" = local.users.pietro
"rustfoundation" = local.users.rustfoundation
}
}

resource "datadog_team" "infra_admins" {
name = "Infrastructure Admins"
description = "The infra-admins"
handle = "infra-admins"
}

resource "datadog_team_membership" "infra_admins" {
for_each = local.infra_admins

team_id = datadog_team.infra_admins.id
user_id = datadog_user.users[each.key].id
}
44 changes: 44 additions & 0 deletions terraform/team-members-datadog/infra.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
locals {
infra = {
"admin" = local.users.admin
"jakub" = local.users.jakub
"jdn" = local.users.jdn
"mark" = local.users.mark
"pietro" = local.users.pietro
}
}

resource "datadog_role" "infra" {
name = "infra"

dynamic "permission" {
for_each = toset([
data.datadog_permissions.all.permissions.logs_read_index_data,
data.datadog_permissions.all.permissions.logs_read_data,
data.datadog_permissions.all.permissions.logs_live_tail,
data.datadog_permissions.all.permissions.logs_read_archives,
data.datadog_permissions.all.permissions.dashboards_write,
data.datadog_permissions.all.permissions.saved_views_write,
data.datadog_permissions.all.permissions.api_keys_read,
data.datadog_permissions.all.permissions.api_keys_write,
data.datadog_permissions.all.permissions.user_app_keys,
])

content {
id = permission.value
}
}
}

resource "datadog_team" "infra" {
name = "infra-team"
description = "The infra-team"
handle = "infra"
}

resource "datadog_team_membership" "infra" {
for_each = local.infra

team_id = datadog_team.infra.id
user_id = datadog_user.users[each.key].id
}
Loading
Loading