PEP y PDP para Autorización Segura con Cognito

Este archivo ha sido traducido automaticamente por IA, pueden ocurrir errores
En una de mis publicaciones anteriores Construyendo un BBQ conectado sin servidor como SaaS - Parte 4 - AuthZ mencioné el tema de Autenticación y Autorización con PEP distribuidos (Puntos de Aplicación de Política) y un PDP centralizado (Punto de Decisión de Política). En esta publicación profundizaré un poco más y expandiré esa configuración. Exploraré cómo estos conceptos funcionan en la práctica, los beneficios que ofrecen y cómo podemos aprovecharlos en nuestra arquitectura sin servidor usando AWS Lambda, API Gateway y Cognito User Pools.
Además, hablaré sobre el modelo de Control de Acceso Basado en Roles (RBAC), cómo implementarlo usando Grupos de Cognito y DynamoDB, y cómo el caché puede mejorar el rendimiento de nuestro sistema de autorización.
Toda la configuración, con instrucciones detalladas de despliegue y todo el código, se puede encontrar en Serverless Handbook PEP y PDP
Comencemos con un breve repaso.
Autenticación (AuthN) vs. Autorización (AuthZ)
Es crucial distinguir entre Autenticación y Autorización, dos términos que a menudo se mezclan y que he tenido que explicar en muchas ocasiones, pero que sirven propósitos muy diferentes.
Autenticación (AuthN)
La autenticación se trata de verificar la identidad. Responde a la pregunta, ¿Quién eres? Cuando un usuario inicia sesión en nuestra aplicación, la autenticación asegura que sean quien dicen ser. Esto podría involucrar algo tan simple como un nombre de usuario y contraseña o una autenticación multifactor (MFA) más compleja.
Autorización (AuthZ)
Una vez que la identidad del usuario está autenticada, entra en juego la autorización. Este proceso responde a la pregunta, ¿Qué puedes hacer? La autorización determina qué recursos, datos y acciones está permitido acceder al usuario basándose en sus roles y permisos.
¿Qué son PEP y PDP?
Antes de profundizar en cómo implementarlos en AWS, es esencial entender los roles que PEP y PDP juegan en la autorización.
PEP (Punto de Aplicación de Política)
En términos simples, el PEP es el guardián. Son los puntos en nuestro sistema donde se hacen cumplir las decisiones de control de acceso. Cuando un usuario intenta acceder a un recurso protegido, el PEP es el componente responsable de verificar si la solicitud está permitida o denegada basándose en los permisos del usuario.
En nuestro caso, el Autorizador Lambda en API Gateway actúa como el PEP. El Autorizador Lambda intercepta cada solicitud API entrante, valida el token JWT (generalmente del Cognito User Pool o cualquier proveedor de identidad), y envía la información del usuario (reclamaciones) al PDP para la evaluación de autorización.
El PEP asegura que el JWT es válido, verifica su caducidad, comprueba su firma y valida las reclamaciones (como aud, iss, y sub). Luego pasa las reclamaciones al PDP para una decisión final sobre si el usuario está autorizado para acceder al recurso solicitado.
PDP (Punto de Decisión de Política)
El PDP es donde reside la lógica de autorización. Una vez que el PEP verifica el JWT y asegura que el token es válido, el PDP determina si el usuario está permitido para acceder al recurso solicitado basándose en sus roles, permisos o políticas.
El PDP es una implementación separada, un microservicio independiente. En nuestro caso, una función Lambda, que realiza la decisión de autorización real. Verifica los roles del usuario, que están almacenados en la reclamación groups en el JWT (de Cognito), y los compara con los permisos requeridos para acceder a un recurso específico, almacenados en un almacén de datos. En nuestro caso usaremos DynamoDB.
El PDP valida si el usuario tiene los permisos necesarios (como Admin, User, o Manager) para acceder al recurso (por ejemplo, GET /admin, POST /profile). El PDP también puede incorporar lógica de negocio adicional, como verificar el acceso basado en el tiempo o geolocalización.
Beneficios de usar PEP y PDP en la Autorización
Implementar PEP distribuidos y PDP centralizado ofrece varios beneficios, especialmente a medida que nuestras aplicaciones escalan.
Separación de Preocupaciones Al dividir las preocupaciones de aplicación (PEP) y decisión (PDP), obtenemos código más limpio y mantenible. El Autorizador Lambda (PEP) se enfoca puramente en la validación y aplicación. Mientras que el PDP está dedicado a la evaluación de políticas.
Reducción de Latencia: Al colocar los PEP cerca de donde se deben tomar las decisiones, podemos reducir la latencia, con una estrategia de caché esto se puede reducir aún más.
Gestión: Con un PDP centralizado, toda nuestra lógica de autorización está centralizada en una ubicación. Esto hace que sea más fácil gestionar y actualizar políticas a medida que evolucionan nuestros requisitos. Ya sea modificando roles o agregando nuevos conjuntos de permisos, tener un PDP central reduce la sobrecarga de actualizar políticas en múltiples lugares.
Consistencia y Cumplimiento: Cada solicitud se evalúa contra el mismo conjunto de políticas, asegurando una toma de decisiones consistente en todo nuestro sistema.
Escalabilidad: Ambos componentes PEP y PDP se escalan independientemente según la demanda. Si nuestro sistema necesita manejar un mayor volumen de solicitudes, API Gateway y Lambda pueden escalar automáticamente. Además, el PDP puede optimizarse para el rendimiento implementando caché.
Flexibilidad: Un PDP nos permite adaptar el modelo de autorización a nuestras necesidades. Si nuestros requisitos cambian (por ejemplo, pasar al control de acceso basado en atributos (ABAC) o introducir un sistema de permisos más granular), podemos modificar fácilmente el PDP para acomodar estos cambios sin afectar otras partes del sistema.
Usando PEP y PDP en AWS con Arquitectura Sin Servidor
En AWS, la integración de PEP y PDP encaja perfectamente con componentes sin servidor como Lambda y API Gateway.
PEP - Autorizador Lambda de API Gateway
Cuando un cliente envía una solicitud a nuestro extremo de API Gateway, el Autorizador Lambda (PEP) intercepta la solicitud antes de que llegue a nuestro servicio de backend. Nuestra implementación realizará varios pasos clave.
Validación de JWT: Decodifica el JWT, valida la firma y verifica si el token ha caducado.
Envío de Reclamaciones: Después de verificar el token, el Autorizador Lambda envía las reclamaciones (como sub, groups, y role) al PDP para futuras verificaciones de autorización. En nuestra solución en realidad enviaremos el token JWT completo.
Para reducir el número de llamadas a nuestro PEP y también al PDP podemos utilizar el caché de autorización que existe en API Gateway.
PDP - Función Lambda de lógica de autorización
El PDP está implementado como una función Lambda separada, en nuestro caso, y recibirá el token JWT completo, o las reclamaciones, para realizar la lógica de autorización, que incluirá varios pasos.
- Verificar el rol del usuario (usando la reclamación
groupsde Cognito). - Consultar una tabla de DynamoDB que contiene asignaciones de rol a permisos (por ejemplo, qué roles tienen acceso a qué extremos de API).
- Evalúa si el rol del usuario coincide con los permisos requeridos para el recurso o extremo de API solicitado.
Token de ID vs Token de Acceso
Al implementar el flujo de trabajo de PEP y PDP, es esencial entender la diferencia entre Tokens de ID y Tokens de Acceso, ya que ambos se usan a menudo en flujos de trabajo de autorización.
Token de ID
El Token de ID se usa principalmente para autenticación y contiene información sobre quién es el usuario. Contiene reclamaciones sobre la identidad del usuario autenticado, como nombre, correo electrónico y número de teléfono.
Token de Acceso
El Token de Acceso se usa para otorgar al usuario acceso a recursos protegidos, autorización. El Token de Acceso contiene información sobre los permisos del usuario, como a qué recursos está permitido acceder y los alcances que se le han concedido, que definen lo que el usuario puede hacer (por ejemplo, read:profile, write:profile). El token de acceso no incluye la reclamación aud.
Personalización de tokens en Cognito
Con el activador Lambda de generación de pre-token podíamos antes solo personalizar el Token de ID, por lo tanto a menudo se usaba también para autorización. Con la introducción del nuevo evento V2 en Cognito User Pools podemos personalizar tanto el Token de ID como el Token de Acceso.
Implementando PEP y PDP
Con esta introducción completada, profundicemos en la implementación de un PEP y PDP con RBAC. Nuestro PEP será el Autorizador Lambda en API Gateway y nuestro PDP será una función Lambda separada. El PDP usará Grupos de Cognito y DynamoDB para la lógica de autorización RBAC.
Visión general de la arquitectura
Como recordatorio, todo el código y la arquitectura se pueden encontrar en Serverless Handbook PEP y PDP
En esta solución implementaremos nuestro PEP usando el Autorizador Lambda en API Gateway. El PDP en este caso también se implementará usando una función Lambda. Asignaremos a los usuarios un Rol usando Grupos de Cognito y mantendremos una asignación Rol - Permiso en DynamoDB.

Para entender mejor el flujo durante un acceso a la API.

Como se ve, no usaremos un API Gateway para nuestro PDP. En su lugar, nuestro PEP invocará la función Lambda del PDP. Hay pros y contras con este enfoque, por supuesto. En el lado positivo tenemos menor latencia, una invocación directa de Lambda es a menudo más rápida que una llamada a una API. Menor costo ya que no tenemos que pagar por la invocación de API Gateway. En el lado negativo, creamos un acoplamiento más estrecho y cambiar la implementación del PDP podría ser más difícil. Necesitaríamos implementar un caché separado en el PDP, usando un API Gateway podríamos confiar en el caché de API Gateway.
Sin embargo, el enfoque que elijas debe ser caso por caso, no hay una regla de oro sobre cómo implementarlo exactamente.
Desplegar autenticación y Cognito
Lo primero que haremos es desplegar y configurar Cognito y los recursos necesarios para el inicio de sesión. Configuraremos el UserPool de Cognito, el inicio de sesión administrado y un sitio web simple que manejará los callbacks de Cognito y mostrará nuestros tokens JWT. Por simplicidad será solo una página HTML estática desde CloudFront y algunas funciones Lambda@Edge. Usaré la configuración que he descrito en esta publicación de blog, así que para una inmersión profunda te recomiendo que la leas.
Así que como primer paso desplegamos Lambda@Edge, la distribución de CloudFront y el certificado SSL desde Serverless Handbook PEP y PDP
Luego, despleguemos y configuremos Cognito. Crearemos el UserPool, un cliente, estilo de inicio de sesión, etc.
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Description: Crea el User Pool y Cliente usados para Autenticación
Parámetros:
ApplicationName:
Tipo: String
Descripción: La aplicación que posee esta configuración.
DomainName:
Tipo: String
Descripción: El nombre de dominio para usar en cloudfront
HostedAuthDomainPrefix:
Tipo: String
Descripción: El prefijo de dominio para usar para la UI alojada del UserPool <HostedAuthDomainPrefix>.auth.[región].amazoncognito.com
Recursos:
UserPool:
Tipo: AWS::Cognito::UserPool
Propiedades:
Configuración de nombre de usuario:
CaseSensitive: false
Atributos verificados automáticamente:
- email
Nombre del UserPool: !Sub ${ApplicationName}-user-pool
Esquema:
- Nombre: email
Tipo de atributo de datos: String
Mutables: false
Requerido: true
- Nombre: name
Tipo de atributo de datos: String
Mutables: true
Requerido: true
UserPoolClient:
Tipo: AWS::Cognito::UserPoolClient
Propiedades:
UserPoolId: !Ref UserPool
GenerarSecreto: Verdadero
AllowedOAuthFlowsUserPoolClient: true
CallbackURLs:
- !Sub https://${DomainName}/signin
AllowedOAuthFlows:
- code
- implicit
AllowedOAuthScopes:
- phone
- email
- openid
- profile
SupportedIdentityProviders:
- COGNITO
HostedUserPoolDomain:
Tipo: AWS::Cognito::UserPoolDomain
Propiedades:
Dominio: !Ref HostedAuthDomainPrefix
Versión de inicio de sesión administrado: 2
UserPoolId: !Ref UserPool
ManagedLoginStyle:
Tipo: AWS::Cognito::ManagedLoginBranding
Propiedades:
ClientId: !Ref UserPoolClient
UserPoolId: !Ref UserPool
UseCognitoProvidedValues: true
UserPoolIdParameter:
Tipo: AWS::SSM::Parameter
Propiedades:
Nombre: !Sub /${ApplicationName}/userPoolId
Tipo: String
Valor: !Ref UserPool
Descripción: Parámetro SSM para el ID del User Pool
Etiquetas:
ApplicationName: !Ref ApplicationName
UserPoolHostedUiParameter:
Tipo: AWS::SSM::Parameter
Propiedades:
Nombre: !Sub /${ApplicationName}/userPoolHostedUi
Tipo: String
Valor: !Sub https://${HostedAuthDomainPrefix}.auth.${AWS::Region}.amazoncognito.com/login?client_id=${UserPoolClient}&response_type=code&scope=email+openid+phone+profile&redirect_uri=https://${DomainName}/signin
Descripción: Parámetro SSM para la UI alojada del User Pool
Etiquetas:
ApplicationName: !Ref ApplicationName
Salidas:
CognitoUserPoolJwksUri:
Valor: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}/.well-known/jwks.json
Descripción: La URI del jwks del UserPool
Exportar:
Nombre: !Sub ${AWS::StackName}:jwks-url
CognitoUserPoolID:
Valor: !Ref UserPool
Descripción: El ID del UserPool
CognitoAppClientID:
Valor: !Ref UserPoolClient
Descripción: El cliente de la aplicación
Exportar:
Nombre: !Sub ${AWS::StackName}:app-audience
CognitoUrl:
Descripción: La url
Valor: !GetAtt UserPool.ProviderURL
CognitoHostedUI:
Valor: !Sub https://${HostedAuthDomainPrefix}.auth.${AWS::Region}.amazoncognito.com/login?client_id=${UserPoolClient}&response_type=code&scope=email+openid+phone+profile&redirect_uri=https://${DomainName}/signin
Descripción: La URL de la UI alojada
Con este despliegue hecho podemos pasar a la Consola y crear grupos a los que se pueden agregar usuarios. Crearé tres grupos, Admin, Developer y Test. Haz clic en Crear Grupo y dale un nombre. El nombre del grupo representaría el Rol que tendrá el usuario y determinará qué permisos obtendrá, más sobre esa configuración más adelante.

Luego podemos crear algunos usuarios y asignarlos a uno de los grupos.
Para probar esta configuración podemos navegar a la página web desplegada con la distribución de CloudFront e inspeccionar los tokens JWT, cookies.

Si copiamos el token de acceso y lo decodificamos, uso jwt.io, podemos ver que mi usuario tiene la reclamación cognito:groups que nuestro PEP y PDP usarán más tarde para los permisos.
Configurar y desplegar PDP
Luego podemos desplegar nuestro servicio de Autorización, nuestro PDP, responsable de tomar decisiones de permisos.
La lógica se implementará en una función Lambda y para gestionar los permisos basados en roles, crearemos una tabla DynamoDB que almacena permisos para cada rol. Cada permiso define qué recursos puede acceder el usuario, esto podría ser un extremo de API específico y el método HTTP, pero por supuesto no limitado a eso. Modelaremos los datos de la tabla
PK (Clave de partición): El Rol (por ejemplo, Admin, User). SK (Clave de ordenación): El recurso, por ejemplo extremo y Método, por ejemplo GET /unicorn. Acción: La acción, por ejemplo GET, PUT, WRITE, READ, LIST etc Recurso: El Recurso, por ejemplo el extremo /unicorn Efecto: El Efecto, Permitir o Denegar Descripción: Una descripción del permiso.
| PK | SK | Acción | Recurso | Efecto | Descripción |
|---|---|---|---|---|---|
| Admin | GET /unicorn | GET | /unicorn | Permitir | Admin puede acceder a todos los unicornios |
| Test | POST /unicorn | POST | /unicorn | Permitir | Test puede publicar en unicornios |
| Developer | DELETE /unicorn | DELETE | /unicorn | Denegar | Manager no puede eliminar un unicornio |
Esto nos permite buscar eficientemente permisos para cada rol usando una simple consulta de DynamoDB.
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Descripción: Aplicación de BBQ conectado Servicio de inquilinos
Parámetros:
ApplicationName:
Tipo: String
Descripción: Nombre de la aplicación propietaria
UserManagementStackName:
Tipo: String
Descripción: El nombre de la pila que contiene la parte de gestión de usuarios, por ejemplo el Cognito UserPool
Globals:
Función:
Tiempo de espera: 30
Tamaño de memoria: 2048
Arquitecturas:
- arm64
Tiempo de ejecución: python3.12
Recursos:
PermissionsTable:
Tipo: AWS::DynamoDB::Table
Propiedades:
Nombre de la tabla:
Fn::Sub: ${ApplicationName}-pdp-role-permission-map
Modo de facturación: PAY_PER_REQUEST
Definiciones de atributos:
- Nombre de atributo: PK
Tipo de atributo: S
- Nombre de atributo: SK
Tipo de atributo: S
Esquema de clave:
- Nombre de atributo: PK
Tipo de clave: HASH
- Nombre de atributo: SK
Tipo de clave: RANGE
LambdaPDPFunction:
Tipo: AWS::Serverless::Function
Propiedades:
CodeUri: Lambda/AuthZ
Handler: authz.handler
Políticas:
- DynamoDBReadPolicy:
Tabla: !Ref PermissionsTable
Entorno:
Variables:
JWKS_URL:
Fn::ImportValue: !Sub ${UserManagementStackName}:jwks-url
AUDIENCE:
Fn::ImportValue: !Sub ${UserManagementStackName}:app-audience
PERMISSIONS_TABLE:
!Ref PermissionsTable
Salidas:
PDPLambdaArn:
Valor: !GetAtt LambdaPDPFunction.Arn
Descripción: El ARN de la función Lambda del PDP
Exportar:
Nombre: !Sub ${AWS::StackName}:pdp-lambda-arn
PDPLambdaName:
Valor: !Ref LambdaPDPFunction
Descripción: El Nombre de la función Lambda del PDP
Exportar:
Nombre: !Sub ${AWS::StackName}:pdp-lambda-nameLógica de autorización de roles
El PDP Lambda decodificará el JWT, recuperará el rol de la reclamación cognito:groups y consultará la tabla DynamoDB para verificar si el rol tiene permiso para acceder al recurso solicitado.
import os
import json
import jwt
import boto3
from jwt import PyJWKClient
from botocore.exceptions import ClientError
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table(os.environ["PERMISSIONS_TABLE"])
JWKS_URL = os.environ["JWKS_URL"]
AUDIENCE = os.environ["AUDIENCE"]
def handler(event, context):
data = event
jwt_token = data["jwt_token"]
resource = data["resource"]
action = data["action"]
return check_authorization(jwt_token, action, resource)
def check_authorization(jwt_token, action, resource):
try:
jwks_client = PyJWKClient(JWKS_URL)
signing_key = jwks_client.get_signing_key_from_jwt(jwt_token)
decoded_token = jwt.decode(
jwt_token,
signing_key.key,
algorithms=["RS256"],
audience=AUDIENCE,
)
role = (
decoded_token["cognito:groups"][0]
if "cognito:groups" in decoded_token
else None
)
if not role:
raise Exception("No autorizado: Rol no encontrado en el token")
if validate_permission(role, action, resource):
response_body = generate_access(
decoded_token["sub"], "Permitir", action, resource
)
return {
"statusCode": 200,
"body": json.dumps(response_body),
"encabezados": {"Content-Type": "application/json"},
}
except Exception as e:
print(f"Error de autorización: {str(e)}")
response_body = generate_access(decoded_token["sub"], "Denegar", action, resource)
return {
"statusCode": 403,
"body": json.dumps(response_body),
"encabezados": {"Content-Type": "application/json"},
}
def validate_permission(role, action, resource):
print(f"validate_permission Rol: {role}, Acción: {action}, Recurso: {resource}")
try:
response = table.query(
KeyConditionExpression="PK = :role AND SK = :endpoint",
ExpressionAttributeValues={
":role": role,
":endpoint": f"{action} {resource}",
},
)
if response["Items"] and response["Items"][0]["Efecto"] == "Permitir":
return True
else:
return False
except ClientError as e:
print(f"Error consultando DynamoDB: {e}")
return False
def generate_access(principal, effect, action, resource):
auth_response = {
"principalId": principal,
"effect": effect,
"action": action,
"resource": resource,
}
return auth_response
Desplegar API y PEP
Ahora podemos desplegar nuestra API y PEP, Autorizador Lambda.
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Descripción: Crea la API para la gestión de certificados de autoservicio
Parámetros:
ApplicationName:
Tipo: String
Descripción: Nombre de la aplicación propietaria
UserManagementStackName:
Tipo: String
Descripción: El nombre de la pila que contiene la parte de gestión de usuarios, por ejemplo el Cognito UserPool
PDPStackName:
Tipo: String
Descripción: El nombre de la pila que contiene el servicio PDP
Globals:
Función:
Tiempo de espera: 30
Tamaño de memoria: 2048
Tiempo de ejecución: python3.12
Recursos:
LambdaGetUnicorn:
Tipo: AWS::Serverless::Function
Propiedades:
CodeUri: Lambda/API/GetUnicorn
Handler: handler.handler
Eventos:
GetUnicorns:
Tipo: Api
Propiedades:
Ruta: /unicorn
Método: get
RestApiId: !Ref UnicornApi
UnicornApi:
Tipo: AWS::Serverless::Api
Propiedades:
Descripción: API para crear y gestionar Unicornios
Nombre: !Sub ${ApplicationName}-api
Nombre de etapa: prod
Versión de OpenApi: '3.0.1'
Siempre desplegar: verdadero
Configuración de extremo: REGIONAL
Cors:
AllowMethods: "'GET,PUT,POST,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
Auth:
AddDefaultAuthorizerToCorsPreflight: false
Authorizers:
LambdaRequestAuthorizer:
FunctionArn: !GetAtt LambdaApiAuthorizer.Arn
FunctionPayloadType: REQUEST
Identidad:
Encabezados:
- Autorización
ReauthorizeEvery: 600
Autorizador predeterminado: LambdaRequestAuthorizer
LambdaApiAuthorizer:
Tipo: AWS::Serverless::Function
Propiedades:
CodeUri: Lambda/Authorizer/
Handler: auth.handler
Políticas:
- LambdaInvokePolicy:
FunctionName:
Fn::ImportValue: !Sub ${PDPStackName}:pdp-lambda-name
Entorno:
Variables:
JWKS_URL:
Fn::ImportValue: !Sub ${UserManagementStackName}:jwks-url
AUDIENCE:
Fn::ImportValue: !Sub ${UserManagementStackName}:app-audience
PDP_AUTHZ_ENDPOINT:
Fn::ImportValue: !Sub ${PDPStackName}:pdp-lambda-name
Establecemos nuestro PEP como el autorizador predeterminado para que se agregue a cada recurso y método. Para reducir el número de llamadas a nuestro PDP, se utiliza el caché de autorización en API Gateway con un TTL de 600 segundos.
Lógica de autorización PEP
El Autorizador Lambda PEP decodificará el JWT, verificará su validez y luego llamará al PDP para una decisión final de permiso.
import os
import json
import jwt
import boto3
from jwt import PyJWKClient
lambda_client = boto3.client("lambda")
def handler(event, context):
print(f"Evento: {json.dumps(event)}")
token = event["headers"].get("autorización", "")
path = event["path"]
method = event["httpMethod"]
if not token:
raise Exception("No autorizado")
token = token.replace("Portador ", "")
decoded_token = None
try:
jwks_url = os.environ["JWKS_URL"]
jwks_client = PyJWKClient(jwks_url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
decoded_token = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
audience=os.environ["AUDIENCE"],
)
data = {
"jwt_token": token,
"recurso": path,
"acción": method,
}
response = lambda_client.invoke(
FunctionName=os.environ["PDP_AUTHZ_ENDPOINT"],
InvocationType="RequestResponse",
Payload=json.dumps(data),
)
response_payload = json.loads(response["Payload"].read())
body = json.loads(response_payload["body"])
effect = body["effect"]
return generate_policy(
decoded_token["sub"], effect, event["methodArn"], decoded_token
)
except Exception as e:
print(f"Error de autorización: {str(e)}")
return generate_policy(
decoded_token["sub"], "Denegar", event["methodArn"], decoded_token
)
def generate_policy(principal_id, effect, resource):
auth_response = {
"principalId": principal_id,
"policyDocument": {
"Versión": "2012-10-17",
"Declaración": [
{"Acción": "execute-api:Invoke", "Efecto": effect, "Recurso": resource}
],
},
}
return auth_response
Importancia del caché
El caché es importante para optimizar nuestro flujo de autorización. Al reducir las llamadas al PDP y acelerar la toma de decisiones, el caché ayuda a mejorar el rendimiento general, la escalabilidad y la eficiencia de costos de nuestra aplicación.
Reducción de la latencia: Al almacenar en caché los datos de roles y permisos, el PEP evita llamadas repetidas a nuestro PDP, lo que lleva a tiempos de respuesta más rápidos y menor latencia para cada solicitud. Disminución de la carga del PDP: El caché minimiza el número de llamadas hechas a nuestro PDP, reduciendo el riesgo de alcanzar límites de tasa o limitación. Mejora de la escalabilidad: Con menos solicitudes llegando a nuestro PDP, nuestra arquitectura puede escalar de manera más eficiente. Reducción de costos: El caché reduce la necesidad de invocaciones repetidas del PDP, lo que reduce directamente los costos de invocación de Lambda.
Resumen y conclusión
Implementar PEP y PDP en nuestro flujo de autorización ofrece una forma muy escalable, flexible y segura de controlar el acceso a los recursos. Al aprovechar AWS Lambda y API Gateway, podemos construir un sistema de autorización sin servidor que separa las preocupaciones de autenticación y autorización, se escala según la demanda y simplifica la gestión de políticas.
Con la adición del Control de Acceso Basado en Roles y DynamoDB para almacenar permisos, combinado con el caché en memoria para un rendimiento mejorado, podemos crear una solución de autorización que se ajuste tanto a las necesidades actuales como futuras.
Entender la diferencia entre los Tokens de ID y los Tokens de Acceso asegura que nuestro sistema use cada uno apropiadamente, ayudándonos a construir un sistema de autorización más seguro y eficiente.
¡Feliz codificación y manténgase seguro!
Código fuente
Toda la configuración, con instrucciones detalladas de despliegue y todo el código, se puede encontrar en Serverless Handbook PEP y PDP
Palabras finales
¡No olvide seguirme en LinkedIn y X para más contenido, y leer el resto de mis Blogs
Como dice Werner! ¡Ahora ve a construir!