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:
- Garantizar un mínimo de cumplimiento de las buenas prácticas.
- Aumenta la consistencia, resiliencia y seguridad por parte de los equipos de forma autónoma.”
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:
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.
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.
Esta PoC crea sobre un proyecto de Google un entorno de completo de Apigee versión SaaS con la siguiente arquitectura:
- LB externo de capa 7 para acceder desde internet a los proxies.
- Se genera un certificado utilizando la utilidad https://nip.io
- Acceso a backends vía internet o con servicios expuestos en la misma VPC que utiliza Apigee.
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.
- Proxies: representan las APIs y permiten exponer interfaces para desacoplar servicios backend. Se implementan dentro de una organización y utilizan políticas para procesar solicitudes HTTP. Estos proxies se construyen utilizando políticas que proporcionan funcionalidades como seguridad, límites de velocidad y transformación de mensajes.
- Shared Flows: estos flujos permiten combinar un conjunto de políticas en un patrón común, lo que facilita la reutilización de la lógica del proxy en múltiples APIs.
- API Products: antes de publicar APIs en el portal del desarrollador, se agrupan y categorizan mediante la creación de productos de API. Estos productos de API proporcionan un mecanismo de acceso y autorización para un grupo de APIs.
- Claves de API y Tokens OAuth: se utilizan para controlar el acceso a las APIs. Las aplicaciones se registran en el portal del desarrollador y obtienen claves de API o tokens OAuth para acceder a las APIs.
- Usuarios y roles: los usuarios pueden tener acceso a una o más organizaciones y están asociados con roles que especifican permisos dentro de la organización. Los roles se gestionan utilizando Identity and Access Management (IAM).
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:
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.
- Tenemos una organización, con dos environments groups (develop y staging) y dos environments (develop y staging). En cada environment está desplegado una revisión del api proxy:
- A la hora de publicar nuestras APIs hemos seguido esta configuración:
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:
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:
- PRE-DEMO: se crea una arquitectura base basada en Apigee X con una organización (una instancia), x2 environments groups, x2 environments, x2 API proxy, x1 SF, x2 Developers, x3 API products y repositorio de código con el pipeline CI/CD (Cloud Build + Trigger + Cloud Source Repositories).
- Toda la infraestructura de la Demo está creada con Terraform, para la creación de del punto de partida de la organización de Apigee se ha creado un pipeline propio que mediante apigeecli crea, configura y despliega los activos en la organización de Apigee previamente creada.
- El pipeline de APIOps está implementado usando: Cloud Build + Trigger + Cloud Source Repositories, pero es exportable a otras tecnologías como GitLab CI/CD.
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.
A continuación detallamos la implementación de cada una de las etapas.
El repo de código tiene la siguiente estructura:
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):
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:
- Step 1: selección de environment y variables
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
- Step 2, 3 y 4: Validate specification
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:
- OAS & Asyncapi: spectral viene con dos ruleset integrados: OpenAPI (OAS) y AsyncAPI. Son buenos puntos de partida, pero el verdadero poder de Spectral radica en la personalización y creación de un conjunto de reglas que se ajuste a su proyecto u organización. En esta demo vamos a usar rulesets predefinidos.
- API Versioning: Spectral API Versioning Ruleset. El control de versiones de API puede ser un tema aterrador, pero hay algunas ventajas fáciles que siempre es mejor evitar cuando se utiliza OpenAPI para describir una API, como no agrupar varias versiones globales en un solo archivo.
- OWASP ruleset: Spectral OWASP API Security: Escanea un documento OpenAPI para detectar problemas de seguridad. Como OpenAPI solo describe el nivel superficial de la API, no puede ver lo que sucede en su código, pero puede detectar problemas obvios y estándares obsoletos que se utilizan.
# 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):
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:
- Business Logic → Los ataques a API de lógica empresarial se refieren a un tipo de amenaza a la seguridad en la que un atacante explota vulnerabilidades en la lógica subyacente de una API para lograr acceso no autorizado o manipular datos dentro de una aplicación empresarial.
- Injections → Los fallos de inyección, como SQL, NoSQL, inyección de comandos, etc., ocurren cuando se envían datos que no son de confianza a un intérprete como parte de un comando o consulta. Los datos maliciosos del atacante pueden engañar al intérprete para que ejecute comandos no deseados o acceda a datos sin la autorización adecuada.
- Authentication Bypass → Se refiere a una vulnerabilidad de seguridad en la que un atacante puede acceder a un punto final o funcionalidad de API sin proporcionar las credenciales de autenticación necesarias.
- Mass Assignment → Es un problema de seguridad que ocurre cuando un atacante puede manipular o inyectar datos inesperados en una solicitud de API que le permite modificar datos que no debería poder modificar.
- Server-Side Request Forgery SSRF → SSRF ocurre cuando un atacante puede manipular los parámetros de entrada de una aplicación web que solicita recursos de otros servidores, como bases de datos, servicios web u otras API.
- El atacante puede aprovechar esta vulnerabilidad para enviar solicitudes falsificadas a servidores internos que no están destinados a estar expuestos a Internet, como sistemas backend o bases de datos. Esto puede resultar en acceso no autorizado, robo de datos u otras actividades maliciosas que pueden comprometer la seguridad de toda la aplicación web o de la red en la que está alojada.
- Stack Trace In Response → Lista de llamadas a funciones que muestra el flujo de ejecución. Puede contener información sobre los nombres y ubicaciones de funciones, variables y parámetros utilizados en el código. Si se devuelve stack trace en una respuesta de API, puede revelar detalles sobre la implementación de la API en el lado del servidor, incluido el lenguaje de programación, el marco y las bibliotecas utilizadas, así como la ruta del archivo y los números de línea del código que arrojó el error.
- Lack of Resources and Rate Limiting → Una vulnerabilidad de límite de recursos en una API ocurre cuando un atacante puede hacer que la API consuma recursos excesivos (como CPU, memoria o ancho de banda de red) más allá de lo previsto por los diseñadores de la API. Esto puede provocar ataques de denegación de servicio (DoS), en los que la API deja de estar disponible o no responde debido al agotamiento de los recursos.
- File Path Manipulation → La manipulación de path del archivo es un tipo de vulnerabilidad de seguridad que ocurre cuando una aplicación en la nube permite a un atacante incluir archivos ubicados en el sistema de archivos local del servidor. Esta vulnerabilidad generalmente surge cuando la aplicación procesa la entrada proporcionada por el usuario sin la validación o desinfección adecuada.
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!
- Incrementar la velocidad. Debido a que todo está automatizado en el pipeline simplifica tanto el proceso de onboarding de nuevos desarrolladores como la entrega iterativa por parte de los equipos.
- Mejorar la consistencia. Al incluir mecanismos de validación automatizada se mejora la consistencia y sobre todo se garantiza un mínimo de cumplimiento de buenas prácticas establecidas.
- Aumentar la agilidad y productividad. Al disminuir el número de iteraciones, se mejora la productividad tanto del equipo de gobierno al no tener que revisar tantas APIs y focalizarse en otras tareas, como de los equipos de desarrollo al no dedicar tanto tiempo en el cumplimiento de la normativa.
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.
Tell us what you think.