This example uses Cloud Pub/Sub, although the instructions can be applied to any Cloud Platform service. The example application in this tutorial authenticates to Cloud Pub/Sub using a service account and subscribes to messages published to a Pub/Sub topic from a Python-based application.
This tutorial covers the following steps:
- How to create a service account
- How to assign necessary roles for your service account to work with Cloud Pub/Sub
- How to save the account key as a Kubernetes Secret
- How to use the service account to configure and deploy an application.
The sample application used in this tutorial subscribes to a Pub/Sub Topic and
prints the messages published to the standard output. You must configure the
application with correct permissions, use
gcloud to publish messages and
inspect the container's output stream to observe the messages are received
Authenticating with Service Accounts
There are three ways to authenticate to Google Cloud services using service accounts from within GKE:
1. Use Workload Identity
Workload Identity is the recommended way to authenticate to Google Cloud services from GKE. Workload Identity allows you to configure Google Cloud service accounts using Kubernetes resources. If this fits your use case, it should be your first option. This example is meant to cover use cases where Workload Identity is not a good fit.
2. Use the default Compute Engine Service Account
Each node in a GKE cluster is a Compute Engine instance. Therefore, applications running on a GKE cluster by default will attempt to authenticate using the "Compute Engine default service account", and inherit the associated scopes.
This default service account may or may not have permissions to use the Google Cloud services you need. It is possible to expand the scopes for the default service account, but that can create security risks and is not recommended.
3. Manage Service Account credentials using Secrets
Your final option is to create a service account for your application, and inject the authentication key as a Kubernetes secret. This will be the focus of this tutorial.
Why use Service Accounts?
The benefits of having separate service accounts for different applications are:
Better visibility into, and auditing of, the API requests your application makes.
The ability to revoke keys for particular applications, instead of sharing a service account and having to revoke API access of all applications at once.
Reduced exposure in case of a potential security incident where the credentials of the service account are compromised.
Before you beginTake the following steps to enable the Kubernetes Engine API:
- Visit the Kubernetes Engine page in the Google Cloud Console.
- Create or select a project.
- Wait for the API and related services to be enabled. This can take several minutes.
Make sure that billing is enabled for your Google Cloud project. Learn how to confirm billing is enabled for your project.
Install the following command-line tools used in this tutorial:
gcloudis used to create and delete Kubernetes Engine clusters.
gcloudis included in the Google Cloud SDK.
kubectlis used to manage Kubernetes, the cluster orchestration system used by Kubernetes Engine. You can install
gcloud components install kubectl
Set defaults for the
To save time typing your project ID
and Compute Engine zone options in the
gcloud command-line tool
gcloudcommand-line tool, you can set the defaults:
gcloud config set project project-id gcloud config set compute/zone compute-zone
For this tutorial, you need to enable the Pub/Sub API and Resource Manager API on your project:
gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com
Create a container cluster
Create a container cluster named
pubsub-test to deploy the Pub/Sub subscriber
gcloud container clusters create pubsub-test
Step 1: Create a Pub/Sub topic
The Pub/Sub subscriber application you will deploy uses a subscription named
echo-read on a Pub/Sub topic called
echo. Create these resources before
deploying the application.
First, create a Pub/Sub topic:
gcloud pubsub topics create echo
apiVersion: pubsub.cnrm.cloud.google.com/v1beta1 kind: PubSubTopic metadata: name: echo
kubectl apply -f topic.yaml
Then, create a subscription:
gcloud pubsub subscriptions create echo-read --topic=echo
apiVersion: pubsub.cnrm.cloud.google.com/v1beta1 kind: PubSubSubscription metadata: name: echo-read spec: topicRef: name: echo
kubectl apply -f subscription.yaml
Step 2: Deploy Pub/Sub subscriber application
The next step is to deploy the application container to retrieve the messages published to the Pub/Sub topic. This application is written in Python using Google Cloud Pub/Sub client libraries and you can find the source code on GitHub.
The following manifest file describes a Deployment that runs a single instance of this application's Docker image:
# Copyright 2020 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. apiVersion: apps/v1 kind: Deployment metadata: name: pubsub spec: selector: matchLabels: app: pubsub template: metadata: labels: app: pubsub spec: containers: - name: subscriber image: gcr.io/google-samples/pubsub-sample:v1
To deploy this manifest, download it to your machine as
pubsub.yaml, and run:
kubectl apply -f pubsub.yaml
Once the application is deployed, query the pods by running:
kubectl get pods -l app=pubsubOutput:
NAME READY STATUS RESTARTS AGE pubsub-2009462906-1l6bh 0/1 CrashLoopBackOff 1 30s
You can see that the container is failing to start and went into a
CrashLoopBackOff state. Inspect the logs from the Pod by running:
kubectl logs -l app=pubsub
... google.gax.errors.RetryError: RetryError(Exception occurred in retry method that was not classified as transient, caused by <_Rendezvous of RPC that terminated with (StatusCode.PERMISSION_DENIED, Request had insufficient authentication scopes.)>)
The stack trace and the error message indicates that the application does not have permissions to query the Cloud Pub/Sub service.
Step 3: Create service account credentials
To give your application running on GKE access to Google Cloud Platform services, you need to use service accounts. Service accounts allow you to define a set of IAM permissions associated with your application.
To create a service account, go to Service Accounts on Cloud Console and click Create Service Account:
- Specify a Service Account Name (for example,
- In the Role dropdown, select "Pub/Sub → Subscriber".
- Click Create key and choose key type as JSON.
- Click Create.
After the service account is created, a JSON key file containing the credentials of the service account is downloaded to your computer. You use this key file to configure the application to authenticate to the Cloud Pub/Sub API.
First, download the following resource as service-account.yaml.
apiVersion: iam.cnrm.cloud.google.com/v1beta1 kind: IAMServiceAccount metadata: name: pubsub-app spec: displayName: Service account for PubSub example
kubectl apply -f service-account.yaml
Next, apply the "Pub/Sub Subscriber" Role to the service account. Download the following resource as service-account-policy.yaml. Replace
[PROJECT_ID] with your Project ID.
apiVersion: iam.cnrm.cloud.google.com/v1beta1 kind: IAMPolicyMember metadata: name: policy-member-binding spec: member: serviceAccount:pubsub-app@[PROJECT_ID].iam.gserviceaccount.com role: roles/pubsub.subscriber resourceRef: apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1 kind: Project external: projects/[PROJECT_ID]
kubectl apply -f service-account-policy.yaml
Step 4: Import credentials as a Secret
Now that you have the service account key, you need a way to load it into your
container. Your first thought might be to add a step in your
service account keys are security-sensitive files that should not be saved into
Instead, Kubernetes offers the Secret resource type to securely mount private files inside Pods at runtime.
To save the JSON key file as a Secret named
pubsub-key, run the following
command with the path to the downloaded service account credentials file:
kubectl create secret generic pubsub-key --from-file=key.json=PATH-TO-KEY-FILE.json
This command creates a Secret named
pubsub-key that has a
key.json file with
the contents of the private key you downloaded from Cloud Console. Once
you create the Secret, you should remove the key file from your computer.
Download the following resource as service-account-key.yaml.
apiVersion: iam.cnrm.cloud.google.com/v1beta1 kind: IAMServiceAccountKey metadata: name: pubsub-key spec: publicKeyType: TYPE_X509_PEM_FILE keyAlgorithm: KEY_ALG_RSA_2048 privateKeyType: TYPE_GOOGLE_CREDENTIALS_FILE serviceAccountRef: name: pubsub-app
kubectl apply -f service-account-key.yaml
Step 5: Configure the application with the Secret
To use the
pubsub-key Secret in your application, you need to modify the
Deployment specification to:
- Define a volume with the secret.
- Mount the secret volume to the application container.
- Set the
GOOGLE_APPLICATION_CREDENTIALSenvironment variable to point to the key file in the secret volume mount.
The updated manifest file looks like the following:
# Copyright 2020 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. apiVersion: apps/v1 kind: Deployment metadata: name: pubsub spec: selector: matchLabels: app: pubsub template: metadata: labels: app: pubsub spec: volumes: - name: google-cloud-key secret: secretName: pubsub-key containers: - name: subscriber image: gcr.io/google-samples/pubsub-sample:v1 volumeMounts: - name: google-cloud-key mountPath: /var/secrets/google env: - name: GOOGLE_APPLICATION_CREDENTIALS value: /var/secrets/google/key.json
This manifest file defines the following to make the credentials available to the application:
a volume named
google-cloud-keywhich uses the Secret named
a volume-mount, making the
/var/secrets/googledirectory inside the container
GOOGLE_APPLICATION_CREDENTIALSenvironment variable set as
/var/secrets/google/key.json, which will contain the credentials file when the secret is mounted to the container as a volume
Note that the
GOOGLE_APPLICATION_CREDENTIALS environment variable is
automatically recognized by Google Cloud client libraries, in this case
the Cloud Pub/Sub client for Python.
To deploy this manifest, download it to your machine as
pubsub-with-secret.yaml, and run:
kubectl apply -f pubsub-with-secret.yaml
Once it is deployed correctly, the Pod status should be listed as
kubectl get pods -l app=pubsubOutput:
NAME READY STATUS RESTARTS AGE pubsub-652482369-2d6h2 1/1 Running 0 29m
Step 6: Test receiving Pub/Sub messages
Now that you configured the application, publish a message to the Pub/Sub Topic
gcloud pubsub topics publish echo --message="Hello, world!"
Within a few seconds, the message should be picked up by the application and printed to the output stream. To inspect the logs from the deployed Pod, run:
kubectl logs -l app=pubsubOutput:
Pulling messages from Pub/Sub subscription... [2017-06-19 12:31:42.501123] ID=130941112144812 Data=Hello, world!
You have successfully configured an application on GKE to authenticate to Pub/Sub API using service account credentials!
To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:
Clean up the Pub/Sub subscription and topic:
gcloud pubsub subscriptions delete echo-read gcloud pubsub topics delete echo
Delete the container cluster:
gcloud container clusters delete pubsub-test