45 Ansible Vault - Umfassende Anleitung

45.1 Einführung

45.1.1 Zweck und Motivation: Umgang mit sensiblen Daten

Ansible Vault verschlüsselt sensible Daten wie Passwörter, API-Keys, Zertifikate und Konfigurationsdateien direkt in Ansible-Projekten. Die symmetrische AES256-Verschlüsselung ermöglicht die sichere Versionskontrolle sensibler Inhalte ohne externe Key-Management-Systeme.

Typische Anwendungsfälle: - Database-Credentials und Connection-Strings - Cloud-Provider-API-Keys und Tokens - SSL/TLS-Zertifikate und Private Keys - Backup-Verschlüsselungsschlüssel - Service-Account-Passwörter - Monitoring- und Logging-Credentials

45.1.2 Abgrenzung zu allgemeinen Sicherheitsmaßnahmen in Ansible

Vault adressiert spezifisch die Verschlüsselung ruhender Daten (data at rest) in Playbooks und Inventories. Transport-Sicherheit, Benutzerauthentifizierung und Systemhärtung bleiben separate Sicherheitsdomänen mit eigenen Implementierungsstrategien.

45.2 Verschlüsselung und Entschlüsselung

45.2.1 ansible-vault encrypt, decrypt, view, edit, rekey

Verschlüsselung bestehender Dateien:

# Datei verschlüsseln
ansible-vault encrypt group_vars/production/vault.yml
New Vault password: 
Confirm New Vault password: 
Encryption successful

# Mehrere Dateien gleichzeitig
ansible-vault encrypt host_vars/*/secrets.yml group_vars/*/vault.yml

Entschlüsselung für dauerhafte Klartext-Verwendung:

# Permanent entschlüsseln
ansible-vault decrypt group_vars/production/vault.yml
Vault password: 
Decryption successful

# Mit spezifischer Vault-ID
ansible-vault decrypt --vault-id production@prompt group_vars/production/vault.yml

Temporäre Anzeige ohne Entschlüsselung:

# Verschlüsselten Inhalt anzeigen
ansible-vault view group_vars/production/vault.yml
Vault password: 

# Mit Passwort-Datei
ansible-vault view --vault-password-file ~/.vault_pass group_vars/production/vault.yml

In-Place-Bearbeitung verschlüsselter Dateien:

# Editor für verschlüsselte Datei
ansible-vault edit group_vars/production/vault.yml
Vault password: 

# Mit externem Editor
EDITOR=vim ansible-vault edit --vault-id production@prompt group_vars/production/vault.yml

Passwort-Änderung:

# Vault-Passwort ändern
ansible-vault rekey group_vars/production/vault.yml
Vault password: 
New Vault password: 
Confirm New Vault password: 
Rekey successful

# Bulk-Rekey für mehrere Dateien
ansible-vault rekey --vault-id old@prompt --new-vault-id new@prompt group_vars/*/vault.yml

45.2.2 Verschlüsselung einzelner Variablen

Einzelne Strings verschlüsseln:

# Variable verschlüsseln
ansible-vault encrypt_string 'mysecretpassword' --name 'vault_database_password'
vault_database_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653237336464643061663135366461343536393934326135323634363761363134346362
          3832623030626364333934663061626431303665333234300a323030643231373562636439643536
          ...

# Direkt in Playbook verwenden
ansible-vault encrypt_string --vault-id production@prompt 'secret_value' --name 'vault_api_key'

45.2.3 Beispiel: Verschlüsselung einer Datei mit Passwort

Erstellung einer verschlüsselten Variable-Datei:

# group_vars/production/vault.yml (vor Verschlüsselung)
---
vault_database_password: "prod_db_secret_2023!"
vault_api_key: "sk-1234567890abcdef"
vault_ssl_private_key: |
  -----BEGIN PRIVATE KEY-----
  MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKB
  wjlCYfzuNqzA8LKzRx4dOJ5USn3EjLcQk5BFxjmCJ6WvJyLJ5DpJqT8kLGnJFZ
  ...
  -----END PRIVATE KEY-----
vault_backup_encryption_key: "backup_key_2023_secure"

Verschlüsselungsvorgang:

ansible-vault encrypt group_vars/production/vault.yml
New Vault password: SecureVaultPassword2023!
Confirm New Vault password: SecureVaultPassword2023!
Encryption successful

Resultierende verschlüsselte Datei:

$ANSIBLE_VAULT;1.1;AES256
66386439653237336464643061663135366461343536393934326135323634363761363134346362
3832623030626364333934663061626431303665333234300a323030643231373562636439643536
33663933373933313064346664383463323532663430653632383836383466343264386465623736
6164643963666231370a323663376131363533656239656638323065376261636534313138396562
...

45.3 Verwendung verschlüsselter Dateien in Playbooks

45.3.1 Syntax vars_files mit verschlüsselten Dateien

Standard-Integration in Playbooks:

---
- name: Production deployment with encrypted variables
  hosts: production_servers
  vars_files:
    - group_vars/production/vars.yml
    - group_vars/production/vault.yml
  tasks:
    - name: Configure database connection
      postgresql_user:
        name: webapp
        password: "{{ vault_database_password }}"
        encrypted: yes
        state: present

    - name: Deploy SSL certificate
      copy:
        content: "{{ vault_ssl_private_key }}"
        dest: /etc/ssl/private/server.key
        mode: '0600'
        owner: root
        group: root
      notify: restart nginx

Rollenbasierte Vault-Integration:

# roles/database/vars/main.yml
---
db_host: "{{ vault_db_host }}"
db_user: "{{ vault_db_user }}"
db_password: "{{ vault_db_password }}"

# roles/database/tasks/main.yml
---
- name: Include encrypted variables
  include_vars: "{{ inventory_dir }}/group_vars/{{ group_names[0] }}/vault.yml"

- name: Configure database access
  template:
    src: database.conf.j2
    dest: /etc/app/database.conf
    mode: '0640'

45.3.2 Kombination mit –ask-vault-pass oder –vault-password-file

Interaktive Passwort-Eingabe:

# Playbook mit Vault-Passwort-Abfrage
ansible-playbook -i inventories/production site.yml --ask-vault-pass

# Mit spezifischem Limit
ansible-playbook -i inventories/production site.yml --limit database_servers --ask-vault-pass

Passwort-Datei für automatisierte Ausführung:

# Passwort-Datei erstellen (sichere Berechtigung!)
echo "SecureVaultPassword2023!" > ~/.vault_pass
chmod 600 ~/.vault_pass

# Playbook mit Passwort-Datei
ansible-playbook -i inventories/production site.yml --vault-password-file ~/.vault_pass

# Über Umgebungsvariable
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
ansible-playbook -i inventories/production site.yml

Konfiguration in ansible.cfg:

# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass
host_key_checking = False
stdout_callback = yaml

[inventory]
enable_plugins = auto

45.4 Einbindung in CI/CD-Workflows

45.4.1 Umgang mit Vault in automatisierten Pipelines

GitLab CI Integration:

# .gitlab-ci.yml
variables:
  ANSIBLE_VAULT_PASSWORD_FILE: /tmp/vault_pass

stages:
  - validate
  - deploy

before_script:
  - echo "$VAULT_PASSWORD" > /tmp/vault_pass
  - chmod 600 /tmp/vault_pass

validate:syntax:
  stage: validate
  script:
    - ansible-playbook --syntax-check site.yml
    - ansible-vault view group_vars/production/vault.yml > /dev/null
  only:
    - merge_requests

deploy:production:
  stage: deploy
  script:
    - ansible-playbook -i inventories/production site.yml
  environment:
    name: production
  only:
    - main
  after_script:
    - rm -f /tmp/vault_pass

GitHub Actions mit verschlüsselten Secrets:

# .github/workflows/deploy.yml
name: Deploy with Vault

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'
          
      - name: Install Ansible
        run: pip install ansible
        
      - name: Create vault password file
        run: |
          echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > .vault_pass
          chmod 600 .vault_pass
        
      - name: Validate vault files
        run: |
          ansible-vault view --vault-password-file .vault_pass group_vars/production/vault.yml > /dev/null
          
      - name: Deploy to production
        run: |
          ansible-playbook \
            -i inventories/production \
            --vault-password-file .vault_pass \
            site.yml
        env:
          ANSIBLE_HOST_KEY_CHECKING: false
          
      - name: Clean up
        if: always()
        run: rm -f .vault_pass

45.4.2 Verwendung von –vault-id und Passwortübergabe via ENV

Multi-Vault-ID-Setup:

# Verschiedene Vault-IDs für Umgebungen
ansible-vault encrypt --vault-id staging@prompt group_vars/staging/vault.yml
ansible-vault encrypt --vault-id production@prompt group_vars/production/vault.yml

# Verwendung mit spezifischen IDs
ansible-playbook -i inventories/staging site.yml --vault-id staging@prompt
ansible-playbook -i inventories/production site.yml --vault-id production@prompt

Umgebungsvariablen für Vault-IDs:

# Passwort-Skript für dynamische Bereitstellung
cat > vault_pass_script.sh << 'EOF'
#!/bin/bash
case "$1" in
    staging)
        echo "$STAGING_VAULT_PASSWORD"
        ;;
    production)
        echo "$PRODUCTION_VAULT_PASSWORD"
        ;;
    *)
        echo "Unknown vault ID: $1" >&2
        exit 1
        ;;
esac
EOF
chmod +x vault_pass_script.sh

# Verwendung in Pipeline
export STAGING_VAULT_PASSWORD="staging_vault_secret"
export PRODUCTION_VAULT_PASSWORD="production_vault_secret"
ansible-playbook -i inventories/production site.yml --vault-id production@vault_pass_script.sh

Jenkins Pipeline mit Vault-Integration:

// Jenkinsfile
pipeline {
    agent any
    
    environment {
        STAGING_VAULT_ID = credentials('staging-vault-password')
        PRODUCTION_VAULT_ID = credentials('production-vault-password')
    }
    
    stages {
        stage('Deploy Staging') {
            steps {
                script {
                    writeFile file: '.vault_staging', text: env.STAGING_VAULT_ID
                    sh 'chmod 600 .vault_staging'
                }
                sh '''
                    ansible-playbook \
                        -i inventories/staging \
                        --vault-id staging@.vault_staging \
                        site.yml
                '''
            }
            post {
                always {
                    sh 'rm -f .vault_staging'
                }
            }
        }
        
        stage('Deploy Production') {
            when {
                tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP"
            }
            steps {
                script {
                    writeFile file: '.vault_production', text: env.PRODUCTION_VAULT_ID
                    sh 'chmod 600 .vault_production'
                }
                sh '''
                    ansible-playbook \
                        -i inventories/production \
                        --vault-id production@.vault_production \
                        site.yml
                '''
            }
            post {
                always {
                    sh 'rm -f .vault_production'
                }
            }
        }
    }
}

45.5 Best Practices für Vault-Einsatz

45.5.1 Trennung sensibler Daten

Strukturierte Separierung von Klartext und verschlüsselten Variablen:

# group_vars/production/vars.yml (unverschlüsselt)
---
database_host: db.production.company.com
database_port: 5432
database_name: webapp_prod
api_endpoint: https://api.production.company.com
ssl_cert_path: /etc/ssl/certs/server.crt

# group_vars/production/vault.yml (verschlüsselt)
---
vault_database_password: "{{ vault_db_pass }}"
vault_database_user: "{{ vault_db_user }}"
vault_api_token: "{{ vault_api_secret }}"
vault_ssl_private_key: "{{ vault_ssl_key }}"
vault_backup_encryption_passphrase: "{{ vault_backup_key }}"

Referenzierung im Playbook:

---
- name: Database configuration
  hosts: database_servers
  vars:
    db_connection:
      host: "{{ database_host }}"
      port: "{{ database_port }}"
      name: "{{ database_name }}"
      user: "{{ vault_database_user }}"
      password: "{{ vault_database_password }}"
  tasks:
    - name: Configure database access
      postgresql_user:
        name: "{{ db_connection.user }}"
        password: "{{ db_connection.password }}"
        db: "{{ db_connection.name }}"
        state: present

45.5.2 Rollenspezifische Vault-Dateien

Granulare Vault-Organisation:

group_vars/
├── all/
│   ├── vars.yml
│   └── vault.yml                 # Gemeinsame Secrets
├── database_servers/
│   ├── vars.yml
│   └── vault.yml                 # DB-spezifische Secrets
├── web_servers/
│   ├── vars.yml
│   └── vault.yml                 # Web-spezifische Secrets
└── monitoring/
    ├── vars.yml
    └── vault.yml                 # Monitoring-spezifische Secrets

Rollenspezifische Vault-Integration:

# roles/database/tasks/main.yml
---
- name: Include role-specific vault
  include_vars: "{{ item }}"
  with_first_found:
    - "{{ inventory_dir }}/group_vars/{{ inventory_hostname }}/vault.yml"
    - "{{ inventory_dir }}/group_vars/database_servers/vault.yml"
    - "{{ inventory_dir }}/group_vars/all/vault.yml"
  no_log: true

- name: Configure database with encrypted credentials
  postgresql_db:
    name: "{{ vault_db_name }}"
    owner: "{{ vault_db_owner }}"
    state: present
  become_user: postgres

45.5.3 Vault-IDs für verschiedene Umgebungen

Environment-spezifische Vault-ID-Struktur:

# Staging-Environment
ansible-vault create --vault-id staging@prompt group_vars/staging/vault.yml
ansible-vault encrypt_string --vault-id staging@prompt 'staging_secret' --name 'vault_api_key'

# Production-Environment  
ansible-vault create --vault-id production@prompt group_vars/production/vault.yml
ansible-vault encrypt_string --vault-id production@prompt 'production_secret' --name 'vault_api_key'

# Development-Environment
ansible-vault create --vault-id development@prompt group_vars/development/vault.yml

Vault-ID-Mapping-Datei:

# vault_ids.yml
vault_mappings:
  development:
    password_file: "{{ playbook_dir }}/.vault_dev"
    description: "Development environment secrets"
  staging:
    password_file: "{{ playbook_dir }}/.vault_staging"
    description: "Staging environment secrets"
  production:
    password_file: "{{ playbook_dir }}/.vault_prod"
    description: "Production environment secrets"

45.5.4 Empfehlungen zur Passwortverwaltung

Starke Vault-Passwörter:

Passwort-Manager-Integration:

# 1Password CLI Integration
ansible-vault encrypt --vault-id production@<(op read "op://vault/ansible-production/password") group_vars/production/vault.yml

# Bitwarden CLI Integration
ansible-vault view --vault-id staging@<(bw get password ansible-staging-vault) group_vars/staging/vault.yml

# HashiCorp Vault Integration
ansible-vault decrypt --vault-id production@<(vault kv get -field=password secret/ansible/production) group_vars/production/vault.yml

Rotations-Workflow für Vault-Passwörter:

#!/bin/bash
# vault_rotation.sh - Automated vault password rotation

ENVIRONMENTS=("staging" "production")
BACKUP_DIR="vault_backups/$(date +%Y%m%d)"

mkdir -p "$BACKUP_DIR"

for env in "${ENVIRONMENTS[@]}"; do
    echo "Rotating vault password for $env environment..."
    
    # Backup current vault files
    cp "group_vars/$env/vault.yml" "$BACKUP_DIR/vault_${env}_backup.yml"
    
    # Generate new password
    NEW_PASSWORD=$(openssl rand -base64 32)
    
    # Rekey vault with new password
    echo "Current password for $env:"
    ansible-vault rekey \
        --vault-id "$env@prompt" \
        --new-vault-id "$env@<(echo '$NEW_PASSWORD')" \
        "group_vars/$env/vault.yml"
    
    # Update password in secure storage
    # op item edit "ansible-${env}-vault" password="$NEW_PASSWORD"
    
    echo "Vault password rotated for $env environment"
done

echo "Vault rotation completed. Backups stored in $BACKUP_DIR"

45.6 Vault-Format und Sicherheitshinweise

45.6.1 Aufbau verschlüsselter Dateien ($ANSIBLE_VAULT)

Vault-Datei-Struktur:

$ANSIBLE_VAULT;1.1;AES256
66386439653237336464643061663135366461343536393934326135323634363761363134346362
3832623030626364333934663061626431303665333234300a323030643231373562636439643536
33663933373933313064346664383463323532663430653632383836383466343264386465623736
6164643963666231370a323663376131363533656239656638323065376261636534313138396562
...

Format-Komponenten:

45.6.2 AES256-Verschlüsselung

Ansible Vault verwendet AES256 im CBC-Modus mit PBKDF2-basierter Key-Derivation. Die Implementierung nutzt:

Kryptographische Eigenschaften:

# Analyse einer Vault-Datei
head -n 1 group_vars/production/vault.yml
# $ANSIBLE_VAULT;1.1;AES256

# Entropie-Überprüfung
ent group_vars/production/vault.yml
# Entropy = 7.999844 bits per byte.

45.6.3 Risiken bei ungeschütztem Vault-Zugriff

Potentielle Angriffsvektoren:

  1. Passwort-Brute-Force: Schwache Vault-Passwörter sind anfällig für Dictionary-Attacks
  2. Memory-Dumps: Entschlüsselte Inhalte könnten in Memory-Dumps erscheinen
  3. Log-Datei-Exposition: Vault-Passwörter in Logs oder Command-History
  4. Ungeschützte Passwort-Dateien: Klartext-Passwörter in zugänglichen Dateien
  5. Git-Repository-Exposition: Versehentliches Committen von Passwort-Dateien
  6. Shared-Storage-Risiken: Unverschlüsselte Vault-Passwörter in geteilten Systemen

Präventionsmaßnahmen:

# Sichere Passwort-Datei-Berechtigungen
chmod 600 ~/.vault_pass
chown $(id -u):$(id -g) ~/.vault_pass

# Passwort-Historie vermeiden
export HISTCONTROL=ignorespace
 ansible-vault view --vault-password-file ~/.vault_pass secrets.yml

# Memory-Dumps ausschließen
echo 'vm.core_dump_filter=0x33' >> /etc/sysctl.conf

# Sichere temporäre Dateien
export TMPDIR=/dev/shm
ansible-vault edit secrets.yml

# .gitignore für Passwort-Dateien
echo "*.vault_pass*" >> .gitignore
echo ".vault_*" >> .gitignore

45.7 Alternativen und Ergänzungen

45.7.1 Integration mit HashiCorp Vault

Vault-Plugin für dynamische Secrets:

# ansible.cfg
[inventory]
enable_plugins = host_list, script, auto, yaml, ini, toml, advanced_host_list

[lookup_plugins]
lookup_plugins = /usr/share/ansible/plugins/lookup

# Playbook mit HashiCorp Vault Lookup
---
- name: Retrieve dynamic secrets from HashiCorp Vault
  hosts: database_servers
  vars:
    vault_addr: https://vault.company.com:8200
    vault_token: "{{ lookup('env', 'VAULT_TOKEN') }}"
  tasks:
    - name: Get database credentials from Vault
      set_fact:
        db_credentials: "{{ lookup('hashi_vault', 'secret=secret/database/prod auth_method=token token=' + vault_token + ' url=' + vault_addr) }}"
      no_log: true

    - name: Configure database connection
      postgresql_user:
        name: "{{ db_credentials.username }}"
        password: "{{ db_credentials.password }}"
        state: present

Vault-Agent für automatische Token-Erneuerung:

# vault-agent.hcl
pid_file = "/var/run/vault-agent.pid"

auto_auth {
    method "aws" {
        mount_path = "auth/aws"
        config = {
            type = "iam"
            role = "ansible-runner"
        }
    }

    sink "file" {
        config = {
            path = "/opt/vault/token"
            mode = 0640
        }
    }
}

template {
    source      = "/etc/ansible/vault_pass.tpl"
    destination = "/etc/ansible/.vault_pass"
    perms       = 0600
}

45.7.2 Dynamische Secrets

CyberArk Integration:

---
- name: Retrieve secrets from CyberArk
  hosts: application_servers
  tasks:
    - name: Get application password
      cyberark_password:
        api_base_url: https://cyberark.company.com
        app_id: ansible_automation
        query: "Safe=ApplicationPasswords;Object={{ inventory_hostname }}_app_user"
        validate_certs: yes
      register: app_password
      no_log: true

    - name: Configure application with dynamic password
      template:
        src: app_config.j2
        dest: /etc/app/config.conf
        mode: '0600'
      vars:
        app_db_password: "{{ app_password.password }}"

Azure Key Vault Integration:

---
- name: Azure Key Vault secrets retrieval
  hosts: azure_vms
  tasks:
    - name: Authenticate to Azure
      azure_rm_auth:
        subscription_id: "{{ azure_subscription_id }}"
        client_id: "{{ azure_client_id }}"
        secret: "{{ azure_client_secret }}"
        tenant: "{{ azure_tenant_id }}"

    - name: Retrieve secret from Key Vault
      azure_rm_keyvault_secret:
        vault_uri: "https://{{ key_vault_name }}.vault.azure.net/"
        secret_name: database-password
        secret_version: current
      register: db_secret
      no_log: true

    - name: Use retrieved secret
      lineinfile:
        path: /etc/app/database.conf
        regexp: '^password='
        line: "password={{ db_secret.secret.value }}"
        mode: '0600'

AWS Secrets Manager Integration:

---
- name: AWS Secrets Manager integration
  hosts: aws_instances
  tasks:
    - name: Retrieve database credentials
      amazon.aws.aws_secret:
        name: "{{ app_name }}/database/credentials"
        region: "{{ aws_region }}"
      register: db_secret
      no_log: true

    - name: Parse JSON secret
      set_fact:
        db_creds: "{{ db_secret.secret | from_json }}"
      no_log: true

    - name: Configure application
      template:
        src: app.conf.j2
        dest: /etc/app/app.conf
        mode: '0600'
      vars:
        database_username: "{{ db_creds.username }}"
        database_password: "{{ db_creds.password }}"

45.8 Troubleshooting und Debugging

45.8.1 Häufige Vault-Probleme

Passwort-Probleme diagnostizieren:

# Vault-Datei validieren
ansible-vault view --vault-password-file ~/.vault_pass group_vars/production/vault.yml

# Syntax-Check mit verschlüsselten Dateien
ansible-playbook --syntax-check --vault-password-file ~/.vault_pass site.yml

# Debug-Modus für Vault-Operationen
ansible-playbook -vvv --vault-password-file ~/.vault_pass site.yml

Encoding- und Format-Probleme:

# Datei-Encoding überprüfen
file group_vars/production/vault.yml
# group_vars/production/vault.yml: ASCII text

# Vault-Header validieren
head -n 1 group_vars/production/vault.yml
# $ANSIBLE_VAULT;1.1;AES256

# Korrupte Vault-Datei reparieren
ansible-vault decrypt --output=temp_vault.yml group_vars/production/vault.yml
ansible-vault encrypt temp_vault.yml
mv temp_vault.yml group_vars/production/vault.yml

45.8.2 Performance-Optimierungen

Große Vault-Dateien optimieren:

# Vault-Dateien komprimieren (bei sehr großen Inhalten)
ansible-vault decrypt large_vault.yml
gzip large_vault.yml
ansible-vault encrypt large_vault.yml.gz

# Aufteilen großer Vault-Dateien
split -l 100 large_vault.yml vault_part_
for part in vault_part_*; do
    ansible-vault encrypt "$part"
done

Caching für wiederholte Vault-Zugriffe:

# Vault-Passwort für Session cachen
eval $(ssh-agent)
echo "export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass" >> ~/.bashrc

# Temporäres Entschlüsseln für intensive Bearbeitung
ansible-vault decrypt group_vars/production/vault.yml
# ... Bearbeitung ...
ansible-vault encrypt group_vars/production/vault.yml