Introdução ao Vault
1. Visão geral
Neste tutorial, exploraremos o Vault do Hashicorp - uma ferramenta popular usada para gerenciar com segurança informações confidenciais nas arquiteturas modernas de aplicativos .
Os principais tópicos que abordaremos incluem:
-
Que problema o Vault tenta resolver
-
Arquitetura do Vault e principais conceitos
-
Configuração de um ambiente de teste simples
-
Interagindo com o Vault usando sua ferramenta de linha de comando
2. O problema com informações confidenciais
Antes de explorar o Vault, vamos tentar entender o problema que ele tenta resolver: gerenciamento de informações confidenciais.
*A maioria dos aplicativos precisa acessar dados confidenciais para funcionar corretamente* . Por exemplo, um aplicativo de comércio eletrônico pode ter um nome de usuário/senha configurado em algum lugar para se conectar ao seu banco de dados. Também pode precisar de chaves de API para integrar-se a outros provedores de serviços, como gateways de pagamento, logística e outros parceiros de negócios.
As credenciais do banco de dados e as chaves da API são alguns exemplos de informações confidenciais que precisamos armazenar e disponibilizar para nossos aplicativos de maneira segura.
Uma solução simples é armazenar essas credenciais em um arquivo de configuração e lê-las no momento da inicialização. O problema com essa abordagem é óbvio, no entanto. Quem tem acesso a esse arquivo compartilha os mesmos privilégios de banco de dados que nosso aplicativo possui - geralmente fornecendo acesso total a todos os dados armazenados.
Podemos tentar tornar as coisas um pouco mais difíceis, criptografando esses arquivos. Essa abordagem, no entanto, não agregará muito em termos de segurança geral. Principalmente porque nosso aplicativo deve ter acesso à chave mestra. A criptografia, quando usada dessa maneira, alcançará apenas uma sensação "falsa" de segurança.
Aplicativos modernos e ambientes de nuvem tendem a adicionar uma complexidade extra: serviços distribuídos, vários bancos de dados, sistemas de mensagens e assim por diante, todos têm informações confidenciais espalhadas um pouco por toda parte, aumentando assim o risco de uma violação de segurança.
Então o que nós podemos fazer? Vamos pular!
3. O que é o Vault?
O Hashicorp Vault soluciona o problema de gerenciar informações confidenciais - um secret na linguagem do Vault. "Gerenciar" nesse contexto significa que o Vault controla todos os aspectos de uma informação sensível : sua geração, armazenamento, uso e, por último mas não menos importante, sua revogação.
Hashicorp oferece duas versões do Vault. A versão de código aberto, usada neste artigo, é de uso gratuito, mesmo em ambientes comerciais. Também está disponível uma versão paga, que inclui suporte técnico em diferentes SLAs e recursos adicionais, como suporte ao HSM (Hardware Security Module).
3.1. Arquitetura e principais recursos
A arquitetura do Vault é enganosamente simples. Seus principais componentes são:
-
Um back-end de persistência - armazenamento para todos os segredos
-
Um servidor de API que lida com solicitações de clientes e executa operações em segredos
-
Vários mecanismos secretos, um para cada tipo de tipo secreto suportado
Ao delegar toda a manipulação secreta no Vault, podemos mitigar alguns problemas de segurança:
-
Nossos aplicativos não precisam mais armazená-los - basta perguntar ao Vault quando necessário e descartá-lo *Podemos usar segredos de curta duração, limitando assim a “janela de oportunidade” onde um invasor pode usar um segredo roubado
O Vault criptografa todos os dados com uma chave de criptografia antes de gravá-los na loja. Essa chave de criptografia é criptografada por outra chave - a chave mestra, usada apenas na inicialização.
Um ponto chave na implementação do Vault é que ele não armazena a chave mestra no servidor.* Isso significa que nem mesmo o Vault pode acessar seus dados salvos após a inicialização. * Neste ponto, diz-se que uma instância do Vault está em um estado "selado".
Posteriormente, seguiremos as etapas necessárias para gerar a chave mestra e desmarcar uma instância do Vault.
Depois de aberto, o Vault estará pronto para aceitar solicitações de API. Obviamente, essas solicitações precisam de autenticação, o que nos leva a como o Vault autentica os clientes e decide o que eles podem ou não fazer.
3.2. Autenticação
*Para acessar segredos no Vault, um cliente precisa se autenticar usando um dos métodos suportados* . O método mais simples usa tokens, que são apenas sequências enviadas em cada solicitação de API usando um cabeçalho HTTP especial.
Quando instalado inicialmente, o Vault gera automaticamente um "token raiz". Esse token é equivalente a superusuário raiz em sistemas Linux, portanto, seu uso deve ser limitado ao mínimo. Como prática recomendada, devemos usar esse token raiz apenas para criar outros tokens com menos privilégios e revogá-lo. Porém, isso não é um problema, pois podemos gerar outro token raiz posteriormente usando chaves não vedadas.
O Vault também suporta outros mecanismos de autenticação, como LDAP, JWT, Certificados TLS, entre outros. Todos esses mecanismos são construídos sobre o mecanismo básico de tokens: quando o Vault valida nosso cliente, ele fornece um token que podemos usar para acessar outras APIs.
Os tokens têm algumas propriedades associadas a eles. As principais propriedades são:
-
Um conjunto de Policies associadas (consulte a próxima seção)
-
Tempo de Viver
-
Se pode ser renovado *Contagem máxima de uso
Salvo indicação em contrário, os tokens criados pelo Vault formarão um relacionamento pai-filho. Um token filho pode ter no máximo o mesmo nível de privilégios que o pai possui.
O oposto não é verdadeiro: podemos - e geralmente fazemos - criar um token filho com políticas restritivas Outro ponto-chave sobre esse relacionamento:* Quando invalidamos um token, todos os tokens filhos e seus descendentes também são invalidados *.
3.3. Políticas
As políticas definem exatamente quais segredos um cliente pode acessar e quais operações ele pode executar com ele. Vamos ver como é uma política simples:
path "secret/accounting" {
capabilities = [ "read" ]
}
Aqui, usamos a sintaxe HCL (Hashicorp’s Configuration Language) para definir nossa política. O Vault também suporta JSON para esse fim, mas seguiremos a HCL em nossos exemplos, pois é mais fácil de ler.
As políticas no Vault são "negadas por padrão" *. Um token anexado a essa política de exemplo terá acesso a segredos armazenados em secret/accounting e nada mais. No momento da criação, um token pode ser anexado a várias políticas. Isso é muito útil porque nos permite criar e testar políticas menores e aplicá-las conforme necessário.
Outro aspecto importante das políticas é que elas aproveitam a avaliação preguiçosa. Isso significa que podemos atualizar uma determinada política e todos os tokens serão afetados imediatamente.
As políticas descritas até o momento também são chamadas de Políticas de Lista de Controle de Acesso ou Políticas da ACL. O Vault também suporta dois tipos de política adicionais: políticas EGP e RGP. Eles estão disponíveis apenas nas versões pagas e estendem a sintaxe básica da política com o Sentinel.
Quando disponível, isso nos permite levar em consideração em nossas políticas atributos adicionais, como hora do dia, vários fatores de autenticação, origem da rede do cliente e assim por diante. Por exemplo, podemos definir uma política que permita o acesso a um determinado segredo apenas no horário comercial.
Podemos encontrar mais detalhes sobre a sintaxe da política em documentação do Vault.
4. Tipos secretos
O Vault oferece suporte a vários tipos secretos diferentes, que abordam diferentes casos de uso:
-
_Key-Value: _ pares de valores-chave estáticos simples
-
_ Credenciais geradas dinamicamente_: geradas pelo Vault mediante solicitação de um cliente
-
Cryptographic keys: Usado para executar funções criptográficas com dados do cliente
Cada tipo secreto é definido pelos seguintes atributos:
-
Um mount _point, _ que define seu prefixo da API REST
-
Um conjunto de operações expostas através da API correspondente *Um conjunto de parâmetros de configuração
Uma determinada instância secreta é acessível através de um path, como uma árvore de diretórios em um sistema de arquivos. O primeiro componente desse caminho corresponde ao mount point onde todos os segredos deste tipo estão localizados* .
Por exemplo, a string secret/my-application corresponde ao caminho sob o qual podemos encontrar pares de valores-chave para my-application.
4.1. Segredos de valor-chave
*Os segredos de valor-chave são, como o nome indica, pares simples no disponível em um determinado caminho* . Por exemplo, podemos armazenar o par _foo = bar_ no caminho _/secret/my-application. _
Posteriormente, usamos o mesmo caminho para recuperar o mesmo par ou pares - vários pares podem ser armazenados no mesmo caminho.
O Vault suporta três tipos de segredos de valor-chave:
-
Parâmetros-chave sem versão, em que as atualizações substituem os valores existentes
-
_ Pares de chaves alternados, _ que mantêm um número configurável de versões antigas
-
Cubbyhole, um tipo especial de pares de chaves sem versão cujos valores têm o escopo definido em um determinado token de acesso_ (mais sobre os que serão posteriormente).
Os segredos de valor-chave são estáticos por natureza, portanto não há conceito de expiração associada a eles. O principal caso de uso para esse tipo de segredo é armazenar credenciais para acessar sistemas externos, como chaves de API.
Nesses cenários, as atualizações de credenciais são um processo semi-manual, geralmente exigindo que alguém adquira novas credenciais e usando a linha de comando do Vault ou sua interface do usuário para inserir os novos valores.
4.2. Segredos gerados dinamicamente
Segredos dinâmicos são gerados dinamicamente pelo Vault quando solicitados por um aplicativo. O Vault suporta vários tipos de segredos dinâmicos, incluindo os seguintes:
-
Credenciais do banco de dados
-
Pares de chaves SSH
-
Certificados X.509
-
Credenciais da AWS
-
Contas de serviço do Google Cloud
-
Contas do Active Directory
Todos estes seguem o mesmo padrão de uso. Primeiro, configuramos o mecanismo secreto com os detalhes necessários para conectar-se ao serviço associado. Em seguida, definimos uma ou mais funções, que descrevem a criação secreta real.
Vamos usar o mecanismo secreto do banco de dados como exemplo. Primeiro, devemos configurar o Vault com todos os detalhes das conexões com o banco de dados do usuário, incluindo credenciais de um usuário preexistente com privilégios de administrador para criar novos usuários.
Em seguida, criamos uma ou mais funções (funções do Vault, não funções do banco de dados) contendo as instruções SQL reais usadas para criar um novo usuário. Geralmente, elas incluem não apenas a instrução de criação do usuário, mas também todas as instruções grant necessárias para acessar objetos de esquema (tabelas, visualizações e assim por diante).
*Quando um cliente acessa a API correspondente, o Vault cria um novo usuário temporário no banco de dados usando as instruções fornecidas e retorna suas credenciais* . O cliente pode usar essas credenciais para acessar o banco de dados durante o período definido pelo atributo de tempo de vida útil da função solicitada.
Quando uma credencial atingir o tempo de expiração, o Vault revogará automaticamente qualquer privilégio associado a esse usuário. Um cliente também pode solicitar ao Vault para renovar essas credenciais. O processo de renovação ocorrerá apenas se suportado pelo driver de banco de dados específico e permitido pela política associada.
4.3. Chaves criptográficas
Os mecanismos secretos do tipo lidam com funções criptográficas, como criptografia, descriptografia, assinatura e assim por diante. Todas essas operações usam chaves criptográficas geradas e armazenadas internamente pelo Vault . A menos que seja explicitamente solicitado, o Vault nunca exporá uma determinada chave criptográfica.
A API associada permite que os clientes enviem dados em texto sem formatação do Vault e recebam uma versão criptografada deles. O oposto também é possível: podemos enviar dados criptografados e recuperar o texto original.
Atualmente, existe apenas um mecanismo desse tipo: o mecanismo Transit. Esse mecanismo suporta tipos de chaves populares, como RSA e ECDSA, e também suporta _Convergent Encryption.
Por exemplo, podemos usar esse modo para criptografar números de cartão de crédito em uma tabela de log de transações. Com a criptografia convergente, toda vez que inserirmos uma nova transação, o valor do cartão de crédito criptografado seria o mesmo, permitindo o uso de consultas SQL regulares para geração de relatórios, pesquisa e assim por diante.
5. Configuração do Vault
Nesta seção, criaremos um ambiente de teste local para testar os recursos do Vault.
A implantação do Vault é simples: basta download do pacote que corresponde ao nosso sistema operacional e extrai seu executável (vault ou vault.exe no Windows) para algum diretório em nosso PATH. Este executável contém o servidor e também é o cliente padrão . Há também uma imagem oficial do Docker disponível, mas não a abordaremos aqui.
O Vault suporta um modo development, o que é bom para alguns testes rápidos e para se acostumar com sua ferramenta de linha de comando, mas é simplista demais para casos de uso reais: todos os dados são perdidos na reinicialização e o acesso à API usa HTTP simples .
Em vez disso, usaremos o armazenamento persistente baseado em arquivo e a configuração HTTPS para poder explorar alguns dos detalhes da configuração da vida real que podem ser uma fonte de problemas.
5.1. Iniciando o servidor Vault
O Vault usa um arquivo de configuração usando o formato HCL ou JSON. O arquivo a seguir define toda a configuração necessária para iniciar nosso servidor usando um armazenamento de arquivos e um certificado autoassinado:
storage "file" {
path = "./vault-data"
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "./src/test/vault-config/localhost.cert"
tls_key_file = "./src/test/vault-config/localhost.key"
}
Agora, vamos executar o Vault. Abra um shell de comando, vá para o diretório que contém nosso arquivo de configuração e execute este comando:
$ vault server -config ./vault-test.hcl
O Vault será iniciado e mostrará algumas mensagens de inicialização. Eles incluirão sua versão, alguns detalhes de configuração e o endereço em que a API está disponível. É isso aí - nosso servidor Vault está em funcionamento.
5.2. Inicialização do Vault
Nosso servidor do Vault agora está em execução, mas como essa é sua primeira execução, precisamos inicializá-lo.
Vamos abrir um novo shell e executar os seguintes comandos para conseguir isso:
$ export VAULT_ADDR=https://localhost:8200
$ export VAULT_CACERT=./src/test/vault-config/localhost.cert
$ vault operator init
Aqui, definimos algumas variáveis de ambiente, portanto, não precisamos transmiti-las ao Vault sempre como parâmetros:
-
VAULT_ADDR: URI base em que o servidor da API atenderá solicitações *VAULT_CACERT: caminho para a chave pública de certificado do nosso servidor
No nosso caso, usamos o VAULT_CACERT para que possamos usar o HTTPS para acessar a API do Vault. Precisamos disso porque estamos usando certificados autoassinados. Isso não seria necessário para ambientes de produção, onde geralmente temos acesso a certificados assinados pela CA.
Depois de emitir o comando acima, devemos ver uma mensagem como esta:
Unseal Key 1: <key share 1 value>
Unseal Key 2: <key share 2 value>
Unseal Key 3: <key share 3 value>
Unseal Key 4: <key share 4 value>
Unseal Key 5: <key share 5 value>
Initial Root Token: <root token value>
... more messages omitted
As cinco primeiras linhas são os compartilhamentos de chaves mestras que usaremos posteriormente para remover o armazenamento do Vault.* Observe que o Vault exibe apenas os compartilhamentos de chaves mestras durante a inicialização - e nunca mais. * Anote e guarde-os com segurança ou perderemos o acesso aos nossos segredos ao reiniciar o servidor!
Além disso, observe o root token, pois precisaremos mais tarde. Diferentemente das chaves não seladas, os tokens raiz podem ser gerados facilmente mais tarde ; portanto, é seguro destruí-lo quando todas as tarefas de configuração estiverem concluídas. Como emitiremos comandos posteriormente que requerem um token de autenticação, vamos salvar o token raiz por enquanto em uma variável de ambiente:
$ export VAULT_TOKEN=<root token value> (Unix/Linux)
Vamos ver o status do servidor agora que o inicializamos, com o seguinte comando:
$ vault status
Key Value
--- -----
Seal Type shamir
Sealed true
Total Shares 5
Threshold 3
Unseal Progress 0/3
Unseal Nonce n/a
Version 0.10.4
HA Enabled false
Podemos ver que o Vault ainda está selado. Também podemos acompanhar o progresso da vedação: “0/3” significa que o Vault precisa de três ações, mas não tem nenhuma até agora. Vamos seguir em frente e fornecer nossas ações.
5.3. Vault Unseal
Agora selamos o Vault para que possamos começar a usar seus serviços secretos. Precisamos fornecer três das cinco ações-chave para concluir o processo de remoção da vedação:
$ vault operator unseal <key share 1 value>
$ vault operator unseal <key share 2 value>
$ vault operator unseal <key share 3 value>
Após a emissão, cada cofre de comando imprimirá o progresso não selado, incluindo quantos compartilhamentos são necessários. Ao enviar o último compartilhamento de chave, veremos uma mensagem como esta:
Key Value
--- -----
Seal Type shamir
Sealed false
... other properties omitted
A propriedade "Selado" é "false" nesse caso, o que significa que o Vault está pronto para aceitar comandos.
6. Testando o Vault
Nesta seção, testaremos nossa configuração do Vault usando dois de seus tipos secretos suportados: Chave/Valor e Banco de dados. Também mostraremos como criar novos tokens com políticas específicas anexadas a eles.
6.1. Usando segredos de chave/valor
Primeiro, vamos armazenar pares secretos de valor-chave e lê-los novamente. Supondo que o shell de comando usado para inicializar o Vault ainda esteja aberto, usamos o seguinte comando para armazenar esses pares no caminho secret/fakebank:
$ vault kv put secret/fakebank api_key=abc1234 api_secret=1a2b3c4d
Agora podemos recuperar esses pares a qualquer momento com o seguinte comando:
$ vault kv get secret/fakebank
======= Data =======
Key Value
--- -----
api_key abc1234
api_secret 1a2b3c4d
Este teste simples mostra que o Vault está funcionando como deveria. Agora podemos testar algumas funcionalidades adicionais.
6.2. Criando novos tokens
Até o momento, usamos o token raiz para autenticar nossos pedidos. Como um token raiz é muito poderoso, é considerado uma prática recomendada usar tokens com menos privilégios e menor tempo de vida.
Vamos criar um novo token que possamos usar como o token raiz, mas expira em apenas um minuto:
$ vault token create -ttl 1m
Key Value
--- -----
token <token value>
token_accessor <token accessor value>
token_duration 1m
token_renewable true
token_policies ["root"]
identity_policies []
policies ["root"]
Vamos testar esse token, usando-o para ler os pares de chave/valor que criamos antes:
$ export VAULT_TOKEN=<token value>
$ vault kv get secret/fakebank
======= Data =======
Key Value
--- -----
api_key abc1234
api_secret 1a2b3c4d
Se esperarmos um minuto e tentarmos reemitir esse comando, receberemos uma mensagem de erro:
$ vault kv get secret/fakebank
Error making API request.
URL: GET https://localhost:8200/v1/sys/internal/ui/mounts/secret/fakebank
Code: 403. Errors:
* permission denied
A mensagem indica que nosso token não é mais válido, e é o que esperávamos.
6.3. Políticas de teste
O token de amostra que criamos na seção anterior teve vida curta, mas ainda é muito poderoso. Vamos agora usar políticas para criar tokens mais restritos.
Por exemplo, vamos definir uma política que permita apenas acesso de leitura ao caminho secret/fakebank que usamos anteriormente:
$ cat > sample-policy.hcl <<EOF
path "secret/fakebank" {
capabilities = ["read"]
}
EOF
$ export VAULT_TOKEN=<root token>
$ vault policy write fakebank-ro ./sample-policy.hcl
Success! Uploaded policy: fakebank-ro
Agora criamos um token com esta política com o seguinte comando:
$ export VAULT_TOKEN=<root token>
$ vault token create -policy=fakebank-ro
Key Value
--- -----
token <token value>
token_accessor <token accessor value>
token_duration 768h
token_renewable true
token_policies ["default" "fakebank-ro"]
identity_policies []
policies ["default" "fakebank-ro"]
Como fizemos antes, vamos ler nossos valores secretos usando este token:
$ export VAULT_TOKEN=<token value>
$ vault kv get secret/fakebank
======= Data =======
Key Value
--- -----
api_key abc1234
api_secret 1a2b3c4d
Por enquanto, tudo bem. Podemos ler dados, conforme o esperado. Vamos ver o que acontece quando tentamos atualizar esse segredo:
$ vault kv put secret/fakebank api_key=foo api_secret=bar
Error writing data to secret/fakebank: Error making API request.
URL: PUT https://127.0.0.1:8200/v1/secret/fakebank
Code: 403. Errors:
* permission denied
Como nossa política não permite explicitamente gravações, o Vault retorna um código de status 403 - Acesso negado.
6.4. Usando credenciais dinâmicas de banco de dados
Como nosso exemplo final neste artigo, vamos usar o mecanismo secreto de banco de dados do Vault para criar credenciais dinâmicas. Assumimos aqui que temos um servidor MySQL disponível localmente e que podemos acessá-lo com privilégios de "root". Também usaremos um esquema muito simples que consiste em uma única tabela - account.
O script SQL usado para criar esse esquema e o usuário privilegiado estão disponíveis aqui.
Agora, vamos configurar o Vault para usar este banco de dados. O mecanismo secreto do banco de dados não está ativado por padrão, portanto, devemos corrigir isso antes de podermos prosseguir:
$ vault secrets enable database
Success! Enabled the database secrets engine at: database/
Agora criamos um recurso de configuração de banco de dados:
$ vault write database/config/mysql-fakebank \
plugin_name=mysql-legacy-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/fakebank" \
allowed_roles="*" \
username="fakebank-admin" \
password="Sup&rSecre7!"
O prefixo do caminho database/config é o local em que todas as configurações do banco de dados devem ser armazenadas. Nós escolhemos o nome mysql-fakebank para que possamos descobrir facilmente a qual banco de dados essa configuração se refere. Quanto às chaves de configuração:
-
_plugin_name: _ Define qual plug-in de banco de dados será usado. Os nomes de plug-ins disponíveis estão descritos em docs do Vault
-
connection_url: este é um modelo usado pelo plug-in ao conectar-se ao banco de dados. Observe os espaços reservados do modelo \ {\ {nome de usuário}} e \ {\ {password}}. Ao se conectar ao banco de dados, o Vault substituirá esses espaços reservados pelos valores reais
-
allowed_roles: Defina quais funções do Vault (discutidas a seguir) podem usar essa configuração. No nosso caso, usamos "*", portanto está disponível para todas as funções
-
_username e senha: _ Essa é a conta que o Vault usará para executar operações do banco de dados, como criar um novo usuário e revogar seus privilégios
*Configuração da função de banco de dados do Vault*
A tarefa de configuração final é criar um recurso de função de banco de dados do Vault que contenha os comandos SQL necessários para criar um usuário. Podemos criar quantas funções forem necessárias, de acordo com nossos requisitos de segurança.
Aqui, criamos uma função que concede acesso somente leitura a todas as tabelas do esquema fakebank:
$ vault write database/roles/fakebank-accounts-ro \
db_name=mysql-fakebank \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON fakebank.* TO '{{name}}'@'%';"
O mecanismo do banco de dados define o prefixo do caminho database/functions como o local para armazenar funções. fakebank-accounts-ro é o nome da função que usaremos posteriormente ao criar credenciais dinâmicas. Nós também fornecemos as seguintes chaves:
-
db_name: nome de uma configuração de banco de dados existente. Corresponde à última parte do caminho que usamos ao criar o recurso de configuração
-
_creation_statements: _ Uma lista de modelos de instrução SQL que o Vault usará para criar um novo usuário
*Criando credenciais dinâmicas*
Assim que tivermos uma função de banco de dados e sua configuração correspondente pronta, geramos novas credenciais dinâmicas com o seguinte comando:
$ vault read database/creds/fakebank-accounts-ro
Key Value
--- -----
lease_id database/creds/fakebank-accounts-ro/0c0a8bef-761a-2ef2-2fed-4ee4a4a076e4
lease_duration 1h
lease_renewable true
password <password>
username <username>
O prefixo database/creds é usado para gerar credenciais para as funções disponíveis. Como usamos a função fakebank-accounts-ro , o nome de usuário/senha retornados serão restritos às operações select.
Podemos verificar isso conectando-se ao banco de dados usando as credenciais fornecidas e executando alguns comandos SQL:
$ mysql -h 127.0.0.1 -u <username> -p fakebank
Enter password:
MySQL [fakebank]> select * from account;
... omitted for brevity
2 rows in set (0.00 sec)
MySQL [fakebank]> delete from account;
ERROR 1142 (42000): DELETE command denied to user 'v-fake-9xoSKPkj1'@'localhost' for table 'account'
*Podemos ver que o primeiro _select_ foi concluído com êxito, mas não foi possível executar a instrução _delete_* . Por fim, se esperarmos uma hora e tentarmos conectar usando essas mesmas credenciais, não poderemos mais nos conectar ao banco de dados. O Google Apps Vault revogou automaticamente todos os privilégios deste usuário
7. Conclusão
Neste artigo, exploramos os conceitos básicos do Vault do Hashicorp, incluindo alguns antecedentes sobre o problema que ele tenta solucionar, sua arquitetura e uso básico.
Ao longo do caminho, criamos um ambiente de teste simples, mas funcional, que usaremos nos artigos a seguir.
O próximo artigo abordará um caso de uso muito específico para o Vault: Utilizando-o no contexto do aplicativo Spring Boot . Fique ligado!