Compare commits
5 Commits
main
...
5691924266
| Author | SHA1 | Date | |
|---|---|---|---|
| 5691924266 | |||
| efe7308200 | |||
| 78b85c892e | |||
| 950568ef3b | |||
| d8dbfbd328 |
32
README.md
32
README.md
@@ -19,35 +19,3 @@ This Ansible setup is designed to automate the configuration and maintenance of
|
||||
```bash
|
||||
ansible-playbook -i inventory/hosts.ini playbooks/apt_upgrade.yml
|
||||
```
|
||||
|
||||
## Proxmox Integration Setup
|
||||
|
||||
To use the provisioning playbooks (`create_lxc.yml`), you must configure Proxmox API access.
|
||||
|
||||
### 1. Requirements on Control Node
|
||||
Install `community.general` collection and `proxmoxer` python library:
|
||||
```bash
|
||||
sudo apt install python3-proxmoxer # OR pip3 install proxmoxer requests
|
||||
ansible-galaxy collection install community.general
|
||||
```
|
||||
|
||||
### 2. Create Proxmox User & Token
|
||||
1. **Create User**: In Proxmox, go to **Datacenter > Permissions > Users** and add `ansible@pve` (Proxmox VE authentication).
|
||||
2. **Create Token**: Go to **API Tokens**, add a token for `ansible@pve` (e.g., `ansible-token`). **Save the Secret!**
|
||||
3. **Permissions**: Go to **Permissions**, add User Permission for `ansible@pve`:
|
||||
- Path: `/`
|
||||
- Role: `Administrator` (Easiest)
|
||||
- **OR** Granular Roles:
|
||||
- Path: `/` -> `PVEVMAdmin` + `Sys.Audit`
|
||||
- Path: `/storage/local` (or your storage ID) -> `Datastore.AllocateSpace` + `Datastore.Audit`
|
||||
|
||||
### 3. Configure Secrets
|
||||
Update your `secrets.yml` (do not commit this file!) with the credentials:
|
||||
|
||||
```yaml
|
||||
proxmox_api_user: "ansible@pve"
|
||||
proxmox_api_token_id: "ansible-token"
|
||||
proxmox_api_token_secret: "YOUR_SECRET_HERE"
|
||||
proxmox_node: "proxmox"
|
||||
proxmox_storage: "local"
|
||||
```
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[defaults]
|
||||
host_key_checking = False
|
||||
inventory = inventory/hosts.ini
|
||||
@@ -1 +1 @@
|
||||
cd /opt/ansible/ && ansible-playbook -i inventory/hosts.ini playbooks/apt_upgrade.yml -l ubuntu --extra-vars "@vars.yml" --extra-vars "@secrets.yml"
|
||||
cd /home/mbuz/git/homelab/Ansible/ && ansible-playbook -i inventory/hosts.ini playbooks/apt_upgrade.yml -l ubuntu --extra-vars "@vars.yml" --extra-vars "@secrets.yml"
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
### Copy this into secrets.yml and replate with a real values ###
|
||||
|
||||
# Password used for Ansible to connect to LXC as root (if not using SSH keys)
|
||||
lxc_root_password: 'REPLACE_WITH_ROOT_PASSWORD'
|
||||
# Copy this into secrets.yml and replate with a real values
|
||||
ansible_password: 'REPLACE_WITH_ROOT_PASSWORD'
|
||||
# Zabbix proxy parameters for connecting to Zabbix server
|
||||
zabbix_server_address: 'x.x.x.x'
|
||||
zabbix_psk_identity: '<zabbix_psk_identity'
|
||||
zabbix_proxy_hostname: '<zabbix_proxy_hostname>' # if needed, in the actual playbook it is set to the hostname of the target
|
||||
zabbix_proxy_psk: 'REPLACE_WITH_ZABBIX_PSK'
|
||||
|
||||
# Proxmox parameters for connecting to Proxmox server
|
||||
proxmox_api_user: "ansible@pve"
|
||||
proxmox_api_token_id: "ansible-token"
|
||||
proxmox_api_token_secret: "YOUR_SECRET_HERE"
|
||||
proxmox_node: "proxmox"
|
||||
proxmox_storage: "local" # or specific storage for users
|
||||
zabbix_proxy_psk: 'REPLACE_WITH_ZABBIX_PSK'
|
||||
@@ -19,9 +19,12 @@ truenas ansible_host=10.0.0.200
|
||||
[lxc]
|
||||
gitea ansible_host=10.0.0.108
|
||||
zabbix-proxy ansible_host=10.0.0.110
|
||||
pi-hole ansible_host=10.0.0.104
|
||||
ansible ansible_host=10.0.0.111
|
||||
tailscale-router ansible_host=10.0.0.100
|
||||
adguard ansible_host=10.0.0.104
|
||||
automate ansible_host=10.0.0.112
|
||||
|
||||
#localhost ansible_connection=local # for testing playbooks on the control node
|
||||
|
||||
|
||||
[pbs]
|
||||
proxmox-backup ansible_host=10.0.0.201
|
||||
@@ -30,4 +33,4 @@ proxmox-backup ansible_host=10.0.0.201
|
||||
[ubuntu:children]
|
||||
docker
|
||||
ubuntu_servers
|
||||
lxc
|
||||
lxc
|
||||
@@ -1,58 +0,0 @@
|
||||
# Ansible Playbooks
|
||||
|
||||
This directory contains automation playbooks for managing the homelab infrastructure.
|
||||
|
||||
## Provisioning & Setup
|
||||
|
||||
### `create_lxc.yml`
|
||||
**Creates and bootstraps a new LXC container on Proxmox.**
|
||||
- **Input**: Prompts for Container Name, IP Address, VMID, CPU Cores, and Memory.
|
||||
- **Actions**:
|
||||
1. Connects to Proxmox API to create a new unprivileged LXC container.
|
||||
2. **Injects SSH Keys**: Uses `vars.yml` to inject public keys directly into `/root/.ssh/authorized_keys` (bypassing password auth).
|
||||
3. Starts the container and waits for connectivity.
|
||||
4. Automatically secures the container (creates `mbuz` user, secures SSH, disables root) effectively running the logic of `lxc_setup_ubuntu.yml`.
|
||||
5. Adds the new host to `inventory/hosts.ini` in the `[lxc]` group.
|
||||
|
||||
### `lxc_setup_ubuntu.yml`
|
||||
**Secures a fresh Ubuntu installation.**
|
||||
- **Target**: Hosts in the `[new]` group (or fresh installs).
|
||||
- **Actions**:
|
||||
1. Creates the administrative user (`mbuz`).
|
||||
2. Sets up SSH public key authentication.
|
||||
3. Disables root login and password authentication for SSH.
|
||||
4. Configures passwordless `sudo` for the admin user.
|
||||
5. **Inventory Update**: Moves the host from the `[new]` group to the `[lxc]` group in `hosts.ini`.
|
||||
|
||||
### `lxc_setup_ubuntu_git.yml`
|
||||
**Provisions application dependencies on managed hosts.**
|
||||
- **Target**: Existing managed hosts (e.g., `[lxc]`).
|
||||
- **Actions**:
|
||||
1. Installs `git` and core utilities.
|
||||
2. Clones the central Docker configuration repository from the local Gitea server.
|
||||
3. Prepares the `/opt/docker` directory structure.
|
||||
|
||||
## Maintenance & Upgrades
|
||||
|
||||
### `apt_upgrade.yml`
|
||||
**Performs system-wide updates.**
|
||||
- **Target**: All Ubuntu hosts.
|
||||
- **Actions**:
|
||||
1. Updates `apt` cache.
|
||||
2. Performs `dist-upgrade`.
|
||||
3. Autoremoves unused packages.
|
||||
4. Checks for and notifies if a reboot is required.
|
||||
|
||||
### `zabbix_agent_upgrade.yml`
|
||||
**Updates Zabbix Agent.**
|
||||
- **Target**: `zagents` group.
|
||||
- **Actions**:
|
||||
1. Ensures `zabbix-agent2` is installed and updated to the latest available version.
|
||||
|
||||
### `zabbix_proxy_install.yml`
|
||||
**Installs Zabbix Proxy and Agent.**
|
||||
- **Target**: Specific Zabbix Proxy host.
|
||||
- **Actions**:
|
||||
1. Downloads and installs the Zabbix release package.
|
||||
2. Installs `zabbix-proxy-sqlite3` and `zabbix-agent2`.
|
||||
3. Configures PSK encryption and connection settings using `secrets.yml`.
|
||||
@@ -1,170 +0,0 @@
|
||||
---
|
||||
- name: Create and Configure New LXC Container
|
||||
hosts: localhost
|
||||
gather_facts: no
|
||||
vars_files:
|
||||
- "../secrets.yml"
|
||||
- "../vars.yml"
|
||||
vars_prompt:
|
||||
- name: container_name
|
||||
prompt: "Enter the new container name"
|
||||
private: no
|
||||
- name: container_ip
|
||||
prompt: "Enter the IP address"
|
||||
private: no
|
||||
- name: container_id
|
||||
prompt: "Enter the Container ID (VMID)"
|
||||
private: no
|
||||
- name: container_cores
|
||||
prompt: "Enter CPU Cores"
|
||||
default: "2"
|
||||
private: no
|
||||
- name: container_memory
|
||||
prompt: "Enter Memory in MB"
|
||||
default: "256"
|
||||
private: no
|
||||
|
||||
tasks:
|
||||
- name: Normalize IP address (append /24 if missing)
|
||||
set_fact:
|
||||
container_ip_cidr: "{{ container_ip if '/' in container_ip else container_ip + '/24' }}"
|
||||
|
||||
- name: Create LXC container on Proxmox
|
||||
community.general.proxmox:
|
||||
api_host: "{{ proxmox_host | default('10.0.0.1') }}"
|
||||
api_user: "{{ proxmox_api_user }}"
|
||||
api_token_id: "{{ proxmox_api_token_id }}"
|
||||
api_token_secret: "{{ proxmox_api_token_secret }}"
|
||||
node: "{{ proxmox_node }}"
|
||||
storage: "{{ proxmox_storage }}"
|
||||
ostemplate: '{{ proxmox_storage }}:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst'
|
||||
vmid: "{{ container_id }}"
|
||||
hostname: "{{ container_name }}"
|
||||
password: "{{ lxc_root_password }}"
|
||||
pubkey: "{{ my_public_keys | join('\n') }}"
|
||||
netif:
|
||||
net0: "name=eth0,gw=10.0.0.1,ip={{ container_ip_cidr }},bridge=vmbr0"
|
||||
cores: "{{ container_cores }}"
|
||||
memory: "{{ container_memory }}"
|
||||
swap: 512
|
||||
state: present
|
||||
unprivileged: yes
|
||||
features:
|
||||
- nesting=1
|
||||
register: proxmox_creation
|
||||
|
||||
- name: Start the container
|
||||
community.general.proxmox:
|
||||
api_host: "{{ proxmox_host | default('10.0.0.1') }}"
|
||||
api_user: "{{ proxmox_api_user }}"
|
||||
api_token_id: "{{ proxmox_api_token_id }}"
|
||||
api_token_secret: "{{ proxmox_api_token_secret }}"
|
||||
vmid: "{{ container_id }}"
|
||||
state: started
|
||||
|
||||
- name: Wait for container to be reachable
|
||||
wait_for:
|
||||
host: "{{ container_ip_cidr | split('/') | first }}"
|
||||
port: 22
|
||||
search_regex: OpenSSH
|
||||
delay: 10
|
||||
timeout: 300
|
||||
|
||||
- name: Add new host to in-memory inventory (group 'new')
|
||||
add_host:
|
||||
name: "{{ container_name }}"
|
||||
groups: new
|
||||
ansible_host: "{{ container_ip_cidr | split('/') | first }}"
|
||||
ansible_user: root
|
||||
# Removed ansible_ssh_pass - we rely on the injected key
|
||||
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
|
||||
- name: Secure and Configure New Container
|
||||
hosts: new
|
||||
gather_facts: no
|
||||
vars:
|
||||
# We must explicitly use the password here because the 'new' group in inventory might not have it set
|
||||
# We use the key for the initial root connection, NOT the password
|
||||
# Set ansible_ssh_private_key_file if needed, otherwise it uses the agent
|
||||
ansible_user: root
|
||||
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
vars_files:
|
||||
- "../vars.yml"
|
||||
tasks:
|
||||
# Updated to verify SSH key works, not password
|
||||
- name: Verify we can connect (ping)
|
||||
ping:
|
||||
|
||||
- name: Create user '{{ target_user }}'
|
||||
ansible.builtin.user:
|
||||
name: '{{ target_user }}'
|
||||
shell: /bin/bash
|
||||
groups: sudo
|
||||
state: present
|
||||
|
||||
- name: Allow '{{ target_user }}' to use sudo without a password
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/sudoers.d/90-{{ target_user }}-nopasswd
|
||||
content: '{{ target_user }} ALL=(ALL) NOPASSWD: ALL'
|
||||
mode: '0440'
|
||||
validate: /usr/sbin/visudo -cf %s
|
||||
|
||||
- name: Set up authorized_keys for '{{ target_user }}'
|
||||
ansible.posix.authorized_key:
|
||||
user: '{{ target_user }}'
|
||||
key: "{{ item }}"
|
||||
state: present
|
||||
path: /home/{{ target_user }}/.ssh/authorized_keys
|
||||
loop: "{{ my_public_keys }}"
|
||||
|
||||
- name: Lock password for '{{ target_user }}'
|
||||
ansible.builtin.user:
|
||||
name: '{{ target_user }}'
|
||||
password_lock: yes
|
||||
|
||||
- name: Disallow root login over SSH
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^#?PermitRootLogin'
|
||||
line: 'PermitRootLogin no'
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: restart sshd
|
||||
|
||||
- name: Disallow password authentication
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^#?PasswordAuthentication'
|
||||
line: 'PasswordAuthentication no'
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: restart sshd
|
||||
|
||||
handlers:
|
||||
- name: restart sshd
|
||||
ansible.builtin.service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
|
||||
- name: Persist Host to Inventory
|
||||
hosts: localhost
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Add new host to local hosts.ini file
|
||||
ansible.builtin.blockinfile:
|
||||
path: "{{ playbook_dir }}/../inventory/hosts.ini"
|
||||
block: |
|
||||
{{ hostvars[item]['inventory_hostname'] }} ansible_host={{ hostvars[item]['ansible_host'] }}
|
||||
insertafter: "^\\[lxc\\]"
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR HOST {{ hostvars[item]['inventory_hostname'] }}"
|
||||
loop: "{{ groups['new'] }}"
|
||||
|
||||
- name: Commit and Push Inventory Changes to Git
|
||||
ansible.builtin.shell: |
|
||||
git config --global user.email "ansible@homelab.local"
|
||||
git config --global user.name "Ansible Automation"
|
||||
git add inventory/hosts.ini
|
||||
git commit -m "Ansible: Added host {{ hostvars[item]['inventory_hostname'] }} to inventory"
|
||||
git push
|
||||
args:
|
||||
chdir: "{{ playbook_dir }}/../"
|
||||
loop: "{{ groups['new'] }}"
|
||||
ignore_errors: yes
|
||||
@@ -1,41 +1,43 @@
|
||||
---
|
||||
- name: 1. Secure and Configure a New LXC Container
|
||||
hosts: 'new' # Target hosts in the [new] group
|
||||
remote_user: root # Connect as root, as defined in the inventory for this group
|
||||
gather_facts: no
|
||||
vars:
|
||||
target_user: mbuz
|
||||
my_public_keys:
|
||||
- "{{ lookup('file', '/home/mbuz/.ssh/id_ed25519.pub') }}"
|
||||
- name: Secure and Configure a New LXC Container
|
||||
hosts: 'lxc' # Hosts or group defined in your inventory
|
||||
remote_user: root
|
||||
tasks:
|
||||
- name: Create user '{{ target_user }}'
|
||||
- name: 1. Create user '{{ target_user }}'
|
||||
ansible.builtin.user:
|
||||
name: '{{ target_user }}'
|
||||
shell: /bin/bash
|
||||
groups: sudo
|
||||
groups: sudo # Add to sudo (for Debian/Ubuntu)
|
||||
state: present
|
||||
|
||||
- name: Allow '{{ target_user }}' to use sudo without a password
|
||||
- name: 1.1. Allow '{{ target_user }}' to use sudo without a password
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/sudoers.d/90-{{ target_user }}-nopasswd
|
||||
content: '{{ target_user }} ALL=(ALL) NOPASSWD: ALL'
|
||||
mode: '0440'
|
||||
validate: /usr/sbin/visudo -cf %s
|
||||
|
||||
- name: Set up authorized_keys for '{{ target_user }}'
|
||||
- name: 2. Set up authorized_keys for '{{ target_user }}'
|
||||
ansible.posix.authorized_key:
|
||||
user: '{{ target_user }}'
|
||||
key: "{{ item }}"
|
||||
state: present
|
||||
path: /home/{{ target_user }}/.ssh/authorized_keys
|
||||
loop: "{{ my_public_keys }}"
|
||||
# ansible.posix.authorized_key will create an .ssh directory with the correct permissions.
|
||||
|
||||
- name: Lock password for '{{ target_user }}'
|
||||
- name: 3. Lock password for '{{ target_user }}'
|
||||
ansible.builtin.user:
|
||||
name: '{{ target_user }}'
|
||||
password_lock: yes
|
||||
|
||||
- name: Disallow root login over SSH
|
||||
- name: 4.0. Install software-properties-common
|
||||
ansible.builtin.apt:
|
||||
name: software-properties-common
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: 4.1. Disallow root login over SSH
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^#?PermitRootLogin'
|
||||
@@ -43,7 +45,7 @@
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: restart sshd
|
||||
|
||||
- name: Disallow password authentication
|
||||
- name: 4.2. Disallow password authentication
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^#?PasswordAuthentication'
|
||||
@@ -52,30 +54,10 @@
|
||||
notify: restart sshd
|
||||
|
||||
handlers:
|
||||
- name: Restart sshd server
|
||||
# This block will only run if at least one task sends a notification.
|
||||
# This prevents unnecessary service restarts.
|
||||
- name: 5. Restart sshd server
|
||||
listen: "restart sshd"
|
||||
ansible.builtin.service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
|
||||
# --- Move host from NEW to LXC group ---
|
||||
- name: 2. Graduate Host from [new] to [lxc] in Inventory
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Remove host from the [new] group
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ playbook_dir }}/../inventory/hosts.ini"
|
||||
regexp: "^{{ item }}\\s" # Match the start of the line with the hostname
|
||||
state: absent
|
||||
loop: "{{ groups['new'] }}" # Loop over all hosts in the 'new' group
|
||||
|
||||
- name: Add host to the [lxc] group
|
||||
ansible.builtin.blockinfile:
|
||||
path: /opt/ansible/inventory/hosts.ini
|
||||
block: |
|
||||
{{ item }} ansible_host={{ hostvars[item]['ansible_host'] }}
|
||||
insertafter: "^\\[lxc\\]"
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK FOR LXC"
|
||||
loop: "{{ groups['new'] }}" # Loop over all hosts in the 'new' group
|
||||
Reference in New Issue
Block a user