Fix issues 3,5,6,7,8,9,11,15,16: security hardening and reliability improvements

- ansible.cfg: enable host_key_checking (closes #1)
- update_upgrade.yml: fix reboot crash on non-Debian hosts, exclude AnsibleHost from targets (closes #2, #7)
- deploy.yml: replace silent ignore_errors with real container health assertion (closes #3)
- redeploy.yml: same assertion fix + restic --overwrite always + RESTIC_RESTORE_PATH variable (closes #3, #4, #5)
- disaster.yml: same fixes as redeploy.yml (closes #3, #4, #5)
- docker_update_containers.yml: create missing playbook (closes #6)
- fresh_install.yml: add safety guard to abort if containers already running (closes #8)
- docker_status.yml: add become: true (closes #9)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jeet
2026-03-22 14:14:14 -04:00
parent fa67a195ab
commit d2e8cc6e70
8 changed files with 106 additions and 28 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
[defaults] [defaults]
inventory = ./inventory.yml inventory = ./inventory.yml
host_key_checking = False host_key_checking = True
#vault_password_file = ./.password_file #vault_password_file = ./.password_file
+13 -7
View File
@@ -12,13 +12,13 @@
path: ~/docker/caddy path: ~/docker/caddy
state: directory state: directory
mode: '0755' mode: '0755'
- name: Create ddns folder - name: Create ddns folder
ansible.builtin.file: ansible.builtin.file:
path: ~/docker/ddns path: ~/docker/ddns
state: directory state: directory
mode: '0755' mode: '0755'
- name: Copy encrypted docker-compose - name: Copy encrypted docker-compose
ansible.builtin.copy: ansible.builtin.copy:
src: ./vault/compose/docker-compose.yml src: ./vault/compose/docker-compose.yml
@@ -38,15 +38,21 @@
ansible.builtin.command: ansible.builtin.command:
cmd: docker compose up -d cmd: docker compose up -d
chdir: ~/docker chdir: ~/docker
ignore_errors: yes
- name: Pause for 30 seconds to allow containers to stabilize - name: Pause for 30 seconds to allow containers to stabilize
ansible.builtin.pause: ansible.builtin.pause:
seconds: 30 seconds: 30
- name: Check container status - name: Verify all containers are running
ansible.builtin.shell: docker compose ps -q | xargs -n1 docker container inspect --format '{{ "{{" }} .State.Running {{ "}}" }}' ansible.builtin.shell: |
expected=$(docker compose config --services | wc -l | tr -d ' ')
running=$(docker compose ps --status running -q | wc -l | tr -d ' ')
if [ "$expected" != "$running" ]; then
echo "FAIL: $running/$expected containers running"
docker compose ps
exit 1
fi
echo "OK: all $running containers running"
args: args:
chdir: ~/docker chdir: ~/docker
register: container_status changed_when: false
ignore_errors: yes
+17 -8
View File
@@ -2,35 +2,44 @@
hosts: DR hosts: DR
tasks: tasks:
- include_vars: ./vault/restic/restic.yml - include_vars: ./vault/restic/restic.yml
- name: Create folder - name: Create folder
ansible.builtin.file: ansible.builtin.file:
path: ~/docker path: ~/docker
state: directory state: directory
mode: '0755' mode: '0755'
- name: Pull backups - name: Pull backups
shell: | ansible.builtin.shell: |
unset HISTFILE unset HISTFILE
export RESTIC_REPOSITORY={{ RESTIC_REPOSITORY }} export RESTIC_REPOSITORY={{ RESTIC_REPOSITORY }}
export AWS_ACCESS_KEY_ID={{ AWS_ACCESS_KEY_ID }} export AWS_ACCESS_KEY_ID={{ AWS_ACCESS_KEY_ID }}
export AWS_SECRET_ACCESS_KEY={{ AWS_SECRET_ACCESS_KEY }} export AWS_SECRET_ACCESS_KEY={{ AWS_SECRET_ACCESS_KEY }}
export RESTIC_PASSWORD={{ RESTIC_PASSWORD }} export RESTIC_PASSWORD={{ RESTIC_PASSWORD }}
cd ~/docker cd ~/docker
restic restore latest:/source/gcloud --target ./ # RESTIC_RESTORE_PATH: verify with 'restic snapshots' before running
# Updated from /source/gcloud — set the correct snapshot path in vault/restic/restic.yml
restic restore latest:{{ RESTIC_RESTORE_PATH }} --target ./ --overwrite always
- name: Start container using Docker Compose - name: Start container using Docker Compose
ansible.builtin.command: ansible.builtin.command:
cmd: docker compose up -d cmd: docker compose up -d
chdir: ~/docker chdir: ~/docker
ignore_errors: true
- name: Pause for 30 seconds to allow containers to stabilize - name: Pause for 30 seconds to allow containers to stabilize
ansible.builtin.pause: ansible.builtin.pause:
seconds: 30 seconds: 30
- name: Check container status - name: Verify all containers are running
ansible.builtin.shell: docker compose ps -q | xargs -n1 docker container inspect --format '{{ "{{" }} .State.Running {{ "}}" }}' ansible.builtin.shell: |
expected=$(docker compose config --services | wc -l | tr -d ' ')
running=$(docker compose ps --status running -q | wc -l | tr -d ' ')
if [ "$expected" != "$running" ]; then
echo "FAIL: $running/$expected containers running"
docker compose ps
exit 1
fi
echo "OK: all $running containers running"
args: args:
chdir: ~/docker chdir: ~/docker
register: container_status changed_when: false
ignore_errors: true
+1
View File
@@ -2,6 +2,7 @@
- name: Check and Report Status of Docker Containers - name: Check and Report Status of Docker Containers
hosts: Docker hosts: Docker
gather_facts: true gather_facts: true
become: true
vars: vars:
exited_containers: [] exited_containers: []
+37
View File
@@ -0,0 +1,37 @@
---
- name: Pull latest images and recreate updated containers
hosts: Docker
tasks:
- name: Pull latest images
ansible.builtin.command:
cmd: docker compose pull
chdir: ~/docker
register: pull_result
changed_when: "'Downloaded newer image' in pull_result.stdout or 'Pulled' in pull_result.stdout"
- name: Recreate containers with updated images
ansible.builtin.command:
cmd: docker compose up -d --remove-orphans
chdir: ~/docker
- name: Pause for 30 seconds to allow containers to stabilize
ansible.builtin.pause:
seconds: 30
- name: Verify all containers are running
ansible.builtin.shell: |
expected=$(docker compose config --services | wc -l | tr -d ' ')
running=$(docker compose ps --status running -q | wc -l | tr -d ' ')
if [ "$expected" != "$running" ]; then
echo "FAIL: $running/$expected containers running"
docker compose ps
exit 1
fi
echo "OK: all $running containers running"
args:
chdir: ~/docker
changed_when: false
- name: Remove dangling images
ansible.builtin.command:
cmd: docker image prune -f
+17 -1
View File
@@ -5,6 +5,22 @@
gather_facts: true gather_facts: true
tasks: tasks:
- name: Check if Docker containers are already running (safety guard)
ansible.builtin.shell: docker compose ps -q 2>/dev/null || true
args:
chdir: ~/docker
register: running_containers
changed_when: false
failed_when: false
- name: Abort if containers are already running on this host
ansible.builtin.fail:
msg: >
Docker containers are already running on {{ inventory_hostname }}.
Use redeploy.yml to restore from backup or deploy.yml to redeploy config.
Only run fresh_install.yml on hosts with no active containers.
when: running_containers.stdout != ""
- name: Update apt cache (Debian/Ubuntu) - name: Update apt cache (Debian/Ubuntu)
apt: apt:
update_cache: yes update_cache: yes
@@ -61,7 +77,7 @@
name: '*' name: '*'
state: latest state: latest
when: ansible_os_family == 'RedHat' when: ansible_os_family == 'RedHat'
- name: Update Restic Binaries - name: Update Restic Binaries
ansible.builtin.command: ansible.builtin.command:
cmd: restic self-update cmd: restic self-update
+17 -8
View File
@@ -2,35 +2,44 @@
hosts: Prod hosts: Prod
tasks: tasks:
- include_vars: ./vault/restic/restic.yml - include_vars: ./vault/restic/restic.yml
- name: Create folder - name: Create folder
ansible.builtin.file: ansible.builtin.file:
path: ~/docker path: ~/docker
state: directory state: directory
mode: '0755' mode: '0755'
- name: Pull backups - name: Pull backups
shell: | ansible.builtin.shell: |
unset HISTFILE unset HISTFILE
export RESTIC_REPOSITORY={{ RESTIC_REPOSITORY }} export RESTIC_REPOSITORY={{ RESTIC_REPOSITORY }}
export AWS_ACCESS_KEY_ID={{ AWS_ACCESS_KEY_ID }} export AWS_ACCESS_KEY_ID={{ AWS_ACCESS_KEY_ID }}
export AWS_SECRET_ACCESS_KEY={{ AWS_SECRET_ACCESS_KEY }} export AWS_SECRET_ACCESS_KEY={{ AWS_SECRET_ACCESS_KEY }}
export RESTIC_PASSWORD={{ RESTIC_PASSWORD }} export RESTIC_PASSWORD={{ RESTIC_PASSWORD }}
cd ~/docker cd ~/docker
restic restore latest:/source/gcloud --target ./ # RESTIC_RESTORE_PATH: verify with 'restic snapshots' before running
# Updated from /source/gcloud — set the correct snapshot path in vault/restic/restic.yml
restic restore latest:{{ RESTIC_RESTORE_PATH }} --target ./ --overwrite always
- name: Start container using Docker Compose - name: Start container using Docker Compose
ansible.builtin.command: ansible.builtin.command:
cmd: docker compose up -d cmd: docker compose up -d
chdir: ~/docker chdir: ~/docker
ignore_errors: true
- name: Pause for 30 seconds to allow containers to stabilize - name: Pause for 30 seconds to allow containers to stabilize
ansible.builtin.pause: ansible.builtin.pause:
seconds: 30 seconds: 30
- name: Check container status - name: Verify all containers are running
ansible.builtin.shell: docker compose ps -q | xargs -n1 docker container inspect --format '{{ "{{" }} .State.Running {{ "}}" }}' ansible.builtin.shell: |
expected=$(docker compose config --services | wc -l | tr -d ' ')
running=$(docker compose ps --status running -q | wc -l | tr -d ' ')
if [ "$expected" != "$running" ]; then
echo "FAIL: $running/$expected containers running"
docker compose ps
exit 1
fi
echo "OK: all $running containers running"
args: args:
chdir: ~/docker chdir: ~/docker
register: container_status changed_when: false
ignore_errors: true
+3 -3
View File
@@ -1,5 +1,5 @@
--- ---
- hosts: all - hosts: "all:!AnsibleHost"
gather_facts: true gather_facts: true
tasks: tasks:
@@ -19,7 +19,7 @@
- name: Reboot the server (if required). - name: Reboot the server (if required).
ansible.builtin.reboot: ansible.builtin.reboot:
when: reboot_required_file.stat.exists == true when: reboot_required_file is defined and reboot_required_file.stat.exists
- name: "Updating and Upgrading Yum Packages" - name: "Updating and Upgrading Yum Packages"
yum: yum:
@@ -42,7 +42,7 @@
category_names: '*' category_names: '*'
reboot: true reboot: true
when: ansible_os_family == "Windows" when: ansible_os_family == "Windows"
- name: Upgrade installed packages - name: Upgrade installed packages
win_chocolatey: win_chocolatey:
name: all name: all