# Comprehensive guide for mastering Ansible automation, from creating web servers with MySQL databases
# to automating SSH key distribution and securing the servers.
Table of Contents
- Setting Up Ansible (opens in a new tab)
- Creating and Managing Droplets on DigitalOcean (opens in a new tab)
- Configuring Inventory and Variables (opens in a new tab)
- Automatically Distributing SSH Keys (opens in a new tab)
- Creating Users with Hashed Passwords (opens in a new tab)
- Setting Up Web Servers and MySQL (opens in a new tab)
- Securing Ubuntu (opens in a new tab)
- Using Ansible Vault for Sensitive Data (opens in a new tab)
- Best Practices, Tips, and Tricks (opens in a new tab)
- Detailed Documentation (opens in a new tab)
1. Setting Up Ansible (opens in a new tab)
# Install Ansible and verify installation on your control machine
sudo apt update
sudo apt install ansible -y
ansible --version
# Ansible configuration file (ansible.cfg) for efficiency
[defaults]
inventory = ./inventory.yml
remote_user = root
host_key_checking = False
2. Creating and Managing Droplets on DigitalOcean (opens in a new tab)
# Create 3 Ubuntu 24.04 droplets with SSH keys for secure login.
# Manually add your SSH key to droplets
ssh-copy-id root@<droplet-ip>
3. Configuring Inventory and Variables (opens in a new tab)
# Define server groupings in inventory.yml
all:
hosts:
web1:
ansible_host: <web1-ip>
ansible_user: root
web2:
ansible_host: <web2-ip>
ansible_user: root
web3:
ansible_host: <web3-ip>
ansible_user: root
vars:
ansible_python_interpreter: /usr/bin/python3
4. Automatically Distributing SSH Keys (opens in a new tab)
Creating Users (opens in a new tab)
# distribute_ssh_keys.yml: Automate SSH key distribution to all servers
---
- hosts: all
become: yes
tasks:
# Task: Create users and add SSH keys for passwordless login
- name: "Create users and add SSH keys"
user:
name: "{{ item.name }}"
state: present
shell: /bin/bash
createhome: yes
with_items:
- { name: 'deploy', groups: 'sudo' }
# Task: Install SSH key for 'deploy' user
- name: "Install authorized SSH key"
authorized_key:
user: "deploy"
key: "{{ lookup('file', '/home/local_user/.ssh/id_rsa.pub') }}"
# Run the playbook to distribute SSH keys
ansible-playbook distribute_ssh_keys.yml
5. Creating Users with Hashed Passwords (opens in a new tab)
# Generate hashed passwords using Python or OpenSSL
python3 -c "import crypt; print(crypt.crypt('YOUR_PASSWORD', crypt.mksalt(crypt.METHOD_SHA512)))"
openssl passwd -6
# user_with_hashed_password.yml: Playbook to create users with hashed passwords
---
- hosts: all
become: yes
vars:
users:
- name: deploy
password: "$6$random_salt$hash"
tasks:
# Task: Create users with hashed passwords for better security
- name: "Create users with hashed passwords"
user:
name: "{{ item.name }}"
password: "{{ item.password }}"
state: present
shell: /bin/bash
with_items: "{{ users }}"
# Run the playbook to create users with hashed passwords
ansible-playbook user_with_hashed_password.yml
6. Setting Up Web Servers and MySQL (opens in a new tab)
# webserver_setup.yml: Playbook for installing Nginx web server
---
- hosts: webservers
become: yes
tasks:
# Task: Install Nginx web server
- name: "Install Nginx"
apt:
name: nginx
state: present
update_cache: yes
# Task: Ensure Nginx service is running and enabled
- name: "Ensure Nginx is running"
service:
name: nginx
state: started
enabled: yes
6A. Ansible mysql_db Module (opens in a new tab)
Ansible mysql_user Module (opens in a new tab) Ansible mysql_query Module (opens in a new tab)
Vault File Setup
Create a Vault file to store sensitive variables securely:
ansible-vault create secrets.yml
Add the following content to secrets.yml
:
mysql_root_password: "your_secure_password_here"
Playbook: mysql_setup.yml
- hosts: database
become: yes
vars_files:
- /path/to/secrets.yml
tasks:
- name: Install MySQL server
apt:
name: mysql-server
state: present
- name: Set MySQL root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
host: localhost
state: present
- name: Remove anonymous MySQL users
mysql_user:
name: ""
host: "%"
state: absent
- name: Remove remote root user
mysql_user:
name: root
host: "{{ item }}"
state: absent
with_items:
- 'localhost'
- '127.0.0.1'
- name: Remove test database
mysql_db:
name: test
state: absent
- name: Reload MySQL privilege tables
mysql_query:
query: "FLUSH PRIVILEGES;"
Task Details
-
Install MySQL Server
- Purpose: Install the MySQL server package.
- Module:
apt
- Parameters:
name
:mysql-server
state
:present
-
Set MySQL Root Password
- Purpose: Set the root password for MySQL.
- Module:
mysql_user
- Parameters:
name
:root
password
: Retrieved from the Vault filehost
:localhost
state
:present
-
Remove Anonymous MySQL Users
- Purpose: Remove any anonymous users in MySQL.
- Module:
mysql_user
- Parameters:
name
:""
(empty name matches anonymous users)host
:%
(all hosts)state
:absent
-
Remove Remote Root User
- Purpose: Remove the root user with remote access.
- Module:
mysql_user
- Parameters:
name
:root
host
:localhost
and127.0.0.1
state
:absent
-
Remove Test Database
- Purpose: Remove the default test database.
- Module:
mysql_db
- Parameters:
name
:test
state
:absent
-
Reload MySQL Privilege Tables
- Purpose: Apply changes by reloading MySQL privilege tables.
- Module:
mysql_query
- Parameters:
query
:FLUSH PRIVILEGES;
Running the Playbook
Execute the playbook with the Vault password file or interactive prompt:
ansible-playbook mysql_setup.yml --vault-password-file /path/to/vault-password-file
Or use the interactive prompt:
ansible-playbook mysql_setup.yml --ask-vault-pass
Summary
- Secure MySQL: This playbook automates the installation and configuration of MySQL to ensure a secure setup.
- Manage Secrets: Use Ansible Vault to securely handle sensitive data such as MySQL root passwords.
- Automate: Achieve consistent MySQL configurations across different environments using Ansible.
7. Securing Ubuntu with ufw (opens in a new tab)
# ufw_setup.yml: Playbook for setting up UFW (Uncomplicated Firewall)
---
- hosts: all
become: yes
tasks:
# Task: Allow OpenSSH for SSH access
- name: "Allow OpenSSH"
ufw:
rule: allow
name: OpenSSH
# Task: Allow Nginx HTTP access
- name: "Allow Nginx HTTP"
ufw:
rule: allow
name: Nginx HTTP
# Task: Enable UFW
- name: "Enable UFW"
ufw:
state: enabled
7B. Securing Ubuntu with ssh module (opens in a new tab)
# ssh_hardening.yml: Playbook to harden SSH security
---
- hosts: all
become: yes
tasks:
# Task: Disable root login for better security
- name: "Disable root login"
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
# Task: Change SSH port from default 22 to a custom port
- name: "Change SSH port"
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#Port 22'
line: 'Port 2222'
# Task: Restart SSH service to apply changes
- name: "Restart SSH"
service:
name: ssh
state: restarted
# Run the security playbooks
ansible-playbook ufw_setup.yml
ansible-playbook ssh_hardening.yml
Explanation
lineinfile module (opens in a new tab)
- name: "Disable root login"
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
- name: "Ensure Port 22 is uncommented"
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#Port 22'
line: 'Port 22'
name
: Descriptive name of the task for readability and documentation.lineinfile
: An Ansible module used to ensure a specific line is present or absent in a file.path
: Specifies the path to the file you want to modify (/etc/ssh/sshd_config
in this case).regexp
: A regular expression that identifies the line to be replaced. Here, it matches lines that start withPermitRootLogin
.line
: The line to ensure is present in the file. If a line matching the regular expression is found, it will be replaced with this line.
What It Does:
- The task searches for any line in
/etc/ssh/sshd_config
that starts withPermitRootLogin
. - It replaces that line with
PermitRootLogin no
, effectively disabling root login via SSH.
Regular Expression Cheat Sheet
Here’s a basic cheat sheet for common regular expression patterns and their meanings:
Pattern | Description | Example Matches |
---|---|---|
. | Any single character except newline | a , b , 1 |
^ | Start of a string | ^abc matches abc but not zabc |
$ | End of a string | abc$ matches abc but not abcd |
* | 0 or more of the preceding element | a* matches ``, a , aa |
+ | 1 or more of the preceding element | a+ matches a , aa but not `` |
? | 0 or 1 of the preceding element | a? matches ``, a |
{n} | Exactly n occurrences of the preceding element | a{2} matches aa |
{n,} | At least n occurrences of the preceding element | a{2,} matches aa , aaa |
{n,m} | Between n and m occurrences of the preceding element | a{2,4} matches aa , aaa , aaaa |
[] | Any one of the characters inside the brackets | [abc] matches a , b , c |
[^ ] | Any one character not inside the brackets | [^abc] matches d , e but not a , b , c |
` | ` | Alternation (or) |
() | Grouping | (abc)+ matches abc , abcabc |
\ | Escape a special character | \. matches . |
Usage Tips
- Use
.
for matching any character except newlines. - Use
*
and+
for matching repeated characters or patterns. - Use
^
and$
to anchor patterns to the start or end of a string. - Use
[]
to match any one of a set of characters. - Use
()
for grouping and|
for alternation.
Regular expressions can be very powerful but also complex. The cheat sheet provides a foundation to get started with basic patterns and operations.
8. Using Ansible Vault for Sensitive Data (opens in a new tab)
# Encrypt sensitive data, like MySQL passwords, using Ansible Vault
ansible-vault encrypt_string 'your-mysql-password' --name 'vault_mysql_password'
# Example of using Ansible Vault in a playbook
vars:
mysql_root_password: !vault |
$ANSIBLE_VAULT;1.1;AES256;...
# Run playbooks that use Ansible Vault for sensitive data
ansible-playbook playbook.yml --ask-vault-pass
9. Best Practices, Tips, and Tricks (opens in a new tab)
Folder Structure:
Organize your Ansible files to make them reusable and scalable:
├── ansible.cfg
├── inventory.yml
├── group_vars
│ ├── all.yml
├── host_vars
│ ├── web1.yml
├── roles
│ ├── common
│ ├── webserver
│ ├── mysql
Best Practices:
- Idempotency: Ensure tasks can run repeatedly without unintended consequences.
- YAML Syntax: Always use correct YAML indentation and formatting.
- Modularity: Use roles to make your playbooks modular and reusable.
- Testing: Use
--check
and--diff
flags to test playbooks before applying changes.
Useful Tricks:
- Dry Run: Use
--check
to simulate playbook execution without making changes. - View Changes: Use
--diff
to see exactly what will be changed. - Parallelism: Use
-f
to run playbooks on multiple hosts in parallel.
10. Detailed Documentation (opens in a new tab)
For more details, refer to Ansible Documentation (opens in a new tab) for official guides and best practices.
This guide aims to provide a thorough understanding of Ansible and its use for automating server setup, configuration, and security tasks.