Configurar Cloud Endpoint y Autenticación JWT GCP
Descripción
Cloud Endpoint es un sistema de administración de API que proporciona funciones para ayuda crear, mantener y proteger sus API.
Para identificar un servicio que envía solicitudes a tu API, usas una cuenta de servicio. El servicio de llamadas emplea la clave privada de la cuenta de servicio para firmar un token web JSON (JWT) seguro y enviarlo en la solicitud a tu API.
Pre-requisitos
- Definir Contrato Openapi.yaml en version 2.0
- Habilitar APIS
- Crear recursos GCP (IP EXTERNA, Cluster GKE y Service Accounts)
- Generar archivos k8s
Requisitos Técnicos
Google Cloud Platform
- Una cuenta personal de Google Cloud
- SDK de Google Cloud
Contrato openapi-jwt.yaml
Para integrar CloudEndpoint en el contrato se debe agregar la siguiente sintaxis.
host: "DOMAIN_OPENAPI"
x-google-endpoints:
- name: "DOMAIN_OPENAPI"
target: "IP_RESERVADA"
Para agregar la autenticación con jwt se debe agregar la siguiente sintaxis.
securityDefinitions:
apitoken:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "SA_EMAIL_ADDRESS"
x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
x-google-audiences: "DOMAIN_OPENAPI"
security:
- apitoken: []
DOMAIN_OPENAPI : Dominio al cual sera asociado el contrato, se puede ocupar un dominio propio o uno generado por google.
IP_RESERVADA : En la sección target del contrato solo aplica si se utiliza el dominio generado por google.
SA_EMAIL_ADDRESS : Hace referencia a la cuenta de servicio la cual tiene permiso para acceder a los diferentes endpoint que la api exponga.
swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Endpoints Example Cloudendpoint"
version: "1.0.0"
host: "DOMAIN_OPENAPI"
x-google-endpoints:
- name: "DOMAIN_OPENAPI"
target: "IP_RESERVADA"
consumes:
- "application/json"
produces:
- "application/json"
schemes:
- "https"
- "http"
securityDefinitions:
apitoken:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "SA_EMAIL_ADDRESS"
x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
x-google-audiences: "DOMAIN_OPENAPI"
security:
- apitoken: []
paths:
"/echo":
post:
description: "Echo back a given message."
operationId: "echo"
produces:
- "application/json"
responses:
200:
description: "Echo"
schema:
$ref: "#/definitions/echoMessage"
parameters:
- description: "Message to echo"
in: body
name: message
required: true
schema:
$ref: "#/definitions/echoMessage"
"/auth/info/googlejwt":
get:
description: "Returns the requests' authentication information."
operationId: "auth_info_google_jwt"
produces:
- "application/json"
responses:
200:
description: "Authentication info."
schema:
$ref: "#/definitions/authInfoResponse"definitions:
echoMessage:
type: "object"
properties:
message:
type: "string"
authInfoResponse:
properties:
id:
type: "string"
email:
type: "string"
Al rellenar los campos mencionados es necesario desplegar el contrato en GCP.
Habilitar APIS en GCP
servicemanagement.googleapis.com
servicecontrol.googleapis.com
endpoints.googleapis.com
Generar Recursos GCP
Crear Ip externa ip-cloudendpoint de tipo Global
VPC NETWORK >> External IP Adressess >> Reserve static address
Crear Cluster GKE
kubernetes Engine >> Cluster >> Create Cluster
Service Accounts
IAM & ADMIN >> Service Accounts >> Create Service Accounts
Para este ejemplo se crearan 2 cuentas de servicios
Se debe crear una cuenta de servicio para realizar la integración con el endpoint desplegado, para que tenga acceso al contrato.
El permiso que debe tener es el siguiente Service Controller
Se debe crear la segunda cuenta de servicio para que esta pueda solicitar token al recurso cloudendpoint con el permiso Service Account Token Creator
Desplegar contrato openapi en cloud endpoint
gcloud config set project [PROJECT ID]
gcloud endpoints services deploy openapi-jwt.yaml
Contrato Desplegado
Paths Contrato Desplegado
Generar Archivos K8S
Deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: esp-echo
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 50% # how many pods we can add at a time
maxUnavailable: 50%
selector:
matchLabels:
app: esp-echo
template:
metadata:
labels:
app: esp-echo
tier: backend
spec:
volumes:
- name: credentials
secret:
secretName: service-account-creds
containers:
- name: esp-echo
image: gcr.io/endpoints-release/echo:latest
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:1
args: [
"--http_port=8080",
"--backend=127.0.0.1:8081",
"--service=echo-api.endpoints.arched-cabinet-288909.cloud.goog",
"--rollout_strategy=managed",
"-z=healthz",
"--service_account_key=/secrets/cloud-endpoints/echo-cloudendpoint.json"]
readinessProbe:
httpGet:
path: /healthz
port: 8080
ports:
- containerPort: 8080
volumeMounts:
- name: credentials
mountPath: /secrets/cloud-endpoints
readOnly: true
En el despliegue se encontraran 2 componentes , el cliente de cloudendpoint y el componente con las características desplegadas en el contrato openapi.
En la sección — service en el deployment debe ser reemplazado por el valor desplegado en su contrato.
Ejemplo:
"--http_port=8080",
"--backend=127.0.0.1:8081",
"--service=echo-api.endpoints.project-id.cloud.goog
Service.yaml
apiVersion: v1
kind: Service
metadata:
name: esp-echo-service
annotations:
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app: esp-echo
tier: backend
# LOCAL/INTERNAL: NodePort, GCP/EXTERNAL: LoadBalancer, ClusterIP
type: NodePort
Ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: "ingress"
annotations:
kubernetes.io/ingress.allow-http: "true"
kubernetes.io/ingress.global-static-ip-name: "ip-cloudendpoint"
spec:
rules:
- http:
paths:
- backend:
serviceName: "esp-echo-service"
servicePort: 80
path: "/*"
Se genera el namespace cloud-endpoint y el secrets con el contenido de la cuenta de servicio para acceder al contrato desplegado en cloudendpoint .
kubectl create namespace cloud-endpoint
kubectl -n cloud-endpoint create secret generic service-account-creds --from-file=echo-cloudendpoint.json
Ya teniendo los archivos se realiza el despliegue de los componentes en el cluster GKE
kubectl -n cloud-endpoint apply -f Deployment.yaml
kubectl -n cloud-endpoint apply -f Service.yaml
kubectl -n cloud-endpoint apply -f Ingress.yaml
Verificar servicios desplegados
Cuando se realiza los despliegues se reflejara en la interfaz de GCP.
Verificar logs servicios desplegados
Componente esp
Componente esp echo
Validar endpoint que expone el servicio
Endpoint 1
http://IP-EXTERNA/echo
Endpoint 2
http://IP-EXTERNA/auth/info/googlejwt
Al intentar consultar los diferentes endpoint , nos responde el servicio que no estamos autorizados.
Generar Token con Firma JWT
Para generar un token es necesaria la cuenta de servicio que se genero previamente con el permiso Service Account Token Creator.
Autentificar con cuenta de servicio generada
gcloud config set project [PROJECT ID]gcloud auth activate-service-account --key-file=[SERVICEACCOUNTJSON]
Generar archivo jwt.json
{
"iss": "[EMAIL_SERVICEACCOUNT]",
"iat": [TIEMPO_INICIO_TOKEN],
"aud": "[SERVICE_NAME_CLOUDENDPOINT]",
"exp": [TIEMPO_INICIO_EXPIRACION],
"sub": "[EMAIL_SERVICEACCOUNT]"
}
Firmar archivo jwt.json
gcloud beta iam service-accounts sign-jwt --iam-account [EMAIL_SERVICEACCOUNT] jwt.json signed-jwt.json
Se generará el archivo signed-jwt.json con el contenido del token. Luego se puede agregar como método de autenticación bearer Token a postman , para consultar el servicio.
Endpoint 1
http://IP-EXTERNA/echo
Endpoint 2
http://IP-EXTERNA/auth/info/googlejwt
Hemos aprendido a realizar la integración de CloudEndpoint mas la autenticación a través de un método jwt.
Código Fuente: https://github.com/mauricio-echeverria/Cloud-Endpoint-y-Autenticaci-n-JWT