Implementing Security Best Practices
1. Using Ansible Vault
| Command | Description | Example |
|---|---|---|
| ansible-vault create | Create a new encrypted file | ansible-vault create secret.yml |
| ansible-vault edit | Edit an existing encrypted file | ansible-vault edit secret.yml |
| ansible-vault view | View the contents of an encrypted file | ansible-vault view secret.yml |
| ansible-vault encrypt | Encrypt an existing file | ansible-vault encrypt secret.yml |
| ansible-vault decrypt | Decrypt an existing file | ansible-vault decrypt secret.yml |
Example: Using Vault in Playbook
- name: Example Playbook with Vault
hosts: all
vars:
secret_key: "{{ vault_secret_key }}"
tasks:
- name: Print secret
debug:
msg: "Secret key is {{ secret_key }}"
Note: Vault requires a password to encrypt/decrypt files. This password can be provided via
--vault-password-file or interactively.
Warning: Never store vault passwords in plain text files or commit them to version control.
| Option | Description | Default |
|---|---|---|
| --vault-id | Specify a vault ID to use | default |
| --vault-password-file | Path to a file containing the vault password | None |
| --ask-vault-pass | Ask for vault password at runtime | false |
2. Managing SSH Keys
| Property | Description | Default | Notes |
|---|---|---|---|
| ansible_ssh_private_key_file | Path to the private SSH key file used for authentication. | None | Must be a valid path to a private key file (e.g., ~/.ssh/id_rsa) |
| ansible_ssh_public_key_file | Path to the public SSH key file used for authentication. | None | Used for validating host keys or setting up key-based auth. |
| ansible_ssh_pass | Password for SSH authentication (not recommended for production). | None | Deprecated in favor of key-based authentication. |
| ansible_ssh_user | Username to use for SSH connections. | root |
Can be overridden per host or group. |
| ansible_ssh_port | Port to use for SSH connections. | 22 |
Change if SSH is running on a non-standard port. |
Example: Using SSH Key for Authentication
---
- name: Deploy application using SSH key
hosts: webservers
vars:
ansible_ssh_private_key_file: "~/.ssh/deploy_key"
tasks:
- name: Ensure application directory exists
file:
path: /opt/myapp
state: directory
Note: It is highly recommended to use SSH key-based authentication instead of passwords for Ansible automation. Passwords are less secure and harder to manage at scale.
Warning: Never store SSH private keys in plain text within playbooks or inventories. Use
ansible-vault to encrypt sensitive data like private keys.
Best Practices for SSH Key Management
- Use dedicated deployment keys with minimal permissions.
- Rotate SSH keys regularly (e.g., every 90 days).
- Store private keys securely with restricted file permissions (e.g.,
chmod 600). - Use
ansible-vaultto encrypt sensitive inventory variables. - Implement key revocation procedures for compromised keys.
3. Setting Become Password
| Parameter | Description | Default | Notes |
|---|---|---|---|
| become_password | Password for privilege escalation | None | Used with become to provide password for sudo/su |
Example: Using become_password in a playbook
- hosts: all
become: yes
become_password: "{{ vault_become_pass }}"
tasks:
- name: Install a package
apt:
name: nginx
state: present
Note: It is recommended to store passwords in encrypted vaults rather than plain text.
Warning: Storing passwords in plain text files is a security risk. Use Ansible Vault for sensitive data.
4. Disabling Root Login
| Configuration | Description | Value |
|---|---|---|
| ansible_become | Enables privilege escalation | true |
| ansible_become_method | Method used for privilege escalation | sudo |
| ansible_become_user | User to escalate to | root |
Example: Disabling Root Login via SSH
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config
sudo systemctl restart sshd
Note: Ensure that alternative user accounts with appropriate permissions are configured before disabling root login.
Warning: Disabling root login can prevent emergency access if SSH keys are lost or compromised.
5. Validating Module Sources
| Source Type | Validation Method | Notes |
|---|---|---|
| Ansible Galaxy | ansible-galaxy install --collections-path ./collections ansible.posix |
Verify collection integrity using checksums from Galaxy |
| Git Repositories | ansible-galaxy collection install git+https://github.com/owner/repo.git |
Ensure repository is from a trusted source and has valid GPG signatures |
| Local Files | ansible-galaxy collection install ./my_collection.tar.gz |
Validate tarball integrity with SHA256 checksums before installation |
Example: Verifying Collection Integrity
ansible-galaxy collection install --collections-path ./collections ansible.posix
# Output includes verification steps
Note: Always verify GPG signatures when installing collections from untrusted sources.
Warning: Do not install collections from unknown sources without validating their integrity.
6. Setting File Permissions
| Permission | Octal Value | Description |
|---|---|---|
| Read (r) | 4 |
Allows reading the file content |
| Write (w) | 2 |
Allows modifying the file content |
| Execute (x) | 1 |
Allows executing the file as a program |
Example: Setting File Permissions with Ansible
- name: Set file permissions to 644
ansible.builtin.file:
path: /etc/myapp/config.ini
mode: '0644'
owner: myuser
group: mygroup
Example: Setting Directory Permissions with Ansible
- name: Set directory permissions to 755
ansible.builtin.file:
path: /var/www/html
state: directory
mode: '0755'
owner: www-data
group: www-data
Note: The
mode parameter in Ansible uses octal notation. For example, 0644 means owner has read/write (6), group and others have read-only (4).
Warning: Be cautious when setting permissions to
0777 or similar overly permissive values, as they can expose sensitive files to unauthorized access.
Key Points for File Permissions
- Use octal notation (e.g.,
0644) for setting permissions in Ansible - Ensure proper ownership using
ownerandgroupparameters - Avoid overly permissive permissions like
0777for security reasons - Use
ansible.builtin.filemodule to manage file and directory permissions
7. Limiting Privilege Escalation
| Directive | Description | Default Behavior | Notes |
|---|---|---|---|
| become | Enables privilege escalation for a task | false |
Set to true to escalate privileges |
| become_method | Specifies the privilege escalation method (e.g., sudo, su) |
sudo |
Must be supported by the target system |
| become_user | Specifies the user to escalate to | root |
Can be any valid system user |
| become_flags | Additional flags to pass to the become method (e.g., -H) |
None | Used to configure behavior of sudo or su |
Example: Using become with sudo
- name: Install package with elevated privileges
apt:
name: nginx
state: present
become: true
become_method: sudo
become_user: root
Note: Privilege escalation should be limited to only necessary tasks and users. Avoid using
become in roles or playbooks unless strictly required.
Warning: Misconfiguring
become can lead to security vulnerabilities. Ensure that only authorized users or roles have access to tasks requiring privilege escalation.
8. Using Separate Vault Files
| File Type | Description | Usage |
|---|---|---|
| .vault | Encrypted files containing sensitive data | Store credentials, keys, and secrets |
| .yml | YAML files with encrypted content | Used in playbooks or roles |
Example: Using Vault File in Playbook
- name: Use Vault Data
hosts: all
vars:
secret_key: "{{ vault_secret_key }}"
tasks:
- debug:
msg: "Secret key is {{ secret_key }}"
Note: Vault files must be decrypted during runtime to access their contents.
Warning: Never commit unencrypted vault files to version control.
9. Auditing Playbook Runs
| Aspect | Description | Notes |
|---|---|---|
| ansible-playbook --check | ansible-playbook --check --diff playbook.yml |
Simulates run without making changes; shows differences |
| --diff | ansible-playbook --diff playbook.yml |
Shows changes made to files during execution |
| --verbose | ansible-playbook -vvv playbook.yml |
Increases verbosity for detailed logging |
| log_path | ansible.cfg |
Configures where logs are stored (e.g., log_path = /var/log/ansible.log) |
| callback_plugins | ansible.cfg |
Enables custom logging plugins (e.g., callback_plugins = /path/to/custom_logger) |
Note: Use
--check mode to preview changes before applying them in production environments.
Warning: Ensure log paths are secure and accessible only to authorized users.
10. Implementing RBAC
| Role | Description | Permissions | Assignment |
|---|---|---|---|
| admin | Full access to all Ansible components | All actions on inventories, playbooks, and configurations | Assigned to system administrators |
| operator | Manage playbooks and inventory | Read/write access to playbooks, read-only to inventory | Assigned to operational staff |
| viewer | Read-only access to Ansible components | Read-only access to all resources | Assigned to auditors or support staff |
Example: Role Assignment in Ansible Tower
---
- name: Assign roles to users
hosts: localhost
tasks:
- name: Add user to admin group
tower_role:
user: admin_user
role: admin
organization: my_org
Note: RBAC in Ansible Tower is managed through the UI or API. Ensure that roles are assigned based on the principle of least privilege.
11. Using Jump Hosts
Jump hosts (also known as bastion hosts) are used to securely access systems that are not directly accessible from the control node. This is particularly useful in environments where systems are behind firewalls or in private networks.
| Parameter | Description | Example |
|---|---|---|
| ansible_ssh_jump | Specifies the jump host to use for connecting to a target host. | ansible_ssh_jump=jump.example.com |
| ansible_ssh_jump_host | Alternative parameter for specifying the jump host. | ansible_ssh_jump_host=jump.example.com |
| ansible_ssh_proxy_command | Custom SSH proxy command to use for connecting through the jump host. | ansible_ssh_proxy_command=ssh -W %h:%p jump.example.com |
Example: Using Jump Host in Inventory
[webservers]
web1 ansible_host=10.0.1.10 ansible_ssh_jump=jump.example.com
[jump_hosts]
jump.example.com ansible_host=192.168.1.10
Example: Using Proxy Command in Playbook
- name: Configure web server via jump host
hosts: web1
vars:
ansible_ssh_proxy_command: "ssh -W %h:%p jump.example.com"
tasks:
- name: Ensure nginx is installed
apt:
name: nginx
state: present
Note: Ensure that the jump host has appropriate SSH keys and permissions to access the target systems.
Warning: Misconfiguring jump hosts can lead to security vulnerabilities or connectivity issues. Always test configurations in a non-production environment.
12. Validating Input
| Input Type | Description | Validation Method | Example |
|---|---|---|---|
| Inventory Variables | Variables defined in inventory files or groups | Use validate with type and required |
ansible_host: "{{ hostvars[inventory_hostname].ansible_host | default('localhost') }}" |
| Host Facts | System information gathered by Ansible | Use gather_facts and validate with assert |
|
| User Input | Variables passed via command line or extra vars | Use vars_prompt and validate |
|
Example: Validating User Input in Playbook
---
- hosts: all
vars_prompt:
- name: "environment"
prompt: "Enter environment (prod/staging/dev)"
default: "dev"
validator: "^(prod|staging|dev)$"
tasks:
- name: Ensure environment is valid
assert:
that:
- "environment in ['prod', 'staging', 'dev']"
fail_msg: "Invalid environment provided: {{ environment }}"