nsd|unbound|nginx reverse proxy use fedora 36

This commit is contained in:
Emmanuel Garette 2022-07-04 15:44:18 +02:00
parent bd82d4e853
commit 69c3a1c375
31 changed files with 274 additions and 55 deletions

View file

@ -2,3 +2,4 @@ format: '0.1'
description: Base information for a machine
depends:
- base
- dns-local

View file

@ -12,8 +12,6 @@
<family name="network" description="Réseau">
<variable name="zones_list" type="string" multi="True" description="Liste de toutes les zones" hidden="True"/>
<variable name="interfaces_list" type="number" multi="True" description="Liste de tous les numéros d'interfaces" hidden="True"/>
<variable name="dns_client_address" type="domainname" description="Nom de domaine du serveur DNS"/>
<variable name="ip_dns" type="ip" description="Adresse IP du serveur DNS" hidden="True"/>
<family name="interface_" description="Interface " dynamic="interfaces_list">
<variable name="zone_name_eth" type="string" description="Nom de la zone de l'interface " hidden="True"/>
<variable name="ip_eth" type="ip" description="Adresse IP pour l'interface " hidden="True" provider="ip"/>
@ -24,18 +22,6 @@
</family>
</variables>
<constraints>
<fill name="get_provider_name">
<param type="variable">zone_name_eth0</param>
<param>LocalDNS</param>
<target>dns_client_address</target>
</fill>
<fill name="set_linked">
<param name="linked_server" type="variable">dns_client_address</param>
<param name="linked_provider">dns</param>
<param name="linked_value" type="variable">ip_eth0</param>
<param name="linked_returns">ip</param>
<target>ip_dns</target>
</fill>
<fill name="calc_value">
<param type="information">zones_name</param>
<target>zones_list</target>

View file

@ -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;

View file

@ -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

View file

@ -0,0 +1,2 @@
format: '0.1'
description: Configuration du client DNS externe

View file

@ -0,0 +1,18 @@
<?xml version='1.0' encoding='UTF-8'?>
<rougail version="0.10">
<variables>
<family name="network">
<variable name="dns_is_only_local" redefine="True">
<value>False</value>
</variable>
<variable name="dns_client_address" redefine="True"/>
</family>
</variables>
<constraints>
<fill name="get_provider_name">
<param type="variable">zone_name_eth0</param>
<param>ExternalDNS</param>
<target>dns_client_address</target>
</fill>
</constraints>
</rougail>

View file

@ -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}'

View file

@ -0,0 +1,2 @@
format: '0.1'
description: Configuration du client DNS local

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<rougail version="0.10">
<services>
<service name="dns-local" manage="False">
<file>/tests/dns-local.yml</file>
</service>
</services>
<variables>
<family name="network">
<variable name="dns_is_only_local" type="boolean" description="DNS resolve only local address" hidden="True">
<value>True</value>
</variable>
<variable name="dns_client_address" type="domainname" description="Nom de domaine du serveur DNS"/>
<variable name="ip_dns" type="ip" description="Adresse IP du serveur DNS" hidden="True"/>
</family>
</variables>
<constraints>
<fill name="get_provider_name">
<param type="variable">zone_name_eth0</param>
<param>LocalDNS</param>
<target>dns_client_address</target>
</fill>
<fill name="set_linked">
<param name="linked_server" type="variable">dns_client_address</param>
<param name="linked_provider">dns</param>
<param name="linked_value" type="variable">ip_eth0</param>
<param name="linked_returns">ip</param>
<target>ip_dns</target>
</fill>
</constraints>
</rougail>

View file

@ -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

View file

@ -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}'

View file

@ -23,11 +23,14 @@
</services>
<variables>
<variable name="host_install_dir" type="filename" description="Nom du répertoire comprenant les descriptions d'installation" mandatory="True"/>
<variable name="host_dhcp_interface" description="Carte réseau en DHCP" multi="True"/>
<variable name="host_dhcp_filename" type="filename" hidden="True" multi="True"/>
<variable name="host_name" type="domainname" hidden="True"/>
<variable name="systemd_zone_filename" type="filename" hidden="True" multi="True"/>
<variable name="systemd_netzone_filename" type="filename" hidden="True" multi="True"/>
<family name="network">
<variable name="host_dhcp_interface" description="Carte réseau en DHCP" multi="True"/>
<variable name="output_interface" description="Nom de l'interface de sortie" mandatory="True"/>
</family>
<family name="zones" leadership="True">
<variable name="zone_name" type="string" hidden="True" multi="True"/>
<variable name="zone_cidr" type="cidr" hidden="True"/>

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
format: '0.1'
description: Let's encrypt
depends:
- base-fedora-35
- base-fedora

View file

@ -70,7 +70,7 @@
<param type="variable">revprox_client_external_domainnames</param>
<target>nextcloud_well_known_server</target>
</fill>
<check name="set_linked_multi_variables">
<!-- FIXME : check name="set_linked_multi_variables">
<param name="linked_provider_0">revprox_clients</param>
<param name="linked_value_0" type="variable">nextcloud_well_known_server</param>
<param name="linked_provider_1">revprox_location</param>
@ -80,14 +80,14 @@
<param name="linked_provider_3">revprox_url</param>
<param name="linked_value_3" type="variable">nextcloud_well_known_caldav</param>
<target>revprox_client_server_domainname</target>
</check>
</check-->
<fill name="calc_web_address">
<param type="variable">domain_name_eth0</param>
<param type="variable">revprox_client_port</param>
<param>/.well-known/caldav</param>
<target>nextcloud_well_known_caldav</target>
</fill>
<check name="set_linked_multi_variables">
<!-- FIXME : check name="set_linked_multi_variables">
<param name="linked_provider_0">revprox_clients</param>
<param name="linked_value_0" type="variable">nextcloud_well_known_server</param>
<param name="linked_provider_1">revprox_location</param>
@ -97,7 +97,7 @@
<param name="linked_provider_3">revprox_url</param>
<param name="linked_value_3" type="variable">nextcloud_well_known_carddav</param>
<target>revprox_client_server_domainname</target>
</check>
</check-->
<fill name="calc_web_address">
<param type="variable">domain_name_eth0</param>
<param type="variable">revprox_client_port</param>

View file

@ -1,6 +1,6 @@
format: '0.1'
description: Nginx as reverse proxy
depends:
- base-fedora-35
- base-fedora-36
- nginx-common
provider: ReverseProxy

View file

@ -7,6 +7,7 @@
<file source="revprox-nginx.conf">/etc/nginx/conf.d/risotto.conf</file>
<file source="certificate.crt" file_type="variable" mode="600" variable="revprox_domainnames_all">nginx_certificate_filename</file>
<file source="private.key" file_type="variable" mode="600" variable="revprox_domainnames_all">nginx_private_key_filename</file>
<file>/tests/reverse-proxy.yml</file>
</service>
</services>
<variables>

View file

@ -6,10 +6,10 @@
<value>False</value>
</variable>
<family name="reverse_proxy_" description="Reverse proxy " help="Paramètrage du proxy inverse" leadership="True">
<variable name="revprox_location_" type="filename" description="Répertoire ou nom de la page à rediriger" help="URL relative (sans le nom de domaine) redirigée pour l'adresse définie dans la variable ci-dessus (exemple &quot;/mail&quot;)" mandatory="True" multi="True" provider="revprox_location"/>
<variable name="revprox_url_" type="web_address" description="Domaine de destination ou URI complète" mandatory="True" help="Nom de domaine ou IP de destination, par exemple &quot;http://domainelocal&quot; ou URI, par exemple &quot;http://domainelocal/dir/&quot;" provider="revprox_url"/>
<variable name="revprox_is_websocket_" type="boolean" description="Le point d'entré est de types websocket" mandatory="True" provider="revprox_is_websocket"/>
<variable name="revprox_max_body_size_" description="Taille maximum du corps" provider="revprox_max_body_size"/>
<variable name="revprox_location_" type="filename" description="Répertoire ou nom de la page à rediriger pour " help="URL relative (sans le nom de domaine) redirigée pour l'adresse définie dans la variable ci-dessus (exemple &quot;/mail&quot;)" mandatory="True" multi="True" provider="revprox_location"/>
<variable name="revprox_url_" type="web_address" description="Domaine de destination ou URI complète pour " mandatory="True" help="Nom de domaine ou IP de destination, par exemple &quot;http://domainelocal&quot; ou URI, par exemple &quot;http://domainelocal/dir/&quot;" provider="revprox_url"/>
<variable name="revprox_is_websocket_" type="boolean" description="Le point d'entré est de types websocket pour " mandatory="True" provider="revprox_is_websocket"/>
<variable name="revprox_max_body_size_" description="Taille maximum du corps pour " provider="revprox_max_body_size"/>
</family>
</family>
</variables>

View file

@ -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]

View file

@ -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

View file

@ -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 "<title>Test Page for the HTTP Server on Fedora</title>" 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 "<title>Test Page for the HTTP Server on Fedora</title>" not in content, f'https://{url} returns default fedora page'

View file

@ -17,9 +17,7 @@
<variables>
<family name="network">
<variable name="dns_client_address" redefine="True" disabled="True"/>
<variable name="ip_dns" redefine="True" remove_fill="True">
<value>127.0.0.1</value>
</variable>
<variable name="ip_dns" redefine="True" remove_fill="True"/>
</family>
<family name="dns_server" description="Serveur DNS">
<variable name="nsd_allowed_client" type="ip" description="Clients" multi="True" mandatory="True" hidden="True" provider="dns"/>
@ -47,6 +45,10 @@
<param>ExternalDNS</param>
<target>nsd_resolver</target>
</fill>
<fill name="calc_value">
<param type="variable">ip_eth0</param>
<target>ip_dns</target>
</fill>
<fill name="nsd_concat_lists">
<param type="variable">ip_eth</param>
<param type="variable">nsd_allowed_client</param>
@ -56,7 +58,7 @@
<fill name="set_linked">
<param name="linked_server" type="variable">nsd_resolver</param>
<param name="linked_provider">authorities</param>
<param name="linked_value" type="variable">ip_eth0</param>
<param name="linked_value" type="variable">domain_name_eth0</param>
<param name="linked_returns">ip</param>
<param name="dynamic">0</param>
<target>nsd_resolve_ip</target>
@ -64,14 +66,14 @@
<check name="set_linked_configuration">
<param name="linked_server" type="variable">nsd_resolver</param>
<param name="leader_provider">authorities</param>
<param name="leader_value" type="variable">ip_eth0</param>
<param name="leader_value" type="variable">domain_name_eth0</param>
<param name="linked_provider">authority_zones</param>
<target>nsd_zones_all</target>
</check>
<check name="set_linked_configuration">
<param name="linked_server" type="variable">nsd_resolver</param>
<param name="leader_provider">authorities</param>
<param name="leader_value" type="variable">ip_eth0</param>
<param name="leader_value" type="variable">domain_name_eth0</param>
<param name="linked_provider">authority_zones</param>
<target>nsd_reverse_reverse_name</target>
</check>

View file

@ -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]}"

View file

@ -2,6 +2,7 @@ format: '0.1'
description: Peertube
depends:
- base-fedora-36
- dns-external
- postgresql-client
- relay-mail-client
- reverse-proxy-client

View file

@ -11,7 +11,9 @@
</services>
<variables>
<family name="network">
<variable name="dns_client_address" redefine="True"/>
<variable name="outgoing_ports" redefine="True">
<value>443</value>
</variable>
</family>
<family name="peertube">
<variable name="peertube_admin_email" type="mail" description="Adresse courriel de l'administrateur Peertube" mandatory="True"/>
@ -54,11 +56,6 @@
</family>
</variables>
<constraints>
<fill name="get_provider_name">
<param type="variable">zone_name_eth0</param>
<param>ExternalDNS</param>
<target>dns_client_address</target>
</fill>
<fill name="calc_oauth2_client_external">
<param type="variable">revprox_client_external_domainnames</param>
<param type="variable">revprox_client_location</param>

View file

@ -2,4 +2,5 @@ format: '0.1'
description: Postfix has relay
depends:
- base-fedora-35
- dns-external
provider: SMTP

View file

@ -33,7 +33,6 @@
</services>
<variables>
<family name="network">
<variable name="dns_client_address" redefine="True"/>
<variable name="outgoing_ports" redefine="True">
<value>25</value>
</variable>
@ -56,11 +55,6 @@
</family>
</variables>
<constraints>
<fill name="get_provider_name">
<param type="variable">zone_name_eth0</param>
<param>ExternalDNS</param>
<target>dns_client_address</target>
</fill>
<fill name="calc_value">
<param>/etc/opendkim/keys/</param>
<param type="variable">postfix_relay_domains</param>

View file

@ -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

View file

@ -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

View file

@ -14,7 +14,7 @@
<variable name="revprox_client_location" redefine="True">
<value>/</value>
<value>/notifications/hub</value>
<value>/notifications/hub/negotiate</value>
<!-- FIXME : value>/notifications/hub/negotiate</value-->
</variable>
</family>
<variable name="revprox_client_cert_owner" redefine="True" hidden="True">