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

261 lines
7.1 KiB
Markdown

# 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
```yaml
---
- 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:
```bash
# 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:
```bash
ansible-vault create key/deploy --vault-password-file vault_pass.txt
```
### Verify encrypted content:
```bash
ansible-vault view key/deploy --vault-password-file vault_pass.txt
```
## Step 2: Complete Ansible Playbook Example
### Full playbook structure:
```yaml
---
- 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:
```bash
# 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:
```yaml
---
- 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:
```bash
# 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:
```bash
# 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.