Skip to content

Move to a unified gateway#1

Merged
kreigan merged 53 commits intomainfrom
gateway
Feb 22, 2026
Merged

Move to a unified gateway#1
kreigan merged 53 commits intomainfrom
gateway

Conversation

@kreigan
Copy link
Copy Markdown
Owner

@kreigan kreigan commented Feb 22, 2026

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restructures the Ansible configuration to support a “unified gateway” approach (Cloudflared tunnel + Caddy reverse proxy) and introduces new DNS components (Unbound resolver + PowerDNS authoritative DNS + zone management), while removing legacy backup and SSL-deployment playbooks.

Changes:

  • Add new Ansible roles and playbooks for gateway (cloudflared + Caddy) and DNS stack (Unbound, PowerDNS, zone management).
  • Restructure inventory groups/hosts and introduce an ansible.cfg with a default inventory.
  • Remove legacy storage backup and SSL certificate deployment playbooks and their supporting files.

Reviewed changes

Copilot reviewed 65 out of 66 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
ansible/requirements.yaml Adds community.sops collection and PowerDNS.pdns role for the new DNS tooling.
ansible/playbooks/storage/backup_test.yml Removes legacy resticprofile backup test playbook.
ansible/playbooks/storage/backup/vars/main.yml Removes legacy backup role defaults/vars.
ansible/playbooks/storage/backup/tasks/validate-configuration.yml Removes legacy backup configuration validation tasks.
ansible/playbooks/storage/backup/tasks/templates/systemd/restic-repo-systemd-dropin.j2 Removes legacy systemd credentials drop-in template for restic repos.
ansible/playbooks/storage/backup/tasks/templates/scripts/snapper-plugin.sh.j2 Removes legacy snapper plugin script template for snapshot integration.
ansible/playbooks/storage/backup/tasks/templates/configs/resticprofile.yaml.j2 Removes legacy resticprofile main config template.
ansible/playbooks/storage/backup/tasks/templates/configs/resticprofile-profile.yaml.j2 Removes legacy resticprofile profile template.
ansible/playbooks/storage/backup/tasks/make-repository.yml Removes legacy restic repository creation tasks.
ansible/playbooks/storage/backup/tasks/files/backup-assist.sh Removes legacy backup mount/unmount helper script.
ansible/playbooks/storage/backup/tasks/deploy.yml Removes legacy backup deployment tasks (packages/restic/resticprofile/snapper).
ansible/playbooks/storage/backup/tasks/deploy-snapper.yml Removes legacy snapper deployment tasks.
ansible/playbooks/storage/backup/tasks/deploy-resticprofile.yml Removes legacy resticprofile deployment/configuration tasks.
ansible/playbooks/storage/backup/tasks/deploy-restic.yml Removes legacy restic binary deployment tasks.
ansible/playbooks/storage/backup/tasks/create-repository-secret.yml Removes legacy systemd-creds secret creation tasks.
ansible/playbooks/storage/backup/tasks/configure-snapshot.yml Removes legacy snapper target configuration tasks.
ansible/playbooks/storage/backup/tasks/configure-profiles.yml Removes legacy resticprofile profile/env/repo config tasks.
ansible/playbooks/storage/backup/README.md Removes legacy backup playbook documentation.
ansible/playbooks/storage/backup/DESIGN.md Removes legacy backup system design documentation.
ansible/playbooks/storage/backup.yml Removes legacy storage backup top-level playbook.
ansible/playbooks/ssl/upload-ssl.yml Removes legacy SSL upload/deploy playbook.
ansible/playbooks/ssl/tasks/validate-post.yml Removes legacy post-deploy SSL validation task file.
ansible/playbooks/ssl/tasks/fetch-remote-cert.yml Removes legacy remote cert fetch task file.
ansible/playbooks/ssl/tasks/deployment/deploy-proxmox.yml Removes legacy Proxmox SSL deploy implementation.
ansible/playbooks/ssl/tasks/deployment/deploy-pihole.yml Removes legacy Pi-hole SSL deploy implementation.
ansible/playbooks/ssl/tasks/deployment/deploy-omv.yml Removes legacy OMV SSL deploy implementation.
ansible/playbooks/roles/unbound/tasks/main.yml Adds a new Unbound role (install + base/cache config).
ansible/playbooks/roles/unbound/handlers/main.yml Adds handler to restart Unbound.
ansible/playbooks/roles/pihole/templates/pihole.toml.j2 Adds a Pi-hole TOML template (currently not wired into tasks).
ansible/playbooks/roles/pihole/tasks/main.yml Adds Pi-hole role to install and configure via API (incl. 1Password secret read).
ansible/playbooks/roles/pihole/tasks/install.yml Adds unattended Pi-hole installation tasks.
ansible/playbooks/roles/pihole/tasks/configure.yml Adds API PATCH-based Pi-hole FTL configuration application.
ansible/playbooks/roles/pihole/defaults/main.yml Adds Pi-hole role defaults (password, upstreams, config map).
ansible/playbooks/roles/cloudflared/templates/cloudflared.conf.j2 Adds systemd override template for cloudflared.
ansible/playbooks/roles/cloudflared/tasks/main.yml Adds cloudflared role to install binary, install service, and configure token + override.
ansible/playbooks/roles/cloudflared/handlers/main.yml Adds handler to restart cloudflared with daemon reload.
ansible/playbooks/roles/cloudflared/defaults/main.yml Adds cloudflared defaults (bin dir, metrics, options).
ansible/playbooks/roles/caddy/templates/caddy.service.j2 Adds a custom systemd unit template for Caddy.
ansible/playbooks/roles/caddy/tasks/main.yml Adds Caddy role to build with xcaddy, deploy, and render JSON config.
ansible/playbooks/roles/caddy/handlers/main.yml Adds handlers for systemd reload + Caddy reload/restart.
ansible/playbooks/roles/caddy/defaults/main.yml Adds Caddy role defaults (paths, version, modules, config).
ansible/playbooks/roles/caddy/README.md Adds documentation for the new Caddy role.
ansible/playbooks/resolvers.yml Adds resolver playbook (targets resolvers group).
ansible/playbooks/powerdns.yml Adds PowerDNS installation/config playbook + TSIG key management.
ansible/playbooks/pihole.yml Adds Pi-hole playbook (targets pihole group).
ansible/playbooks/manage-zones.yml Adds zone-management playbook using pdns-zone-manager and playbooks/files/zones.yml.
ansible/playbooks/gateway.yml Adds unified gateway playbook (cloudflared on gateways; Caddy on gateway01).
ansible/playbooks/files/zones.yml Adds DNS zones/rrsets configuration data file.
ansible/inventory/hosts.yml Restructures inventory into new host/group layout (onprem, gateways, etc.).
ansible/inventory/host_vars/resolver01/unbound.yml Adds resolver01 Unbound configuration.
ansible/inventory/host_vars/pihole01/pihole_config.yml Adds Pi-hole FTL config for pihole01.
ansible/inventory/host_vars/ns01/powerdns_sqlite3.yml Adds PowerDNS sqlite3 backend and API/web settings for ns01.
ansible/inventory/host_vars/gateway01/caddy.yml Adds gateway01 Caddy config (TLS automation, routes, L4).
ansible/inventory/host_vars/gateway01/00-routes-public.yml Adds public Caddy routes list.
ansible/inventory/host_vars/gateway01/00-routes-internal.yml Adds internal Caddy routes list.
ansible/files/host_config/storage.yml Removes legacy storage backup host config source.
ansible/files/host_config/ns01.yml Adds ns01 host config source (PowerDNS API key + TSIG refs).
ansible/files/host_config/gateway01.yml Adds gateway01 host config source (cloudflared + Cloudflare token refs).
ansible/files/host_config/ampere-vm.yml Adds oracle VM host config source (cloudflared token ref).
ansible/files/group_config/proxmox_hosts.yml Removes legacy Proxmox group config source.
ansible/ansible.cfg Adds default inventory configuration.
ansible/README.md Removes sections describing now-deleted playbooks and trims “best practices” section.
README.md Updates repository-level configuration docs but still references removed backup playbook path.
.sops.yaml Adds sops configuration (currently points to a non-existent zones file path).
.gitignore Stops ignoring ansible.cfg so it can be committed.
.github/workflows/ansible-lint.yml Excludes */files/* from playbook syntax checks (so data files aren’t treated as playbooks).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

---
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/playbook.json
- name: Configure resolvers
hosts: resolvers
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Playbook targets hosts: resolvers, but the inventory (ansible/inventory/hosts.yml) does not define a resolvers group (only resolver01 host under onprem). Either add a resolvers group (with resolver01 as member) or change this play to target the intended group/host.

Suggested change
hosts: resolvers
hosts: resolver01

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +10
- name: Read 1Password reference for Pi-hole password
ansible.builtin.command: op read "{{ pihole_webpassword }}"
delegate_to: localhost
register: pihole_password_op
changed_when: false
failed_when: pihole_password_op.rc != 0
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The op read task will print the resolved Pi-hole password in Ansible output (it registers stdout and isn't no_log). Mark this task no_log: true (and consider no_log on the surrounding block) to avoid leaking secrets in CI logs and local runs.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +39
- name: Download cloudflared binary
ansible.builtin.get_url:
url: "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-{{ cloudflared_arch }}"
dest: "{{ cloudflared_bin_dir }}/cloudflared"
mode: "0755"
owner: root
group: root
become: true
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_url downloads the binary into {{ cloudflared_bin_dir }} but the role never ensures that directory exists. On hosts where /usr/local/bin (or a custom cloudflared_bin_dir) is missing, this will fail. Add an ansible.builtin.file task to create cloudflared_bin_dir before the download.

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines 29 to 33
## Available Playbooks

- **Storage Backup** - Automated BTRFS snapshot backup to S3-compatible storage using restic
- See [ansible/playbooks/storage/backup/](ansible/playbooks/storage/backup/)

Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Available Playbooks” section still documents “Storage Backup” and links to ansible/playbooks/storage/backup/, but that directory/playbook has been removed in this PR. Update or remove this section so the repository README doesn’t point to non-existent playbooks.

Copilot uses AI. Check for mistakes.
---
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/playbook.json
- name: Configure Pi-hole
hosts: pihole
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Playbook targets hosts: pihole, but the inventory (ansible/inventory/hosts.yml) does not define a pihole group (only pihole01 host under onprem). Either add a pihole group (with pihole01) or change this play to target the correct host/group.

Suggested change
hosts: pihole
hosts: pihole01

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines 26 to 27
2. Generate inventory variables: `task ansible:generate-config`
3. Run playbooks as needed (see [ansible/README.md](ansible/README.md))
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The numbered list under “Configuration” has duplicate step numbering (two items labeled 2.). Renumber the steps so the sequence is consistent.

Suggested change
2. Generate inventory variables: `task ansible:generate-config`
3. Run playbooks as needed (see [ansible/README.md](ansible/README.md))
3. Generate inventory variables: `task ansible:generate-config`
4. Run playbooks as needed (see [ansible/README.md](ansible/README.md))

Copilot uses AI. Check for mistakes.
# CLOUD PROVIDERS

oracle:
hosts:
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the inventory, the oracle group declares hosts: but provides no mapping (so YAML parses it as null). Ansible’s YAML inventory expects hosts to be a dictionary; consider changing this to hosts: {} (or omit hosts entirely) to avoid inventory parsing issues.

Suggested change
hosts:
hosts: {}

Copilot uses AI. Check for mistakes.
# Caddy environment variables
# Sourced by systemd service
CF_API_TOKEN={{ caddy_cf_api_token }}
dest: /etc/caddy/caddy.env
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The credentials env file is written to a hard-coded path (/etc/caddy/caddy.env), but the systemd unit references {{ caddy_config_dir }}/caddy.env. If caddy_config_dir is overridden, the service will look in a different location than this task writes. Use dest: "{{ caddy_config_dir }}/caddy.env" for consistency.

Suggested change
dest: /etc/caddy/caddy.env
dest: "{{ caddy_config_dir }}/caddy.env"

Copilot uses AI. Check for mistakes.
Comment thread .sops.yaml
- &user_kreigan age165j834wdl949ss7rqpxytcw4hcmp3k7kakrjs9gphch3q3ag4pdqmycj78

creation_rules:
- path_regex: ansible/playbooks/dns/files/zones.yml$
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.sops.yaml creation rule targets ansible/playbooks/dns/files/zones.yml, but that path doesn't exist in this repo (zones file is under ansible/playbooks/files/zones.yml). As written, sops won't encrypt/decrypt the zones file at all. Update path_regex to the real path (or move the file to match the rule).

Suggested change
- path_regex: ansible/playbooks/dns/files/zones.yml$
- path_regex: ansible/playbooks/files/zones.yml$

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +22
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE

NoNewPrivileges=true
PrivateDevices=true
SecureBits=keep-caps
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service is granted AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE with SecureBits=keep-caps, which unnecessarily gives the Caddy process powerful network administration privileges (e.g., changing routing, firewall rules) if it is compromised. An attacker exploiting Caddy would gain far more control over the host network stack than needed just to bind to ports 80/443. Restrict the service to only the minimal capability required (typically CAP_NET_BIND_SERVICE) and consider using a capability bounding set or dropping CAP_NET_ADMIN entirely.

Suggested change
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=true
PrivateDevices=true
SecureBits=keep-caps
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
PrivateDevices=true

Copilot uses AI. Check for mistakes.
@kreigan kreigan merged commit 11db493 into main Feb 22, 2026
4 of 5 checks passed
@kreigan kreigan deleted the gateway branch February 22, 2026 04:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants