Plugin Vault pour ArgoCD¶
Dans la logique GitOps, l'état de l'infrastructure et des applications est constamment défini dans les repository git qui est la source unique de vérité.
Néanmoins, un problème apparait quand il y a un besoin de passer des données sensibles (token, password, adresses, etc).
En terme de bonne pratique, stocker ces éléments dans le repository git, même si ce dernier est privé, n'est pas recommandé. Généralement, les secrets vont être stockés dans un coffre-fort (Vault en anglais).
ArgoCD a pour vocation à rester neutre vis-à-vis des solutions de passage de secrets dans les processus GitOps.
Néanmoins, ArgoCD reste ouvert aux extentions, ainsi qu'à l'utilisation de ressources spécialisées dans le passage de secrets.
La solution retenue dans notre cas est le plugin argocd-vault-plugin developpé par IBM.
Ce plugin permet de configurer dans des templates YAML, Helm ou Kustomize avec des <placeholder>
(les chevrons <
et >
délimitent les "secrets") qui seront instanciés par des valeurs venant d'un Vault Hashicorp.
Exemple de fonctionnement¶
Avant de décrire l'installation et la configuration du plugin, étudions un exemple d'usage du plugin Vault/ArgoCD, l'utilisation se fait en 3 étapes :
- Création du secret sur Vault ;
- Création d'une application sur ArgoCD ;
- Passage d'un manifeste contenant un
<placeholder>
.
Cette sous-partie de la documentation part du principe que le plugin et le vault sont déjà configurés.
Création du secret dans Vault¶
Il d'abord créer un secret sur le vault :
$ curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST --data '{ "data": {"token": "Nqd2SFJN1zef2"} }' http://127.0.0.1:8200/v1/secret/data/gitops/gitlab-monitoring/gitlab-token
token:Nqd2SFJN1zef2
est versé sur le chemin /secret/data/gitops/gitlab-token
du vault.
Création de l'application Vault¶
Ensuite, il faut créer une application ArgoCD via son CRD en y précisant l'emploi du plugin argocd-vault-plugin
:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: vault-plugin-test-app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
project: default
source:
path: .
repoURL: $ADDRESSE_REPOSITORY
targetRevision: HEAD
plugin:
name: argocd-vault-plugin
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Passage d'un manifeste avec secret¶
Pour finir, il faut ajouter dans le repository défini dans l'application à l'étape précédente, un manifeste YAML contenant les deux éléments nécessaires pour l'exécution du manifest :
- Une annotation
avp.kubernetes.io/path
avec en valeur le chemin du secret, dans notre cassecret/data/gitops/gitlab-token
; - Le
<placeholder>
où la valeur de ce dernier doit correspondre à la clef du secret passé au Vault, dans notre cas<token>
!
Ensuite, il faut créer une application ArgoCD via son CRD.
Voici un exemple de fichier YAML fonctionnant avec le plugin :
kind: Secret
apiVersion: v1
metadata:
name: example-secret
annotations:
avp.kubernetes.io/path: "secret/data/gitops/gitlab-token"
type: Opaque
stringData:
password: <token>
Configuration du Vault¶
Voici les étapes du configuration du vault pour fonctionner avec le plugin Vault/ArgoCD, ce n'est pas une configuration spécifique, le plugin s'intègre au Vault comme le ferait une application lambda, en utilisant un AppRole
.
Les étapes présentées couvrent la configuration globale du Vault (autorisation des AppRole
et activation du KeyValue
store).
Pour la configuration du Vault, il est nécessaire d'avoir accès à ce dernier
, ainsi que d'avoir les droits d'admin sur user/token/AppRole
avec les droits administrateur ou, a minima, les droits suivants si le Vault est déjà existant et que vous ne l'administrez pas :
- Création d'
AppRole
; - Création de Police de Sécurité ;
- Création de Secret KV ou KV2.
Résumé des Étapes¶
- Autorisation des
AppRole
s sur Vault ; - Activation du secret backend KV2 sur l'endpoint
/secret
; - Application de la politique de sécurité pour le rôle GitOps ;
- Création de l'
AppRole
GitOps ; - Récupération ID/Access Key pour l'
AppRole
GitOps ; - Création des secrets.
Avant de suivre la procédure, il faut exporter les variables d'environnement suivantes: VAULT_ADDR
qui contient l'adresse du Vault ainsi que VAULT_TOKEN
qui doit contenir un jeton avec des droits suffisant sur le Vault (Cf. supra pour les droits).
Il est aussi possible d'effectuer certaines des commandes ci-dessous en ligne de commandes du vault !
Autoriser AppRoles sur Vault¶
$ curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST --data '{"type": "approle"}'$VAULT_ADDR/v1/sys/auth/approle
Autoriser le secret backend KV sur l'endpoint souhaité¶
Cette commande s'effectue avec la ligne de commande :
$ vault secrets enable -version=2 -path=secret kv
Trouver équivalent en appels API
Création de la politique GitOps¶
Il faut créer une règle pour permettre au plugin de lire et lister les secrets (aucun droit supplémentaire n'est nécessaire pour ce faire).
Dans la politique ci-dessous, les droit de lecture et de listage sont alloués (["read","list"]
), sur tous les secrets du chemin /setcret/data/gitops/
sous le nom gitops-policy
.
Tous les secrets liés au GitOps seront sous le chemin /secret/data/gitops/
.
Le "sous-dossier" /data
est précisé car il est obligatoire dans l'API du storage KV2.
Configuration du fichier de la politique gitops-policy.hcl
:
path "/secret/data/gitops/*"
{
capabilities = ["read","list"]
}
Le fichier doit être convertit en JSON avant le versement, on utilise le script jsonify.sh
d'Erwan broquaire ou des solution de conversion sur le net comme celle-ci .
Il faut ensuite verser cette politique d'accès au Vault :
curl --header "X-Vault-Token: $VAULT_TOKEN" --request PUT --data "@gitops-policy.json" "$VAULT_ADDR/v1/sys/policies/acl/gitops-policy"
Il est ensuite possible d'interroger cette politique pour vérifier qu'elle a bien été appliquée :
curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST --data '{"policies": "gitops-policy"}' $VAULT_ADDR/v1/auth/approle/role/gitops-role
Création de l'AppRole Gitops¶
Il faut ensuite créer l'AppRole qui sera utilisé par le plugin pour interroger les secrets dans le Vault.
Dans l'exemple ci-dessous, le rôle créé porte le nom gitops-role
:
curl --header "X-Vault-Token: $VAULT_TOKEN" http://127.0.0.1:8200/v1/auth/approle/role/gitops-role
Il faut ensuite interroger le role-id
et le secret-id
qui seront utilisés pour obtenir un jeton pour interagir avec le vault :
curl --header "X-Vault-Token: $VAULT_TOKEN" http://127.0.0.1:8200/v1/auth/approle/role/gitops-role/role-id
curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST http://127.0.0.1:8200/v1/auth/approle/role/gitops-role/secret-id
Il faut garder ces éléments, il seront utilisés pour insertion dans le fichier de configuration.
Création du secret test¶
Un secret test est créé pour ce tutoriel, sous le chemin /secret/data/gitops/gitlab-monitoring/gitlab-token
, avec pour clef token
et en valeur Nqd2SFJN1zef2
(ce sont des variables test) :
curl --header "X-Vault-Token: $VAULT_TOKEN" --request POST --data '{ "data": {"token": "Nqd2SFJN1zef2"} }' $VAULT_ADDR/v1/secret/data/gitops/gitlab-monitoring/gitlab-token
Configuration du plugin Vault ArgoCD¶
Nous suivons la procédure définie par ArgoCD.
Il est soit possible de passer l'exécutable du plugin par un initContainer
et un EmptyDir
via la solution de déploiement utilisée (Helm ou Kustomize et
manifeste YAML), soit de construire sa propre image ArgoCD et l'utiliser dans le déploiement.
La première approche a été utilisée, car plus simple dans le déploiement et dans la gestion des mises-à-jour.
Voici la marche à suivre pour rendre un plugin disponible à ArgoCD (applicable à tout plugin qui se présente sous la forme d'un exécutable) :
- Création d'un
InitContainer
dans le déploiementargocd-repo-server
, qui télécharge la version souhaitée du plugin, et qui le passe dans unEmptyDir
; - L'exécutable du plugin est passé au container
argocd-repo-server
, via unvolumeMount
; - Le plugin est déclaré dans la configMap
argocd-cm
; - Les argument nécessaires au fonctionnement du plugin sont passés en variable d'environnement au pod
argocd-repo-server
; dans le cas du plugin vault, un secret avec les variables est créé.
Le déploiement du plugin via Helm et Kustomize seront décrite plus bas.
Mais il faut d'abord créer dans le cluster un secret qui va contenir les information de connexion au Vault qui va pouvoir être passé au pod argocd-repo-server
.
Copier le manifeste ci-dessous, configurer les variables et l'appliquer, dans l'espace de nommage qui va accueillir l'ArgoCD :
kind: Secret
apiVersion: v1
metadata:
name: argocd-vault-plugin-credentials
namespace: argocd
type: Opaque
stringData:
VAULT_ADDR: <Addresse du Vault>
AVP_TYPE: vault
AVP_AUTH_TYPE: approle
AVP_ROLE_ID: <Id du role>
AVP_SECRET_ID: <secret ID du Role>
Déploiement d'ArgoCD et du plugin vault via Helm¶
Il existe un repository Helm d'ArgoCD, maintenu par la communauté. Il est possible de déployer le plugin entièrement via une configuration du fichier values.yaml
du chart Helm.
Voici ce fichier configuré :
#Argocd Server Config
server:
config:
url: https://argocd.example.com
application.instanceLabelKey: argocd.argoproj.io/instance
configManagementPlugins: |- #Theses lines will append the argocd-vault-plugin in the configmap
- name: argocd-vault-plugin
generate:
command: ["argocd-vault-plugin"]
args: ["generate", "./"]
- name: argocd-vault-plugin-helm
generate:
command: ["sh", "-c"]
args: ["helm template . > all.yaml && argocd-vault-plugin generate all.yaml"]
- name: argocd-vault-plugin-kustomize
generate:
command: ["sh", "-c"]
args: ["kustomize build . > all.yaml && argocd-vault-plugin generate all.yaml"]
repoServer:
envFrom: #Thise line will mount the values of the secret in the repo server
- secretRef:
name: argocd-vault-plugin-credentials
volumeMounts: #Mounting the binary download by the initContainer in the main pod
- name: custom-tools
mountPath: /usr/local/bin/argocd-vault-plugin
subPath: argocd-vault-plugin
volumes: #Creation of an EmptyDir sha red by the initContainer and the repo-server container
- name: custom-tools
emptyDir: {}
initContainers: #Creation of an init container that download the binary
- name: download-tools
image: busybox
command: [sh, -c]
args:
- wget -O argocd-vault-plugin
https://github.com/IBM/argocd-vault-plugin/releases/download/v1.5.0/argocd-vault-plugin_1.5.0_linux_amd64
chmod +x argocd-vault-plugin && mv argocd-vault-plugin /custom-tools/
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
Il est néanmoins nécessaire de modifier quelques points avant d'appliquer :
repoServer/envFrom
: bien vérifier que le nom du secret correspond à celui créé à l'étape précédente ;repoServer/initContainer[0].args
: vérifier la version du binaire souhaitée, dans l'exemple ci-dessus, la version téléchargée est la v1.5.0.
Il est possible de rajouter des configurations au fichier values.yaml
ci-dessus.
Déploiement d'ArgoCD et du plugin Vault via Kustomize¶
Il est aussi possible de déployer le plugin Vault via l'utilisation de l'outil Kustomize, afin d'ajouter au manifeste d'ArgoCD les modifications à apporter.
Voici le lien du manifeste officiel d'installation maintenu par ArgoCD ; ce dernier déploie ArgoCD sans la haute disponibilité (ce qui n'est pas un point critique car ArgoCD ne possède aucune donnée), mais un manifeste compatible avec la haute disponibilité est ici .
Pour déployer via Kustomize, il faut définir les ressources à modifier, ainsi qu'un manifeste kustomization.yml
:
- argocd-cm-kustomize.yaml :
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
data:
configManagementPlugins: |-
- name: argocd-vault-plugin
generate:
command: ["argocd-vault-plugin"]
args: ["generate", "./"]
- name: argocd-vault-plugin-helm
generate:
command: ["sh", "-c"]
args: ["helm template . > all.yaml && argocd-vault-plugin generate all.yaml"]
- name: argocd-vault-plugin-kustomize
generate:
command: ["sh", "-c"]
args: ["kustomize build . > all.yaml && argocd-vault-plugin generate all.yaml"]
- argcd-repo-vault-kustomize.yaml :
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-repo-server
template:
spec:
containers:
- name: argocd-repo-server
volumeMounts:
- name: custom-tools
mountPath: /usr/local/bin/argocd-vault-plugin
subPath: argocd-vault-plugin
envFrom:
- secretRef:
name: argocd-vault-plugin-credentials
volumes:
- name: custom-tools
emptyDir: {}
initContainers:
- name: download-tools
image: alpine:3.8
command: [sh, -c]
args:
- >-
wget -O argocd-vault-plugin
https://github.com/IBM/argocd-vault-plugin/releases/download/v1.5.0/argocd-vault-plugin_1.5.0_linux_amd64 &&
chmod +x argocd-vault-plugin &&
mv argocd-vault-plugin /custom-tools/
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
automountServiceAccountToken: true
Il faut penser à vérifier et à configurer la version du plugin souhaité dans spec.template.spec.initContainer[0].args
ainsi que le nom du secret dans spec.template.spec.container[0].volumeMount
.
- kustomization.yml :
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
patchesStrategicMerge:
- argocd-repo-vault-plugin-kustomize.yaml
- argocd-cm-kustomize.yaml
Afin de vérifier le bon fonctionnement du kustomize, il est possible de créer des modèles pour les manifestes avec :
$ kubectl kustomize ./
Et ensuite de les appliquer avec :
$ kubectl apply -k ./
Les deux commandes précédentes sont appliquées dans le dossier où les trois manifestes décrits précédemment sont présents.