Como projetar sistemas de configuração centralizada com Vault

1. Fundamentos da Configuração Centralizada com Vault

A configuração centralizada com HashiCorp Vault vai muito além do simples armazenamento de senhas. Em um ecossistema de 1200 temas de infraestrutura moderna, o Vault se destaca por tratar configurações como secrets dinâmicos — credenciais que são geradas sob demanda, têm tempo de vida limitado e podem ser revogadas instantaneamente.

Conceitos fundamentais:

  • Secrets estáticos: valores fixos como senhas de banco, chaves de API — armazenados no KV Secrets Engine
  • Secrets dinâmicos: credenciais geradas pelo Vault no momento da requisição (ex: usuário de banco com validade de 1 hora)
  • Configurações dinâmicas: parâmetros de aplicação que podem ser alterados sem reinicialização

Diferentemente de soluções como etcd ou Consul (focadas em descoberta de serviço e armazenamento de chave-valor simples), o Vault implementa zero trust architecture: nenhum sistema confia em outro por padrão. Toda requisição deve ser autenticada e autorizada, com criptografia tanto em trânsito (TLS) quanto em repouso (AES-256-GCM).

# Exemplo: Configuração mínima de um servidor Vault
storage "raft" {
  path = "/opt/vault/data"
  node_id = "node1"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "/etc/vault/certs/vault.crt"
  tls_key_file  = "/etc/vault/certs/vault.key"
}

seal "awskms" {
  region     = "us-east-1"
  kms_key_id = "alias/vault-unseal"
}

api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201"

2. Arquitetura de Alto Nível para Configuração Centralizada

A arquitetura do Vault para configuração centralizada é composta por três camadas essenciais:

Servidor Vault: responsável por autenticação, autorização e armazenamento. Pode operar em modo standalone ou cluster (Raft ou Consul como backend de armazenamento).

Storage Backend: onde os dados criptografados residem. Opções incluem Raft (integrado), Consul, DynamoDB, MySQL. O backend de armazenamento nunca vê dados decifrados — toda criptografia ocorre no servidor Vault.

Selo de Segurança (Seal): mecanismo que protege a chave mestra. Pode ser via Shamir (divisão de chaves entre operadores) ou cloud KMS (AWS KMS, Azure Key Vault, GCP Cloud KMS).

# Padrão de deployment multi-cluster com replicação
# Primário (us-east-1)
storage "raft" {
  path = "/vault/data"
  node_id = "primary-1"
}

replication {
  mode = "primary"
  token = "hvs.replication-token"
}

# Secundário (us-west-2) - apenas leitura
storage "raft" {
  path = "/vault/data"
  node_id = "secondary-1"
}

replication {
  mode = "secondary"
  token = "hvs.replication-token"
  primary_api_addr = "https://vault-primary.example.com:8200"
}

Para ambientes Kubernetes, o Vault se integra nativamente via Vault Agent Injector — um mutating webhook que injeta sidecars nos pods para fornecer configurações.

3. Estrutura de Paths e Namespaces para Organização de Configurações

A organização hierárquica é crucial para gerenciar 1200 temas de configuração. O Vault utiliza paths como unidades de acesso e namespaces como isolamento lógico entre equipes ou ambientes.

Hierarquia recomendada:

# Estrutura de paths para configuração centralizada
secret/
├── datacenter/
│   ├── us-east/
│   │   ├── database/
│   │   │   └── primary
│   │   └── redis/
│   │       └── config
│   └── eu-west/
│       ├── database/
│       │   └── replica
│       └── cache/
├── application/
│   ├── payment-service/
│   │   ├── production
│   │   └── staging
│   └── notification-service/
│       ├── config
│       └── webhook-keys
└── infrastructure/
    ├── kubernetes/
    │   ├── cluster-1/
    │   │   └── service-accounts
    │   └── cluster-2/
    └── terraform/
        └── state-backend

Namespaces multi-tenant permitem isolar completamente ambientes:

# Política de acesso baseada em namespace e path
path "namespace-dev/secret/application/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

path "namespace-prod/secret/application/*" {
  capabilities = ["read", "list"]
  required_parameters = ["version"]
}

path "namespace-prod/secret/infrastructure/*" {
  capabilities = ["deny"]
}

4. Estratégias de Versionamento e Rollback de Configurações

O KV Secrets Engine v2 oferece versionamento automático — cada alteração cria uma nova versão, mantendo as anteriores disponíveis para rollback.

Operações de versionamento:

# Escrever configuração (cria versão 1)
vault kv put secret/application/payment-service/production \
  db_host="prod-db.example.com" \
  db_port="5432" \
  max_connections="100"

# Atualizar (cria versão 2)
vault kv put secret/application/payment-service/production \
  db_host="prod-db.example.com" \
  db_port="5432" \
  max_connections="200"

# Listar versões
vault kv metadata get secret/application/payment-service/production

# Rollback para versão 1
vault kv rollback -version=1 secret/application/payment-service/production

# Deletar versão específica (soft delete)
vault kv metadata delete -versions=2 secret/application/payment-service/production

# Destruir permanentemente
vault kv destroy -versions=2 secret/application/payment-service/production

Auditoria imutável: configure audit devices para registrar toda operação:

# Habilitar audit log para arquivo
vault audit enable file file_path=/vault/logs/audit.log

# Audit para syslog
vault audit enable syslog facility="AUTH" tag="vault-audit"

# Audit para socket (Graylog, ELK)
vault audit enable socket address="10.0.1.10:514" socket_type="tcp"

Cada entrada de audit contém timestamp, identidade do requisitante, path acessado e operação — impossível de modificar retroativamente.

5. Autenticação e Autorização para Acesso a Configurações

O Vault suporta múltiplos métodos de autenticação, cada um adequado a diferentes cenários:

AppRole: ideal para máquinas e serviços automatizados
Kubernetes Auth: para pods que precisam de configurações
LDAP: para integração com Active Directory corporativo
Tokens: método base, com políticas associadas

# Configuração de AppRole para CI/CD
vault auth enable approle

# Criar role com política restrita
vault write auth/approle/role/jenkins-role \
  token_policies="ci-cd-policy" \
  token_ttl=1h \
  token_max_ttl=4h \
  secret_id_ttl=10m \
  secret_id_num_uses=40

# Política HCL para acesso controlado
path "secret/application/*" {
  capabilities = ["read", "list"]
  allowed_parameters = {
    "version" = []
  }
  denied_parameters = {
    "delete" = []
  }
}

path "secret/infrastructure/terraform/*" {
  capabilities = ["read", "list"]
  # Apenas entre 9h e 18h
  condition {
    time {
      weekday = ["mon", "tue", "wed", "thu", "fri"]
      timezone = "America/Sao_Paulo"
      start_time = "09:00"
      end_time = "18:00"
    }
  }
}

Para secrets dinâmicos, configure leases com renovação automática:

# Configurar lease para banco PostgreSQL
vault write database/config/postgres-lab \
  plugin_name="postgresql-database-plugin" \
  allowed_roles="*" \
  connection_url="postgresql://{{username}}:{{password}}@postgres.example.com:5432/lab" \
  username="vault_admin" \
  password="P@ssw0rd"

# Role que gera credenciais com TTL controlado
vault write database/roles/db-readonly \
  db_name="postgres-lab" \
  creation_statements="CREATE USER \"{{name}}\" WITH PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="30m" \
  max_ttl="2h"

6. Integração com Aplicações e Pipelines de CI/CD

A injeção de configurações em aplicações segue dois padrões principais:

Vault Agent Sidecar: ideal para Kubernetes, o agente executa como sidecar e mantém arquivos de configuração sincronizados.

# Configuração do Vault Agent para sidecar
pid_file = "/tmp/agent-pid"

vault {
  address = "https://vault-internal:8200"
  retry {
    num_retries = 5
  }
}

auto_auth {
  method "kubernetes" {
    mount_path = "auth/kubernetes"
    config {
      role = "app-role"
      jwt_path = "/var/run/secrets/kubernetes.io/serviceaccount/token"
    }
  }
}

template {
  source      = "/etc/config.tpl"
  destination = "/etc/config/app.conf"
  perms       = 0644

  # Recarregar aplicação quando config mudar
  exec {
    command = ["/bin/systemctl", "reload", "myapp"]
  }
}

Template de configuração (Consul Template syntax):

{{- with secret "secret/application/payment-service/production" }}
# Configuração gerada pelo Vault Agent em {{ currentTime }}
db_host = "{{ .Data.data.db_host }}"
db_port = {{ .Data.data.db_port }}
max_connections = {{ .Data.data.max_connections }}
db_password = "{{ .Data.data.db_password }}"
{{- end }}

{{- with secret "database/creds/db-readonly" }}
# Credenciais dinâmicas - válidas até {{ .Data.lease_duration }}s
db_user = "{{ .Data.username }}"
db_pass = "{{ .Data.password }}"
{{- end }}

Pipeline seguro: injete secrets em runtime, nunca em build:

# Pipeline Jenkins - injeção segura em tempo de execução
stage('Deploy') {
  steps {
    script {
      # Obter token AppRole
      sh '''
        VAULT_TOKEN=$(vault write -field=token auth/approle/login \
          role_id=${ROLE_ID} \
          secret_id=${SECRET_ID})

        # Exportar configurações como variáveis de ambiente
        vault kv get -field=db_host secret/application/payment-service/production > .env
        vault kv get -field=db_password secret/application/payment-service/production >> .env

        # Deploy com configurações injetadas
        docker run --env-file .env myapp:${BUILD_TAG}
      '''
    }
  }
}

7. Monitoramento, Performance e Boas Práticas Operacionais

Métricas essenciais para operação do Vault:

# Métricas Prometheus do Vault
# vault_raft_leader_latency_ms - latência de replicação Raft
# vault_token_count - número de tokens ativos
# vault_secret_lease_count - leases ativos
# vault_audit_log_request_failure - falhas de auditoria
# vault_core_unsealed - status do selo (1=aberto, 0=fechado)

# Configuração de métricas no Vault
telemetry {
  prometheus_retention_time = "24h"
  disable_hostname = true
}

Estratégias de cache com Vault Agent:

# Vault Agent com cache local
cache {
  use_auto_auth_token = true
}

listener "tcp" {
  address = "127.0.0.1:8200"
  tls_disable = true
}

# Aplicação consulta agente local, que faz cache
# Reduz latência de 50ms para <1ms em leituras repetidas

Disaster Recovery:

# Backup do storage backend Raft
vault operator raft snapshot save /backup/vault-snapshot-$(date +%Y%m%d).snap

# Restore em novo cluster
vault operator raft snapshot restore /backup/vault-snapshot-20240101.snap

# Failover automático com replicação
# No primário:
vault write -f sys/replication/primary/enable primary_cluster_addr="https://vault-primary:8201"

# No secundário:
vault write sys/replication/secondary/enable token="hvs.replication-token"

Rate limiting para evitar abuso:

# Rate limit por caminho
path "secret/application/*" {
  capabilities = ["read"]
  rate_limit = {
    rate = 100
    burst = 200
  }
}

Referências