Enmilocalfunciona

Thoughts, stories and ideas.

Policy as Code con Open Policy Agent - Introducción (Parte I)

Publicado por Alejandro Nieto el

PolicyAsCodeDevOpsSeguridad

Cuando queremos gobernar el comportamiento de nuestro software (o de nuestro equipo) utilizamos un conjunto de reglas definidas. A este conjunto de reglas se les llaman políticas.

alt

¿Y por qué no manejar esas políticas como código? Ya lo hacemos en infinidad de ámbitos como IaC (infraestructura como código) o ICaC (integración continua como código) así que las políticas de seguridad se pueden sumar a ello. Las ventajas que nos proporciona este enfoque son las siguientes:

  • Integración con el resto de nuestro ecosistema
  • Automatización
  • Testing
  • Control de versiones

Las herramientas disponibles en el mercado además proporcionan lo necesario:

  • CLI para llevar a cabo el testing antes de llevar a producción las políticas.
  • Lenguaje, cada herramienta propone un lenguaje para llevar a cabo el desarrollo de políticas, en su mayoría declarativos.
Open Policy Agent

Open Policy Agent (OPA de ahora en adelante) es un motor de políticas que proporciona un lenguaje declarativo de alto nivel para definir y hacer cumplir políticas con un gran abanico de integraciones con el resto de sistemas, como herramientas de aprovisionamiento de infraestructura como Terraform u orquestadores como Kubernetes.

Como ya se ha comentado, OPA utiliza un lenguaje declarativo, en el que no importa cómo llegamos al resultado, lo que importa es el resultado en sí mismo. La finalidad de OPA es dar respuesta a preguntas como las siguientes:

  • ¿Puedo crear máquinas con 4GB de memoria?
  • ¿Puedo crear recursos en Kubernetes sin límites de consumo?"
  • ¿Puedo escribir en esta base de datos?

La finalidad es denegar o aceptar la ejecución de determinadas acciones sobre nuestro stack tecnológico.

¿Cómo funciona OPA?

OPA permite desacoplar la política del software destinado a negocio. Cuando el resto de software necesita tomar decisiones de este tipo, le realiza peticiones a OPA proporcionándole los datos a evaluar.
Para que OPA tome una decisión, son necesarios tres factores en el proceso de toma de decisión:

  • OPA será capaz de evaluar si está permitido o denegado realizar acciones con la información proporcionada (data). Ésta debe ser proporcionada en formato JSON.
  • Query Input: Define la pregunta sobre la que OPA tiene que decidir y que inicia el proceso de toma de decisión. También debe ser proporcionada en formato JSON.
  • Policy: Conjunto de reglas definidas. OPA interpreta las reglas definidas y basándose en los datos proporcionados (data) y la pregunta a resolver (query input), genera una respuesta (una decisión). Las políticas están escritas utilizando  Rego, lenguaje nativo de OPA para definición de consultas.

Para utilizar OPA en un entorno productivo es posible desplegarlo como servidor tradicional en una máquina, o bien en el caso de Kubernetes es posible desplegarlo utilizando el patrón sidecar. OPA expondrá un API Rest que será consumida tanto por servicios ya existentes, como por nuestros desarrollos y les devolverá una respuesta en formato JSON sobre HTTP.

ops-service
Usando OPA

La forma más fácil de probar las primeras políticas que definamos es mediante el interfaz de comandos. Con opa eval es posible evaluar políticas sin necesidad de tener OPA en modo servidor. Otra alternativa es jugar con el editor online de OPA: https://play.openpolicyagent.org

Un ejemplo bastante sencillo es definir una serie de datos, en este caso serán superhéroes con sus poderes y el universo al que pertenecen:

{
  "heroes": [
      {"id": "superman", "powers": ["flying", "strength"], "companies": ["c2"]},
      {"id": "batman", "powers": ["money", "intelligence","funny"], "companies": ["c2"]},
      {"id": "deadpool", "powers": ["immortality","funny"], "companies": ["c1"]}
  ],
  "companies": [
      {"id": "c1", "company": "marvel"},
      {"id": "c2", "company": "dc"}
  ]
}

A continuación, la política definida establece que por defecto la petición es denegada a menos que no se produzca ninguna violación de los términos establecidos.

En este caso se ha establecido que los héroes DC no pueden ser graciosos:

package example

default allow = false                               # unless otherwise defined, allow is false

allow = true {                                      # allow is true if...  
    count(violation) == 0                           # there are zero violations.
}


violation[hero.id] {                              # a hero is in the violation set if...  
    some hero
    dc_hero[hero]                                 # it exists in the 'dc_universe' set and...
    hero.powers[_] == "funny"                     # it contains the funny powers.
}


dc_hero[hero] {                             # a hero exists in the dc_universe set if...  
    some i
    hero := input.heroes[_]                      # it exists in the input.heroes collection and...
    hero.companies[_] == input.companies[i].id   # it references a company in the input.companies collection and...
    input.companies[i].company == "dc"           # the company is dc
}

Para evaluar la política:

opa eval -i input.json -d policy.rego 'data.example'  

O bien, pulsando el botón Evaluate de la herramienta online antes proporcionada.

En la ejecución se ve que Batman está violando los términos:

{
  "result": [
    {
      "expressions": [
        {
          "value": {
            "allow": false,
            "dc_hero": [
...
            ],
            "violation": [
              "batman"
            ]
          },

Tal como se definió en el input, Batman tenía el poder "funny" y la política está denegando esta posibilidad. Otra política a aplicar podría ser que Batman pudiera "escribir" o "leer" sobre algún recurso de nuestro stack y cualquier otra política definida lo denegara.

Podéis encontrar estos ejemplos y muchos más en mi repositorio git.

En los siguientes capítulo de la serie se entrará en profundidad en la integración de OPA Gatekeeper con Kubernetes o en cómo denegar la modificación de infraestructura basándonos en un sistema de puntos integrándonos con Terraform.

Si te ha gustado, ¡síguenos en Twitter para estar al día de nuevas entregas!