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!). Y como backend para almacenar los secretos, utilizaremos consul. 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": {"consul": {"path": "vault/", "address": "consul:8500", "scheme": "http"}}, "listener": {"tcp": {"address": "0.0.0.0:8200", "tls_disable": 1}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h", "ui": true}'
      VAULT_ADDR: http://127.0.0.1:8200
    networks:
      - net
      - traefik
    command: server
    depends_on:
      - consul
    labels:
      - "traefik.backend=vault"
      - "traefik.frontend.rule=Host:vault.example.com"
      - "traefik.docker.network=traefik"
      - "traefik.port=8200"

  consul:
    image: consul
    container_name: consul
    restart: always
    command: agent -server -bind 0.0.0.0 -data-dir=/consul/data -client 0.0.0.0 -bootstrap-expect=1
    networks:
      - net
    volumes:
      - consul1:/consul/data
    healthcheck:
      test: ['CMD', '/bin/sh', '-c', 'curl -sfLo /dev/null http://127.0.0.1:8500/v1/health/node/$HOSTNAME']

volumes:
  file:
  logs:
  consul:

networks:
  net:
  traefik:
    external:
      name: traefik

Levantar el stack

docker-compose up -d
vault      |              Api Address: http://172.19.0.2:8200
vault      |                      Cgo: disabled
vault      |          Cluster Address: https://172.19.0.2:8201
vault      |               Listener 1: tcp (addr: "0.0.0.0:8200", cluster address: "0.0.0.0:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
vault      |                Log Level: info
vault      |                    Mlock: supported: true, enabled: true
vault      |                  Storage: consul (HA available)
vault      |                  Version: Vault v1.1.2
vault      |              Version Sha: 0082501623c0b704b87b1fbc84c2d725994bac54

Iniciar vault

Nota: Si queremos conectarnos desde un host externo, hay que configurar la siguiente variable:

export VAULT_ADDR=https://vault.example.com

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: AnvbKvub4vWZ8PcjWSCGO+Wqoe165sI6gc5Q0dJr4Sb5
Unseal Key 2: vvz/FqHo3TE8dW8LQNIrU4dt0L2iIynhOJzdjjWZ3H+h
Unseal Key 3: SS5eAnYBM0YPjKnS9kIftaGq95QWva4Lo0tEvZqZ3vj/
Unseal Key 4: Z8v06Mk5eHEBcNFADLFqHMvMPktrGDgIaEFFCViW0r4P
Unseal Key 5: CQ8PmG0xf5MzrjyQwBK4AsLdSz9Dg7GGPYprj6dNZbmz

Initial Root Token: s.TsEFCD3LVDwquUblsmPFD8Rg

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                s.TsEFCD3LVDwquUblsmPFD8Rg
token_accessor       CNjpS8D3ElE4tIwgygKmYsdo
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
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                  s.IrTfojMb5CryYG2n3kMChTDn
token_accessor         zIwzjwxtkMr83G7CrEZkt9jN
token_duration         168h
token_renewable        true
token_policies         ["admin" "default"]
identity_policies      []
policies               ["admin" "default"]
token_meta_username    admin

Probar el usuario por la API

curl -k https://vault.example.com/v1/auth/userpass/login/admin -d '{ "password": "S3cr3t" }'
{
  "request_id": "22431a91-7ebe-17b2-d170-bcd639a39a2a",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": null,
  "wrap_info": null,
  "warnings": null,
  "auth": {
    "client_token": "s.zPNwyG26ZVYCNAaHZpkr0AED",
    "accessor": "tr2xUEB4P3iVoy0bQXFnZU0k",
    "policies": [
      "admin",
      "default"
    ],
    "token_policies": [
      "admin",
      "default"
    ],
    "metadata": {
      "username": "admin"
    },
    "lease_duration": 604800,
    "renewable": true,
    "entity_id": "b0017de2-d2ed-7757-706b-1b6bf920f1d4",
    "token_type": "service",
    "orphan": true
  }
}

Backends

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

Listar los backends habilitados

docker exec -it vault vault secrets list
Path          Type         Accessor              Description
----          ----         --------              -----------
cubbyhole/    cubbyhole    cubbyhole_aa560446    per-token private secret storage
identity/     identity     identity_f7242aa5     identity store
sys/          system       system_cdb394e2       system endpoints used for control, policy and debugging
test/         kv           kv_19bb74c6           esto es un test

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 test/user user_key=supersecret
docker exec -it vault vault write test/admin admin_key=supersecret

Listar las keys

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

Leer la key creada

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

Listar las keys utilizando la API

curl -H "X-Vault-Token: s.JWDBOiIZQnnn9ze2iW0bUSOg" -X LIST https://vault.example.com/v1/test/ -s | jq
{
  "request_id": "2ee4517c-d79e-8270-103a-1fbf8bf0cd96",
  "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: s.JWDBOiIZQnnn9ze2iW0bUSOg" -X GET https://vault.example.com/v1/test/admin -s | jq
{
  "request_id": "5c361926-be89-1a9f-6256-18a95b33f1ed",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 604800,
  "data": {
    "admin_key": "supersecret"
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

UI Web

Una vez añadido en la configuración de Vault el UI a true se podrá acceder a la web mediante la siguiente URL:

https://vault.example.com/ui

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/


Also published on Medium.

One comment

Leave a Reply

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