Ahora que ya estamos familiarizados con el término de APIOps, gracias a Noelia Martín y su reciente post APIOps, ¿qué es y en qué consiste?, vamos a ver un enfoque más práctico de cómo llevar a la práctica esta disciplina con Apigee como pieza central en un entorno real.

Si quieres refrescar tus conocimientos sobre Apigee te recomendamos este post en el que te contamos qué es y cómo configurar Apigee X, donde José Ramón Berenguer profundiza en la plataforma para desarrollar y administrar APIs.

A pesar de querer darle un enfoque práctico, no podemos perder de vista cuál es el objetivo de esta disciplina: “Mejorar la eficiencia y productividad del equipo de gobierno y de los desarrolladores que generan APIs a través de la automatización de procesos dentro del ciclo de vida de las APIs, permitiendo:

APIOps paso a paso

Teniendo claro el objetivo final, antes de ponernos manos a la obra, era necesario pararse a pensar qué queríamos conseguir en cada una de las etapas del ciclo de APIOps para lograr el objetivo:

Etapas del ciclo de APIOps

Para alcanzar estos resultados es necesario apoyarse en herramientas específicas. A continuación os dejamos la selección de herramientas que hemos utilizado en cada etapa.

Herramientas que hemos utilizado en cada etapa.

Tened en cuenta que no son las únicas herramientas que existen, sino que son las que hemos seleccionado para realizar de forma práctica un ciclo completo de APIOps. Más adelante, daremos unas pinceladas de para qué y cómo usar cada una de ellas. No es el objetivo de este post entrar en los criterios de selección para estas herramientas, pero si tenéis interés no dudéis en enviarnos vuestras dudas.

Antes de poder empezar a plantear siquiera cómo empezar el desarrollo y aplicación de nuestro pipeline, es necesario saber sobre qué entorno, qué API y/o qué aplicación queremos trabajar. Para este fin, hemos utilizado una aplicación ya existente: simplebank-api.

Punto de partida

Esta PoC crea sobre un proyecto de Google un entorno de completo de Apigee versión SaaS con la siguiente arquitectura:

Arquitectura de la PoC

Como veis, es una arquitectura de referencia, más o menos sencilla, que pretende simular casos reales que nos encontramos en nuestros clientes. En este punto tenemos nuestra organización de Apigee desplegada, la base necesaria para empezar a crear nuestras APIs, pero para poder ejecutar un ciclo completo de APIOps necesitamos mucho más. Para poder entender bien el flujo es necesaria una pequeña introducción a los componentes de Apigee, para saber sobre qué recurso se está aplicando el ciclo de APIOps.

Una organización en Apigee es la entidad de nivel superior que contiene todos los recursos, como proxies y productos de API. Cada organización se asigna a un proyecto de Google Cloud Platform (GCP) específico.

Cada organización se asigna a un proyecto específico.

Un environment en Apigee es un contexto de ejecución en tiempo real para tus APIs. Los proxies y shared flows se implementan en entornos específicos. Aquí hay más detalles sobre los elementos dentro de un entorno:

Environment en Apigee

Ahora que ya conocéis los componentes principales de Apigee, teniendo en cuenta que partimos de una definición de API e implementación existente: simplebank-api, la estructura desplegada sobre nuestra organización (Eval) es sencilla de entender.

Environments groups
Configuración para publicar nuestras APIs

Las APIs se convierten en productos exponiéndolas en el portal de desarrollador como productos API. Los desarrolladores de aplicaciones registran aplicaciones para utilizar uno o más productos API.

Una vez publicado el API proxy, junto con sus políticas y shared flow, la vista principal de Apigee queda de la siguiente manera:

Vista principal de Apigee
Vista panel de Apigee

Con todo esto, que no es nada trivial, tenemos preparado nuestro entorno para poder “empezar” a plantear nuestro pipeline de APIOps.

Pensaréis, todo este trabajo para empezar…. ¡sí!, pero hemos de confesaros que gran parte de nuestro esfuerzo, se centró en hacer replicable este punto de partida. Pusimos encima de la mesa tres consideraciones para hacer replicable y customizable esta demo:

pipeline de APIOps

Ahora, aparte de una demo, tenemos activos muy valiosos para hacer proyectos de Apigee donde el arranque está automatizado y es customizable para cada cliente. Destacar que automáticamente el pipeline de APIOps implementado usando: Cloud Build para la definición y ejecución del pipeline, un Trigger que tiene en cuenta los dos branch del repo: main y develop, cada rama está configurada para desplegarse en un environment correspondiente y Cloud Source Repositories para el control de versiones de nuestro código.

APIOps en funcionamiento

A continuación detallamos la implementación de cada una de las etapas.

El repo de código tiene la siguiente estructura:

Repositorio de código

Por un lado, tenemos las especificaciones del proxy: definición, políticas, especificaciones, etc. y, por otro lado, todos los ficheros de configuración necesarios para el pipeline y las distintas herramientas.

A continuación, mostramos el Trigger creado vía Terraform en el paso anterior (Punto de Partida):

Trigger creado vía Terraform

El Trigger se dispara cada vez que se hace un commit a una de las ramas del repositorio, y el pipeline tiene los siguientes pasos:

Pasos del pipeline

En este primer paso seleccionamos sobre qué environment se va a realizar el despliegue, que depende del branch donde se ha hecho el commit. En nuestro caso, el branch main sirve para desplegar en el environment de staging y el branch develop para desplegar en el environment de develop. Aparte, guardamos ciertas variables que posteriormente necesitaremos.

- name: 'gcr.io/cloud-builders/gcloud'
    id: variables
    entrypoint: 'bash'
    args:
      - -c
      - |
        echo "***********************"
        echo "$BRANCH_NAME"
        echo "***********************"

        if [ "$BRANCH_NAME" = "main" ]; then
          export build_envapigee=staging
        else
          export build_envapigee=develop
        fi
        export build_token=\"$(gcloud auth application-default print-access-token)\"
        export build_date=$(date +%Y%m%d_%H%M%S)

        # write all "build_" variables to the persistent volume "/workspace"
        env | grep "^build_" > /workspace/build_vars

Hasta ahora, todos estos pasos del pipeline no hacen que se pare la ejecución del mismo, pero se puede cambiar si el caso de negocio lo requiere.

En este paso, no se trata solo de validar documentos OpenAPI o JSON Schema según las especificaciones. Sirve para hacer cumplir las guías de estilo para garantizar que sus API sean consistentes, válidas y de alta calidad. Vamos a usar rulesets “predefinidos” que actúan como un contenedor de reglas y funciones. Las rulesets que utilizamos son las siguientes:

# Validate specification file: oas and asyncapi
  - name: 'stoplight/spectral'
    id: OAS-validation
    entrypoint: 'sh'
    args:
      - -c
      - |
        echo "Validate API Basic Specification: oas and asyncapi"
        spectral lint -r ./specs/.spectral.yaml ./specs/simplebank-api.yaml -f html -o /workspace/spectral-report.html|| true # catch all errors for demo purpose 

# Validate specification file: owasp-validation
  - name: 'stoplight/spectral'
    id: OWASP-validation
    entrypoint: 'sh'
    args:
      - -c
      - |
        mkdir -p /workspace/spectral
        echo 'extends: ["https://unpkg.com/@stoplight/spectral-owasp-ruleset/dist/ruleset.mjs"]' > ./specs/.spectral.yaml
        spectral lint -r ./specs/.spectral.yaml ./specs/simplebank-api.yaml -f html -o /workspace/spectral/spectral-report-owasp.html || true # catch all errors for demo purpose

# Validate specification file: api versioning
  - name: 'stoplight/spectral'
    id: API-Versioning-validation
    entrypoint: 'sh'
    args:
      - -c
      - |
        mkdir -p /workspace/spectral
        echo 'extends: ["https://unpkg.com/@stoplight/spectral-url-versioning/dist/ruleset.mjs"]' > ./specs/.spectral.yaml
        spectral lint -r ./specs/.spectral.yaml ./specs/simplebank-api.yaml -f html -o /workspace/spectral/spectral-report-url-versioning.html || true # catch all errors for demo purpose 

Openapi-changes: permite ver y explorar lo que ha cambiado con su especificación OpenAPI, entre un solo cambio o para siempre. Generamos un report y lo dejamos en un bucket para poder revisarlo.

# Generate change report
  - id: 'openapi-changes report'
    name: pb33f/openapi-changes
    entrypoint: 'sh'
    args:
      - -c
      - |
        cd /workspace/repository/proxy-cicd
        openapi-changes html-report ./ ./specs/simplebank-openapi.json
        mkdir -p /workspace/openapi-changes
        cp report.html /workspace/openapi-changes/

Hasta ahora hemos detallado la etapa de diseño. Para las siguientes fases de desarrollo, despliegue y testing contaremos cómo se hace para el api proxy simplebank-api y sus configuraciones (no detallamos el despliegue del backend en cloud run, ya que para este post como venimos diciendo nos centramos en la API):

Fases del api proxi
Fases del api proxy pynt
Fases api proxy demo

En primer lugar, os mostramos la parte más interesante: como la solución API de Pynt realiza hacks automatizados de sus API para encontrar los problemas más críticos y las vulnerabilidades de día cero en menos de dos minutos, sin necesidad de configuración. Las pruebas de seguridad dinámicas de Pynt cubren todas las 10 principales API de OWASP.

Pynt utiliza los test funcionales para informar las pruebas de seguridad que ejecuta. Cuanto más extensas sean las pruebas funcionales, más cubrirán las pruebas de seguridad. Más API, más usuarios, más solicitudes y el uso completo de los parámetros desencadenarán pruebas de seguridad dinámicas más amplias y ricas.

Security Test:

La realidad es que la integración con Cloud Build nos dio bastantes dolores de cabeza, pero finalmente pudimos integrarlo en el pipeline de la siguiente manera:

#Security Authoring PYNT
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
    id: Security Authoring PYNT
    entrypoint: 'bash'
    args:
      - '-eEuo'
      - 'pipefail'
      - -c
      - | 
          _VM_STATUS=$(eval 'gcloud compute instances describe pynt-vm --zone=europe-west1-b --format="yaml(status)"')
          echo "PYNT VM Status: $_VM_STATUS"
          while [ "$_VM_STATUS" != "status: RUNNING" ]
          do
            gcloud compute instances start pynt-vm --zone=europe-west1-b
            echo "Wait starting Pynt VM"
            sleep 30
            _VM_STATUS=$(eval 'gcloud compute instances describe pynt-vm --zone=europe-west1-b --format="yaml(status)"')
            echo "PYNT VM Status: $_VM_STATUS"
          done
            echo "Pynt VM Running"
          
          source /workspace/build_vars
        
          gcloud compute config-ssh

          echo "Copy postman collection to pynt-vm"
          gcloud compute scp --ssh-key-expire-after=5m ./specs/SimpleBankBackendAPI.postman_collection.json builder@pynt-vm:~/ --zone=europe-west1-b

          echo "Run pyntcli commands"
          gcloud compute ssh builder@pynt-vm --zone=europe-west1-b --command="export PYNT_CREDENTIALS='$(<pynt_token)' && sudo pynt newman --collection /home/builder/SimpleBankBackendAPI.postman_collection.json  --reporters"

          echo "Copy Report From pynt-vm to local workspace"
          mkdir -p /workspace/pynt
          gcloud compute scp --ssh-key-expire-after=5m --recurse builder@pynt-vm:/home/builder/pynt_results.* /workspace/pynt --zone=europe-west1-b

El proxy se ha creado utilizando arquetipo para generar la estructura básica y Apigee para hacer el export del proxy, políticas, etc. y así se precronstruye la estructura básica de la organización usando apigeecli y cloudbuild y en esta fase se puede usar directamente. Cualquier cambio en la API o en las políticas, se trata como un cambio de código y para realizar el despliegue del proxy se realiza a través del maven pluguin (no hemos incluido un ejemplo completo del pom.xml, ya que podéis encontrar ejemplos sencillos en la documentación de Apigee) de Apigee integrado con Cloud Build:

 - name: 'gcr.io/cloud-builders/mvn'
    id: "Deploy bundle"
    entrypoint: 'bash'
    args:
      - -c
      - |
        # Read environment variables from disk
        source /workspace/build_vars
        mvn -f pom.xml -ntp install -P$BRANCH_NAME -Dorg=$PROJECT_ID \
          -Denv=${build_envapigee} -Dbearer=${build_token}

¡Pipeline completo y funcionando!

Pipeline completo y funcionando

¿Qué hemos conseguido?

Este post es un trabajo conjunto de nuestro de equipo de Estrategia Tecnológica, compartiendo la visión estratégica de cómo afrontar de manera eficiente la adopción de una estrategia de apificación, teniendo en cuenta todos los puntos de fricción y sin perder de vista el objetivo de que las APIs deben aportar valor empresarial y una visión táctica muy técnica de cómo crear un pipeline efectivo para llevar a la práctica la implantación de APIOps, que además sea reutilizable y aplicable a nuestros clientes. Gracias en gran parte a Noelia Martín y a José Ramón Berenguer hemos podido materializar esta visión y presentaros resumidamente este trabajo. Sabemos que nos hemos dejado algunos paso por el camino en este post, pero si estáis interesados en ampliar la información o ver en funcionamiento el pipeline, no dudéis en escribirnos.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.