From af8880f3a3281612340ec3d38e823684d9af5baa Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 16 May 2020 23:35:25 +0200 Subject: wiki/website: harden config and port to Debian 10. --- roles/wiki/files/etc/nginx/sites-available/website | 4 +- roles/wiki/files/etc/nginx/sites-available/wiki | 6 +-- .../wiki/files/etc/systemd/system/ikiwiki.service | 23 +++++++++ roles/wiki/files/etc/systemd/system/ikiwiki.socket | 11 +++++ .../files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm | 55 ++++++++++++++++++---- .../wiki/files/var/lib/ikiwiki/fripost-wiki.setup | 3 +- roles/wiki/handlers/main.yml | 9 ++++ roles/wiki/tasks/main.yml | 35 ++++++++++++-- 8 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 roles/wiki/files/etc/systemd/system/ikiwiki.service create mode 100644 roles/wiki/files/etc/systemd/system/ikiwiki.socket diff --git a/roles/wiki/files/etc/nginx/sites-available/website b/roles/wiki/files/etc/nginx/sites-available/website index ba227e5..c524800 100644 --- a/roles/wiki/files/etc/nginx/sites-available/website +++ b/roles/wiki/files/etc/nginx/sites-available/website @@ -5,7 +5,7 @@ server { server_name fripost.org; server_name www.fripost.org; - include snippets/acme-challenge.conf; + include /etc/lacme/nginx.conf; access_log /var/log/nginx/www.access.log; error_log /var/log/nginx/www.error.log info; @@ -28,7 +28,7 @@ server { include snippets/headers.conf; add_header Content-Security-Policy - "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'none'; form-action https://www.paypal.com/; base-uri fripost.org www.fripost.org"; + "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; frame-ancestors 'none'; form-action https://www.paypal.com/; base-uri fripost.org www.fripost.org"; include snippets/ssl.conf; ssl_certificate ssl/www.fripost.org.pem; diff --git a/roles/wiki/files/etc/nginx/sites-available/wiki b/roles/wiki/files/etc/nginx/sites-available/wiki index 7759fa5..4b62d54 100644 --- a/roles/wiki/files/etc/nginx/sites-available/wiki +++ b/roles/wiki/files/etc/nginx/sites-available/wiki @@ -4,7 +4,7 @@ server { server_name wiki.fripost.org; - include snippets/acme-challenge.conf; + include /etc/lacme/nginx.conf; access_log /var/log/nginx/wiki.access.log; error_log /var/log/nginx/wiki.error.log info; @@ -27,7 +27,7 @@ server { include snippets/headers.conf; add_header Content-Security-Policy - "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; referrer no-referrer-when-downgrade; frame-ancestors 'none'; form-action 'self'; base-uri wiki.fripost.org"; + "default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri wiki.fripost.org"; include snippets/ssl.conf; ssl_certificate ssl/www.fripost.org.pem; @@ -46,7 +46,7 @@ server { fastcgi_param SCRIPT_FILENAME /var/lib/ikiwiki/public_html/ikiwiki.cgi; fastcgi_index ikiwiki.cgi; include snippets/fastcgi.conf; - fastcgi_pass unix:/var/run/fcgiwrap.socket; + fastcgi_pass unix:/run/ikiwiki.socket; gzip off; } } diff --git a/roles/wiki/files/etc/systemd/system/ikiwiki.service b/roles/wiki/files/etc/systemd/system/ikiwiki.service new file mode 100644 index 0000000..3ee7d66 --- /dev/null +++ b/roles/wiki/files/etc/systemd/system/ikiwiki.service @@ -0,0 +1,23 @@ +[Unit] +Description=wiki compiler (CGI script) +Documentation=https://ikiwiki.info/ + +[Service] +User=ikiwiki +Group=ikiwiki +ExecStart=/usr/sbin/fcgiwrap +SyslogIdentifier=ikiwiki +# +# Hardening +NoNewPrivileges=yes +ReadWriteDirectories=/var/lib/ikiwiki/fripost-wiki +ReadWriteDirectories=/var/lib/ikiwiki/public_html/fripost-wiki +PrivateDevices=yes +ProtectHome=yes +ProtectSystem=strict +ProtectControlGroups=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes + +[Install] +WantedBy=multi-user.target diff --git a/roles/wiki/files/etc/systemd/system/ikiwiki.socket b/roles/wiki/files/etc/systemd/system/ikiwiki.socket new file mode 100644 index 0000000..8dc1a0e --- /dev/null +++ b/roles/wiki/files/etc/systemd/system/ikiwiki.socket @@ -0,0 +1,11 @@ +[Unit] +Description=wiki compiler (CGI script) +Documentation=https://ikiwiki.info/ + +[Socket] +ListenStream=%t/ikiwiki.socket +SocketUser=www-data +SocketMode=0600 + +[Install] +WantedBy=sockets.target diff --git a/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm b/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm index 25081ef..34bdd89 100644 --- a/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm +++ b/roles/wiki/files/var/lib/ikiwiki/IkiWiki/Plugin/pandoc.pm @@ -21,6 +21,23 @@ my %extra_formats = ( latex => { ext=>'tex', label=>'LaTeX', format=>'latex', extra=>['--standalone'], order=>7 }, ); +my @scalar_meta_keys = qw/ + title date bibliography csl subtitle abstract summary description + version lang locale titlesort tag fripost_debug_inner + /; + +my @list_meta_keys = qw/ + author + /; + +my @hash_meta_keys = qw/ + experiment + /; + +my @list_hash_meta_keys = qw/ + references + /; + sub import { my $markdown_ext = $config{pandoc_markdown_ext} || "mdwn"; @@ -96,6 +113,13 @@ sub getsetup () { safe => 1, rebuild => 1, }, + pandoc_markdown_fmt => { + type => "string", + example => "markdown", + description => "Format string to use when processing files handled by Pandoc.", + safe => 1, + rebuild => 1, + }, pandoc_latex => { type => "boolean", example => 0, @@ -409,10 +433,11 @@ sub htmlize ($@) { # can be parsed out # We must omit the 'bibliography' parameter here, otherwise the list of # references will be doubled. + my $markdown_fmt = $config{pandoc_markdown_fmt} || 'markdown'; my $to_json_pid = open2(*JSON_OUT, *PANDOC_OUT, $command, - '-f', $format, + '-f', $markdown_fmt, '-t', 'json', - @args, '--normalize'); + @args); error("Unable to open $command") unless $to_json_pid; # Workaround for perl bug (#376329) @@ -435,8 +460,8 @@ sub htmlize ($@) { my $meta = undef; my $decoded_json = decode_json($json_content); # The representation of the meta block changed in pandoc version 1.18 - if (ref $decoded_json eq 'HASH' && $decoded_json->{'Meta'}) { - $meta = $decoded_json->{'Meta'} || {}; # post-1.18 version + if (ref $decoded_json eq 'HASH' && $decoded_json->{'meta'}) { + $meta = $decoded_json->{'meta'} || {}; # post-1.18 version } elsif (ref $decoded_json eq 'ARRAY') { $meta = $decoded_json->[0]->{'unMeta'} || {}; # pre-1.18 version } @@ -450,12 +475,11 @@ sub htmlize ($@) { # as well as some configuration options (generate_*, *_extra_options, *_template). my @format_keys = grep { $_ ne 'pdf' } keys %extra_formats; - my %scalar_meta = map { ($_=>undef) } qw( - title date bibliography csl subtitle abstract summary - description version lang locale); + my %scalar_meta = map { ($_=>undef) } @scalar_meta_keys; $scalar_meta{$_.'_template'} = undef for @format_keys; my %bool_meta = map { ("generate_$_"=>0) } keys %extra_formats; - my %list_meta = map { ($_=>[]) } qw/author references/; + my %list_meta = map { ($_=>[]) } ( + @list_meta_keys, @list_hash_meta_keys, @hash_meta_keys); $list_meta{$_.'_extra_options'} = [] for @format_keys; my $have_bibl = 0; foreach my $k (keys %scalar_meta) { @@ -484,6 +508,7 @@ sub htmlize ($@) { $list_meta{$k} = unwrap_c($meta->{$k}); $list_meta{$k} = [$list_meta{$k}] unless ref $list_meta{$k} eq 'ARRAY'; $have_bibl = 1 if $k eq 'references'; + $pagestate{$page}{meta}{$k} = $list_meta{$k}; $pagestate{$page}{meta}{"pandoc_$k"} = $list_meta{$k}; } # Try to add other keys as scalars, with pandoc_ prefix only. @@ -596,9 +621,14 @@ sub pagetemplate (@) { my $page = $params{page}; my $template = $params{template}; foreach my $k (keys %{$pagestate{$page}{meta}}) { - next unless $k =~ /^pandoc_/; + next unless + (grep {/^$k$/} ( + @scalar_meta_keys, @list_meta_keys, + @hash_meta_keys, @list_hash_meta_keys)) || + ($k =~ /^(pandoc_)/); $template->param($k => $pagestate{$page}{meta}{$k}); } + return $template; } sub pageactions { @@ -757,6 +787,11 @@ sub unwrap_c { # Finds the deepest-level scalar value for 'c' in the data structure. # Lists with one element are replaced with the scalar, lists with more # than one element are returned as an arrayref containing scalars. + # + # Elements containing hash as keys are unwrapped. That is to + # support *MetaList* containing *MetaMap* with keys pointing to + # *MetaInlines*. Reference are examples of that structure. (hash unwrap) + # my $container = shift; if (ref $container eq 'ARRAY' && @$container > 1) { if (ref $container->[0] eq 'HASH' && $container->[0]->{t} =~ /^(?:Str|Space)$/) { @@ -771,6 +806,8 @@ sub unwrap_c { return; } elsif (ref $container eq 'HASH' && $container->{c}) { return unwrap_c($container->{c}); + } elsif (ref $container eq 'HASH' && keys $container->%*) { # (hash unwrap) + return {map { $_ => unwrap_c($container->{$_}) } keys $container->%*}; } elsif (ref $container) { return; } else { diff --git a/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup b/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup index 4353965..4af3d59 100644 --- a/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup +++ b/roles/wiki/files/var/lib/ikiwiki/fripost-wiki.setup @@ -31,7 +31,7 @@ reverse_proxy: 0 # filename of cgi wrapper to generate cgi_wrapper: /var/lib/ikiwiki/public_html/ikiwiki.cgi # mode for cgi_wrapper (can safely be made suid) -cgi_wrappermode: 06755 +cgi_wrappermode: 0755 # number of seconds to delay CGI requests when overloaded cgi_overload_delay: '' # message to display when overloaded (may contain html) @@ -416,5 +416,4 @@ getsource_mimetype: text/plain; charset=utf-8 #tag_autocreate_commit: 1 # pandoc plugin -pandoc_smart: 1 pandoc_html5: 1 diff --git a/roles/wiki/handlers/main.yml b/roles/wiki/handlers/main.yml index 109c63d..ac9ad2b 100644 --- a/roles/wiki/handlers/main.yml +++ b/roles/wiki/handlers/main.yml @@ -5,3 +5,12 @@ - name: Refresh ikiwiki become_user: ikiwiki command: ikiwiki --setup /var/lib/ikiwiki/fripost-wiki.setup --refresh --wrappers + +- name: systemctl daemon-reload + command: /bin/systemctl daemon-reload + +- name: Stop ikiwiki + service: name=ikiwiki.service state=stopped + +- name: Restart ikiwiki + service: name=ikiwiki.socket state=restarted diff --git a/roles/wiki/tasks/main.yml b/roles/wiki/tasks/main.yml index 718b433..9d436a9 100644 --- a/roles/wiki/tasks/main.yml +++ b/roles/wiki/tasks/main.yml @@ -12,6 +12,12 @@ - fcgiwrap - pandoc +- name: Stop and disable fcgiwrap socket + service: name=fcgiwrap.socket state=stopped enabled=false + +- name: Stop fcgiwrap service + service: name=fcgiwrap.service state=stopped + - name: Create a user 'ikiwiki' user: name=ikiwiki system=yes home=/var/lib/ikiwiki @@ -21,9 +27,6 @@ generate_ssh_key=yes ssh_key_comment=ikiwiki@{{ ansible_fqdn }} -- name: Add 'www-data' to the group 'ikiwiki' - user: name=www-data groups=ikiwiki append=yes - - name: Create directory ~ikiwiki/IkiWiki/Plugin file: path=/var/lib/ikiwiki/IkiWiki/Plugin state=directory @@ -70,6 +73,32 @@ - meta: flush_handlers +- name: Copy ikiwiki service unit + copy: src=etc/systemd/system/ikiwiki.service + dest=/etc/systemd/system/ikiwiki.service + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + - Stop ikiwiki + +- name: Copy ikiwiki socket unit + copy: src=etc/systemd/system/ikiwiki.socket + dest=/etc/systemd/system/ikiwiki.socket + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + - Restart ikiwiki + +- name: Disable ikiwiki service + service: name=ikiwiki.service enabled=false + +- name: Start ikiwiki socket + service: name=ikiwiki.socket state=started enabled=true + +- meta: flush_handlers + - name: Copy /etc/nginx/sites-available/{wiki,website} copy: src=etc/nginx/sites-available/{{ item }} dest=/etc/nginx/sites-available/{{ item }} -- cgit v1.2.3