D8.3 Secrets Management 🔐

Το πρόβλημα με τα env vars

# ❌ Κοινό αλλά ΛΑΘΟΣ:
docker run -e POSTGRES_PASSWORD=MySecret123 postgres

# Πρόβλημα 1: Εμφανίζεται σε docker inspect
docker inspect postgres | grep -A5 Env
# "Env": ["POSTGRES_PASSWORD=MySecret123"]  ← ορατό!

# Πρόβλημα 2: Εμφανίζεται σε ps
ps aux | grep docker
# ... -e POSTGRES_PASSWORD=MySecret123 ...  ← ορατό!

# Πρόβλημα 3: Μπαίνει σε logs
# Αν app κάνει log τα env vars → secret exposed!

Pattern 1: Ansible Vault + File mount (Συνίσταται)

Το ασφαλέστερο pattern για single-host deployments:

# group_vars/all/vault.yml (encrypted)
vault_postgres_pass: "StrongP@ssw0rd!"
vault_redis_pass:    "RedisP@ssw0rd!"
vault_app_secret:    "SuperSecretKey!"
tasks:

  # ── Δημιουργία secrets directory (700) ────────
  - name: Secrets directory
    ansible.builtin.file:
      path:  /run/secrets
      state: directory
      owner: root
      group: root
      mode:  '0700'

  # ── Γράψιμο secrets ως αρχεία ─────────────────
  - name: Postgres password secret
    ansible.builtin.copy:
      content: "{{ vault_postgres_pass }}"
      dest:    /run/secrets/postgres_password
      owner:   root
      group:   "999"      # ← postgres GID
      mode:    '0640'     # ← μόνο root + postgres group
    no_log: true

  - name: App secret key
    ansible.builtin.copy:
      content: "{{ vault_app_secret }}"
      dest:    /run/secrets/app_secret_key
      owner:   root
      group:   "1000"
      mode:    '0640'
    no_log: true

  # ── Mount secrets ως read-only files ──────────
  - name: PostgreSQL με file secret
    community.docker.docker_container:
      name:           postgres_db
      image:          postgres:15-alpine
      state:          started
      restart_policy: unless-stopped
      volumes:
        - "/run/secrets/postgres_password:/run/secrets/postgres_password:ro"
      env:
        POSTGRES_PASSWORD_FILE: "/run/secrets/postgres_password"
        #                        ↑ Το postgres image διαβάζει αυτό αντί για POSTGRES_PASSWORD
        POSTGRES_USER: appuser
        POSTGRES_DB:   mydb
      # no_log ΔΕΝ χρειάζεται (δεν υπάρχουν secrets στα env!)

💡 PostgreSQL, MySQL, Redis υποστηρίζουν _FILE suffix για env vars που διαβάζουν από αρχείο αντί για env:

  • POSTGRES_PASSWORD_FILE=/run/secrets/pg_pass
  • MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pass
  • REDIS_PASSWORD_FILE=/run/secrets/redis_pass (custom)

Pattern 2: tmpfs secrets (in-memory)

tasks:

  # ── Secrets σε tmpfs (RAM, δεν γράφονται σε disk) ──
  - name: tmpfs secrets directory
    ansible.posix.mount:
      src:    tmpfs
      path:   /run/secrets
      fstype: tmpfs
      opts:   "size=32m,mode=0700,noexec,nosuid,nodev"
      state:  mounted

  - name: Write secrets to tmpfs
    ansible.builtin.copy:
      content: "{{ vault_postgres_pass }}"
      dest:    /run/secrets/postgres_password
      mode:    '0600'
    no_log: true

Τι να ΑΠΟΦΕΥΓΕΙΣ

# ❌ Secrets σε plain env vars
- community.docker.docker_container:
    name: postgres
    env:
      POSTGRES_PASSWORD: "MySecret123"    # ← ΕΠΙΚΙΝΔΥΝΟ

# ❌ Secrets hardcoded στο playbook
vars:
  db_pass: "MySecret123"    # ← ΕΠΙΚΙΝΔΥΝΟ (git log!)

# ❌ no_log: false με secrets
- name: Something with secrets
  community.docker.docker_container:
    env:
      SECRET: "{{ vault_secret }}"
  # no_log: true ← ΛΕΙΠΕΙ!

# ✅ Σωστό
- name: Something with secrets
  community.docker.docker_container:
    env:
      SECRET_FILE: "/run/secrets/mysecret"    # ← file reference
  no_log: true    # ← πάντα για secrets!

Σύνοψη D8.3

Secrets Management
│
├── ❌ Αποφεύγουμε:
│   ├── Plaintext env vars
│   └── Hardcoded values στο playbook
│
├── ✅ Χρησιμοποιούμε:
│   ├── Ansible Vault → encrypted στο git
│   ├── File mounts → /run/secrets/
│   ├── _FILE env vars (postgres, mysql)
│   └── no_log: true σε κάθε task με secrets
│
└── Extras:
    ├── /run/secrets: mode 0700
    ├── Secret files: mode 0640
    └── tmpfs για in-memory secrets