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

Feature/add groups creation #757

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
new groups module + changing 0-bootstrap step to use this module
  • Loading branch information
mauro-cit committed Jul 7, 2022
commit dde9224e4502a3ad8e135b59e141823b105e39c7
16 changes: 16 additions & 0 deletions 0-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,22 @@ For more information about the permissions that are required, and the resources
that are created, see the organization bootstrap module
[documentation.](https://github.com/terraform-google-modules/terraform-google-bootstrap)

### Optional - Automatic creation of required groups

Google Cloud Identity groups are used for [authentication and access management](https://cloud.google.com/architecture/security-foundations/authentication-authorization) in the foundation.

To enable automatic creation of the [required groups](https://cloud.google.com/architecture/security-foundations/authentication-authorization#users_and_groups) you need to:

- Have an existing project for Cloud Identity API billing.
- Enable the Cloud Identity API(`cloudidentity.googleapis.com`) on the billing project.
- Grant role `roles/serviceusage.serviceUsageConsumer` to the user running Terraform on the billing project.
- Uncomment the `google-beta` provider definition at the [provider.tf](https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/0-bootstrap/provider.tf).
- Provide values for the groups and billing project in the variable `create_groups_holder`.

All groups in the `create_groups_holder.required_groups` are required.

All groups in the `create_groups_holder.optional_groups` are optional.

### Troubleshooting

Please refer to [troubleshooting](../docs/TROUBLESHOOTING.md) if you run into issues during this step.
Expand Down
28 changes: 23 additions & 5 deletions 0-bootstrap/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ locals {
org_admins_org_iam_permissions = var.org_policy_admin_role == true ? [
"roles/orgpolicy.policyAdmin", "roles/resourcemanager.organizationAdmin", "roles/billing.user"
] : ["roles/resourcemanager.organizationAdmin", "roles/billing.user"]
group_org_admins = var.create_groups_holder.create_groups == false ? var.group_org_admins : element(module.google_groups[*].created_required_groups, 0).group_org_admins
group_billing_admins = var.create_groups_holder.create_groups == false ? var.group_billing_admins : element(module.google_groups[*].created_required_groups, 0).group_billing_admins
}

resource "google_folder" "bootstrap" {
Expand All @@ -37,8 +39,8 @@ module "seed_bootstrap" {
project_id = "${var.project_prefix}-b-seed"
state_bucket_name = "${var.bucket_prefix}-b-tfstate"
billing_account = var.billing_account
group_org_admins = var.group_org_admins
group_billing_admins = var.group_billing_admins
group_org_admins = local.group_org_admins
group_billing_admins = local.group_billing_admins
default_region = var.default_region
org_project_creators = var.org_project_creators
sa_enable_impersonation = true
Expand All @@ -47,7 +49,7 @@ module "seed_bootstrap" {
project_prefix = var.project_prefix

# Remove after github.com/terraform-google-modules/terraform-google-bootstrap/issues/160
depends_on = [google_folder.bootstrap]
depends_on = [google_folder.bootstrap, module.google_groups.required_groups]

project_labels = {
environment = "bootstrap"
Expand Down Expand Up @@ -94,6 +96,7 @@ module "seed_bootstrap" {
"roles/securitycenter.notificationConfigEditor",
"roles/resourcemanager.organizationViewer"
]

}

resource "google_billing_account_iam_member" "tf_billing_admin" {
Expand All @@ -110,7 +113,7 @@ module "cloudbuild_bootstrap" {
folder_id = google_folder.bootstrap.id
project_id = "${var.project_prefix}-b-cicd"
billing_account = var.billing_account
group_org_admins = var.group_org_admins
group_org_admins = local.group_org_admins
default_region = var.default_region
terraform_sa_email = module.seed_bootstrap.terraform_sa_email
terraform_sa_name = module.seed_bootstrap.terraform_sa_name
Expand All @@ -125,7 +128,7 @@ module "cloudbuild_bootstrap" {
terraform_version_sha256sum = "4a52886e019b4fdad2439da5ff43388bbcc6cce9784fde32c53dcd0e28ca9957"

# Remove after github.com/terraform-google-modules/terraform-google-bootstrap/issues/160
depends_on = [module.seed_bootstrap]
depends_on = [module.seed_bootstrap, module.google_groups.required_groups]

activate_apis = [
"serviceusage.googleapis.com",
Expand Down Expand Up @@ -157,8 +160,10 @@ module "cloudbuild_bootstrap" {
"non\\-production", //non-production needs a \ to ensure regex matches correct branches.
"production"
]

}


// Standalone repo for Terraform-validator policies.
// This repo does not need to trigger builds in Cloud Build.
resource "google_sourcerepo_repository" "gcp_policies" {
Expand Down Expand Up @@ -272,3 +277,16 @@ resource "google_folder_iam_member" "folder_tf_compute_security_resource_admin"
# role = "roles/browser"
# member = "serviceAccount:${module.jenkins_bootstrap.jenkins_agent_sa_email}"
# }


#Groups creation resources
data "google_organization" "org" {
mauro-cit marked this conversation as resolved.
Show resolved Hide resolved
organization = var.org_id
}

module "google_groups" {
count = var.create_groups_holder.create_groups ? 1 : 0
source = "./modules/groups"
mauro-cit marked this conversation as resolved.
Show resolved Hide resolved
create_groups_holder = var.create_groups_holder
customer_id = data.google_organization.org.directory_customer_id
}
39 changes: 39 additions & 0 deletions 0-bootstrap/modules/groups/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

module "required_group" {
for_each = tomap(var.create_groups_holder.required_groups)
source = "terraform-google-modules/group/google"
version = "~> 0.1"

id = each.value
display_name = each.key
description = each.key
initial_group_config = var.initial_group_config
customer_id = var.customer_id
}

module "optional_group" {
for_each = var.create_groups_holder.optional_groups != null ? tomap(var.create_groups_holder.optional_groups) : {}
source = "terraform-google-modules/group/google"
version = "~> 0.1"

id = each.value
display_name = each.key
description = each.key
initial_group_config = var.initial_group_config
customer_id = var.customer_id
}
23 changes: 23 additions & 0 deletions 0-bootstrap/modules/groups/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

output "created_required_groups" {
value = var.create_groups_holder.required_groups
}

output "created_optinal_groups" {
value = var.create_groups_holder.optional_groups
}
121 changes: 121 additions & 0 deletions 0-bootstrap/modules/groups/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

variable "create_groups_holder" {
mauro-cit marked this conversation as resolved.
Show resolved Hide resolved
description = "Contain the details of the Groups to be created"
type = object({
create_groups = bool
bharathkkb marked this conversation as resolved.
Show resolved Hide resolved
required_groups = object({
group_org_admins = string
group_billing_admins = string
billing_data_users = string
audit_data_users = string
monitoring_workspace_users = string
})
optional_groups = object({
gcp_platform_viewer = string
gcp_security_reviewer = string
gcp_network_viewer = string
gcp_scc_admin = string
gcp_global_secrets_admin = string
gcp_audit_viewer = string
})
})
default = {
create_groups = false
required_groups = {
group_org_admins = ""
group_billing_admins = ""
billing_data_users = ""
audit_data_users = ""
monitoring_workspace_users = ""
}
optional_groups = {
gcp_platform_viewer = ""
gcp_security_reviewer = ""
gcp_network_viewer = ""
gcp_scc_admin = ""
gcp_global_secrets_admin = ""
gcp_audit_viewer = ""
}
}

validation {
condition = var.create_groups_holder.create_groups == true ? can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.required_groups.group_org_admins)) : true
mauro-cit marked this conversation as resolved.
Show resolved Hide resolved
error_message = "The group group_org_admins is invalid. Only valid format emails Required Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.required_groups.group_billing_admins)) : true
error_message = "The group group_billing_admins is invalid. Only valid format emails Required Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.required_groups.billing_data_users)) : true
error_message = "The group billing_data_users is invalid. Only valid format emails Required Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.required_groups.audit_data_users)) : true
error_message = "The group audit_data_users is invalid. Only valid format emails Required Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.required_groups.monitoring_workspace_users)) : true
error_message = "The group monitoring_workspace_users is invalid. Only valid format emails Required Groups creation."
}


validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_platform_viewer == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_platform_viewer))) : true
error_message = "The group gcp_platform_viewer is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_security_reviewer == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_security_reviewer))) : true
error_message = "The group gcp_security_reviewer is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_network_viewer == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_network_viewer))) : true
error_message = "The group gcp_network_viewer is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_scc_admin == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_scc_admin))) : true
error_message = "The group gcp_scc_admin is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_global_secrets_admin == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_global_secrets_admin))) : true
error_message = "The group gcp_global_secrets_admin is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

validation {
condition = var.create_groups_holder.create_groups == true ? (var.create_groups_holder.optional_groups.gcp_audit_viewer == "" ? true : can(regex("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?[.])+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", var.create_groups_holder.optional_groups.gcp_audit_viewer))) : true
error_message = "The group gcp_audit_viewer is invalid. Only valid format emails or empty strings are valid for Optional Groups creation."
}

}

variable "customer_id" {
type = string
}

variable "initial_group_config" {
type = string
default = "WITH_INITIAL_OWNER"
}
15 changes: 15 additions & 0 deletions 0-bootstrap/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,18 @@ output "terraform_validator_policies_repo" {
// description = "Bucket used to store Jenkins artifacts in Jenkins project."
// value = module.jenkins_bootstrap.gcs_bucket_jenkins_artifacts
//}


/* ----------------------------------------
Specific to Google Groups creation module
---------------------------------------- */

output "required_groups" {
description = "List of Google Groups created that are required by the Example Foundation steps."
value = var.create_groups_holder.create_groups == true ? element(module.google_groups[*].created_required_groups, 0) : {}
}

output "optional_groups" {
description = "List of Google Groups created that are optional to the Example Foundation steps."
value = var.create_groups_holder.create_groups == true ? element(module.google_groups[*].created_optinal_groups, 0) : {}
}
23 changes: 23 additions & 0 deletions 0-bootstrap/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Uncomment this provider definition in order to be able to perform the Groups Creation
*provider "google-beta" {
mauro-cit marked this conversation as resolved.
Show resolved Hide resolved
* user_project_override = true
* billing_project = var.billing_project
*}
*/
21 changes: 21 additions & 0 deletions 0-bootstrap/terraform.example.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,24 @@ default_region = "us-central1"
//tunnel1_bgp_peer_address = "169.254.2.1"
//
//tunnel1_bgp_session_range = "169.254.2.2/30"
//
//create_groups_holder = {
// create_groups = true,
// required_groups = {
// group_org_admins = "group_org_admins_local_test@example.com"
// group_billing_admins = "group_billing_admins_local_test@example.com"
// billing_data_users = "billing_data_users_local_test@example.com"
// audit_data_users = "audit_data_users_local_test@example.com"
// monitoring_workspace_users = "monitoring_workspace_users_local_test@example.com"
// },
// optional_groups = {
// gcp_platform_viewer = "gcp_platform_viewer_local_test@example.com"
// gcp_security_reviewer = "gcp_security_reviewer_local_test@example.com"
// gcp_network_viewer = "gcp_network_viewer_local_test@example.com"
// gcp_scc_admin = "gcp_scc_admin_local_test@example.com"
// gcp_global_secrets_admin = "gcp_global_secrets_admin_local_test@example.com"
// gcp_audit_viewer = "gcp_audit_viewer_local_test@example.com"
// }
//}
//
//billing_project = "billing-project"
Loading