To manage cloud infrastructure I’m a huge fan of Terraform. Unfortunately I noticed that it’s not possible to use Terraform for managing API Keys for Google Maps (and other services). After some digging I found that the alpha version of the Google Cloud SDK has support for it.
Commands available in the stable gcloud
release:
describe Describe an API key's metadata.
list Lists API keys.
Commands available in the alpha gcloud
release:
clone *(ALPHA)* Create a new API key with the same
metadata as input key.
create *(ALPHA)* Create an API key.
delete *(ALPHA)* Delete an API key.
describe *(ALPHA)* Describe an API key's metadata.
get-key-string *(ALPHA)* Get key string of an API key.
list *(ALPHA)* Lists API keys.
lookup *(ALPHA)* Look up resource name of a key string.
undelete *(ALPHA)* Undelete an API key.
update *(ALPHA)* Update an API key's metadata.
Aha, that’s more like it!
~
To create an API key use gcloud alpha services api-keys create
. A basic API Key for uses the Map JavaScript API can be created with this command:
gcloud alpha services api-keys create \
--display-name="My Google Maps Key" \
--api-target=service=maps_backend \
--allowed-referrers="https://bram.us/*,https://*.bram.us/*"
Note that this API key requires the maps-backend.googleapis.com
API to be active for your GCP project:
gcloud alpha services enable maps-backend.googleapis.com
The other gcloud alpha services api-keys
subcommands are pretty straightforward.
~
One thing that did require some more tweaking was the ability to extract the key string for an existing key using the Key’s Display Name. The “problem” is that get-key-string
only accepts a Key Id, not a Display Name.
To work around that I nested the gcloud alpha services api-keys list
call (to find the Key Id based on the Display Name) inside a gcloud alpha services api-keys get-key-string
call, along with some grep
and cut
magic.
gcloud alpha services api-keys get-key-string \
"$( \
gcloud alpha services api-keys list \
--filter DISPLAY_NAME:"My Google Maps Key" \
| grep "projects/" \
| cut -d ' ' -f1\
)" \
| cut -d ' ' -f2
(Replace My Google Maps Key
with the Display Name of your key)
~
To integrate this a bit more nicely with Terraform I whipped up this little shell script:
# Extract gc-project value from Terraform environments file
TF_WORKSPACE=`terraform workspace show`
GC_PROJECT=`cat "./environments/$TF_WORKSPACE.json" | grep '"gc-project"' | cut -d '"' -f4`
# Name of the Key to create
KEY_NAME="My Google Maps Key"
# Get ID for the key.
KEY_ID=`gcloud alpha services api-keys list --filter DISPLAY_NAME:"$KEY_NAME" --project="$GC_PROJECT" | grep "projects/" | cut -d ' ' -f1`
# No Key ID Found
# ~> Key does not exist yet
# ~> Create it + Output the Key String
if [ -z "$KEY_ID" ]; then
echo -e "\033[33m♺\033[0m Creating Key '$KEY_NAME'"
gcloud alpha services api-keys create \
--project="$GC_PROJECT" \
--display-name="$KEY_NAME" \
--api-target=service=maps_backend \
--allowed-referrers="https://bram.us/*,https://*.bram.us/*" \
&> /dev/null
KEY_ID=`gcloud alpha services api-keys list --filter DISPLAY_NAME:"$KEY_NAME" --project="$GC_PROJECT" | grep "projects/" | cut -d ' ' -f1`
KEY_STRING=`gcloud alpha services api-keys get-key-string "$KEY_ID" --project="$GC_PROJECT" | cut -d ' ' -f2`
echo -e "\033[32m✓\033[0m Created key '$KEY_NAME'. Key String = $KEY_STRING"
# Key ID found
# ~> Output the Key String
else
KEY_STRING=`gcloud alpha services api-keys get-key-string "$KEY_ID" --project="$GC_PROJECT" | cut -d ' ' -f2`
echo -e "\033[32m✓\033[0m Key '$KEY_NAME' already exists. Key String = $KEY_STRING"
fi
Note that I’ve written this script to be run in conjunction with Terraform using our specific code structure. On the first few lines you can see that it extracts the value for GC_PROJECT
from a JSON file that’s named after the Terraform Workspace.
Created keys won’t be stored in Terraform’s state. However, the code is written in such a way that successive runs will not create a new key nor overwrite the existing one. Note that this check to see if a key exists is only a superficial check, as it does not check the key’s settings (such as api-target
) — Only the Display Name is checked.
To not have to run this script on the site, you can execute it using a local-exec
~
Thank me with a coffee.
I don\'t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!
To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.