Simplify org policies data model in resman modules.

This commit is contained in:
Julio Castillo 2023-02-21 12:24:40 +01:00
parent 77df3c8721
commit 6b767c9035
19 changed files with 242 additions and 288 deletions

View File

@ -42,40 +42,46 @@ module "folder" {
name = "Folder name" name = "Folder name"
org_policies = { org_policies = {
"compute.disableGuestAttributesAccess" = { "compute.disableGuestAttributesAccess" = {
enforce = true rules = [{ enforce = true }]
} }
"constraints/compute.skipDefaultNetworkCreation" = { "constraints/compute.skipDefaultNetworkCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')"
title = "condition" title = "condition"
description = "test condition" description = "test condition"
location = "somewhere" location = "somewhere"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }
"constraints/iam.allowedPolicyMemberDomains" = { "constraints/iam.allowedPolicyMemberDomains" = {
allow = { rules = [{
values = ["C0xxxxxxx", "C0yyyyyyy"] allow = {
} values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
} }
"constraints/compute.trustedImageProjects" = { "constraints/compute.trustedImageProjects" = {
allow = { rules = [{
values = ["projects/my-project"] allow = {
} values = ["projects/my-project"]
}
}]
} }
"constraints/compute.vmExternalIpAccess" = { "constraints/compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,16 +28,6 @@ locals {
k => { k => {
inherit_from_parent = try(v.inherit_from_parent, null) inherit_from_parent = try(v.inherit_from_parent, null)
reset = try(v.reset, null) reset = try(v.reset, null)
allow = can(v.allow) ? {
all = try(v.allow.all, null)
values = try(v.allow.values, null)
} : null
deny = can(v.deny) ? {
all = try(v.deny.all, null)
values = try(v.deny.values, null)
} : null
enforce = try(v.enforce, true)
rules = [ rules = [
for r in try(v.rules, []) : { for r in try(v.rules, []) : {
allow = can(r.allow) ? { allow = can(r.allow) ? {
@ -48,7 +38,7 @@ locals {
all = try(r.deny.all, null) all = try(r.deny.all, null)
values = try(r.deny.values, null) values = try(r.deny.values, null)
} : null } : null
enforce = try(r.enforce, true) enforce = try(r.enforce, null)
condition = { condition = {
description = try(r.condition.description, null) description = try(r.condition.description, null)
expression = try(r.condition.expression, null) expression = try(r.condition.expression, null)
@ -67,8 +57,9 @@ locals {
k => merge(v, { k => merge(v, {
name = "${local.folder.name}/policies/${k}" name = "${local.folder.name}/policies/${k}"
parent = local.folder.name parent = local.folder.name
is_boolean_policy = (
is_boolean_policy = v.allow == null && v.deny == null alltrue([for r in v.rules : r.allow == null && r.deny == null])
)
has_values = ( has_values = (
length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.allow.values, []), [])) > 0 ||
length(coalesce(try(v.deny.values, []), [])) > 0 length(coalesce(try(v.deny.values, []), [])) > 0
@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" {
for_each = local.org_policies for_each = local.org_policies
name = each.value.name name = each.value.name
parent = each.value.parent parent = each.value.parent
spec { spec {
inherit_from_parent = each.value.inherit_from_parent inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset reset = each.value.reset
dynamic "rules" { dynamic "rules" {
for_each = each.value.rules for_each = each.value.rules
iterator = rule iterator = rule
@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" {
? upper(tostring(rule.value.enforce)) ? upper(tostring(rule.value.enforce))
: null : null
) )
condition { dynamic "condition" {
description = rule.value.condition.description for_each = rule.value.condition.expression != null ? [1] : []
expression = rule.value.condition.expression content {
location = rule.value.condition.location description = rule.value.condition.description
title = rule.value.condition.title expression = rule.value.condition.expression
location = rule.value.condition.location
title = rule.value.condition.title
}
} }
dynamic "values" { dynamic "values" {
for_each = rule.value.has_values ? [1] : [] for_each = rule.value.has_values ? [1] : []
@ -121,22 +113,5 @@ resource "google_org_policy_policy" "default" {
} }
} }
} }
rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -143,19 +143,6 @@ variable "org_policies" {
type = map(object({ type = map(object({
inherit_from_parent = optional(bool) # for list policies only. inherit_from_parent = optional(bool) # for list policies only.
reset = optional(bool) reset = optional(bool)
# default (unconditional) values
allow = optional(object({
all = optional(bool)
values = optional(list(string))
}))
deny = optional(object({
all = optional(bool)
values = optional(list(string))
}))
enforce = optional(bool, true) # for boolean policies only.
# conditional values
rules = optional(list(object({ rules = optional(list(object({
allow = optional(object({ allow = optional(object({
all = optional(bool) all = optional(bool)
@ -165,13 +152,13 @@ variable "org_policies" {
all = optional(bool) all = optional(bool)
values = optional(list(string)) values = optional(list(string))
})) }))
enforce = optional(bool, true) # for boolean policies only. enforce = optional(bool) # for boolean policies only.
condition = object({ condition = optional(object({
description = optional(string) description = optional(string)
expression = optional(string) expression = optional(string)
location = optional(string) location = optional(string)
title = optional(string) title = optional(string)
}) }), {})
})), []) })), [])
})) }))
default = {} default = {}

View File

@ -25,50 +25,77 @@ module "org" {
iam_additive_members = { iam_additive_members = {
"user:compute@example.org" = ["roles/compute.admin", "roles/container.viewer"] "user:compute@example.org" = ["roles/compute.admin", "roles/container.viewer"]
} }
tags = {
allowexternal = {
description = "Allow external identities."
values = {
true = {}, false = {}
}
}
}
org_policies = { org_policies = {
"custom.gkeEnableAutoUpgrade" = { "custom.gkeEnableAutoUpgrade" = {
enforce = true rules = [{ enforce = true }]
} }
"compute.disableGuestAttributesAccess" = { "compute.disableGuestAttributesAccess" = {
enforce = true rules = [{ enforce = true }]
} }
"constraints/compute.skipDefaultNetworkCreation" = { "constraints/compute.skipDefaultNetworkCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')"
title = "condition" title = "condition"
description = "test condition" description = "test condition"
location = "somewhere" location = "somewhere"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }
"constraints/iam.allowedPolicyMemberDomains" = { "constraints/iam.allowedPolicyMemberDomains" = {
allow = { rules = [
values = ["C0xxxxxxx", "C0yyyyyyy"] {
} allow = { all = true }
condition = {
expression = "resource.matchTag('1234567890/allowexternal', 'true')"
title = "Allow external identities"
description = "Allow external identities when resource has the `allowexternal` tag set to true."
}
},
{
allow = { values = ["C0xxxxxxx", "C0yyyyyyy"] }
condition = {
expression = "!resource.matchTag('1234567890/allowexternal', 'true')"
title = ""
description = "For any resource without allowexternal=true, only allow identities from restricted domains."
}
}
]
} }
"constraints/compute.trustedImageProjects" = { "constraints/compute.trustedImageProjects" = {
allow = { rules = [{
values = ["projects/my-project"] allow = {
} values = ["projects/my-project"]
}
}]
} }
"constraints/compute.vmExternalIpAccess" = { "constraints/compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
} }
} }
# tftest modules=1 resources=13 inventory=basic.yaml # tftest modules=1 resources=16 inventory=basic.yaml
``` ```
## IAM ## IAM
@ -111,7 +138,7 @@ module "org" {
# not necessarily to enforce on the org level, policy may be applied on folder/project levels # not necessarily to enforce on the org level, policy may be applied on folder/project levels
org_policies = { org_policies = {
"custom.gkeEnableAutoUpgrade" = { "custom.gkeEnableAutoUpgrade" = {
enforce = true rules = [{ enforce = true }]
} }
} }
} }
@ -131,7 +158,7 @@ module "org" {
org_policy_custom_constraints_data_path = "configs/custom-constraints" org_policy_custom_constraints_data_path = "configs/custom-constraints"
org_policies = { org_policies = {
"custom.gkeEnableAutoUpgrade" = { "custom.gkeEnableAutoUpgrade" = {
enforce = true rules = [{ enforce = true }]
} }
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,16 +28,6 @@ locals {
k => { k => {
inherit_from_parent = try(v.inherit_from_parent, null) inherit_from_parent = try(v.inherit_from_parent, null)
reset = try(v.reset, null) reset = try(v.reset, null)
allow = can(v.allow) ? {
all = try(v.allow.all, null)
values = try(v.allow.values, null)
} : null
deny = can(v.deny) ? {
all = try(v.deny.all, null)
values = try(v.deny.values, null)
} : null
enforce = try(v.enforce, true)
rules = [ rules = [
for r in try(v.rules, []) : { for r in try(v.rules, []) : {
allow = can(r.allow) ? { allow = can(r.allow) ? {
@ -48,7 +38,7 @@ locals {
all = try(r.deny.all, null) all = try(r.deny.all, null)
values = try(r.deny.values, null) values = try(r.deny.values, null)
} : null } : null
enforce = try(r.enforce, true) enforce = try(r.enforce, null)
condition = { condition = {
description = try(r.condition.description, null) description = try(r.condition.description, null)
expression = try(r.condition.expression, null) expression = try(r.condition.expression, null)
@ -67,8 +57,9 @@ locals {
k => merge(v, { k => merge(v, {
name = "${var.organization_id}/policies/${k}" name = "${var.organization_id}/policies/${k}"
parent = var.organization_id parent = var.organization_id
is_boolean_policy = (
is_boolean_policy = v.allow == null && v.deny == null alltrue([for r in v.rules : r.allow == null && r.deny == null])
)
has_values = ( has_values = (
length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.allow.values, []), [])) > 0 ||
length(coalesce(try(v.deny.values, []), [])) > 0 length(coalesce(try(v.deny.values, []), [])) > 0
@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" {
for_each = local.org_policies for_each = local.org_policies
name = each.value.name name = each.value.name
parent = each.value.parent parent = each.value.parent
spec { spec {
inherit_from_parent = each.value.inherit_from_parent inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset reset = each.value.reset
dynamic "rules" { dynamic "rules" {
for_each = each.value.rules for_each = each.value.rules
iterator = rule iterator = rule
@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" {
? upper(tostring(rule.value.enforce)) ? upper(tostring(rule.value.enforce))
: null : null
) )
condition { dynamic "condition" {
description = rule.value.condition.description for_each = rule.value.condition.expression != null ? [1] : []
expression = rule.value.condition.expression content {
location = rule.value.condition.location description = rule.value.condition.description
title = rule.value.condition.title expression = rule.value.condition.expression
location = rule.value.condition.location
title = rule.value.condition.title
}
} }
dynamic "values" { dynamic "values" {
for_each = rule.value.has_values ? [1] : [] for_each = rule.value.has_values ? [1] : []
@ -121,25 +113,7 @@ resource "google_org_policy_policy" "default" {
} }
} }
} }
rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
} }
depends_on = [ depends_on = [
google_organization_iam_audit_config.config, google_organization_iam_audit_config.config,
google_organization_iam_binding.authoritative, google_organization_iam_binding.authoritative,

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -183,18 +183,6 @@ variable "org_policies" {
type = map(object({ type = map(object({
inherit_from_parent = optional(bool) # for list policies only. inherit_from_parent = optional(bool) # for list policies only.
reset = optional(bool) reset = optional(bool)
# default (unconditional) values
allow = optional(object({
all = optional(bool)
values = optional(list(string))
}))
deny = optional(object({
all = optional(bool)
values = optional(list(string))
}))
enforce = optional(bool, true) # for boolean policies only.
# conditional values
rules = optional(list(object({ rules = optional(list(object({
allow = optional(object({ allow = optional(object({
all = optional(bool) all = optional(bool)
@ -204,13 +192,13 @@ variable "org_policies" {
all = optional(bool) all = optional(bool)
values = optional(list(string)) values = optional(list(string))
})) }))
enforce = optional(bool, true) # for boolean policies only. enforce = optional(bool) # for boolean policies only.
condition = object({ condition = optional(object({
description = optional(string) description = optional(string)
expression = optional(string) expression = optional(string)
location = optional(string) location = optional(string)
title = optional(string) title = optional(string)
}) }), {})
})), []) })), [])
})) }))
default = {} default = {}

View File

@ -243,40 +243,46 @@ module "project" {
prefix = "foo" prefix = "foo"
org_policies = { org_policies = {
"compute.disableGuestAttributesAccess" = { "compute.disableGuestAttributesAccess" = {
enforce = true rules = [{ enforce = true }]
} }
"constraints/compute.skipDefaultNetworkCreation" = { "constraints/compute.skipDefaultNetworkCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')"
title = "condition" title = "condition"
description = "test condition" description = "test condition"
location = "somewhere" location = "somewhere"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }
"constraints/iam.allowedPolicyMemberDomains" = { "constraints/iam.allowedPolicyMemberDomains" = {
allow = { rules = [{
values = ["C0xxxxxxx", "C0yyyyyyy"] allow = {
} values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
} }
"constraints/compute.trustedImageProjects" = { "constraints/compute.trustedImageProjects" = {
allow = { rules = [{
values = ["projects/my-project"] allow = {
} values = ["projects/my-project"]
}
}]
} }
"constraints/compute.vmExternalIpAccess" = { "constraints/compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
} }
} }
@ -306,36 +312,42 @@ module "project" {
```yaml ```yaml
# tftest-file id=boolean path=configs/org-policies/boolean.yaml # tftest-file id=boolean path=configs/org-policies/boolean.yaml
compute.disableGuestAttributesAccess: compute.disableGuestAttributesAccess:
enforce: true rules:
- enforce: true
constraints/compute.skipDefaultNetworkCreation: constraints/compute.skipDefaultNetworkCreation:
enforce: true rules:
- enforce: true
iam.disableServiceAccountKeyCreation: iam.disableServiceAccountKeyCreation:
enforce: true rules:
- enforce: true
iam.disableServiceAccountKeyUpload: iam.disableServiceAccountKeyUpload:
enforce: false
rules: rules:
- condition: - condition:
description: test condition description: test condition
expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
location: somewhere location: somewhere
title: condition title: condition
enforce: true enforce: true
- enforce: false
``` ```
```yaml ```yaml
# tftest-file id=list path=configs/org-policies/list.yaml # tftest-file id=list path=configs/org-policies/list.yaml
constraints/compute.trustedImageProjects: constraints/compute.trustedImageProjects:
allow: rules:
values: - allow:
- projects/my-project values:
- projects/my-project
constraints/compute.vmExternalIpAccess: constraints/compute.vmExternalIpAccess:
deny: rules:
all: true - deny:
all: true
constraints/iam.allowedPolicyMemberDomains: constraints/iam.allowedPolicyMemberDomains:
allow: rules:
values: - allow:
- C0xxxxxxx values:
- C0yyyyyyy - C0xxxxxxx
- C0yyyyyyy
``` ```

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,16 +28,6 @@ locals {
k => { k => {
inherit_from_parent = try(v.inherit_from_parent, null) inherit_from_parent = try(v.inherit_from_parent, null)
reset = try(v.reset, null) reset = try(v.reset, null)
allow = can(v.allow) ? {
all = try(v.allow.all, null)
values = try(v.allow.values, null)
} : null
deny = can(v.deny) ? {
all = try(v.deny.all, null)
values = try(v.deny.values, null)
} : null
enforce = try(v.enforce, true)
rules = [ rules = [
for r in try(v.rules, []) : { for r in try(v.rules, []) : {
allow = can(r.allow) ? { allow = can(r.allow) ? {
@ -48,7 +38,7 @@ locals {
all = try(r.deny.all, null) all = try(r.deny.all, null)
values = try(r.deny.values, null) values = try(r.deny.values, null)
} : null } : null
enforce = try(r.enforce, true) enforce = try(r.enforce, null)
condition = { condition = {
description = try(r.condition.description, null) description = try(r.condition.description, null)
expression = try(r.condition.expression, null) expression = try(r.condition.expression, null)
@ -67,8 +57,9 @@ locals {
k => merge(v, { k => merge(v, {
name = "projects/${local.project.project_id}/policies/${k}" name = "projects/${local.project.project_id}/policies/${k}"
parent = "projects/${local.project.project_id}" parent = "projects/${local.project.project_id}"
is_boolean_policy = (
is_boolean_policy = v.allow == null && v.deny == null alltrue([for r in v.rules : r.allow == null && r.deny == null])
)
has_values = ( has_values = (
length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.allow.values, []), [])) > 0 ||
length(coalesce(try(v.deny.values, []), [])) > 0 length(coalesce(try(v.deny.values, []), [])) > 0
@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" {
for_each = local.org_policies for_each = local.org_policies
name = each.value.name name = each.value.name
parent = each.value.parent parent = each.value.parent
spec { spec {
inherit_from_parent = each.value.inherit_from_parent inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset reset = each.value.reset
dynamic "rules" { dynamic "rules" {
for_each = each.value.rules for_each = each.value.rules
iterator = rule iterator = rule
@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" {
? upper(tostring(rule.value.enforce)) ? upper(tostring(rule.value.enforce))
: null : null
) )
condition { dynamic "condition" {
description = rule.value.condition.description for_each = rule.value.condition.expression != null ? [1] : []
expression = rule.value.condition.expression content {
location = rule.value.condition.location description = rule.value.condition.description
title = rule.value.condition.title expression = rule.value.condition.expression
location = rule.value.condition.location
title = rule.value.condition.title
}
} }
dynamic "values" { dynamic "values" {
for_each = rule.value.has_values ? [1] : [] for_each = rule.value.has_values ? [1] : []
@ -121,22 +113,5 @@ resource "google_org_policy_policy" "default" {
} }
} }
} }
rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
} }
} }

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2022 Google LLC * Copyright 2023 Google LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -147,19 +147,6 @@ variable "org_policies" {
type = map(object({ type = map(object({
inherit_from_parent = optional(bool) # for list policies only. inherit_from_parent = optional(bool) # for list policies only.
reset = optional(bool) reset = optional(bool)
# default (unconditional) values
allow = optional(object({
all = optional(bool)
values = optional(list(string))
}))
deny = optional(object({
all = optional(bool)
values = optional(list(string))
}))
enforce = optional(bool, true) # for boolean policies only.
# conditional values
rules = optional(list(object({ rules = optional(list(object({
allow = optional(object({ allow = optional(object({
all = optional(bool) all = optional(bool)
@ -169,13 +156,13 @@ variable "org_policies" {
all = optional(bool) all = optional(bool)
values = optional(list(string)) values = optional(list(string))
})) }))
enforce = optional(bool, true) # for boolean policies only. enforce = optional(bool) # for boolean policies only.
condition = object({ condition = optional(object({
description = optional(string) description = optional(string)
expression = optional(string) expression = optional(string)
location = optional(string) location = optional(string)
title = optional(string) title = optional(string)
}) }), {})
})), []) })), [])
})) }))
default = {} default = {}

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -91,7 +91,7 @@ values:
- allow_all: null - allow_all: null
condition: condition:
- description: test condition - description: test condition
expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
location: somewhere location: somewhere
title: condition title: condition
deny_all: null deny_all: null

View File

@ -1,9 +1,8 @@
org_policies = { org_policies = {
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
@ -13,6 +12,9 @@ org_policies = {
location = "xxx" location = "xxx"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }

View File

@ -1,14 +1,15 @@
org_policies = { org_policies = {
"compute.vmExternalIpAccess" = { "compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
"iam.allowedPolicyMemberDomains" = { "iam.allowedPolicyMemberDomains" = {
allow = { rules = [{
values = ["C0xxxxxxx", "C0yyyyyyy"] allow = {
} values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
} }
"compute.restrictLoadBalancerCreationForTypes" = { "compute.restrictLoadBalancerCreationForTypes" = {
deny = { values = ["in:EXTERNAL"] }
rules = [ rules = [
{ {
condition = { condition = {
@ -31,6 +32,9 @@ org_policies = {
allow = { allow = {
all = true all = true
} }
},
{
deny = { values = ["in:EXTERNAL"] }
} }
] ]
} }

View File

@ -71,8 +71,23 @@ values:
- inherit_from_parent: null - inherit_from_parent: null
reset: null reset: null
rules: rules:
- allow_all: 'TRUE'
condition:
- description: Allow external identities when resource has the `allowexternal`
tag set to true.
expression: resource.matchTag('1234567890/allowexternal', 'true')
location: null
title: Allow external identities
deny_all: null
enforce: null
values: []
- allow_all: null - allow_all: null
condition: [] condition:
- description: For any resource without allowexternal=true, only allow identities
from restricted domains.
expression: '!resource.matchTag(''1234567890/allowexternal'', ''true'')'
location: null
title: ''
deny_all: null deny_all: null
enforce: null enforce: null
values: values:
@ -102,7 +117,7 @@ values:
- allow_all: null - allow_all: null
condition: condition:
- description: test condition - description: test condition
expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
location: somewhere location: somewhere
title: condition title: condition
deny_all: null deny_all: null
@ -141,6 +156,20 @@ values:
member: user:compute@example.org member: user:compute@example.org
org_id: '1234567890' org_id: '1234567890'
role: roles/container.viewer role: roles/container.viewer
module.org.google_tags_tag_key.default["allowexternal"]:
description: Allow external identities.
parent: organizations/1234567890
purpose: null
purpose_data: null
short_name: allowexternal
module.org.google_tags_tag_value.default["allowexternal/false"]:
short_name: 'false'
module.org.google_tags_tag_value.default["allowexternal/true"]:
short_name: 'true'
counts: counts:
google_org_policy_policy: 8 google_org_policy_policy: 8
google_organization_iam_binding: 3 google_organization_iam_binding: 3
google_organization_iam_member: 2
google_tags_tag_key: 1
google_tags_tag_value: 2

View File

@ -1,9 +1,9 @@
org_policies = { org_policies = {
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
@ -13,6 +13,9 @@ org_policies = {
location = "xxx" location = "xxx"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }

View File

@ -1,15 +1,17 @@
org_policies = { org_policies = {
"compute.vmExternalIpAccess" = { "compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
"iam.allowedPolicyMemberDomains" = { "iam.allowedPolicyMemberDomains" = {
inherit_from_parent = true inherit_from_parent = true
allow = { rules = [{
values = ["C0xxxxxxx", "C0yyyyyyy"] allow = {
} values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
} }
"compute.restrictLoadBalancerCreationForTypes" = { "compute.restrictLoadBalancerCreationForTypes" = {
deny = { values = ["in:EXTERNAL"] }
rules = [ rules = [
{ {
condition = { condition = {
@ -32,6 +34,9 @@ org_policies = {
allow = { allow = {
all = true all = true
} }
},
{
deny = { values = ["in:EXTERNAL"] }
} }
] ]
} }

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -26,61 +26,35 @@ def test_policy_implementation():
path = modules_path / module / 'organization-policies.tf' path = modules_path / module / 'organization-policies.tf'
lines[module] = path.open().readlines() lines[module] = path.open().readlines()
diff1 = difflib.unified_diff(lines['project'], lines['folder']) diff1 = difflib.unified_diff(lines['project'], lines['folder'], 'project',
'folder', n=0)
assert list(diff1) == [ assert list(diff1) == [
'--- \n', '--- project\n',
'+++ \n', '+++ folder\n',
'@@ -14,7 +14,7 @@\n', '@@ -17 +17 @@\n',
' * limitations under the License.\n',
' */\n',
' \n',
'-# tfdoc:file:description Project-level organization policies.\n', '-# tfdoc:file:description Project-level organization policies.\n',
'+# tfdoc:file:description Folder-level organization policies.\n', '+# tfdoc:file:description Folder-level organization policies.\n',
' \n', '@@ -58,2 +58,2 @@\n',
' locals {\n',
' _factory_data_raw = merge([\n',
'@@ -65,8 +65,8 @@\n',
' org_policies = {\n',
' for k, v in local._org_policies :\n',
' k => merge(v, {\n',
'- name = "projects/${local.project.project_id}/policies/${k}"\n', '- name = "projects/${local.project.project_id}/policies/${k}"\n',
'- parent = "projects/${local.project.project_id}"\n', '- parent = "projects/${local.project.project_id}"\n',
'+ name = "${local.folder.name}/policies/${k}"\n', '+ name = "${local.folder.name}/policies/${k}"\n',
'+ parent = local.folder.name\n', '+ parent = local.folder.name\n',
' \n',
' is_boolean_policy = v.allow == null && v.deny == null\n',
' has_values = (\n',
] ]
diff2 = difflib.unified_diff(lines['folder'], lines['organization']) diff2 = difflib.unified_diff(lines['folder'], lines['organization'], 'folder',
'organization', n=0)
assert list(diff2) == [ assert list(diff2) == [
'--- \n', '--- folder\n',
'+++ \n', '+++ organization\n',
'@@ -14,7 +14,7 @@\n', '@@ -17 +17 @@\n',
' * limitations under the License.\n',
' */\n',
' \n',
'-# tfdoc:file:description Folder-level organization policies.\n', '-# tfdoc:file:description Folder-level organization policies.\n',
'+# tfdoc:file:description Organization-level organization policies.\n', '+# tfdoc:file:description Organization-level organization policies.\n',
' \n', '@@ -58,2 +58,2 @@\n',
' locals {\n',
' _factory_data_raw = merge([\n',
'@@ -65,8 +65,8 @@\n',
' org_policies = {\n',
' for k, v in local._org_policies :\n',
' k => merge(v, {\n',
'- name = "${local.folder.name}/policies/${k}"\n', '- name = "${local.folder.name}/policies/${k}"\n',
'- parent = local.folder.name\n', '- parent = local.folder.name\n',
'+ name = "${var.organization_id}/policies/${k}"\n', '+ name = "${var.organization_id}/policies/${k}"\n',
'+ parent = var.organization_id\n', '+ parent = var.organization_id\n',
' \n', '@@ -116,0 +117,8 @@\n',
' is_boolean_policy = v.allow == null && v.deny == null\n',
' has_values = (\n',
'@@ -139,4 +139,13 @@\n',
' }\n',
' }\n',
' }\n',
'+\n',
'+ depends_on = [\n', '+ depends_on = [\n',
'+ google_organization_iam_audit_config.config,\n', '+ google_organization_iam_audit_config.config,\n',
'+ google_organization_iam_binding.authoritative,\n', '+ google_organization_iam_binding.authoritative,\n',
@ -89,5 +63,4 @@ def test_policy_implementation():
'+ google_organization_iam_policy.authoritative,\n', '+ google_organization_iam_policy.authoritative,\n',
'+ google_org_policy_custom_constraint.constraint,\n', '+ google_org_policy_custom_constraint.constraint,\n',
'+ ]\n', '+ ]\n',
' }\n',
] ]

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -102,7 +102,7 @@ values:
- allow_all: null - allow_all: null
condition: condition:
- description: test condition - description: test condition
expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
location: somewhere location: somewhere
title: condition title: condition
deny_all: null deny_all: null

View File

@ -1,9 +1,8 @@
org_policies = { org_policies = {
"iam.disableServiceAccountKeyCreation" = { "iam.disableServiceAccountKeyCreation" = {
enforce = true rules = [{ enforce = true }]
} }
"iam.disableServiceAccountKeyUpload" = { "iam.disableServiceAccountKeyUpload" = {
enforce = false
rules = [ rules = [
{ {
condition = { condition = {
@ -13,6 +12,9 @@ org_policies = {
location = "xxx" location = "xxx"
} }
enforce = true enforce = true
},
{
enforce = false
} }
] ]
} }

View File

@ -1,15 +1,17 @@
org_policies = { org_policies = {
"compute.vmExternalIpAccess" = { "compute.vmExternalIpAccess" = {
deny = { all = true } rules = [{ deny = { all = true } }]
} }
"iam.allowedPolicyMemberDomains" = { "iam.allowedPolicyMemberDomains" = {
inherit_from_parent = true inherit_from_parent = true
allow = { rules = [{
values = ["C0xxxxxxx", "C0yyyyyyy"] allow = {
} values = ["C0xxxxxxx", "C0yyyyyyy"]
}
}]
} }
"compute.restrictLoadBalancerCreationForTypes" = { "compute.restrictLoadBalancerCreationForTypes" = {
deny = { values = ["in:EXTERNAL"] }
rules = [ rules = [
{ {
condition = { condition = {
@ -32,6 +34,9 @@ org_policies = {
allow = { allow = {
all = true all = true
} }
},
{
deny = { values = ["in:EXTERNAL"] }
} }
] ]
} }