
En el panorama actual de los microservicios en Kubernetes, la gestión eficaz de las API, la seguridad y la implementación de políticas de uso justo representan desafíos significativos para los equipos de desarrollo e infraestructura.
Kuadrant.io emerge como una solución open-source diseñada para abordar estas complejidades. El proyecto permite gestionar, asegurar y limitar el acceso a servicios expuestos en Kubernetes, aprovechando la infraestructura estándar como Istio/Envoy y la Kubernetes Gateway API.
En esta publicación
Las Capacidades Clave de Kuadrant
Kuadrant ofrece una capa de gestión de API centrada en el ecosistema nativo de la nube:
- Seguridad Declarativa: Facilita la aplicación de autenticación y autorización (por ejemplo, OAuth2/OIDC) a las APIs. Esto se logra sin requerir modificaciones en el código fuente de los microservicios subyacentes.
- Gestión de Tráfico y Uso: Proporciona un mecanismo robusto de Limitación de Tasa (Rate Limiting) para prevenir sobrecargas en los backends y asegurar un consumo equitativo de los recursos de la API.
- Integración Nativa: Utiliza Custom Resource Definitions (CRDs) que se integran directamente con Kubernetes, ofreciendo una experiencia de configuración familiar.
Componentes Fundamentales de la Arquitectura de Kuadrant
Componentes Fundamentales de la Arquitectura de Kuadrant
Kuadrant opera a través de varios componentes principales que se ejecutan dentro del clúster de Kubernetes y trabajan en conjunto con el Ingress Controller (como Istio o Envoy) para aplicar las políticas:
- Kuadrant Controller: Actúa como el cerebro de la Gestión de API. Su función es observar los recursos de política de Kuadrant (como RateLimitPolicy o AuthPolicy) y traducirlos a la configuración específica necesaria para el data plane.
- Authorino: Es el Servicio de Autorización. Maneja la autenticación (OIDC, OAuth2, claves API) y la autorización, comunicándose con el Ingress.
- Limitador: Es el Servicio de Limitación de Tasa. Se encarga de mantener el estado de las cuentas de las tasas de uso (rate limits) y es el que decide si una solicitud debe ser permitida o rechazada (devolviendo HTTP 429).
- CRDs (Custom Resource Definitions): Definen los recursos declarativos de Kuadrant (RateLimitPolicy, AuthPolicy, etc.), permitiendo a los usuarios gestionar las políticas de API de forma nativa en Kubernetes.
- Data Plane: El Ingress Controller subyacente (e.g., Istio, Envoy) funciona como el punto de aplicación (enforcement point), interceptando el tráfico y consultando a Authorino y Limitador para obtener la decisión de política.
Puesta en Acción
Prerequisitos
Para probar Kuadrant, es necesario contar con un clúster de Kubernetes. En esta publicación se usará kind en forma local.
Para utilizar Kuadrant, se requiere el tipo de servicio LoadBalancer para los Gateways. Dado que kind no cuenta con un mecanismo nativo para asignar direcciones IP a este tipo de servicios, se puede seguir esta guía para configurar un proveedor de LoadBalancer en kind.
Son necesarios los clientes de linea de comandos kubectl y helm
Establecer las variables de entorno
export KUADRANT_GATEWAY_NS=api-gateway # Namespace for the example Gateway export KUADRANT_GATEWAY_NAME=external # Name for the example Gateway export KUADRANT_DEVELOPER_NS=node-api # Namespace for an example node-api app export KUADRANT_CLUSTER_ISSUER_NAME=selfsigned # Name for the ClusterIssuer
Instalar Istio Service Mesh
En este ejemplo se utilizará Istio como proveedor de Gateway API, y Sail Operator proporcionará la instalación de la Gateway API de Istio.
helm install sail-operator \
--create-namespace \
--namespace istio-system \
--wait \
--timeout=300s \
https://github.com/istio-ecosystem/sail-operator/releases/download/0.1.0/sail-operator-0.1.0.tgz
kubectl apply -f -<<EOF
apiVersion: sailoperator.io/v1alpha1
kind: Istio
metadata:
name: default
spec:
# Supported values for sail-operator v0.1.0 are [v1.22.4,v1.23.0]
version: v1.23.0
namespace: istio-system
# Disable autoscaling to reduce dev resources
values:
pilot:
autoscaleEnabled: false
EOF
Desplegar Gateway API CRDs
Para habilitar los CRDs, se debe ejecutar el siguiente comando en una terminal que tenga una sesión iniciada en el clúster.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
Desplegar el Operador Cert Manager
Cert Manager gestiona los certificados TLS para los componentes y los Gateways. Esta herramienta consume los recursos Certificate creados por el operador de Kuadrant en respuesta a la TLSPolicy.
helm repo add jetstack https://charts.jetstack.io --force-update
helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.15.3 \ --set crds.enabled=true
Después de instalar el operador, crear un nuevo recurso ClusterIssuer, para el manejo de certificados para este ejemplo auto firmados.
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: ${KUADRANT_CLUSTER_ISSUER_NAME}
spec:
selfSigned: {}
EOF
Desplegar el Operador Kuadrant
helm repo add kuadrant https://kuadrant.io/helm-charts/ --force-update
helm install \ kuadrant-operator kuadrant/kuadrant-operator \ --create-namespace \ --namespace kuadrant-system
Tras instalar el operador, crear un recurso Kuadrant para instalar los componentes del operador.
kubectl apply -f -<<EOF
kind: Kuadrant
apiVersion: kuadrant.io/v1beta1
metadata:
name: kuadrant
namespace: kuadrant-system
spec: {}
EOF
Desplegar API ejemplo.
Se desplegará una API sencilla de Node.js en Kubernetes que devuelve una lista de libros. En los pasos subsiguientes, se conectará, asegurará y protegerá dicha API utilizando Kuadrant.
kubectl create ns ${KUADRANT_DEVELOPER_NS}
kubectl create deployment ${KUADRANT_DEVELOPER_NS} --image=quay.io/vravula_redhat/node-api:test -n ${KUADRANT_DEVELOPER_NS}
kubectl expose deployment ${KUADRANT_DEVELOPER_NS} --port=8080 --target-port=8080 -n ${KUADRANT_DEVELOPER_NS}
Desplegar Gateway y HTTPRoute
Este es el gateway mediante el cual se permite el tráfico de entrada (ingress) al clúster. En el siguiente YAML, el Gateway representa la instanciación de un balanceador de carga lógico, mientras que la GatewayClass define la plantilla que se utiliza al crear un Gateway.
Usaremos como DNS el servicio nip.io para resolver el nombre de los servicios ofrecidos por kind.
kubectl create ns ${KUADRANT_GATEWAY_NS}
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: ${KUADRANT_GATEWAY_NAME}
namespace: ${KUADRANT_GATEWAY_NS}
spec:
gatewayClassName: istio
listeners:
- allowedRoutes:
namespaces:
from: All
name: api
hostname: "*.nip.io"
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: api-${KUADRANT_GATEWAY_NAME}-tls
kind: Secret
EOF
Desplegar HTTPRoute direccionando hacia el servicio en la API de ejemplo.
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ${KUADRANT_DEVELOPER_NS}
namespace: ${KUADRANT_DEVELOPER_NS}
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: ${KUADRANT_GATEWAY_NAME}
namespace: ${KUADRANT_GATEWAY_NS}
rules:
- backendRefs:
- group: ''
kind: Service
name: ${KUADRANT_DEVELOPER_NS}
namespace: ${KUADRANT_DEVELOPER_NS}
port: 8080
weight: 1
matches:
- path:
type: PathPrefix
value: /
EOF
Verificar el estado del Gateway para asegurar que se encuentre Accepted (aceptado) y Programmed (programado)
kubectl get gateway ${KUADRANT_GATEWAY_NAME} -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Programmed")].message}'
Al revisar el estado del listener, se observará que aún no está programado ni listo para aceptar tráfico debido a una configuración TLS incorrecta. Esto se solucionará en el siguiente paso mediante la TLSPolicy.
kubectl get gateway ${KUADRANT_GATEWAY_NAME} -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.listeners[0].conditions[?(@.type=="Programmed")].message}'
Crear una nueva TLSPolicy
Una TLSPolicy apunta a los recursos Gateways de la Gateway API para proporcionar TLS a los listeners del gateway, gestionando el ciclo de vida de los certificados TLS mediante CertManager.
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1
kind: TLSPolicy
metadata:
name: ${KUADRANT_GATEWAY_NAME}-tls
namespace: ${KUADRANT_GATEWAY_NS}
spec:
targetRef:
name: ${KUADRANT_GATEWAY_NAME}
group: gateway.networking.k8s.io
kind: Gateway
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: ${KUADRANT_CLUSTER_ISSUER_NAME}
EOF
Asegurarse de que el estado de la TLSPolicy sea Enforced.
kubectl get tlspolicy ${KUADRANT_GATEWAY_NAME}-tls -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Enforced")].message}'
Obtener el hostname del Gateway, ejecute el siguiente comando en la terminal.
export INGRESS_HOST=$(kubectl get gtw ${KUADRANT_GATEWAY_NAME} -n ${KUADRANT_GATEWAY_NS} -o jsonpath='{.status.addresses[0].value}')
Verificar la dirección del Gateway
echo $INGRESS_HOST
Nota: Si no se visualiza un valor o si se presenta un mensaje de estado de error que indica que está "esperando la asignación de dirección", se debe verificar si el clúster cuenta con un balanceador de carga predeterminado que pueda asignar una dirección al Gateway.
Realizar una llamada al Gateway. Se debería poder acceder a la API, la cual se encuentra protegida por la TLSPolicy. Es importante notar el uso de https en la URL, ya que esto demuestra que la TLSPolicy se ha aplicado correctamente. Agregaremos el dominio nip.io a nuestras llamadas que corresponde a la configuración del Gateway.
curl -v -k https://$INGRESS_HOST.nip.io/books
Auth policy: Crear un Deny all auth policy a nivel de gateway.
La creación de una política de autenticación de denegación total (deny-all) a nivel del gateway establece una política de autenticación de confianza cero (zero-trust). Con Kuadrant, se pueden añadir políticas tanto a nivel del Gateway como a nivel del HTTPRoute (servicio).
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1
kind: AuthPolicy
metadata:
name: ${KUADRANT_GATEWAY_NAME}-deny-all
namespace: ${KUADRANT_GATEWAY_NS}
spec:
rules:
authorization:
deny-all:
metrics: false
opa:
allValues: false
rego: allow = false
priority: 0
response:
unauthorized:
body:
value: |
{
"error": "Forbidden",
"message": "Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
}
headers:
content-type:
value: application/json
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: ${KUADRANT_GATEWAY_NAME}
EOF
Asegurarse de que el estado de la AuthPolicy sea Enforced.
kubectl get authpolicy ${KUADRANT_GATEWAY_NAME}-deny-all -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Enforced")].message}'
Al intentar acceder a la API nuevamente, se debería obtener un error 403 y un mensaje de error que indica lo siguiente:
"error": "Forbidden","message":"Access denied by default by the gateway operator. If you are the administrator of the service, create a specific auth policy for the route."
Esto demuestra que el gateway es seguro por defecto y aplica una política de confianza cero (zero trust).
curl -k -w "%{http_code}" https://$INGRESS_HOST.nip.io/books
Crear una política de autenticación basada en APIkey para la API.
Si un equipo de desarrollo desea proporcionar un acceso basado en claves (API key) a su API, se puede crear una política de autenticación específica para dicha API basada en llaves.
Crear algunas claves API de muestra como secretos.
kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: api-key-regular-user namespace: kuadrant-system labels: authorino.kuadrant.io/managed-by: authorino stringData: api_key: iamaregularuser type: Opaque --- apiVersion: v1 kind: Secret metadata: name: api-key-admin-user namespace: kuadrant-system labels: authorino.kuadrant.io/managed-by: authorino annotations: kuadrant.io/groups: admins stringData: api_key: iamanadmin type: Opaque EOF
Nota: Este es solo un ejemplo sencillo con claves basadas en cadenas. También puede utilizar un proveedor OIDC para autenticar a los usuarios.
Crear una nueva politica para el acceso con api key.
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1
kind: AuthPolicy
metadata:
name: ${KUADRANT_DEVELOPER_NS}-allow-key
namespace: ${KUADRANT_DEVELOPER_NS}
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: ${KUADRANT_DEVELOPER_NS}
rules:
authentication:
"api-key-authn":
apiKey:
selector: {}
credentials:
queryString:
name: apikey
EOF
Asegurarse de que el estado de la AuthPolicy sea Enforced.
kubectl get authpolicy ${KUADRANT_DEVELOPER_NS}-allow-key -n ${KUADRANT_DEVELOPER_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Enforced")].message}'
Ahora acceda a la API sin la clave. Debería ver un error 401 y deberá denegar el acceso.
curl -k -w "%{http_code}\n" https://$INGRESS_HOST.nip.io/books
Ahora accede con la clave API y debería devolverte una lista de libros junto con el código HTTP 200.
curl -k -w "\n%{http_code}\n" "https://$INGRESS_HOST.nip.io/books?apikey=iamaregularuser"
Crear una política de control de tráfico(rate limit policy) a nivel de Gateway
La política de límite de frecuencia se aplica a los recursos de red de la API de Gateway, como HTTPRoutes y Gateways, utilizando estos recursos para obtener contexto adicional, es decir, qué carga de tráfico (atributos HTTP, nombres de host, atributos de usuario, etc.) se debe limitar.
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1
kind: RateLimitPolicy
metadata:
name: ${KUADRANT_GATEWAY_NAME}-rlp-lowlimits
namespace: ${KUADRANT_GATEWAY_NS}
spec:
limits:
default-limits:
rates:
- limit: 3
window: 10s
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: ${KUADRANT_GATEWAY_NAME}
EOF
Asegurarse de que el estado de la AuthPolicy sea Enforced.
kubectl get ratelimitpolicy ${KUADRANT_GATEWAY_NAME}-rlp-lowlimits -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Enforced")].message}'
Ahora acceda a la API más de 3 veces en 10 segundos para infringir los límites de frecuencia y debería ver un 429 con un mensaje de Demasiadas solicitudes después de las primeras 3 llamadas.
for i in $(seq 1 10);
do
curl -k -w "\n%{http_code}\n" "https://$INGRESS_HOST.nip.io/books?apikey=iamaregularuser"
done
Conclusión
La gestión de APIs en Kubernetes ya no tiene que ser un ejercicio complejo de configuración de proxies y lógica dispersa. Kuadrant.io ofrece una visión unificada y declarativa para proteger y monetizar los servicios en la nube, alineando la seguridad y la gestión del tráfico con los principios nativos de Kubernetes.
El futuro de la gestión de APIs en Kubernetes es nativo y declarativo.
Puedes explorar ladocumentación oficial de Kuadrant.io para profundizar en sus capacidades y entender cómo puede transformar la gestión de APIs en entornos de Kubernetes.
