documentation and fmt
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
terraform {
|
terraform {
|
||||||
backend "gcs" {
|
backend "gcs" {
|
||||||
bucket = "arcodange-tf"
|
bucket = "arcodange-tf"
|
||||||
prefix = "tools/hashicorp_vault/main"
|
prefix = "tools/hashicorp_vault/main"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@ resource "vault_auth_backend" "kubernetes" {
|
|||||||
type = "kubernetes"
|
type = "kubernetes"
|
||||||
}
|
}
|
||||||
resource "vault_kubernetes_auth_backend_config" "config" {
|
resource "vault_kubernetes_auth_backend_config" "config" {
|
||||||
backend = vault_auth_backend.kubernetes.path
|
backend = vault_auth_backend.kubernetes.path
|
||||||
kubernetes_host = "https://kubernetes.default.svc:443"
|
kubernetes_host = "https://kubernetes.default.svc:443"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "vault_mount" "kvv2" {
|
resource "vault_mount" "kvv2" {
|
||||||
@@ -29,18 +29,18 @@ resource "vault_database_secret_backend_connection" "postgres" {
|
|||||||
|
|
||||||
postgresql {
|
postgresql {
|
||||||
connection_url = "postgresql://{{username}}:{{password}}@pgbouncer.tools:5432/postgres?sslmode=disable"
|
connection_url = "postgresql://{{username}}:{{password}}@pgbouncer.tools:5432/postgres?sslmode=disable"
|
||||||
username = var.POSTGRES_CREDENTIALS_EDITOR_USERNAME
|
username = var.POSTGRES_CREDENTIALS_EDITOR_USERNAME
|
||||||
password = var.POSTGRES_CREDENTIALS_EDITOR_PASSWORD
|
password = var.POSTGRES_CREDENTIALS_EDITOR_PASSWORD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resource "vault_mount" "transit" {
|
resource "vault_mount" "transit" {
|
||||||
path = "transit"
|
path = "transit"
|
||||||
type = "transit"
|
type = "transit"
|
||||||
description = "Pour le vault secret operator (vso) dans k3s en cas de redemarrage par exemple"
|
description = "Pour le vault secret operator (vso) dans k3s en cas de redemarrage par exemple"
|
||||||
# default_lease_ttl_seconds = 3600
|
# default_lease_ttl_seconds = 3600
|
||||||
# max_lease_ttl_seconds = 86400
|
# max_lease_ttl_seconds = 86400
|
||||||
}
|
}
|
||||||
resource "vault_transit_secret_backend_key" "vso_client_cache" {
|
resource "vault_transit_secret_backend_key" "vso_client_cache" {
|
||||||
backend = vault_mount.transit.path
|
backend = vault_mount.transit.path
|
||||||
@@ -49,17 +49,17 @@ resource "vault_transit_secret_backend_key" "vso_client_cache" {
|
|||||||
|
|
||||||
data "vault_policy_document" "vso_client_cache" {
|
data "vault_policy_document" "vso_client_cache" {
|
||||||
rule {
|
rule {
|
||||||
path = "${vault_mount.transit.path}/encrypt/${vault_transit_secret_backend_key.vso_client_cache.name}"
|
path = "${vault_mount.transit.path}/encrypt/${vault_transit_secret_backend_key.vso_client_cache.name}"
|
||||||
capabilities = ["create", "update"]
|
capabilities = ["create", "update"]
|
||||||
}
|
}
|
||||||
rule {
|
rule {
|
||||||
path = "${vault_mount.transit.path}/decrypt/${vault_transit_secret_backend_key.vso_client_cache.name}"
|
path = "${vault_mount.transit.path}/decrypt/${vault_transit_secret_backend_key.vso_client_cache.name}"
|
||||||
capabilities = ["create", "update"]
|
capabilities = ["create", "update"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resource "vault_policy" "vso_client_cache" {
|
resource "vault_policy" "vso_client_cache" {
|
||||||
name = "edit-vso-client-cache"
|
name = "edit-vso-client-cache"
|
||||||
policy = data.vault_policy_document.vso_client_cache.hcl
|
policy = data.vault_policy_document.vso_client_cache.hcl
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "vault_kubernetes_auth_backend_role" "vso" {
|
resource "vault_kubernetes_auth_backend_role" "vso" {
|
||||||
@@ -75,8 +75,8 @@ resource "vault_kubernetes_auth_backend_role" "vso" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module "app_policies" {
|
module "app_policies" {
|
||||||
source = "./modules/app_policy"
|
source = "./modules/app_policy"
|
||||||
for_each = var.applications
|
for_each = var.applications
|
||||||
name = each.value
|
name = each.value
|
||||||
gitea_app_id = var.gitea_app_id
|
gitea_app_id = var.gitea_app_id
|
||||||
}
|
}
|
||||||
197
hashicorp-vault/iac/modules/README.md
Normal file
197
hashicorp-vault/iac/modules/README.md
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# Modules
|
||||||
|
|
||||||
|
## app_policy
|
||||||
|
|
||||||
|
_Ce module à déclarer dans ce projet permet au projet subordonné de déclarer le module app_roles suivant._
|
||||||
|
|
||||||
|
Ce module Terraform associe un **projet Git** à un ensemble de ressources Vault :
|
||||||
|
- Une **policy `-ops`** pour la CI/CD du projet (dépôt Git).
|
||||||
|
- Une **policy `app`** pour le runtime applicatif (pods).
|
||||||
|
- Un **groupe Vault** lié au projet. (pour ajouter les utilisateurs vault associé à leur compte gitea)
|
||||||
|
- Un **rôle JWT Vault** lié à ton SCM (ex: Gitea).
|
||||||
|
- Les droits nécessaires pour gérer les rôles Kubernetes et Postgres associés au projet.
|
||||||
|
|
||||||
|
### 🚀 Usage
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
module "webapp_vault" {
|
||||||
|
source = "./modules/vault_project"
|
||||||
|
name = "webapp"
|
||||||
|
|
||||||
|
gitea_app_id = "my-gitea-oauth-app-id" # secret récupéré via vault dans la CI
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## app_roles
|
||||||
|
|
||||||
|
Ce module Terraform configure les rôles Vault nécessaires pour qu’une **application déployée dans Kubernetes** puisse :
|
||||||
|
- s’authentifier auprès de Vault via son `ServiceAccount`,
|
||||||
|
- obtenir des **identifiants Postgres dynamiques**,
|
||||||
|
- accéder à ses secrets dans Vault.
|
||||||
|
|
||||||
|
### 🚀 Usage
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
module "webapp_vault_app" {
|
||||||
|
source = "./modules/vault_app"
|
||||||
|
name = "webapp"
|
||||||
|
database = "mydb" # optionnel, par défaut = name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## principe
|
||||||
|
|
||||||
|
```lua
|
||||||
|
+-----------------+
|
||||||
|
| Dépôt Git |
|
||||||
|
| (CI/CD Terraform|
|
||||||
|
+--------+--------+
|
||||||
|
|
|
||||||
|
[Auth via Vault JWT Role]
|
||||||
|
|
|
||||||
|
+----------v-----------+
|
||||||
|
| Vault (Policy -ops) |
|
||||||
|
| - Peut gérer |
|
||||||
|
| - Roles K8s |
|
||||||
|
| - Roles Postgres|
|
||||||
|
| - Secrets KV |
|
||||||
|
+----------+-----------+
|
||||||
|
|
|
||||||
|
[Token éphémère CI/CD]
|
||||||
|
|
|
||||||
|
+----------------v----------------+
|
||||||
|
| Kubernetes API |
|
||||||
|
| - Applique CRDs / Secrets |
|
||||||
|
| - Configure Longhorn / RBAC |
|
||||||
|
+---------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------- Flux runtime ---------------------------
|
||||||
|
|
||||||
|
+-----------------+
|
||||||
|
| Pod App |
|
||||||
|
| (SA: webapp) |
|
||||||
|
+--------+--------+
|
||||||
|
|
|
||||||
|
[Auth via Vault K8s Role]
|
||||||
|
|
|
||||||
|
+----------v-----------+
|
||||||
|
| Vault (Policy app) |
|
||||||
|
| - Peut lire |
|
||||||
|
| - kvv2/data/... |
|
||||||
|
| - postgres/... |
|
||||||
|
+---------------------+
|
||||||
|
|
|
||||||
|
[Secrets dynamiques: PW DB, etc.]
|
||||||
|
|
|
||||||
|
+--------v---------+
|
||||||
|
| Postgres DB |
|
||||||
|
+------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
_documentation destinée aux dépots des applications:_
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🔑 Gestion des secrets avec Vault Secrets Operator (VSO)
|
||||||
|
|
||||||
|
Ce repository utilise [Vault Secrets Operator](https://developer.hashicorp.com/vault/docs/platform/k8s/vso) pour gérer les secrets de l’application (notamment les identifiants Postgres).
|
||||||
|
L’objectif est d’éviter de stocker des credentials statiques, en déléguant la génération et la rotation à HashiCorp Vault.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Architecture
|
||||||
|
|
||||||
|
1. **Terraform côté admin** configure Vault :
|
||||||
|
- un **backend Postgres** (`postgres/`) connecté à la base via pgbouncer,
|
||||||
|
- un **rôle Vault** `webapp` (`postgres/roles/webapp`) qui définit la manière dont les credentials dynamiques sont créés,
|
||||||
|
- un **rôle Kubernetes** `webapp` (`auth/kubernetes/role/webapp`) qui autorise le ServiceAccount `webapp` du namespace à s’authentifier auprès de Vault.
|
||||||
|
|
||||||
|
2. **L’application** (dans ce repo) déclare :
|
||||||
|
- un `VaultAuth` qui associe le **ServiceAccount `webapp`** au rôle Vault `webapp`,
|
||||||
|
- un `VaultDynamicSecret` qui demande un secret dynamique (`postgres/creds/webapp`),
|
||||||
|
- un `Secret` Kubernetes généré automatiquement par VSO (`vso-db-credentials`), injecté dans le Pod de l’application.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Ressources déployées
|
||||||
|
|
||||||
|
### `VaultAuth`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: secrets.hashicorp.com/v1beta1
|
||||||
|
kind: VaultAuth
|
||||||
|
metadata:
|
||||||
|
name: auth
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
method: kubernetes
|
||||||
|
mount: kubernetes
|
||||||
|
kubernetes:
|
||||||
|
role: webapp
|
||||||
|
serviceAccount: {{ include "webapp.serviceAccountName" . }}
|
||||||
|
audiences:
|
||||||
|
- vault
|
||||||
|
```
|
||||||
|
|
||||||
|
Permet à VSO (et donc à l’app) de s’authentifier auprès de Vault avec le rôle webapp.
|
||||||
|
|
||||||
|
VaultDynamicSecret
|
||||||
|
```yaml
|
||||||
|
apiVersion: secrets.hashicorp.com/v1beta1
|
||||||
|
kind: VaultDynamicSecret
|
||||||
|
metadata:
|
||||||
|
name: vso-db
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
mount: postgres
|
||||||
|
path: creds/webapp # chemin du rôle dynamique Postgres
|
||||||
|
destination:
|
||||||
|
create: true
|
||||||
|
name: vso-db-credentials
|
||||||
|
rolloutRestartTargets:
|
||||||
|
- kind: Deployment
|
||||||
|
name: {{ include "webapp.fullname" . }}
|
||||||
|
vaultAuthRef: auth
|
||||||
|
```
|
||||||
|
Demande un secret dynamique Postgres depuis Vault et le stocke dans un Secret Kubernetes nommé vso-db-credentials.
|
||||||
|
Le Deployment de l’app est redémarré automatiquement à chaque rotation de credentials.
|
||||||
|
|
||||||
|
📦 Consommation du secret
|
||||||
|
Une fois VSO en place, les credentials Postgres sont disponibles dans le Secret Kubernetes :
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: app
|
||||||
|
image: myapp:latest
|
||||||
|
env:
|
||||||
|
- name: DB_USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: vso-db-credentials
|
||||||
|
key: username
|
||||||
|
- name: DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: vso-db-credentials
|
||||||
|
key: password
|
||||||
|
````
|
||||||
|
|
||||||
|
🔄 Rotation
|
||||||
|
Vault génère des identifiants éphémères (par défaut TTL = 1h).
|
||||||
|
|
||||||
|
VSO renouvelle ou régénère automatiquement ces credentials.
|
||||||
|
|
||||||
|
Lorsqu’un nouveau secret est émis, le Deployment ciblé est redémarré pour recharger les variables d’environnement.
|
||||||
|
|
||||||
|
✅ Résumé
|
||||||
|
Pas de secrets stockés en clair dans Git ou Helm.
|
||||||
|
|
||||||
|
Rotation automatique des credentials Postgres.
|
||||||
|
|
||||||
|
Intégration fluide avec Kubernetes via ServiceAccounts.
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
terraform {
|
terraform {
|
||||||
required_providers {
|
required_providers {
|
||||||
vault = {
|
vault = {
|
||||||
source = "vault"
|
source = "vault"
|
||||||
version = "4.4.0"
|
version = "4.4.0"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider vault {
|
provider "vault" {
|
||||||
address = "https://vault.arcodange.duckdns.org"
|
address = "https://vault.arcodange.duckdns.org"
|
||||||
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
|
auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable
|
||||||
mount = "gitea_jwt"
|
mount = "gitea_jwt"
|
||||||
role = "gitea_cicd"
|
role = "gitea_cicd"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
applications = [
|
applications = [
|
||||||
"webapp",
|
"webapp",
|
||||||
"erp",
|
"erp",
|
||||||
]
|
]
|
||||||
@@ -2,11 +2,11 @@ variable "gitea_app_id" {
|
|||||||
type = string
|
type = string
|
||||||
}
|
}
|
||||||
variable "POSTGRES_CREDENTIALS_EDITOR_USERNAME" {
|
variable "POSTGRES_CREDENTIALS_EDITOR_USERNAME" {
|
||||||
type = string
|
type = string
|
||||||
sensitive = true
|
sensitive = true
|
||||||
}
|
}
|
||||||
variable "POSTGRES_CREDENTIALS_EDITOR_PASSWORD" {
|
variable "POSTGRES_CREDENTIALS_EDITOR_PASSWORD" {
|
||||||
type = string
|
type = string
|
||||||
sensitive = true
|
sensitive = true
|
||||||
}
|
}
|
||||||
variable "applications" {
|
variable "applications" {
|
||||||
|
|||||||
Reference in New Issue
Block a user