Draft: Add the possibility to use an external tool to manage secrets
L'idée de cette MR est de proposer des modifications permettant de gérer les secrets via un outil externe.
Objectifs :
- Ne jamais avoir de secrets stockés en clair
- Avoir le choix de l'outil de gestion des secrets
- Outils possibles (seul le 1er a été testé ;-))
- secret_manager.py https://gitlab.mim-libre.fr/frederic.lespez/secrets_manager
- HashiCorp Vault
- CyberArk Conjur
- Mozilla SOPS https://github.com/mozilla/sops
- Outils possibles (seul le 1er a été testé ;-))
- Minimiser le couplage entre EOLE3 et l'outil de gestion des secrets
- Dans le fichiers de configuration (fichiers
vars.ini
), les secrets seront remplacés par des tokens qui seront utilisés par l'outil identifier le secret correspondant. Le format du token est imposé par l'outil.- Exemple :
nextcloud_admin_password=my_best_password
=>nextcloud_admin_password=@@@@nextcloud_admin@@@@
- Exemple :
- L'outil doit accepter une chaîne de caractères en paramètre et envoyer sur la sortie standard (STDOUT) le contenu de la chaîne de caractères avec les tokens remplacés par les secrets correspondants. Autrement dit, l'outil doit se comporter comme une commande 'echo' améliorée remplaçant les tokens par les secrets correspondants
- Exemple d'utilisation dans un script shell:
- On transforme la déclaration d'une variable contenant un secret de la façon suivante :
adminPassword='mybestsecret'
=>adminPassword=$(secret_tool '@@@@nextcloud_admin@@@@')
- Lors de l'exécution la variable
adminPassword
sera initialisé avec le secretnextcloud_admin
- On transforme la déclaration d'une variable contenant un secret de la façon suivante :
- Exemple d'utilisation dans un script shell:
- L'outil doit lire un fichier (texte) passé en paramètre (
values.yaml
par exemple) et envoyer sur la sortie standard (STDOUT) le contenu du fichier avec les tokens remplacés par les secrets correspondants. Autrement dit, l'outil doit se comporter comme une commande 'cat' améliorée remplaçant les tokens par les secrets correspondants- Exemple d'utilisation avec
kubectl
:- On prépare le fichier
values.yaml
en remplaçant les secrets par des tokens - On transforme l'appel à
kubectl
de la manière suivante :kubectl apply -f values.yaml
=>secrets_tool values.yaml|kubectl apply -f -
- Lors de l'exécution, tous les tokens contenus dans le fichier
values.yaml
seront remplacés par les secrets correspondants et le résultat sera transmis àkubectl
à la volée (sans stockage sur disque).
- On prépare le fichier
- Exemple d'utilisation avec
- En particulier, le code EOLE3 n'a pas besoin de savoir où sont stockés les secrets, ni sous quelle forme, ni comment ils sont stockés, chiffrés ou déchiffrés.
- Dans le fichiers de configuration (fichiers
vars.ini
)
Configuration au niveau d'EOLE3 (fichier [secret_management]
enable=false
# Path to secret manager tool
tool_cmd=/path/to/secrets_manager
# Arguments to pass when processing a file containing secrets
tool_args_file=
# Arguments to pass when processing a string containing secrets
tool_args_string=
secret_manager.py
Exemple de mise en oeuvre avec l'outil - Dans un shell, déclarer une variable
SECRETS_MANAGER_MASTER_PASSWORD
contenant le "mot de passe maître" utilisé pour chiffrer/déchiffrer les secrets et l'exporterread -r -s -p "Enter your master password: " SECRETS_MANAGER_MASTER_PASSWORD export SECRETS_MANAGER_MASTER_PASSWORD
- Remplacer dans tous les fichiers
vars.ini
les secrets par défaut par des tokens (de la forme @@@@NOM_DU_SECRET@@@@)- Exemple :
adminUser=@@@@keycloak_admin@@@@
- Exemple :
- Dans le fichier
vars.ini
, paramétrer la sectionsecret_management
[secret_management] enable=true # Path to secret manager tool tool_cmd=/path/to/secret_handler.py # Arguments to pass when processing a file containing secrets tool_args_file=-s /path/to/file/secrets.yaml process-file # Arguments to pass when processing a string containing secrets tool_args_string=-s /path/to/file/secrets.yaml process-string
- Déployer EOLE3 comme d'habitude. Les secrets seront générés automatiquement et stockés chiffrés dans le fichier
/path/to/file/secrets.yaml
. - Les secrets peuvent être affichés avec la commande suivante
/chemin/vers/secret_handler.py -s /path/to/file/secrets.yaml display
Notes
- Certains secrets sont encodés (
urlencode
) par Jinja2 (lors de l'exécution de la commandebuild
). Comme l'outil de gestion des secrets s'exécute après (dans ledeploy
par exemple), le token ayant été encodé, il peut ne plus être reconnu par l'outil de gestion des secrets.- Pour éviter cela, l'encodage est fait au niveau de
curl
(paramètres--data-urlencode
). La variable peut alors être initialisée avec le secret non encodé.
- Pour éviter cela, l'encodage est fait au niveau de
- Si la MR !175 (merged) est acceptée, on pourra optimiser un peu le code en centralisant la définition des variables
ECHO
etCAT
.
Limitations
- Attention aux exécutions simultanées.
-
secrets_manager.py
ne gère pas l'exécution de plusieurs instances en simultané.
-
- Si les secrets comportent des caractères spéciaux ayant une signification particulière pour bash ou en YAML, cela peut provoquer des erreurs à l'exécution.
- Pour éviter cela, utiliser, par exemple, des secrets de 30 caractères de long, contenant uniquement des lettres minuscules, majuscules et des chiffres (comportement par défaut de
secrets_manager.py
).
- Pour éviter cela, utiliser, par exemple, des secrets de 30 caractères de long, contenant uniquement des lettres minuscules, majuscules et des chiffres (comportement par défaut de
- Attention si on utilise des commandes
helm
oukubectl
comportant plusieurs directives-f
-
secrets_manager.py
accepte plusieurs fichiers en paramètres (comme la commandecat
). Il faut juste s'assurer que les fichiersvalues.yaml
débute par une ligne---
pour qu'ils puissent être concaténés sans problème
-
Autre voie pour la gestion des secrets
- Centraliser tout les secrets dans un objet de type
Secret
(ou dérivé). Le fichier contenant le description de cet objet est chiffré intégralement ou alors seuls les secrets sont chiffrés. - Charger cet objet dans le cluster Kubernetes (en déchiffrant à la volée les secrets ou en utilisant un opérateur dans le cluster pour les déchiffrer à la demande (dans le cluster)
- Paramétrer tous les charts Helm pour utiliser le nom d'un secret existant au lieu d'utiliser un secret ou un mot de passe en dur
Exemple d'outil : sealed-secrets
https://github.com/bitnami-labs/sealed-secrets (anciennement kubeseal
)
Inconvénient : Tous les charts doivent offrir la possibilité de donner le nom d'un secret existant. Est-ce le cas de tous les charts ?