Part 1: Docker & Vault Agent

Part 2: Docker & Vault Agent with Dynamic Secrets

Part 3: Docker & Vault Agent with Docker Compose

Terraform

Sve prethodne dijelove ovog serijala smo pratili kroz izvršavanje naredbi u terminalu međutim, kao i u svim slučajevima, takav pristup je podložan pogreškama te bi bilo smislenije koristiti neki orkestrator tipa Hashicorp Terraform.

Preuzmite repozitorij na adresi https://github.com/myros/docker-vault-agent-terraform

git clone https://github.com/myros/docker-vault-agent-terraform

Repozitorij sadrži sve potrebno za praćenje ovog teksta stoga ga ne treba dodatno modificirati.

Spin up Vault

Prvo pokrenemo Vault container na slijedeći način:

terraform apply --target=docker_container.vault

Nakon planiranja i prikaza promjena, Terraform će tražiti potvrdu da se slažete sa izvršavanjem te će pokrenuti Vault container i pripremiti policu koju ćemo koristiti kasnije. Terraform log izgleda ovako:

...
Plan: 2 to add, 0 to change, 0 to destroy.
docker_network.private_network: Creating...
docker_network.private_network: Creation complete after 2s [id=f7640502520b3ad38c980122f033545140f8549b4742c42f4f2b284f7d7cd3fa]
docker_container.vault: Creating...
docker_container.vault: Creation complete after 0s [id=b2c1587c05189f4e68d5750d4d98a116d4993d559243ec71ded56e5f71799664]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Možete provjeriti da je Docker container zaista pokrenut

$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                     PORTS                    NAMES
b2c1587c0518   6a1ffdd512ce   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (unhealthy)   0.0.0.0:8200->8200/tcp   vault

a možemo se i prijaviti u UI na adresi http://localhost:8200 sa tokenom root

Vault Agent i Baze

Nakon što se uvjerimo da je sve ok, pokrenimo ostale dijelove.

terraform apply --auto-approve

Nakon izvršavanja pogledajmo stanje

$ docker ps

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                     PORTS                    NAMES
8607daf84720   6a1ffdd512ce   "docker-entrypoint.s…"   38 seconds ago   Up 36 seconds              8200/tcp                 vault-agent
cb57659215a9   30873abfecef   "docker-entrypoint.s…"   38 seconds ago   Up 36 seconds              3306/tcp, 33060/tcp      mysql
06706c1b09cc   080ed0ed8312   "/docker-entrypoint.…"   38 seconds ago   Up 37 seconds              0.0.0.0:80->80/tcp       nginx
596f2a7c7ff5   236fd2f7b949   "docker-entrypoint.s…"   38 seconds ago   Up 36 seconds              5432/tcp                 postgres
b2c1587c0518   6a1ffdd512ce   "docker-entrypoint.s…"   5 minutes ago    Up 5 minutes (unhealthy)   0.0.0.0:8200->8200/tcp   vault

Vidimo da je sve u redu, baze su prisutne i agent je ovdje.

Napomena: Ukoliko dobijete slijedeću pogrešku, pričekajte par sekundi i izvršite terraform apply ponovo. Radi se samo o tome da baza nije spremna ali će biti dovoljno brzo da ne treba čekati predugo.

 Error: error configuring database connection "mysql/config/items": Error making API request.

URL: PUT http://localhost:8200/v1/mysql/config/items
Code: 400. Errors:

* error creating database object: error verifying - ping: dial tcp 172.21.0.3:3306: connect: connection refused

with vault_database_secrets_mount.mysql,
on main.tf line 258, in resource "vault_database_secrets_mount" "mysql":
258: resource "vault_database_secrets_mount" "mysql" {

Obzirom da datotke sadrže sve potrebno fokusirajmo se na Vault Agent i njegove logove.

$ docker logs -f vault-agent
==> Vault Agent started! Log data will stream in below:

==> Vault Agent configuration:

           Api Address 1: http://bufconn
                     Cgo: disabled
               Log Level: 
2023-04-17T17:26:00.859Z [INFO]  agent.sink.file: creating file sink
                 Version: Vault v1.13.1, built 2023-03-23T12:51:35Z
2023-04-17T17:26:00.864Z [INFO]  agent.sink.file: file sink configured: path=/tmp/.token mode=-rw-r--r--
             Version Sha: 4472e4a3fbcc984b7e3dc48f5a8283f3efe6f282

2023-04-17T17:26:00.864Z [INFO]  agent.template.server: starting template server
2023-04-17T17:26:00.864Z [INFO]  agent.auth.handler: starting auth handler
2023-04-17T17:26:00.864Z [INFO]  agent.sink.server: starting sink server
2023-04-17T17:26:00.864Z [INFO]  agent.auth.handler: authenticating
2023-04-17T17:26:00.864Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-17T17:26:00.865Z [INFO] (runner) creating watcher
2023-04-17T17:26:00.866Z [INFO]  agent.auth.handler: authentication successful, sending token to sinks
2023-04-17T17:26:00.866Z [INFO]  agent.auth.handler: starting renewal process
2023-04-17T17:26:00.866Z [INFO]  agent.sink.file: token written: path=/tmp/.token
2023-04-17T17:26:00.867Z [INFO]  agent.auth.handler: renewed auth token
2023-04-17T17:26:00.875Z [INFO]  agent.template.server: template server received new token
2023-04-17T17:26:00.875Z [INFO] (runner) stopping
2023-04-17T17:26:00.875Z [INFO] (runner) creating new runner (dry: false, once: false)
2023-04-17T17:26:00.875Z [INFO] (runner) creating watcher
2023-04-17T17:26:00.875Z [INFO] (runner) starting
2023-04-17T17:26:00.878Z [WARN] (view) vault.read(postgres/creds/nginx): vault.read(postgres/creds/nginx): Error making API request.


...


* unknown role: nginx (retry attempt 6 after "8s")
2023-04-17T17:26:16.641Z [WARN] (view) vault.read(postgres/creds/nginx): vault.read(postgres/creds/nginx): Error making API request.

URL: GET http://vault:8200/v1/postgres/creds/nginx
Code: 400. Errors:

* unknown role: nginx (retry attempt 7 after "16s")
2023-04-17T17:26:16.641Z [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: 400. Errors:

* unknown role: nginx (retry attempt 7 after "16s")

2023-04-17T17:26:32.654Z [INFO] (runner) rendered "/agent/psql.tmpl" => "/usr/share/nginx/html/psql.html"
2023-04-17T17:26:32.657Z [INFO] (runner) rendered "/agent/rails.tmpl" => "/usr/share/nginx/html/rails.yaml"
2023-04-17T17:26:32.661Z [INFO] (runner) rendered "/agent/mysql.tmpl" => "/usr/share/nginx/html/mysql.html"

Primjećujemo puno grešaka i puno prigovora od strane Agenta međutim na kraju vidimo 3 renderirane datoteke i ako pristupimo adresi http://localhost/kv.html vidjet ćemo podatke iz Vaulta.

Docker, Vault Agent & Vault Dynamic Secret Engine

U razgovoru s klijentima, uvijek preporučujem upotrebu Terraforma ispred ručnog izvršavanja naredbi ili upotrebe Postmana i to iz više razloga:

  • Open Source ili besplatna Cloud verzija je dovoljno moćna za većinu korisnika
  • Smanjuje se mogućnost pogreške ili zlouporabe te je kontrola nad izvršavanjem daleko veća
  • Kod se može nalaziti u repozitoriju (Github, Gitlab, …) pa uz standardne procedure smanjujemo mogućnost nehotične izmjene infrastrukture
  • Ako se kod nalazi u repozitoriju, možemo raditi Code Reviews
  • Ako koristimo Terraform Cloud (TFC), obično je postavljen tako da TFC ima veća korisnička prava nego sam korisnik
  • Povijest izvršavanja koju Vault nema, primjerice, izmjena police