Skip to content

Commit

Permalink
feat: create service account as part of instance template module
Browse files Browse the repository at this point in the history
  • Loading branch information
q2w committed Jan 25, 2025
1 parent b5aa23a commit 4fd9e5f
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 3 deletions.
25 changes: 25 additions & 0 deletions examples/instance_template/simple_with_sa_creation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# instance-template-simple

This is a simple, minimal example of how to use the instance_template module.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| enable\_nested\_virtualization | Defines whether the instance should have nested virtualization enabled. | `bool` | `false` | no |
| labels | Labels, provided as a map | `map(string)` | n/a | yes |
| project\_id | The GCP project to use for integration tests | `string` | n/a | yes |
| region | The GCP region to create and test resources in | `string` | `"us-central1"` | no |
| subnetwork | The name of the subnetwork create this instance in. | `string` | `""` | no |
| tags | Network tags, provided as a list | `list(string)` | n/a | yes |
| threads\_per\_core | The number of threads per physical core. To disable simultaneous multithreading (SMT) set this to 1. | `string` | `null` | no |

## Outputs

| Name | Description |
|------|-------------|
| name | Name of the instance templates |
| self\_link | Self-link to the instance template |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
47 changes: 47 additions & 0 deletions examples/instance_template/simple_with_sa_creation/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2025 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.
*/

provider "google" {

project = var.project_id
region = "us-central1"
}

resource "google_compute_address" "ip_address" {
name = "external-ip"
}

locals {
access_config = {
nat_ip = google_compute_address.ip_address.address
network_tier = "PREMIUM"
}
}

module "instance_template" {
source = "../../../modules/instance_template"

project_id = var.project_id
region = "us-central1"
subnetwork = ""
stack_type = "IPV4_ONLY"
name_prefix = "simple"
tags = var.tags
labels = var.labels
access_config = [local.access_config]
enable_nested_virtualization = false
threads_per_core = null
}
26 changes: 26 additions & 0 deletions examples/instance_template/simple_with_sa_creation/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright 2025 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 "self_link" {
description = "Self-link to the instance template"
value = module.instance_template.self_link
}

output "name" {
description = "Name of the instance templates"
value = module.instance_template.name
}

32 changes: 32 additions & 0 deletions examples/instance_template/simple_with_sa_creation/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright 2025 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 "project_id" {
description = "The GCP project to use for integration tests"
type = string
}

variable "tags" {
type = list(string)
description = "Network tags, provided as a list"
}

variable "labels" {
type = map(string)
description = "Labels, provided as a map"
}
5 changes: 4 additions & 1 deletion modules/instance_template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
| 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 |
| can\_ip\_forward | Enable IP forwarding, for NAT instances for example | `string` | `"false"` | no |
| 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 |
| 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 |
| description | The template's description | `string` | `""` | no |
| 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 |
| disk\_labels | Labels to be assigned to boot disk, provided as a map | `map(string)` | `{}` | no |
Expand All @@ -47,7 +48,8 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
| project\_id | The GCP project ID | `string` | n/a | yes |
| region | Region where the instance template should be created. | `string` | n/a | yes |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
Expand All @@ -69,6 +71,7 @@ See the [simple](../../examples/instance_template/simple) for a usage example.
| name | Name of instance template |
| self\_link | Self-link of instance template |
| self\_link\_unique | Unique self-link of instance template (recommended output to use instead of self\_link) |
| service\_account\_info | Service account id and email |
| tags | Tags that will be associated with instance(s) |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
36 changes: 35 additions & 1 deletion modules/instance_template/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,40 @@ locals {
# must be true when preemtible or spot is true
var.preemptible || var.spot ? true : false
)

service_account = (
var.service_account != null
? var.service_account
: (
var.create_service_account
? { email : google_service_account.sa[0].email, scopes : ["cloud-platform"] }
: null
)
)
create_service_account = var.create_service_account ? var.service_account == null : false

service_account_prefix = substr("${var.name_prefix}-${var.region}", 0, 27)
service_account_output = local.create_service_account ? {
id = google_service_account.sa[0].account_id,
email = google_service_account.sa[0].email,
member = google_service_account.sa[0].member
} : {}
}

# Service account
resource "google_service_account" "sa" {
count = local.create_service_account ? 1 : 0
project = var.project_id
account_id = "${local.service_account_prefix}-sa"
display_name = "Service account for ${var.name_prefix} in ${var.region}"
}

resource "google_project_iam_member" "roles" {
for_each = toset(distinct(var.service_account_project_roles))

project = var.project_id
role = each.value
member = "serviceAccount:${local.service_account.email}"
}

####################
Expand Down Expand Up @@ -111,7 +145,7 @@ resource "google_compute_instance_template" "tpl" {
}

dynamic "service_account" {
for_each = var.service_account == null ? [] : [var.service_account]
for_each = local.service_account == null ? [] : [local.service_account]
content {
email = lookup(service_account.value, "email", null)
scopes = lookup(service_account.value, "scopes", null)
Expand Down
9 changes: 9 additions & 0 deletions modules/instance_template/metadata.display.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ spec:
confidential_instance_type:
name: confidential_instance_type
title: Confidential Instance Type
create_new_service_account:
name: create_new_service_account
title: Create New Service Account
create_service_account:
name: create_service_account
title: Create Service Account
description:
name: description
title: Description
Expand Down Expand Up @@ -158,6 +164,9 @@ spec:
service_account:
name: service_account
title: Service Account
service_account_project_roles:
name: service_account_project_roles
title: Service Account Project Roles
shielded_instance_config:
name: shielded_instance_config
title: Shielded Instance Config
Expand Down
13 changes: 12 additions & 1 deletion modules/instance_template/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ spec:
location: examples/preemptible_and_regular_instance_templates/simple
- name: simple
location: examples/umig/simple
- name: simple_with_sa_creation
location: examples/instance_template/simple_with_sa_creation
- name: static_ips
location: examples/umig/static_ips
- name: tags
Expand Down Expand Up @@ -292,14 +294,21 @@ spec:
email = string
scopes = optional(set(string), ["cloud-platform"])
})
required: true
connections:
- source:
source: github.com/terraform-google-modules/terraform-google-service-accounts//modules/simple-sa
version: ">= 4.4"
spec:
outputExpr: email
inputPath: email
- name: create_service_account
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!
varType: bool
defaultValue: true
- name: service_account_project_roles
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
varType: list(string)
defaultValue: []
- name: enable_shielded_vm
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
varType: bool
Expand Down Expand Up @@ -365,6 +374,8 @@ spec:
- name: self_link_unique
description: Unique self-link of instance template (recommended output to use instead of self_link)
type: string
- name: service_account_info
description: Service account id and email
- name: tags
description: Tags that will be associated with instance(s)
type:
Expand Down
5 changes: 5 additions & 0 deletions modules/instance_template/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ output "tags" {
description = "Tags that will be associated with instance(s)"
value = google_compute_instance_template.tpl.tags
}

output "service_account_info" {
description = "Service account id and email"
value = local.service_account_output
}
13 changes: 13 additions & 0 deletions modules/instance_template/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,19 @@ variable "service_account" {
scopes = optional(set(string), ["cloud-platform"])
})
description = "Service account to attach to the instance. See https://www.terraform.io/docs/providers/google/r/compute_instance_template#service_account."
default = null
}

variable "create_service_account" {
type = bool
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!"
default = true
}

variable "service_account_project_roles" {
type = list(string)
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"
default = []
}

###########################
Expand Down

0 comments on commit 4fd9e5f

Please sign in to comment.