You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
montpelliermaalsi2024/devSecOps/ansible_decrypt.md

7.1 KiB

Ansible Vault SSH Key Management Guide

Overview

This document explains how to securely manage SSH private keys using Ansible Vault and the copy module with decryption capabilities, including proper playbook configuration to handle decryption before fact gathering.

Important: Playbook Configuration

Critical Setup Requirements

---
- name: Deploy with encrypted SSH key
  hosts: all
  gather_facts: false  # ⚠️ ESSENTIAL - prevents early SSH connection attempts
  vars:
    ssh_private_key_file: key/deploy  # Path to your encrypted key file
  
  tasks:
    # Your decryption and deployment tasks here

Why gather_facts: false is Mandatory

Without gather_facts: false:

  • Ansible attempts to connect to target hosts immediately
  • It tries to use SSH with the default SSH agent configuration
  • Fails because the encrypted key isn't decrypted yet
  • Playbook stops before reaching your decryption task

With gather_facts: false:

  • Ansible skips the initial fact gathering phase
  • Allows your decryption task to run first
  • You control when and how the SSH key is used

Step 1: Encrypt SSH Private Key with Ansible Vault

Encrypt an existing SSH key:

# Method 1: Interactive password prompt
ansible-vault encrypt key/deploy --ask-vault-pass

# Method 2: Using a password file
ansible-vault encrypt key/deploy --vault-password-file vault_pass.txt

# Method 3: Using vault ID
ansible-vault encrypt key/deploy --vault-id deploy@vault_pass.txt

Create a new encrypted SSH key:

ansible-vault create key/deploy --vault-password-file vault_pass.txt

Verify encrypted content:

ansible-vault view key/deploy --vault-password-file vault_pass.txt

Step 2: Complete Ansible Playbook Example

Full playbook structure:

---
- name: Deploy using encrypted SSH key
  hosts: all
  gather_facts: false  # CRITICAL: Must be disabled
  vars:
    ssh_private_key_file: key/deploy
    decrypted_key_path: /tmp/ansible_deploy_key
  
  tasks:
    - name: Decrypt SSH private key
      copy:
        src: "{{ ssh_private_key_file }}"
        dest: "{{ decrypted_key_path }}"
        decrypt: yes
        mode: '0600'
      delegate_to: localhost
      become: false
      run_once: true

    - name: Enable fact gathering with decrypted key
      setup:
      delegate_to: localhost
      become: false

    - name: Use the decrypted key for deployment
      ansible.builtin.shell: |
        ssh -i "{{ decrypted_key_path }}" \
            -o StrictHostKeyChecking=no \
            -o UserKnownHostsFile=/dev/null \
            deploy@{{ inventory_hostname }} 'deployment_command'        
      args:
        executable: /bin/bash

    - name: Remove decrypted SSH key (cleanup)
      file:
        path: "{{ decrypted_key_path }}"
        state: absent
      delegate_to: localhost
      become: false
      always: yes

Step 3: Running the Playbook

Execution methods:

# With password file
ansible-playbook playbook.yml --vault-password-file vault_pass.txt

# Interactive password prompt
ansible-playbook playbook.yml --ask-vault-pass

# With vault ID
ansible-playbook playbook.yml --vault-id deploy@vault_pass.txt

# With inventory file
ansible-playbook -i hosts.ini playbook.yml --vault-password-file vault_pass.txt

Step 4: Advanced Error Handling & Security

Robust playbook with proper error handling:

---
- name: Secure deployment with encrypted SSH key
  hosts: all
  gather_facts: false
  vars:
    ssh_private_key_file: key/deploy
    decrypted_key_path: "/tmp/ansible_deploy_key_{{ ansible_date_time.epoch }}"
  
  tasks:
    - name: Ensure encrypted key file exists
      stat:
        path: "{{ ssh_private_key_file }}"
      register: key_file
      delegate_to: localhost
      become: false
    
    - name: Fail if encrypted key is missing
      fail:
        msg: "Encrypted SSH key file {{ ssh_private_key_file }} not found"
      when: not key_file.stat.exists
      delegate_to: localhost
      become: false

    - name: Decrypt SSH private key
      copy:
        src: "{{ ssh_private_key_file }}"
        dest: "{{ decrypted_key_path }}"
        decrypt: yes
        mode: '0600'
      delegate_to: localhost
      become: false
      run_once: true

    - name: Verify decrypted key permissions
      file:
        path: "{{ decrypted_key_path }}"
        mode: '0600'
      delegate_to: localhost
      become: false

    - name: Gather facts using decrypted key (if needed)
      setup:
      delegate_to: localhost
      become: false

    - name: Perform deployment tasks
      block:
        - name: Execute remote deployment
          ansible.builtin.shell: |
            ssh -i "{{ decrypted_key_path }}" \
                -o ConnectTimeout=30 \
                -o StrictHostKeyChecking=no \
                deploy@{{ inventory_hostname }} 'your_deployment_script'            
          args:
            executable: /bin/bash
          register: deployment_result
        
        - name: Display deployment output
          debug:
            var: deployment_result.stdout

      rescue:
        - name: Handle deployment failure
          debug:
            msg: "Deployment failed - check SSH connectivity and permissions"
      
      always:
        - name: Always remove decrypted key
          file:
            path: "{{ decrypted_key_path }}"
            state: absent
          delegate_to: localhost
          become: false

Security Best Practices

1. File Security:

# Secure permissions for password files
chmod 600 vault_pass.txt

# Secure permissions for encrypted key
chmod 600 key/deploy

2. Temporary File Safety:

  • Use unique temporary filenames with timestamps
  • Set strict permissions (0600)
  • Always clean up, even on failure

3. Key Management:

  • Never store unencrypted keys in version control
  • Rotate deployment keys regularly
  • Use different keys for different environments

Troubleshooting

Common Issues & Solutions:

  1. "Permission denied" errors:

    • Verify vault password is correct
    • Check encrypted file permissions
    • Ensure cleanup tasks run successfully
  2. SSH connection failures:

    • Verify the decrypted key is authorized on target hosts
    • Check network connectivity
    • Validate target host accessibility
  3. Fact gathering issues:

    • Use gather_facts: false in main playbook
    • Manually call setup module after decryption if needed

Debug Commands:

# Test vault decryption
ansible-vault view key/deploy --vault-password-file vault_pass.txt

# Verify playbook syntax
ansible-playbook playbook.yml --syntax-check

# Dry run to see what would happen
ansible-playbook playbook.yml --vault-password-file vault_pass.txt --check

Summary

The key points for successful encrypted SSH key management:

  1. Always use gather_facts: false in the main playbook
  2. Decrypt the key early in your tasks
  3. Use unique temporary paths for decrypted keys
  4. Always clean up decrypted keys, even on failures
  5. Secure your vault passwords with proper file permissions

This approach ensures your SSH keys remain encrypted at rest and are only temporarily decrypted during execution, maintaining security throughout your deployment process.