4

I've been trying to spin up a project from scratch over the Christmas break to automate the creation of my home network, one of those components is the Ubiquiti Controller which requires a Google Maps API key to plot devices onto maps.

I've been able to automate the creation of the project using Terraform:

resource "google_project" "slaterfamily_network" {
  depends_on      = ["data.google_organization.org"]
  name            = "Slater Family Network"
  project_id      = "slaterfamily-network"
  org_id          = "${data.google_organization.org.id}"
  billing_account = "${var.billing_account}"
}

resource "google_project_iam_binding" "account_owner" {
  project = "${google_project.slaterfamily_network.project_id}"

  # It's important to specify ALL members, as this replaces them:
  #   https://twitter.com/devopsreact/status/840233052194320384
  members = [
    "user:[email protected]",
    "serviceAccount:${data.google_service_account.terraform_service_account.email}",
  ]

  role = "roles/owner"
}

This works fine for configuring Google Cloud DNS, however, I can't seem to find a way of enabling Google Maps and generating an API key, the following statements enable the Service Usage API, however it fails enabling the Maps API:

resource "google_project_service" "service_usage" {
  project = "${var.project_id}"
  service = "serviceusage.googleapis.com"
}

resource "google_project_service" "maps" {
  depends_on = ["google_project_service.service_usage"]
  project = "${var.project_id}"
  service = "maps.googleapis.com"
}

With this error:

google_project_service.maps: Error enabling service: failed to issue request: googleapi: Error 403: The caller does not have permission, forbidden

Which after tracing the HTTP calls gives me the following, formatted as cURL for ease of reproduction:

curl -H 'Host: serviceusage.googleapis.com' -H 'content-type: application/json' -H 'authorization: Bearer {{ BEARER_TOKEN }}' -H 'user-agent: google-api-go-client/0.5 Terraform/0.11.7 (+https://www.terraform.io) terraform-provider-google/1.20.0' --data-binary "{}" --compressed 'https://serviceusage.googleapis.com/v1beta1/projects/slaterfamily-network/services/maps.googleapis.com:enable?alt=json&prettyPrint=false'

Which results in:

{
  "error": {
    "code": 403,
    "message": "The caller does not have permission",
    "errors": [
      {
        "message": "The caller does not have permission",
        "domain": "global",
        "reason": "forbidden"
      }
    ],
    "status": "PERMISSION_DENIED"
  }
}
2

3 Answers 3

2
+100

I guess the service ID you're looking for is maps-backend.googleapis.com or static-maps-backend.googleapis.com if you want to generate static maps.

➜  ~ gcloud services list --available |grep maps
maps-android-backend.googleapis.com                                                                  Maps SDK for Android
maps-backend.googleapis.com                                                                          Maps JavaScript API
maps-embed-backend.googleapis.com                                                                    Maps Embed API
maps-ios-backend.googleapis.com                                                                      Maps SDK for iOS
static-maps-backend.googleapis.com                                                                   Maps Static API

I've got these result with Google Cloud SDK version 360.0.0, also there is apikeys.googleapis.com service available with alpha component which makes me think it could be achievable by using gcloud module and gcloud alpha services api-keys create command.

1

I faced the similar problem recently, but fixed it by providing additional roles to the service account. I am not sure what permissions you need, you need to look it up. In my case, I was trying to create an appengine project, So I had to add "Appengine Admin" role to the service account and enable "appengine.googleapis.com" via terraform resource "google_project_service"

0

Thanks @Ahmet! I put up a bounty for this question and Ahmet came through with a great answer. I tried the gcloud module for terraform and it worked! However I needed to go a step further as the gcloud command wasn't able to save the output and also couldn't read the file due to permission issues. So I actually took the concept and used the local-exec in terraform instead to run a script which does all the gcloud commands I needed.

You can find a list of APIs here: https://developers.google.com/apis-explorer/

Go into the documentation for the one you need and copy the url *.googleapis.com, in my example I needed the Geocoding API turned on and an API key for it.

# main.tf

module "project_services" {
  source  = "terraform-google-modules/project-factory/google//modules/project_services"
  version = "11.2.1"

  project_id = var.project_id
  activate_apis = [
    "geocoding-backend.googleapis.com",
  ]
  disable_dependent_services  = false
  disable_services_on_destroy = false
}

resource "null_resource" "geocode" {
  provisioner "local-exec" {
    command = "chmod +x ./scripts/script.sh && sh ./scripts/script.sh"
    environment = {
      SERVICE_API = "geocoding-backend.googleapis.com"
      KEY_NAME = "my-key"
      SECRET_NAME = "my-secret"
    }
  }
  depends_on = [
    # e.g. module.secret_manager
  ]
}

Then you can create a script like so, with the environment variables being injected in:

# ./scripts/script.sh

GCLOUD_LOCATION=$(command -v gcloud)
echo "Using gcloud from $GCLOUD_LOCATION"

gcloud alpha services api-keys create --api-target=service="$SERVICE_API" --display-name="$KEY_NAME" &&
export KEY_NAME=$(gcloud alpha services api-keys list --format="value(name)" --sort-by createTime --limit 1) &&
export API_KEY=$(gcloud alpha services api-keys get-key-string $KEY_NAME --format="value(keyString)") &&
printf $API_KEY | gcloud secrets versions add "$SECRET_NAME" --data-file=-

My above script takes the key and inserts it into an existing Secret I created in terraform.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.