Add existing Service account to terraform Google compute instance - google-cloud-platform

Hello I am trying to add an existing service account to a new Google compute instance I am spinning up.
How can I attach the already existing account?
Here is what my file looks like
provider "google" {
project = var.project
region = "us-central1"
zone = "us-central1-c"
}
resource "google_compute_disk" "data_disk" {
name = "data-test"
size = 120
}
resource "google_compute_disk" "other_data_disk" {
name = "other-data-test"
size = 400
}
resource "google_compute_attached_disk" "data" {
disk = google_compute_disk.data_disk.id
instance = google_compute_instance.test_vm_instance.id
}
resource "google_compute_attached_disk" "other_data" {
disk = google_compute_disk.other_data_disk.id
instance = google_compute_instance.tyler_test_vm_instance.id
}
resource "google_compute_instance" "test_vm" {
name = "worker-test"
machine_type = "n2-standard-2"
min_cpu_platform = "Intel Ice Lake"
boot_disk {
initialize_params {
image = "ubuntu-2004-focal-v20210211"
}
}
network_interface {
network = var.gcp_project_network_name
subnetwork = var.subnet_name
#access_config {
#}
}
metadata_startup_script = "${file("./startup-script.sh")}"
What's the best way to insert add an already existing service account to the new VM.
I want to be able to create and destroy the VM without worrying about deleting this service account.

Add to this resource:
resource "google_compute_instance" "test_vm" {
...
service_account {
email = REPLACE_WITH_EXISTING_SERVICE_ACCOUNT_EMAIL_ADDRESS
scopes = ["cloud-platform"]
}
...
}

Related

GCP Compute Engine using Terraform

How to provision multiple instances in GCP Compute Engine using Terraform. I've tried using 'count' parameter in the resource block. But terraform is not provisioning more than one instance because the VM with a particular name is created once when first count is executed.
provider "google" {
version = "3.5.0"
credentials = file("battleground01-5c86f5873d44.json")
project = "battleground01"
region = "us-east1"
zone = "us-east1-b"
}
variable "node_count" {
default = "3"
}
resource "google_compute_instance" "appserver" {
count = "${var.node_count}"
name = "battleground"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = "default"
}
}
In order for this to work, you would have to make a slight change in the way you are naming your compute instances:
provider "google" {
version = "3.5.0"
credentials = file("battleground01-5c86f5873d44.json")
project = "battleground01"
region = "us-east1"
zone = "us-east1-b"
}
variable "node_count" {
type = number
default = 3
}
resource "google_compute_instance" "appserver" {
count = var.node_count
name = "battleground-${count.index}"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = "default"
}
}
As you are using the count meta-argument, the way to access the array index is by using the count.index attribute [1]. You have also set the node_count variable default value to be a string and even though it would probably get converted to a number by Terraform, make sure to use the right variable types.
[1] https://www.terraform.io/language/meta-arguments/count#the-count-object

GCP terraform compute instance template labels

I have a TF GCP google_compute_instance_template configured to deploy a range of individual VMs, each of which will perform a different role in a "micro-services" style application. I am adding a single label to my instance_template, costing="app". However when I go to deploy the various VM components of the app with google_compute_instance_group_manager, I was expecting to be able to add another label in the in the instance group manager configuration, specific to the VM that is being deployed, such as "component=blah". The google_compute_instance_group_manager is not talking labels as a configuration element. Does anyone know how I can use the template to add a generic label, but then add additional machine-specific labels when the VMs are created?
Here is the TF code:
// instance template
resource "google_compute_instance_template" "app" {
name = "appserver-template"
machine_type = var.app_machine_type
labels = {
costing = "app"
}
disk {
source_image = data.google_compute_image.debian_image.self_link
auto_delete = true
boot = true
disk_size_gb = 20
}
tags = ["compute", "app"]
network_interface {
subnetwork = var.subnetwork
}
// no access config
service_account {
email = var.service_account_email
// email = google_service_account.vm_sa.email
scopes = ["cloud-platform"]
}
}
// create instances --how to add instance-specific label here? eg component="admin"
resource "google_compute_instance_group_manager" "admin" {
provider = google-beta
name = "admin-igm"
base_instance_name = "${var.project_short_name}-admin"
zone = var.zone
target_size = 1
version {
name = "appserver"
instance_template = google_compute_instance_template.app.id
}
}
I got the desired outcome by creating a google_compute_instance_template for each server type in my application, which then allowed me to assign both a universal label and a component-specific label. It was more code than I hoped to have to write, but the objective is met.
resource "google_compute_instance_template" "admin" {
name = "admin-template"
machine_type = var.app_machine_type
labels = {
costing = "app",
component = "admin"
}
disk {
source_image = data.google_compute_image.debian_image.self_link
auto_delete = true
boot = true
disk_size_gb = 20
}
tags = ["compute"]
network_interface {
subnetwork = var.subnetwork
}
// no access config
service_account {
email = var.service_account_email
// email = google_service_account.vm_sa.email
scopes = ["cloud-platform"]
}
}

google cloud platform instance in MIG cannot access artifact registry

I'm trying to deploy a managed instance group with a load balancer which will be running a web server container.
The container is stored in the google artifcat registry.
If I manually create a VM and define the container usage, it is successfully able to pull and activate the container.
When I try to create the managed instance group via terraform, the VM does not pull nor activate the container.
When I ssh to the VM and try to manually pull the container, I get the following error:
Error response from daemon: Get https://us-docker.pkg.dev/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
The only notable difference between the VM I created manually to the VM created by terraform is that the manual VM has an external IP address. Not sure if this matters and not sure how to add one to the terraform file.
Below is my main.tf file. Can anyone tell me what I'm doing wrong?
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.53.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = "~> 4.0"
}
}
}
provider "google" {
credentials = file("compute_lab2-347808-dab33a244827.json")
project = "lab2-347808"
region = "us-central1"
zone = "us-central1-f"
}
locals {
google_load_balancer_ip_ranges = [
"130.211.0.0/22",
"35.191.0.0/16",
]
}
module "gce-container" {
source = "terraform-google-modules/container-vm/google"
version = "~> 2.0"
cos_image_name = "cos-stable-77-12371-89-0"
container = {
image = "us-docker.pkg.dev/lab2-347808/web-server-repo/web-server-image"
volumeMounts = [
{
mountPath = "/cache"
name = "tempfs-0"
readOnly = false
},
]
}
volumes = [
{
name = "tempfs-0"
emptyDir = {
medium = "Memory"
}
},
]
restart_policy = "Always"
}
resource "google_compute_firewall" "rules" {
project = "lab2-347808"
name = "allow-web-ports"
network = "default"
description = "Opens the relevant ports for the web server"
allow {
protocol = "tcp"
ports = ["80", "8080", "5432", "5000", "443"]
}
source_ranges = ["0.0.0.0/0"]
#source_ranges = local.google_load_balancer_ip_ranges
target_tags = ["web-server-ports"]
}
resource "google_compute_autoscaler" "default" {
name = "web-autoscaler"
zone = "us-central1-f"
target = google_compute_instance_group_manager.default.id
autoscaling_policy {
max_replicas = 10
min_replicas = 1
cooldown_period = 60
cpu_utilization {
target = 0.5
}
}
}
resource "google_compute_instance_template" "default" {
name = "my-web-server-template"
machine_type = "e2-medium"
can_ip_forward = false
tags = ["ssh", "http-server", "https-server", "web-server-ports"]
disk {
#source_image = "cos-cloud/cos-73-11647-217-0"
source_image = module.gce-container.source_image
}
network_interface {
network = "default"
}
service_account {
#scopes = ["userinfo-email", "compute-ro", "storage-ro"]
scopes = ["cloud-platform"]
}
metadata = {
gce-container-declaration = module.gce-container.metadata_value
}
}
resource "google_compute_target_pool" "default" {
name = "web-server-target-pool"
}
resource "google_compute_instance_group_manager" "default" {
name = "web-server-igm"
zone = "us-central1-f"
version {
instance_template = google_compute_instance_template.default.id
name = "primary"
}
target_pools = [google_compute_target_pool.default.id]
base_instance_name = "web-server-instance"
}
Your VM templates haven't public IPs, therefore, you can't reach public IP.
However, you have 3 ways to solve that issue:
Add a public IP on the VM template (bad idea)
Add a Cloud NAT on your VM private IP range to allow outgoing traffic to the internet (good idea)
Activate the Google private access in the subnet that host the VM private iP range. It create a bridge to access to Google services without having a public IP (my prefered idea) -> https://cloud.google.com/vpc/docs/configure-private-google-access
Apparently I was missing the following acecss_config inside network_interface of the google_compute_instance_template as following:
network_interface {
network = "default"
access_config {
network_tier = "PREMIUM"
}

Terraform & GCP: Google kubernetes cluster problem: Can't see monitoring section (memory and cpu) inside workloads (deployments, statefulsets)

I spent 4 days already testing all configurations from kubernetes terraform gcp module and I can't see the metrics of my workloads, It never shows me CPU nor Memory (and even the standard default created kubernetes in the GUI has this activated.
Here's my code:
resource "google_container_cluster" "default" {
provider = google-beta
name = var.name
project = var.project_id
description = "Vectux GKE Cluster"
location = var.zonal_region
remove_default_node_pool = true
initial_node_count = var.gke_num_nodes
master_auth {
#username = ""
#password = ""
client_certificate_config {
issue_client_certificate = false
}
}
timeouts {
create = "30m"
update = "40m"
}
logging_config {
enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
}
monitoring_config {
enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
}
}
resource "google_container_node_pool" "default" {
name = "${var.name}-node-pool"
project = var.project_id
location = var.zonal_region
node_locations = [var.zonal_region]
cluster = google_container_cluster.default.name
node_count = var.gke_num_nodes
node_config {
preemptible = true
machine_type = var.machine_type
disk_size_gb = var.disk_size_gb
service_account = google_service_account.default3.email
oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/cloud-platform",
"compute-ro",
"storage-ro",
"service-management",
"service-control",
]
metadata = {
disable-legacy-endpoints = "true"
}
}
management {
auto_repair = true
auto_upgrade = true
}
}
resource "google_service_account" "default3" {
project = var.project_id
account_id = "terraform-vectux-33"
display_name = "tfvectux2"
provider = google-beta
}
Here's some info on the cluster (when I compare against the standard one with the metrics enabled I see no differences:
And here 's the workload view without the metrics that I'd like to see:
As I mentioned in the comment to solve your issue, you must add google_service_account_iam_binding module and grant your Service Account specific role - roles/monitoring.metricWriter. In comments I mention that you can also grant role/compute.admin but after another test I've run it's not necessary.
Below is a terraform snippet I've used to create a test cluster with Service Account called sa. I've changed some fields in node config. In your case, you would need to add the whole google_project_iam_binding module.
Terraform Snippet
### Creating Service Account
resource "google_service_account" "sa" {
project = "my-project-name"
account_id = "terraform-vectux-2"
display_name = "tfvectux2"
provider = google-beta
}
### Binding Service Account with IAM
resource "google_project_iam_binding" "sa_binding_writer" {
project = "my-project-name"
role = "roles/monitoring.metricWriter"
members = [
"serviceAccount:${google_service_account.sa.email}"
### in your case it will be "serviceAccount:${google_service_account.your-serviceaccount-name.email}"
]
}
resource "google_container_cluster" "default" {
provider = google-beta
name = "cluster-test-custom-sa"
project = "my-project-name"
description = "Vectux GKE Cluster"
location = "europe-west2"
remove_default_node_pool = true
initial_node_count = "1"
master_auth {
#username = ""
#password = ""
client_certificate_config {
issue_client_certificate = false
}
}
timeouts {
create = "30m"
update = "40m"
}
logging_config {
enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
}
monitoring_config {
enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
}
}
resource "google_container_node_pool" "default" {
name = "test-node-pool"
project = "my-project-name"
location = "europe-west2"
node_locations = ["europe-west2-a"]
cluster = google_container_cluster.default.name
node_count = "1"
node_config {
preemptible = "true"
machine_type = "e2-medium"
disk_size_gb = 50
service_account = google_service_account.sa.email
###service_account = google_service_account.your-serviceaccount-name.email
oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/cloud-platform",
"compute-ro",
"storage-ro",
"service-management",
"service-control",
]
metadata = {
disable-legacy-endpoints = "true"
}
}
management {
auto_repair = true
auto_upgrade = true
}
}
My Screens:
Whole workload
Node Workload
Additional Information
If you would add just roles/compute.admin you might see workload for the whole application,but you wouldn't be able to see each node workload. With "roles/monitoring.metricWriter" you are able to see the whole application workload and each node workload. To achieve what you want - see workloads in the node, you just need "roles/monitoring.metricWriter".
You need to use "google_project_iam_binding" as without this in IAM roles, you won't have your newly created Service Account and it will lack permission. In short, Your new SA will be visible in IAM & Admin > Service Accounts but there will be no entry in IAM & Admin > IAM.
If you want more information about IAM and Binding in terraform, please check this Terraform Documentation
As a last thing, please remember that Oauth Scope with "https://www.googleapis.com/auth/cloud-platform" gives access to all GCP resources.

how to declare gcp compute engine images from gcp marketplace through terraform

I've a request in company to write a terraform script to deploy a compute engine image from GCP marketplace? This is most likely a deep-learning image. Can anyone please help?
Example image - https://console.cloud.google.com/marketplace/details/click-to-deploy-images/deeplearning?q=compute%20engine%20images&id=8857b4a3-f60f-40b2-9b32-22b4428fd256
Please take a look at the following examples here
resource "random_id" "instance_id" {
byte_length = 8
}
resource "google_compute_instance" "default" {
name = "vm-${random_id.instance_id.hex}"
machine_type = var.instance_type
zone = var.zone
boot_disk {
initialize_params {
image = "deeplearning-platform-release/tf-ent-latest-gpu" # TensorFlow Enterprise
size = 50 // 50 GB Storage
}
}
network_interface {
network = "default"
access_config {}
}
guest_accelerator {
type = var.gpu_type
count = var.gpu_count
}
scheduling {
automatic_restart = true
on_host_maintenance = "TERMINATE"
}
metadata = {
install-nvidia-driver = "True"
proxy-mode = "service_account"
}
tags = ["deeplearning-vm"]
service_account {
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
}
}
I recently added support for AI Platform Notebooks in Terraform as well.