diff --git a/seed/base-machine/manual/install/diff.py b/seed/base-machine/manual/install/diff.py index 510dcc5d..b2030863 100755 --- a/seed/base-machine/manual/install/diff.py +++ b/seed/base-machine/manual/install/diff.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 -from os.path import join from filecmp import dircmp from difflib import unified_diff from sys import stdout, argv from os import walk -from os.path import join +from os.path import join, islink from datetime import datetime, timezone @@ -87,10 +86,13 @@ for filename in old - new: for filename in new - old: - print(f'\n- fichier {filename} ajouté :\n') - with open(join(NEW_DIR, filename), 'r') as fh: - if WEBSITE: - print('```') - print(fh.read()) - if WEBSITE: - print('```') + if islink(join(NEW_DIR, filename)): + print(f'\n- lien {filename} ajouté\n') + else: + print(f'\n- fichier {filename} ajouté :\n') + with open(join(NEW_DIR, filename), 'r') as fh: + if WEBSITE: + print('```') + print(fh.read()) + if WEBSITE: + print('```') diff --git a/seed/base-machine/manual/install/install_machines b/seed/base-machine/manual/install/install_machines index f053a5f4..82388f32 100755 --- a/seed/base-machine/manual/install/install_machines +++ b/seed/base-machine/manual/install/install_machines @@ -14,7 +14,7 @@ for image in *; do if [ -f "host/configurations/$HOST_NAME/etc/systemd/nspawn/$osname.nspawn" ]; then MACHINES="$MACHINES$osname " fi - echo + echo echo "Install machine $image" ./install_machine "$HOST_NAME" "$image" "$osname" fi @@ -23,5 +23,39 @@ for image in *; do done machinectl enable $MACHINES machinectl start $MACHINES +STARTED="" +DEGRADED="" +found=true +idx=0 +while [ $found = true ]; do + found=false + echo "tentative $idx" + for machine in $MACHINES; do + if ! echo $STARTED | grep -q " $machine "; then + status=$(machinectl -q shell $machine /usr/bin/systemctl is-system-running || true) + if echo "$status" | grep -q degraded; then + STARTED="$STARTED $machine " + DEGRADED="$DEGRADED $machine" + elif echo "$status" | grep -q running; then + STARTED="$STARTED $machine " + else + found=true + echo "status actuel de $machine : $status" + fi + fi + done + sleep 2 + idx=$((idx+1)) + if [ $idx = 60 ]; then + break + fi +done +retcode=0 +for machine in $DEGRADED; do + echo + echo "========= $machine" + machinectl -q shell $machine /usr/bin/systemctl --state=failed --no-legend --no-pager + retcode=1 +done -exit 0 +exit $retcode diff --git a/seed/base-machine/tests/execute.py b/seed/base-machine/tests/execute.py index 7b9cb08b..76747d75 100644 --- a/seed/base-machine/tests/execute.py +++ b/seed/base-machine/tests/execute.py @@ -2,12 +2,14 @@ from os import fdopen from dbus import SystemBus, Array -def run(host, cmd): +def run(host, cmd, user=None): bus = SystemBus() remote_object = bus.get_object('org.freedesktop.machine1', '/org/freedesktop/machine1', False, ) + if user is not None: + cmd = ['/bin/su', '-', user, '-s', '/bin/bash', '-c', ' '.join(cmd)] res = remote_object.OpenMachineShell(host, '', cmd[0], diff --git a/seed/dovecot/dictionaries/26_dovecot.xml b/seed/dovecot/dictionaries/26_dovecot.xml index 05e555eb..89a55027 100644 --- a/seed/dovecot/dictionaries/26_dovecot.xml +++ b/seed/dovecot/dictionaries/26_dovecot.xml @@ -18,7 +18,7 @@ - /etc/nginx/conf.d/autoconfig.conf + /etc/nginx/default.d/autoconfig.conf well_known_filenames @@ -90,8 +90,8 @@ - - False + + /var/www/html diff --git a/seed/dovecot/templates/autoconfig.conf b/seed/dovecot/templates/autoconfig.conf index 8be4082e..c4faeebb 100644 --- a/seed/dovecot/templates/autoconfig.conf +++ b/seed/dovecot/templates/autoconfig.conf @@ -1,12 +1,2 @@ -server { - listen 443 ssl; - server_name %%domain_name_eth0; - - ssl_client_certificate %%revprox_ca_file; - ssl_certificate %%revprox_cert_file; - ssl_certificate_key %%revprox_key_file; - - root /var/www/html/; - # To allow POST on static pages - error_page 405 =200 $uri; -} +# To allow POST on static pages +error_page 405 =200 $uri; diff --git a/seed/dovecot/templates/dovecot-init.service b/seed/dovecot/templates/dovecot-init.service index b4f9cecd..1df2ef4f 100644 --- a/seed/dovecot/templates/dovecot-init.service +++ b/seed/dovecot/templates/dovecot-init.service @@ -1,5 +1,5 @@ [Unit] -After=network.target +After=risotto.target [Service] ExecStart= diff --git a/seed/gitea/templates/gitea.service b/seed/gitea/templates/gitea.service index 9f19bf7b..abb4929c 100644 --- a/seed/gitea/templates/gitea.service +++ b/seed/gitea/templates/gitea.service @@ -1,7 +1,7 @@ #ORIGIN https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/systemd/gitea.service [Unit] Description=Gitea (Git with a cup of tea) -After=network.target postgresqlclient.service +After=risotto.target [Service] # Modify these two values and uncomment them if you have diff --git a/seed/ldap-client/dictionaries/21_ldap-client.xml b/seed/ldap-client/dictionaries/21_ldap-client.xml index ac1ce2f4..b0835e48 100644 --- a/seed/ldap-client/dictionaries/21_ldap-client.xml +++ b/seed/ldap-client/dictionaries/21_ldap-client.xml @@ -2,7 +2,7 @@ - + ldap_client_file ldap_ca_file ldap_cert_file diff --git a/seed/ldap-client/templates/ldap-client.service b/seed/ldap-client/templates/ldap-client.service new file mode 100644 index 00000000..6cbf68c8 --- /dev/null +++ b/seed/ldap-client/templates/ldap-client.service @@ -0,0 +1,8 @@ +[Unit] +After=network-online.target +Before=risotto.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/timeout 90 bash -c 'while ! 3<> /dev/tcp/%%ldap_server_address/%%ldap_port; do sleep 1; done' + diff --git a/seed/lemonldap/dictionaries/70_lemonldap_ng.xml b/seed/lemonldap/dictionaries/70_lemonldap_ng.xml index 37b7de86..d5b9eea9 100644 --- a/seed/lemonldap/dictionaries/70_lemonldap_ng.xml +++ b/seed/lemonldap/dictionaries/70_lemonldap_ng.xml @@ -25,10 +25,10 @@ + diff --git a/seed/lemonldap/templates/lemonldap-ng-fastcgi-server.service b/seed/lemonldap/templates/lemonldap-ng-fastcgi-server.service index f61277e7..adbfcf36 100644 --- a/seed/lemonldap/templates/lemonldap-ng-fastcgi-server.service +++ b/seed/lemonldap/templates/lemonldap-ng-fastcgi-server.service @@ -1,7 +1,6 @@ [Unit] -After=nginx.service +After=risotto.target nginx.service [Service] -ExecStartPre=/usr/bin/timeout 90 bash -c 'while ! 3<> /dev/tcp/%%ldap_server_address/%%ldap_port; do sleep 1; done' ExecStartPost=-/usr/bin/timeout 10 bash -c 'while ! /usr/local/lib/sbin/interne_well_known.pl > /var/www/html/.well-known/openid-configuration/int; do sleep 1; done' ExecStartPost=-/bin/bash -c '/usr/local/lib/sbin/interne_well_known.pl no > /var/www/html/.well-known/openid-configuration/ext' diff --git a/seed/lemonldap/templates/wget.pl b/seed/lemonldap/templates/wget.pl index b46dc4b7..ca4eda78 100644 --- a/seed/lemonldap/templates/wget.pl +++ b/seed/lemonldap/templates/wget.pl @@ -1,7 +1,6 @@ %echo "#!/usr/bin/env perl" use HTTP::Tiny; -use JSON qw(from_json to_json); my $response = HTTP::Tiny->new->get('https://%%domain_name_eth0/.well-known/openid-configuration'); diff --git a/seed/mailman/applicationservice.yml b/seed/mailman/applicationservice.yml index 769c5867..17e1ec58 100644 --- a/seed/mailman/applicationservice.yml +++ b/seed/mailman/applicationservice.yml @@ -5,5 +5,5 @@ depends: - postgresql-client - relay-lmtp-client - reverse-proxy-client - - nginx-common + - nginx-https - oauth2-client diff --git a/seed/mailman/dictionaries/31_mailman.xml b/seed/mailman/dictionaries/31_mailman.xml index b7055029..575e133e 100644 --- a/seed/mailman/dictionaries/31_mailman.xml +++ b/seed/mailman/dictionaries/31_mailman.xml @@ -11,8 +11,9 @@ /etc/postorius/gunicorn_config.py /sysusers.d/0postorius.conf - /etc/nginx/conf.d/postorius.conf + /etc/nginx/default.d/postorius.conf /etc/mailman3.d/postorius.py + /tests/mailman.yml /etc/pki/tls/private/postgresql_postorius.key @@ -47,6 +48,11 @@ + + + /usr/share/webapps/postorius + + mailman diff --git a/seed/mailman/extras/mailman/20_mailman.xml b/seed/mailman/extras/mailman/20_mailman.xml index 97066c77..37e46c9a 100644 --- a/seed/mailman/extras/mailman/20_mailman.xml +++ b/seed/mailman/extras/mailman/20_mailman.xml @@ -3,7 +3,7 @@ - diff --git a/seed/mailman/funcs/mailman.py b/seed/mailman/funcs/mailman.py index 07372bc5..66b633d4 100644 --- a/seed/mailman/funcs/mailman.py +++ b/seed/mailman/funcs/mailman.py @@ -1,20 +1,18 @@ from risotto.utils import multi_function as _multi_function -from itertools import chain -@_multi_function def mailman_emails(lists, domain): - ret = [] - for lst in lists: - for suffix in [None, 'bounces(\+.*)?', 'confirm(\+.*)?', 'join', 'leave', 'owner', 'request', 'subscribe', 'unsubscribe']: - if suffix: - lst_name = lst + '-' + suffix - else: - lst_name = lst - ret.append(lst_name + '@' + domain) - return ret + return '.*@' + domain +# ret = [] +# for lst in lists: +# for suffix in [None, 'bounces(\+.*)?', 'confirm(\+.*)?', 'join', 'leave', 'owner', 'request', 'subscribe', 'unsubscribe']: +# if suffix: +# lst_name = lst + '-' + suffix +# else: +# lst_name = lst +# ret.append(lst_name + '@' + domain) +# return ret @_multi_function def mailman_concat(lists): - # list of lists to a single list - return list(chain(*lists)) + return lists diff --git a/seed/mailman/templates/config-nginx.conf b/seed/mailman/templates/config-nginx.conf index 5c928d74..56b07475 100644 --- a/seed/mailman/templates/config-nginx.conf +++ b/seed/mailman/templates/config-nginx.conf @@ -1,42 +1,31 @@ -server { - listen 443 ssl; - server_name %%domain_name_eth0; - - ssl_client_certificate %%revprox_ca_file; - ssl_certificate %%revprox_cert_file; - ssl_certificate_key %%revprox_key_file; - - charset utf-8; - client_max_body_size 75M; - root /usr/share/webapps/postorius; - - location /mailman/postorius_static { - alias /usr/lib/python3.10/site-packages/postorius/static; - } - #FIXME user-profile seems to be in hyperkitty redirect in existing page - location /mailman/user-profile { - proxy_pass http://127.0.0.1:8002/postorius/users; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -%for %%location in ['accounts', 'admin', 'postorius'] - location /mailman/%%location { - proxy_pass http://127.0.0.1:8002/%%location; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -%end for - location /mailman { - rewrite ^(/mailman/.*)$ /mailman/postorius/ permanent; - } +charset utf-8; +client_max_body_size 75M; +location /mailman/postorius_static { + alias /usr/lib/python3.10/site-packages/postorius/static; +} +#FIXME user-profile seems to be in hyperkitty redirect in existing page +location /mailman/user-profile { + proxy_pass http://127.0.0.1:8002/postorius/users; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +%for %%location in ['accounts', 'admin', 'postorius'] +location /mailman/%%location { + proxy_pass http://127.0.0.1:8002/%%location; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +%end for +location /mailman { + rewrite ^(/mailman/.*)$ /mailman/postorius/ permanent; } diff --git a/seed/mailman/templates/mailman.yml b/seed/mailman/templates/mailman.yml new file mode 100644 index 00000000..2c96daf1 --- /dev/null +++ b/seed/mailman/templates/mailman.yml @@ -0,0 +1,12 @@ +%set %%username="rougail_test@silique.fr" +ip: %%ip_eth0 +revprox_ip: %%revprox_client_server_ip +%set %%domain = %%revprox_client_external_domainnames[0] +domain_name: %%domain +base_url: https://%%domain%%domain.revprox_client_location +auth_url: %%oauth2_client_external[0] +auth_server: %%oauth2_server_domainname +username: %%username +password: %%get_password(server_name='test', username=%%username, description='test', type="cleartext", hide=%%hide_secret, temporary=True) +mailman_domain: %%mailman_domains[0] +internal_address: %%domain_name_eth0 diff --git a/seed/mailman/templates/mailman3.service b/seed/mailman/templates/mailman3.service index 58932c6c..5727c469 100644 --- a/seed/mailman/templates/mailman3.service +++ b/seed/mailman/templates/mailman3.service @@ -1,6 +1,6 @@ [Unit] Description=Postorius WSGI Service -After=postgresqlclient.service +After=risotto.target [Service] %for %%domain in %%mailman_domains diff --git a/seed/mailman/templates/postorius.service b/seed/mailman/templates/postorius.service index 1f29c6c4..83374d6d 100644 --- a/seed/mailman/templates/postorius.service +++ b/seed/mailman/templates/postorius.service @@ -1,6 +1,6 @@ [Unit] Description=Postorius WSGI Service -After=network.target postgresqlclient.service +After=risotto.target [Service] Type=notify diff --git a/seed/mailman/tests/test_mailman.py b/seed/mailman/tests/test_mailman.py new file mode 100644 index 00000000..2b7e899d --- /dev/null +++ b/seed/mailman/tests/test_mailman.py @@ -0,0 +1,396 @@ +from yaml import load, SafeLoader +from os import environ +from os.path import join, isdir +from revprox import Authentication +from execute import run +from re import search +from time import sleep +from imaplib2 import IMAP4_SSL +from smtplib import SMTP +from email import message_from_bytes +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + + +DATA = None +DATA_IMAP = None +IMAP = None +IMAP_FAMILY = None + + +def get_data(): + global DATA + if not DATA: + conf_file = f'{environ["MACHINE_TEST_DIR"]}/mailman.yml' + with open(conf_file) as yaml: + DATA = load(yaml, Loader=SafeLoader) + return DATA + + +def get_imap_data(): + global DATA_IMAP + if not DATA_IMAP: + machine_test_dir = environ['MACHINE_TEST_DIR'] + print("FIXME") + machine_test_dir = machine_test_dir.replace('mailman', 'dovecot') + if not isdir(machine_test_dir): + print('!!! No local IMAP server found !!!') + return + conf_file = f'{machine_test_dir}/imap.yml' + with open(conf_file) as yaml: + DATA_IMAP = load(yaml, Loader=SafeLoader) + return DATA_IMAP + + +def get_authentication(data, family=False): + if family: + username = data['username_family'] + password = data['password_family'] + else: + username = data['username'] + password = data['password'] + return Authentication(data['auth_url'], + data['auth_server'], + data['revprox_ip'], + username, + password, + f""" +Listes - {data["domain_name"]} +""", + ) + + +def check_mail(subject, family=False, reply=False): + global IMAP, IMAP_FAMILY + data = get_imap_data() + if data is None: + return + if family: + if IMAP_FAMILY is None: + IMAP_FAMILY = IMAP4_SSL(data['address']) + IMAP_FAMILY.LOGIN(data['username_family'], data['password_family'] + '2') + imap = IMAP_FAMILY + else: + if IMAP is None: + IMAP = IMAP4_SSL(data['address']) + IMAP.LOGIN(data['username'], data['password']) + imap = IMAP + imap.SELECT(readonly=False) + typ, req = imap.SEARCH(None, 'ALL') + assert typ == 'OK' + if not req[0].decode(): + raise Exception('pas de mail') + num = req[0].decode().split()[-1] + field = imap.FETCH(num, '(RFC822)') + assert field[0] == 'OK' + msg = message_from_bytes(field[1][-2][-1]) + #if msg.is_multipart(): + # for part in msg.walk(): + # # extract content type of email + # try: + # print(part.get_payload(decode=True).decode()) + # except: + # pass + #else: + # print(msg.get_payload(decode=True).decode()) + if subject is not None: + assert subject == msg['Subject'] + if reply: + reply_message(msg) + ret = imap.store(num, '+FLAGS', '\\Deleted') + assert ret[0] == 'OK', f'error when deleting mail: {ret}' + imap.expunge() +# imap.CLOSE() +# imap.LOGOUT() + + +def reply_message(msg): + data = get_imap_data() + body = MIMEText('resend') + message = MIMEMultipart() + message["to"] = msg["From"] + message['from'] = msg["To"] + message['subject'] = f'Re: {msg["Subject"]}' + message.add_header('reply-to', msg["From"]) + message.attach(body) + # + smtp = SMTP(data['address'], '587') + smtp.starttls() + smtp.login(data['username_family'], data['password_family'] + '2') + smtp.sendmail(msg["To"], + msg["From"], + message.as_string(), + ) + smtp.quit() + + +def send_mail(subject, data, data_mm, family=False, add_mail=''): + list_name = 'test' + smtp = SMTP(data['address'], '587') + smtp.starttls() + if not family: + sender = data['username'] + smtp.login(sender, data['password']) + else: + sender = data['username_family'] + smtp.login(sender, data['password_family'] + '2') + list_addr = f'{list_name}{add_mail}@{data_mm["mailman_domain"]}' + msg = f"""From: {sender}\r\n\ +To: {list_addr}\r\n\ +Subject: {subject}\r\n\ +\r\n\ +MESSAGE""" + smtp.sendmail(sender, + list_addr, + msg, + ) + smtp.quit() + + +def test_mailman(): + data = get_data() + get_authentication(data) + + +def test_mailman_login(): + data = get_data() + authentication = get_authentication(data) + content = authentication.get(data['auth_url']) + login = data['username'].split('@')[0] + assert f'Successfully signed in as {login}.' in content + + +def test_mailman_list(): + data = get_data() + authentication = get_authentication(data) + list_name = 'test' + search_list = f'href="/mailman/postorius/lists/{list_name}.{data["mailman_domain"]}/"' + if 'FIRST_RUN' in environ: + content = authentication.get(data['auth_url']) + assert search_list not in content + result = run(data['internal_address'], + ['/usr/bin/mailman3', 'create', '--language', 'fr', '-o', data['username'], '-N', '-d', f'{list_name}@{data["mailman_domain"]}'], + 'mailman', + ) + assert list(result) == [f'Liste de diffusion créée : {list_name}@{data["mailman_domain"]}'] + content = authentication.get(data['auth_url']) + assert search_list in content + + +def test_mailman_inscription(): + data = get_data() + authentication = get_authentication(data) + list_name = 'test' + search_inscription = f'Adresse principale ({data["username"]})' + url = join(data['base_url'], f'postorius/lists/{list_name}.{data["mailman_domain"]}/') + if 'FIRST_RUN' in environ: + content = authentication.get(url) + assert search_inscription not in content + pattern_csrf = r'name="csrfmiddlewaretoken" value="([a-zA-Z0-9\-\_=]+)"' + pattern_sub = r' diff --git a/seed/nginx-common/templates/nginx-common.yml b/seed/nginx-common/templates/nginx-common.yml new file mode 100644 index 00000000..4680042f --- /dev/null +++ b/seed/nginx-common/templates/nginx-common.yml @@ -0,0 +1,13 @@ +address: %%ip_eth0 +nginx_default_http: %slurp +%if %%getVar('nginx_default_http', False) and not %%getVar('revprox_client_external_domainnames', None) +true +%else +false +%end if +nginx_default_https: %slurp +%if %%getVar('nginx_default_https', False) and not %%getVar('revprox_client_external_domainnames', None) +true +%else +false +%end if diff --git a/seed/nginx-common/templates/nginx.conf b/seed/nginx-common/templates/nginx.conf index 758cb4de..b8cf4220 100644 --- a/seed/nginx-common/templates/nginx.conf +++ b/seed/nginx-common/templates/nginx.conf @@ -76,14 +76,24 @@ http { %if %%nginx_default_https server { listen 443 ssl http2; - server_name %%domain_name_eth0; + %if %%getVar('revprox_client_external_domainnames', None) + %for %%domain in %%revprox_client_external_domainnames + server_name %%domain; + %end for + %else + server_name _; + %end if root %%nginx_root; # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; ssl_certificate /etc/pki/tls/certs/nginx.crt; ssl_certificate_key /etc/pki/tls/private/nginx.key; - ssl_client_certificate /etc/pki/ca-trust/source/anchors/ca_InternalReverseProxy.crt; + %if %%getVar('revprox_client_external_domainnames', None) + ssl_client_certificate %%revprox_ca_file; + %else + ssl_client_certificate /etc/pki/ca-trust/source/anchors/ca_HTTP.crt; + %end if ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; @@ -105,5 +115,7 @@ http { %else include /etc/nginx/sites-enabled/*; %end if - +%if not %%getVar('revprox_client_external_domainnames', None) + include /etc/nginx/sites-enabled/*; +%end if } diff --git a/seed/nginx-common/tests/test_nginx_commmon.py b/seed/nginx-common/tests/test_nginx_commmon.py new file mode 100644 index 00000000..efbfc866 --- /dev/null +++ b/seed/nginx-common/tests/test_nginx_commmon.py @@ -0,0 +1,50 @@ +from yaml import load, SafeLoader +from os import environ +from pytest import raises + +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 + if not verify: + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + ret = get(url, verify=verify) + else: + 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"]}/nginx-common.yml' + with open(conf_file) as yaml: + data = load(yaml, Loader=SafeLoader) + # test unknown domain + url = 'google.fr' + protocols = [] + if data['nginx_default_http']: + protocols.append('http') + if data['nginx_default_https']: + protocols.append('https') + # test certificate + with raises(SSLError): + # not certificat problem for https://{url} + req(f'https://{url}', data['address']) + for protocol in protocols: + ret_code, content = req(f'{protocol}://{url}', data['address'], verify=False) + assert ret_code == 200, f'{protocol}://{url} do not returns code 200 but {ret_code}' + assert "Test Page for the HTTP Server on Fedora" in content, f'{protocol}://{url} do not returns default fedora page' diff --git a/seed/nginx-https/dictionaries/25_nginx.xml b/seed/nginx-https/dictionaries/25_nginx.xml index f908f0b5..1f24bfaf 100644 --- a/seed/nginx-https/dictionaries/25_nginx.xml +++ b/seed/nginx-https/dictionaries/25_nginx.xml @@ -1,22 +1,16 @@ - - - /etc/nginx/default.d/risotto.conf - - - + + nginx - - - / - @@ -29,11 +23,4 @@ - - - - nginx_default_risotto - nginx_locations - - diff --git a/seed/nginx-reverse-proxy/dictionaries/20_nginx.xml b/seed/nginx-reverse-proxy/dictionaries/20_nginx.xml new file mode 100644 index 00000000..85ac9c5a --- /dev/null +++ b/seed/nginx-reverse-proxy/dictionaries/20_nginx.xml @@ -0,0 +1,8 @@ + + + + + /etc/pki/ca-trust/source/anchors/ca_HTTP.crt + + + diff --git a/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml b/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml index 3ed3d35b..e4aa3699 100644 --- a/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml +++ b/seed/nginx-reverse-proxy/dictionaries/25_nginx.xml @@ -4,7 +4,7 @@ /etc/nginx/conf.d/options-rp.conf - /etc/nginx/conf.d/risotto.conf + /etc/nginx/sites-enabled/risotto.conf nginx.nginx_certificate_filename nginx.nginx_private_key_filename /tests/reverse-proxy.yml @@ -22,6 +22,9 @@ True + + True + diff --git a/seed/nginx-reverse-proxy/templates/ca_HTTP.crt b/seed/nginx-reverse-proxy/templates/ca_HTTP.crt new file mode 100644 index 00000000..dcbc3aa3 --- /dev/null +++ b/seed/nginx-reverse-proxy/templates/ca_HTTP.crt @@ -0,0 +1,3 @@ +%for %%idx in %%range(%%len(%%zones_list)) +%%get_chain(authority_cn=%%getVar('domain_name_eth' + %%str(%%idx)), authority_name="HTTP", hide=%%hide_secret) +%end for diff --git a/seed/nginx-reverse-proxy/templates/nginx.crt b/seed/nginx-reverse-proxy/templates/nginx.crt new file mode 100644 index 00000000..de2a8a1d --- /dev/null +++ b/seed/nginx-reverse-proxy/templates/nginx.crt @@ -0,0 +1,2 @@ +%%get_certificate(%%nginx_default, authority_cn=%%domain_name_eth0, authority_name='HTTP', type="server", hide=%%hide_secret) +%%get_chain(%%nginx_default, 'HTTP', hide=%%hide_secret) diff --git a/seed/nginx-reverse-proxy/templates/nginx.key b/seed/nginx-reverse-proxy/templates/nginx.key new file mode 100644 index 00000000..4d393c67 --- /dev/null +++ b/seed/nginx-reverse-proxy/templates/nginx.key @@ -0,0 +1 @@ +%%get_private_key(%%nginx_default, authority_cn=%%domain_name_eth0, authority_name='HTTP', type='server', hide=%%hide_secret) diff --git a/seed/nginx-reverse-proxy/templates/revprox-nginx.conf b/seed/nginx-reverse-proxy/templates/revprox-nginx.conf index c1c7ff68..0f48e774 100644 --- a/seed/nginx-reverse-proxy/templates/revprox-nginx.conf +++ b/seed/nginx-reverse-proxy/templates/revprox-nginx.conf @@ -41,7 +41,7 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Destination $dest; %end if - proxy_ssl_trusted_certificate /etc/pki/ca-trust/source/anchors/ca_InternalReverseProxy.crt; + proxy_ssl_trusted_certificate %%revprox_ca_file; proxy_ssl_verify on; proxy_ssl_verify_depth 2; proxy_ssl_session_reuse on; diff --git a/seed/nginx-reverse-proxy/tests/test_revprox.py b/seed/nginx-reverse-proxy/tests/test_revprox.py index d48cc788..592807d8 100644 --- a/seed/nginx-reverse-proxy/tests/test_revprox.py +++ b/seed/nginx-reverse-proxy/tests/test_revprox.py @@ -32,19 +32,8 @@ 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' - 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' + assert "Test Page for the HTTP Server on Fedora" not in content, f'https://{url} do returns default fedora page' diff --git a/seed/nsd/templates/nsd.service b/seed/nsd/templates/nsd.service index 6f45f4ef..f48cf183 100644 --- a/seed/nsd/templates/nsd.service +++ b/seed/nsd/templates/nsd.service @@ -1,2 +1,2 @@ [Unit] -After=network.target +After=risotto.target diff --git a/seed/oauth2-client/dictionaries/30_oauth2_client.xml b/seed/oauth2-client/dictionaries/30_oauth2_client.xml index cc6e415c..80a28a6c 100644 --- a/seed/oauth2-client/dictionaries/30_oauth2_client.xml +++ b/seed/oauth2-client/dictionaries/30_oauth2_client.xml @@ -1,5 +1,8 @@ + + + diff --git a/seed/oauth2-client/manual/image/preinstall/oauth2-client.sh b/seed/oauth2-client/manual/image/preinstall/oauth2-client.sh new file mode 100644 index 00000000..c6335d96 --- /dev/null +++ b/seed/oauth2-client/manual/image/preinstall/oauth2-client.sh @@ -0,0 +1 @@ +PKG="$PKG curl" diff --git a/seed/oauth2-client/templates/oauth2-client.service b/seed/oauth2-client/templates/oauth2-client.service new file mode 100644 index 00000000..c2bb7768 --- /dev/null +++ b/seed/oauth2-client/templates/oauth2-client.service @@ -0,0 +1,7 @@ +[Unit] +After=network-online.target +Before=risotto.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/timeout 90 bash -c 'while ! [ "$(/usr/bin/curl --write-out '%{http_code}' --silent --output /dev/null https://%%oauth2_client_server_domainname/.well-known/openid-configuration)" = 200 ]; do sleep 1; done;' diff --git a/seed/peertube/applicationservice.yml b/seed/peertube/applicationservice.yml index 6ae8b4b7..1aa97aba 100644 --- a/seed/peertube/applicationservice.yml +++ b/seed/peertube/applicationservice.yml @@ -7,5 +7,5 @@ depends: - relay-mail-client - reverse-proxy-client - redis-client - - nginx-common + - nginx-https - oauth2-client diff --git a/seed/peertube/dictionaries/30_peertube.xml b/seed/peertube/dictionaries/30_peertube.xml index 47aa5482..6e627f15 100644 --- a/seed/peertube/dictionaries/30_peertube.xml +++ b/seed/peertube/dictionaries/30_peertube.xml @@ -6,7 +6,8 @@ /sysusers.d/0peertube.conf /tmpfiles.d/0peertube.conf /etc/peertube/production.yaml - /etc/nginx/conf.d/peertube.conf + /etc/nginx/default.d/peertube.conf + /etc/nginx/conf.d/peertube.conf @@ -45,6 +46,9 @@ + + /usr/share/peertube + / diff --git a/seed/peertube/templates/nginx.peertube.conf b/seed/peertube/templates/nginx.peertube.conf index 145eee6f..0f1fcf99 100644 --- a/seed/peertube/templates/nginx.peertube.conf +++ b/seed/peertube/templates/nginx.peertube.conf @@ -16,15 +16,14 @@ # GNUNUX location / { return 301 https://$host$request_uri; } # GNUNUX } -upstream %%domain_name_eth0 { -# GNUNUX server ${PEERTUBE_HOST}; - server localhost:9000; -} +# GNUNUX upstream %%domain_name_eth0 { +# GNUNUX server ${PEERTUBE_HOST}; +# GNUNUX } -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name %%domain_name_eth0; +# GNUNUX server { +# GNUNUX listen 443 ssl http2; +# GNUNUX listen [::]:443 ssl http2; +# GNUNUX server_name %%domain_name_eth0; # GNUNUX access_log /var/log/nginx/peertube.access.log; # reduce I/0 with buffer=10m flush=5m # GNUNUX error_log /var/log/nginx/peertube.error.log; @@ -35,11 +34,6 @@ server { ## # GNUNUX ssl_certificate /etc/letsencrypt/live/${WEBSERVER_HOST}/fullchain.pem; # GNUNUX ssl_certificate_key /etc/letsencrypt/live/${WEBSERVER_HOST}/privkey.pem; -#>GNUNUX - ssl_client_certificate %%revprox_ca_file; - ssl_certificate %%revprox_cert_file; - ssl_certificate_key %%revprox_key_file; -#/etc/piwigo/database.inc.php /sbin/piwigo.sh /etc/php-fpm.d/piwigo.conf + /etc/nginx/default.d/piwigo.conf diff --git a/seed/nginx-https/templates/risotto.conf b/seed/piwigo/templates/piwigo.nginx.conf similarity index 82% rename from seed/nginx-https/templates/risotto.conf rename to seed/piwigo/templates/piwigo.nginx.conf index e7d34a48..1ba02a33 100644 --- a/seed/nginx-https/templates/risotto.conf +++ b/seed/piwigo/templates/piwigo.nginx.conf @@ -1,3 +1,5 @@ +# To allow POST on static pages +error_page 405 =200 $uri; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; @@ -6,18 +8,15 @@ add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none; add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;'; add_header Referrer-Policy no-referrer always; - -%for %%location in %%nginx_locations + +%for %%location in %%piwigo_locations location %%location { -%if %%location == '/' + %if %%location == '/' root %slurp -%else + %else alias %slurp -%end if -%%nginx_root_directory; -%if not %%getVar('php_fpm_installed', False) - index index.html; -%else + %end if + /usr/local/share/piwigo; index index.php; location ~ ^(?.+?\.php)(?/.*)?$ { fastcgi_pass php-fpm; @@ -25,6 +24,5 @@ location %%location { fastcgi_param SCRIPT_FILENAME $request_filename; include fastcgi_params; } -%end if } %end for diff --git a/seed/piwigo/templates/piwigo.service b/seed/piwigo/templates/piwigo.service index e75c1c11..16b5b987 100644 --- a/seed/piwigo/templates/piwigo.service +++ b/seed/piwigo/templates/piwigo.service @@ -1,6 +1,6 @@ [Unit] Description=Piwigo management -After=mariadbclient.service +After=risotto.target Before=nginx.service php-fpm.service [Service] diff --git a/seed/pleroma/dictionaries/30_pleroma.xml b/seed/pleroma/dictionaries/30_pleroma.xml index b457600c..6a6cc7ed 100644 --- a/seed/pleroma/dictionaries/30_pleroma.xml +++ b/seed/pleroma/dictionaries/30_pleroma.xml @@ -7,7 +7,7 @@ /tmpfiles.d/0peertube.conf /etc/peertube/production.yaml /etc/pam.d/login - /etc/nginx/conf.d/peertube.conf + /etc/nginx/sites-enabled/peertube.conf diff --git a/seed/postgresql-client/dictionaries/23_postgresql.xml b/seed/postgresql-client/dictionaries/23_postgresql.xml index 138f7d3f..9afde856 100644 --- a/seed/postgresql-client/dictionaries/23_postgresql.xml +++ b/seed/postgresql-client/dictionaries/23_postgresql.xml @@ -1,7 +1,7 @@ - + /secrets/postgresql.pass /etc/pki/ca-trust/source/anchors/ca_PostgreSQL.crt /etc/pki/tls/certs/postgresql.crt diff --git a/seed/postgresql-client/templates/postgresqlclient.service b/seed/postgresql-client/templates/postgresqlclient.service index 7addde19..fd8b647a 100644 --- a/seed/postgresql-client/templates/postgresqlclient.service +++ b/seed/postgresql-client/templates/postgresqlclient.service @@ -1,6 +1,7 @@ [Unit] Description=Waiting for postgresql server -Before=network.target +After=network-online.target +Before=risotto.target [Service] Type=oneshot diff --git a/seed/postgresql/DEBUG.md b/seed/postgresql/DEBUG.md new file mode 100644 index 00000000..c835ba01 --- /dev/null +++ b/seed/postgresql/DEBUG.md @@ -0,0 +1 @@ +pg_dumpall --clean > /srv/database.sql diff --git a/seed/reverse-proxy-client/tests/revprox.py b/seed/reverse-proxy-client/tests/revprox.py index bb9ab177..134fb4f2 100644 --- a/seed/reverse-proxy-client/tests/revprox.py +++ b/seed/reverse-proxy-client/tests/revprox.py @@ -33,7 +33,7 @@ class Authentication: ret = req.get(url) code = ret.status_code content = ret.content - assert code == 200 + assert code == 200, f"cannot access to lemonldap; {content}" assert b'Authentication portal' in content, f'cannot find LemonLdap title: {content}' def auth_lemonldap(self, @@ -62,7 +62,8 @@ class Authentication: authorize_url = f'{portal_url}authorize' ret = req.get(authorize_url) assert ret.status_code == 200 - assert title in ret.content.decode() + content = ret.content.decode() + assert title in content, f'cannot find {title} in {content}' def get(self, url, @@ -78,7 +79,8 @@ class Authentication: def post(self, url, data, + headers=None, ): with MookDns(self.ip): - ret = post(url, cookies=self.cookies, data=data) + ret = post(url, cookies=self.cookies, data=data, headers=headers) assert ret.status_code == 200, f'return code is {ret.status_code}' diff --git a/seed/roundcube/templates/roundcube.service b/seed/roundcube/templates/roundcube.service index 92913e35..19b462b2 100644 --- a/seed/roundcube/templates/roundcube.service +++ b/seed/roundcube/templates/roundcube.service @@ -1,6 +1,6 @@ [Unit] Description=Roundcube database init -After=postgresqlclient.service +After=risotto.target Before=nginx.service php-fpm.service [Service] diff --git a/seed/systemd/dictionaries/15-systemd.xml b/seed/systemd/dictionaries/15-systemd.xml index 6819b861..deaf2e74 100644 --- a/seed/systemd/dictionaries/15-systemd.xml +++ b/seed/systemd/dictionaries/15-systemd.xml @@ -29,6 +29,7 @@ /secrets/root.pwd /tmpfiles.d/risotto-volatile.conf + diff --git a/seed/systemd/templates/risotto.target b/seed/systemd/templates/risotto.target new file mode 100644 index 00000000..8f4c5e63 --- /dev/null +++ b/seed/systemd/templates/risotto.target @@ -0,0 +1,5 @@ +[Unit] +Description=Waiting for all dependencies +Before=multi-user.target +After=network-online.target +Wants=network-online.target