Compare commits

...

2 Commits

Author SHA1 Message Date
74b8676244 auto upgrade webapp image 2025-12-23 14:20:56 +01:00
1fd47e9d97 install pihole to fix failing duckdns name servers 2025-12-23 14:20:04 +01:00
12 changed files with 532 additions and 3 deletions

View File

@@ -42,6 +42,11 @@ gitea:
children:
postgres:
pihole:
hosts:
pi1:
pi3:
all:
children:
raspberries:

View File

@@ -0,0 +1,3 @@
---
- name: dns
ansible.builtin.import_playbook: ./dns/dns.yml

View File

@@ -0,0 +1,2 @@
- name: pihole
ansible.builtin.import_playbook: pihole.yml

View File

@@ -0,0 +1,213 @@
---
- name: Installer et configurer Pi-hole sur pi1
hosts: raspberries:&local #pihole # change with pihole group
become: yes
vars:
pihole_custom_dns:
".arcodange.duckdns.org": "{{ hostvars['pi1'].preferred_ip }}"
roles:
- pihole
# tasks:
# - name: Proposer la commande d'installation manuelle de Pi-hole
# debug:
# msg: |
# Veuillez installer Pi-hole manuellement sur ce host avec la commande suivante :
# # curl -sSL https://install.pi-hole.net | sudo bash
# L'installation sera vérifiée automatiquement dans les 10 prochaines minutes.
# - name: Attendre que Pi-hole soit installé (vérification service et fichier config)
# wait_for:
# path: /etc/pihole/pihole-FTL.db
# state: present
# timeout: 600 # 10 minutes
# register: pihole_config_ready
# - name: Vérifier que le service pihole-FTL est actif
# wait_for:
# port: 53 # port interne par défaut Pi-hole
# state: started
# timeout: 60
# when: pihole_config_ready is succeeded
# - name: Modifier le fichier /etc/pihole/pihole.toml pour changer le port
# replace:
# path: /etc/pihole/pihole.toml
# regexp: '^\s*port\s*=\s*".*"'
# replace: ' port = "{{ pihole_ports }}"'
# - name: Modifier le fichier /etc/pihole/pihole.toml pour autoriser toutes les origines DNS
# replace:
# path: /etc/pihole/pihole.toml
# regexp: '^\s*listeningMode\s*=\s*".*"'
# replace: ' listeningMode = "ALL"'
# - name: Activer le chargement des fichiers /etc/dnsmasq.d/ dans Pi-hole
# lineinfile:
# path: /etc/pihole/pihole.toml
# regexp: '^\s*etc_dnsmasq_d\s*='
# line: ' etc_dnsmasq_d = true'
# state: present
# create: yes
# - name: Créer le fichier dnsmasq pour le wildcard
# copy:
# dest: /etc/dnsmasq.d/10-arcodange-wildcard.conf
# content: |
# address=/{{ pihole_wildcard_rule }}/{{ pihole_dns_ip }}
# owner: root
# group: root
# mode: '0644'
# - name: Créer les entrées DNS locales pour les RPis (pi*.home)
# copy:
# dest: /etc/dnsmasq.d/20-rpis.conf
# owner: root
# group: root
# mode: '0644'
# content: |
# # Generated by Ansible Raspberry Pi local DNS
# {% for host in groups['raspberries']
# if host is match('^pi[0-9]+$')
# and hostvars[host].preferred_ip is defined %}
# address=/{{ host }}.home/{{ hostvars[host].preferred_ip }}
# {% endfor %}
# - name: Configurer resolv.conf pour DNS croisé
# copy:
# dest: /etc/resolv.conf
# owner: root
# group: root
# mode: '0644'
# content: |
# {% if inventory_hostname == 'pi1' %}
# nameserver {{ hostvars['pi3'].preferred_ip }}
# {% elif inventory_hostname == 'pi3' %}
# nameserver {{ hostvars['pi1'].preferred_ip }}
# {% endif %}
# - name: Redémarrer le service Pi-hole FTL
# service:
# name: pihole-FTL
# state: restarted
# ############################################################
# # 2. Configuration DNS des Raspberry Pi clients
# ############################################################
# - name: Configurer Docker via systemd override (DNS Pi-hole)
# hosts: raspberries:&local
# become: yes
# vars:
# docker_dns_servers:
# - "{{ hostvars['pi1']['preferred_ip'] }}"
# - "8.8.8.8"
# - "1.1.1.1"
# docker_override_dir: /etc/systemd/system/docker.service.d
# docker_override_file: /etc/systemd/system/docker.service.d/override.conf
# tasks:
# - name: Créer le dossier systemd override pour Docker
# file:
# path: "{{ docker_override_dir }}"
# state: directory
# owner: root
# group: root
# mode: '0755'
# tags: docker, override
# - name: Déployer l'override systemd pour dockerd (DNS + IPv4 only)
# copy:
# dest: "{{ docker_override_file }}"
# owner: root
# group: root
# mode: '0644'
# content: |
# [Service]
# ExecStart=
# ExecStart=/usr/bin/dockerd \
# -H fd:// \
# --containerd=/run/containerd/containerd.sock \
# {% for dns in docker_dns_servers %}
# --dns={{ dns }} \
# {% endfor %}
# --ipv6=false
# notify:
# - Reexec systemd
# - Restart Docker
# - Restart k3s
# tags: docker, override
# # -------- ROLLBACK --------
# - name: Rollback - Supprimer l'override systemd Docker
# file:
# path: "{{ docker_override_file }}"
# state: absent
# notify:
# - Reexec systemd
# - Restart Docker
# - Restart k3s
# when: "'rollbacks' in ansible_run_tags"
# handlers:
# - name: Reexec systemd
# command: systemctl daemon-reexec
# - name: Restart Docker
# service:
# name: docker
# state: restarted
# - name: Restart k3s
# service:
# name: k3s
# state: restarted
# ignore_errors: yes
# - name: Restart k3s-agent
# service:
# name: k3s-agent
# state: restarted
# ignore_errors: yes
## 3 configurer traefik
# apiVersion: v1
# kind: Service
# metadata:
# name: pihole-external
# namespace: kube-system
# spec:
# type: ExternalName
# externalName: {{ hostvars[groups.pihole[0]]['preferred_ip'] }}
# ports:
# - port: 3000
# targetPort: 3000
# ---
# apiVersion: traefik.io/v1alpha1
# kind: IngressRoute
# metadata:
# name: pihole
# namespace: kube-system
# spec:
# entryPoints:
# - web
# routes:
# - match: Host(`gitea.arcodange.fr`)
# kind: Rule
# middlewares:
# - name: crowdsec
# namespace: kube-system
# services:
# - kind: Service
# name: gitea-external
# namespace: kube-system
# port: 3000

View File

@@ -0,0 +1,7 @@
pihole_primary: pi1
pihole_user_gravity: pihole_gravity
pihole_gravity_home: /var/lib/pihole_gravity
pihole_dns_domain: lab
pihole_ports: '8081o,443os,[::]:8081o,[::]:443os' # web interface
pihole_gravity_conf: /etc/gravity-sync/gravity-sync.conf # should not be changed
pihole_custom_dns: {}

View File

@@ -0,0 +1,5 @@
---
- name: Restart Pi-hole
service:
name: pihole-FTL
state: restarted

View File

@@ -0,0 +1,27 @@
---
- name: Build DNS server list (exclude self)
set_fact:
pihole_dns_servers: >-
{{
groups['pihole']
| reject('equalto', inventory_hostname)
| map('extract', hostvars, 'preferred_ip')
| list
}}
# 1⃣ Supprimer déventuelles anciennes entrées Pi-hole
- name: Remove existing Pi-hole nameservers
lineinfile:
path: /etc/resolv.conf
regexp: '^nameserver ({{ pihole_dns_servers | join("|") }})$'
state: absent
when: pihole_dns_servers | length > 0
# 2⃣ Insérer les Pi-hole juste après la ligne search
- name: Insert Pi-hole nameservers with priority
lineinfile:
path: /etc/resolv.conf
insertafter: '^search'
line: "nameserver {{ item }}"
state: present
loop: "{{ pihole_dns_servers }}"

View File

@@ -0,0 +1,153 @@
---
# -------------------------------------------------------------------
# Gravity Sync HA setup final version with SSH key rotation
# -------------------------------------------------------------------
- name: Determine primary Pi-hole
set_fact:
pihole_primary: "{{ groups['pihole'] | first }}"
- name: Set secondary Pi-hole hosts
set_fact:
pihole_secondaries: "{{ groups['pihole'] | difference([pihole_primary]) }}"
#################################################################
# 1⃣ Ensure gravity user exists on all Pi-hole nodes
#################################################################
- name: Ensure gravity user exists
user:
name: "{{ pihole_user_gravity }}"
home: "{{ pihole_gravity_home }}"
shell: /bin/bash
system: yes
create_home: yes
- name: Create .ssh directory for gravity user
file:
path: "{{ pihole_gravity_home }}/.ssh"
state: directory
owner: "{{ pihole_user_gravity }}"
group: "{{ pihole_user_gravity }}"
mode: '0700'
#################################################################
# 2⃣ Generate SSH key for each host (rotation at each run)
#################################################################
- name: Generate SSH keypair for gravity user
openssh_keypair:
path: "{{ pihole_gravity_home }}/.ssh/id_ed25519"
type: ed25519
owner: "{{ pihole_user_gravity }}"
group: "{{ pihole_user_gravity }}"
mode: '0600'
register: gravity_key
no_log: true
- name: Set gravity key in hostvars
set_fact:
gravity_pubkey: "{{ gravity_key.public_key }}"
- name: Clean authorized_keys for gravity user
file:
path: "{{ pihole_gravity_home }}/.ssh/authorized_keys"
state: absent
- name: Authorize SSH keys from other Pi-hole hosts
authorized_key:
user: "{{ pihole_user_gravity }}"
key: "{{ hostvars[item].gravity_pubkey }}"
state: present
loop: "{{ groups['pihole'] }}"
when: inventory_hostname != item
- name: Add all Pi-hole hosts to known_hosts
known_hosts:
path: "{{ pihole_gravity_home }}/.ssh/known_hosts"
name: "{{ item }}"
key: "{{ lookup('pipe', 'ssh-keyscan -t ed25519 ' ~ item) }}"
state: present
loop: "{{ groups['pihole'] }}"
when: inventory_hostname != item
become: yes
become_user: "{{ pihole_user_gravity }}"
#################################################################
# Install Gravity Sync binary if absent
#################################################################
- name: Check if Gravity Sync binary exists
stat:
path: /usr/local/bin/gravity-sync
register: gravity_sync_bin
- name: Download installer
get_url:
url: https://raw.githubusercontent.com/vmstan/gs-install/main/gs-install.sh
dest: /tmp/gs-install.sh
mode: '0755'
when: not gravity_sync_bin.stat.exists
- name: Give full sudo to gravity user
copy:
dest: /etc/sudoers.d/gravity-sync
mode: '0440'
content: "{{ pihole_user_gravity }} ALL=(ALL) NOPASSWD: ALL"
when: not gravity_sync_bin.stat.exists
- name: Execute Gravity Sync installer non-interactively
command: bash /tmp/gs-install.sh
become: yes
become_user: "{{ pihole_user_gravity }}"
environment:
HOME: "{{ pihole_gravity_home }}"
when: not gravity_sync_bin.stat.exists
#################################################################
# Generate gravity-sync.conf for non-interactive use
#################################################################
- name: Set remote host for gravity-sync.conf
set_fact:
remote_pihole: "{{ (inventory_hostname == pihole_primary) | ternary(pihole_secondaries[0] ~ '.home', pihole_primary ~ '.home') }}"
- name: Create gravity-sync.conf file
copy:
dest: "{{ pihole_gravity_conf }}"
owner: "{{ pihole_user_gravity }}"
group: "{{ pihole_user_gravity }}"
mode: '0600'
content: |
# REQUIRED SETTINGS
REMOTE_HOST='{{ remote_pihole }}'
REMOTE_USER='{{ pihole_user_gravity }}'
# CUSTOM VARIABLES
# LOCAL_PIHOLE_DIRECTORY='/etc/pihole'
# REMOTE_PIHOLE_DIRECTORY='/etc/pihole'
# LOCAL_FILE_OWNER='{{ pihole_user_gravity }}'
# REMOTE_FILE_OWNER='{{ pihole_user_gravity }}'
# LOCAL_DOCKER_CONTAINER='' # optional
# REMOTE_DOCKER_CONTAINER='' # optional
- name: Create symlink for gravity-sync.rsa
file:
src: "{{ pihole_gravity_home }}/.ssh/id_ed25519"
dest: /etc/gravity-sync/gravity-sync.rsa
owner: "{{ pihole_user_gravity }}"
group: "{{ pihole_user_gravity }}"
mode: '0600'
state: link
#################################################################
# Execute Gravity Sync with non-interactive config
#################################################################
- name: Run Gravity Sync script
command: bash /usr/local/bin/gravity-sync
become: yes
become_user: "{{ pihole_user_gravity }}"
environment:
HOME: "{{ pihole_gravity_home }}"

View File

@@ -0,0 +1,100 @@
#################################################################
# Bootstrap Pi-hole (installation manuelle attendue)
#################################################################
- name: Proposer la commande d'installation manuelle de Pi-hole
debug:
msg: |
Veuillez installer Pi-hole manuellement sur ce host avec la commande suivante :
------------------------------------------------------------
curl -sSL https://install.pi-hole.net | sudo bash
------------------------------------------------------------
L'installation sera vérifiée automatiquement dans les 10 prochaines minutes.
#################################################################
# Vérification installation Pi-hole
#################################################################
- name: Attendre que Pi-hole soit installé (FTL DB)
wait_for:
path: /etc/pihole/pihole-FTL.db
state: present
timeout: 600 # 10 minutes
register: pihole_config_ready
- name: Vérifier que le service pihole-FTL est actif
wait_for:
port: 53
state: started
timeout: 60
when: pihole_config_ready is succeeded
#################################################################
# Configuration Pi-hole (commune HA)
#################################################################
- name: Modifier le port d'écoute Pi-hole
replace:
path: /etc/pihole/pihole.toml
regexp: '^\s*port\s*=\s*".*"'
replace: ' port = "{{ pihole_ports }}"'
notify: Restart Pi-hole
- name: Autoriser Pi-hole à écouter sur toutes les interfaces
replace:
path: /etc/pihole/pihole.toml
regexp: '^\s*listeningMode\s*=\s*".*"'
replace: ' listeningMode = "ALL"'
notify: Restart Pi-hole
- name: Activer le chargement de /etc/dnsmasq.d
lineinfile:
path: /etc/pihole/pihole.toml
regexp: '^\s*etc_dnsmasq_d\s*='
line: ' etc_dnsmasq_d = true'
state: present
notify: Restart Pi-hole
#################################################################
# DNS custom (wildcard + locaux)
#################################################################
- name: Validate custom DNS IPs
assert:
that:
- ip is match('^([0-9]{1,3}\.){3}[0-9]{1,3}$')
fail_msg: "Invalid IP for {{ fqdn }}"
loop: "{{ pihole_custom_dns | dict2items }}"
loop_control:
label: "{{ item.key }}"
vars:
fqdn: "{{ item.key }}"
ip: "{{ item.value }}"
- name: Générer les règles DNS custom (wildcards + FQDN)
copy:
dest: /etc/dnsmasq.d/10-custom-rules.conf
owner: root
group: root
mode: '0644'
content: |
# Generated by Ansible Pi-hole custom DNS rules
{% for fqdn, ip in pihole_custom_dns.items() %}
address=/{{ fqdn }}/{{ ip }}
{% endfor %}
when: pihole_custom_dns | length > 0
notify: Restart Pi-hole
- name: Créer les entrées DNS locales pour les RPis
copy:
dest: /etc/dnsmasq.d/20-rpis.conf
owner: root
group: root
mode: '0644'
content: |
# Generated by Ansible Raspberry Pi local DNS
{% for host in groups['raspberries']
if hostvars[host].preferred_ip is defined %}
address=/{{ host }}.home/{{ hostvars[host].preferred_ip }}
{% endfor %}
notify: Restart Pi-hole

View File

@@ -0,0 +1,11 @@
---
- name: Setup Pi-hole HA
include_tasks: ha_pihole_setup.yml
when: "'pihole' in group_names"
- name: Setup Gravity Sync
include_tasks: gravity_setup.yml
when: "'pihole' in group_names"
- name: Setup DNS client
include_tasks: client_setup.yml

View File

@@ -3,8 +3,9 @@ roles:
- name: geerlingguy.docker
collections:
- name: community.general
- name: community.docker
- name: ansible.posix
- name: community.crypto
- name: community.docker
- name: community.general
- name: kubernetes.core
- name: git+https://github.com/k3s-io/k3s-ansible.git

View File

@@ -7,7 +7,9 @@ gitea_applications:
tools:
annotations: {}
webapp:
annotations: {}
annotations:
argocd-image-updater.argoproj.io/image-list: webapp=gitea.arcodange.duckdns.org/arcodange-org/webapp:latest
argocd-image-updater.argoproj.io/webapp.update-strategy: digest
erp:
annotations: {}
cms: