Autenticación de Servicios
Autenticando Servicios Desplegados
DownToZero (DTZ) proporciona autenticación integrada para tus servicios desplegados, lo que facilita construir aplicaciones seguras sin gestionar tu propia infraestructura de autenticación.
Resumen
Cuando despliegas un servicio en DTZ, la plataforma proporciona automáticamente credenciales de autenticación e información de contexto a través de variables de entorno. Tu servicio puede usar estas para:
- Autenticar solicitudes a otros servicios de DTZ (llamadas a la API, almacenamiento de objetos, etc.)
- Verificar solicitudes entrantes de usuarios
- Acceder a recursos específicos del contexto
- Implementar comunicación segura entre servicios
Variables de Entorno
DTZ inyecta automáticamente las siguientes variables de entorno en los contenedores de tu servicio:
| Variable | Descripción | Ejemplo |
|---|---|---|
DTZ_ACCESS_TOKEN |
Un token JWT para acceder a los servicios de DTZ dentro de tu contexto. | eyJhbGciOiJSUzI1NiI... |
DTZ_CONTEXT_ID |
El identificador de contexto de tu DTZ. | context-3cd84429-64a4-4226-b868-c83feeff0f46 |
PORT |
El puerto en el que tu servicio debe escuchar. | 80 |
Autenticando Solicitudes Entrantes
Tu servicio desplegado puede autenticar solicitudes entrantes usando varios métodos:
Autenticación con API Key
Los usuarios pueden autenticarse con tu servicio usando claves API de DTZ proporcionando la clave en la cabecera X-API-KEY.
curl -H "X-API-KEY: your-api-key" https://yourservice.dtz.rocks/api/endpoint
Autenticación Bearer Token
Proporciona un token JWT en la cabecera Authorization para autenticar.
curl -H "Authorization: Bearer your-jwt-token" https://yourservice.dtz.rocks/api/endpoint
Autenticación Básica
También puedes enviar claves API usando autenticación básica.
curl -u apikey:your-api-key https://yourservice.dtz.rocks/api/endpoint
Autenticación basada en Cookies
Para aplicaciones web, el servicio de identidad de DTZ puede gestionar la autenticación mediante cookies del navegador.
Flujo OAuth
DTZ proporciona autenticación OAuth automática para aplicaciones web. Cuando usuarios no autenticados acceden a tu servicio, son redirigidos automáticamente a la página de inicio de sesión de DTZ y luego redirigidos de vuelta tras un inicio de sesión exitoso.
Usando la Autenticación DTZ en Tu Servicio
Realizar Solicitudes Autenticadas a Servicios DTZ
Usa la variable de entorno DTZ_ACCESS_TOKEN para realizar llamadas autenticadas a otros servicios de DTZ.
import os
import requests
# Obtener el token de acceso DTZ desde el entorno
token = os.environ.get('DTZ_ACCESS_TOKEN')
context_id = os.environ.get('DTZ_CONTEXT_ID')
# Realizar una solicitud autenticada a la API de DTZ
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
response = requests.get(
'https://api.dtz.rocks/v1/containers/services',
headers=headers
)
// Ejemplo en Node.js
const token = process.env.DTZ_ACCESS_TOKEN;
const contextId = process.env.DTZ_CONTEXT_ID;
const response = await fetch('https://api.dtz.rocks/v1/containers/services', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
# Ejemplo en Bash
curl -H "Authorization: Bearer $DTZ_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
https://api.dtz.rocks/v1/containers/services
Verificar la Autenticación Entrante
DTZ gestiona automáticamente la autenticación de las solicitudes entrantes. Cuando un usuario realiza una solicitud autenticada a tu servicio, DTZ:
- Valida las credenciales de autenticación.
- Convierte las API keys en tokens JWT.
- Reenvía la solicitud con una cabecera
Authorization: Bearer <token>.
Tu servicio recibe el token JWT y puede extraer información del usuario de él.
import jwt
import os
from flask import Flask, request
app = Flask(__name__)
@app.route('/protected')
def protected_endpoint():
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return {'error': 'No se proporcionó autenticación'}, 401
token = auth_header.split(' ')[1]
try:
# El token ya está verificado por DTZ, por lo que puedes
# extraer las claims sin verificar la firma.
payload = jwt.decode(token, options={"verify_signature": False})
user_id = payload.get('sub') # ID de identidad
context_id = payload.get('scope') # ID de contexto
roles = payload.get('roles', []) # Roles del usuario
return {
'user_id': user_id,
'context_id': context_id,
'roles': roles,
'message': 'Acceso concedido'
}
except jwt.InvalidTokenError:
return {'error': 'Token inválido'}, 401
// Ejemplo en Express.js
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.get('/protected', (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'No se proporcionó autenticación' });
}
const token = authHeader.split(' ')[1];
try {
// El token ya está verificado por DTZ.
const payload = jwt.decode(token);
const userId = payload.sub; // ID de identidad
const contextId = payload.scope; // ID de contexto
const roles = payload.roles || []; // Roles del usuario
res.json({
user_id: userId,
context_id: contextId,
roles: roles,
message: 'Acceso concedido'
});
} catch (error) {
res.status(401).json({ error: 'Token inválido' });
}
});
Estructura del Token JWT
Los tokens JWT de DTZ contienen las siguientes claims:
| Claim | Descripción | Ejemplo |
|---|---|---|
iss |
Emisor (siempre “dtz.rocks”) | "dtz.rocks" |
sub |
Sujeto (ID de identidad del usuario) | "identity-abc123..." |
aud |
Audiencia (siempre “dtz.rocks”) | "dtz.rocks" |
scope |
ID de contexto | "context-3cd84429..." |
roles |
Roles/permisos del usuario | ["https://dtz.rocks/context/admin/{context_id}"] |
contexts |
Contextos disponibles | ["context-3cd84429..."] |
exp |
Tiempo de expiración | 1640995200 |
iat |
Tiempo de emisión | 1640908800 |
Control de Acceso Basado en Roles
DTZ usa control de acceso basado en roles con identificadores de roles basados en URI. Patrones de roles comunes incluyen:
https://dtz.rocks/context/admin/{context_id}- Administrador de contextohttps://dtz.rocks/containers/admin/{context_id}- Administrador del servicio de contenedoreshttps://dtz.rocks/objectstore/admin/{context_id}- Administrador del almacenamiento de objetos
Puedes comprobar los roles en tu servicio:
def check_role(token, required_role_pattern):
payload = jwt.decode(token, options={"verify_signature": False})
roles = payload.get('roles', [])
context_id = payload.get('scope')
required_role = required_role_pattern.replace('{context_id}', context_id)
return required_role in roles
# Ejemplo:
if check_role(token, 'https://dtz.rocks/containers/admin/{context_id}'):
# El usuario tiene permisos de administrador de contenedores
pass
Buenas Prácticas
Seguridad
- Siempre valida que los tokens JWT contengan las claims esperadas.
- Comprueba los roles del usuario antes de conceder acceso a operaciones sensibles.
- Usa HTTPS para todas las comunicaciones.
- No registres tokens de autenticación sensibles.
Manejo de Errores
- Devuelve códigos de estado HTTP apropiados (por ejemplo, 401 para no autorizado, 403 para prohibido).
- Proporciona mensajes de error significativos sin exponer información sensible.
Rendimiento
- Cachea los resultados de validación de tokens JWT cuando sea posible.
- Usa pool de conexiones para las llamadas a la API de DTZ.
- Considera implementar limitación de tasa de solicitudes.
Ejemplo: Servicio Completo Autenticado
Aquí hay un ejemplo completo de un servicio Python Flask con autenticación DTZ:
import os
import jwt
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
DTZ_TOKEN = os.environ.get('DTZ_ACCESS_TOKEN')
DTZ_CONTEXT_ID = os.environ.get('DTZ_CONTEXT_ID')
def get_user_from_token(token):
"""Extrae información del usuario desde un token JWT de DTZ."""
try:
payload = jwt.decode(token, options={"verify_signature": False})
return {
'user_id': payload.get('sub'),
'context_id': payload.get('scope'),
'roles': payload.get('roles', [])
}
except jwt.InvalidTokenError:
return None
def require_auth(f):
"""Un decorador para requerir autenticación."""
def decorated(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return jsonify({'error': 'Autenticación requerida'}), 401
token = auth_header.split(' ')[1]
user = get_user_from_token(token)
if not user:
return jsonify({'error': 'Token inválido'}), 401
request.user = user
return f(*args, **kwargs)
decorated.__name__ = f.__name__
return decorated
@app.route('/health')
def health():
"""Un endpoint público para comprobación de estado."""
return jsonify({'status': 'healthy'})
@app.route('/profile')
@require_auth
def profile():
"""Un endpoint protegido que devuelve el perfil del usuario."""
return jsonify({
'user_id': request.user['user_id'],
'context_id': request.user['context_id'],
'roles': request.user['roles']
})
@app.route('/admin/users')
@require_auth
def admin_users():
"""Un endpoint solo para administradores."""
required_role = f'https://dtz.rocks/context/admin/{DTZ_CONTEXT_ID}'
if required_role not in request.user['roles']:
return jsonify({'error': 'Se requiere acceso de administrador'}), 403
# Realizar una solicitud autenticada a la API de DTZ
headers = {'Authorization': f'Bearer {DTZ_TOKEN}'}
response = requests.get(
'https://identity.dtz.rocks/api/2021-02-21/users',
headers=headers
)
return jsonify(response.json())
if __name__ == '__main__':
port = int(os.environ.get('PORT', 80))
app.run(host='0.0.0.0', port=port)
Resolución de Problemas
Problemas Comunes
- Token de autenticación no encontrado: Asegúrate de que tu servicio esté desplegado a través del servicio de contenedores de DTZ y de que las variables de entorno se estén leyendo correctamente.
- Errores de token inválido: Verifica que estás extrayendo correctamente el token de la cabecera
Authorizationy que el parseo del JWT funciona. - Errores 403 Forbidden: Verifica que el usuario tenga los roles requeridos en su token JWT.
- Fallo en autenticación servicio a servicio: Asegúrate de usar la variable de entorno
DTZ_ACCESS_TOKENpara las solicitudes salientes.
Pruebas de Autenticación
Puedes probar la autenticación de tu servicio usando curl:
# Probar con una API key
curl -H "X-API-KEY: your-api-key" https://yourservice.dtz.rocks/profile
# Probar con un bearer token
curl -H "Authorization: Bearer your-jwt-token" https://yourservice.dtz.rocks/profile
# Probar sin autenticar (debería devolver 401)
curl https://yourservice.dtz.rocks/profile
Para más información detallada sobre la autenticación de DTZ, consulta la Documentación de autenticación.