Vault: Centralizar los secretos de un modo seguro

En este post, vengo a presentaros una herramienta que ha causado mucha expectación que ayuda a complementar el movimiento DevOps y Seguridad haciendo que todos los secretos no estén en el servicio si no en un sitio centralizado. Esta herramienta, se llama Vault y es de la empresa HashiCorp. Esta empresa, tiene varias herramientas muy interesantes como; Consul, Packer, Terraform.. Recomiendo echarles un vistazo.

No quiero meterme mucho en la teoría ya que hay varios posts que explican mejor (abajo os dejo algunos de referencia). Pero básicamente es un servicio que alberga secretos portegidos por PGP que permiten ser consultados mediante una API del modo que no hay que declararlos en el propio servicio.

En este ejemplo, vamos a montarlo sobre docker (oh que sorpresa!). Para esto como siempre utilizaremos: docker-compose y traefik.

Docker-compose

vim docker-compose.yml
version: '3.5'
services:
  vault:
    image: vault
    restart: always
    container_name: vault
    volumes:
      - file:/vault/file
      - logs:/vault/logs
      - ./config/policies:/vault/policies
    cap_add:
      - IPC_LOCK
    environment:
      VAULT_LOCAL_CONFIG: '{"backend": {"file": {"path": "/vault/file"}}, "listener": {"tcp": {"address": "0.0.0.0:8200", "tls_disable": 1}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h"}'
      VAULT_ADDR: http://127.0.0.1:8200
    networks:
      - traefik
    command: server
    labels:
      - "traefik.backend=vault"
      - "traefik.frontend.rule=Host:vaultapi.example.com"
      - "traefik.docker.network=traefik"
      - "traefik.port=8200"

  vault-ui:
    image: djenriquez/vault-ui
    restart: always
    container_name: vault-ui
    links:
      - vault
    volumes:
      - ui:/app
    environment:
      - NODE_TLS_REJECT_UNAUTHORIZED=0
      - VAULT_URL_DEFAULT=http://vault:8200
      - VAULT_AUTH_DEFAULT=USERNAMEPASSWORD
    networks:
      - traefik
    labels:
      - "traefik.backend=vault_ui"
      - "traefik.frontend.rule=Host:vault.example.com"
      - "traefik.docker.network=traefik"
      - "traefik.port=8000"

volumes:
  file:
  logs:
  ui:

networks:
  traefik:
    external:
      name: traefik

Levantar el stack

docker-compose up -d

Iniciar vault

Una vez iniciado, nos mostrará varias Keys para desbloquear vault. Por defecto viene bloqueado. Aparte de las Keys nos dará el token de root que es necesario para crear la configuración.

docker exec -it vault vault operator init
Unseal Key 1: l860hyRUvAjvR+4aYgP8ZOw7I+4ZWokLGz7VhR6VT4gl
Unseal Key 2: QWSw5kx5GTtNKeIbItRtKFZGfVHkB0zl18GGk6UM54ua
Unseal Key 3: zXptx6jt1bHm54PGqEFkPs2Y7NRsCsPa/wge+XMJHJtw
Unseal Key 4: iaDsYaltuqo3uI6OMV6KBiqcZ+GOYLOOrEMo83QaDD21
Unseal Key 5: 7dDPj2rYY+1Gg8YkaY8yl7Ntmhii1HxAzIzLSL1icxZG

Initial Root Token: f892253c-df80-ac1e-104e-85e02f9050aa

Desbloquear Vault

Una vez iniciado Vault, hay que desbloquearlo. Para esto, se necesitan 3 de las 5 claves de Unseal que nos mostró anteriormente. Se pueden usar cualquiera de ellas

docker exec -it vault vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 1/3
Unseal Nonce a1a4f8ac-2a82-70ea-b333-a341533d2265
Version 0.10.1
HA Enabled true
docker exec -it vault vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 2/3
Unseal Nonce a1a4f8ac-2a82-70ea-b333-a341533d2265
Version 0.10.1
HA Enabled true
docker exec -it vault vault operator unseal
Unseal Key (will be hidden):
Key Value
--- -----
Seal Type shamir
Sealed false
Total Shares 5
Threshold 3
Version 0.10.1
Cluster Name vault-cluster-1805cfbc
Cluster ID ee3dc20e-e40c-c717-0025-544c6bd2cd71
HA Enabled false

Configuración

Para empezar, hay que autenticarse como root para poder comenzar a configurarlo. Para esto, necesitamos el Token de root que nos ha aparecido antes.

docker exec -it vault vault login
Key Value
--- -----
token f892253c-df80-ac1e-104e-85e02f9050aa
token_accessor f6030203-5c7d-c909-0834-0c249607f8f1
token_duration ∞
token_renewable false
token_policies [root]

Logs

Es recomendable habilitar los logs para poder tener un registro de lo que está pasando y quien accede a los secretos. Este log se guardará en el volumen que hemos mapeado previamente.

docker exec -it vault vault audit enable file file_path=/vault/logs/vault_audit.log

Políticas

Crear políticas

Para las políticas, hemos mapeado anteriormente (en el docker-compose) una carpeta desde ./config/policies que albergará todas las políticas que creemos. De este modo, si el contenedor se borra, los ficheros de las políticas seguirán existiendo. En este caso vamos a crear 2 políticas. Una será para admin con permiso para todo y la otra para usuarios mas restringida.

mkdir ./config/policies

Admin

vim ./config/policies/admin.hcl
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

User

vim ./config/policies/user.hcl
path "secret/*" {
capabilities = ["read", "update", "list"]
}

path "secret/admin" {
capabilities = ["deny"]
}

path "sys/mounts" {
    capabilities = [ "read" ]
}

path "sys/auth" {
    capabilities = [ "read" ]
}

Aplicar políticas

docker exec -it vault vault policy write admin /vault/policies/admin.hcl
docker exec -it vault vault policy write user /vault/policies/user.hcl

Autenticación

La autenticación de los usuarios, puede se por distintos modos; github, ldap, userpass.. En este caso, vamos a utilizar la última opción, userpass por lo que hay que hay que habilitar este método y crear los usuarios en vault

Habilitar autenticación de usuario

docker exec -it vault vault auth enable userpass

Crear usuarios

Usuario admin:

docker exec -it vault vault write auth/userpass/users/admin password=S3cr3t policies=admin

Usuario normal:

docker exec -it vault vault write auth/userpass/users/user password=S3cr3t1 policies=user

Probar el usuario en la consola

docker exec -it vault vault login -method=userpass username=admin password=S3cr3t
Key Value
--- -----
token 5bfeaa97-91e3-41e9-278d-a913fa925b7c
token_accessor 1c49081f-9720-4ada-d167-f31923cef725
token_duration 168h
token_renewable true
token_policies [admins default]
token_meta_username admin

Probar el usuario por la API

curl -k https://vaultapi.example.com/v1/auth/userpass/login/admin -d '{ "password": "S3cr3t" }'
{
  "request_id":"c1d9499a-bfbb-95bc-d57a-ee426151ead7",
  "lease_id":"",
  "renewable":false,
  "lease_duration":0,
  "data":null,
  "wrap_info":null,
  "warnings":null,
  "auth":{
    "client_token":"59e57e66-1787-6830-1e6b-6aaa91936d0a",
    "accessor":"5752d6b8-a0f0-b7fc-b043-e35fb5b030a1",
    "policies":[
      "admin",
      "default"
    ],
    "metadata":{
      "username":"admin"
    },
    "lease_duration":604800, 
    "renewable":true,
    "entity_id":"7692a08a-a35a-015e-76f6-da9d7caa7cc9"
  }
}

Backends

Los backends son las “ubicaciones” donde podremos almacenar las keys

Listar los backends habilitados

docker exec -it vault vault secrets list
Path        Type        Description
----        ----        -----------
cubbyhole/  cubbyhole   per-token private secret storage
identity/   identity    identity store
secret/     kv          key/value secret storage
sys/        system      system endpoints used for control, policy and debugging

Crear un backend nuevo

Hay diferentes tipos de backends. Mas info aquí

docker exec -it vault vault secrets enable -path=test -description="esto es un test" kv

Crear keys

docker exec -it vault vault write secret/user user_key=supersecret
docker exec -it vault vault write secret/admin admin_key=supersecret

Listar las keys

docker exec -it vault vault list secret/
Keys
----
admin
user

Leer la key creada

docker exec -it vault vault read secret/admin
Key               Value
---               -----
refresh_interval  168h
admin_key         supersecret

Listar las keys utilizando la API

curl -H "X-Vault-Token: 6046c079-4ebf-3999-41c4-adc56a5e679f" -X LIST https://vaultapi.example.com/v1/secret/ -s | jq
{
  "request_id": "d0638f20-c43f-cd6c-0f43-c57d16290bb9",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "keys": [
      "admin",
      "user"
    ]
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

Ver las keys utilizando la API

curl -H "X-Vault-Token: 6046c079-4ebf-3999-41c4-adc56a5e679f" -X GET https://vaultapi.example.com/v1/secret/admin -s | jq
{
  "request_id": "05df0182-5ce3-7e37-3b94-722c0109d86d",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 604800,
  "data": {
    "admin_key": "supersecret",
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

UI Web

Y para que Vault sea mas accesible, en el docker-compose hemos desplegado otro docker que habilita una web para poder gestionar completamente vault de una manera mas fácil. En este caso lo hemos desplegado bajo traefik.

Para acceder a la web:

https://vault.example.com

De momento esto es todo. En un futuro, iré añadiendo mas posts de como conectar diferentes servicios con Vault según vaya profundizando en la materia.

Post para echar un ojo:

https://blog.irontec.com/guardando-nuestros-secretos-en-vault-1-de-2/
https://blog.irontec.com/guardando-nuestros-secretos-en-vault-2-de-2/
https://www.vaultproject.io/docs/

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *