GCP Terraform Archives - For all your terraform needs https://terraformarchitect.com/category/gcp-terraform/ Automation cannot be an afterthought (TM) Sun, 26 Jun 2022 02:57:36 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 The Vault Provider in Terraform https://terraformarchitect.com/gcp-terraform/the-vault-provider-in-terraform/?utm_source=rss&utm_medium=rss&utm_campaign=the-vault-provider-in-terraform https://terraformarchitect.com/gcp-terraform/the-vault-provider-in-terraform/#respond Wed, 30 Dec 2020 15:48:54 +0000 http://terraformarchitect.com/?p=103 These are some notes from the field around using Vault and Terraform. Storing a Sample Secret in Vault – Resource vault_generic_secret provider "vault" { # It is strongly recommended to […]

The post The Vault Provider in Terraform appeared first on For all your terraform needs.

]]>
These are some notes from the field around using Vault and Terraform.

Storing a Sample Secret in Vault – Resource vault_generic_secret

provider "vault" {
  # It is strongly recommended to configure this provider through the
  # environment variables described above, so that each user can have
  # separate credentials set in the environment.
  #
  # This will default to using $VAULT_ADDR
  # But can be set explicitly
  # address = "https://vault.example.net:8200"
}

resource "vault_generic_secret" "example" {
  path = "secret/foo"

  data_json = <<EOT
{
  "foo":   "bar",
  "pizza": "cheese"
}
EOT
}

Backups of Vault Data

Vault uses Consul as the encrypted database.

consul snapshot will provide the ability to backup the consul db containing encrypted secrets

Authenticate to Vault ( Token Per User )

Users should authenticate to get Vault access. This can happen via github (configure github as the identity provider for Vault). Github will return a token that can be used by each user to authenticate themselves to Vault.

Vault Architecture on AWS (7 EC2 Instances on AWS)

A possible architecture may involve a  Bastion host and a couple of standby vault servers. The consul servers should ideally be separate (database servers). This would translate to 7 EC2 instances on AWS.

vault architecture
vault architecture




Need an experienced Cloud Networking or a Cloud Data Protection Expert?  Anuj has successfully delivered over a dozen deployments on each of the public clouds (AWS/GCP/Azure) including several DevSecOps engagements. Set up a time with Anuj Varma.

The post The Vault Provider in Terraform appeared first on For all your terraform needs.

]]>
https://terraformarchitect.com/gcp-terraform/the-vault-provider-in-terraform/feed/ 0
REusable Modules https://terraformarchitect.com/gcp-terraform/reusable-modules/?utm_source=rss&utm_medium=rss&utm_campaign=reusable-modules https://terraformarchitect.com/gcp-terraform/reusable-modules/#comments Fri, 06 Nov 2020 23:44:40 +0000 http://terraformarchitect.com/?p=85 Let us say you need to repeat a resource creation task (a set of resources) more than once. You may need to create those resources in two separate environments – […]

The post REusable Modules appeared first on For all your terraform needs.

]]>
Let us say you need to repeat a resource creation task (a set of resources) more than once. You may need to create those resources in two separate environments – dev and prod.

Or you may need to spin up an instance each in two separate regions (regional managed instance groups would only work across two zones in the SAME region).

Or, as another example, say you want to use code (modules) that already exists in github or on terraform’s public registry.

Creating  a Module for local use

In my f5module folder, I have all of the terraform (main.tf and variables.tf) to spin up F5 instances in a particular environment. What that module (basically, any folder in terraform is a module), requires is a parent vpc, a region and gui_port,  a couple of zones, a couple of static IPs and a NAT_IP. All these can be passed in as variables to the f5module, as shown below.

module "f5multiregional" {
  source ="./f5module"
  parent_vpc = var.parent_vpc
  region = var.region
  management_gui_port = var.management_gui_port
  zone1 = var.zone1
  zone2 = var.zone2
  staticIP_instance1 = google_compute_address.static1.address
  staticIP_instance2 = google_compute_address.static2.address
  subnet_id = google_compute_subnetwork.network-for-f5.id
  static_ip_nat = google_compute_address.staticnat.address
}

The actual module code (the f5module folder containing main.tf and variables.tf)

resource "google_compute_instance_template" "f5-template" {
  name         = "${var.environment}-f5-template"
  machine_type = "${var.instance_type}"

  network_interface {
    subnetwork = var.subnet_id
    access_config {
        nat_ip = var.static_ip_nat
    }
  }

  disk {
    source_image = "${var.image_name}" 
    auto_delete  = false
    disk_size_gb = 100
    boot         = true
  } 

    # Shows up as network tags
    # Must be a match of regex '(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)
    tags = [
        "name-${var.environment}-shared-proxy",
        "environment-${var.environment}",
        "owner-${var.owner}",
        "group-${var.group}",
        "costcenter-${var.costcenter}",
        "application-${var.application}"

    ]

  metadata = {
        Name           = "${var.environment}_proxy"
        environment    = "${var.environment}"
        owner          = "${var.owner}"
        group          = "${var.group}"
        costcenter     = "${var.costcenter}"
        application    = "${var.application}"
        ssh-keys       = "${var.admin_username}:${var.ssh_key_public}"
    }
  can_ip_forward = true
 }

locals {
    instance1_bootstrap = templatefile("${path.module}/f5config1.sh", {
    admin_username         = var.admin_username
    admin_password        = var.admin_password
    })

   instance2_bootstrap = templatefile("${path.module}/f5config2.sh",
    {
     admin_username          = var.admin_username
     admin_password        = var.admin_password
   })
}

resource "google_compute_instance_from_template" "f5-instance-1" {
  name = "${var.environment}-${var.instance1_name}"
  zone = var.zone1
 
  source_instance_template = google_compute_instance_template.f5-template.id

  scratch_disk {
    interface = "SCSI"
  }
  
  network_interface {
    subnetwork = var.subnet_id
    access_config {
        nat_ip = var.staticIP_instance1
    }
   }

  metadata = {
    startup-script = local.instance1_bootstrap != "" ? local.instance1_bootstrap : local.instance1_bootstrap
  } 

  service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }    

  can_ip_forward = true

}

resource "google_compute_instance_from_template" "f5-instance-2" {
  name = "${var.environment}-${var.instance2_name}"
  zone = var.zone2
 
  source_instance_template = google_compute_instance_template.f5-template.id

  scratch_disk {
    interface = "SCSI"
  }

  network_interface {
    subnetwork = var.subnet_id
      access_config {
        nat_ip = var.staticIP_instance2
    }
 }

  metadata = {
    startup-script = local.instance2_bootstrap != "" ? local.instance2_bootstrap : local.instance2_bootstrap
  } 
 
  service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
   }    
 
  can_ip_forward = true
}

locals {
  api_url = "https://compute.googleapis.com/compute/v1/"
  instance1url =  "${local.api_url}${google_compute_instance_from_template.f5-instance-1.id}"
  instance2url =  "${local.api_url}${google_compute_instance_from_template.f5-instance-2.id}"
}

resource "google_compute_http_health_check" "default" {
  name               = "f5healthcheck"
  request_path       = "/"
  check_interval_sec = 1
  timeout_sec        = 1
}

resource "google_compute_target_pool" "f5targetpool" {
  name = "instance-pool"

  instances = [
      local.instance1url,local.instance2url
  ]

  health_checks = [
    google_compute_http_health_check.default.name,
  ]
}

resource "google_compute_region_instance_group_manager" "f5-regional-group" {
  name = "f5-regional-instance-group"

  base_instance_name         = "f5"
  region                     = var.region
  distribution_policy_zones  = [var.zone1, var.zone2]

  version {
    instance_template = google_compute_instance_template.f5-template.id
  }

  target_pools = [google_compute_target_pool.f5targetpool.id]
  target_size  = 2

  named_port {
    name = "custom"
    port = 8888
  }

  auto_healing_policies {
    health_check      = google_compute_http_health_check.default.id
    initial_delay_sec = 300
  }
}

output "instance1_url" {
    value = local.instance1url
}

How else can Terraform Modules be leveraged?

There’s more to using terraform modules, but the use case above (using terraform modules locally), is a good way to get a basic understanding of terraform modules. Some other ways that modules can be leveraged include:

  1. Using terraform modules from the public registry
  2. Using Terraform module using GitHub
  3. Using a custom module
  4. Using Terraform’s module generator




Need an experienced Cloud Networking or a Cloud Data Protection Expert?  Anuj has successfully delivered over a dozen deployments on each of the public clouds (AWS/GCP/Azure) including several DevSecOps engagements.

Next Steps?

Need help with your Terraform or PowerShell or other automation effort? Set up a free consultation – Start the conversation today.  

The post REusable Modules appeared first on For all your terraform needs.

]]>
https://terraformarchitect.com/gcp-terraform/reusable-modules/feed/ 1
Terraform GCP Error – Could not find default credentials https://terraformarchitect.com/gcp-terraform/terraform-gcp-error-could-not-find-default-credentials/?utm_source=rss&utm_medium=rss&utm_campaign=terraform-gcp-error-could-not-find-default-credentials https://terraformarchitect.com/gcp-terraform/terraform-gcp-error-could-not-find-default-credentials/#respond Fri, 25 Sep 2020 02:54:05 +0000 http://terraformarchitect.com/?p=49 This post captures a couple of errors you might encounter getting started with terraform and GCP. ( Also read Protecting Service Account Keys in GCP )  and  Sentinel tfplan policies […]

The post Terraform GCP Error – Could not find default credentials appeared first on For all your terraform needs.

]]>
This post captures a couple of errors you might encounter getting started with terraform and GCP. ( Also read Protecting Service Account Keys in GCP )  and  Sentinel tfplan policies in GCP
Typical Steps to getting started
   Are you going to be performing actions on GCP using a Service account or using your human user credentials?
Say you took the latter approach and created a custom service account for use with your project (and granted the SA a Project Owner or Editor role) – and downloaded the JSON key.  You would think you are all set to execute Terraform against the project defined in the JSON key, since the service account is the ‘owner’ on the project.
You would be wrong.
You would encounter this error on your terraform init
Error: google: could not find default credentials.
for more information.
  on  line 0:
  (source code not available)
The Quick Fix – Install Client Libraries for GCP APIs
  1. Client Libraries can be used to call GCP APIs
  2. All one needs is the Cloud SDK (see below) – which install client libraries locally on your desktop.

install Google Cloud SDK on your development desktop

  • On windows, just open up a powershell prompt and use this:
(New-Object Net.WebClient).DownloadFile("https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe", "$env:Temp\GoogleCloudSDKInstaller.exe")

& $env:Temp\GoogleCloudSDKInstaller.exe
  • Once installed, run the following gcloud commands
gcloud init  --> THis will prompt you to use an existing gmail account or a different one

gcloud auth application-default login

This command will generate an ADC (Application Default Credentials) JSON file based on your user (IAM user) account and store it in a location where the SDK can find it automatically.

You should also receive a ‘security alert’ email from google  – Google Auth Library was granted access to your Google Account myuser@gmail.com

What if you need to switch your human (gmail) or service account identities ? Or to do this from another PC?

You need the command below to re-prompt a login ( This will allow you to switch gmail identites ).

gcloud auth application-default login

Another possible error – Callers must accept terms of service…

When you try to create a new project (gcloud create project myproject),

gcloud projects create myprojectname

you may encounter this error. This is true if the gSuite account is one which HASN’T created any projects in the past.

The Quick Fix  for Callers must accept terms of service..

Log into the console with the same gSuite account and create a project by selecting ‘select a project’ (and ‘Create a Project’).

This will prompt the terms of service agreement and you may carry on after agreeing to the terms of service.

That’s it. Those are two of the more common errors that GCP and Terraform users encounter when getting started.
Where does my human user (IAM user) enter into this picture?

If you are using Cloud Shell, you are logged in as your IAM user. The IAM (Human) User is what logs on to GCP (via cloud shell).

Happy Terraforming!

Appendix A – Some Roles your Human or Service Account identity may need on GCP for successfully creating Terraform Resources

    1. iam.serviceAccounts.actAs permission for your  project – e.g. ‘projects/my-awesome-project’
    2. If you plan to use the default compute engine SA, you would need to be granted the role – serviceAccountUser for that SA. Ask a project owner to grant you the iam.serviceAccountUser role on the service account
    3. If you will be creating your own SAs and assigning roles to them,
      1. resourcemanager.projects.getIamPolicy  on the my-awesome-project
      2. resourcemanager.projects.setIamPolicy  on the same project
      3. iam.roles.list  – on the same project.



 

The post Terraform GCP Error – Could not find default credentials appeared first on For all your terraform needs.

]]>
https://terraformarchitect.com/gcp-terraform/terraform-gcp-error-could-not-find-default-credentials/feed/ 0