chore: lots of changes
This commit is contained in:
134
ansible/roles/app/tasks/main.yml
Normal file
134
ansible/roles/app/tasks/main.yml
Normal file
@@ -0,0 +1,134 @@
|
||||
- name: Zielverzeichnis erstellen
|
||||
file:
|
||||
path: "{{ deploy_root }}"
|
||||
state: directory
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: SSL-Verzeichnis sicherstellen
|
||||
file:
|
||||
path: "{{ deploy_root }}/ssl"
|
||||
state: directory
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: SSL-Zertifikate prüfen
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ app_domain }}/fullchain.pem"
|
||||
register: ssl_certs
|
||||
|
||||
- name: SSL-Zertifikate kopieren (falls vorhanden)
|
||||
copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
remote_src: yes
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: "/etc/letsencrypt/live/{{ app_domain }}/fullchain.pem", dest: "{{ deploy_root }}/ssl/fullchain.pem" }
|
||||
- { src: "/etc/letsencrypt/live/{{ app_domain }}/privkey.pem", dest: "{{ deploy_root }}/ssl/privkey.pem" }
|
||||
when: ssl_certs.stat.exists
|
||||
|
||||
- name: public-Verzeichnis synchronisieren
|
||||
synchronize:
|
||||
src: "{{ playbook_dir }}/../../public/"
|
||||
dest: "{{ deploy_public }}/"
|
||||
delete: yes
|
||||
recursive: yes
|
||||
|
||||
- name: Projekt-Stammdaten kopieren
|
||||
copy:
|
||||
src: "{{ playbook_dir }}/../../docker-compose.yml"
|
||||
dest: "{{ deploy_root }}/docker-compose.yml"
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: .env-Datei prüfen
|
||||
stat:
|
||||
path: "{{ project_root }}/.env"
|
||||
register: env_file
|
||||
|
||||
- name: .env kopieren (falls vorhanden)
|
||||
copy:
|
||||
src: "{{ project_root }}/.env"
|
||||
dest: "{{ deploy_root }}/.env"
|
||||
mode: '0644'
|
||||
when: env_file.stat.exists
|
||||
|
||||
- name: Quellcode synchronisieren
|
||||
synchronize:
|
||||
src: "{{ playbook_dir }}/../../src/"
|
||||
dest: "{{ deploy_root }}/src/"
|
||||
delete: yes
|
||||
recursive: yes
|
||||
|
||||
- name: Docker-Verzeichnis prüfen
|
||||
stat:
|
||||
path: "{{ project_root }}/docker"
|
||||
register: docker_dir
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
|
||||
- name: Docker-Configs synchronisieren (falls vorhanden)
|
||||
synchronize:
|
||||
src: "{{ project_root }}/docker/"
|
||||
dest: "{{ deploy_root }}/docker/"
|
||||
delete: yes
|
||||
recursive: yes
|
||||
when: docker_dir.stat.exists
|
||||
|
||||
- name: Rechte im Zielverzeichnis korrigieren
|
||||
file:
|
||||
path: "{{ deploy_root }}"
|
||||
state: directory
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0755'
|
||||
recurse: yes
|
||||
|
||||
# Cache-Verzeichnis für UID/GID 1000 (z.B. appuser im Container)
|
||||
- name: Stelle Schreibrechte für Cache-Verzeichnis her
|
||||
file:
|
||||
path: "{{ deploy_root }}/cache"
|
||||
state: directory
|
||||
owner: 1000
|
||||
group: 1000
|
||||
mode: '0775'
|
||||
recurse: yes
|
||||
|
||||
- name: Docker Compose neu bauen und starten
|
||||
shell: |
|
||||
docker compose down
|
||||
docker compose up -d --build
|
||||
args:
|
||||
chdir: "{{ deploy_root }}"
|
||||
|
||||
- name: PHP-Container für Composer starten
|
||||
shell: docker compose up -d php
|
||||
args:
|
||||
chdir: "{{ deploy_root }}"
|
||||
|
||||
- name: Kurze Wartezeit bis PHP-Container bereit
|
||||
wait_for:
|
||||
timeout: 5
|
||||
|
||||
- name: Composer Abhängigkeiten installieren
|
||||
shell: docker compose exec -T php composer install --no-interaction
|
||||
args:
|
||||
chdir: "{{ deploy_root }}"
|
||||
register: composer_result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Composer-Ergebnis anzeigen
|
||||
debug:
|
||||
var: composer_result.stdout_lines
|
||||
when: composer_result.stdout is defined
|
||||
|
||||
- name: Composer-Fehler anzeigen
|
||||
debug:
|
||||
var: composer_result.stderr_lines
|
||||
when: composer_result.stderr is defined
|
||||
26
ansible/roles/common/tasks/main.yml
Normal file
26
ansible/roles/common/tasks/main.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
# Grundlegende Systemkonfiguration
|
||||
- name: Basis-Pakete aktualisieren und installieren
|
||||
apt:
|
||||
name:
|
||||
- sudo
|
||||
- vim
|
||||
- htop
|
||||
- git
|
||||
- zip
|
||||
- unzip
|
||||
- curl
|
||||
- wget
|
||||
state: present
|
||||
update_cache: yes
|
||||
become: true
|
||||
|
||||
# Passwordless sudo für den deploy-Benutzer einrichten
|
||||
- name: Konfiguriere passwordless sudo für deploy-Benutzer
|
||||
lineinfile:
|
||||
path: "/etc/sudoers.d/{{ deploy_user }}"
|
||||
line: "{{ deploy_user }} ALL=(ALL) NOPASSWD: ALL"
|
||||
state: present
|
||||
create: yes
|
||||
mode: '0440'
|
||||
validate: 'visudo -cf %s'
|
||||
become: true
|
||||
9
ansible/roles/console/tasks/main.yml
Normal file
9
ansible/roles/console/tasks/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
- name: Füge Funktion für ms (mit Argumenten) hinzu
|
||||
blockinfile:
|
||||
path: "/home/{{ ansible_user }}/.bashrc"
|
||||
marker: "# {mark} ms docker alias"
|
||||
block: |
|
||||
ms() {
|
||||
docker compose exec php php ms "$@"
|
||||
}
|
||||
become: false
|
||||
9
ansible/roles/docker/README.md
Normal file
9
ansible/roles/docker/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Rolle: Docker
|
||||
|
||||
Diese Rolle installiert Docker Engine, CLI, Compose-Plugin sowie (optional) Docker Compose V1 als Fallback.
|
||||
- Fügt den gewünschten User zur Docker-Gruppe hinzu.
|
||||
- Startet und aktiviert den Docker-Dienst.
|
||||
|
||||
## Variablen
|
||||
- `docker_compose_version`: Version von Docker Compose V1 für Fallback (Standard: 1.29.2).
|
||||
- `docker_user`: Benutzer, der in die Gruppe `docker` aufgenommen werden soll (Standard: aktueller Ansible-User).
|
||||
3
ansible/roles/docker/defaults/main.yml
Normal file
3
ansible/roles/docker/defaults/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
docker_compose_version: "v2.29.2"
|
||||
docker_install_compose: true
|
||||
docker_user: "{{ ansible_user || default('michael' }}"
|
||||
4
ansible/roles/docker/handlers/main.yml
Normal file
4
ansible/roles/docker/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: restart docker
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
state: restarted
|
||||
58
ansible/roles/docker/tasks/main.yml
Normal file
58
ansible/roles/docker/tasks/main.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
- name: Docker-Abhängigkeiten installieren
|
||||
apt:
|
||||
name:
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- curl
|
||||
- gnupg
|
||||
- lsb-release
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Docker GPG-Schlüssel hinzufügen
|
||||
apt_key:
|
||||
url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
|
||||
state: present
|
||||
|
||||
- name: Docker Repository hinzufügen
|
||||
apt_repository:
|
||||
repo: "deb [arch=amd64] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
|
||||
state: present
|
||||
|
||||
- name: Docker Engine installieren
|
||||
apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-compose-plugin
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Docker Compose installieren (V1 als Fallback)
|
||||
get_url:
|
||||
url: "https://github.com/docker/compose/releases/download/v{{ docker_compose_version }}/docker-compose-linux-x86_64"
|
||||
dest: /usr/local/bin/docker-compose
|
||||
mode: '0755'
|
||||
|
||||
- name: Benutzer zur Docker-Gruppe hinzufügen
|
||||
user:
|
||||
name: "{{ ansible_user }}"
|
||||
groups: docker
|
||||
append: yes
|
||||
|
||||
- name: Docker-Service starten und aktivieren
|
||||
service:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: yes
|
||||
notify: restart docker
|
||||
|
||||
|
||||
- name: Starte Docker-Container via Compose
|
||||
community.docker.docker_compose_v2:
|
||||
#project_src: "{{ playbook_dir | dirname }}/../" # ggf. anpassen auf deinen Compose-Pfad!
|
||||
project_src: "{{ app_root }}"
|
||||
build: always
|
||||
recreate: always
|
||||
|
||||
5
ansible/roles/nginx/defaults/main.yml
Normal file
5
ansible/roles/nginx/defaults/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
nginx_conf_template: nginx.conf.j2
|
||||
nginx_default_site_template: default.conf.j2
|
||||
nginx_ssl_src_dir: "{{ app_root }}/ssl"
|
||||
nginx_ssl_dest_dir: "/var/www/michaelschiemer/ssl"
|
||||
nginx_target_dir: "/var/www/michaelschiemer/docker/nginx"
|
||||
0
ansible/roles/nginx/files/docker-entrypoint.sh
Normal file
0
ansible/roles/nginx/files/docker-entrypoint.sh
Normal file
2
ansible/roles/nginx/handlers/main.yml
Normal file
2
ansible/roles/nginx/handlers/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
- name: reload nginx
|
||||
ansible.builtin.command: docker exec <nginx_container_name> nginx -s reload
|
||||
37
ansible/roles/nginx/tasks/main.yml
Normal file
37
ansible/roles/nginx/tasks/main.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
- name: Stelle das nginx-Verzeichnis sicher
|
||||
ansible.builtin.file:
|
||||
path: "{{ nginx_target_dir }}"
|
||||
state: directory
|
||||
recurse: yes
|
||||
mode: '0755'
|
||||
|
||||
- name: Kopiere nginx-Konfiguration (nginx.conf)
|
||||
ansible.builtin.template:
|
||||
src: "{{ nginx_conf_template }}"
|
||||
dest: "{{ nginx_target_dir }}/nginx.conf"
|
||||
mode: '0644'
|
||||
|
||||
- name: Kopiere default site conf
|
||||
ansible.builtin.template:
|
||||
src: "{{ nginx_default_site_template }}"
|
||||
dest: "{{ nginx_target_dir }}/default.conf"
|
||||
mode: '0644'
|
||||
|
||||
- name: Kopiere docker-entrypoint Skript
|
||||
ansible.builtin.copy:
|
||||
src: docker-entrypoint.sh
|
||||
dest: "{{ nginx_target_dir }}/docker-entrypoint.sh"
|
||||
mode: '0755'
|
||||
|
||||
- name: Baue und starte Nginx-Container (optional, wenn Compose separat genutzt wird, dann hier nicht nötig)
|
||||
ansible.builtin.command: docker-compose up -d --build web
|
||||
args:
|
||||
chdir: "{{ docker_compose_project_path }}"
|
||||
when: nginx_target_dir is defined
|
||||
register: nginx_compose_result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Zeige Compose-Resultat
|
||||
ansible.builtin.debug:
|
||||
var: nginx_compose_result.stdout_lines
|
||||
when: nginx_compose_result is defined
|
||||
0
ansible/roles/nginx/templates/default.conf.j2
Normal file
0
ansible/roles/nginx/templates/default.conf.j2
Normal file
0
ansible/roles/nginx/templates/nginx.conf.j2
Normal file
0
ansible/roles/nginx/templates/nginx.conf.j2
Normal file
4
ansible/roles/setup/handlers/main.yml
Normal file
4
ansible/roles/setup/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: Reload nginx
|
||||
service:
|
||||
name: nginx
|
||||
state: reloaded
|
||||
@@ -1,3 +1,47 @@
|
||||
- name: Test-Task Setup-Rolle lokal
|
||||
debug:
|
||||
msg: "Setup-Rolle ist vorbereitet – echte Installation folgt auf Server."
|
||||
- name: Docker installieren
|
||||
apt:
|
||||
name:
|
||||
- docker.io
|
||||
- docker-compose
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Certbot + Plugin installieren
|
||||
apt:
|
||||
name:
|
||||
- certbot
|
||||
- python3-certbot-nginx
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Challenge-Verzeichnis für Let's Encrypt anlegen
|
||||
file:
|
||||
path: /var/www/html/.well-known/acme-challenge
|
||||
state: directory
|
||||
owner: www-data
|
||||
group: www-data
|
||||
mode: '0755'
|
||||
recurse: yes
|
||||
|
||||
- name: Füge Let's Encrypt Challenge-Pfad in den Nginx-Vhost ein
|
||||
blockinfile:
|
||||
path: /etc/nginx/sites-available/default
|
||||
marker: "# {mark} ANSIBLE LETSENCRYPT"
|
||||
insertafter: "^\\s*server\\s*{"
|
||||
block: |
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
allow all;
|
||||
default_type "text/plain";
|
||||
}
|
||||
notify: Reload nginx
|
||||
|
||||
|
||||
|
||||
- name: Let's Encrypt Zertifikat anfordern
|
||||
command: >
|
||||
certbot --nginx -n --agree-tos --redirect
|
||||
-m kontakt@michaelschiemer.de
|
||||
-d test.michaelschiemer.de
|
||||
args:
|
||||
creates: /etc/letsencrypt/live/test.michaelschiemer.de/fullchain.pem
|
||||
|
||||
18
ansible/roles/system_update/tasks/main.yml
Normal file
18
ansible/roles/system_update/tasks/main.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- name: Systempakete aktualisieren
|
||||
apt:
|
||||
update_cache: yes
|
||||
upgrade: safe
|
||||
autoremove: yes
|
||||
autoclean: yes
|
||||
register: upgrade_result
|
||||
become: true
|
||||
|
||||
- name: Zeige ggf. Anzahl aktualisierter Pakete
|
||||
debug:
|
||||
msg: "Anzahl aktualisierter Pakete: {{ upgrade_result.stdout_lines | default([]) | length }}"
|
||||
|
||||
- name: Reboot durchführen, wenn notwendig
|
||||
reboot:
|
||||
msg: "Reboot wegen Kernel-/System-Update erforderlich"
|
||||
pre_reboot_delay: 30
|
||||
when: upgrade_result.changed
|
||||
50
ansible/roles/webserver/tasks/main.yml
Normal file
50
ansible/roles/webserver/tasks/main.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
- name: Certbot + Plugin installieren
|
||||
apt:
|
||||
name:
|
||||
- certbot
|
||||
- python3-certbot-nginx
|
||||
state: present
|
||||
update_cache: yes
|
||||
when: letsencrypt_enabled
|
||||
|
||||
- name: Challenge-Verzeichnis für Let's Encrypt anlegen
|
||||
file:
|
||||
path: "{{ app_public }}/.well-known/acme-challenge"
|
||||
state: directory
|
||||
owner: www-data
|
||||
group: www-data
|
||||
mode: '0755'
|
||||
recurse: yes
|
||||
when: letsencrypt_enabled and letsencrypt_certbot_method == 'webroot'
|
||||
|
||||
- name: Stoppe Nginx für Standalone-Methode
|
||||
service:
|
||||
name: nginx
|
||||
state: stopped
|
||||
when: letsencrypt_enabled and letsencrypt_certbot_method == 'standalone'
|
||||
|
||||
- name: Let's Encrypt Zertifikat anfordern (Standalone)
|
||||
command: >
|
||||
certbot certonly --standalone -n --agree-tos
|
||||
-m {{ app_email }}
|
||||
-d {{ app_domain }}
|
||||
args:
|
||||
creates: /etc/letsencrypt/live/{{ app_domain }}/fullchain.pem
|
||||
when: letsencrypt_enabled and letsencrypt_certbot_method == 'standalone'
|
||||
|
||||
- name: Let's Encrypt Zertifikat anfordern (Webroot)
|
||||
command: >
|
||||
certbot certonly --webroot -w {{ app_public }} -n --agree-tos
|
||||
-m {{ app_email }}
|
||||
-d {{ app_domain }}
|
||||
args:
|
||||
creates: /etc/letsencrypt/live/{{ app_domain }}/fullchain.pem
|
||||
when: letsencrypt_enabled and letsencrypt_certbot_method == 'webroot'
|
||||
|
||||
- name: Kopiere SSL-Zertifikate für Docker
|
||||
copy:
|
||||
src: "/etc/letsencrypt/live/{{ app_domain }}/"
|
||||
dest: "{{ app_root }}/ssl/"
|
||||
remote_src: yes
|
||||
mode: '0644'
|
||||
when: letsencrypt_enabled
|
||||
6
ansible/roles/wireguard/defaults/main.yml
Normal file
6
ansible/roles/wireguard/defaults/main.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
wireguard_interface: wg0
|
||||
wireguard_port: 51820
|
||||
wireguard_address: 10.8.0.1/24
|
||||
wireguard_server_ip: 94.16.110.151 # oder deine Domain
|
||||
|
||||
wireguard_network: "10.8.0.0/24"
|
||||
133
ansible/roles/wireguard/tasks/configure.yml
Normal file
133
ansible/roles/wireguard/tasks/configure.yml
Normal file
@@ -0,0 +1,133 @@
|
||||
# --------------------------------------------------------
|
||||
# WireGuard installieren
|
||||
# --------------------------------------------------------
|
||||
|
||||
- name: Stelle sicher, dass WireGuard installiert ist
|
||||
apt:
|
||||
name: wireguard
|
||||
state: present
|
||||
update_cache: yes
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
|
||||
# --------------------------------------------------------
|
||||
# Server-Schlüssel erzeugen und speichern
|
||||
# --------------------------------------------------------
|
||||
|
||||
- name: Prüfe ob privater Server-Schlüssel existiert
|
||||
stat:
|
||||
path: /etc/wireguard/privatekey
|
||||
register: privkey_file
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Erstelle Schlüsselpaar für Server (wenn nicht vorhanden)
|
||||
command: wg genkey
|
||||
register: server_private_key
|
||||
when: ansible_connection != "local" and (not privkey_file.stat.exists | default(true))
|
||||
|
||||
- name: Speichere privaten Schlüssel
|
||||
copy:
|
||||
content: "{{ server_private_key.stdout }}"
|
||||
dest: /etc/wireguard/privatekey
|
||||
mode: "0600"
|
||||
when: server_private_key.stdout is defined and server_private_key.stdout is defined
|
||||
|
||||
- name: Lies privaten Schlüssel ein
|
||||
slurp:
|
||||
src: /etc/wireguard/privatekey
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Erzeuge öffentlichen Server-Schlüssel
|
||||
command: "echo '{{ wg_privkey }}' | wg pubkey"
|
||||
register: wg_pubkey
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Privaten Server-Schlüssel anzeigen
|
||||
debug:
|
||||
msg: "{{ server_private_key }}"
|
||||
when: ansible_connection != "local"
|
||||
|
||||
# --------------------------------------------------------
|
||||
# Client-Key-Erzeugung lokal (einmalig pro Client)
|
||||
# --------------------------------------------------------
|
||||
|
||||
- name: Generiere privaten Schlüssel für Clients (auf dem Server)
|
||||
command: wg genkey
|
||||
args:
|
||||
creates: "/etc/wireguard/client-{{ item.name }}.key"
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
register: client_private_keys
|
||||
when: ansible_connection != "local"
|
||||
|
||||
|
||||
- name: Erzeuge öffentlichen Schlüssel für Clients
|
||||
command: "echo '{{ client_privkey_result.stdout }}' | wg pubkey"
|
||||
register: client_pubkey_result
|
||||
when:
|
||||
- ansible_connection != "local"
|
||||
- client_privkey_result is defined
|
||||
- client_privkey_result.stdout is defined
|
||||
|
||||
- name: wireguard_clients mit public_key anreichern
|
||||
set_fact:
|
||||
wireguard_clients: "{{ wireguard_clients_with_pubkey | default([]) + [ item.0 | combine({'public_key': item.1.stdout|trim }) ] }}"
|
||||
loop: "{{ wireguard_clients | zip(client_public_keys.results) | list }}"
|
||||
when: client_public_keys is defined
|
||||
|
||||
- name: Aktuelles wireguard_clients-Set überschreiben
|
||||
set_fact:
|
||||
wireguard_clients: "{{ wireguard_clients_with_pubkey }}"
|
||||
when: wireguard_clients_with_pubkey is defined
|
||||
|
||||
# --------------------------------------------------------
|
||||
# Konfigurationsdatei erzeugen
|
||||
# --------------------------------------------------------
|
||||
|
||||
#- debug:
|
||||
# var: wireguard_clients
|
||||
|
||||
- name: Render wg0.conf
|
||||
template:
|
||||
src: wg0.conf.j2
|
||||
dest: /etc/wireguard/wg0.conf
|
||||
when: wg_privkey is defined and wg_privkey != ""
|
||||
|
||||
# --------------------------------------------------------
|
||||
# IP Forwarding & WireGuard aktivieren
|
||||
# --------------------------------------------------------
|
||||
|
||||
- name: Aktiviere IP-Forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: 1
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Starte und aktiviere WireGuard
|
||||
systemd:
|
||||
name: wg-quick@wg0
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: yes
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Verteilt für jeden Client die Client-Config
|
||||
template:
|
||||
src: client.conf.j2
|
||||
dest: "/etc/wireguard/clients/{{ item.name }}.conf"
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
loop: "{{ wireguard_clients }}"
|
||||
#delegate_to: localhost
|
||||
run_once: true
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
54
ansible/roles/wireguard/tasks/failsafe.yml
Normal file
54
ansible/roles/wireguard/tasks/failsafe.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
# roles/wireguard/tasks/failsafe.yml
|
||||
# Sicherstellt, dass SSH über VPN funktioniert und ein Fallback vorhanden ist
|
||||
|
||||
- name: Stelle sicher, dass wireguard_network gesetzt ist
|
||||
assert:
|
||||
that:
|
||||
- wireguard_network is defined
|
||||
fail_msg: "wireguard_network muss gesetzt sein (z. B. 10.8.0.0/24)"
|
||||
|
||||
- name: Automatisch externe IP als fallback_ip setzen (nur wenn nicht gesetzt)
|
||||
shell: curl -s ifconfig.me
|
||||
register: detected_fallback_ip
|
||||
when: fallback_ip is not defined
|
||||
changed_when: false
|
||||
|
||||
- name: Setze fallback_ip dynamisch als Ansible-Fact (wenn nicht gesetzt)
|
||||
set_fact:
|
||||
fallback_ip: "{{ detected_fallback_ip.stdout }}"
|
||||
when: fallback_ip is not defined
|
||||
|
||||
- name: (Optional) Erlaube temporär Fallback-SSH von aktueller IP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
proto: tcp
|
||||
from_ip: "{{ fallback_ip }}"
|
||||
|
||||
- name: Erlaube SSH-Zugriff über VPN
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
proto: tcp
|
||||
from_ip: "{{ wireguard_network }}"
|
||||
|
||||
- name: (Warnung) Prüfe ob VPN-Interface aktiv ist
|
||||
shell: ip a show dev wg0
|
||||
register: vpn_interface_check
|
||||
failed_when: false
|
||||
|
||||
- name: Hinweis, wenn VPN-Interface nicht aktiv ist
|
||||
debug:
|
||||
msg: "⚠️ VPN-Interface wg0 scheint nicht aktiv zu sein. SSH über VPN wird nicht funktionieren."
|
||||
when: vpn_interface_check.rc != 0
|
||||
|
||||
- name: (Optional) SSH von überall blockieren – nur wenn VPN aktiv
|
||||
when:
|
||||
- ssh_lockdown | default(false)
|
||||
- vpn_interface_check.rc == 0
|
||||
ufw:
|
||||
rule: deny
|
||||
port: 22
|
||||
proto: tcp
|
||||
from_ip: 0.0.0.0/0
|
||||
83
ansible/roles/wireguard/tasks/firewall.yml
Normal file
83
ansible/roles/wireguard/tasks/firewall.yml
Normal file
@@ -0,0 +1,83 @@
|
||||
# Beispiel: Passe jeden Task in dieser Datei so an:
|
||||
- name: Aktiviere Firewall-Regeln für WireGuard
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ wireguard_port }}"
|
||||
proto: udp
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
- name: Prüfe, ob UFW installiert ist
|
||||
command: which ufw
|
||||
register: ufw_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Installiere UFW (falls nicht vorhanden)
|
||||
apt:
|
||||
name: ufw
|
||||
state: present
|
||||
update_cache: yes
|
||||
when: ufw_installed.rc != 0
|
||||
|
||||
# Setze Standardrichtlinien (erst Konfiguration, dann am Ende aktivieren)
|
||||
- name: Setze Policy für eingehenden Traffic auf "deny"
|
||||
ufw:
|
||||
direction: incoming
|
||||
policy: deny
|
||||
|
||||
- name: Setze Policy für ausgehenden Traffic auf "allow"
|
||||
ufw:
|
||||
direction: outgoing
|
||||
policy: allow
|
||||
|
||||
# WireGuard-Port freigeben (UDP)
|
||||
- name: WireGuard-Port erlauben
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ wireguard_port | default(51820) }}"
|
||||
proto: udp
|
||||
|
||||
# SSH von bestimmter IP erlauben
|
||||
- name: SSH von deiner IP erlauben (empfohlen)
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
proto: tcp
|
||||
from_ip: "{{ fallback_ip }}"
|
||||
when: fallback_ip is defined and fallback_ip | length > 0
|
||||
|
||||
# Temporär für Tests: SSH für alle erlauben (nur bei Bedarf!)
|
||||
- name: SSH von überall erlauben (fail-safe, NUR während Setup/Test)
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
proto: tcp
|
||||
when: (not (fallback_ip is defined and fallback_ip | length > 0)) or (enable_ssh_from_anywhere | default(false))
|
||||
|
||||
# Masquerading für WireGuard
|
||||
- name: NAT für WireGuard aktivieren
|
||||
iptables:
|
||||
table: nat
|
||||
chain: POSTROUTING
|
||||
out_interface: "{{ wireguard_exit_interface | default('eth0') }}"
|
||||
source: "{{ wireguard_network }}"
|
||||
jump: MASQUERADE
|
||||
|
||||
- name: WireGuard Kernel-Modul laden
|
||||
modprobe:
|
||||
name: wireguard
|
||||
state: present
|
||||
|
||||
# UFW ganz am Schluss aktivieren
|
||||
- name: UFW aktivieren
|
||||
ufw:
|
||||
state: enabled
|
||||
|
||||
- name: Aktive UFW-Regeln anzeigen (zum Debuggen)
|
||||
command: ufw status verbose
|
||||
register: ufw_status
|
||||
changed_when: false
|
||||
|
||||
- name: Zeige UFW-Regeln im Ansible-Output
|
||||
debug:
|
||||
var: ufw_status.stdout
|
||||
60
ansible/roles/wireguard/tasks/generate_client_single.yml
Normal file
60
ansible/roles/wireguard/tasks/generate_client_single.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
- name: Key-Verzeichnis für Client anlegen
|
||||
file:
|
||||
path: "{{ role_path }}/client-keys/{{ client.name }}"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
become: true
|
||||
|
||||
- name: Existenz des privaten Schlüssels prüfen
|
||||
stat:
|
||||
path: "{{ role_path }}/client-keys/{{ client.name }}/private.key"
|
||||
register: client_private_key_stat
|
||||
|
||||
- name: Privaten Schlüssel generieren (nur falls nicht vorhanden)
|
||||
command: wg genkey
|
||||
register: genpriv
|
||||
args:
|
||||
chdir: "{{ role_path }}/client-keys/{{ client.name }}"
|
||||
when: not client_private_key_stat.stat.exists
|
||||
|
||||
- name: Privaten Schlüssel speichern (nur falls nicht vorhanden)
|
||||
copy:
|
||||
content: "{{ genpriv.stdout }}"
|
||||
dest: "{{ role_path }}/client-keys/{{ client.name }}/private.key"
|
||||
mode: "0600"
|
||||
when: not client_private_key_stat.stat.exists
|
||||
|
||||
- name: Public Key aus privaten Schlüssel generieren (bei Neuerstellung)
|
||||
command: wg pubkey
|
||||
args:
|
||||
stdin: "{{ genpriv.stdout }}"
|
||||
chdir: "{{ role_path }}/client-keys/{{ client.name }}"
|
||||
register: genpub
|
||||
when: not client_private_key_stat.stat.exists
|
||||
|
||||
- name: Bestehenden privaten Schlüssel laden (falls vorhanden)
|
||||
slurp:
|
||||
src: "{{ role_path }}/client-keys/{{ client.name }}/private.key"
|
||||
register: loaded_private
|
||||
when: client_private_key_stat.stat.exists
|
||||
|
||||
- name: Public Key aus gespeichertem Private Key erzeugen (falls vorhanden)
|
||||
command: wg pubkey
|
||||
args:
|
||||
stdin: "{{ loaded_private.content | b64decode }}"
|
||||
chdir: "{{ role_path }}/client-keys/{{ client.name }}"
|
||||
register: genpub_existing
|
||||
when: client_private_key_stat.stat.exists
|
||||
|
||||
- name: Public Key für Client in Datei schreiben
|
||||
copy:
|
||||
content: >
|
||||
{{ (genpub.stdout if not client_private_key_stat.stat.exists else genpub_existing.stdout) }}
|
||||
dest: "{{ role_path }}/client-keys/{{ client.name }}/public.key"
|
||||
mode: "0644"
|
||||
|
||||
- name: Variablen für Client setzen (private/public key, Adresse)
|
||||
set_fact:
|
||||
"wg_{{ client.name }}_private_key": "{{ (genpriv.stdout if not client_private_key_stat.stat.exists else loaded_private.content | b64decode) }}"
|
||||
"wg_{{ client.name }}_public_key": "{{ (genpub.stdout if not client_private_key_stat.stat.exists else genpub_existing.stdout) }}"
|
||||
"wg_{{ client.name }}_address": "{{ client.address }}"
|
||||
39
ansible/roles/wireguard/tasks/generate_clients.yml
Normal file
39
ansible/roles/wireguard/tasks/generate_clients.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
- name: Schleife über alle WireGuard-Clients
|
||||
include_tasks: generate_client_single.yml
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
loop_var: client
|
||||
|
||||
- name: Generiere privaten Schlüssel für jeden Client
|
||||
shell: "wg genkey"
|
||||
register: wg_client_private_keys
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
# kein delegate_to mehr!
|
||||
run_once: true # ggf. auch entfernen, siehe Anmerkung unten
|
||||
|
||||
- name: Setze globale Client-Key-Facts für alle Clients
|
||||
set_fact:
|
||||
wg_all_clients_private_keys: >-
|
||||
{{
|
||||
wg_all_clients_private_keys | default({}) | combine({
|
||||
item.1.name: item.0.stdout
|
||||
})
|
||||
}}
|
||||
loop: "{{ wg_client_private_keys.results | zip(wireguard_clients) | list }}"
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
|
||||
- name: Generiere Private Keys für Clients
|
||||
command: "wg genkey"
|
||||
register: client_keys_raw
|
||||
loop: "{{ wireguard_clients }}"
|
||||
loop_control:
|
||||
loop_var: client
|
||||
changed_when: false
|
||||
|
||||
- name: Mappe Keys nach Namen
|
||||
set_fact:
|
||||
wg_all_clients_private_keys: "{{ dict(wireguard_clients | map(attribute='name') | list | zip(client_keys_raw.results | map(attribute='stdout') | list)) }}"
|
||||
7
ansible/roles/wireguard/tasks/install.yml
Normal file
7
ansible/roles/wireguard/tasks/install.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
- name: Stelle sicher, dass WireGuard installiert ist
|
||||
apt:
|
||||
name: wireguard
|
||||
state: present
|
||||
update_cache: yes
|
||||
become: true
|
||||
when: ansible_connection != "local"
|
||||
22
ansible/roles/wireguard/tasks/main.yml
Normal file
22
ansible/roles/wireguard/tasks/main.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
#- include_tasks: install.yml
|
||||
#- include_tasks: configure.yml
|
||||
#- include_tasks: generate_clients.yml
|
||||
#- include_tasks: firewall.yml
|
||||
|
||||
|
||||
- name: Installiere WireGuard
|
||||
import_tasks: install.yml
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Konfiguriere WireGuard
|
||||
import_tasks: configure.yml
|
||||
|
||||
- name: Generiert .conf Dateien
|
||||
import_tasks: generate_clients.yml
|
||||
|
||||
- name: Setze Firewall-Regeln
|
||||
import_tasks: firewall.yml
|
||||
when: ansible_connection != "local"
|
||||
|
||||
- name: Wende VPN-Failsafe-Regeln an
|
||||
import_tasks: failsafe.yml
|
||||
10
ansible/roles/wireguard/templates/client.conf.j2
Normal file
10
ansible/roles/wireguard/templates/client.conf.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = {{ wg_all_clients_private_keys[item.name] }}
|
||||
Address = {{ item.address }}/32
|
||||
DNS = 1.1.1.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{ item.public_key }}
|
||||
Endpoint = {{ wireguard_server_ip }}:{{ wireguard_port }}
|
||||
AllowedIPs = {{ wireguard_network }}, {{ wireguard_server_ip }}/32
|
||||
PersistentKeepalive = 25
|
||||
12
ansible/roles/wireguard/templates/wg0.conf.j2
Normal file
12
ansible/roles/wireguard/templates/wg0.conf.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
[Interface]
|
||||
Address = {{ wireguard_address }}
|
||||
PrivateKey = {{ wg_privkey | b64decode | trim }}
|
||||
ListenPort = {{ wireguard_port }}
|
||||
PostUp = iptables -A FORWARD -i {{ wireguard_interface }} -j ACCEPT; iptables -A FORWARD -o {{ wireguard_interface }} -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i {{ wireguard_interface }} -j ACCEPT; iptables -D FORWARD -o {{ wireguard_interface }} -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
|
||||
|
||||
{% for client in wireguard_clients %}
|
||||
[Peer]
|
||||
PublicKey = {{ client.public_key }}
|
||||
AllowedIPs = {{ client.address }}/32
|
||||
{% endfor %}
|
||||
Reference in New Issue
Block a user