extract-fw-host-vars.py: abort if a conf file cannot be read; add --from-dir. Migrate cl-test.
Previously an unreadable file (e.g. /etc/ipt-firewall is 0750 after the role ran) silently produced almost empty host_vars. The script now exits with an error and writes nothing. --from-dir reads the conf files from a local directory, e.g. fetched with ansible using the vaulted become password. Add host_vars for cl-test.oopen.de (fw_manage_config: true). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+30
-12
@@ -6,7 +6,7 @@ Reads /etc/ipt-firewall/{interfaces,main}_ipv{4,6}.conf via SSH,
|
|||||||
maps all variables to Ansible fw_* names, and writes a host_vars file.
|
maps all variables to Ansible fw_* names, and writes a host_vars file.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
./extract-fw-host-vars.py <hostname> [--user USER] [--port PORT] [--dry-run]
|
./extract-fw-host-vars.py <hostname> [--user USER] [--port PORT] [--sudo] [--from-dir DIR] [--output FILE] [--dry-run]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
./extract-fw-host-vars.py cl-01.oopen.de
|
./extract-fw-host-vars.py cl-01.oopen.de
|
||||||
@@ -749,6 +749,9 @@ def main():
|
|||||||
parser.add_argument("--output", "-o", default=None, help="Output file (default: stdout)")
|
parser.add_argument("--output", "-o", default=None, help="Output file (default: stdout)")
|
||||||
parser.add_argument("--sudo", "-s", action="store_true",
|
parser.add_argument("--sudo", "-s", action="store_true",
|
||||||
help="Read files via sudo (prompts for sudo password once)")
|
help="Read files via sudo (prompts for sudo password once)")
|
||||||
|
parser.add_argument("--from-dir", "-d", default=None,
|
||||||
|
help="Read the conf files from this local directory instead of via SSH "
|
||||||
|
"(e.g. fetched with: ansible HOST -b -m fetch ...)")
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Print SSH commands without executing")
|
parser.add_argument("--dry-run", action="store_true", help="Print SSH commands without executing")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -767,18 +770,33 @@ def main():
|
|||||||
print(f"ssh {args.user}@{hostname} {cmd} {path}")
|
print(f"ssh {args.user}@{hostname} {cmd} {path}")
|
||||||
return
|
return
|
||||||
|
|
||||||
sudo_password = None
|
|
||||||
if args.sudo:
|
|
||||||
import getpass
|
|
||||||
sudo_password = getpass.getpass(f"sudo password for {args.user}@{hostname}: ")
|
|
||||||
|
|
||||||
print(f"Connecting to {hostname} as {args.user} ...", file=sys.stderr)
|
|
||||||
|
|
||||||
contents = {}
|
contents = {}
|
||||||
for key, path in files.items():
|
if args.from_dir:
|
||||||
print(f" Reading {path} ...", file=sys.stderr)
|
for key, path in files.items():
|
||||||
content = ssh_cat(hostname, args.user, args.port, path, sudo_password=sudo_password)
|
local = Path(args.from_dir) / Path(path).name
|
||||||
contents[key] = content or ""
|
print(f" Reading {local} ...", file=sys.stderr)
|
||||||
|
try:
|
||||||
|
contents[key] = local.read_text()
|
||||||
|
except OSError as e:
|
||||||
|
print(f" WARNING: could not read {local}: {e}", file=sys.stderr)
|
||||||
|
contents[key] = None
|
||||||
|
else:
|
||||||
|
sudo_password = None
|
||||||
|
if args.sudo:
|
||||||
|
import getpass
|
||||||
|
sudo_password = getpass.getpass(f"sudo password for {args.user}@{hostname}: ")
|
||||||
|
|
||||||
|
print(f"Connecting to {hostname} as {args.user} ...", file=sys.stderr)
|
||||||
|
|
||||||
|
for key, path in files.items():
|
||||||
|
print(f" Reading {path} ...", file=sys.stderr)
|
||||||
|
contents[key] = ssh_cat(hostname, args.user, args.port, path, sudo_password=sudo_password)
|
||||||
|
|
||||||
|
# An unreadable file would silently produce (nearly) empty host_vars
|
||||||
|
if any(c is None for c in contents.values()):
|
||||||
|
print("ERROR: not all config files could be read — nothing written "
|
||||||
|
"(try --sudo or --from-dir)", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
all_warnings = []
|
all_warnings = []
|
||||||
parsed = {}
|
parsed = {}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
# ipt-firewall configuration for cl-test.oopen.de
|
||||||
|
# Generated by extract-fw-host-vars.py - review before committing!
|
||||||
|
# Place in: host_vars/<hostname>/<short-hostname>-ipt-server.yml
|
||||||
|
|
||||||
|
fw_manage_config: true
|
||||||
|
|
||||||
|
# --- Network
|
||||||
|
fw_ext_interfaces:
|
||||||
|
- "eth0"
|
||||||
|
fw_ext_ips_v4:
|
||||||
|
- "159.69.74.143"
|
||||||
|
fw_ext_ips_v6:
|
||||||
|
- "2a01:4f8:231:19a7::143"
|
||||||
|
|
||||||
|
# --- Munin
|
||||||
|
munin_remote_ipv4: 37.27.121.227
|
||||||
|
munin_remote_ipv6: "2a01:4f9:3070:2bda::227"
|
||||||
|
|
||||||
|
# --- Access control IPv4
|
||||||
|
fw_allow_ext_service_v4: "159.69.74.156:3478:tcp 159.69.74.156:3478:udp 159.69.74.156:3479:tcp 159.69.74.156:3479:udp 159.69.74.156:5349:tcp 159.69.74.156:5350:udp"
|
||||||
|
fw_allow_local_service_from_networks_v4: "46.90.86.195:80:tcp 46.90.86.195:443:tcp"
|
||||||
|
|
||||||
|
# --- Access control IPv6
|
||||||
|
fw_allow_ext_service_v6: "2a01:4f8:231:19a7::156,3478,tcp 2a01:4f8:231:19a7::156,3478,udp 2a01:4f8:231:19a7::156,3479,tcp 2a01:4f8:231:19a7::156,3479,udp 2a01:4f8:231:19a7::156,5349,tcp 2a01:4f8:231:19a7::156,5349,udp 2a01:4f8:231:19a7::156,5350,tcp 2a01:4f8:231:19a7::156,5350,udp"
|
||||||
|
fw_allow_local_service_from_networks_v6: "2003:ec:df11:4400::/56,80,tcp 2003:ec:df11:4400::/56,443,tcp"
|
||||||
|
|
||||||
|
# --- HTTP
|
||||||
|
fw_http_server_ips: $ext_1_ip
|
||||||
|
|
||||||
|
# --- Mail
|
||||||
|
fw_mail_client_ips: $ext_1_ip
|
||||||
|
|
||||||
|
# --- TURN / STUN
|
||||||
|
fw_nc_turn_server_ips: $ext_1_ip
|
||||||
|
|
||||||
|
# --- Block
|
||||||
|
fw_blocked_ips_v4: 222.184.0.0/13 61.160.0.0/16 116.8.0.0/14
|
||||||
@@ -60,7 +60,21 @@ HOSTNAME=<hostname>
|
|||||||
-o host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml
|
-o host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Das Skript fragt einmalig nach dem `sudo`-Passwort.
|
Das Skript fragt einmalig nach dem `sudo`-Passwort. Kann eine der Dateien nicht
|
||||||
|
gelesen werden, bricht es ab, ohne etwas zu schreiben.
|
||||||
|
|
||||||
|
Alternativ ohne Passwortabfrage (sudo über `ansible_become_password` aus dem Vault):
|
||||||
|
die Dateien mit Ansible holen und lokal einlesen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
for f in interfaces_ipv4 interfaces_ipv6 main_ipv4 main_ipv6 ; do
|
||||||
|
ansible ${HOSTNAME} -b -m fetch \
|
||||||
|
-a "src=/etc/ipt-firewall/${f}.conf dest=/tmp/fw-${HOSTNAME}/ flat=yes"
|
||||||
|
done
|
||||||
|
./extract-fw-host-vars.py ${HOSTNAME} --from-dir /tmp/fw-${HOSTNAME} \
|
||||||
|
-o host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml
|
||||||
|
rm -rf /tmp/fw-${HOSTNAME}
|
||||||
|
```
|
||||||
|
|
||||||
**Ergebnis prüfen:**
|
**Ergebnis prüfen:**
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user