Autenticar Cloud Platform con cuentas de servicio

En este instructivo, se muestra cómo crear una cuenta de servicio de Google Cloud, asignar funciones para autenticarte en los servicios de Cloud Platform y usar credenciales de cuentas de servicio en aplicaciones que se ejecutan en GKE.

En este ejemplo, se usa Cloud Pub/Sub, aunque las instrucciones se pueden aplicar a cualquier servicio de Cloud Platform. La aplicación de ejemplo de este instructivo se autentica en Cloud Pub/Sub con una cuenta de servicio y se suscribe a los mensajes publicados en un tema de Pub/Sub desde una aplicación basada en Python.

Objetivos

En este instructivo se analizan los siguientes pasos:

  • Cómo se crea una cuenta de servicio.
  • Cómo se asignan las funciones necesarias para que la cuenta de servicio funcione con Cloud Pub/Sub.
  • Cómo se guarda la clave de la cuenta como un secreto de Kubernetes.
  • Cómo se usa la cuenta de servicio para implementar y configurar una aplicación.

La aplicación de muestra que se usa en este instructivo se suscribe a un tema de Pub/Sub y, también, imprime los mensajes publicados en los resultados estándar. Debes configurar la aplicación con los permisos correctos. Usa gcloud para publicar mensajes e inspeccionar el flujo de los resultados del contenedor a fin de observar si los mensajes se reciben de forma correcta.

Autentica con cuentas de servicio

Existen tres maneras de autenticarse en los servicios de Google Cloud mediante cuentas de servicio desde GKE:

1. Usa Workload Identity

Workload Identity es la forma recomendada para autenticarse en los servicios de Google Cloud desde GKE. Workload Identity te permite configurar las cuentas de servicio de Google Cloud mediante recursos de Kubernetes. Si esto se ajusta a tu caso de uso, debería ser tu primera opción. Este ejemplo tiene como objetivo describir casos de uso en los que Workload Identity no es una buena opción.

2. Usa la cuenta de servicio predeterminada de Compute Engine

Cada nodo en un clúster de GKE es una instancia de Compute Engine. Por lo tanto, las aplicaciones que se ejecutan en un clúster de GKE intentarán autenticarse de forma predeterminada con la “cuenta de servicio predeterminada de Compute Engine” y heredar los permisos asociados.

Esta cuenta de servicio predeterminada puede o no tener permisos para usar los servicios de Google Cloud que necesitas. Es posible expandir los permisos de la cuenta de servicio predeterminada, pero esa acción puede generar riesgos de seguridad y no se recomienda.

3. Administra credenciales de cuenta de servicio mediante Secretos

Tu última opción es crear una cuenta de servicio para tu aplicación e incorporar la clave de autenticación como un Secreto de Kubernetes. Este será el enfoque del instructivo.

¿Por qué es necesario usar cuentas de servicio?

Estos son los beneficios de tener cuentas de servicio independientes para diferentes aplicaciones:

  • Mejor visibilidad y auditoría de las solicitudes a la API que realiza la aplicación

  • La capacidad de revocar claves de aplicaciones particulares en lugar de compartir una cuenta de servicio y revocar el acceso a la API de todas las aplicaciones a la vez.

  • Exposición reducida en el caso de un incidente de seguridad posible en el que las credenciales de la cuenta de servicio se vuelvan vulnerables.

Antes de comenzar

Sigue los pasos que se indican a continuación para habilitar la API de Kubernetes Engine:
  1. Consulta la página de Kubernetes Engine en Google Cloud Console.
  2. Crea o selecciona un proyecto.
  3. Espera a que la API y los servicios relacionados se habiliten. Esto puede tardar varios minutos.
  4. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

Instala las siguientes herramientas de línea de comandos de este instructivo:

  • gcloud se usa para crear y borrar clústeres de Kubernetes Engine. gcloud se incluye en el SDK de Google Cloud.
  • kubectl se usa para administrar Kubernetes, el sistema de organización de clústeres que emplea Kubernetes Engine. Puedes instalar kubectl mediante gcloud:
    gcloud components install kubectl

Cómo establecer valores predeterminados para la herramienta de línea de comandos de gcloud

Para ahorrar tiempo cuando escribes las opciones del ID del proyecto y la zona de Compute Engine en la herramienta de línea de comandos de gcloud, puedes establecer valores predeterminados:
gcloud config set project project-id
gcloud config set compute/zone compute-zone

Habilita API

Para este instructivo, debes habilitar la API de Pub/Sub y la API de Resource Manager en tu proyecto:

gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com

Crea un clúster de contenedor

Crea un clúster de contenedor con el nombre pubsub-test para implementar la aplicación de suscripción a Pub/Sub:

gcloud container clusters create pubsub-test

Paso 1: Crea un tema de Pub/Sub

En la aplicación de suscripción a Pub/Sub que implementarás, se usa una suscripción denominada echo-read en un tema de Pub/Sub con nombre echo. Crea estos recursos antes de implementar la aplicación.

Primero, crea un tema Pub/Sub:

gcloud

gcloud pubsub topics create echo

Config Connector

Nota: En este paso, se necesita Config Connector. Sigue las instrucciones de instalación para instalar Config Connector en el clúster.

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubTopic
metadata:
  name: echo
Para implementar este manifiesto, descárgalo en tu máquina como topic.yaml y ejecuta lo siguiente:
kubectl apply -f topic.yaml

Luego, crea una suscripción:

gcloud

gcloud pubsub subscriptions create echo-read --topic=echo

Config Connector

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubSubscription
metadata:
  name: echo-read
spec:
  topicRef:
    name: echo
Para implementar este manifiesto, descárgalo en tu máquina como subscription.yaml y ejecuta lo siguiente:
kubectl apply -f subscription.yaml

Paso 2: Implementa la aplicación de suscripción a Pub/Sub

El siguiente paso es implementar el contenedor de la aplicación para recuperar los mensajes publicados en el tema de Pub/Sub. Esta aplicación se escribe en Python mediante las bibliotecas cliente de Google Cloud Pub/Sub, y puedes buscar el código fuente en GitHub.

En el siguiente archivo de manifiesto, se describe una implementación que ejecuta una instancia única de la imagen de Docker de esta aplicación:

# 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

Para implementar este manifiesto, descárgalo en tu máquina como pubsub.yaml y ejecuta lo siguiente:

kubectl apply -f pubsub.yaml

Una vez implementada la aplicación, ejecuta lo siguiente para consultar los pods:

kubectl get pods -l app=pubsub
Resultado:
NAME                      READY     STATUS             RESTARTS   AGE
pubsub-2009462906-1l6bh   0/1       CrashLoopBackOff   1          30s

Puedes ver que el contenedor tiene fallas para iniciarse y que entró en un estado CrashLoopBackOff. Ejecuta lo siguiente para inspeccionar los registros del pod:

kubectl logs -l app=pubsub

Salida:

...
google.gax.errors.RetryError: RetryError(Exception occurred in retry method that
was not classified as transient, caused by <_Rendezvous (StatusCode.PERMISSION_DENIED, scopes.) of RPC that terminated with Request had insufficient authentication>)

El seguimiento de la pila y el mensaje de error indican que la aplicación no tiene permisos para consultar el servicio de Cloud Pub/Sub.

Paso 3: Crea credenciales de una cuenta de servicio

Para otorgarle a tu aplicación en ejecución en GKE el acceso a los servicios de Google Cloud Platform, debes usar cuentas de servicio. Las cuentas de servicio te permiten definir un conjunto de permisos de IAM asociados con tu aplicación.

Console

Para crear una cuenta de servicio, ve a cuentas de servicio en Cloud Console y haz clic en Crear cuenta de servicio:

  1. Especifica un Nombre de cuenta de servicio (por ejemplo, pubsub-app).
  2. En el menú desplegable Función, selecciona "Pub/Sub → Suscriptor".
  3. Haz clic en Crear clave y elige el tipo de clave JSON.
  4. Haz clic en Crear.

Una vez creada la cuenta de servicio, un archivo de claves JSON que contiene las credenciales de la cuenta de servicio se descarga en tu computadora. Debes usar este archivo de claves a fin de configurar la aplicación para autenticarte en la API de Cloud Pub/Sub.

Config Connector

Primero, descarga el recurso siguiente como service-account.yaml.

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccount
metadata:
  name: pubsub-app
spec:
  displayName: Service account for PubSub example

Luego, ejecuta el comando siguiente:

kubectl apply -f service-account.yaml

A continuación, aplica la Función del “Suscriptor de Pub/Sub” a la cuenta de servicio. Descarga el recurso siguiente como service-account-policy.yaml. Reemplaza [PROJECT_ID] por el ID del proyecto.

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]

Luego, ejecuta el comando siguiente:

kubectl apply -f service-account-policy.yaml

Paso 4: Importa credenciales como Secretos

Ahora que tienes la clave de la cuenta de servicio, necesitas una forma de cargarla en tu contenedor. Tu primera idea podría ser agregar un paso en el Dockerfile, pero las claves de la cuenta de servicio son archivos sensibles a la seguridad que no se deben guardar en imágenes de contenedor.

En su lugar, Kubernetes ofrece el tipo de recurso Secreto para activar de forma segura los archivos privados dentro de los Pods en el entorno de ejecución.

kubectl

Para guardar el archivo de claves JSON como un secreto con el nombre pubsub-key, ejecuta el comando siguiente con la ruta al archivo de las credenciales de la cuenta de servicio descargado:

kubectl create secret generic pubsub-key --from-file=key.json=PATH-TO-KEY-FILE.json

Con este comando, se crea un secreto con el nombre pubsub-key que tiene un archivo key.json con los contenidos de la clave privada que descargaste de Cloud Console. Una vez creado el secreto, debes quitar el archivo de claves de tu computadora.

Config Connector

Descarga el recurso siguiente como 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

Luego, ejecuta el comando siguiente:

kubectl apply -f service-account-key.yaml

Paso 5: Configura la aplicación con el secreto

A fin de usar el secreto pubsub-key en tu aplicación, debes modificar la especificación de implementación para realizar las acciones siguientes:

  1. Definir un volumen con el secreto
  2. Activar el volumen del secreto en el contenedor de la aplicación
  3. Configurar la variable de entorno GOOGLE_APPLICATION_CREDENTIALS para señalar el archivo de claves en la activación del volumen del secreto

El archivo de manifiesto actualizado se verá como el siguiente:

# 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

En este archivo de manifiesto, se define lo siguiente a fin de que las credenciales estén disponibles para la aplicación:

  • Un volumen denominado google-cloud-key que usa el secreto con el nombre pubsub-key.

  • Una activación de volumen, que hace que el google-cloud-key esté disponible en el directorio /var/secrets/google dentro del contenedor.

  • La variable de entorno GOOGLE_APPLICATION_CREDENTIALS configurada como /var/secrets/google/key.json, que contendrá el archivo de credenciales cuando el secreto se active como un volumen en el contenedor.

Ten en cuenta que las bibliotecas cliente de Google Cloud reconocen de forma automática la variable de entorno GOOGLE_APPLICATION_CREDENTIALS; en este caso, el cliente de Cloud Pub/Sub para Python.

Para implementar este manifiesto, descárgalo en tu máquina como pubsub-with-secret.yaml y ejecuta lo siguiente:

kubectl apply -f pubsub-with-secret.yaml

Una vez implementado de forma correcta, el estado del pod debe mostrarse como Running:

kubectl get pods -l app=pubsub
Resultado:
NAME                     READY     STATUS    RESTARTS   AGE
pubsub-652482369-2d6h2   1/1       Running   0          29m

Paso 6: Prueba la recepción de mensajes de Pub/Sub

Ahora que ya configuraste la aplicación, publica un mensaje para el tema de Pub/Sub con el nombre echo:

gcloud pubsub topics publish echo --message="Hello, world!"

En pocos segundos, la aplicación debe tomar el mensaje para después imprimirlo en el flujo de resultados. Para inspeccionar los registros desde el pod implementado, ejecuta lo siguiente:

kubectl logs -l app=pubsub
Salida:
Pulling messages from Pub/Sub subscription...
[2017-06-19 12:31:42.501123] ID=130941112144812 Data=Hello, world!

Configuraste correctamente una aplicación en GKE para autenticarte en la API de Pub/Sub con las credenciales de la cuenta de servicio.

Limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

  1. Limpia la suscripción y el tema de Pub/Sub:

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
  2. Borra el clúster del contenedor:

    gcloud container clusters delete pubsub-test

Próximos pasos