PEP (Punto de Aplicación de Políticas)

Autorización Security Notes Jan 6, 2025 JAVASCRIPT

Definition

Imagina un edificio elegante con un guardia de seguridad en la puerta. El guardia no decide quién tiene permitido entrar - ese es el trabajo de gerencia. Pero cuando te presentas, el guardia es quien realmente verifica tus credenciales, llama a gerencia si es necesario, y físicamente bloquea o permite tu entrada. Ese guardia es el Policy Enforcement Point (PEP) - el músculo de tu sistema de autorización, el componente que realmente dice “puedes pasar” o “acceso denegado.”

El PEP se sitúa entre usuarios y recursos protegidos, interceptando cada solicitud de acceso. Cuando alguien intenta eliminar un documento, leer un archivo, o llamar a un endpoint de API, el PEP interviene primero. Recopila el contexto relevante (quién está pidiendo, qué quieren, qué recurso están apuntando), pregunta al PDP (Policy Decision Point) si esto debería ser permitido, y luego hace cumplir esa decisión. Si el PDP dice denegar, el PEP bloquea la solicitud. Si el PDP dice permitir, el PEP la deja pasar. El PEP no piensa - actúa.

Lo que hace cruciales a los PEPs es su ubicación. Deben ser puntos de control inevitables por los que cada solicitud debe pasar. Si hay alguna forma de llegar a un recurso protegido sin pasar por el PEP, todo tu sistema de autorización tiene una vulnerabilidad de bypass. Es por esto que los API gateways, reverse proxies, y middleware son implementaciones comunes de PEP - están posicionados para que ninguna solicitud pueda escabullirse alrededor de ellos. Un PDP sin un PEP son solo reglas en papel. Un PEP sin un PDP es solo un guardia sin instrucciones. Juntos, forman control de acceso completo.

Example

Los PEPs son los puntos de control que hacen cumplir decisiones de seguridad en sistemas modernos:

API Gateway como PEP: Cada solicitud a la API de tu empresa golpea Kong, Apigee, o AWS API Gateway primero. El gateway extrae el token JWT, determina qué endpoint está siendo llamado, consulta al servicio de autorización (PDP), y o reenvía la solicitud al backend o retorna 403 Forbidden. El backend nunca ve solicitudes no autorizadas.

Admission Controllers de Kubernetes: Cuando alguien intenta desplegar un pod en Kubernetes, los admission controllers actúan como PEPs. Interceptan la solicitud de despliegue, verifican si viola alguna política (límites de recursos, fuentes de imagen, contextos de seguridad), y o permiten el despliegue o lo rechazan con una explicación.

Row-Level Security en Base de Datos: Las políticas RLS de PostgreSQL convierten a la base de datos en un PEP. Cuando un usuario consulta historiales de pacientes, PostgreSQL intercepta la consulta y la modifica para retornar solo filas que ese usuario está autorizado a ver. La aplicación no necesita filtrar - la base de datos hace cumplir el acceso a nivel de consulta.

Web Application Firewall (WAF): Cloudflare o AWS WAF actúa como PEP para tráfico web. Intercepta cada solicitud HTTP, la evalúa contra reglas de seguridad (patrones de SQL injection, rate limits, restricciones geográficas), y o permite que la solicitud pase o la bloquea. Tu servidor de aplicación nunca procesa solicitudes maliciosas.

Permisos del Sistema de Archivos: Cuando un proceso intenta leer /etc/shadow, el kernel del sistema operativo actúa como PEP. Verifica el UID efectivo del proceso contra los permisos del archivo y o permite la lectura o retorna “Permiso denegado.” Cada operación de archivo pasa por este enforcement a nivel de kernel.

Analogía

El Guardia de Seguridad en la Puerta: Un guardia de seguridad no escribe la lista de invitados (eso es gerencia/PDP), pero son ellos quienes verifican identificaciones, comprueban nombres contra la lista, y físicamente bloquean la entrada a personas no autorizadas. Si el guardia se va, cualquiera puede entrar - por eso los PEPs deben estar siempre activos e inevitables.

El Portero en el Club: El dueño del club establece políticas (código de vestimenta, lista VIP, límites de capacidad). El portero (PEP) las hace cumplir - verificando identificaciones, mirando atuendos, contando cabezas. El portero podría llamar por radio al gerente para casos especiales (llamando al PDP), pero son ellos los que están físicamente en la puerta asegurándose de que las reglas se cumplan.

El Operador de Peaje: Las autoridades de autopistas deciden precios de peaje y quién obtiene descuentos (PDP). La caseta de peaje (PEP) es donde realmente paras, pagas, y te dejan pasar - o te deniegan si tu pago falla. No hay forma de usar la autopista sin pasar por una caseta de peaje, igual que no debería haber forma de acceder a recursos sin pasar por un PEP.

El Punto de Control de Seguridad del Aeropuerto: Las políticas de TSA las establecen directrices federales (PDP). El punto de control con máquinas de rayos X y agentes (PEP) es donde esas políticas se hacen cumplir. Cada pasajero debe pasar - no hay forma de llegar a la puerta que bypass seguridad. Si TSA dice no líquidos de más de 100ml, el punto de control es donde te confiscan tu botella de agua.

Code Example


// Policy Enforcement Point implementation
class PolicyEnforcementPoint {
  constructor(pdp) {
    this.pdp = pdp // Policy Decision Point
    this.obligationHandlers = new Map()
  }

  // Express middleware as PEP
  middleware() {
    return async (req, res, next) => {
      try {
        // Extract authorization context
        const authzRequest = this.buildAuthzRequest(req)

        // Query PDP for decision
        const decision = await this.pdp.authorize(authzRequest)

        if (decision.decision === 'DENY') {
          return res.status(403).json({
            error: 'Forbidden',
            message: decision.reason || 'Access denied'
          })
        }

        if (decision.decision === 'PERMIT') {
          // Enforce obligations before allowing access
          await this.enforceObligations(decision.obligations)

          // Store decision context for downstream handlers
          req.authzContext = {
            decision,
            obligations: decision.obligations,
            advice: decision.advice
          }

          return next()
        }

        // INDETERMINATE or error - fail closed
        return res.status(403).json({
          error: 'Forbidden',
          message: 'Authorization could not be determined'
        })

      } catch (error) {
        // Fail closed on error
        console.error('PEP error:', error)
        return res.status(500).json({
          error: 'Internal Server Error',
          message: 'Authorization check failed'
        })
      }
    }
  }

  buildAuthzRequest(req) {
    return {
      subject: {
        id: req.user?.id,
        attributes: {
          roles: req.user?.roles || [],
          department: req.user?.department,
          ...req.user
        }
      },
      resource: {
        id: req.params.id || req.path,
        type: this.getResourceType(req.path),
        attributes: {
          path: req.path,
          method: req.method
        }
      },
      action: this.getAction(req.method),
      environment: {
        time: new Date(),
        ipAddress: req.ip,
        userAgent: req.headers['user-agent'],
        protocol: req.protocol,
        sourceNetwork: this.getNetworkZone(req.ip)
      }
    }
  }

  getAction(method) {
    const actionMap = {
      'GET': 'READ',
      'POST': 'CREATE',
      'PUT': 'UPDATE',
      'PATCH': 'UPDATE',
      'DELETE': 'DELETE'
    }
    return actionMap[method] || method
  }

  getResourceType(path) {
    // Extract resource type from path
    const match = path.match(/^/api/([^/]+)/)
    return match ? match[1] : 'unknown'
  }

  async enforceObligations(obligations = []) {
    for (const obligation of obligations) {
      const handler = this.obligationHandlers.get(obligation.type)

      if (!handler) {
        throw new Error(`No handler for obligation: ${obligation.type}`)
      }

      await handler(obligation)
    }
  }

  registerObligationHandler(type, handler) {
    this.obligationHandlers.set(type, handler)
  }
}

// Setup PEP with PDP
const pdp = new PolicyDecisionPoint(policyStore)
const pep = new PolicyEnforcementPoint(pdp)

// Register obligation handlers
pep.registerObligationHandler('audit-log', async (obligation) => {
  await auditLog.log({
    action: obligation.action,
    resource: obligation.resource,
    timestamp: new Date()
  })
})

pep.registerObligationHandler('notify-owner', async (obligation) => {
  await notificationService.send({
    to: obligation.ownerId,
    message: `Your resource ${obligation.resourceId} was accessed`
  })
})

pep.registerObligationHandler('require-mfa', async (obligation) => {
  if (!obligation.user.mfaVerified) {
    throw new Error('MFA verification required')
  }
})

// Apply PEP to routes
app.use('/api/documents', pep.middleware())
app.use('/api/sensitive', pep.middleware())

// Alternative: Resource-specific PEP
class ResourcePEP {
  constructor(pdp, resourceType) {
    this.pdp = pdp
    this.resourceType = resourceType
  }

  async checkAccess(userId, resourceId, action) {
    const decision = await this.pdp.authorize({
      subject: { id: userId },
      resource: {
        id: resourceId,
        type: this.resourceType
      },
      action,
      environment: { time: new Date() }
    })

    if (decision.decision !== 'PERMIT') {
      throw new ForbiddenError(decision.reason)
    }

    return decision
  }
}

// Usage in business logic
const documentPEP = new ResourcePEP(pdp, 'document')

async function deleteDocument(userId, documentId) {
  // PEP check before business logic
  await documentPEP.checkAccess(userId, documentId, 'DELETE')

  // Proceed with deletion
  await db.documents.delete(documentId)
}

Notas de Seguridad

SECURITY NOTES

CRÍTICO: PEP es la última línea de defensa. Vulnerabilidades: (1) Bypass de PEP - …

Configuración y Validación:

  • si cualquier ruta de código omite PEP, la autorización falla completamente, (2) Errores de caché de decisión - servir PERMIT en caché a usuario incorrecto, (3) Aplicación incompleta - verificar autorización pero no hacer cumplir obligaciones, (4) Condiciones de carrera asíncronas - recurso accedido antes de que PEP complete, (5) Bypass por manejo de errores - excepciones que omiten verificaciones de PEP, (6) Inconsistencia de múltiples PEPs - diferente aplicación en diferentes capas.
  • Mejores prácticas: Centralizar aplicación (PEP único en punto de entrada), nunca dejar que lógica de negocio omita PEP, fallar cerrado (denegar en timeout/error de PDP), hacer cumplir TODAS las obligaciones antes de conceder acceso (no después), validar respuestas de PDP (no confiar ciegamente), implementar timeout para llamadas a PDP, registrar todas las decisiones de aplicación, manejar operaciones asíncronas cuidadosamente, no filtrar información en mensajes de denegación, implementar lógica de reintento para fallos transitorios de PDP, monitorear latencia PEP-PDP, probar que todas las rutas de código incluyen PEP, separar autenticación de autorización claramente.
  • Recordar: PEP sin PDP es inútil, PDP sin PEP es impotente.

Monitoreo y Protección:

    • si cualquier ruta de código omite PEP, la autorización falla completamente, (2) Errores de caché de decisión - servir PERMIT en caché a usuario incorrecto, (3) Aplicación incompleta - verificar autorización pero no hacer cumplir obligaciones, (4) Condiciones de carrera asíncronas - recurso accedido antes de que PEP complete, (5) Bypass por manejo de errores - excepciones que omiten verificaciones de PEP, (6) Inconsistencia de múltiples PEPs - diferente aplicación en diferentes capas.
    • Mejores prácticas: Centralizar aplicación (PEP único en punto de entrada), nunca dejar que lógica de negocio omita PEP, fallar cerrado (denegar en timeout/error de PDP), hacer cumplir TODAS las obligaciones antes de conceder acceso (no después), validar respuestas de PDP (no confiar ciegamente), implementar timeout para llamadas a PDP, registrar todas las decisiones de aplicación, manejar operaciones asíncronas cuidadosamente, no filtrar información en mensajes de denegación, implementar lógica de reintento para fallos transitorios de PDP, monitorear latencia PEP-PDP, probar que todas las rutas de código incluyen PEP, separar autenticación de autorización claramente.
    • Recordar: PEP sin PDP es inútil, PDP sin PEP es impotente.