Skip to content

Commit

Permalink
feat(db): add dynamic db credential mysql lab (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
FalcoSuessgott authored Nov 10, 2023
1 parent 4fc208e commit 38e4ef5
Show file tree
Hide file tree
Showing 20 changed files with 340 additions and 30 deletions.
16 changes: 11 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ fmt: ## fmt
terraform fmt -recursive -write .

.PHONY: bootstrap
bootstrap: ## boostrap cluster
@command -v terraform || echo "terraform not installed"
@command -v docker || echo "docker not installed"
@command -v minikube || echo "minikube not installed"

bootstrap: deps ## boostrap cluster
terraform init
terraform apply -target=module.minikube -auto-approve
terraform apply -auto-approve
Expand All @@ -22,6 +18,16 @@ bootstrap: ## boostrap cluster
teardown: ## teadown cluster
terraform destroy -auto-approve

.PHONY: deps
deps: ## verify required deps
@command -v terraform > /dev/null || echo "terraform not installed -> https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli"
@command -v docker > /dev/null || echo "docker not installed -> https://docs.docker.com/engine/install/"
@command -v minikube > /dev/null || echo "minikube not installed -> https://minikube.sigs.k8s.io/docs/start/"
@command -v vault > /dev/null || echo "vault not installed -> https://developer.hashicorp.com/vault/docs/install"
@command -v kubectl > /dev/null || echo "kubectl not installed -> https://kubernetes.io/docs/tasks/tools/install-kubectl-linux"
@command -v helm > /dev/null || echo "helm not installed -> https://helm.sh/docs/helm/helm_install/"
@command -v jq > /dev/null || echo "jq not installed -> https://jqlang.github.io/jq/download/"

.PHONY: cleanup
cleanup: ## cleanup
docker stop $(shell docker ps -aq) || true
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Please refer to the [documentation](https://falcosuessgott.github.io/hashicorp-v
* [x] [Vault Kubernetes Auth Method](https://falcosuessgott.github.io/hashicorp-vault-playground/minikube/) configured for Minikube
* [x] [External Secrets Manager](https://falcosuessgott.github.io/hashicorp-vault-playground/esm/)
* [x] [Vault Secrets operator](https://falcosuessgott.github.io/hashicorp-vault-playground/vso/)
* [x] [Vault Agent Injector](https://falcosuessgott.github.io/hashicorp-vault-playground/vai/)
* [x] [Certmanager](https://falcosuessgott.github.io/hashicorp-vault-playground/cm/)
* [ ] MySQL dynamic DB Credentials
* [x] MySQL dynamic DB Credentials
* [ ] Prometheus & Grafana + Vault Metrics
1 change: 0 additions & 1 deletion docs/d.md

This file was deleted.

126 changes: 126 additions & 0 deletions docs/databases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Dynamic MySQL Database Credentials

## Requirements
You can enable this lab by setting:

```
# terraform.tfvars
databases = {
enabled = true
mysql = true
}
```

You then can bootstrap the cluster using `make bootstrap`

## Overview
The following resources will be created:

1. A MySQL Container will be deployed
2. The Database secret engine will be enabled
3. The A MySQL Database Connection will be created
4. A Database Role pointing to that MySQL DB will be created

## Walkthrough
A MySQL DB has been configured:

```bash
# https://localhost/ui/vault/secrets/databases/show/mysql
$> vault read databases/config/mysql
Key Value
--- -----
allowed_roles [mysql]
connection_details map[connection_url:{{username}}:{{password}}@tcp(mysql:3306)/vault-playgound max_open_connections:2 username:root]
password_policy n/a
plugin_name mysql-database-plugin
plugin_version n/a
root_credentials_rotate_statements []
```

A MySQL Role has been created:

```bash
# https://localhost/ui/vault/secrets/databases/show/role/mysql?type=dynamic
$> vault read databases/roles/mysql
Key Value
--- -----
creation_statements [CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';]
credential_type password
db_name mysql
default_ttl 1m
max_ttl 0s
renew_statements []
revocation_statements []
rollback_statements []
```

You can now generate MySQL Credentials:

```bash
$> vault read databases/creds/mysql
Key Value
--- -----
lease_id databases/creds/mysql/fnkxlDtia5R3UcNHXICZY4Vn
lease_duration 1m
lease_renewable true
password edljV1npo5tiiQ3crT-A
username v-root-mysql-639DVnmggyE3xJE62i3
```

You can verify these credentials by using them:

```bash
$> mysql -h 127.0.0.1 -P 3306 -u v-root-mysql-639DVnmggyE3xJE62i3 --password=edljV1npo5tiiQ3crT-A
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.2.0 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

**The Credentials are automatically revoked after 60 seconds**

Verify root credentials:

```bash
$> mysql -h 127.0.0.1 -P 3306 -u root --password=root
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 8.2.0 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

Roate root credentials:

```bash
# https://localhost/ui/vault/secrets/databases/show/mysql
$> vault write -force databases/rotate-root/mysql
Success! Data written to: databases/rotate-root/mysql
```

Root Credentials are not working anymore:

```bash
$> mysql -h 127.0.0.1 -P 3306 -u root --password=root
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'172.16.10.1' (using password: YES)
```
2 changes: 1 addition & 1 deletion docs/vai.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ spec:
vault.hashicorp.com/agent-inject-secret-secrets.txt: 'vai/data/secrets'
vault.hashicorp.com/agent-inject-template-secrets.txt: |
{{- with secret "vai/data/secrets" -}}
{
{
"username": "{{ .Data.data.username }}",
"password": "{{ .Data.data.password }}"
}
Expand Down
2 changes: 1 addition & 1 deletion k8s-vault-agent-injector/terraform/kuard.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ resource "kubectl_manifest" "kuard" {
yaml_body = file("${path.module}/../files/kuard.yml")

depends_on = [helm_release.vai]
}
}
8 changes: 8 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ module "vault" {
depends_on = [module.tls]
}

module "database" {
count = var.databases.enabled ? 1 : 0

source = "./vault-database/terraform"

depends_on = [module.vault]
}

# Spin up a K8s Cluster
module "minikube" {
count = var.minikube.enabled ? 1 : 0
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ nav:
- Vault Secrets Operator: vso.md
- Vault Agent Injector: vai.md
- Cert Manager: cm.md
- Dynamic Database Credentials: databases.md

markdown_extensions:
- pymdownx.superfences:
Expand Down
8 changes: 8 additions & 0 deletions output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ output "ca_cert" {
output "minikube_ip" {
value = module.minikube[0].minikube_ip
}

output "root_token" {
value = module.vault.root_token
}

output "unseal_keys" {
value = module.vault.unseal_keys
}
8 changes: 8 additions & 0 deletions terraform.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ vault = {
}
}

# Dyanmic DB Credentials
databases = {
enabled = true

# enable mysql db
mysql = true
}

# Minikube Configuration
minikube = {
# wether to enable minikube deployment
Expand Down
60 changes: 46 additions & 14 deletions tests/e2e.tftest.hcl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 1. only create vault and tls resources
# only create vault and tls resources
run "setup_vault" {
plan_options {
target = [
Expand All @@ -7,12 +7,12 @@ run "setup_vault" {
}
}

# 2. execute helper module to check http code of Vault URL
# execute helper module to check http code of Vault URL
run "vault_is_initialized" {
command = plan

module {
source = "./tests/http_get"
source = "./tests/http"
}

variables {
Expand All @@ -37,7 +37,39 @@ run "vault_is_initialized" {
}
}

# 3. create only minikube
# create database
run "setup_database" {
plan_options {
target = [
module.database
]
}
}

# check kuard demo app is tls secured
run "mysql_user_is_created" {
command = plan

module {
source = "./tests/http"
}

variables {
ca_cert = run.setup_vault.ca_cert
insecure = null
header = {
"X-Vault-Token" = run.setup_vault.root_token
}
url = "https://127.0.0.1/v1/databases/creds/mysql"
}

assert {
condition = data.http.request.status_code == 200
error_message = "Error while generating MySQL Credentials (Want: 200, Got:${data.http.request.status_code})."
}
}

# create only minikube
run "setup_minikube" {
plan_options {
target = [
Expand All @@ -46,12 +78,12 @@ run "setup_minikube" {
}
}

# 4. check if KubeAPI URL is available
# check if KubeAPI URL is available
run "kubeapi_is_available" {
command = plan

module {
source = "./tests/http_get"
source = "./tests/http"
}

variables {
Expand All @@ -64,7 +96,7 @@ run "kubeapi_is_available" {
}
}

# 5. run esm
# run esm
run "setup_esm" {
plan_options {
target = [
Expand All @@ -73,7 +105,7 @@ run "setup_esm" {
}
}

# 6. check if ESM Secret has been created
# check if ESM Secret has been created
run "esm_secret_is_created" {
command = plan

Expand All @@ -91,7 +123,7 @@ run "esm_secret_is_created" {
}
}

# 7. run vso
# run vso
run "setup_vso" {
plan_options {
target = [
Expand All @@ -100,7 +132,7 @@ run "setup_vso" {
}
}

# 8. check if VSO Secret has been created
# check if VSO Secret has been created
run "vso_secret_is_created" {
command = plan

Expand Down Expand Up @@ -128,12 +160,12 @@ run "setup_cm" {
}
}

# 10. check kuard demo app is tls secured
# check kuard demo app is tls secured
run "kuard_verifies_using_ca_cert" {
command = plan

module {
source = "./tests/http_get"
source = "./tests/http"
}

variables {
Expand All @@ -148,7 +180,7 @@ run "kuard_verifies_using_ca_cert" {
}
}

# 11. setup vault agent injector
# setup vault agent injector
run "setup_vai" {
plan_options {
target = [
Expand All @@ -157,7 +189,7 @@ run "setup_vai" {
}
}

# 12. check if vai injected secrets into pod
# check if vai injected secrets into pod
run "vai_secret_is_injected" {
command = plan

Expand Down
Loading

0 comments on commit 38e4ef5

Please sign in to comment.