Skip to content

Commit 5c6ae0f

Browse files
committed
feat: change 'gitlab_group_id' and 'gitlab_project_id' variables to 'gitlab_group_ids' and 'gitlab_project_ids' allowing for multiple GitLab groups or projects configuration
1 parent c2acb40 commit 5c6ae0f

File tree

10 files changed

+154
-69
lines changed

10 files changed

+154
-69
lines changed

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,50 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

99
## [Unreleased]
1010

11+
## [0.5.0] - 2025-05-30
12+
13+
[Compare with previous version](https://github.com/sparkfabrik/terraform-google-gcp-gitlab-wif/compare/0.4.0...0.5.0)
14+
15+
### :warning: Breaking change
16+
17+
The variables `gitlab_group_id` and `gitlab_project_id` have been renamed to `gitlab_group_ids` and `gitlab_project_ids` and the type has been changed from `string` to `list(string)`. This allows for multiple group and project IDs to be specified.
18+
19+
You can update your configuration simply by changing the variable names and wrapping the existing values in a list, like this:
20+
21+
**From:**
22+
23+
```hcl
24+
module "example" {
25+
source = "github.com/sparkfabrik/terraform-google-gcp-gitlab-wif?ref=main"
26+
version = ">= 0.1.0"
27+
28+
name = "My Workload Identity Federation"
29+
gcp_project_id = "awesome-gcp-project"
30+
gitlab_project_id = 42
31+
}
32+
```
33+
34+
**To:**
35+
36+
```hcl
37+
module "example" {
38+
source = "github.com/sparkfabrik/terraform-google-gcp-gitlab-wif?ref=main"
39+
version = ">= 0.1.0"
40+
41+
name = "My Workload Identity Federation"
42+
gcp_project_id = "awesome-gcp-project"
43+
gitlab_project_ids = [42]
44+
}
45+
```
46+
47+
### Added
48+
49+
- You can add GitLab groups and projects together with the same module, allowing for more flexibility in managing multiple GitLab groups and projects usint the same OIDC provider configuration.
50+
51+
### Changed
52+
53+
- Change the variables `gitlab_group_id` and `gitlab_project_id` to `gitlab_group_ids` and `gitlab_project_ids`, allowing for multiple group and project IDs to be specified.
54+
1155
## [0.4.0] - 2025-05-29
1256

1357
[Compare with previous version](https://github.com/sparkfabrik/terraform-google-gcp-gitlab-wif/compare/0.3.1...0.4.0)

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ You can refer to the official [GitLab documentation](https://docs.gitlab.com/ci/
3434
| <a name="input_gitlab_gcp_wif_project_id_variable_name"></a> [gitlab\_gcp\_wif\_project\_id\_variable\_name](#input\_gitlab\_gcp\_wif\_project\_id\_variable\_name) | The name of the GitLab variable to store the GCP project ID for WIF. | `string` | `"GCP_WIF_PROJECT_ID"` | no |
3535
| <a name="input_gitlab_gcp_wif_provider_variable_name"></a> [gitlab\_gcp\_wif\_provider\_variable\_name](#input\_gitlab\_gcp\_wif\_provider\_variable\_name) | The name of the GitLab variable to store the GCP WIF provider name. | `string` | `"GCP_WIF_PROVIDER"` | no |
3636
| <a name="input_gitlab_gcp_wif_service_account_email_variable_name"></a> [gitlab\_gcp\_wif\_service\_account\_email\_variable\_name](#input\_gitlab\_gcp\_wif\_service\_account\_email\_variable\_name) | The name of the GitLab variable to store the GCP WIF service account email. | `string` | `"GCP_WIF_SERVICE_ACCOUNT_EMAIL"` | no |
37-
| <a name="input_gitlab_group_id"></a> [gitlab\_group\_id](#input\_gitlab\_group\_id) | The GitLab group ID to allow access from. Use this for group-level access. | `number` | `0` | no |
37+
| <a name="input_gitlab_group_ids"></a> [gitlab\_group\_ids](#input\_gitlab\_group\_ids) | The GitLab group IDs to allow access from. Use this for group-level access. | `list(number)` | `[]` | no |
3838
| <a name="input_gitlab_instance_url"></a> [gitlab\_instance\_url](#input\_gitlab\_instance\_url) | The URL of your GitLab instance. | `string` | `"https://gitlab.com"` | no |
39-
| <a name="input_gitlab_project_id"></a> [gitlab\_project\_id](#input\_gitlab\_project\_id) | The GitLab project ID to allow access from. Use this for project-level access. | `number` | `0` | no |
39+
| <a name="input_gitlab_project_ids"></a> [gitlab\_project\_ids](#input\_gitlab\_project\_ids) | The GitLab project IDs to allow access from. Use this for project-level access. | `list(number)` | `[]` | no |
4040
| <a name="input_gitlab_variables_additional"></a> [gitlab\_variables\_additional](#input\_gitlab\_variables\_additional) | Additional GitLab variables to create. This should be a map where the key is the variable name and the value is an object containing the variable properties. This allows you to define custom variables for project or group where the module is applied. | <pre>map(object({<br/> value = string<br/> protected = optional(bool, false)<br/> masked = optional(bool, false)<br/> description = optional(string, "Managed by {{MANAGER_NAME}}.")<br/> }))</pre> | `{}` | no |
4141
| <a name="input_gitlab_variables_description"></a> [gitlab\_variables\_description](#input\_gitlab\_variables\_description) | The description for the GitLab variables created by this module. You can use `{{MANAGER_NAME}}` to include the name of the 'manager' defined in `gitlab_variables_description_manager_name`. | `string` | `"Managed by {{MANAGER_NAME}}."` | no |
4242
| <a name="input_gitlab_variables_description_manager_name"></a> [gitlab\_variables\_description\_manager\_name](#input\_gitlab\_variables\_description\_manager\_name) | The name of the manager to include in the GitLab variable description. | `string` | `"terraform-google-gcp-gitlab-wif module"` | no |
@@ -49,7 +49,7 @@ You can refer to the official [GitLab documentation](https://docs.gitlab.com/ci/
4949
| Name | Description |
5050
|------|-------------|
5151
| <a name="output_gitlab_variables"></a> [gitlab\_variables](#output\_gitlab\_variables) | The GitLab variables created by this module. |
52-
| <a name="output_principal_set"></a> [principal\_set](#output\_principal\_set) | The principal set string used for IAM bindings. |
52+
| <a name="output_principal_set"></a> [principal\_set](#output\_principal\_set) | The principal sets string used for IAM bindings. |
5353
| <a name="output_secret_created"></a> [secret\_created](#output\_secret\_created) | The names and IDs of the secrets created by this module. |
5454
| <a name="output_secret_ids"></a> [secret\_ids](#output\_secret\_ids) | Map of original secret names to their Secret Manager secret IDs |
5555
| <a name="output_secret_names"></a> [secret\_names](#output\_secret\_names) | Map of original secret names to their formatted names |

examples/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module "example" {
77

88
name = var.name
99
gcp_project_id = var.gcp_project_id
10-
gitlab_project_id = var.gitlab_project_id
10+
gitlab_project_ids = var.gitlab_project_ids
1111
gitlab_instance_url = var.gitlab_instance_url
1212
secret_gcp_project_id = var.secret_gcp_project_id
1313
secret_names = var.secret_names

examples/test.tfvars

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "MyAwesomeWif"
22
gcp_project_id = "my-gcp-project-id"
3-
gitlab_project_id = 42
3+
gitlab_project_id = [42]
44
gitlab_instance_url = "https://my.gitlab.com"
55
secret_gcp_project_id = "my-gcp-secret-project-id"
66
secret_names = [

examples/variables.tf

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ variable "gcp_project_id" {
1010
}
1111

1212
# GitLab variables
13-
variable "gitlab_project_id" {
14-
description = "The GitLab project ID to allow access from. Use this for project-level access."
15-
type = string
13+
variable "gitlab_project_ids" {
14+
description = "The GitLab project IDs to allow access from. Use this for project-level access."
15+
type = list(number)
16+
default = []
1617
}
1718

1819
variable "gitlab_instance_url" {

gitlab.tf

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# GitLab group and project variables for Workload Identity Federation
22
# Group variables if `var.gitlab_group_id` is provided
33
resource "gitlab_group_variable" "gcp_wif_project_id" {
4-
count = local.is_gitlab_group_level ? 1 : 0
4+
for_each = length(var.gitlab_group_ids) > 0 ? toset(formatlist("%s", var.gitlab_group_ids)) : []
55

6-
group = var.gitlab_group_id
6+
group = each.value
77
key = var.gitlab_gcp_wif_project_id_variable_name
88
value = data.google_project.project.number
99
description = local.gitlab_variables_description
@@ -12,9 +12,9 @@ resource "gitlab_group_variable" "gcp_wif_project_id" {
1212
}
1313

1414
resource "gitlab_group_variable" "gcp_wif_pool" {
15-
count = local.is_gitlab_group_level ? 1 : 0
15+
for_each = length(var.gitlab_group_ids) > 0 ? toset(formatlist("%s", var.gitlab_group_ids)) : []
1616

17-
group = var.gitlab_group_id
17+
group = each.value
1818
key = var.gitlab_gcp_wif_pool_variable_name
1919
value = google_iam_workload_identity_pool.this.workload_identity_pool_id
2020
description = local.gitlab_variables_description
@@ -23,9 +23,9 @@ resource "gitlab_group_variable" "gcp_wif_pool" {
2323
}
2424

2525
resource "gitlab_group_variable" "gcp_wif_provider" {
26-
count = local.is_gitlab_group_level ? 1 : 0
26+
for_each = length(var.gitlab_group_ids) > 0 ? toset(formatlist("%s", var.gitlab_group_ids)) : []
2727

28-
group = var.gitlab_group_id
28+
group = each.value
2929
key = var.gitlab_gcp_wif_provider_variable_name
3030
value = google_iam_workload_identity_pool_provider.this.workload_identity_pool_provider_id
3131
description = local.gitlab_variables_description
@@ -34,9 +34,9 @@ resource "gitlab_group_variable" "gcp_wif_provider" {
3434
}
3535

3636
resource "gitlab_group_variable" "gcp_wif_service_account_email" {
37-
count = local.is_gitlab_group_level ? 1 : 0
37+
for_each = length(var.gitlab_group_ids) > 0 ? toset(formatlist("%s", var.gitlab_group_ids)) : []
3838

39-
group = var.gitlab_group_id
39+
group = each.value
4040
key = var.gitlab_gcp_wif_service_account_email_variable_name
4141
value = local.sa_email
4242
description = local.gitlab_variables_description
@@ -45,10 +45,12 @@ resource "gitlab_group_variable" "gcp_wif_service_account_email" {
4545
}
4646

4747
resource "gitlab_group_variable" "gitlab_variables_additional" {
48-
for_each = local.is_gitlab_group_level ? local.gitlab_variables_additional_final : {}
48+
for_each = length(var.gitlab_group_ids) > 0 ? {
49+
for key, val in local.gitlab_variables_additional_final : key => val if val.gitlab_resorce_type == local.group_resource_suffix
50+
} : {}
4951

50-
group = var.gitlab_group_id
51-
key = each.key
52+
group = each.value.gitlab_resource_id
53+
key = each.value.key
5254
value = each.value.value
5355
description = each.value.description
5456
protected = each.value.protected
@@ -57,9 +59,9 @@ resource "gitlab_group_variable" "gitlab_variables_additional" {
5759

5860
# Project variables if `var.gitlab_project_id` is provided
5961
resource "gitlab_project_variable" "gcp_wif_project_id" {
60-
count = local.is_gitlab_project_level ? 1 : 0
62+
for_each = length(var.gitlab_project_ids) ? toset(formatlist("%s", var.gitlab_project_ids)) : []
6163

62-
project = var.gitlab_project_id
64+
project = each.value
6365
key = var.gitlab_gcp_wif_project_id_variable_name
6466
value = data.google_project.project.number
6567
description = local.gitlab_variables_description
@@ -68,9 +70,9 @@ resource "gitlab_project_variable" "gcp_wif_project_id" {
6870
}
6971

7072
resource "gitlab_project_variable" "gcp_wif_pool" {
71-
count = local.is_gitlab_project_level ? 1 : 0
73+
for_each = length(var.gitlab_project_ids) ? toset(formatlist("%s", var.gitlab_project_ids)) : []
7274

73-
project = var.gitlab_project_id
75+
project = each.value
7476
key = var.gitlab_gcp_wif_pool_variable_name
7577
value = google_iam_workload_identity_pool.this.workload_identity_pool_id
7678
description = local.gitlab_variables_description
@@ -79,9 +81,9 @@ resource "gitlab_project_variable" "gcp_wif_pool" {
7981
}
8082

8183
resource "gitlab_project_variable" "gcp_wif_provider" {
82-
count = local.is_gitlab_project_level ? 1 : 0
84+
for_each = length(var.gitlab_project_ids) ? toset(formatlist("%s", var.gitlab_project_ids)) : []
8385

84-
project = var.gitlab_project_id
86+
project = each.value
8587
key = var.gitlab_gcp_wif_provider_variable_name
8688
value = google_iam_workload_identity_pool_provider.this.workload_identity_pool_provider_id
8789
description = local.gitlab_variables_description
@@ -90,9 +92,9 @@ resource "gitlab_project_variable" "gcp_wif_provider" {
9092
}
9193

9294
resource "gitlab_project_variable" "gcp_wif_service_account_email" {
93-
count = local.is_gitlab_project_level ? 1 : 0
95+
for_each = length(var.gitlab_project_ids) ? toset(formatlist("%s", var.gitlab_project_ids)) : []
9496

95-
project = var.gitlab_project_id
97+
project = each.value
9698
key = var.gitlab_gcp_wif_service_account_email_variable_name
9799
value = local.sa_email
98100
description = local.gitlab_variables_description
@@ -101,10 +103,12 @@ resource "gitlab_project_variable" "gcp_wif_service_account_email" {
101103
}
102104

103105
resource "gitlab_project_variable" "gitlab_variables_additional" {
104-
for_each = local.is_gitlab_project_level ? local.gitlab_variables_additional_final : {}
106+
for_each = length(var.gitlab_project_ids) ? {
107+
for key, val in local.gitlab_variables_additional_final : key => val if val.gitlab_resorce_type == local.group_resource_suffix
108+
} : {}
105109

106-
project = var.gitlab_project_id
107-
key = each.key
110+
project = each.value.gitlab_resource_id
111+
key = each.value.key
108112
value = each.value.value
109113
description = each.value.description
110114
protected = each.value.protected

locals.tf

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
locals {
2-
resource_name_suffix = "${var.name}-${random_id.suffix.hex}"
3-
is_gitlab_group_level = var.gitlab_group_id > 0
4-
is_gitlab_project_level = var.gitlab_project_id > 0
5-
attribute_condition = local.is_gitlab_project_level ? "assertion.project_id==\"${var.gitlab_project_id}\"" : "assertion.namespace_id==\"${var.gitlab_group_id}\""
6-
principal_subject = local.is_gitlab_project_level ? "attribute.project_id/${var.gitlab_project_id}" : "attribute.namespace_id/${var.gitlab_group_id}"
7-
principal_set = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.this.name}/${local.principal_subject}"
2+
resource_name_suffix = "${var.name}-${random_id.suffix.hex}"
3+
4+
project_resource_suffix = "project"
5+
group_resource_suffix = "group"
6+
custom_id_group_valid_attribute_name = "custom_is_group_valid"
7+
8+
projects_attribute_condition = "(${join(" || ", [for id in var.gitlab_project_ids : "attribute.project_id==\"${id}\""])})"
9+
groups_attribute_condition = "(attribute.${local.custom_id_group_valid_attribute_name}==\"1\")"
10+
attribute_condition = join(" || ", flatten([
11+
concat(
12+
length(var.gitlab_project_ids) > 0 ? [local.projects_attribute_condition] : [],
13+
length(var.gitlab_group_ids) > 0 ? [local.groups_attribute_condition] : []
14+
)
15+
]))
16+
17+
principal_subjects = merge(
18+
{ for id in var.gitlab_project_ids : "${local.project_resource_suffix}-${id}" => "attribute.project_id/${id}" },
19+
{ (local.group_resource_suffix) = "attribute.${local.custom_id_group_valid_attribute_name}/1" },
20+
)
21+
principal_sets = {
22+
for key, subject in local.principal_subjects : key => "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.this.name}/${subject}"
23+
}
824

925
# Ensure the account_id is always 28 characters or less
1026
sa_name_prefix = "gwif-sa-"
@@ -44,12 +60,35 @@ locals {
4460

4561
gitlab_variables_description = replace(var.gitlab_variables_description, "{{MANAGER_NAME}}", var.gitlab_variables_description_manager_name)
4662
gitlab_variables_additional_final = {
47-
for key, value in var.gitlab_variables_additional :
48-
key => merge(
49-
value,
50-
{
51-
description = replace(value.description, "{{MANAGER_NAME}}", var.gitlab_variables_description_manager_name)
52-
}
53-
)
63+
for item in flatten(concat([
64+
for gitlab_resource_id in var.gitlab_group_ids : [
65+
for key, value in var.gitlab_variables_additional : [
66+
merge(
67+
value,
68+
{
69+
gitlab_resorce_type = local.group_resource_suffix,
70+
gitlab_resource_id = gitlab_resource_id,
71+
key = key,
72+
description = replace(value.description, "{{MANAGER_NAME}}", var.gitlab_variables_description_manager_name)
73+
}
74+
)
75+
]
76+
]
77+
],
78+
[
79+
for gitlab_resource_id in var.gitlab_project_ids : [
80+
for key, value in var.gitlab_variables_additional : [
81+
merge(
82+
value,
83+
{
84+
gitlab_resorce_type = local.project_resource_suffix,
85+
gitlab_resource_id = gitlab_resource_id,
86+
key = key,
87+
description = replace(value.description, "{{MANAGER_NAME}}", var.gitlab_variables_description_manager_name)
88+
}
89+
)
90+
]
91+
]
92+
])) : "${item.key}--${item.gitlab_resorce_type}--${item.gitlab_resource_id}" => item
5493
}
5594
}

main.tf

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,8 @@ resource "google_iam_workload_identity_pool" "this" {
1616
lifecycle {
1717
# Prevent creation of resources if the module is not configured correctly
1818
precondition {
19-
condition = var.gitlab_group_id > 0 || var.gitlab_project_id > 0
20-
error_message = "Either gitlab_group_id or gitlab_project_id must be provided."
21-
}
22-
23-
precondition {
24-
condition = (var.gitlab_group_id > 0) != (var.gitlab_project_id > 0)
25-
error_message = "Only one of gitlab_group_id or gitlab_project_id should be provided, not both."
19+
condition = length(var.gitlab_group_ids) > 0 || length(var.gitlab_project_ids) > 0
20+
error_message = "Either gitlab_group_ids or gitlab_project_ids must be provided."
2621
}
2722
}
2823
}
@@ -58,7 +53,9 @@ data "google_service_account" "this" {
5853
}
5954

6055
resource "google_service_account_iam_member" "this" {
56+
for_each = local.principal_sets
57+
6158
service_account_id = local.sa_name
6259
role = "roles/iam.workloadIdentityUser"
63-
member = local.principal_set
60+
member = each.value
6461
}

outputs.tf

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ output "workload_identity_pool_name" {
66

77
output "workload_identity_pool_provider" {
88
description = "The full resource name of the Workload Identity Provider."
9-
value = google_iam_workload_identity_pool_provider.this.name
9+
value = google_iam_workload_identity_pool_provider.this.workload_identity_pool_provider_id
1010
}
1111
output "service_account_email" {
1212
description = "The email of the Service Account used."
1313
value = local.sa_email
1414
}
1515

1616
output "principal_set" {
17-
description = "The principal set string used for IAM bindings."
18-
value = local.principal_set
17+
description = "The principal sets string used for IAM bindings."
18+
value = local.principal_sets
1919
}
2020

2121
# GitLab variables outputs
@@ -28,9 +28,9 @@ output "gitlab_variables" {
2828
(var.gitlab_gcp_wif_provider_variable_name) = google_iam_workload_identity_pool_provider.this.name
2929
(var.gitlab_gcp_wif_service_account_email_variable_name) = local.sa_email
3030
},
31-
length(local.gitlab_variables_additional_final) > 0 ? {
32-
for key, value in local.gitlab_variables_additional_final :
33-
key => local.is_gitlab_group_level ? gitlab_group_variable.gitlab_variables_additional[key].value : gitlab_project_variable.gitlab_variables_additional[key].value
31+
length(var.gitlab_variables_additional) > 0 ? {
32+
for key, val in var.gitlab_variables_additional :
33+
key => val.value
3434
} : {}
3535
)
3636
}

0 commit comments

Comments
 (0)