Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 6408dcd

Browse files
westonplatterGowiemCopilot
authored
feat(INT-53): bring in tf module from existing repo (#1)
## what - bring in existing postgres module under new repo name <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced comprehensive support for managing Google Workspace users, groups, group settings, and group memberships via Terraform. - Added detailed input variables for users and groups with extensive validation. - Provided example configurations and import workflows for existing organizations using YAML and Terraform files. - **Documentation** - Rewrote and expanded the README with Google Workspace-specific usage instructions, examples, and input schemas. - Updated provider and resource documentation to reflect new functionality. - **Bug Fixes** - Improved input validation for user and group attributes, ensuring correct email formats and allowed values. - **Tests** - Added extensive test coverage for user and group variable validation, including edge cases and failure scenarios. - **Chores** - Updated .gitignore rules and removed outdated changelog entries. - Removed obsolete outputs and variables related to previous random resource usage. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Matt Gowie <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 5387f28 commit 6408dcd

21 files changed

+1032
-42
lines changed

.github/renovate.json5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@
6161
"groupName": "tf"
6262
}
6363
]
64-
}
64+
}

.gitignore

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99
# Local .terraform directories
1010
**/.terraform/*
1111

12+
# Example terraform lock files
13+
examples/**/*.terraform.lock.hcl
14+
1215
# Ignore the root .terraform.lock.hcl file (Child modules don't want this)
1316
.terraform.lock.hcl
14-
!examples/**/.terraform.lock.hcl
17+
# !examples/**/.terraform.lock.hcl
18+
19+
# Ignore the live-providers.tf file
20+
examples/**/live-provider.tf
1521

1622
# IDE/Editor settings
1723
**/.idea
@@ -44,3 +50,6 @@ backend.tf.json
4450
**/*.bak
4551
**/*.*swp
4652
**/.DS_Store
53+
54+
55+

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Changelog
22

3-
## [0.7.0](https://github.com/masterpointio/terraform-module-template/compare/v0.6.0...v0.7.0) (2025-05-07)
4-
53

64
### Features
75

README.md

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,82 @@
11
[![Banner][banner-image]](https://masterpoint.io/)
22

3-
# terraform-module-template
3+
# terraform-googleworkspace-users-groups-automation
44

55
[![Release][release-badge]][latest-release]
66

77
💡 Learn more about Masterpoint [below](#who-we-are-𐦂𖨆𐀪𖠋).
88

99
## Purpose and Functionality
1010

11-
This repository serves as a template for creating Terraform modules, providing a standardized structure and essential files for efficient module development. It's designed to ensure consistency and our best practices across Terraform projects.
11+
This is a [child-module](https://opentofu.org/docs/language/modules/#child-modules) for managing Google Workspace users, groups, and roles.
1212

1313
## Usage
1414

15-
### Prerequisites (optional)
16-
17-
TODO
18-
1915
### Step-by-Step Instructions
2016

21-
TODO
17+
There are 2 provider authentication routes available,
18+
1 - authenticate a service account via API keys
19+
2 - authenticate using API keys and impersonate a real User with Super Admin privileges.
20+
21+
We recommend impersonating a Super Admin, which allows you to grant Admin privileges to users (service Accounts cannot do this).
22+
23+
Follow the provider [authentication setup instructions](https://github.com/hashicorp/terraform-provider-googleworkspace/blob/main/docs/index.md#google-workspace-provider).
24+
25+
<!-- TODO(weston) - provide step by step instructions for setting this up -->
26+
27+
Once you've finished the setup process, your provider block should look like this,
28+
29+
```hcl
30+
provider "googleworkspace" {
31+
# use 'my_customer', which is an alias that Google's API recognizes to reference your account's customerId.
32+
# For example - Custom Schemas on the user object will fail if the customer_id is set to your actual customer_id.
33+
# For more details see: https://developers.google.com/workspace/admin/directory/reference/rest/v1/schemas/get
34+
customer_id = "my_customer"
35+
36+
credentials = "/path/to/credentials/my-google-project-credentials-1234567890.json"
37+
impersonated_user_email = "my_impersonated_user_email@my_domain.com"
38+
39+
oauth_scopes = [
40+
"https://www.googleapis.com/auth/admin.directory.group",
41+
"https://www.googleapis.com/auth/admin.directory.user",
42+
"https://www.googleapis.com/auth/admin.directory.userschema",
43+
"https://www.googleapis.com/auth/apps.groups.settings",
44+
"https://www.googleapis.com/auth/iam",
45+
]
46+
}
47+
```
48+
49+
## Example
50+
51+
```hcl
52+
module "googleworkspace_users_groups" {
53+
source = "git::https://github.com/masterpointio/terraform-googleworkspace-users-groups-automation.git"
54+
55+
users = {
56+
57+
primary_email = "[email protected]"
58+
family_name = "Last"
59+
given_name = "First"
60+
password = "example-password"
61+
groups = {
62+
"platform" = {
63+
role = "member"
64+
}
65+
}
66+
}
67+
}
68+
69+
groups = {
70+
"platform" = {
71+
name = "Platform"
72+
73+
settings = {
74+
who_can_join = "ALL_IN_DOMAIN_CAN_JOIN"
75+
}
76+
}
77+
}
78+
}
79+
```
2280

2381
<!-- prettier-ignore-start -->
2482
<!-- markdownlint-disable MD013 -->
@@ -28,13 +86,13 @@ TODO
2886
| Name | Version |
2987
|------|---------|
3088
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
31-
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.0 |
89+
| <a name="requirement_googleworkspace"></a> [googleworkspace](#requirement\_googleworkspace) | >= 0.7.0 |
3290

3391
## Providers
3492

3593
| Name | Version |
3694
|------|---------|
37-
| <a name="provider_random"></a> [random](#provider\_random) | >= 3.0 |
95+
| <a name="provider_googleworkspace"></a> [googleworkspace](#provider\_googleworkspace) | >= 0.7.0 |
3896

3997
## Modules
4098

@@ -46,7 +104,10 @@ TODO
46104

47105
| Name | Type |
48106
|------|------|
49-
| [random_pet.template](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource |
107+
| [googleworkspace_group.defaults](https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs/resources/group) | resource |
108+
| [googleworkspace_group_member.user_to_groups](https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs/resources/group_member) | resource |
109+
| [googleworkspace_group_settings.defaults](https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs/resources/group_settings) | resource |
110+
| [googleworkspace_user.defaults](https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs/resources/user) | resource |
50111

51112
## Inputs
52113

@@ -59,24 +120,23 @@ TODO
59120
| <a name="input_descriptor_formats"></a> [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.<br/>Map of maps. Keys are names of descriptors. Values are maps of the form<br/>`{<br/> format = string<br/> labels = list(string)<br/>}`<br/>(Type is `any` so the map values can later be enhanced to provide additional options.)<br/>`format` is a Terraform format string to be passed to the `format()` function.<br/>`labels` is a list of labels, in order, to pass to `format()` function.<br/>Label values will be normalized before being passed to `format()` so they will be<br/>identical to how they appear in `id`.<br/>Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
60121
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
61122
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
123+
| <a name="input_groups"></a> [groups](#input\_groups) | List of groups | <pre>map(object({<br/> name : string,<br/> description : optional(string),<br/> email : string,<br/> timeouts : optional(object({<br/> create : optional(string),<br/> update : optional(string),<br/> }), {<br/> create = null<br/> update = null<br/> }),<br/> # https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs/resources/group_settings<br/> settings : optional(object({<br/> allow_external_members : optional(bool),<br/> allow_web_posting : optional(bool),<br/> archive_only : optional(bool),<br/> custom_footer_text : optional(string),<br/> custom_reply_to : optional(string),<br/> default_message_deny_notification_text : optional(string),<br/> enable_collaborative_inbox : optional(bool),<br/> include_custom_footer : optional(bool),<br/> include_in_global_address_list : optional(bool),<br/> is_archived : optional(bool),<br/> members_can_post_as_the_group : optional(bool),<br/> message_moderation_level : optional(string),<br/> primary_language : optional(string),<br/> reply_to : optional(string),<br/> send_message_deny_notification : optional(bool),<br/> spam_moderation_level : optional(string),<br/> who_can_assist_content : optional(string),<br/> who_can_contact_owner : optional(string),<br/> who_can_discover_group : optional(string),<br/> who_can_join : optional(string),<br/> who_can_leave_group : optional(string),<br/> who_can_moderate_content : optional(string),<br/> who_can_moderate_members : optional(string),<br/> who_can_post_message : optional(string),<br/> who_can_view_group : optional(string),<br/> who_can_view_membership : optional(string),<br/> }), {}),<br/> }))</pre> | `{}` | no |
62124
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br/>Set to `0` for unlimited length.<br/>Set to `null` for keep the existing setting, which defaults to `0`.<br/>Does not affect `id_full`. | `number` | `null` | no |
63125
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br/>Does not affect keys of tags passed in via the `tags` input.<br/>Possible values: `lower`, `title`, `upper`.<br/>Default value: `title`. | `string` | `null` | no |
64126
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br/>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br/>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
65127
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br/>set as tag values, and output by this module individually.<br/>Does not affect values of tags passed in via the `tags` input.<br/>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br/>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br/>Default value: `lower`. | `string` | `null` | no |
66128
| <a name="input_labels_as_tags"></a> [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.<br/>Default is to include all labels.<br/>Tags with empty values will not be included in the `tags` output.<br/>Set to `[]` to suppress all generated tags.<br/>**Notes:**<br/> The value of the `name` tag, if included, will be the `id`, not the `name`.<br/> Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be<br/> changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` | <pre>[<br/> "default"<br/>]</pre> | no |
67-
| <a name="input_length"></a> [length](#input\_length) | The length of the random name | `number` | `2` | no |
68129
| <a name="input_name"></a> [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.<br/>This is the only ID element not also included as a `tag`.<br/>The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no |
69130
| <a name="input_namespace"></a> [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |
70131
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.<br/>Characters matching the regex will be removed from the ID elements.<br/>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
71132
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
72133
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br/>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
73134
| <a name="input_tenant"></a> [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no |
135+
| <a name="input_users"></a> [users](#input\_users) | List of users | <pre>map(object({<br/> # addresses<br/> aliases : optional(list(string), []),<br/> archived : optional(bool, false),<br/> change_password_at_next_login : optional(bool),<br/> # custom_schemas<br/> # emails<br/> # external_ids<br/> family_name : string,<br/> given_name : string,<br/> groups : optional(map(object({<br/> role : optional(string, "MEMBER"),<br/> delivery_settings : optional(string, "ALL_MAIL"),<br/> type : optional(string, "USER"),<br/> })), {}),<br/> # ims<br/> include_in_global_address_list : optional(bool),<br/> ip_allowlist : optional(bool),<br/> is_admin : optional(bool),<br/> # keywords<br/> # languages<br/> # locations<br/> org_unit_path : optional(string),<br/> # organizations<br/> # phones<br/> # posix_accounts<br/> primary_email : string,<br/> recovery_email : optional(string),<br/> recovery_phone : optional(string),<br/> # relations<br/> # ssh_public_keys<br/> suspended : optional(bool),<br/> # timeouts<br/> # websites<br/><br/> # User attributes with unique constraints<br/><br/> # password and hash_function<br/> # If a hashFunction is specified, the password must be a valid hash key.<br/> # If it's not specified, the password should be in clear text and between<br/> # 8–100 ASCII characters.<br/> # https://developers.google.com/workspace/admin/directory/v1/guides/manage-users<br/> hash_function : optional(string),<br/> password : optional(string),<br/> }))</pre> | `{}` | no |
74136

75137
## Outputs
76138

77-
| Name | Description |
78-
|------|-------------|
79-
| <a name="output_random_pet_name"></a> [random\_pet\_name](#output\_random\_pet\_name) | The generated random pet name |
139+
No outputs.
80140
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
81141
<!-- markdownlint-enable MD013 -->
82142
<!-- prettier-ignore-end -->
@@ -138,11 +198,8 @@ Copyright © 2016-2025 [Masterpoint Consulting LLC](https://masterpoint.io/)
138198
[newsletter-url]: https://newsletter.masterpoint.io/
139199
[youtube-badge]: https://img.shields.io/badge/YouTube-Subscribe-D191BF?style=for-the-badge&logo=youtube&logoColor=white
140200
[youtube-url]: https://www.youtube.com/channel/UCeeDaO2NREVlPy9Plqx-9JQ
141-
142-
<!-- TODO: Replace `terraform-module-template` with your actual repository name. -->
143-
144-
[release-badge]: https://img.shields.io/github/v/release/masterpointio/terraform-module-template?color=0E383A&label=Release&style=for-the-badge&logo=github&logoColor=white
145-
[latest-release]: https://github.com/masterpointio/terraform-module-template/releases/latest
146-
[contributors-image]: https://contrib.rocks/image?repo=masterpointio/terraform-module-template
147-
[contributors-url]: https://github.com/masterpointio/terraform-module-template/graphs/contributors
148-
[issues-url]: https://github.com/masterpointio/terraform-module-template/issues
201+
[release-badge]: https://img.shields.io/github/v/release/masterpointio/terraform-googleworkspace-users-groups-automation?color=0E383A&label=Release&style=for-the-badge&logo=github&logoColor=white
202+
[latest-release]: https://github.com/masterpointio/terraform-googleworkspace-users-groups-automation/releases/latest
203+
[contributors-image]: https://contrib.rocks/image?repo=masterpointio/terraform-googleworkspace-users-groups-automation
204+
[contributors-url]: https://github.com/masterpointio/terraform-googleworkspace-users-groups-automation/graphs/contributors
205+
[issues-url]: https://github.com/masterpointio/terraform-googleworkspace-users-groups-automation/issues

examples/complete/main.tf

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,58 @@
1-
# complete.tf
1+
locals {
2+
default_group_settings = {
3+
allow_external_members = false
4+
allow_web_posting = true
5+
archive_only = false
6+
custom_roles_enabled_for_settings_to_be_merged = false
7+
enable_collaborative_inbox = false
8+
is_archived = false
9+
primary_language = "en_US"
10+
who_can_join = "ALL_IN_DOMAIN_CAN_JOIN"
11+
who_can_assist_content = "OWNERS_AND_MANAGERS"
12+
who_can_view_group = "ALL_IN_DOMAIN_CAN_VIEW"
13+
who_can_view_membership = "ALL_IN_DOMAIN_CAN_VIEW"
14+
}
15+
}
16+
17+
18+
module "googleworkspace" {
19+
source = "../../"
20+
21+
users = {
22+
23+
primary_email = "[email protected]"
24+
family_name = "Last"
25+
given_name = "First"
26+
password = "insecure-password-for-example" # trunk-ignore(checkov/CKV_SECRET_6)
27+
groups = {
28+
"platform" = {
29+
role = "MEMBER"
30+
}
31+
}
32+
}
33+
}
34+
35+
groups = {
36+
"support" = {
37+
name = "Support"
38+
39+
settings = merge(local.default_group_settings, {
40+
enable_collaborative_inbox = true,
41+
})
42+
},
43+
"platform" = {
44+
name = "Platform"
45+
46+
settings = merge(local.default_group_settings, {})
47+
},
48+
"engineers" = {
49+
name = "Engineering"
50+
51+
settings = merge(local.default_group_settings, {
52+
who_can_join = "INVITED_CAN_JOIN",
53+
who_can_view_group = "ALL_MEMBERS_CAN_VIEW",
54+
who_can_view_membership = "ALL_MEMBERS_CAN_VIEW",
55+
})
56+
}
57+
}
58+
}

examples/complete/outputs.tf

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/complete/providers.tf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
provider "googleworkspace" {
2+
# # use the 'my_customer' string, which is an alias that Google's API recognizes to reference your account's customerId.
3+
# # Custom Schemas on the user object will fail if the customer_id is set to your actual customer_id.
4+
# # For more details see: https://developers.google.com/workspace/admin/directory/reference/rest/v1/schemas/get
5+
customer_id = "my_customer"
6+
7+
credentials = "/Users/my_user/Downloads/my-google-project-credentials-1234567890.json"
8+
impersonated_user_email = "my_impersonated_user_email@my_domain.com"
9+
10+
oauth_scopes = [
11+
"https://www.googleapis.com/auth/admin.directory.group",
12+
"https://www.googleapis.com/auth/admin.directory.user",
13+
"https://www.googleapis.com/auth/admin.directory.userschema",
14+
"https://www.googleapis.com/auth/apps.groups.settings",
15+
"https://www.googleapis.com/auth/iam",
16+
]
17+
}

examples/complete/variables.tf

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/complete/versions.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
googleworkspace = {
6+
source = "hashicorp/googleworkspace"
7+
version = "0.7.0"
8+
}
9+
}
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
_default_active_settings: &default_active_settings
3+
allow_external_members: false
4+
allow_web_posting: true
5+
archive_only: false
6+
custom_roles_enabled_for_settings_to_be_merged: false
7+
enable_collaborative_inbox: false
8+
is_archived: false
9+
primary_language: en_US
10+
who_can_join: ALL_IN_DOMAIN_CAN_JOIN
11+
who_can_assist_content: OWNERS_AND_MANAGERS
12+
who_can_view_group: ALL_IN_DOMAIN_CAN_VIEW
13+
who_can_view_membership: ALL_IN_DOMAIN_CAN_VIEW
14+
15+
team:
16+
17+
name: Engineering Team
18+
description: Engineering Team that all technical employees are members of by default
19+
is_admin: false
20+
settings:
21+
<<: *default_active_settings

0 commit comments

Comments
 (0)