diff --git a/seed/base-machine/applicationservice.yml b/seed/base-machine/applicationservice.yml
index faed7a8..e21bf79 100644
--- a/seed/base-machine/applicationservice.yml
+++ b/seed/base-machine/applicationservice.yml
@@ -2,3 +2,4 @@ format: '0.1'
description: Base information for a machine
depends:
- base
+ - dns-local
diff --git a/seed/base-machine/dictionaries/12-base.xml b/seed/base-machine/dictionaries/12-base.xml
index 20dbf7b..168801c 100644
--- a/seed/base-machine/dictionaries/12-base.xml
+++ b/seed/base-machine/dictionaries/12-base.xml
@@ -12,8 +12,6 @@
-
-
@@ -24,18 +22,6 @@
-
- zone_name_eth0
- LocalDNS
- dns_client_address
-
-
- dns_client_address
- dns
- ip_eth0
- ip
- ip_dns
-
zones_name
zones_list
diff --git a/seed/base-machine/manual/install/install_host b/seed/base-machine/manual/install/install_host
index 35d83c4..04a0b69 100755
--- a/seed/base-machine/manual/install/install_host
+++ b/seed/base-machine/manual/install/install_host
@@ -5,7 +5,9 @@ if [ -z "$HOST_NAME" ]; then
echo "usage: $0 host name"
exit 1
fi
-apt install --yes systemd-container dnf jq debootstrap htop gettext patch unzip mlocate xz-utils
+# remove current rules
+systemctl stop risottofirewall.service || true
+apt install --yes systemd-container dnf jq debootstrap htop gettext patch unzip mlocate xz-utils iptables
systemd-tmpfiles --create --clean --remove $PWD/host/configurations/$HOST_NAME/tmpfiles.d/0asystemd-nspawn.conf
systemd-tmpfiles --create --clean --remove $PWD/host/configurations/$HOST_NAME/tmpfiles.d/0rougail.conf
systemctl daemon-reload
@@ -17,6 +19,8 @@ systemctl restart systemd-resolved
# systemctl mask dev-hugepages.mount
systemctl enable risotto-images.timer
systemctl restart risotto-images.timer
+systemctl enable risottofirewall.service
+systemctl start risottofirewall.service
#nft add table nat
#nft flush table nat;
diff --git a/seed/base-machine/tests/execute.py b/seed/base-machine/tests/execute.py
new file mode 100644
index 0000000..7b9cb08
--- /dev/null
+++ b/seed/base-machine/tests/execute.py
@@ -0,0 +1,26 @@
+from os import fdopen
+from dbus import SystemBus, Array
+
+
+def run(host, cmd):
+ bus = SystemBus()
+ remote_object = bus.get_object('org.freedesktop.machine1',
+ '/org/freedesktop/machine1',
+ False,
+ )
+ res = remote_object.OpenMachineShell(host,
+ '',
+ cmd[0],
+ Array(cmd, signature='s'),
+ Array(['TERM=dumb'], signature='s'),
+ dbus_interface='org.freedesktop.machine1.Manager',
+ )
+ fd = res[0].take()
+ fh = fdopen(fd)
+ while True:
+ try:
+ yield fh.readline().strip()
+ except OSError as err:
+ if err.errno != 5:
+ raise err from err
+ break
diff --git a/seed/dns-external/applicationservice.yml b/seed/dns-external/applicationservice.yml
new file mode 100644
index 0000000..654347d
--- /dev/null
+++ b/seed/dns-external/applicationservice.yml
@@ -0,0 +1,2 @@
+format: '0.1'
+description: Configuration du client DNS externe
diff --git a/seed/dns-external/dictionaries/14-dns-external.xml b/seed/dns-external/dictionaries/14-dns-external.xml
new file mode 100644
index 0000000..9cdb18b
--- /dev/null
+++ b/seed/dns-external/dictionaries/14-dns-external.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ False
+
+
+
+
+
+
+ zone_name_eth0
+ ExternalDNS
+ dns_client_address
+
+
+
diff --git a/seed/dns-external/tests/test_dns_external.py b/seed/dns-external/tests/test_dns_external.py
new file mode 100644
index 0000000..b821252
--- /dev/null
+++ b/seed/dns-external/tests/test_dns_external.py
@@ -0,0 +1,17 @@
+from yaml import load, SafeLoader
+from os import environ
+
+from execute import run
+
+
+EXTERNAL_DOMAIN = 'google.fr'
+
+
+def test_dns_external():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/dns-local.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ result = run(data['address'],
+ ['/bin/resolvectl', 'query', EXTERNAL_DOMAIN],
+ )
+ assert 'resolve call failed' not in next(result), f'cannot resolved {EXTERNAL_DOMAIN}'
diff --git a/seed/dns-local/applicationservice.yml b/seed/dns-local/applicationservice.yml
new file mode 100644
index 0000000..ad16e59
--- /dev/null
+++ b/seed/dns-local/applicationservice.yml
@@ -0,0 +1,2 @@
+format: '0.1'
+description: Configuration du client DNS local
diff --git a/seed/dns-local/dictionaries/13-dns-local.xml b/seed/dns-local/dictionaries/13-dns-local.xml
new file mode 100644
index 0000000..129bfc8
--- /dev/null
+++ b/seed/dns-local/dictionaries/13-dns-local.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ /tests/dns-local.yml
+
+
+
+
+
+ True
+
+
+
+
+
+
+
+ zone_name_eth0
+ LocalDNS
+ dns_client_address
+
+
+ dns_client_address
+ dns
+ ip_eth0
+ ip
+ ip_dns
+
+
+
+
+
diff --git a/seed/dns-local/templates/dns-local.yml b/seed/dns-local/templates/dns-local.yml
new file mode 100644
index 0000000..10e0101
--- /dev/null
+++ b/seed/dns-local/templates/dns-local.yml
@@ -0,0 +1,25 @@
+address: '%%domain_name_eth0'
+addresses:
+%if %%getVar('dns_client_address', None)
+- dns_address: '%%dns_client_address'
+ dns_ip: '%%ip_dns'
+%elif %%getVar('unbound_forward_address', None)
+ %for %%authority in %%unbound_forward_address
+- dns_address: %%authority
+ dns_ip: %%get_ip(%%str(%%authority))
+ %end for
+%else
+ %for %%zone in %%nsd_zones_auto
+ %set %%suffix = %%normalize_family(%%zone)
+ %set %%hostnames = %%nsd["nsd_zone_" + %%suffix]["hostname_" + %%suffix]["hostname_" + %%suffix]
+ %for %%nsd in %%hostnames
+- dns_address: %%{nsd}.%%zone
+ dns_ip: %%nsd["ip_" + %%suffix]
+ %end for
+ %end for
+%end if
+%if %%dns_is_only_local
+dns_is_only_local: true
+%else
+dns_is_only_local: false
+%end if
diff --git a/seed/dns-local/tests/test_dns_local.py b/seed/dns-local/tests/test_dns_local.py
new file mode 100644
index 0000000..669a931
--- /dev/null
+++ b/seed/dns-local/tests/test_dns_local.py
@@ -0,0 +1,32 @@
+from yaml import load, SafeLoader
+from os import environ
+
+from execute import run
+
+EXTERNAL_DOMAIN = 'google.fr'
+
+
+def test_dns_local():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/dns-local.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ if 'addresses' not in data:
+ return
+ for address in data['addresses']:
+ result = run(data['address'],
+ ['/bin/resolvectl', 'query', address['dns_address']],
+ )
+ first = next(result)
+ search = f"{address['dns_address']}: {address['dns_ip']}"
+ assert first == search or first.startswith(search + " "), f'dns return "{first}" instead of "{search}"'
+
+
+def test_dns_external():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/dns-local.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ if data['dns_is_only_local']:
+ result = run(data['address'],
+ ['/bin/resolvectl', 'query', EXTERNAL_DOMAIN],
+ )
+ assert 'resolve call failed' in next(result), f'should not resolved {EXTERNAL_DOMAIN}'
diff --git a/seed/host-systemd-machined/dictionaries/21-machined.xml b/seed/host-systemd-machined/dictionaries/21-machined.xml
index 9e19a52..3e9636f 100644
--- a/seed/host-systemd-machined/dictionaries/21-machined.xml
+++ b/seed/host-systemd-machined/dictionaries/21-machined.xml
@@ -23,11 +23,14 @@
-
+
+
+
+
diff --git a/seed/host-systemd-machined/templates/0asystemd-nspawn.conf b/seed/host-systemd-machined/templates/0asystemd-nspawn.conf
index d4bc73a..98de2d2 100644
--- a/seed/host-systemd-machined/templates/0asystemd-nspawn.conf
+++ b/seed/host-systemd-machined/templates/0asystemd-nspawn.conf
@@ -1,8 +1,15 @@
D /usr/local/lib/sbin/ 0755 root root - -
D /etc/systemd/nspawn/ 0755 root root - -
D /etc/systemd/network/ 0755 root root - -
+D /usr/local/lib/systemd/system/ 0755 root root - -
d /var/lib/risotto/configurations/ 0755 root root - -
r /etc/network/interfaces - - - - -
%for %%filename in %%machined.nspawn_script_filename
C %%filename 0755 root root - %%host_install_dir/host/configurations/%%host_name%%filename
%end for
+%for %%service in %%services
+ %if %%service.engine != 'none'
+ %set %%filename = '/usr/local/lib/systemd/system/' + %%service.doc
+C %%filename 0755 root root - %%host_install_dir/host/configurations/%%host_name%%filename
+ %end if
+%end for
diff --git a/seed/host-systemd-machined/templates/risottofirewall.service b/seed/host-systemd-machined/templates/risottofirewall.service
index d3eb053..fa56e57 100644
--- a/seed/host-systemd-machined/templates/risottofirewall.service
+++ b/seed/host-systemd-machined/templates/risottofirewall.service
@@ -4,6 +4,7 @@ After=network.target
[Service]
Type=oneshot
+RemainAfterExit=yes
%for %%dns in %%machined.machines
%set %%machine = %%normalize_family(%%dns)
%set %%outgoing = %%machined['machine_' + %%machine]['outgoing_ports_' + %%machine]
@@ -14,8 +15,8 @@ Type=oneshot
%else
%set %%protocol = 'tcp'
%end if
-ExecStart=/sbin/iptables -t nat -A POSTROUTING -s %%get_ip(%%dns) -p %%protocol -m %%protocol --dport %%port -o enp3s0 -j MASQUERADE
-ExecStop=-/sbin/iptables -t nat -D POSTROUTING -s %%get_ip(%%dns) -p %%protocol -m %%protocol --dport %%port -o enp3s0 -j MASQUERADE
+ExecStart=/sbin/iptables -t nat -A POSTROUTING -s %%get_ip(%%dns) -p %%protocol -m %%protocol --dport %%port -o %%output_interface -j MASQUERADE
+ExecStop=-/sbin/iptables -t nat -D POSTROUTING -s %%get_ip(%%dns) -p %%protocol -m %%protocol --dport %%port -o %%output_interface -j MASQUERADE
%end for
%end if
%end for
diff --git a/seed/letsencrypt/applicationservice.yml b/seed/letsencrypt/applicationservice.yml
index 3cd83fa..d3cc591 100644
--- a/seed/letsencrypt/applicationservice.yml
+++ b/seed/letsencrypt/applicationservice.yml
@@ -1,4 +1,4 @@
format: '0.1'
description: Let's encrypt
depends:
- - base-fedora-35
+ - base-fedora
diff --git a/seed/nextcloud/dictionaries/31_nextcloud.xml b/seed/nextcloud/dictionaries/31_nextcloud.xml
index 2cc50fa..ef6a93e 100644
--- a/seed/nextcloud/dictionaries/31_nextcloud.xml
+++ b/seed/nextcloud/dictionaries/31_nextcloud.xml
@@ -70,7 +70,7 @@
revprox_client_external_domainnames
nextcloud_well_known_server
-
+
domain_name_eth0
revprox_client_port
/.well-known/caldav
nextcloud_well_known_caldav
-
+
domain_name_eth0
revprox_client_port
diff --git a/seed/nginx-reverse-proxy/applicationservice.yml b/seed/nginx-reverse-proxy/applicationservice.yml
index e980731..b8c2c66 100644
--- a/seed/nginx-reverse-proxy/applicationservice.yml
+++ b/seed/nginx-reverse-proxy/applicationservice.yml
@@ -1,6 +1,6 @@
format: '0.1'
description: Nginx as reverse proxy
depends:
- - base-fedora-35
+ - base-fedora-36
- nginx-common
provider: ReverseProxy
diff --git a/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml b/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml
index dd65443..3572c6f 100644
--- a/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml
+++ b/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml
@@ -7,6 +7,7 @@
/etc/nginx/conf.d/risotto.conf
nginx_certificate_filename
nginx_private_key_filename
+ /tests/reverse-proxy.yml
diff --git a/seed/nginx-reverse-proxy/extras/nginx/00-nginx.xml b/seed/nginx-reverse-proxy/extras/nginx/00-nginx.xml
index 96f1a93..8c37ebb 100644
--- a/seed/nginx-reverse-proxy/extras/nginx/00-nginx.xml
+++ b/seed/nginx-reverse-proxy/extras/nginx/00-nginx.xml
@@ -5,11 +5,11 @@
False
-
-
-
-
-
+
+
+
+
+
diff --git a/seed/nginx-reverse-proxy/templates/nginx.service b/seed/nginx-reverse-proxy/templates/nginx.service
index 3176d6d..db75ec1 100644
--- a/seed/nginx-reverse-proxy/templates/nginx.service
+++ b/seed/nginx-reverse-proxy/templates/nginx.service
@@ -1,12 +1,14 @@
-%set %%domains = []
+%set %%domains = set()
%for %%domainname in %%revprox_domainnames_all
%set %%family = %%normalize_family(%%domainname)
%set %%revprox = %%nginx['reverse_proxy_for_' + family]['reverse_proxy_' + family]
%for %%location in %%revprox['revprox_location_' + family]
%set %%domain = %%location['revprox_url_' + family].split('/', 3)[2].split(':')[0]
-%%domains.append(%%domain)%slurp
+%%domains.add(%%domain)%slurp
%end for
%end for
+%set %%domains = %%list(%%domains)
+%%domains.sort()
%if %%domains
%set %%domains_str = " ".join(%%domains)
[Service]
diff --git a/seed/nginx-reverse-proxy/templates/reverse-proxy.yml b/seed/nginx-reverse-proxy/templates/reverse-proxy.yml
new file mode 100644
index 0000000..c4dbdce
--- /dev/null
+++ b/seed/nginx-reverse-proxy/templates/reverse-proxy.yml
@@ -0,0 +1,10 @@
+address: %%ip_eth0
+urls:
+%for %%domain in %%revprox_domainnames_all
+ %set %%suffix = %%normalize_family(%%domain)
+ %for %%location in %%nginx['reverse_proxy_for_' + %%suffix]['reverse_proxy_' + %%suffix]['revprox_location_' + %%suffix]
+ %if not %%location['revprox_is_websocket_' + %%suffix]
+- %%domain%%location
+ %end if
+ %end for
+%end for
diff --git a/seed/nginx-reverse-proxy/tests/test_revprox.py b/seed/nginx-reverse-proxy/tests/test_revprox.py
new file mode 100644
index 0000000..ea50b26
--- /dev/null
+++ b/seed/nginx-reverse-proxy/tests/test_revprox.py
@@ -0,0 +1,47 @@
+from yaml import load, SafeLoader
+from os import environ
+
+import warnings
+import socket
+from requests import get
+from requests.exceptions import SSLError
+
+
+def req(url, ip, verify=True):
+ # Monkey patch to force IPv4 resolution
+ old_getaddrinfo = socket.getaddrinfo
+ def new_getaddrinfo(*args, **kwargs):
+ ret = old_getaddrinfo(*args, **kwargs)
+ dns = list(ret[0])
+ dns[-1] = (ip, dns[-1][1])
+ return [dns]
+ socket.getaddrinfo = new_getaddrinfo
+ ret = get(url, verify=verify)
+ ret_code = ret.status_code
+ content = ret.content
+ socket.getaddrinfo = old_getaddrinfo
+ return ret_code, content.decode()
+
+
+def test_revprox():
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/reverse-proxy.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
+ # test unknown domain
+ url = 'google.fr'
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ ret_code, content = req(f'https://{url}', data['address'], verify=False)
+ assert ret_code == 200, f'https://{url} do not returns code 200 but {ret_code}'
+ assert "Test Page for the HTTP Server on Fedora" in content, f'https://{url} returns default fedora page'
+ # test certificate
+ try:
+ req(f'https://{url}', data['address'])
+ raise Exception(f'not certificat problem for https://{url}')
+ except SSLError:
+ pass
+ # test known domains
+ for url in data['urls']:
+ ret_code, content = req(f'https://{url}', data['address'])
+ assert ret_code == 200, f'https://{url} do not returns code 200 but {ret_code}'
+ assert "Test Page for the HTTP Server on Fedora" not in content, f'https://{url} returns default fedora page'
diff --git a/seed/nsd/dictionaries/20_nsd.xml b/seed/nsd/dictionaries/20_nsd.xml
index 52800f0..19ee622 100644
--- a/seed/nsd/dictionaries/20_nsd.xml
+++ b/seed/nsd/dictionaries/20_nsd.xml
@@ -17,9 +17,7 @@
-
- 127.0.0.1
-
+
@@ -47,6 +45,10 @@
ExternalDNS
nsd_resolver
+
+ ip_eth0
+ ip_dns
+
ip_eth
nsd_allowed_client
@@ -56,7 +58,7 @@
nsd_resolver
authorities
- ip_eth0
+ domain_name_eth0
ip
0
nsd_resolve_ip
@@ -64,14 +66,14 @@
nsd_resolver
authorities
- ip_eth0
+ domain_name_eth0
authority_zones
nsd_zones_all
nsd_resolver
authorities
- ip_eth0
+ domain_name_eth0
authority_zones
nsd_reverse_reverse_name
diff --git a/seed/nsd/tests/test_dns.py b/seed/nsd/tests/test_dns.py
index 2eca07c..0eadf3f 100644
--- a/seed/nsd/tests/test_dns.py
+++ b/seed/nsd/tests/test_dns.py
@@ -1,14 +1,20 @@
# DNSSEC : https://github.com/wubo1994/DNS-resolver-in-python3/blob/master/dnssec.py
-from yaml import loads
+# python3-pytest python3-yaml
+from yaml import load, SafeLoader
from dns.resolver import Resolver
+from os import environ
def test_nsd():
- data = loads('./nsd.yml')
+ if 'MACHINE_TEST_DIR' not in environ:
+ return
+ conf_file = f'{environ["MACHINE_TEST_DIR"]}/nsd.yml'
+ with open(conf_file) as yaml:
+ data = load(yaml, Loader=SafeLoader)
resolver = Resolver()
resolver.nameservers = [data['address']]
for dns, ip in data['records'].items():
records = resolver.resolve(dns, 'A')
ips = [record.address for record in records]
assert len(ips) == 1, f"le domaine {dns} n'a pas qu'une ip {ips}"
- assert ips[0] == ip, f"l'IP du domaine {dns} n'est pas correct, attendu : {ip}, obtenu {ips[0}}"
+ assert ips[0] == ip, f"l'IP du domaine {dns} n'est pas correct, attendu : {ip}, obtenu {ips[0]}"
diff --git a/seed/peertube/applicationservice.yml b/seed/peertube/applicationservice.yml
index b04cca1..6ae8b4b 100644
--- a/seed/peertube/applicationservice.yml
+++ b/seed/peertube/applicationservice.yml
@@ -2,6 +2,7 @@ format: '0.1'
description: Peertube
depends:
- base-fedora-36
+ - dns-external
- postgresql-client
- relay-mail-client
- reverse-proxy-client
diff --git a/seed/peertube/dictionaries/30_peertube.xml b/seed/peertube/dictionaries/30_peertube.xml
index b250e06..47aa548 100644
--- a/seed/peertube/dictionaries/30_peertube.xml
+++ b/seed/peertube/dictionaries/30_peertube.xml
@@ -11,7 +11,9 @@
-
+
+ 443
+
@@ -54,11 +56,6 @@
-
- zone_name_eth0
- ExternalDNS
- dns_client_address
-
revprox_client_external_domainnames
revprox_client_location
diff --git a/seed/postfix-relay/applicationservice.yml b/seed/postfix-relay/applicationservice.yml
index 3356451..88aa472 100644
--- a/seed/postfix-relay/applicationservice.yml
+++ b/seed/postfix-relay/applicationservice.yml
@@ -2,4 +2,5 @@ format: '0.1'
description: Postfix has relay
depends:
- base-fedora-35
+ - dns-external
provider: SMTP
diff --git a/seed/postfix-relay/dictionaries/30_postfix.xml b/seed/postfix-relay/dictionaries/30_postfix.xml
index c7c0388..57230e0 100644
--- a/seed/postfix-relay/dictionaries/30_postfix.xml
+++ b/seed/postfix-relay/dictionaries/30_postfix.xml
@@ -33,7 +33,6 @@
-
25
@@ -56,11 +55,6 @@
-
- zone_name_eth0
- ExternalDNS
- dns_client_address
-
/etc/opendkim/keys/
postfix_relay_domains
diff --git a/seed/unbound/applicationservice.yml b/seed/unbound/applicationservice.yml
index 4229402..1e21e9a 100644
--- a/seed/unbound/applicationservice.yml
+++ b/seed/unbound/applicationservice.yml
@@ -2,5 +2,6 @@ format: '0.1'
description: Configuration du serveur DNS unbound
service: true
depends:
- - base-fedora-35
+ - base-fedora-36
+ - dns-external
provider: ExternalDNS
diff --git a/seed/unbound/templates/risotto.conf b/seed/unbound/templates/risotto.conf
index 9032e98..8540752 100644
--- a/seed/unbound/templates/risotto.conf
+++ b/seed/unbound/templates/risotto.conf
@@ -21,7 +21,7 @@ remote-control:
%for %%zone in %%authority.unbound_forward_zones
forward-zone:
name: "%%zone"
- forward-addr: %%authority
+ forward-addr: %%get_ip(%%str(%%authority))
%end for
%end for
diff --git a/seed/vaultwarden/dictionaries/40_vaultwarden.xml b/seed/vaultwarden/dictionaries/40_vaultwarden.xml
index 3bf7973..aeab9bc 100644
--- a/seed/vaultwarden/dictionaries/40_vaultwarden.xml
+++ b/seed/vaultwarden/dictionaries/40_vaultwarden.xml
@@ -14,7 +14,7 @@
/
/notifications/hub
- /notifications/hub/negotiate
+