Skip to content

Commit 99db651

Browse files
committed
feat: create service account as part of instance template module
1 parent 11a9137 commit 99db651

File tree

10 files changed

+208
-3
lines changed

10 files changed

+208
-3
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# instance-template-simple
2+
3+
This is a simple, minimal example of how to use the instance_template module.
4+
5+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
6+
## Inputs
7+
8+
| Name | Description | Type | Default | Required |
9+
|------|-------------|------|---------|:--------:|
10+
| enable\_nested\_virtualization | Defines whether the instance should have nested virtualization enabled. | `bool` | `false` | no |
11+
| labels | Labels, provided as a map | `map(string)` | n/a | yes |
12+
| project\_id | The GCP project to use for integration tests | `string` | n/a | yes |
13+
| region | The GCP region to create and test resources in | `string` | `"us-central1"` | no |
14+
| subnetwork | The name of the subnetwork create this instance in. | `string` | `""` | no |
15+
| tags | Network tags, provided as a list | `list(string)` | n/a | yes |
16+
| threads\_per\_core | The number of threads per physical core. To disable simultaneous multithreading (SMT) set this to 1. | `string` | `null` | no |
17+
18+
## Outputs
19+
20+
| Name | Description |
21+
|------|-------------|
22+
| name | Name of the instance templates |
23+
| self\_link | Self-link to the instance template |
24+
25+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
provider "google" {
18+
19+
project = var.project_id
20+
region = "us-central1"
21+
}
22+
23+
resource "google_compute_address" "ip_address" {
24+
name = "external-ip"
25+
}
26+
27+
locals {
28+
access_config = {
29+
nat_ip = google_compute_address.ip_address.address
30+
network_tier = "PREMIUM"
31+
}
32+
}
33+
34+
module "instance_template" {
35+
source = "../../../modules/instance_template"
36+
37+
project_id = var.project_id
38+
region = "us-central1"
39+
subnetwork = ""
40+
stack_type = "IPV4_ONLY"
41+
name_prefix = "simple"
42+
tags = var.tags
43+
labels = var.labels
44+
access_config = [local.access_config]
45+
enable_nested_virtualization = false
46+
threads_per_core = null
47+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
output "self_link" {
18+
description = "Self-link to the instance template"
19+
value = module.instance_template.self_link
20+
}
21+
22+
output "name" {
23+
description = "Name of the instance templates"
24+
value = module.instance_template.name
25+
}
26+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
19+
variable "project_id" {
20+
description = "The GCP project to use for integration tests"
21+
type = string
22+
}
23+
24+
variable "tags" {
25+
type = list(string)
26+
description = "Network tags, provided as a list"
27+
}
28+
29+
variable "labels" {
30+
type = map(string)
31+
description = "Labels, provided as a map"
32+
}

modules/instance_template/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
2121
| automatic\_restart | (Optional) Specifies whether the instance should be automatically restarted if it is terminated by Compute Engine (not terminated by a user). | `bool` | `true` | no |
2222
| can\_ip\_forward | Enable IP forwarding, for NAT instances for example | `string` | `"false"` | no |
2323
| confidential\_instance\_type | Defines the confidential computing technology the instance uses. If this is set to "SEV\_SNP", var.min\_cpu\_platform will be automatically set to "AMD Milan". See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#confidential_instance_type. | `string` | `null` | no |
24+
| create\_service\_account | Create a new service account to attach to the instance. This is alternate to providing the service\_account input variable. Please provide the service\_account input if setting this to false! | `bool` | `true` | no |
2425
| description | The template's description | `string` | `""` | no |
2526
| disk\_encryption\_key | The id of the encryption key that is stored in Google Cloud KMS to use to encrypt all the disks on this instance | `string` | `null` | no |
2627
| disk\_labels | Labels to be assigned to boot disk, provided as a map | `map(string)` | `{}` | no |
@@ -47,7 +48,8 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
4748
| project\_id | The GCP project ID | `string` | n/a | yes |
4849
| region | Region where the instance template should be created. | `string` | n/a | yes |
4950
| resource\_policies | A list of self\_links of resource policies to attach to the instance. Modifying this list will cause the instance to recreate. Currently a max of 1 resource policy is supported. | `list(string)` | `[]` | no |
50-
| service\_account | Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account. | <pre>object({<br> email = string<br> scopes = optional(set(string), ["cloud-platform"])<br> })</pre> | n/a | yes |
51+
| service\_account | Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account. | <pre>object({<br> email = string<br> scopes = optional(set(string), ["cloud-platform"])<br> })</pre> | `null` | no |
52+
| service\_account\_project\_roles | Roles to grant to the newly created cloud run SA in specified project. Should be used with create\_service\_account set to true and no input for service\_account | `list(string)` | `[]` | no |
5153
| shielded\_instance\_config | Not used unless enable\_shielded\_vm is true. Shielded VM configuration for the instance. | <pre>object({<br> enable_secure_boot = bool<br> enable_vtpm = bool<br> enable_integrity_monitoring = bool<br> })</pre> | <pre>{<br> "enable_integrity_monitoring": true,<br> "enable_secure_boot": true,<br> "enable_vtpm": true<br>}</pre> | no |
5254
| source\_image | Source disk image. If neither source\_image nor source\_image\_family is specified, defaults to the latest public Rocky Linux 9 optimized for GCP image. | `string` | `""` | no |
5355
| source\_image\_family | Source image family. If neither source\_image nor source\_image\_family is specified, defaults to the latest public Rocky Linux 9 optimized for GCP image. | `string` | `"rocky-linux-9-optimized-gcp"` | no |
@@ -69,6 +71,7 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
6971
| name | Name of instance template |
7072
| self\_link | Self-link of instance template |
7173
| self\_link\_unique | Unique self-link of instance template (recommended output to use instead of self\_link) |
74+
| service\_account\_info | Service account id and email |
7275
| tags | Tags that will be associated with instance(s) |
7376

7477
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

modules/instance_template/main.tf

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,40 @@ locals {
6363
# must be true when preemtible or spot is true
6464
var.preemptible || var.spot ? true : false
6565
)
66+
67+
service_account = (
68+
var.service_account != null
69+
? var.service_account
70+
: (
71+
var.create_service_account
72+
? { email : google_service_account.sa[0].email, scopes : ["cloud-platform"] }
73+
: null
74+
)
75+
)
76+
create_service_account = var.create_service_account ? var.service_account == null : false
77+
78+
service_account_prefix = substr("${var.name_prefix}-${var.region}", 0, 27)
79+
service_account_output = local.create_service_account ? {
80+
id = google_service_account.sa[0].account_id,
81+
email = google_service_account.sa[0].email,
82+
member = google_service_account.sa[0].member
83+
} : {}
84+
}
85+
86+
# Service account
87+
resource "google_service_account" "sa" {
88+
count = local.create_service_account ? 1 : 0
89+
project = var.project_id
90+
account_id = "${local.service_account_prefix}-sa"
91+
display_name = "Service account for ${var.name_prefix} in ${var.region}"
92+
}
93+
94+
resource "google_project_iam_member" "roles" {
95+
for_each = toset(distinct(var.service_account_project_roles))
96+
97+
project = var.project_id
98+
role = each.value
99+
member = "serviceAccount:${local.service_account.email}"
66100
}
67101

68102
####################
@@ -111,7 +145,7 @@ resource "google_compute_instance_template" "tpl" {
111145
}
112146

113147
dynamic "service_account" {
114-
for_each = var.service_account == null ? [] : [var.service_account]
148+
for_each = local.service_account == null ? [] : [local.service_account]
115149
content {
116150
email = lookup(service_account.value, "email", null)
117151
scopes = lookup(service_account.value, "scopes", null)

modules/instance_template/metadata.display.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ spec:
5858
confidential_instance_type:
5959
name: confidential_instance_type
6060
title: Confidential Instance Type
61+
create_new_service_account:
62+
name: create_new_service_account
63+
title: Create New Service Account
64+
create_service_account:
65+
name: create_service_account
66+
title: Create Service Account
6167
description:
6268
name: description
6369
title: Description
@@ -158,6 +164,9 @@ spec:
158164
service_account:
159165
name: service_account
160166
title: Service Account
167+
service_account_project_roles:
168+
name: service_account_project_roles
169+
title: Service Account Project Roles
161170
shielded_instance_config:
162171
name: shielded_instance_config
163172
title: Shielded Instance Config

modules/instance_template/metadata.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ spec:
7474
location: examples/preemptible_and_regular_instance_templates/simple
7575
- name: simple
7676
location: examples/umig/simple
77+
- name: simple_with_sa_creation
78+
location: examples/instance_template/simple_with_sa_creation
7779
- name: static_ips
7880
location: examples/umig/static_ips
7981
- name: tags
@@ -292,14 +294,21 @@ spec:
292294
email = string
293295
scopes = optional(set(string), ["cloud-platform"])
294296
})
295-
required: true
296297
connections:
297298
- source:
298299
source: github.com/terraform-google-modules/terraform-google-service-accounts//modules/simple-sa
299300
version: ">= 4.4"
300301
spec:
301302
outputExpr: email
302303
inputPath: email
304+
- name: create_service_account
305+
description: Create a new service account to attach to the instance. This is alternate to providing the service_account input variable. Please provide the service_account input if setting this to false!
306+
varType: bool
307+
defaultValue: true
308+
- name: service_account_project_roles
309+
description: Roles to grant to the newly created cloud run SA in specified project. Should be used with create_service_account set to true and no input for service_account
310+
varType: list(string)
311+
defaultValue: []
303312
- name: enable_shielded_vm
304313
description: Whether to enable the Shielded VM configuration on the instance. Note that the instance image must support Shielded VMs. See https://cloud.google.com/compute/docs/images
305314
varType: bool
@@ -365,6 +374,8 @@ spec:
365374
- name: self_link_unique
366375
description: Unique self-link of instance template (recommended output to use instead of self_link)
367376
type: string
377+
- name: service_account_info
378+
description: Service account id and email
368379
- name: tags
369380
description: Tags that will be associated with instance(s)
370381
type:

modules/instance_template/outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ output "tags" {
3333
description = "Tags that will be associated with instance(s)"
3434
value = google_compute_instance_template.tpl.tags
3535
}
36+
37+
output "service_account_info" {
38+
description = "Service account id and email"
39+
value = local.service_account_output
40+
}

modules/instance_template/variables.tf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,19 @@ variable "service_account" {
328328
scopes = optional(set(string), ["cloud-platform"])
329329
})
330330
description = "Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account."
331+
default = null
332+
}
333+
334+
variable "create_service_account" {
335+
type = bool
336+
description = "Create a new service account to attach to the instance. This is alternate to providing the service_account input variable. Please provide the service_account input if setting this to false!"
337+
default = true
338+
}
339+
340+
variable "service_account_project_roles" {
341+
type = list(string)
342+
description = "Roles to grant to the newly created cloud run SA in specified project. Should be used with create_service_account set to true and no input for service_account"
343+
default = []
331344
}
332345

333346
###########################

0 commit comments

Comments
 (0)