Skip to content

Tutorial: cofre persistente

Objetivo

Ao final você vai ver um servidor OpenBao que guarda os dados em disco e fala TLS. Ele é inicializado uma vez, destrancado com 2 de 3 chaves e configurado sem guardar o token root. O Keyholder o usa por TLS, um reinício o tranca de novo, ele é destrancado e por fim ganha um backup.

Cada comando e cada saída abaixo vêm de uma execução real, gravada em demo/tutorials/server/expected/ e conferida por run.sh --check. As saídas são do programa, em inglês. Os passos, e o motivo de cada um, estão no guia do cofre persistente.

O que muda em relação a uma instalação real. O servidor roda o próprio deploy/server.hcl, com os caminhos levados para um diretório temporário e a porta trocada para 18200. A autoridade certificadora é criada para a execução. As chaves de destrancamento, o token root e a senha do administrador ficam nesse diretório temporário e são apagados com ele.

Como rodar

bash demo/tutorials/server/run.sh all       # precisa de bao, openssl, python3, curl e go
bash demo/tutorials/server/run.sh --check

Script: demo/tutorials/server/run.sh. Políticas: policy-project-read.hcl e policy-admin.hcl.

1. Inicializar uma vez, destrancar com 2 de 3 chaves

Um servidor novo vem trancado e sem inicializar. O bao operator init roda uma única vez na vida do cofre e imprime as chaves de destrancamento e o token root; aqui elas vão para um arquivo que nunca entra no repositório. Cada chave avança o progresso em um; a segunda abre o cofre.

# Start the server, initialize it once, unseal it with 2 of 3 keys

$ bao status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            2.7.1
Commit Date        <time>
Storage Type       raft
HA Enabled         true
exit_code=2

$ bao operator init -key-shares=3 -key-threshold=2 -format=json > <file kept offline>
exit_code=0

The file now holds 3 unseal keys and the root token. It never goes into a repository; give each key to a different place or person.

$ bao operator unseal <unseal key 1> >/dev/null
exit_code=0

Vault: initialized=true sealed=true unseal_progress=1/2

$ bao operator unseal <unseal key 2> >/dev/null
exit_code=0

Vault: initialized=true sealed=false unseal_progress=0/2

2. Configurar e revogar o token root

O token root cria o mount KV, as políticas e um login de administrador, e depois é revogado. A partir daí o administrador entra com senha e recebe um token de 8 horas, que guarda segredos e emite os tokens embrulhados dos agentes, mas não muda a configuração do cofre.

# With the root token: KV, policies and an administrator login; then the root token is revoked

$ bao secrets enable -path=secret kv-v2
Success! Enabled the kv-v2 secrets engine at: secret/
exit_code=0

$ bao kv put -mount=secret my-project/dev API_TOKEN=tok-fake-not-a-real-secret
======= Secret Path =======
secret/data/my-project/dev

======= Metadata =======
Key                Value
---                -----
created_time       <time>
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
exit_code=0

$ bao policy write my-project-read deploy/policy-project-read.hcl
Success! Uploaded policy: my-project-read
exit_code=0

$ bao policy write keyholder-admin deploy/policy-admin.hcl
Success! Uploaded policy: keyholder-admin
exit_code=0

$ bao auth enable userpass
Success! Enabled userpass auth method at: userpass/
exit_code=0

$ bao write auth/userpass/users/admin password=<password> token_policies=keyholder-admin token_ttl=8h token_max_ttl=8h
Success! Data written to: auth/userpass/users/admin
exit_code=0

$ bao token revoke -self
Success! Revoked token (if it existed)
exit_code=0

The root token no longer exists. Each day the administrator logs in instead:

$ bao login -method=userpass -field=token username=admin password=<password> > <administrator token>
exit_code=0

Policies of the administrator's token: default, keyholder-admin

3. Keyholder por TLS

Com BAO_CACERT apontando para a autoridade certificadora, a sessão abre e a API recebe o token. Sem ele, o Keyholder recusa a conexão e diz qual variável definir.

# Keyholder reaches the vault over TLS; without the CA it refuses to connect

$ BAO_WRAPPING_TOKEN=<wrapped token> khcall keyholder_status keyholder_run '{"command":"curl","args":["-sS","-H","Authorization: Bearer {{vault://my-project/dev/API_TOKEN}}","http://127.0.0.1:18080/"]}'
### keyholder_status
{
  "addr": "https://127.0.0.1:18200",
  "initialized": true,
  "kv_mount": "secret",
  "scope": "my-project",
  "sealed": false,
  "server_version": "2.7.1",
  "token_expire_time": "<time>",
  "token_policies": [
    "default",
    "my-project-read"
  ],
  "token_renewable": true,
  "token_ttl_seconds": <ttl>
}
### keyholder_run
{
  "exit_code": 0,
  "refs_used": [
    "vault://my-project/dev/API_TOKEN"
  ],
  "stderr": "",
  "stdout": "api says: hello, caller with header Authorization: Bearer [hidden:vault://my-project/dev/API_TOKEN]\n"
}
--- stderr
<timestamp> audit cmd="curl" refs=[vault://my-project/dev/API_TOKEN] exit=0 dur=<duration> status=ok
exit_code=0

Did the API receive the stored token? yes

$ BAO_CACERT= BAO_WRAPPING_TOKEN=<wrapped token> khcall keyholder_status
{
  "addr": "https://127.0.0.1:18200",
  "initialized": false,
  "kv_mount": "secret",
  "scope": "my-project",
  "sealed": false,
  "server_version": "",
  "session_error": "unwrap token: cannot reach the vault at https://127.0.0.1:18200: tls: failed to verify certificate: x509: certificate signed by unknown authority; set BAO_CACERT to the CA certificate that signed the vault's certificate",
  "token_policies": null,
  "token_renewable": false,
  "token_ttl_seconds": 0
}
--- stderr
<timestamp> session not opened: unwrap token: cannot reach the vault at https://127.0.0.1:18200: tls: failed to verify certificate: x509: certificate signed by unknown authority; set BAO_CACERT to the CA certificate that signed the vault's certificate
exit_code=0

4. Um reinício tranca o cofre

Um token embrulhado é emitido e o servidor reinicia. Ele volta trancado: o Keyholder avisa e não consome o token. Depois de duas chaves, um novo início do Keyholder abre a sessão com esse mesmo token, e o segredo guardado antes do reinício continua lá.

# After a restart the vault is sealed: Keyholder fails cleanly, then works once it is unsealed

A wrapped token was issued before the restart.

Vault after the restart: initialized=true sealed=true unseal_progress=0/2

$ BAO_WRAPPING_TOKEN=<same wrapped token> khcall keyholder_status
{
  "addr": "https://127.0.0.1:18200",
  "initialized": true,
  "kv_mount": "secret",
  "scope": "my-project",
  "sealed": true,
  "server_version": "2.7.1",
  "session_error": "unwrap token: the vault is sealed: an administrator must unseal it (bao operator unseal), then restart this server; the wrapped token was not used",
  "token_policies": null,
  "token_renewable": false,
  "token_ttl_seconds": 0
}
--- stderr
<timestamp> session not opened: unwrap token: the vault is sealed: an administrator must unseal it (bao operator unseal), then restart this server; the wrapped token was not used
exit_code=0

$ bao operator unseal <unseal key 2> >/dev/null
exit_code=0

Vault: initialized=true sealed=true unseal_progress=1/2

$ bao operator unseal <unseal key 3> >/dev/null
exit_code=0

Vault: initialized=true sealed=false unseal_progress=0/2

$ BAO_WRAPPING_TOKEN=<same wrapped token> khcall keyholder_list
{
  "entries": [
    {
      "ref": "vault://my-project/dev/API_TOKEN",
      "version": 1
    }
  ],
  "note": "Use {{vault://path/KEY}} in the args, env or files of keyholder_run.",
  "scope": "my-project"
}
exit_code=0

5. Backup

O administrador salva um snapshot do cofre inteiro. Ele é cifrado com as chaves do cofre, então é restaurado e destrancado com as mesmas chaves.

# A snapshot of the whole vault, taken by the administrator

$ bao operator raft snapshot save <backup file>
exit_code=0

Snapshot written: yes. It is encrypted with the vault's keys; it is restored with `bao operator raft snapshot restore` and unsealed with the same keys.