Introdução
No primeiro post relacionado a Data-at-Rest Parte 1, eu demonstrei como realizar a utilização do keyring_file, que funciona como esperado, mas ainda assim tem uma grande vulnerabilidade, no caso de acesso não autorizado ao servidor.
Neste segundo blog irei apresentar como externalizar as chaves com o keyring_vault, utilizando o OpenBao como vault. O OpenBao é um projeto open source de gerenciamento de segredos (key-values (KV), políticas, tokens, audit), criado a partir de um fork open source do HashiCorp Vault.
Ambiente
No exemplo abaixo, utilizarei dois servidores: um será o nosso OpenBao, que chamaremos de vault server, e o outro será a instalação do MySQL.
Não serão abordadas neste post a instalação e a inicialização do OpenBao. Realizaremos apenas as configurações necessárias para o MySQL.
Configuração
Após instalado e inicializado, vamos logar ao bao. Para isso, será necessária a senha root inicial.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ export BAO_ADDR='https://127.0.0.1:8200' $ bao login Token (will be hidden): Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "bao login" again. Future OpenBao requests will automatically use this token. Key Value --- ----- token s.EARTFqMzS0UMTUu6wl8Bj7v8 token_accessor Bv5zeDBccEpA2JsC4FOpXm79 token_duration ∞ token_renewable false token_policies ["root"] identity_policies [] policies ["root"] |
Após logar, iremos criar o secrets engine com path mysql-keyring e utilizando o key-value version 2:
|
1 2 |
$ bao secrets enable -path=mysql-keyring kv-v2 Success! Enabled the kv-v2 secrets engine at: mysql-keyring/ |
Tendo secrets engine criado, vamos criar a política para o Mysql Keyring, no exemplo abaixo damos acesso a alguns paths somente leitura, e para os paths relacionados à gravação e leitura de chaves damos acesso de leitura e escrita (metadata e data para prod/app/mysql01):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ bao policy write mysql-keyring_prod_app_mysql01 - <<'EOF' path "sys/mounts/mysql-keyring" { capabilities = ["read"] } path "mysql-keyring/config" { capabilities = ["read"] } path "mysql-keyring/data/prod/app/mysql01/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "mysql-keyring/metadata/prod/app/mysql01/*" { capabilities = ["list", "read", "delete"] } EOF Success! Uploaded policy: mysql-keyring_prod_app_mysql01 |
Após as políticas criadas, vamos criar o token para o uso no MySQL. Este é o token que será utilizado para configurar o keyring vault. Para criar, precisamos passar a política criada acima na criação do token:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ bao token create \ -policy=mysql-keyring_prod_app_mysql01 \ -ttl=768h \ -renewable=true \ -display-name="ps84/app/mysql01/keyring_vault" Key Value --- ----- token s.4CKGgpH6kYtb7StAihAPrBLP token_accessor rzP6Lx934jnGx1F7iv0rTvpX token_duration 768h token_renewable true token_policies ["default" "mysql-keyring_prod_app_mysql01"] identity_policies [] policies ["default" "mysql-keyring_prod_app_mysql01"] |
Configuração no MySQL
Assim como no keyring_file, precisamos criar o arquivo de manifesto em <basedir>/bin/mysqld.my (ex.: /usr/sbin/mysqld.my):
|
1 2 3 4 |
{ "read_local_manifest": false, "components": "file://component_keyring_vault" } |
Porém, note que, acima, o valor do campo components mudou para component_keyring_vault.
Adicionando as informações do OpenBao Vault no arquivo de configuração /usr/lib64/mysql/plugin/component_keyring_vault.cnf:
|
1 2 3 4 5 6 7 8 |
{ "timeout": 30, "vault_url": "https://172.19.0.3:8200", #Vault server IP "secret_mount_point": "mysql-keyring/prod/app/mysql01", # secrets from kv-v2 (mysql-keyring/) + sufixo policy (prod/app/mysql01). "secret_mount_point_version": "2", # Version 2 = kv-v2 "token": "s.4CKGgpH6kYtb7StAihAPrBLP", #Token created from the last bao command "vault_ca": "/var/lib/mysql/openbao-ca-chain.pem" #Se o TLS estiver ativo, será necessário passar o certificado } |
Corrigindo permissões e reiniciando MySQL
|
1 2 3 |
sudo chown mysql:mysql /usr/lib64/mysql/plugin/component_keyring_vault.cnf sudo chmod 0640 /usr/lib64/mysql/plugin/component_keyring_vault.cnf sudo systemctl restart mysql |
Validando integração
Componente ativo
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
MySQL > SELECT * FROM performance_schema.keyring_component_status; +----------------------------+-------------------------------------+ | STATUS_KEY | STATUS_VALUE | +----------------------------+-------------------------------------+ | Component_name | component_keyring_vault | | Author | Percona Corporation | | License | GPL | | Implementation_name | component_keyring_vault | | Version | 1.0 | | Component_status | Active | | timeout | 30 | | vault_url | https://node1:8200 | | secret_mount_point | mysql-keyring/prod/app/mysql01 | | vault_ca | /var/lib/mysql/openbao-ca-chain.pem | | secret_mount_point_version | 2 | +----------------------------+-------------------------------------+ 11 rows in set (0.00 sec) |
Esperado: Component_name = component_keyring_vault, Status = Active, Vault_url e Secret_mount_point corretos.
Sanity check no OpenBao
Após o MySQL materializar chaves (ex.: ALTER INSTANCE ROTATE INNODB MASTER KEY), podemos ver que a chave foi criada no bao:
|
1 2 3 4 |
bao kv list -mount=mysql-keyring prod/app/mysql01/ Keys ---- NDhfSU5OT0RCS2V5LTIzYTk5NmEzLTU2ZTAtMTFmMS05MGUwLWI2NjAyM2JkMmM5Ny0xMF8= |
Sanity check no MySQL similar ao do blog post anterior
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
MySQL > ALTER INSTANCE ROTATE INNODB MASTER KEY; Query OK, 0 rows affected (0.01 sec) MySQL > CREATE DATABASE lab; Query OK, 1 row affected (0.00 sec) MySQL > USE lab; Database changed MySQL > MySQL > CREATE TABLE pii ( id BIGINT PRIMARY KEY AUTO_INCREMENT, cpf CHAR(11), email VARCHAR(255) ) ENGINE=InnoDB ENCRYPTION='Y'; Query OK, 0 rows affected (0.04 sec) MySQL > INSERT INTO pii (cpf, email) VALUES Query OK, 1 row affected (0.01 sec) MySQL > CREATE TABLE pii2 ( id BIGINT PRIMARY KEY AUTO_INCREMENT, cpf CHAR(11), email VARCHAR(255) ) ENGINE=InnoDB ; Query OK, 0 rows affected (0.01 sec) MySQL > INSERT INTO pii2 (cpf, email) VALUES Query OK, 1 row affected (0.00 sec) |
Checando create_options de cada tabela:
|
1 2 3 4 5 6 7 8 |
MySQL > SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS FROM information_schema.TABLES WHERE TABLE_SCHEMA='lab'; +--------------+------------+----------------+ | TABLE_SCHEMA | TABLE_NAME | CREATE_OPTIONS | +--------------+------------+----------------+ | lab | pii | ENCRYPTION='Y' | | lab | pii2 | | +--------------+------------+----------------+ 2 rows in set (0.00 sec) |
Realizando teste do blog anterior para chegar à criptografia dos dados:
|
1 2 3 4 5 |
$ strings /var/lib/mysql/lab/pii.ibd | grep 12345678901 || echo "Sem match (esperado)" Sem match (esperado) $ strings /var/lib/mysql/lab/pii2.ibd | grep 12345678901 || echo "Sem match (esperado)" 12345678901dba@example.com |
Rotacionando a chave de criptografia
|
1 2 |
mysql> ALTER INSTANCE ROTATE INNODB MASTER KEY; Query OK, 0 rows affected (0.01 sec) |
Verificando se há uma nova chave no Opan Bao:
|
1 2 3 4 5 |
$ bao kv list -mount=mysql-keyring prod/app/mysql01/ Keys ---- NDhfSU5OT0RCS2V5LTIzYTk5NmEzLTU2ZTAtMTFmMS05MGUwLWI2NjAyM2JkMmM5Ny0xMF8= NDhfSU5OT0RCS2V5LTIzYTk5NmEzLTU2ZTAtMTFmMS05MGUwLWI2NjAyM2JkMmM5Ny0yMF8= |
Conclusão
keyring_vault component + OpenBao é um caminho mais seguro e mais próximo de produção para data-at-rest no MySQL/Percona Server 8.4. Evita situações em que haja acesso não autorizado aos arquivos do banco de dados, o que dificulta a leitura direta dos arquivos.





