This example uses Pub/Sub, although the instructions can be applied to any Google Cloud service. The example application in this tutorial authenticates to 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 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
to publish messages,
and inspect the container's output stream to observe that the messages are
gcloud command-line tool
Authenticating with service accounts
You can authenticate to Google Cloud services with service accounts from within GKE using Workload Identity, the default Compute Engine service account, or Secrets.
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 method of authentication 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.
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 attempt to authenticate using the "Compute Engine default service account", and inherit the associated scopes.
This default service account might 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.
Manage service account credentials using Secrets
You can create a service account for your application, and inject the authentication key as a Kubernetes secret. This option is the focus of this tutorial.
Why use Service Accounts?
Using separate service accounts for different applications provides the following benefits:
Better visibility into, and auditing of, the API requests that 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 the same time.
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 Cloud project. Learn how to confirm that 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
Clone the sample code from GitHub:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples cd kubernetes-engine-samples/cloud-pubsub/deployment
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, 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
Creating a Pub/Sub topic
The Pub/Sub subscriber application 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
Deploying Pub/Sub subscriber application
Next, 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. 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, run:
kubectl apply -f pubsub.yaml
After 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 fails to start and is in 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 Pub/Sub service.
Creating service account credentials
To give your application running on GKE access to Google Cloud services, use service accounts. Service accounts let you define a set of Identity and Access Management (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 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
Importing 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. After
you create the Secret, 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
Configuring the application with the Secret
To use the
pubsub-key Secret in your application, 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 fields to make the credentials available to the application:
A volume named
google-cloud-keywhich uses the Secret named
A volume-mount that makes the
google-cloud-keyavailable at the
/var/secrets/googledirectory inside the container.
GOOGLE_APPLICATION_CREDENTIALSenvironment variable set as
/var/secrets/google/key.json, which contains the credentials file after 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 Pub/Sub client for Python.
To deploy this manifest, run:
kubectl apply -f pubsub-with-secret.yaml
Verify that the Pod status is
kubectl get pods -l app=pubsubOutput:
NAME READY STATUS RESTARTS AGE pubsub-652482369-2d6h2 1/1 Running 0 29m
Testing receiving Pub/Sub messages
Now that you configured the application, publish a message to the Pub/Sub
gcloud pubsub topics publish echo --message="Hello, world!"
Within a few seconds, the message is 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 account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.
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