diff options
-rw-r--r-- | files/etc/nginx/sites-available/webmap | 2 | ||||
-rw-r--r-- | files/etc/systemd/system/webmap-download@.service | 7 | ||||
-rw-r--r-- | files/etc/systemd/system/webmap-import@.service | 39 | ||||
-rw-r--r-- | files/etc/systemd/system/webmap-publish@.service | 40 | ||||
-rw-r--r-- | files/etc/tmpfiles.d/webmap.conf | 11 | ||||
-rw-r--r-- | group_vars/all.yml | 5 | ||||
-rw-r--r-- | handlers/main.yml | 9 | ||||
-rw-r--r-- | tasks/apt.yml | 9 | ||||
-rw-r--r-- | tasks/httpd.yml | 6 | ||||
-rw-r--r-- | tasks/webmap.yml | 263 | ||||
m--------- | webmap-tools | 0 |
11 files changed, 380 insertions, 11 deletions
diff --git a/files/etc/nginx/sites-available/webmap b/files/etc/nginx/sites-available/webmap index d16ab60..92809e2 100644 --- a/files/etc/nginx/sites-available/webmap +++ b/files/etc/nginx/sites-available/webmap @@ -62,7 +62,7 @@ server { } location ^~ /tiles/ { expires 1d; - gzip_static on; + brotli_static on; try_files $uri =404; error_page 404 /_.txt; } diff --git a/files/etc/systemd/system/webmap-download@.service b/files/etc/systemd/system/webmap-download@.service index a928a13..2c5a3e4 100644 --- a/files/etc/systemd/system/webmap-download@.service +++ b/files/etc/systemd/system/webmap-download@.service @@ -8,7 +8,7 @@ Upholds=webmap-update@%i.target [Service] User=_webmap-download -Group=nogroup +Group=_webmap Nice=15 IOSchedulingClass=idle @@ -16,7 +16,7 @@ IOSchedulingClass=idle Type=oneshot ExecStart=/usr/local/bin/webmap-download \ --cachedir=/var/cache/webmap \ - --lockdir=%t/webmap-download \ + --lockdir=%t/lock/webmap/download \ --no-exit-code \ --quiet \ -- %I @@ -31,8 +31,7 @@ ProtectKernelModules=yes ProtectKernelTunables=yes RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 ReadWritePaths=/var/cache/webmap -RuntimeDirectory=webmap-download -RuntimeDirectoryPreserve=yes +ReadWritePaths=%t/lock/webmap/download [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..06d204c --- /dev/null +++ b/files/etc/systemd/system/webmap-import@.service @@ -0,0 +1,39 @@ +[Unit] +Description=Webmap updater service (import %I to PostgreSQL) +After=postgresql.service webmap-update@%i.target +After=webmap-download@%i.service +Upholds=webmap-update@%i.target + +# XXX webmap-download write cached files atomatically but there is no +# guarantee that GDAL/OGR opens them atomically. It'd therefore make +# sense to use the following Conflict= directive, however systemd skips +# webmap-download@%i.service in that case. +#Conflicts=webmap-download@%i.service + +[Service] +User=_webmap-import +Group=_webmap + +Nice=15 +IOSchedulingClass=idle + +Type=oneshot +ExecStart=/usr/local/bin/webmap-import \ + --cachedir=/var/cache/webmap \ + --lockfile=%t/lock/webmap/lock \ + -- %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 +PrivateTmp=yes + +[Install] +WantedBy=webmap-update@%i.target diff --git a/files/etc/systemd/system/webmap-publish@.service b/files/etc/systemd/system/webmap-publish@.service new file mode 100644 index 0000000..e2f8e6b --- /dev/null +++ b/files/etc/systemd/system/webmap-publish@.service @@ -0,0 +1,40 @@ +[Unit] +Description=Webmap updater service (publish %I as MVT) +#After=postgresql.service webmap-update@%i.target +#After=webmap-download@%i.service +#After=webmap-import@%i.service +#Upholds=webmap-update@%i.target + +[Service] +User=_webmap-publish +Group=_webmap + +Nice=15 +IOSchedulingClass=idle + +Type=oneshot +ExecStart=/usr/local/bin/webmap-publish \ + --lockfile=%t/lock/webmap/lock \ + --destdir=/var/www/webmap/tiles/%i \ + --name=%I \ + --webroot=/var/www/webmap \ + --metadata=/var/www/webmap/tiles/metadata.json \ + --metadata-lockfile=%t/lock/webmap/tiles.lock \ + --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=/var/www/webmap/tiles +ReadWritePaths=%t/lock/webmap +PrivateTmp=yes + +#[Install] +#WantedBy=webmap-update@%i.target diff --git a/files/etc/tmpfiles.d/webmap.conf b/files/etc/tmpfiles.d/webmap.conf new file mode 100644 index 0000000..620cd24 --- /dev/null +++ b/files/etc/tmpfiles.d/webmap.conf @@ -0,0 +1,11 @@ +d %t/lock/webmap 0755 root root + +# for webmap-download's --lockdir +d %t/lock/webmap/download 0755 _webmap-download _webmap + +# for webmap-import's *and* webmap-publish's --lockfile (hence the +# ownership and g+w) +f %t/lock/webmap/lock 0664 root _webmap + +# for webmap-publish's --metadata-lockfile +f %t/lock/webmap/tiles.lock 0644 _webmap-publish _webmap diff --git a/group_vars/all.yml b/group_vars/all.yml index a0d35c6..5d4474a 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -7,3 +7,8 @@ webmap_layer_groups: - sks - st - vbk + +# PostgreSQL's version number and cluster name +postgresql: + version: 15 + cluster: main diff --git a/handlers/main.yml b/handlers/main.yml index c241ecc..281951b 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,9 @@ - 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 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/httpd.yml b/tasks/httpd.yml index 22757d5..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 diff --git a/tasks/webmap.yml b/tasks/webmap.yml index 9b60359..9e2c2f6 100644 --- a/tasks/webmap.yml +++ b/tasks/webmap.yml @@ -1,17 +1,23 @@ - name: Install gdal-bin apt: pkg=gdal-bin install-recommends=true -- name: Install unzip - apt: pkg=unzip +- 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-lxml - python3-requests + - python3-systemd - python3-tqdm - python3-urllib3 - python3-xdg @@ -64,9 +70,13 @@ - 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=nogroup + group=_webmap createhome=false home=/nonexistent shell=/usr/sbin/nologin @@ -95,7 +105,7 @@ - name: Create directory /var/cache/webmap file: path=/var/cache/webmap state=directory - owner=_webmap-download group=nogroup + owner=_webmap-download group=root mode=0755 - name: Copy webmap-download@.service @@ -111,3 +121,248 @@ with_items: "{{ webmap_layer_groups }}" - meta: flush_handlers + + +- name: Create system user '_webmap-import' + user: name=_webmap-import 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: 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: + 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-import 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 + 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 + 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: + database: 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: + database: 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: + database: 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: + database: 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: + database: 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 + +- meta: flush_handlers + + +- name: Create system user '_webmap-publish' + user: name=_webmap-publish system=true + group=_webmap + createhome=false + home=/nonexistent + shell=/usr/sbin/nologin + comment="Webmap update (publication as MVT)" + password="!" + state=present + +- name: Copy /usr/local/share/webmap/publish.py + copy: src=webmap-tools/webmap-publish + dest=/usr/local/share/webmap/publish.py + owner=root group=root + mode=0755 + +- name: Create /usr/local/bin/webmap-publish + file: src=../share/webmap/publish.py + dest=/usr/local/bin/webmap-publish + owner=root group=root + state=link force=yes + +- name: Create directory /var/www/webmap/tiles + file: path=/var/www/webmap/tiles + state=directory + owner=_webmap-publish group=root + mode=0755 + +- name: Copy webmap-publish@.service + copy: src=etc/systemd/system/webmap-publish@.service + dest=/etc/systemd/system/webmap-publish@.service + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + +#- name: Enable webmap-publish@.service +# service: name=webmap-publish@{{ item }}.service enabled=true +# with_items: "{{ webmap_layer_groups }}" + + +- 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 diff --git a/webmap-tools b/webmap-tools -Subproject 729a5df4ba9889aebcd51787ec11a4d0d1ea547 +Subproject 7cda119879cf48ba72ba34522fa9cdf9ef6d9b4 |