From eac2af3b6f7fb511274fa6040ec3b92b8f163e97 Mon Sep 17 00:00:00 2001 From: Adar Nimrod <nimrod@shore.co.il> Date: Thu, 28 Jan 2021 01:45:17 +0200 Subject: [PATCH] SSL on Kodi. Both host01 and kodi are behind the ns1 router. For completely secure connections, SSL termination should be done on each host. So use HAProxy on ns1 to route HTTPS traffic using the SNI extension and HTTP traffic using the Host header (default to host01). Add tasks to the renew-hosts playbook to issue (or renew) Let's Encrypt certificates on kodi. --- .gitignore | 7 +- renew-certs.yaml | 139 +++++++++++++++++++++++++++++ roles/router/files/haproxy.cfg | 62 +++++++++++++ roles/router/files/nsd/shore.co.il | 13 +-- roles/router/files/pf.conf | 8 +- roles/router/handlers/main.yaml | 5 ++ roles/router/tasks/main.yaml | 25 ++++++ 7 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 roles/router/files/haproxy.cfg diff --git a/.gitignore b/.gitignore index ed3e466..69692d4 100644 --- a/.gitignore +++ b/.gitignore @@ -47,8 +47,7 @@ dist/ *.env .bundle/ !Pipfile.lock -site.* -mail.* -account.* -host.* +*.crt +*.csr +*.key .vault-password diff --git a/renew-certs.yaml b/renew-certs.yaml index 23043fe..937e353 100644 --- a/renew-certs.yaml +++ b/renew-certs.yaml @@ -20,6 +20,10 @@ delegate_to: ns4 command: docker restart web-proxy_proxy_1 + - name: Restart Nginx on kodi + delegate_to: kodi + command: docker restart web-proxy_proxy_1 + - name: Reload Exim delegate_to: host01 command: docker kill --signal SIGHUP mail_smtp_1 @@ -425,6 +429,126 @@ tags: - mail + - name: Generate kodi key + community.crypto.openssl_privatekey: + mode: *mode + path: &kodi_key_src |- + {{ playbook_dir }}/kodi.key + size: *size + state: present + type: *type + tags: + - kodi + + - name: Generate kodi certificate signing request + community.crypto.openssl_csr: + common_name: kodi.shore.co.il + country_name: *country_name + digest: *digest + email_address: |- + {{ email }} + locality_name: *locality_name + organization_name: *organization_name + path: &kodi_csr_src kodi.csr + privatekey_path: *kodi_key_src + state: present + subject_alt_name: |- + DNS:kodi.shore.co.il,DNS:library.shore.co.il,DNS:jellyfin.shore.co.il + register: acme_kodi_csr + tags: + - kodi + + - name: Create kodi challenge + community.crypto.acme_certificate: + account_email: |- + {{ email }} + account_key_src: *account_key_src + acme_directory: |- + {{ acme_directory }} + acme_version: | + {{ acme_version }} + csr: *kodi_csr_src + fullchain_dest: &kodi_cert_src |- + {{ playbook_dir }}/kodi.crt + modify_account: false + remaining_days: 35 + select_crypto_backend: *crypto_backend + register: acme_kodi_challenge + tags: + - kodi + + - name: Debug kodi challenge + debug: + var: acme_kodi_challenge + verbosity: 1 + tags: + - kodi + + - name: Renew kodi cert + when: acme_kodi_challenge is changed + tags: + - kodi + block: + + - name: Create ACME challenge directory + delegate_to: kodi + file: + path: /var/www/www.shore.co.il/.well-known/acme-challenge + state: directory + + - name: Copy http-01 kodi challenge + delegate_to: kodi + with_dict: | + {{ acme_kodi_challenge['challenge_data'] }} + copy: + content: |- + {{ item.value['http-01']['resource_value'] }} + # yamllint disable-line rule:line-length + dest: /var/www/www.shore.co.il/{{ item.value['http-01']['resource'] }} + group: www-data + mode: 0o0644 + owner: root + + - name: Validate kodi challenge + community.crypto.acme_certificate: + account_email: |- + {{ email }} + account_key_src: *account_key_src + acme_directory: |- + {{ acme_directory }} + acme_version: | + {{ acme_version }} + challenge: http-01 + csr: *kodi_csr_src + data: "{{ acme_kodi_challenge }}" + fullchain_dest: *kodi_cert_src + modify_account: false + remaining_days: 35 + select_crypto_backend: *crypto_backend + + - name: Copy kodi key, certificate to server + delegate_to: kodi + with_items: + - src: *kodi_key_src + dest: /var/ssl/site.key + mode: 0o0444 + - src: *kodi_cert_src + dest: /var/ssl/site.crt + mode: 0o0444 + copy: + src: |- + {{ item.src }} + dest: |- + {{ item.dest }} + mode: |- + {{ item.mode }} + owner: root + group: root + notify: + - Restart Nginx on kodi + tags: + - kodi + - name: Generate Diffie-Hellman parameters on host01 become: true delegate_to: host01 @@ -456,3 +580,18 @@ tags: - ns4 - dhparams + + - name: Generate Diffie-Hellman parameters on kodi + become: true + delegate_to: kodi + community.crypto.openssl_dhparam: + force: true + mode: 0o0644 + path: /var/ssl/dhparams + size: 4096 + state: present + notify: + - Restart Nginx on kodi + tags: + - kodi + - dhparams diff --git a/roles/router/files/haproxy.cfg b/roles/router/files/haproxy.cfg new file mode 100644 index 0000000..89bed2b --- /dev/null +++ b/roles/router/files/haproxy.cfg @@ -0,0 +1,62 @@ +global + log 127.0.0.1 local0 debug + log-send-hostname + maxconn 1024 + chroot /var/haproxy + uid 604 + gid 604 + daemon + pidfile /var/run/haproxy.pid + +defaults + log global + mode http + option httplog + option dontlognull + option redispatch + retries 3 + maxconn 2000 + timeout client 30s + timeout server 30s + timeout connect 5s + +frontend http + bind 62.219.131.121:80 + mode http + acl kodi hdr(host) -i kodi.shore.co.il + acl kodi hdr(host) -i library.shore.co.il + acl kodi hdr(host) -i jellyfin.shore.co.il + use_backend kodi_http if kodi + default_backend host01_http + +frontend https + bind 62.219.131.121:443 + mode tcp + option tcplog + tcp-request inspect-delay 5s + tcp-request content accept if { req_ssl_hello_type 1 } + acl kodi req_ssl_sni -i kodi.shore.co.il + acl kodi req_ssl_sni -i library.shore.co.il + acl kodi req_ssl_sni -i jellyfin.shore.co.il + use_backend kodi_https if kodi + default_backend host01_https + +backend host01_http + mode http + option forwardfor + server host01 host01.shore.co.il:80 check + +backend host01_https + mode tcp + option ssl-hello-chk + server host01 host01.shore.co.il:443 check + +backend kodi_http + mode http + option forwardfor + server kodi kodi.shore.co.il:80 check + +backend kodi_https + mode tcp + option ssl-hello-chk + server kodi kodi.shore.co.il:443 check diff --git a/roles/router/files/nsd/shore.co.il b/roles/router/files/nsd/shore.co.il index e84bfa0..897139b 100644 --- a/roles/router/files/nsd/shore.co.il +++ b/roles/router/files/nsd/shore.co.il @@ -1,7 +1,7 @@ $TTL 1h $ORIGIN shore.co.il. @ IN SOA ns1 hostmaster ( - 2021012601 + 2021012701 1h 5m 4w @@ -51,15 +51,18 @@ _caldavs._tcp IN SRV 0 1 443 nextcloud IN TXT "v=spf1 -all" IN SPF "v=spf1 -all" -www IN CNAME ns4 autoconfig IN CNAME ns4 -nextcloud IN CNAME ns1 code IN CNAME ns1 git IN CNAME ns1 -lam IN CNAME ns1 -registry IN CNAME ns4 imap IN CNAME smtp +jellyfin IN CNAME ns1 +kodi IN CNAME ns1 +lam IN CNAME ns1 +library IN CNAME ns1 mta-sts IN CNAME smtp +nextcloud IN CNAME ns1 +registry IN CNAME ns4 +www IN CNAME ns4 host01._domainkey IN TXT ("v=DKIM1\; k=rsa\;" "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw9EM6TzCofz004vL+aBV" diff --git a/roles/router/files/pf.conf b/roles/router/files/pf.conf index b88d537..ebbc869 100644 --- a/roles/router/files/pf.conf +++ b/roles/router/files/pf.conf @@ -39,13 +39,11 @@ pass quick inet proto icmp icmp-type { echoreq, unreach } # Allowed local services pass in quick on ingress proto { tcp, udp } to (ingress:0) port { bootps, bootpc } set prio ( 4, 6 ) pass in quick proto { tcp, udp } to port domain set queue services set prio ( 4, 6 ) -#pass in quick proto tcp to (egress:0) port { www, https } set prio ( 4, 6 ) +pass in quick proto tcp to (egress:0) port { www, https } set prio ( 4, 6 ) # Port redirection -pass in quick proto tcp to (egress:0) port { smtp, submission, imaps, www, https } rdr-to host01.shore.co.il set queue critical set prio ( 4, 6 ) -pass out quick proto tcp to host01.shore.co.il port { submission, smtp, imaps, www, https } received-on ingress nat-to ingress set prio ( 4, 6 ) -#pass in quick proto tcp to (egress:0) port { smtp, submission, imaps } rdr-to host01.shore.co.il set queue critical set prio ( 4, 6 ) -#pass out quick proto tcp to host01.shore.co.il port { submission, smtp, imaps } received-on ingress nat-to ingress set prio ( 4, 6 ) +pass in quick proto tcp to (egress:0) port { smtp, submission, imaps } rdr-to host01.shore.co.il set queue critical set prio ( 4, 6 ) +pass out quick proto tcp to host01.shore.co.il port { submission, smtp, imaps } received-on ingress nat-to ingress set prio ( 4, 6 ) pass in quick proto { tcp, udp } to (egress:0) port bittorrent rdr-to kodi.shore.co.il set queue bulk set prio 1 # Allowd NAT and proxying diff --git a/roles/router/handlers/main.yaml b/roles/router/handlers/main.yaml index cf1a557..f5409e7 100644 --- a/roles/router/handlers/main.yaml +++ b/roles/router/handlers/main.yaml @@ -11,6 +11,11 @@ command: cmd: newaliases +- name: Restart HAProxy + service: + name: haproxy + state: restarted + - name: Restart NSD service: name: nsd diff --git a/roles/router/tasks/main.yaml b/roles/router/tasks/main.yaml index e21666a..c7177c9 100644 --- a/roles/router/tasks/main.yaml +++ b/roles/router/tasks/main.yaml @@ -135,6 +135,30 @@ - dns - network +- name: Configure HAProxy + copy: + backup: true + dest: /etc/haproxy/haproxy.cfg + mode: preserve + src: haproxy.cfg + validate: haproxy -c -f %s + notify: + - Restart HAProxy + tags: + - haproxy + - web + - network + +- name: Enable HAProxy + service: + enabled: true + name: haproxy + state: started + tags: + - haproxy + - web + - network + - name: Configure PF copy: dest: /etc/pf.conf @@ -169,6 +193,7 @@ - curl - git - go + - haproxy community.general.openbsd_pkg: name: '{{ item }}' state: present -- GitLab