
Pour partager un projet Pulumi local sans laisser une stack lisible par
n’importe quel shell du poste, commencez par une vraie passphrase, des
permissions strictes et un preview self-hosted qui lit son secret depuis un
stockage adapte. Ce guide montre comment creer une stack team chiffree,
verifier que Pulumi echoue sans passphrase, utiliser
PULUMI_CONFIG_PASSPHRASE_FILE en local, durcir le backend file://~ et
injecter la passphrase dans GitHub Actions via secrets. Le flux a ete
rejoue le 1 avril 2026 sur KVM/libvirt avec preview, up, verification
virsh, puis destroy.
Ce que vous allez securiser
Section intitulée « Ce que vous allez securiser »Le but n’est pas de transformer le projet en usine a gaz. Vous allez proteger les trois zones qui fuient le plus vite dans un petit workflow d’equipe :
- le fichier de stack et ses secrets ;
- le backend local et ses permissions ;
- la CI self-hosted qui doit lire la passphrase sans la coder en dur.
Dans le lab rejoue, la stack securisee s’appelle team et pilote une VM
pulumi-team-vm sur le reseau pulumi-team-net.
Pourquoi le workflow dev ne suffit plus
Section intitulée « Pourquoi le workflow dev ne suffit plus »Dans les guides precedents, le projet etait volontairement simple : stack dev,
backend local, secret masque dans Pulumi et workflow self-hosted minimal.
Pour apprendre, c’est tres bien. Pour travailler a plusieurs, ce n’est plus
suffisant.
Les risques deviennent vite concrets :
- une passphrase vide laisse la stack dechiffrable sans protection reelle ;
- un fichier
Pulumi.<stack>.yamltrop ouvert peut etre lu par un autre compte du meme poste ; - un workflow CI avec une passphrase en clair dans le YAML devient une fuite de secret versionnee.
Autrement dit : la bonne question n’est plus seulement “est-ce que le preview
passe ?” mais aussi “qui peut dechiffrer la stack et ou le secret circule-t-il ?”.
Etape 1 - Creer une stack d’equipe chiffree des l’initialisation
Section intitulée « Etape 1 - Creer une stack d’equipe chiffree des l’initialisation »Commencez par une nouvelle stack dediee a un usage d’equipe. Dans le lab valide,
la passphrase n’est plus vide et la stack porte des noms de ressources separes
de dev.
source venv/bin/activateexport PULUMI_CONFIG_PASSPHRASE='Team-Pulumi-2026!'
pulumi stack init teampulumi config set libvirt:uri qemu:///system --stack teampulumi config set vmName pulumi-team-vm --stack teampulumi config set networkName pulumi-team-net --stack teampulumi config set vmMemoryMiB 3072 --stack teampulumi config set vmVcpu 2 --stack teampulumi config set adminUser devops --stack teampulumi config set --secret adminPassword 'Team-Pulumi-2026!' --stack teamchmod 600 Pulumi.team.yamlVerification :
pulumi config --stack teamstat -c '%a %n' Pulumi.team.yamlsed -n '1,120p' Pulumi.team.yamlDans le lab rejoue, vous devez observer :
adminPassword [secret]dans la sortie depulumi config;- des permissions
600surPulumi.team.yaml; - un bloc
encryptionsalt:et une entreesecure:dans le fichier de stack, sans secret en clair.
Etape 2 - Verifier que Pulumi refuse la stack sans passphrase
Section intitulée « Etape 2 - Verifier que Pulumi refuse la stack sans passphrase »Une stack d’equipe ne doit pas etre lisible si la passphrase n’est pas fournie. Testez explicitement ce refus :
env -u PULUMI_CONFIG_PASSPHRASE \ pulumi preview --stack team --diff --non-interactiveDans le lab valide, Pulumi retourne :
error: getting stack configuration: get stack secrets manager: passphrase must be set with PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE environment variablesCe message est utile : il prouve que la stack team n’est plus exploitable sans
secret de dechiffrement.
Rejouez ensuite le preview avec la passphrase correcte :
export PULUMI_CONFIG_PASSPHRASE='Team-Pulumi-2026!'pulumi preview --stack team --diff --non-interactiveLe preview doit alors annoncer les 7 ressources attendues et continuer a
masquer userData comme secret.
Etape 3 - Eviter l’export direct de la passphrase dans le shell
Section intitulée « Etape 3 - Eviter l’export direct de la passphrase dans le shell »Exporter la passphrase dans l’environnement fonctionne, mais ce n’est pas
toujours le meilleur compromis. Pour un poste local, PULUMI_CONFIG_PASSPHRASE_FILE
evite de garder la valeur dans l’historique du shell ou dans un copier-coller
malheureux.
Dans le lab rejoue, ce flux fonctionne :
printf 'Team-Pulumi-2026!' > .pulumi-passphrasechmod 600 .pulumi-passphrase
env -u PULUMI_CONFIG_PASSPHRASE \ PULUMI_CONFIG_PASSPHRASE_FILE=$PWD/.pulumi-passphrase \ pulumi preview --stack team --diff --non-interactive
rm -f .pulumi-passphraseVerification : le preview passe normalement avec le fichier de passphrase,
alors que le meme preview sans passphrase echoue.
Important : ce fichier ne doit jamais etre committe. Gardez-le hors du repo
ou ajoutez-le explicitement a votre .gitignore si vous utilisez cette
strategie au quotidien.
Etape 4 - Durcir les permissions du backend local
Section intitulée « Etape 4 - Durcir les permissions du backend local »Le backend file://~ reste pedagogique, mais il ne doit pas etre lisible en
groupe sur un poste partage. Dans le lab, les permissions initiales de
~/.pulumi et ~/.pulumi/stacks etaient trop ouvertes pour un usage
serieux.
Le durcissement rejoue est le suivant :
chmod 700 ~/.pulumi ~/.pulumi/stackschmod 600 Pulumi.dev.yaml Pulumi.team.yamlstat -c '%a %n' ~/.pulumi ~/.pulumi/stacks Pulumi.dev.yaml Pulumi.team.yamlDans le lab valide, la verification retourne :
700pour~/.pulumi;700pour~/.pulumi/stacks;600pourPulumi.dev.yamletPulumi.team.yaml.
Ce n’est pas un substitut a un backend distant avec verrouillage, mais c’est un minimum sain pour un backend local sur une machine Linux.
Etape 5 - Injecter la passphrase dans GitHub Actions sans la versionner
Section intitulée « Etape 5 - Injecter la passphrase dans GitHub Actions sans la versionner »Le workflow CI du guide precedent utilisait une passphrase vide. Pour une stack
partagee, il faut sortir le secret du YAML et le fournir via secrets.
Le workflow valide dans le lab est le suivant :
---name: pulumi-preview-secure
"on": pull_request: paths: - "**/*.py" - "Pulumi.yaml" - "Pulumi.team.yaml" - "requirements.txt" - ".github/workflows/pulumi-preview-secure.yml" workflow_dispatch:
permissions: contents: read
jobs: validate-preview: runs-on: - self-hosted - linux steps: - name: Checkout uses: actions/checkout@v4
- name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.12"
- name: Install dependencies run: | python -m venv venv . venv/bin/activate pip install -r requirements.txt
- name: Compile Python sources run: | . venv/bin/activate python -m compileall .
- name: Run unit tests run: | . venv/bin/activate python -m unittest discover -s tests -p 'test_*.py'
- name: Check passphrase secret is available env: PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} run: | test -n "$PULUMI_CONFIG_PASSPHRASE"
- name: Pulumi preview env: PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} run: | . venv/bin/activate pulumi login --local pulumi stack select team pulumi preview --stack team --diff --non-interactiveVerification :
actionlint .github/workflows/pulumi-preview-secure.ymlyamllint .github/workflows/pulumi-preview-secure.ymlDans le lab rejoue, ces deux commandes passent proprement.
Trois choix sont importants ici :
- le runner reste self-hosted parce qu’il doit voir
qemu:///system; - la passphrase vient de
secrets.PULUMI_CONFIG_PASSPHRASEet non du repo ; - une etape intermediaire verifie que le secret est bien present avant de lancer
le
preview.
Etape 6 - Rejouer le cycle complet sur la stack securisee
Section intitulée « Etape 6 - Rejouer le cycle complet sur la stack securisee »Une securisation credible doit encore laisser le projet exploitable. Rejouez un cycle complet :
export PULUMI_CONFIG_PASSPHRASE='Team-Pulumi-2026!'
pulumi up --stack team --yesvirsh list --all | grep pulumi-team-vmvirsh domstate pulumi-team-vmvirsh domiflist pulumi-team-vm
pulumi destroy --stack team --yesDans le lab valide, vous obtenez :
- une VM
pulumi-team-vmen etatrunningapresup; - une interface
virtioreliee au reseaupulumi-team-net; - un
destroyqui supprime proprement les 7 ressources de la stack.
Cette etape compte autant que le reste. Une pile de securite qui empeche le
travail ou casse le destroy n’est pas une bonne securisation.
Ce que ce guide couvre reellement
Section intitulée « Ce que ce guide couvre reellement »Ce guide valide trois protections utiles et concretes :
- le chiffrement de la stack avec une passphrase non vide ;
- la reduction de surface locale via des permissions
600/700; - l’injection de la passphrase dans une CI self-hosted via un secret GitHub.
Ce guide ne valide pas encore :
- un backend distant partage avec verrouillage ;
- un chiffrement par KMS ;
- des politiques RBAC ou SSO autour de Pulumi Cloud ;
- la rotation organisationnelle des secrets a grande echelle.
Il faut rester honnete sur ce perimetre. Ici, on durcit un workflow local serieux. On ne pretend pas encore couvrir tout le sujet plateforme.
Pieges frequents
Section intitulée « Pieges frequents »| Symptome | Cause probable | Solution |
|---|---|---|
incorrect passphrase | La valeur injectee ne correspond pas a la stack | Verifiez la passphrase active et rejouez pulumi preview avec la bonne valeur |
passphrase must be set with PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE | Aucune passphrase n’a ete fournie | Exportez PULUMI_CONFIG_PASSPHRASE ou pointez PULUMI_CONFIG_PASSPHRASE_FILE |
| La passphrase se retrouve dans le repo | Un fichier temporaire ou un YAML a ete committe | Sortez la valeur du repo, supprimez le fichier et utilisez secrets ou un fichier local ignore |
Le preview CI echoue sur ubuntu-latest | Le runner ne voit pas qemu:///system | Gardez le workflow sur un runner self-hosted Linux |
| Le backend local reste trop ouvert | Les permissions de ~/.pulumi ou des fichiers de stack sont trop larges | Appliquez chmod 700 ~/.pulumi ~/.pulumi/stacks et chmod 600 Pulumi.<stack>.yaml |
A retenir
Section intitulée « A retenir »- Une stack d’equipe Pulumi doit exiger une passphrase non vide.
PULUMI_CONFIG_PASSPHRASE_FILEest utile pour eviter l’export direct du secret dans le shell.- Un backend local
file://~doit au minimum etre limite au proprietaire sur un poste Linux. - Dans GitHub Actions, la passphrase doit venir d’un secret, jamais du YAML versionne.
- Une securisation utile se valide encore avec
preview -> up -> virsh -> destroy.