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

CCL-1274 - Create Dynatrace IAM resources #1

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
26 changes: 26 additions & 0 deletions .github/workflows/pull-request-sast.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Validate Terraform with Trivy

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

jobs:
RunTerraformValidation:
name: Run Terraform SAST
runs-on: ubuntu-latest

steps:
- name: Clone the Repository
uses: actions/checkout@v4

# Results have to be a table as the organisation does not have Advanced Security license.
- name: Terraform Trivy Scan
uses: aquasecurity/[email protected]
with:
scan-type: 'config'
exit-code: '1'
39 changes: 39 additions & 0 deletions .github/workflows/pull-request-semver-label-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: 'Check PR for SemVer Label'
on:
pull_request:
types:
- labeled
- unlabeled
- opened
- reopened
- synchronize
branches:
- main

permissions:
pull-requests: read
contents: read

jobs:
semver-check:
name: 'Check PR for SemVer Label'
if: |
contains(github.event.pull_request.labels.*.name, 'skip-release') == false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Parse the SemVer label
id: label
uses: UKHomeOffice/match-label-action@v1
with:
labels: minor,major,patch
mode: singular

- name: Calculate SemVer value
id: calculate
uses: UKHomeOffice/semver-calculate-action@v2
with:
increment: ${{ steps.label.outputs.matchedLabels }}
github_token: ${{ secrets.GITHUB_TOKEN }}
46 changes: 46 additions & 0 deletions .github/workflows/pull-request-semver-tag-merge.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: 'SemVer Tag on Main Merge'
on:
pull_request:
types:
- closed
branches:
- main

permissions:
pull-requests: read
contents: write

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
semver-tag:
name: 'Tag Repository with SemVer'
if: |
github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'skip-release') == false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Parse the SemVer label
id: label
uses: UKHomeOffice/match-label-action@v1
with:
labels: minor,major,patch
mode: singular

- name: Calculate SemVer value
id: calculate
uses: UKHomeOffice/semver-calculate-action@v2
with:
increment: ${{ steps.label.outputs.matchedLabels }}
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Tag Repository
uses: UKHomeOffice/semver-tag-action@v4
with:
tag: ${{ steps.calculate.outputs.version }}
github_token: ${{ secrets.GITHUB_TOKEN }}
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Local .terraform directories
**/.terraform/*

**/.terraform*
**/.terragrunt*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc

*.env
__dont_track*
.DS_Store
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
# core-cloud-dynatrace-iam-terraform
# What does the repository do?

This repository creates the following resources:

1. Dynatrace IAM groups
2. Dynatrace IAM policies
3. Bindings of the policies - both predefined and custom - to the created/configured groups.

# What is not implemented?

1. As required in the ticket, boundaries will not be created by the repository as the functionality is not available through code.
2. Policies are not created with environment scope as it is a deprecated functionality (as per the [terraform documentation](https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy)). However, the functionality could be achieved through policy statement condition.

# Inputs

Please refer to the [variables.tf](variables.tf) and [iam\_group\_variable\_type.tf](iam\_group\_variable\_type.tf) for details on the input variables.

# Outputs

No outputs
8 changes: 8 additions & 0 deletions groups_and_bindings/dt_provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
dynatrace = {
version = "~> 1.0"
source = "dynatrace-oss/dynatrace"
}
}
}
1 change: 1 addition & 0 deletions groups_and_bindings/environment_policies/dt_provider.tf
9 changes: 9 additions & 0 deletions groups_and_bindings/environment_policies/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resource "dynatrace_iam_policy_bindings_v2" "cc-env-policy-bindings" {
group = var.group_id
environment = var.env_id
policy{
id = var.policy_id
parameters = var.policy_parameters
metadata = var.policy_metadata
}
}
18 changes: 18 additions & 0 deletions groups_and_bindings/environment_policies/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
variable "group_id" {
type = string
}
variable "env_id" {
type = string
}
variable "policy_id" {
type = string
}
variable "policy_parameters" {
type = map(string)
default = null
}
variable "policy_metadata" {
type = map(string)
default = null
}

32 changes: 32 additions & 0 deletions groups_and_bindings/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
locals {
group_name = keys(var.groups_and_permissions)[0]
}

resource "dynatrace_iam_group" "cc-iam-group" {
name = local.group_name
federated_attribute_values = toset(var.groups_and_permissions[local.group_name].federated_attribute_values)
}

resource "dynatrace_iam_policy_bindings_v2" "cc-acc-policy-bindings" {
group = dynatrace_iam_group.cc-iam-group.id
account = var.accountUUID
dynamic "policy" {
for_each = keys(var.groups_and_permissions[local.group_name].account_bound_policies)
content {
id = element([for item in var.group_policies : item if item["name"] == policy.value], 0).id
parameters = var.groups_and_permissions[local.group_name].account_bound_policies[policy.value].policy_parameters
metadata = var.groups_and_permissions[local.group_name].account_bound_policies[policy.value].policy_metadata
}
}
}

module "environment_policies" {
source = "./environment_policies"
for_each = var.groups_and_permissions[local.group_name].environment_bound_policies

group_id = dynatrace_iam_group.cc-iam-group.id
env_id = each.value.environment_id
policy_id = element([for item in var.group_policies : item if item["name"] == each.key], 0).id
policy_parameters = each.value.policy_parameters
policy_metadata = each.value.policy_metadata
}
1 change: 1 addition & 0 deletions groups_and_bindings/shared_vars.tf
4 changes: 4 additions & 0 deletions groups_and_bindings/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
variable "group_policies" {
type = any
description = "Combination of list of predefined and custom policies."
}
26 changes: 26 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Required when creating the groups so we can attach newly created
# and/or existing policies
data "dynatrace_iam_policies" "allPolicies" {
environments = ["*"]
accounts = ["*"]
global = true
}

resource "dynatrace_iam_policy" "env_policy" {
for_each = var.iam_policies

name = each.key
account = var.accountUUID # Account, until discovered to be otherwise, account id is going to be a constant
statement_query = each.value
}

module "groups_and_bindings" {
source = "./groups_and_bindings"
for_each = var.groups_and_permissions

groups_and_permissions= tomap({"${each.key}"=each.value})
# Concatenate the newly created policies with the existing polices
# so we can refer to the policies both during plan and apply stages
group_policies = concat(data.dynatrace_iam_policies.allPolicies.policies, [for k, v in dynatrace_iam_policy.env_policy : v])
accountUUID = var.accountUUID
}
38 changes: 38 additions & 0 deletions shared_vars.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This file is shared(symlinked) between the root and the submodule(s)
# for DRY purpose
variable "groups_and_permissions" {
type = map(object({
# Refer to :
# https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_group#federated_attribute_values-1
# and
# https://docs.dynatrace.com/docs/manage/identity-access-management/user-and-group-management/access-group-management
# for more details
federated_attribute_values = optional(list(string))
# Refer to https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy_bindings_v2 and
# https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy
# for more details.
# Please note that 'environment' is deprecated from the 'iam_policy'
# resource and therefore not supported here - only 'account' is supported
# For documentation on parameters refer to:
# https://docs.dynatrace.com/docs/manage/identity-access-management/permission-management/manage-user-permissions-policies/advanced/iam-policy-templating
environment_bound_policies = optional(map(object({
environment_id = string
policy_parameters = optional(map(string),null)
policy_metadata = optional(map(string),null)

})),{})
account_bound_policies = optional(map(object({
policy_parameters = optional(map(string),null)
policy_metadata = optional(map(string),null)

})),{})

}))
description = "Map of IAM groups"
default = {}
}

variable "accountUUID" {
type = string
description = "Root account UUID"
}
12 changes: 12 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# !!!! There are more variable definitions in the file
# 'shared_vars.tf' shared between the root and
# the sub modules


# Refer to https://docs.dynatrace.com/docs/manage/identity-access-management/permission-management/manage-user-permissions-policies/advanced/iam-policystatements
variable "iam_policies" {
type = map(string)
description = "Dictionary of policies with policy query statement."
default = {}
}

Loading