Padroneggiare le Variabili d'Ambiente in Docker: Configurazione vs. Segreti

Sblocca implementazioni Docker sicure e flessibili padroneggiando le variabili d'ambiente. Questa guida completa chiarisce la distinzione cruciale tra l'uso delle variabili d'ambiente per la configurazione generale dell'applicazione e la gestione sicura di dati sensibili come chiavi API e password. Impara metodi pratici per trasmettere impostazioni non sensibili, comprendi i gravi rischi derivanti dall'esposizione dei segreti tramite variabili d'ambiente e scopri come sfruttare Docker Secrets e Compose per una gestione dei segreti solida e crittografata. Migliora la tua conoscenza di Docker e metti al sicuro le tue applicazioni.

36 visualizzazioni

Gestire le Variabili d'Ambiente in Docker: Configurazione vs. Segreti

Docker ha rivoluzionato il modo in cui le applicazioni vengono costruite, distribuite ed eseguite, fornendo un ambiente coerente nelle varie fasi di sviluppo. Un aspetto fondamentale della gestione delle applicazioni containerizzate è la loro configurazione, e le variabili d'ambiente sono il meccanismo principale per questo. Tuttavia, non tutti i dati sono uguali; alcune configurazioni sono innocue, mentre altre informazioni, come le chiavi API o le credenziali del database, sono estremamente sensibili. Confondere queste due categorie può portare a significative vulnerabilità di sicurezza.

Questo articolo approfondisce la distinzione cruciale tra l'uso delle variabili d'ambiente per la configurazione generale e i metodi appropriati e sicuri per la gestione dei dati sensibili, comunemente denominati "segreti" (secrets). Esploreremo i vari modi per passare la configurazione ai container Docker, evidenzieremo i rischi intrinseci nel trattare i segreti come normali variabili d'ambiente e presenteremo le soluzioni dedicate di Docker per la gestione sicura dei segreti. Alla fine, avrai una chiara comprensione di quando e come utilizzare ciascun approccio, garantendo che le tue applicazioni siano flessibili e sicure.

Comprendere le Variabili d'Ambiente per la Configurazione

Le variabili d'ambiente sono un metodo semplice e ampiamente adottato per passare la configurazione runtime alle applicazioni, comprese quelle in esecuzione nei container Docker. Ti consentono di modificare il comportamento di un'applicazione senza dover ricostruire l'immagine Docker, rendendo i tuoi container più flessibili e portatili. Questo è l'ideale per impostazioni dinamiche e non sensibili come i numeri di porta dell'applicazione, i flag di debug o gli URL di servizi di terze parti.

Metodi per Passare le Variabili di Configurazione

Docker fornisce diversi modi per definire e iniettare variabili d'ambiente nei tuoi container:

1. Istruzione ENV nel Dockerfile

L'istruzione ENV imposta una variabile d'ambiente predefinita che sarà disponibile all'interno del container quando viene eseguito. Questo è adatto per variabili che difficilmente cambieranno o che forniscono valori predefiniti sensati per la tua applicazione.

FROM alpine:latest

ENV APP_PORT=8080
ENV DEBUG_MODE=false

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

Suggerimento: Sebbene ENV imposti i valori predefiniti, questi possono essere sovrascritti in fase di esecuzione.

2. Flag -e o --env con docker run

Quando si avvia un singolo container, è possibile utilizzare il flag -e o --env per passare direttamente le variabili d'ambiente. Questo è comune per test ad hoc o per fornire impostazioni specifiche che differiscono dai valori predefiniti del 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 in Docker Compose

Per gestire più variabili d'ambiente, specialmente tra diversi servizi definiti in un file docker-compose.yml, l'opzione env_file è molto comoda. Permette di caricare variabili da uno o più file .env, mantenendo più pulito il tuo docker-compose.yml.

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. Chiave environment in Docker Compose

In alternativa, puoi definire le variabili d'ambiente direttamente all'interno della sezione environment di un servizio in docker-compose.yml. Questo è spesso preferito per un piccolo numero di variabili o per variabili specifiche di un singolo servizio.

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

Le Insidie dell'Uso di Variabili d'Ambiente per i Segreti

Sebbene le variabili d'ambiente siano eccellenti per la configurazione, esse sono fondamentalmente non sicure per la gestione di dati sensibili (segreti) come password di database, chiavi API o chiavi SSH private. Questa è una vulnerabilità di sicurezza critica che viene spesso trascurata, specialmente negli ambienti di sviluppo.

Perché le Variabili d'Ambiente sono Non Sicure per i Segreti:

  1. Visibilità tramite docker inspect: Chiunque abbia accesso all'host Docker può visualizzare facilmente le variabili d'ambiente di un container in esecuzione utilizzando docker inspect <id_del_container>. Ciò significa che i tuoi segreti sono chiaramente visibili in testo semplice.

    ```bash

    Esempio di esposizione di un segreto (NON FARLO IN PRODUZIONE)

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

    Chiunque può vedere la password

    docker inspect insecure_app | grep DB_PASSWORD
    ```

  2. Process Snooping (Spionaggio dei processi): All'interno del container, altri processi o utenti (se esistono più utenti) potrebbero essere in grado di leggere le variabili d'ambiente, specialmente se l'applicazione viene eseguita come root o ha privilegi elevati.

  3. Logging e Cronologia: Le variabili d'ambiente possono finire inavvertitamente nei log, nella cronologia della pipeline CI/CD o nella cronologia della shell, portando a un'esposizione accidentale.

  4. Livelli dell'Immagine (Image Layers): Se utilizzi ENV in un Dockerfile con un segreto, quel segreto viene incorporato in un livello dell'immagine e vi rimane, anche se provi a rimuoverlo (unset) in un livello successivo. Questo rende il segreto recuperabile dall'immagine stessa.

  5. Condivisione Accidentale: I file .env o docker-compose.yml contenenti segreti vengono spesso commessi nei sistemi di controllo versione o condivisi in modo inappropriato, portando a un'esposizione diffusa.

Avviso: Trattare le informazioni sensibili come normali variabili d'ambiente è un errore di sicurezza comune. Presumi sempre che le variabili d'ambiente siano visibili pubblicamente sull'host e all'interno del container.

Gestione Sicura dei Segreti in Docker

Per ovviare alle carenze di sicurezza delle variabili d'ambiente per i dati sensibili, Docker fornisce funzionalità dedicate alla gestione dei segreti, principalmente tramite Docker Secrets (per Docker Swarm) e strumenti esterni come Docker Compose con la funzionalità secrets (che può sfruttare i segreti di Docker Swarm o semplicemente montare file).

Docker Secrets (Modalità Docker Swarm)

Docker Secrets è una funzionalità integrata nella modalità Docker Swarm che fornisce un modo sicuro per trasmettere e archiviare dati sensibili per i servizi. I segreti sono:

  • Crittografati a riposo nei log Raft del manager Swarm.
  • Trasmessi in modo sicuro ai task di servizio autorizzati.
  • Montati come file in memoria all'interno del filesystem del container, in genere in /run/secrets/<nome_del_segreto>, anziché essere esposti come variabili d'ambiente.
  • Accessibili solo dai servizi a cui è stato esplicitamente concesso l'accesso.

Come Usare Docker Secrets (Modalità Swarm)

  1. Inizializza Swarm (se non è già stato fatto):
    bash docker swarm init

  2. Crea un Segreto: I segreti vengono creati da un file o da input 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. Distribuisci un Servizio con il Segreto: I servizi fanno riferimento ai segreti per nome. Docker monta il segreto all'interno del container.
    bash docker service create --name my-webapp \n --secret db_password_secret \n --secret sendgrid_api_key \n my_app_image:latest

  4. Accesso ai Segreti nel Container: Le applicazioni leggono il segreto dal percorso del file montato.
    ```python

Nel codice della tua applicazione Python (o simile per altri linguaggi)

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 e Segreti (per host singolo o Swarm)

Docker Compose versione 3.1+ ha introdotto una sezione secrets, che ti consente di definire e fare riferimento ai segreti all'interno del tuo docker-compose.yml. Quando eseguito in modalità Swarm, Compose sfrutta i segreti nativi di Docker Swarm. Quando eseguito su un host singolo senza la modalità Swarm, Compose supporta comunque i segreti montando i file dall'host nel container in modo sicuro, sebbene senza la crittografia a riposo fornita da Swarm.

Utilizzo di secrets in docker-compose.yml

  1. Definire i Segreti: È possibile definire i segreti facendo riferimento a un file esterno o rendendolo un segreto esterno (segreto Swarm pre-creato).

    ```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 # Percorso di un file sull'host contenente la password
    sendgrid_api_key:
    external: true # Si riferisce a un segreto Docker Swarm preesistente chiamato 'sendgrid_api_key'
    ```

  2. Creare File di Segreti Locali (se viene usato file):
    bash mkdir secrets echo "my_local_db_password" > ./secrets/db_password.txt

  3. Deploy con Compose: docker compose up -d distribuirà i tuoi servizi, rendendo i segreti disponibili in /run/secrets/<nome_del_segreto> all'interno dei container.

    ```bash

    All'interno del container, il contenuto di ./secrets/db_password.txt si troverà in:

    /run/secrets/db_password

    ```

Scegliere lo Strumento Giusto: Configurazione vs. Segreti

La decisione se utilizzare una variabile d'ambiente per la configurazione o una soluzione dedicata per la gestione dei segreti si riduce a una domanda fondamentale:

Il dato è sensibile?

  • Se Sì (dati sensibili): Utilizza Docker Secrets (con Swarm) o un sistema di gestione dei segreti simile (ad esempio, Kubernetes Secrets, HashiCorp Vault). Per le configurazioni Compose su singolo host, utilizza la sezione secrets per montare i file in modo sicuro.
  • Se No (configurazione non sensibile): Utilizza variabili d'ambiente (tramite ENV nel Dockerfile, flag -e, env_file o environment in Compose).

| Caratteristica | Variabili d'Ambiente (per config) | Docker Secrets (per dati sensibili) |
| :------------------ | :--------------------------------------- | :------------------------------------------ |\n| Scopo | Configurazione dell'applicazione non sensibile | Dati sensibili (password, chiavi API) |\n| Visibilità | Visibile tramite docker inspect, ps -e | Montato come file; non in docker inspect |\n| Sicurezza | Non sicuro per dati sensibili | Crittografia, trasmissione e archiviazione sicura |\n| Accesso nell'App| Lettura da os.environ (o simili) | Lettura dal file /run/secrets/<nome_del_segreto> |\n| Gestito da | Docker runtime, Docker Compose | Docker Swarm, Docker Compose |\n| Casi d'Uso | Numeri di porta, flag di debug, URL non sensibili | Password di database, token API, chiavi private |\n

Best Practice per Entrambi

Per la Configurazione (Variabili d'Ambiente):

  • Fornisci valori predefiniti sensati nel tuo Dockerfile usando ENV. Questo rende le tue immagini eseguibili immediatamente e documenta chiaramente le variabili attese.
  • Esternalizza la configurazione ove possibile. Utilizza file .env con docker compose o servizi di configurazione esterni per distribuzioni più grandi.
  • Documenta tutte le opzioni di configurazione e i relativi valori attesi, magari in un README.md o nella documentazione dell'applicazione.
  • Evita di codificare (hardcoding) valori che potrebbero cambiare tra i vari ambienti (sviluppo, staging, produzione).

Per i Segreti (Docker Secrets e oltre):

  • Non commettere mai segreti (ad esempio, file .env contenenti segreti, db_password.txt) in sistemi di controllo versione come Git.
  • Ruota i segreti regolarmente. Ciò riduce al minimo la finestra di esposizione se un segreto viene compromesso.
  • Concedi il privilegio minimo. Dai ai servizi accesso solo ai segreti di cui hanno assolutamente bisogno.
  • Evita di registrare i valori dei segreti (logging). Assicurati che il logging della tua applicazione e dell'infrastruttura non stampi il contenuto dei segreti.
  • Per distribuzioni su larga scala e di livello aziendale, considera soluzioni dedicate per la gestione dei segreti come HashiCorp Vault, AWS Secrets Manager o Azure Key Vault, che offrono funzionalità più avanzate come auditing, generazione dinamica di segreti e integrazione con Identity and Access Management (IAM).

Conclusione

Padroneggiare le variabili d'ambiente in Docker significa più che sapere come passarle; significa comprendere la differenza fondamentale tra la configurazione generica e i segreti sensibili. Sebbene le variabili d'ambiente offrano una flessibilità ineguagliabile per la configurazione delle applicazioni, sono intrinsecamente non sicure per i dati sensibili.

Sfruttando Docker Secrets per le informazioni sensibili all'interno di un ambiente Swarm, o utilizzando attentamente la funzionalità secrets di Docker Compose per distribuzioni su host singolo, è possibile migliorare significativamente la postura di sicurezza delle applicazioni containerizzate. Dai sempre la priorità alla sicurezza utilizzando lo strumento giusto per il lavoro, aderendo alle migliori pratiche e assicurando che i tuoi dati sensibili rimangano protetti dall'esposizione accidentale. Questo approccio disciplinato porterà a distribuzioni Docker più robuste, manutenibili e sicure.