Skip to content

Commit

Permalink
CCL-1274-2 - Create Dynatrace IAM resources (#2)
Browse files Browse the repository at this point in the history
* Initial revision.

* Modified the groups permissions.

* Added the account uuid variable and renamed the shared var file accordingly.

* Changed the policy query statement format and added federated_attribute_values.

* Added provision for environment bound policies.

* Remove ticket link

* Revert "Added provision for environment bound policies."

This reverts commit c4f500f.

* Example terraform

* Examples and small cleanup

* rename all_policies submodule variable to iam_policies

* updatre trivy action

---------

Co-authored-by: Srinivasan Sundaram <[email protected]>
  • Loading branch information
ukho-cfreeman and SrinivasanSundaram-HO authored Dec 19, 2024
1 parent 7818b3a commit 0fd4410
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 1 deletion.
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
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
# 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
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_dynatrace"></a> [dynatrace](#requirement\_dynatrace) | ~> 1.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_dynatrace"></a> [dynatrace](#provider\_dynatrace) | ~> 1.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_groups_and_bindings"></a> [groups\_and\_bindings](#module\_groups\_and\_bindings) | ./groups_and_bindings | n/a |

## Resources

| Name | Type |
|------|------|
| [dynatrace_iam_policy.env_policy](https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_accountUUID"></a> [accountUUID](#input\_accountUUID) | Root account UUID | `string` | n/a | yes |
| <a name="input_groups_and_permissions"></a> [groups\_and\_permissions](#input\_groups\_and\_permissions) | Map containing group name, federated values and policy attachment configuration | <pre>map(object({<br/> # Refer to :<br/> # https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_group#federated_attribute_values-1<br/> # and<br/> # https://docs.dynatrace.com/docs/manage/identity-access-management/user-and-group-management/access-group-management<br/> # for more details<br/> federated_attribute_values = optional(list(string))<br/> # Refer to https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy_bindings_v2 and<br/> # https://registry.terraform.io/providers/dynatrace-oss/dynatrace/latest/docs/resources/iam_policy<br/> # for more details.<br/> # Please note that 'environment' is deprecated from the 'iam_policy'<br/> # resource and therefore not supported here - only 'account' is supported<br/> # For documentation on parameters refer to:<br/> # https://docs.dynatrace.com/docs/manage/identity-access-management/permission-management/manage-user-permissions-policies/advanced/iam-policy-templating<br/> attached_policies = optional(map(object({<br/> policy_parameters = optional(map(string), null)<br/> policy_metadata = optional(map(string), null)<br/> environment = string<br/> })), {})<br/> }))</pre> | `{}` | no |
| <a name="input_iam_policies"></a> [iam\_policies](#input\_iam\_policies) | Map of policy names and their policy query statement. | `map(string)` | n/a | yes |

## Outputs

No outputs.
<!-- END_TF_DOCS -->
46 changes: 46 additions & 0 deletions examples/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module "example" {
source = "../"
groups_and_permissions = {
group_one = {
attached_policies = {
policy_static = {
environment = "tvy38111"
}
}
}
group_two = {
attached_policies = {
policy_with_param = {
environment = "tvy38111"
policy_parameters = {
zone = "zone1"
}
policy_metadata = {
meta1 = "metaval1"
}
}
}
}
}

iam_policies = {
policy_with_param = <<EOT
ALLOW environment:roles:viewer, environment:roles:manage-settings
WHERE environment:management-zone IN ("zone2", "$${bindParam:my-policy-param}");
EOT
policy_static = "ALLOW settings:objects:read;"
}

accountUUID = "a8c6fb99-cc30-46b5-9306-1111111"
}


terraform {
required_providers {
dynatrace = {
version = "~> 1.0"
source = "dynatrace-oss/dynatrace"
}
}
}
17 changes: 17 additions & 0 deletions groups_and_bindings/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "dynatrace_iam_group" "cc-iam-group" {
name = var.group_name
federated_attribute_values = var.federated_attribute_values
}

resource "dynatrace_iam_policy_bindings_v2" "cc-policy-bindings" {
group = dynatrace_iam_group.cc-iam-group.id
for_each = var.attached_policies

environment = each.value.environment

policy {
id = element([for item in var.iam_policies : item if item["name"] == each.key], 0).id
parameters = each.value.policy_parameters
metadata = each.value.policy_metadata
}
}
8 changes: 8 additions & 0 deletions groups_and_bindings/providers.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"
}
}
}
23 changes: 23 additions & 0 deletions groups_and_bindings/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
variable "iam_policies" {
type = any
description = "Combination of list of predefined and custom policies."
}

variable "group_name" {
description = "The name of the group used as an id"
type = string
}

variable "attached_policies" {
description = "A map with the key being the policy name and the value object containing the policy binding configuration"
type = map(object({
policy_parameters = optional(map(string), null)
policy_metadata = optional(map(string), null)
environment = string
}))
}

variable "federated_attribute_values" {
description = "A list of federated attribute values"
type = list(string)
}
17 changes: 17 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "dynatrace_iam_policy" "env_policy" {
for_each = var.iam_policies

name = each.key
account = var.accountUUID
statement_query = each.value
}

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

group_name = each.key
attached_policies = each.value.attached_policies
federated_attribute_values = each.value.federated_attribute_values
iam_policies = [for k, v in dynatrace_iam_policy.env_policy : v]
}
36 changes: 36 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
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
attached_policies = optional(map(object({
policy_parameters = optional(map(string), null)
policy_metadata = optional(map(string), null)
environment = string
})), {})
}))
description = "Map containing group name, federated values and policy attachment configuration"
default = {}
}

variable "accountUUID" {
type = string
description = "Root account UUID"
}


# 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 = "Map of policy names and their policy query statement."
}

0 comments on commit 0fd4410

Please sign in to comment.