Part 3: Docker & Vault Agent with Docker Compose
Part 4: Docker, Vault Agent with Terraform
U prethodnom dijelu smo pisali o povezivanju Vault, Vault Agenta i Docker, ali sa statičnim, KV2 podacima. Logičan nastavak je uvrstiti i primjer dinamički kreiranih podataka poput korisničkog računa za bazu podataka.
Provjerimo da su Vault i Nginx pokrenuti, zaustavimo Vault Agent kontejner (CTRL-C) te pokrenimo Postgres kontejner.
$ docker run -it --net=vault --name=postgres -e POSTGRES_DB=products -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=pass -p 5432:5432 hashicorpdemoapp/product-api-db:v0.0.22
Vault: Database Secret Engine (PostgreSQL)
$ vault secrets enable -path=postgres database
Success! Enabled the database secrets engine at: postgres/
$ vault write postgres/config/products \
plugin_name=postgresql-database-plugin \
allowed_roles="*" \
connection_url="postgresql://{{username}}:{{password}}@postgres:5432/products?sslmode=disable" \
username="postgres" \
password="pass"
Success! Data written to: postgres/config/products
Nakon što je konekcija ostvarena, možemo kreirati role koje smiju koristiti ovu konekciju. Potrebna nam je samo jedna, koju ćemo nazvati nginx.
$ vault write postgres/roles/nginx \
db_name=products \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\"" \
default_ttl="30m" \
max_ttl="24h"
Pokušajmo generirati korisničke podatke:
$ vault read postgres/creds/nginx
Key Value
--- -----
lease_id postgres/creds/nginx/eT9YrTgR8F9mKybwiWskWrlL
lease_duration 30m
lease_renewable true
password P7KUBJ-1WueV8m9Zb9O8
username v-token-nginx-AM2KIHBDw7XSQchZBE8i-1681239818
Prijavimo se u psql pomoću tih podataka
$ export PGPASSWORD=P7KUBJ-1WueV8m9Zb9O8
$ psql -h localhost -U v-token-nginx-AM2KIHBDw7XSQchZBE8i-1681239818 -d products -c "select id, name from coffees"
id | name
----+---------------------
1 | HCP Aeropress
2 | Packer Spiced Latte
3 | Vaulatte
4 | Nomadicano
5 | Terraspresso
6 | Vagrante espresso
7 | Connectaccino
8 | Boundary Red Eye
9 | Waypointiato
(9 rows)
Ovo je divno, dinamički kreiran korisnik sa pripadajućom šifrom, koji ima pristup samo određenoj bazi, divota. Znači, Vault je kreirao korisnika u bazi, dodijelio mu šifru i obrisati će ga nakon što mu istekne vrijeme trajanja (TTL). Pomoću creation_statement možemo ograničiti njegov pristup određenim bazama ili čak samo nekim tablicama upotrebljavajući SQL.
Vault: Database Secret Engine (MySQL/MariaDB)
$ docker run --net=vault --name mysql -e MYSQL_ROOT_PASSWORD=pass mysql
$ vault secrets enable -path=mysql database
Success! Enabled the database secrets engine at: mysql/
$ vault write mysql/config/items \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(mysql:3306)/" \
allowed_roles="my-role" \
username="root" \
password="pass"
Success! Data written to: mysql/config/nginx
$ vault write mysql/roles/nginx \
db_name=itemcollection \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';" \
default_ttl="1h" \
max_ttl="24h"
$ vault read mysql/creds/nginx
Key Value
--- -----
lease_id mysql/creds/nginx/4p9RdInQU6yQJrewzcIiCYwD
lease_duration 1h
lease_renewable true
password F5xPhvB9CNWymaa7DoL-
username v-token-nginx-o1V7sOhWKMl3WKAbnl
$ mysql -h 127.0.0.1 -u v-token-nginx-o1V7sOhWKMl3WKAbnl -pF5xPhvB9CNWymaa7DoL- itemcollection -e "select * from items"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+----------+
| id | name |
+----+----------+
| 1 | bike |
| 2 | baseball |
| 3 | chair |
+----+----------+
Vault Agent & Dynamic Secrets
Pripremimo dvije nove datoteke (./agent/psql.tmpl i ./agent/mysql.tmpl) i ubacimo slijedeće za PostgreSQL
{{ with secret "postgres/creds/nginx" -}}
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css">
</head>
<body>
<main>
<h4>Secret path: postgres/creds/nginx, Policy: nginx-agent-policy</h4>
<ul>
<ul><li><strong>Connection String</strong>: postgresql://{{ .Data.username }}:{{ .Data.password }}@postgres:5432/products</li>
<li><strong>username:</strong> {{ .Data.username }}</li>
<li><strong>password:</strong> {{ .Data.password }}</li>
</ul>
<h4>Vault commands</h4>
<pre><code>
vault read postgres/creds/nginx
vault lease renew postgres/creds/nginx/lease_id
vault lease revoke postgres/creds/nginx/lease_id
vault policy read nginx
</code></pre></div>
</main>
</body></html>
{{- end }}
i MySql:
{{ with secret "mysql/creds/nginx" -}}
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css">
</head>
<body>
<main>
<h4>Secret path: mysql/creds/nginx, Policy: nginx-agent-policy</h4>
<ul>
<ul><li><strong>Connection String</strong>: {{.Data.username}}:{{.Data.password}}@tcp(mysql:3306)</li>
<li><strong>username:</strong> {{ .Data.username }}</li>
<li><strong>password:</strong> {{ .Data.password }}</li>
</ul>
<h4>Vault commands</h4>
<pre><code>
vault read mysql/creds/nginx
vault lease renew mysql/creds/nginx/lease_id
vault lease revoke mysql/creds/nginx/lease_id
vault policy read nginx-agent-policy
</code></pre></div>
</main>
</body></html>
{{- end }}
Nakon toga, moramo proširiti konfiguraciju Vault Agenta da bude informiran i o novim datotekama koje treba generirati ./agent/config.hcl
template {
source = "/agent/kv.tmpl"
destination = "/usr/share/nginx/html/kv.html"
}
template {
source = "/agent/psql.tmpl"
destination = "/usr/share/nginx/html/psql.html"
}
template {
source = "/agent/mysql.tmpl"
destination = "/usr/share/nginx/html/mysql.html"
}
Pokrenimo Vault Agent
$ docker run --cap-add IPC_LOCK -v $PWD/agent:/agent -v $PWD/nginx:/usr/share/nginx/html --net vault vault vault agent -config=/agent/config.hcl
==> Vault Agent started! Log data will stream in below:
==> Vault Agent configuration:
Api Address 1: http://bufconn
Cgo: disabled
Log Level:
Version: Vault v1.13.1, built 2023-03-23T12:51:35Z
Version Sha: 4472e4a3fbcc984b7e3dc48f5a8283f3efe6f282
2023-04-11T20:06:52.704Z [INFO] agent.sink.file: creating file sink
2023-04-11T20:06:52.704Z [INFO] agent.sink.file: file sink configured: path=/agent/.token mode=-rw-r--r--
2023-04-11T20:06:52.704Z [INFO] agent.template.server: starting template server
2023-04-11T20:06:52.704Z [INFO] agent.sink.server: starting sink server
2023-04-11T20:06:52.704Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-11T20:06:52.704Z [INFO] agent.auth.handler: starting auth handler
2023-04-11T20:06:52.704Z [INFO] agent.auth.handler: authenticating
2023-04-11T20:06:52.705Z [INFO] (runner) creating watcher
2023-04-11T20:06:52.706Z [INFO] agent.auth.handler: authentication successful, sending token to sinks
2023-04-11T20:06:52.706Z [INFO] agent.auth.handler: starting renewal process
2023-04-11T20:06:52.706Z [INFO] agent.template.server: template server received new token
2023-04-11T20:06:52.706Z [INFO] (runner) stopping
2023-04-11T20:06:52.706Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-11T20:06:52.706Z [INFO] agent.sink.file: token written: path=/agent/.token
2023-04-11T20:06:52.706Z [INFO] (runner) creating watcher
2023-04-11T20:06:52.706Z [INFO] (runner) starting
2023-04-11T20:06:52.707Z [INFO] agent.auth.handler: renewed auth token
2023-04-11T20:06:52.710Z [WARN] vault.read(mysql/creds/nginx): failed to check if mysql/creds/nginx is KVv2, assume not: Error making API request.
URL: GET http://vault:8200/v1/sys/internal/ui/mounts/mysql/creds/nginx
Code: 403. Errors:
* preflight capability check returned 403, please ensure client's policies grant access to path "mysql/creds/nginx/"
2023-04-11T20:06:52.711Z [WARN] (view) vault.read(mysql/creds/nginx): vault.read(mysql/creds/nginx): Error making API request.
URL: GET http://vault:8200/v1/mysql/creds/nginx
Code: 403. Errors:
* 1 error occurred:
* permission denied
Odmah na početku, pojavljuje se greška u Vault Agentu. Ako se sjećate, u prvom dijelu smo kreirali policu koja nam dozvoljava samo 2 stvari: čitanje KV2 nginx i postgres credentials.
path "secret/data/nginx/*"
{
capabilities = ["create", "read", "update", "delete", "list"]
}
path "postgres/creds/nginx"
{
capabilities = ["read"]
}
# Read dynamic database secrets (mysql)
path "mysql/creds/nginx"
{
capabilities = ["read"]
}
Nakon toga izvršimo
$ vault policy write nginx-agent-policy ./policy.hcl
Success! Uploaded policy: nginx-agent-policy
i pokrenemo Vault Agent ponovo:
docker run --cap-add IPC_LOCK -v $PWD/agent:/agent -v $PWD/nginx:/usr/share/nginx/html --net vault vault vault agent -config=/agent/config.hcl
==> Vault Agent started! Log data will stream in below:
==> Vault Agent configuration:
Api Address 1: http://bufconn
Cgo: disabled
Log Level:
Version: Vault v1.13.1, built 2023-03-23T12:51:35Z
Version Sha: 4472e4a3fbcc984b7e3dc48f5a8283f3efe6f282
2023-04-11T20:10:50.411Z [INFO] agent.sink.file: creating file sink
2023-04-11T20:10:50.411Z [INFO] agent.sink.file: file sink configured: path=/agent/.token mode=-rw-r--r--
2023-04-11T20:10:50.411Z [INFO] agent.template.server: starting template server
2023-04-11T20:10:50.411Z [INFO] agent.sink.server: starting sink server
2023-04-11T20:10:50.411Z [INFO] agent.auth.handler: starting auth handler
2023-04-11T20:10:50.411Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-11T20:10:50.411Z [INFO] agent.auth.handler: authenticating
2023-04-11T20:10:50.412Z [INFO] (runner) creating watcher
2023-04-11T20:10:50.412Z [INFO] agent.auth.handler: authentication successful, sending token to sinks
2023-04-11T20:10:50.412Z [INFO] agent.auth.handler: starting renewal process
2023-04-11T20:10:50.412Z [INFO] agent.template.server: template server received new token
2023-04-11T20:10:50.412Z [INFO] (runner) stopping
2023-04-11T20:10:50.413Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-11T20:10:50.413Z [INFO] (runner) creating watcher
2023-04-11T20:10:50.413Z [INFO] agent.sink.file: token written: path=/agent/.token
2023-04-11T20:10:50.413Z [INFO] (runner) starting
2023-04-11T20:10:50.413Z [INFO] agent.auth.handler: renewed auth token
2023-04-11T20:10:50.426Z [INFO] (runner) rendered "/agent/psql.tmpl" => "/usr/share/nginx/html/psql.html"
2023-04-11T20:10:50.443Z [INFO] (runner) rendered "/agent/mysql.tmpl" => "/usr/share/nginx/html/mysql.html"
Primjećujete da je agent kreirao 2 nove datoteke: psql.html i mysql.html. Ovorimo ih u pregledniku:
Pogledajmo mysql.html stranicu
Dodatak: Rails database.yml
Ako kreiramo novi Vault Agent predložak (./agent/rails.tmpl) slijedećeg sadržaja:
{{ with secret "postgres/creds/nginx" -}}
development:
adapter: postgresql
database: products
host: localhost
port: 5432
username: {{ .Data.username }}
password: {{ .Data.password }}
{{- end }}
I u ./agent/config.hcl dodamo još jedan template blok:
template {
source = "/agent/rails.tmpl"
destination = "/usr/share/nginx/html/rails.yaml"
}
Ponovo pokrenimo Vault Agent i primjetit ćete da se kreirala nova datoteka rails.yaml koja je popunjena korisničkim podacima i kao takvu je Rails aplikacija normalno može koristiti.
development:
adapter: postgresql
database: products
host: localhost
port: 5432
username: v-approle-nginx-EOCjZfcNqVJ33aiDBMxp-1681247094
password: YhQ9vFzJG1H-omSmxNcf
Dodatak II:
Vault Agent Templates: https://developer.hashicorp.com/vault/docs/agent/template