diff options
26 files changed, 846 insertions, 91 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a9b9b64 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "webmap-tools"] + path = webmap-tools + url = https://git.guilhem.org/KlimatanalysNorr/tools.git diff --git a/ansible.cfg b/ansible.cfg index a35402e..cf64db8 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,5 +1,6 @@ [defaults] inventory = ./hosts.ini +max_diff_size = 524288 [privilege_escalation] become = True diff --git a/files/etc/nginx/sites-available/webmap b/files/etc/nginx/sites-available/webmap new file mode 100644 index 0000000..24ccdb9 --- /dev/null +++ b/files/etc/nginx/sites-available/webmap @@ -0,0 +1,124 @@ +server { + listen 80; + listen [::]:80; + + server_name karta.klimatanalysnorr.se hel01.guilhem.se; + + include /etc/lacme/nginx.conf; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log warn; + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443; + listen [::]:443; + + server_name hel01.guilhem.se; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log warn; + + ssl_certificate /etc/nginx/ssl/webmap.rsa.pem; + ssl_certificate_key /etc/nginx/ssl/webmap.rsa.key; + include snippets/ssl.conf; + + location / { + return 303 https://karta.klimatanalysnorr.se$request_uri; + } +} + +server { + listen 443 ssl http2 default_server; + listen [::]:443 ssl http2 default_server; + + server_name karta.klimatanalysnorr.se; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log warn; + + ssl_certificate /etc/nginx/ssl/webmap.rsa.pem; + ssl_certificate_key /etc/nginx/ssl/webmap.rsa.key; + include snippets/ssl.conf; + + root /var/www/webmap; + index index.html; + + add_header Referrer-Policy "no-referrer"; + add_header X-Frame-Options "DENY"; + add_header X-Content-Type-Options "nosniff"; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always; + add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; form-action 'none'; base-uri 'self'"; + #add_header Access-Control-Allow-Origin $http_origin always; + + include mime.types; + types { + # application/protobuf and application/vnd.google.protobuf might be valid types too, cf. + # https://stackoverflow.com/questions/30505408/what-is-the-correct-protobuf-content-type + application/x-protobuf pbf; + } + + location ^~ /assets/ { + expires 7d; + try_files $uri =404; + location ~ "\.(?:css|js|svg)$" { + brotli_static on; + } + } + location ^~ /tiles/ { + expires 30m; + brotli_static on; + try_files $uri =404; + # service an empty payload to save bandwidth + error_page 404 /_.txt; + } + location ^~ /raster/ { + expires 30m; + try_files $uri =404; + # service an empty payload to save bandwidth + error_page 404 /_.txt; + } + location = /q { + expires epoch; + limit_except POST { deny all; } + #if ($request_method = OPTIONS) { + # add_header Strict-Transport-Security "max-age=31557600; includeSubDomains"; + # add_header Access-Control-Allow-Origin $http_origin; + # add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; + # add_header Access-Control-Allow-Headers "Accept, Content-Type"; + # add_header Access-Control-Max-Age 28800; + # return 204; + #} + client_max_body_size 64k; + gzip on; + gzip_types application/json text/plain; + include uwsgi_params; + uwsgi_pass unix:/run/webmap-cgi.socket; + } + + location = /_.txt { + # cache 404 responses for 30m like for valid tiles + add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always; + add_header Cache-Control "public; max-age=1800" always; + #add_header Access-Control-Allow-Origin $http_origin always; + internal; + } + + location / { + add_header Referrer-Policy "no-referrer"; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always; + add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self' data: https://minkarta.lantmateriet.se/map/; script-src 'self'; style-src 'self'; frame-ancestors 'self'; form-action 'none'; worker-src blob:; base-uri 'self'"; + + expires 1h; + brotli_static on; + try_files $uri $uri/ =404; + } +} diff --git a/files/etc/nginx/sites-enabled/webmap b/files/etc/nginx/sites-enabled/webmap deleted file mode 100644 index d16ab60..0000000 --- a/files/etc/nginx/sites-enabled/webmap +++ /dev/null @@ -1,80 +0,0 @@ -server { - listen 80; - listen [::]:80; - - server_name karta.klimatanalysnorr.se hel01.guilhem.se; - - include /etc/lacme/nginx.conf; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log warn; - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443; - listen [::]:443; - - server_name hel01.guilhem.se; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log warn; - - ssl_certificate /etc/nginx/ssl/webmap.rsa.pem; - ssl_certificate_key /etc/nginx/ssl/webmap.rsa.key; - include snippets/ssl.conf; - - location / { - return 303 https://karta.klimatanalysnorr.se$request_uri; - } -} - -server { - listen 443 ssl http2 default_server; - listen [::]:443 ssl http2 default_server; - - server_name karta.klimatanalysnorr.se; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log warn; - - ssl_certificate /etc/nginx/ssl/webmap.rsa.pem; - ssl_certificate_key /etc/nginx/ssl/webmap.rsa.key; - include snippets/ssl.conf; - - add_header Referrer-Policy "no-referrer"; - add_header X-Frame-Options "SAMEORIGIN"; - add_header X-Content-Type-Options "nosniff"; - add_header X-XSS-Protection "1; mode=block"; - add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always; - add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self' data: https://minkarta.lantmateriet.se/map/; script-src 'self'; style-src 'self'; frame-ancestors 'self'; form-action 'none'; base-uri 'self'"; - - root /var/www/webmap; - index index.html; - - location ^~ /assets/ { - expires 7d; - gzip_static on; - try_files $uri =404; - } - location ^~ /tiles/ { - expires 1d; - gzip_static on; - try_files $uri =404; - error_page 404 /_.txt; - } - - location = /_.txt { - # cache 404 responses - add_header Strict-Transport-Security "max-age=31557600; includeSubDomains" always; - add_header Cache-Control "public; max-age=86400" always; - internal; - } - - location / { - try_files $uri $uri/ =404; - } -} diff --git a/files/etc/postfix/master.cf b/files/etc/postfix/master.cf new file mode 100644 index 0000000..3c60f31 --- /dev/null +++ b/files/etc/postfix/master.cf @@ -0,0 +1,44 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master" or +# on-line: http://www.postfix.org/master.5.html). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (no) (never) (100) +# ========================================================================== +smtp inet n - y - - smtpd +pickup unix n - y 60 1 pickup +cleanup unix n - y - 0 cleanup +qmgr unix n - n 300 1 qmgr +tlsmgr unix - - y 1000? 1 tlsmgr +rewrite unix - - y - - trivial-rewrite +bounce unix - - y - 0 bounce +defer unix - - y - 0 bounce +trace unix - - y - 0 bounce +verify unix - - y - 1 verify +flush unix n - y 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - y - - smtp +relay unix - - y - - smtp + -o syslog_name=postfix/$service_name +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 + -o smtp_tls_security_level=fingerprint +relay-smtps unix - - y - - smtp + -o syslog_name=postfix/$service_name +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 + -o smtp_tls_wrappermode=yes + -o smtp_tls_security_level=fingerprint +showq unix n - y - - showq +error unix - - y - - error +retry unix - - y - - error +discard unix - - y - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - y - - lmtp +anvil unix - - y - 1 anvil +scache unix - - y - 1 scache +postlog unix-dgram n - n - 1 postlogd diff --git a/files/etc/postfix/tls_policy b/files/etc/postfix/tls_policy index 2af19c5..c5641d3 100644 --- a/files/etc/postfix/tls_policy +++ b/files/etc/postfix/tls_policy @@ -1,3 +1,3 @@ # WARN: smtp_tls_fingerprint_digest MUST be sha256! -[smtp.guilhem.org]:587 fingerprint ciphers=high protocols=!SSLv2:!SSLv3:!TLSv1:!TLSv1.1:!TLSv1.2 +[smtp.guilhem.org]:465 fingerprint ciphers=high protocols=!SSLv2:!SSLv3:!TLSv1:!TLSv1.1:!TLSv1.2 match=B2:37:09:EC:B9:54:DC:51:FA:77:A1:31:0D:30:06:84:7E:10:81:5B:9B:30:B0:31:6E:9A:7B:53:13:C8:37:62 diff --git a/files/etc/postgresql/postgresql.conf b/files/etc/postgresql/postgresql.conf new file mode 100644 index 0000000..038438a --- /dev/null +++ b/files/etc/postgresql/postgresql.conf @@ -0,0 +1,4 @@ +shared_buffers = 768MB +temp_buffers = 128MB +work_mem = 16MB +effective_cache_size = 1536MB diff --git a/files/etc/systemd/system/webmap-cgi.service b/files/etc/systemd/system/webmap-cgi.service new file mode 100644 index 0000000..88f22e5 --- /dev/null +++ b/files/etc/systemd/system/webmap-cgi.service @@ -0,0 +1,36 @@ +[Unit] +Description=Webmap CGI (Common Gateway Interface) +After=syslog.target network.target postgresql.service + +[Service] +DynamicUser=yes +User=_webmap-cgi +# Note: the "WARNING: you have enabled harakiri without post buffering" can +# be ignored because body requests are in fact buffered on the nginx side +ExecStart=/usr/bin/uwsgi -M -p2 \ + --single-interpreter --die-on-term \ + --close-on-exec --close-on-exec2 \ + --max-requests 1000 \ + --max-worker-lifetime 86400 \ + --max-worker-lifetime-delta 11 \ + --harakiri 60 \ + --lazy-apps \ + --plugins python3 \ + --pythonpath /usr/local/share/webmap \ + --wsgi-file /usr/libexec/webmap-cgi +Nice=10 +RestartSec=15s +Restart=always + +# Hardening +NoNewPrivileges=yes +ProtectHome=yes +ProtectSystem=strict +PrivateDevices=yes +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictAddressFamilies=AF_UNIX + +[Install] +WantedBy=multi-user.target diff --git a/files/etc/systemd/system/webmap-cgi.socket b/files/etc/systemd/system/webmap-cgi.socket new file mode 100644 index 0000000..2828985 --- /dev/null +++ b/files/etc/systemd/system/webmap-cgi.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Webmap CGI (Common Gateway Interface) activation socket +After=syslog.target network.target + +[Socket] +ListenStream=%t/webmap-cgi.socket +SocketUser=www-data +SocketMode=0666 + +[Install] +WantedBy=sockets.target diff --git a/files/etc/systemd/system/webmap-download@.service b/files/etc/systemd/system/webmap-download@.service new file mode 100644 index 0000000..d7a49dc --- /dev/null +++ b/files/etc/systemd/system/webmap-download@.service @@ -0,0 +1,37 @@ +[Unit] +Description=Webmap updater service (download ‘%I’) +# Chaining logic from https://serverfault.com/questions/1079993/why-does-my-systemd-timer-only-trigger-once-when-the-unit-is-a-target#answer-1128671 +# XXX Looks like Upholds= prevents running a single unit, as it causes +# webmap-update@%i.target to start upon `systemctl start webmap-download@foo.service` +After=network-online.target webmap-update@%i.target +Upholds=webmap-update@%i.target + +[Service] +User=_webmap-download +Group=_webmap + +Nice=15 +IOSchedulingClass=idle + +Type=oneshot +ExecStart=/usr/local/bin/webmap-download \ + --cachedir=%C/webmap \ + --lockdir=%t/lock/webmap/cache \ + --no-exit-code \ + --quiet \ + -- %I + +# Hardening +NoNewPrivileges=yes +ProtectHome=yes +ProtectSystem=strict +PrivateDevices=yes +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +ReadWritePaths=%C/webmap +ReadWritePaths=%t/lock/webmap/cache + +[Install] +WantedBy=webmap-update@%i.target diff --git a/files/etc/systemd/system/webmap-import@.service b/files/etc/systemd/system/webmap-import@.service new file mode 100644 index 0000000..964c37d --- /dev/null +++ b/files/etc/systemd/system/webmap-import@.service @@ -0,0 +1,37 @@ +[Unit] +Description=Webmap updater service (import ‘%I’ to PostGIS) +After=postgresql.service webmap-update@%i.target +After=webmap-download@%i.service +Upholds=webmap-update@%i.target + +[Service] +User=_webmap +Group=_webmap + +Nice=15 +IOSchedulingClass=idle + +Type=oneshot +ExecStart=/usr/local/bin/webmap-import \ + --cachedir=%C/webmap \ + --lockfile=%t/lock/webmap/lock \ + --lockdir-sources=%t/lock/webmap/cache \ + --mvtdir=/var/www/webmap/tiles/%I \ + --mvt-compress \ + -- %I + +# Hardening +NoNewPrivileges=yes +ProtectHome=yes +ProtectSystem=strict +PrivateDevices=yes +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +ReadWritePaths=%t/lock/webmap +ReadWritePaths=/var/www/webmap/tiles +PrivateTmp=yes + +[Install] +WantedBy=webmap-update@%i.target diff --git a/files/etc/systemd/system/webmap-update@.target b/files/etc/systemd/system/webmap-update@.target new file mode 100644 index 0000000..840de96 --- /dev/null +++ b/files/etc/systemd/system/webmap-update@.target @@ -0,0 +1,3 @@ +[Unit] +Description=Webmap updater (target unit ‘%I’) +StopWhenUnneeded=true diff --git a/files/etc/systemd/system/webmap-update@.timer b/files/etc/systemd/system/webmap-update@.timer new file mode 100644 index 0000000..74fb848 --- /dev/null +++ b/files/etc/systemd/system/webmap-update@.timer @@ -0,0 +1,11 @@ +[Unit] +Description=Webmap updater (timer unit) + +[Timer] +OnCalendar=*-*-* 01:00:00 +AccuracySec=1s +RandomizedDelaySec=3599 +Unit=webmap-update@%i.target + +[Install] +WantedBy=timers.target diff --git a/files/etc/tmpfiles.d/webmap.conf b/files/etc/tmpfiles.d/webmap.conf new file mode 100644 index 0000000..786e6dd --- /dev/null +++ b/files/etc/tmpfiles.d/webmap.conf @@ -0,0 +1,8 @@ +d %t/lock/webmap 00755 root root + +# for `webmap-download --lockdir` *and* `webmap-import --lockdir-sources` +# (hence the set-group-ID bit and g+w) +d %t/lock/webmap/cache 02775 _webmap-download _webmap + +# for `webmap-import --lockfile` +f %t/lock/webmap/lock 00644 _webmap _webmap diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100644 index 0000000..29ad0b9 --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,25 @@ +--- +# The list of layer groups to process, see +# webmap-tools/config.yml:layer-groups. +webmap_layer_groups: + - mrr + - skydd + - avverk + - ren + - vbk + - ri + - svk + - misc + - nv + +webmap_layer_groups_nodownload: + - misc + +# adjust calendar events for individual units +webmap_layer_groups_update_calendar: + mrr: "*-*-* 05:00:00" # updated daily at 04:33 CEST + +# PostgreSQL's version number and cluster name +postgresql: + version: 15 + cluster: main diff --git a/handlers/main.yml b/handlers/main.yml index c241ecc..b6ee548 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -5,6 +5,9 @@ - name: systemctl daemon-reload command: /usr/bin/systemctl daemon-reload +- name: systemd-tmpfiles --create + command: /usr/bin/systemd-tmpfiles --create + - name: Refresh hostname command: /usr/bin/hostnamectl hostname {{ inventory_hostname_short }} @@ -46,3 +49,12 @@ - name: Reload nginx service: name=nginx.service state=reloaded + +- name: Restart PostgreSQL + service: name=postgresql.service state=restarted + +- name: Reload PostgreSQL + service: name=postgresql.service state=reloaded + +- name: Stop webmap-cgi.service + service: name=webmap-cgi.service state=stopped @@ -5,13 +5,28 @@ - name: Install etckeeper apt: pkg=etckeeper - import_tasks: ./tasks/firewall.yml + tags: firewall - import_tasks: ./tasks/network.yml + tags: network - import_tasks: ./tasks/sysctl.yml + tags: sysctl - import_tasks: ./tasks/hosts.yml + tags: hosts - import_tasks: ./tasks/apt.yml + tags: apt - import_tasks: ./tasks/ssh.yml + tags: ssh - import_tasks: ./tasks/base.yml + tags: base - import_tasks: ./tasks/mail.yml + tags: + - mail + - postfix + - import_tasks: ./tasks/webmap.yml + tags: webmap - import_tasks: ./tasks/httpd.yml + tags: + - httpd + - nginx handlers: - import_tasks: ./handlers/main.yml diff --git a/tasks/apt.yml b/tasks/apt.yml index 1023908..f17a2e4 100644 --- a/tasks/apt.yml +++ b/tasks/apt.yml @@ -5,8 +5,13 @@ - apt - lsb-release -- name: Remove /etc/apt/sources.list - file: path=/etc/apt/sources.list state=absent +# something keeps recreating (without content) it if we delete it, so we +# leave it instead but ensure it's empty instead +- name: Create empty /etc/apt/sources.list + copy: content="" + dest=/etc/apt/sources.list + owner=root group=root + mode=0644 notify: - apt-get update diff --git a/tasks/base.yml b/tasks/base.yml index 623d209..ad8b1f0 100644 --- a/tasks/base.yml +++ b/tasks/base.yml @@ -18,7 +18,6 @@ - dosfstools - eatmydata - acpid - - acl - fdisk - gdisk - genisoimage @@ -106,6 +105,7 @@ apt: pkg={{ packages }} vars: packages: + - acl - bind9-dnsutils - bzip2 - htop @@ -114,10 +114,12 @@ - python3 - less - iproute2 + - jq - git - curl - screen - sudo + - tig - vim-nox - qemu-guest-agent # Useful for `getent passwd dynamic_user` diff --git a/tasks/httpd.yml b/tasks/httpd.yml index 2138d35..2e1fa98 100644 --- a/tasks/httpd.yml +++ b/tasks/httpd.yml @@ -2,6 +2,12 @@ - name: Install nginx apt: pkg=nginx-light +- name: Install nginx modules + apt: pkg={{ packages }} + vars: + packages: + - libnginx-mod-http-brotli-static + - name: Start nginx service: name=nginx enabled=true state=started @@ -29,13 +35,20 @@ mode=0644 notify: Reload nginx -- name: Copy /etc/nginx/sites-enabled/webmap - copy: src=etc/nginx/sites-enabled/webmap - dest=/etc/nginx/sites-enabled/webmap +- name: Copy /etc/nginx/sites-available/webmap + copy: src=etc/nginx/sites-available/webmap + dest=/etc/nginx/sites-available/webmap owner=root group=root mode=0644 notify: Reload nginx +- name: Create /etc/nginx/sites-enabled/webmap + file: src=../sites-available/webmap + dest=/etc/nginx/sites-enabled/webmap + owner=root group=root + state=link force=yes + notify: Reload nginx + - name: Create directory /var/www/webmap file: path=/var/www/webmap state=directory diff --git a/tasks/mail.yml b/tasks/mail.yml index 89d8530..8f58c8a 100644 --- a/tasks/mail.yml +++ b/tasks/mail.yml @@ -13,7 +13,7 @@ notify: - Run newaliases -- name: Configure Postfix +- name: Configure Postfix (main.cf) template: src=etc/postfix/main.cf.j2 dest=/etc/postfix/main.cf owner=root group=root @@ -21,6 +21,14 @@ notify: - Reload Postfix +- name: Configure Postfix (master.cf) + copy: src=etc/postfix/master.cf + dest=/etc/postfix/master.cf + owner=root group=root + mode=0644 + notify: + - Restart Postfix + - name: Start Postfix service: name=postfix.service enabled=true state=started diff --git a/tasks/network.yml b/tasks/network.yml index 1551f82..a02b07c 100644 --- a/tasks/network.yml +++ b/tasks/network.yml @@ -32,6 +32,7 @@ packages: - systemd-resolved - libnss-resolve + - libnss-myhostname - name: Create directory /etc/systemd/resolved.conf.d file: path=/etc/systemd/resolved.conf.d diff --git a/tasks/webmap.yml b/tasks/webmap.yml new file mode 100644 index 0000000..de320d4 --- /dev/null +++ b/tasks/webmap.yml @@ -0,0 +1,433 @@ +- name: Install gdal-bin + apt: pkg=gdal-bin install-recommends=true + +- name: Install unzip and brotli + apt: pkg={{ packages }} + vars: + packages: + - unzip + - brotli + +- name: Install python dependencies + apt: pkg={{ packages }} + vars: + packages: + - python3 + - python3-brotli + - python3-gdal + - python3-requests + - python3-systemd + - python3-tqdm + - python3-urllib3 + - python3-xdg + - python3-yaml + +- name: Create directory /etc/webmap + file: path=/etc/webmap + state=directory + owner=root group=root + mode=0755 + +- name: Copy /etc/webmap/config.yml + copy: src=webmap-tools/config.yml + dest=/etc/webmap/config.yml + owner=root group=root + mode=0644 + +- name: Create directory /usr/local/share/webmap + file: path=/usr/local/share/webmap + state=directory + owner=root group=root + mode=0755 + +- name: Copy /usr/local/share/webmap/*.py modules + copy: src=webmap-tools/{{ item }} + dest=/usr/local/share/webmap/{{ item }} + owner=root group=root + mode=0644 + with_items: + # TODO these should be compiled + - common.py + - common_gdal.py + - import_source.py + - export_mvt.py + - rename_exchange.py + +- name: Copy webmap-update@.target + copy: src=etc/systemd/system/webmap-update@.target + dest=/etc/systemd/system/webmap-update@.target + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +- name: Copy webmap-update@.timer + copy: src=etc/systemd/system/webmap-update@.timer + dest=/etc/systemd/system/webmap-update@.timer + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +- name: Create directory /etc/systemd/system/webmap-update@*.timer.d + file: path=/etc/systemd/system/webmap-update@{{ item }}.timer.d + state=directory + owner=root group=root + mode=0755 + with_items: "{{ webmap_layer_groups_update_calendar.keys() | list }}" + +- name: Copy /etc/systemd/system/webmap-update@*.timer.d/override.conf + template: src=etc/systemd/system/webmap-update@.timer.d/override.conf.j2 + dest=/etc/systemd/system/webmap-update@{{ item }}.timer.d/override.conf + owner=root group=root + mode=0644 + with_items: "{{ webmap_layer_groups_update_calendar.keys() | list }}" + notify: + - systemctl daemon-reload + +- name: Enable webmap-update.timer + service: name=webmap-update@{{ item }}.timer state=started enabled=true + with_items: "{{ webmap_layer_groups }}" + +- meta: flush_handlers + + +- name: Create system group '_webmap' + group: name=_webmap system=true + state=present + +- name: Create system user '_webmap-download' + user: name=_webmap-download system=true + group=_webmap + createhome=false + home=/nonexistent + shell=/usr/sbin/nologin + comment="Webmap update (download)" + password="!" + state=present + +- name: Copy /usr/local/share/webmap/download.py + copy: src=webmap-tools/webmap-download + dest=/usr/local/share/webmap/download.py + owner=root group=root + mode=0755 + +- name: Create /usr/local/bin/webmap-download + file: src=../share/webmap/download.py + dest=/usr/local/bin/webmap-download + owner=root group=root + state=link force=yes + +- name: Create directory /var/cache/webmap + file: path=/var/cache/webmap + state=directory + owner=_webmap-download group=root + mode=0755 + +- name: Create directory /var/cache/webmap/custom + file: path=/var/cache/webmap/custom + state=directory + owner=root group=root + mode=0755 + +- name: Copy custom layers into /var/cache/webmap/custom + copy: src=webmap-tools/layers/custom/ + dest=/var/cache/webmap/custom/ + owner=root group=root + mode=0644 + directory_mode=0755 + +- name: Copy webmap-download@.service + copy: src=etc/systemd/system/webmap-download@.service + dest=/etc/systemd/system/webmap-download@.service + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +- name: Enable webmap-download@.service + service: name=webmap-download@{{ item }}.service enabled=true + with_items: "{{ webmap_layer_groups | difference(webmap_layer_groups_nodownload) }}" + +- name: Disable some webmap-download@.service + service: name=webmap-download@{{ item }}.service enabled=false + with_items: "{{ webmap_layer_groups_nodownload }}" + +- meta: flush_handlers + + +- name: Create system user '_webmap' + user: name=_webmap system=true + group=_webmap + createhome=false + home=/nonexistent + shell=/usr/sbin/nologin + comment="Webmap update (extract/import)" + password="!" + state=present + +- name: Install PostgreSQL and PostGIS + apt: pkg={{ packages }} + vars: + packages: + - postgresql + - postgresql-postgis + - postgis + # for ansible + - python3-psycopg + +- name: Generate sv_SE.UTF-8 locales + locale_gen: name=sv_SE.UTF-8 state=present + # PostgreSQL needs to be restarted to see the new locale + notify: Restart PostgreSQL + +- name: Configure PostgreSQL + copy: src=etc/postgresql/postgresql.conf + dest=/etc/postgresql/{{ postgresql.version }}/{{ postgresql.cluster }}/conf.d/local.conf + owner=postgres group=postgres + mode=0644 + notify: Restart PostgreSQL + +- name: Start PostgreSQL + service: name=postgresql@{{ postgresql.version }}-{{ postgresql.cluster }}.service state=started + +- meta: flush_handlers + +# Usage: \sudo -u postgres psql </usr/local/share/webmap/schema.sql +- name: Copy /usr/local/share/webmap/schema.sql + copy: src=webmap-tools/schema.sql + dest=/usr/local/share/webmap/schema.sql + owner=root group=root + mode=0644 + +- name: Create PostgreSQL database + become: true + # XXX: this creates /var/lib/postgresql/.ansible/tmp + become_user: postgres + community.postgresql.postgresql_db: + name: webmap + comment: Backend PostGIS database for KlimatanalysNorr tooling + encoding: UTF-8 + lc_collate: sv_SE.UTF-8 + lc_ctype: sv_SE.UTF-8 + locale_provider: icu + icu_locale: sv-SE-x-icu + template: template0 + owner: postgres + +- name: Create 'webmap_import' and 'webmap_guest' PostgreSQL users (roles) + become: true + become_user: postgres + community.postgresql.postgresql_user: + login_db: webmap + name: "{{ item }}" + with_items: + - webmap_import + - webmap_guest + +- name: Add a rule for 'webmap_import' user in pg_hba.conf + ansible.builtin.lineinfile: + path: /etc/postgresql/{{ postgresql.version }}/{{ postgresql.cluster }}/pg_hba.conf + regexp: '^local\s+webmap\s' + line: 'local webmap all peer map=pgmap_webmap' + # must come before 'local all all peer', cf. + # https://dba.stackexchange.com/questions/177142/postgresql-cannot-peer-authenticate-using-usermap-provided-user-name-dbuser + insertbefore: '^local\s+all\s+all\s' + create: false + notify: Reload PostgreSQL + +- name: Add a mapping rule for 'webmap_import' user in pg_ident.conf + ansible.builtin.lineinfile: + path: /etc/postgresql/{{ postgresql.version }}/{{ postgresql.cluster }}/pg_ident.conf + regexp: '^pgmap_webmap\s.*\swebmap_import\s*$' + line: 'pgmap_webmap _webmap webmap_import' + create: false + notify: Reload PostgreSQL + +- name: Add a mapping rule for 'webmap_guest' user in pg_ident.conf + ansible.builtin.lineinfile: + path: /etc/postgresql/{{ postgresql.version }}/{{ postgresql.cluster }}/pg_ident.conf + regexp: '^pgmap_webmap\s.*\swebmap_guest\s*$' + line: 'pgmap_webmap /^_?[a-zA-Z][a-zA-Z0-9_\-]*[a-zA-Z0-9]$ webmap_guest' + create: false + notify: Reload PostgreSQL + +- name: Create 'postgis' PostgreSQL schema + become: true + become_user: postgres + community.postgresql.postgresql_schema: + name: postgis + login_db: webmap + owner: postgres + +- name: Install 'postgis' PostgreSQL extension to the webmap database in the postgis schema + become: true + become_user: postgres + community.postgresql.postgresql_ext: + name: postgis + login_db: webmap + schema: postgis + comment: Geographic objects support for PostgreSQL + +- name: GRANT CONNECT ON DATABASE webmap TO webmap_import, webmap_guest + become: true + become_user: postgres + community.postgresql.postgresql_privs: + login_db: webmap + privs: CONNECT + type: database + role: webmap_import,webmap_guest + +- name: GRANT USAGE ON SCHEMA postgis TO webmap_import, webmap_guest + become: true + become_user: postgres + community.postgresql.postgresql_privs: + login_db: webmap + privs: USAGE + type: schema + obj: postgis + role: webmap_import,webmap_guest + +# webmap-import should TRUNCATE existing output layers +- name: REVOKE CREATE ON SCHEMA postgis FROM webmap_import + become: true + become_user: postgres + community.postgresql.postgresql_privs: + login_db: webmap + privs: CREATE + type: schema + obj: postgis + role: webmap_import + state: absent + +- name: GRANT SELECT ON TABLES IN SCHEMA postgis TO webmap_guest + become: true + become_user: postgres + community.postgresql.postgresql_privs: + login_db: webmap + privs: SELECT + type: table + obj: ALL_IN_SCHEMA + schema: postgis + role: webmap_guest + +- name: GRANT USAGE, SELECT ON SEQUENCES IN SCHEMA postgis TO webmap_guest + become: true + become_user: postgres + community.postgresql.postgresql_privs: + login_db: webmap + privs: USAGE,SELECT + type: sequence + obj: ALL_IN_SCHEMA + schema: postgis + role: webmap_guest + +- name: Copy /usr/local/share/webmap/import.py + copy: src=webmap-tools/webmap-import + dest=/usr/local/share/webmap/import.py + owner=root group=root + mode=0755 + +- name: Create /usr/local/bin/webmap-import + file: src=../share/webmap/import.py + dest=/usr/local/bin/webmap-import + owner=root group=root + state=link force=yes + +- name: Copy webmap-import@.service + copy: src=etc/systemd/system/webmap-import@.service + dest=/etc/systemd/system/webmap-import@.service + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +- name: Enable webmap-import@.service + service: name=webmap-import@{{ item }}.service enabled=true + with_items: "{{ webmap_layer_groups }}" + + +- name: Build administrative-codes.json* + become: false + local_action: + module: community.general.make + chdir: ./webmap-tools/administrative-codes + target: all + +- name: Create directory /var/www/webmap/data + file: path=/var/www/webmap/data + state=directory + owner=root group=root + mode=0755 + +- name: Copy /var/www/webmap/data/administrative-codes.json* + copy: src=./webmap-tools/administrative-codes/{{ item }} + dest=/var/www/webmap/data/{{ item }} + owner=root group=root + mode=0644 + with_items: + - administrative-codes.json + - administrative-codes.json.br + +- meta: flush_handlers + + +- name: Create directory /var/www/webmap/tiles + file: path=/var/www/webmap/tiles + state=directory + owner=_webmap group=root + mode=0755 + + +- name: Copy /etc/tmpfiles.d/webmap.conf + copy: src=etc/tmpfiles.d/webmap.conf + dest=/etc/tmpfiles.d/webmap.conf + owner=root group=root + mode=0644 + notify: + - systemd-tmpfiles --create + +- meta: flush_handlers + + +- name: Install Python/WSGI dependencies + apt: pkg={{ packages }} + vars: + packages: + - uwsgi-core + - uwsgi-plugin-python3 + # TODO[trixie]: install python3-psycopg-c instead + - python3-psycopg + +- name: Copy webmap-cgi.socket + copy: src=etc/systemd/system/webmap-cgi.socket + dest=/etc/systemd/system/webmap-cgi.socket + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +- name: Copy webmap-cgi.service + copy: src=etc/systemd/system/webmap-cgi.service + dest=/etc/systemd/system/webmap-cgi.service + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + - Stop webmap-cgi.service + +- name: Copy /usr/libexec/webmap-cgi + copy: src=./webmap-tools/webmap-cgi + dest=/usr/libexec/webmap-cgi + owner=root group=root + mode=0755 + notify: + - Stop webmap-cgi.service + +- meta: flush_handlers + +- name: Enable webmap-cgi.socket + service: name=webmap-cgi.socket state=started enabled=true + +- name: Disable webmap-cgi.service + service: name=webmap-cgi.service enabled=false diff --git a/templates/etc/postfix/main.cf.j2 b/templates/etc/postfix/main.cf.j2 index 9557cc4..35a6790 100644 --- a/templates/etc/postfix/main.cf.j2 +++ b/templates/etc/postfix/main.cf.j2 @@ -29,10 +29,9 @@ alias_database = $virtual_alias_maps mailbox_size_limit = 0 # Forward everything to our internal outgoing proxy -# TODO: User relay-smtps on 465/tcp once Hetzner opens it relay_domains = -relayhost = [smtp.guilhem.org]:587 -default_transport = relay +relayhost = [smtp.guilhem.org]:465 +default_transport = relay-smtps smtpd_tls_security_level = none smtp_tls_exclude_ciphers = EXPORT, LOW, MEDIUM, aNULL, eNULL, DES, RC4, MD5 diff --git a/templates/etc/systemd/system/webmap-update@.timer.d/override.conf.j2 b/templates/etc/systemd/system/webmap-update@.timer.d/override.conf.j2 new file mode 100644 index 0000000..795ee20 --- /dev/null +++ b/templates/etc/systemd/system/webmap-update@.timer.d/override.conf.j2 @@ -0,0 +1,3 @@ +[Timer] +OnCalendar= +OnCalendar={{ webmap_layer_groups_update_calendar[item] }} diff --git a/webmap-tools b/webmap-tools new file mode 160000 +Subproject 4263125c9bc8f23cf5ef6f3257b575537e3cad7 |