Maîtrise des Variables d'Environnement dans Docker : Configuration vs. Secrets

Débloquez des déploiements Docker sécurisés et flexibles en maîtrisant les variables d'environnement. Ce guide complet clarifie la distinction essentielle entre l'utilisation des variables d'environnement pour la configuration générale des applications et la gestion sécurisée des données sensibles comme les clés API et les mots de passe. Apprenez des méthodes pratiques pour transmettre des paramètres non sensibles, comprenez les risques graves d'exposition des secrets via les variables d'environnement, et découvrez comment tirer parti de Docker Secrets et Compose pour une gestion des secrets robuste et chiffrée. Améliorez vos connaissances Docker et protégez vos applications.

32 vues

Maîtriser les variables d'environnement dans Docker : Configuration vs Secrets

Docker a révolutionné la manière dont les applications sont construites, déployées et exécutées, offrant un environnement cohérent à travers les différentes étapes de développement. Un aspect fondamental de la gestion des applications conteneurisées est leur configuration, et les variables d'environnement en sont le mécanisme principal. Cependant, toutes les données ne sont pas égales ; certaines configurations sont inoffensives, tandis que d'autres informations, comme les clés d'API ou les informations d'identification de base de données, sont très sensibles. Confondre ces deux catégories peut entraîner des vulnérabilités de sécurité importantes.

Cet article explore la distinction cruciale entre l'utilisation des variables d'environnement pour la configuration générale et les méthodes appropriées et sécurisées pour gérer les données sensibles, communément appelées « secrets ». Nous examinerons les différentes manières de transmettre la configuration à vos conteneurs Docker, mettrons en évidence les risques inhérents à traiter les secrets comme des variables d'environnement ordinaires, et présenterons les solutions dédiées de Docker pour la gestion sécurisée des secrets. À la fin, vous aurez une compréhension claire de quand et comment utiliser chaque approche, garantissant que vos applications sont à la fois flexibles et sécurisées.

Comprendre les variables d'environnement pour la configuration

Les variables d'environnement sont une méthode simple et largement adoptée pour transmettre la configuration d'exécution aux applications, y compris celles s'exécutant dans des conteneurs Docker. Elles vous permettent de modifier le comportement d'une application sans reconstruire l'image Docker, rendant vos conteneurs plus flexibles et portables. C'est idéal pour les paramètres dynamiques non sensibles tels que les numéros de port de l'application, les indicateurs de débogage ou les URL de services tiers.

Méthodes pour transmettre les variables de configuration

Docker fournit plusieurs façons de définir et d'injecter des variables d'environnement dans vos conteneurs :

1. Instruction ENV dans le Dockerfile

L'instruction ENV définit une variable d'environnement par défaut qui sera disponible à l'intérieur du conteneur lors de son exécution. Ceci convient aux variables qui sont peu susceptibles de changer ou qui fournissent des valeurs par défaut sensées pour votre application.

FROM alpine:latest

ENV APP_PORT=8080
ENV DEBUG_MODE=false

COPY ./app /app
WORKDIR /app
CMD ["/app/start.sh"]

Astuce : Bien que ENV définisse des valeurs par défaut, celles-ci peuvent être écrasées lors de l'exécution.

2. Drapeau -e ou --env avec docker run

Lors du lancement d'un seul conteneur, vous pouvez utiliser le drapeau -e ou --env pour transmettre directement des variables d'environnement. Ceci est courant pour les tests ponctuels ou pour fournir des paramètres spécifiques qui diffèrent des valeurs par défaut du Dockerfile.

docker run -d -p 80:8080 --name my_app_instance \n  -e APP_PORT=80 \n  -e DEBUG_MODE=true \n  my_app_image:latest

3. env_file dans Docker Compose

Pour gérer plusieurs variables d'environnement, en particulier sur plusieurs services définis dans un fichier docker-compose.yml, l'option env_file est très pratique. Elle vous permet de charger des variables à partir d'un ou plusieurs fichiers .env, gardant votre docker-compose.yml plus propre.

docker-compose.yml :

version: '3.8'
services:
  webapp:
    image: my_app_image:latest
    ports:
      - "80:8080"
    env_file:
      - ./config/app.env

./config/app.env :

APP_PORT=8080
DEBUG_MODE=false
API_ENDPOINT=https://api.example.com/v1

4. Clé environment dans Docker Compose

Alternativement, vous pouvez définir des variables d'environnement directement dans la section environment d'un service dans docker-compose.yml. Ceci est souvent préféré pour un petit nombre de variables ou pour des variables spécifiques à un seul service.

version: '3.8'
services:
  webapp:
    image: my_app_image:latest
    ports:
      - "80:8080"
    environment:
      APP_PORT: 8080
      DEBUG_MODE: false

Les pièges de l'utilisation des variables d'environnement pour les secrets

Bien que les variables d'environnement soient excellentes pour la configuration, elles ne sont fondamentalement pas sécurisées pour gérer des données sensibles (secrets) telles que les mots de passe de base de données, les clés d'API ou les clés SSH privées. C'est une vulnérabilité de sécurité critique qui est souvent négligée, en particulier dans les environnements de développement.

Pourquoi les variables d'environnement sont-elles dangereuses pour les secrets :

  1. Visibilité via docker inspect : Toute personne ayant accès à l'hôte Docker peut facilement voir les variables d'environnement d'un conteneur en cours d'exécution en utilisant docker inspect <container_id>. Cela signifie que vos secrets sont clairement visibles en texte brut.

    ```bash

    Exemple d'exposition d'un secret (NE PAS FAIRE CECI EN PRODUCTION)

    docker run -d -e DB_PASSWORD=mysecretpassword --name insecure_app nginx:latest

    N'importe qui peut voir le mot de passe

    docker inspect insecure_app | grep DB_PASSWORD
    ```

  2. Espionnage de processus : À l'intérieur du conteneur, d'autres processus ou utilisateurs (s'il existe plusieurs utilisateurs) pourraient être en mesure de lire les variables d'environnement, surtout si l'application s'exécute en tant que root ou dispose de privilèges élevés.

  3. Journalisation et historique : Les variables d'environnement peuvent se retrouver accidentellement dans les journaux, l'historique des pipelines CI/CD ou l'historique du shell, entraînant une exposition accidentelle.

  4. Couches d'image : Si vous utilisez ENV dans un Dockerfile avec un secret, ce secret est intégré dans une couche d'image et y reste, même si vous essayez de le désactiver (unset) dans une couche ultérieure. Cela rend le secret récupérable à partir de l'image elle-même.

  5. Partage accidentel : Les fichiers .env ou docker-compose.yml contenant des secrets sont souvent intégrés dans des systèmes de contrôle de version ou partagés de manière inappropriée, entraînant une exposition généralisée.

Avertissement : Traiter les informations sensibles comme des variables d'environnement normales est une erreur de sécurité courante. Supposez toujours que les variables d'environnement sont visibles publiquement sur l'hôte et à l'intérieur du conteneur.

Gestion sécurisée des secrets dans Docker

Pour remédier aux lacunes de sécurité des variables d'environnement pour les données sensibles, Docker fournit des capacités dédiées de gestion des secrets, principalement via Docker Secrets (pour Docker Swarm) et des outils externes comme Docker Compose avec la fonctionnalité secrets (qui peut exploiter les secrets Docker Swarm ou simplement monter des fichiers).

Docker Secrets (Mode Swarm Docker)

Docker Secrets est une fonctionnalité intégrée au mode Docker Swarm qui fournit un moyen sécurisé de transmettre et de stocker des données sensibles pour les services. Les secrets sont :

  • Chiffrés au repos dans les journaux Raft du gestionnaire Swarm.
  • Transmis de manière sécurisée aux tâches de service autorisées.
  • Montés comme des fichiers en mémoire dans le système de fichiers du conteneur, généralement à l'emplacement /run/secrets/<nom_du_secret>, au lieu d'être exposés comme des variables d'environnement.
  • Accessibles uniquement par les services auxquels un accès explicite a été accordé.

Comment utiliser Docker Secrets (Mode Swarm)

  1. Initialiser Swarm (si ce n'est pas déjà fait) :
    bash docker swarm init

  2. Créer un secret : Les secrets sont créés à partir d'un fichier ou de l'entrée standard.
    bash echo "my_secure_db_password" | docker secret create db_password_secret - echo "SG.your_api_key_here" | docker secret create sendgrid_api_key -

  3. Déployer un service avec le secret : Les services référencent les secrets par leur nom. Docker monte le secret dans le conteneur.
    bash docker service create --name my-webapp \n --secret db_password_secret \n --secret sendgrid_api_key \n my_app_image:latest

  4. Accéder aux secrets dans le conteneur : Les applications lisent le secret à partir du chemin du fichier monté.
    ```python

Dans votre code d'application Python (ou similaire pour d'autres langages)

with open('/run/secrets/db_password_secret', 'r') as f:
db_password = f.read().strip()

with open('/run/secrets/sendgrid_api_key', 'r') as f:
sendgrid_key = f.read().strip()
```

Docker Compose et Secrets (pour un hôte unique ou Swarm)

Docker Compose version 3.1+ a introduit une section secrets, qui vous permet de définir et de référencer des secrets dans votre docker-compose.yml. Lorsqu'il est exécuté en mode Swarm, Compose utilise les secrets natifs de Docker Swarm. Lorsqu'il est exécuté sur un seul hôte sans le mode Swarm, Compose prend toujours en charge les secrets en montant des fichiers de l'hôte vers le conteneur de manière sécurisée, bien que sans le chiffrement au repos fourni par Swarm.

Utilisation de secrets dans docker-compose.yml

  1. Définir les secrets : Vous pouvez définir les secrets soit en référençant un fichier externe, soit en en faisant un secret externe (secret Swarm préexistant).

    ```yaml

    docker-compose.yml

    version: '3.8'

    services:
    webapp:
    image: my_app_image:latest
    ports:
    - "80:8080"
    secrets:
    - db_password
    - sendgrid_api_key

    secrets:
    db_password:
    file: ./secrets/db_password.txt # Chemin vers un fichier sur l'hôte contenant le mot de passe
    sendgrid_api_key:
    external: true # Fait référence à un secret Docker Swarm préexistant nommé 'sendgrid_api_key'
    ```

  2. Créer des fichiers de secrets locaux (si file est utilisé) :
    bash mkdir secrets echo "my_local_db_password" > ./secrets/db_password.txt

  3. Déployer avec Compose : docker compose up -d déploiera vos services, rendant les secrets disponibles à l'emplacement /run/secrets/<nom_du_secret> à l'intérieur des conteneurs.

    ```bash

    À l'intérieur du conteneur, le contenu de ./secrets/db_password.txt sera à :

    /run/secrets/db_password

    ```

Choisir le bon outil : Configuration vs Secrets

La décision d'utiliser une variable d'environnement pour la configuration ou une solution dédiée de gestion des secrets se résume à une question principale :

Les données sont-elles sensibles ?

  • Si oui (données sensibles) : Utilisez Docker Secrets (avec Swarm) ou un système de gestion des secrets similaire (par exemple, Kubernetes Secrets, HashiCorp Vault). Pour les configurations sur un seul hôte avec Compose, utilisez la section secrets pour monter les fichiers en toute sécurité.
  • Si non (configuration non sensible) : Utilisez les variables d'environnement (via ENV dans Dockerfile, drapeau -e, env_file ou environment dans Compose).

| Caractéristique | Variables d'environnement (pour la config) | Docker Secrets (pour les données sensibles) |
| :-------------------------- | :----------------------------------------- | :---------------------------------------------- |\n| Objectif | Configuration d'application non sensible | Données sensibles (mots de passe, clés d'API) |\n| Visibilité | Visible via docker inspect, ps -e | Monté comme des fichiers ; pas dans docker inspect |\n| Sécurité | Non sécurisé pour les données sensibles | Transmission et stockage chiffrés et sécurisés |\n| Accès dans l'application| Lecture depuis os.environ (ou similaire) | Lecture depuis le fichier /run/secrets/<secret_name> |\n| Géré par | Exécution Docker, Docker Compose | Docker Swarm, Docker Compose |\n| Cas d'utilisation | Numéros de port, indicateurs de débogage, URL non sensibles | Mots de passe de base de données, jetons d'API, clés privées |\n

Bonnes pratiques pour les deux

Pour la configuration (variables d'environnement) :

  • Fournissez des valeurs par défaut sensées dans votre Dockerfile en utilisant ENV. Cela rend vos images exécutables immédiatement et documente clairement les variables attendues.
  • Externalisez la configuration lorsque cela est possible. Utilisez des fichiers .env avec docker compose ou des services de configuration externes pour les déploiements plus importants.
  • Documentez toutes les options de configuration et leurs valeurs attendues, peut-être dans un README.md ou la documentation de l'application.
  • Évitez d'intégrer en dur des valeurs susceptibles de changer entre les environnements (développement, staging, production).

Pour les secrets (Docker Secrets et au-delà) :

  • N'intégrez jamais de secrets (par exemple, des fichiers .env contenant des secrets, db_password.txt) dans des systèmes de contrôle de version comme Git.
  • Faites pivoter les secrets régulièrement. Cela minimise la fenêtre d'exposition si un secret est compromis.
  • Accordez le moindre privilège. Ne donnez aux services que l'accès aux secrets dont ils ont absolument besoin.
  • Évitez d'enregistrer les valeurs des secrets. Assurez-vous que la journalisation de votre application et de votre infrastructure n'affiche pas le contenu des secrets.
  • Pour les déploiements à grande échelle de niveau entreprise, envisagez des solutions dédiées de gestion des secrets telles que HashiCorp Vault, AWS Secrets Manager ou Azure Key Vault, qui offrent des fonctionnalités plus avancées comme l'audit, la génération de secrets dynamiques et l'intégration avec la gestion des identités et des accès (IAM).

Conclusion

Maîtriser les variables d'environnement dans Docker signifie plus que simplement savoir comment les transmettre ; cela signifie comprendre la différence fondamentale entre la configuration générique et les secrets sensibles. Bien que les variables d'environnement offrent une flexibilité inégalée pour la configuration des applications, elles sont intrinsèquement non sécurisées pour les données sensibles.

En tirant parti de Docker Secrets pour les informations sensibles au sein d'un environnement Swarm, ou en utilisant judicieusement la fonctionnalité secrets de Docker Compose pour les déploiements sur un seul hôte, vous pouvez améliorer considérablement la posture de sécurité de vos applications conteneurisées. Priorisez toujours la sécurité en utilisant le bon outil pour le travail, en adhérant aux meilleures pratiques et en vous assurant que vos données sensibles restent protégées contre toute exposition accidentelle. Cette approche disciplinée mènera à des déploiements Docker plus robustes, maintenables et sécurisés.