Skip to main content

Usar Rego como lenguaje de políticas de propósito general

Escrito por
Headshot of Dickson Boateng

Dickson Boateng

feature iac drift blue

3 de junio de 2022

0 minutos de lectura

Las políticas desempeñan un papel fundamental en todas las organizaciones, pero pueden significar muchas cosas distintas según el contexto. Para nuestros fines, una política se refiere a los principios o ideas que una organización usa para tomar decisiones.

En esta publicación, hablaremos sobre Open Policy Agent (OPA) y su lenguaje de reglas, Rego, y destacaremos cómo podemos usarlos para escribir una política sencilla para un microservicio de nómina.

¿Qué es una política?

En los sistemas de software, las políticas son las reglas que controlan cómo funciona un sistema. Las computadoras y las personas suelen usar políticas para responder preguntas como:

  • ¿Tiene permitido el usuario A modificar la configuración del servicio X?

  • ¿En qué dominio deberíamos instalar la aplicación X?

  • ¿Qué operaciones están en la región geográfica incorrecta?

La forma en que definimos y aplicamos una política depende de varios factores, como la tecnología a la que se aplica y la claridad de la política. En algunos casos, las políticas son conocimientos no documentados. Por eso, si queremos modificar un sistema o comprender cómo debería funcionar, tenemos que consultar a otra persona. Después de un tiempo, documentamos las respuestas, pero esos documentos terminan quedando desactualizados.

Otra opción es incorporar las políticas directamente en los sistemas de software. Lamentablemente, las políticas cambian con el tiempo. Además de las actualizaciones casi constantes y la necesidad de volver a capacitarse, modificar políticas codificadas requiere una revisión integral y exhaustiva del código para entender qué hay que cambiar. Codificar las políticas directamente hace que sean menos accesibles y más difíciles de modificar.

Presentamos Open Policy Agent

Los enfoques tradicionales para administrar políticas ofrecen pocas garantías de cumplimiento y son costosos de mantener. Una solución moderna a este problema es Open Policy Agent (OPA, se pronuncia “OH-pa”).

OPA es un motor de políticas de código abierto y de propósito general que se usa para definir políticas en distintos sistemas, incluidos microservicios, puertas de enlace de API, pipelines de CI/CD y Kubernetes. Permite escribir políticas como código y luego usarlas como parte del proceso de toma de decisiones.

Con OPA, definimos reglas que controlan el comportamiento de un sistema. Estas reglas sirven para responder preguntas como:

  • ¿Puede el usuario A realizar una solicitud GET a este servicio?

  • ¿Qué registros tiene permitido ver el usuario B?

  • ¿A qué servidor deberíamos implementar la aplicación X?

Cuando solicitamos una decisión de política, OPA analiza las reglas y los datos que proporcionamos para generar una respuesta, que aplica el servicio que solicitó la decisión. En otras palabras, OPA se encarga de tomar una decisión de política, mientras que los servicios integrados con OPA se encargan de implementarla. El diagrama siguiente muestra el flujo de trabajo general de OPA:

Diagrama que muestra una solicitud de usuario que llega a un servicio, el cual envía una consulta de política JSON a un motor OPA y recibe una decisión de política JSON.

Para comprender todo el flujo de trabajo de OPA, veamos cómo gestiona las solicitudes en un caso de uso sencillo de autorización de API, en el que definimos reglas para permitir o denegar el acceso a determinados servicios de API. Cuando un servicio recibe una solicitud de API, envía una consulta a OPA. Luego, OPA compara la consulta con las políticas y los datos existentes para responder con una decisión de “permitir” o “denegar”. Por último, el servicio aplica la decisión de OPA al aprobar o rechazar la solicitud de API.

El lenguaje de políticas de OPA: Rego

Escribimos políticas de OPA en un lenguaje declarativo de alto nivel llamado Rego (se pronuncia “RAY-go”). Rego nos permite escribir decisiones de políticas que se escalan fácilmente para distintos tipos de servicios. Usamos Rego para evaluar los datos proporcionados como entrada y tomar las decisiones de políticas correspondientes. Recuerda que Rego no es un lenguaje de programación para crear programas de software, sino un lenguaje declarativo para escribir reglas, similar a un lenguaje de consulta como SQL.

Rego es un lenguaje de políticas de propósito general, lo que significa que funciona con distintos sistemas. Solo reconoce datos JSON, así que podemos escribir una política para cualquier servicio, siempre que los datos que necesitamos estén en formato JSON. Esto nos permite usar Rego para escribir políticas que abarquen distintos sistemas.

Escribe tu primera política de OPA

Ahora, escribamos una política sencilla con Rego y probémosla en Rego Playground, una plataforma interactiva en línea. La política que escribiremos determina qué usuarios pueden acceder a la información salarial en un microservicio de nómina.

Para comenzar, elimina todo el código existente en el panel principal de Rego Playground y reemplázalo por lo siguiente:

package play 
default allow = false
# Users can only view their salary info
allow = true { 
    input.method = "GET" 
    input.path = ["getSalary", user_id] 
    input.user = user_id 
}

Ahora, revisemos el fragmento de código anterior para entender qué sucede:

  • La primera línea de nuestra política es el nombre del paquete. Todas las políticas de Rego tienen un nombre de paquete que define su alcance.

  • La línea siguiente indica que el valor de allow es false de forma predeterminada.

  • El símbolo de numeral (#) indica el inicio de un comentario y brinda información explicativa sencilla sobre el código escrito.

  • allow = true significa que allow tendrá el valor true si todas las expresiones entre corchetes son true.

  • Por último, podemos interpretar las expresiones entre corchetes de la siguiente manera: se permitirán las solicitudes si el método de entrada es GET, la ruta es /getSalary/user_id y el usuario es user_id. Ten en cuenta que la variable input representa los datos JSON que proporcionamos a Rego.

Rego Playground nos permite evaluar el código y comprobar que la política funcione según lo previsto. Por eso, en el panel de entrada podemos simular una solicitud agregando el siguiente código:

{ 
    "method": "GET", 
    "path": ["getSalary","John"], 
    "user": "John" 
}

Ahora, veamos cómo respondería OPA a la solicitud anterior. Para hacerlo, haz clic en el botón Evaluate. El panel de resultados debería mostrar algo como lo siguiente:

{
    "allow": true 
}

Esta es una captura de Rego Playground después de completar todos los pasos:

La interfaz de Rego Playground muestra una política que permite a los usuarios ver su propio salario, con una solicitud GET para John que devuelve «allow»: true.

Probemos nuestra política otra vez cambiando el user de la solicitud por Jane. Esto significa que un usuario intenta ver la información salarial de otra persona. Al hacer clic en Evaluate, vemos el siguiente resultado esperado:

{
    "allow": false
}

A continuación, actualizaremos la política para que el personal del departamento de finanzas pueda ver la información salarial de todos los usuarios. Para hacerlo, agregaremos el siguiente código a la política que definimos antes:

#finance department workers can view every user's salary info
allow = true { 
    input.method = "GET" 
    input.path = ["getSalary", user_id] 
    finance[input.user] 
} 
finance = {"Ruth","Josh","Vivian"}

En el nuevo código de la política, definimos un objeto finance y agregamos los nombres de todos los empleados que trabajan en el departamento de finanzas.

Probemos la política asignando el mismo nombre a user y user_id (por ejemplo, Joe). La política debería devolver true. Ahora, cambia user por John (un empleado del departamento de finanzas) y ejecuta la política. De nuevo, debería devolver true. Por último, cambia user por un nombre que no aparezca en el objeto finance (por ejemplo, Jane). Esta vez, la política debería devolver false.

Unamos todo

Al combinar todos los fragmentos de código, obtenemos nuestra nueva política:

package play 
default allow = false
# Users should have access to view their salary 
allow = true { 
    input.method = "GET" 
    input.path = ["getSalary", user_id] 
    input.user = user_id 
}
allow = true { 
    input.method = "GET" 
    input.path = ["getSalary", user_id] 
    finance[input.user] 
} 
finance = {"John","Mary","Peter","Vivian"}

El futuro de la personalización de políticas

Ahora que sabes cómo escribir políticas nuevas con OPA y Rego, debes mantenerlas y analizarlas para asegurarte de que no tengan vulnerabilidades. Con Snyk Infrastructure as Code (Snyk IaC), que aprovecha OPA para analizar políticas, puedes agregar tus políticas nuevas y existentes a los análisis con solo unos comandos. Consulta la documentación de Snyk IaC y nuestro artículo Cómo desarrollar reglas de IaC personalizadas con Snyk para obtener más información.

Para comenzar, crea tu cuenta gratuita de Snyk y empieza a encontrar y corregir errores de configuración de IaC con comprobaciones de seguridad integradas, protecciones de políticas y recomendaciones de corrección fáciles de seguir para desarrolladores, directamente en tu flujo de trabajo.

Protege la infraestructura desde el origen

Snyk automatiza la seguridad y el cumplimiento de IaC en los flujos de trabajo, y detecta recursos con desviaciones de configuración y recursos faltantes.