diff --git a/modules/kubernetes/keyserver/deploy_keyserver.yaml b/modules/kubernetes/keyserver/deploy_keyserver.yaml new file mode 100644 index 00000000..fe721bc0 --- /dev/null +++ b/modules/kubernetes/keyserver/deploy_keyserver.yaml @@ -0,0 +1,155 @@ +# @nocommit: job to periodically update the certs +--- +- name: Deploy Nginx-based key server for TrueNAS unlock + hosts: keyserver + become: true + vars: + server_name: "keyserver.viktorbarzin.me" + key_filename: "truenas.key" + htpasswd_user: "truenas" + htpasswd_password: "EcDZgBnUtGM09qiUXts81HjHybM" # replace with vault + ssl_cert_path: "/etc/ssl/certs/keyserver.crt" + ssl_key_path: "/etc/ssl/private/keyserver.key" + local_ssl_cert: "../../../secrets/fullchain.pem" # LOCAL path + local_ssl_key: "../../../secrets/privkey.pem" # LOCAL path + + tasks: + + - name: Install packages + apt: + name: + - nginx + - apache2-utils + - python3-passlib + state: present + update_cache: yes + + - name: Create basic-auth file + community.general.htpasswd: + path: /etc/nginx/.htpasswd + name: "{{ htpasswd_user }}" + password: "{{ htpasswd_password }}" + crypt_scheme: bcrypt + + - name: Create key directory + file: + path: /srv/keys + state: directory + owner: root + group: root + mode: '0755' + + - name: Create key file if it doesn't exist + command: "head -c 128 /dev/urandom > /srv/keys/{{ key_filename }}" + args: + creates: "/srv/keys/{{ key_filename }}" + + - name: Set key file permissions + file: + path: "/srv/keys/{{ key_filename }}" + owner: www-data + group: www-data + mode: '0640' + + - name: Enable info logging in nginx.conf + lineinfile: + path: /etc/nginx/nginx.conf + regexp: '^(\s*)error_log' + line: ' error_log /var/log/nginx/error.log info;' + insertafter: 'http {' + notify: reload nginx + + - name: Ensure rate limit config exists + copy: + dest: /etc/nginx/conf.d/ratelimit.conf + content: | + limit_req_zone $binary_remote_addr zone=authfail:10m rate=5r/m; + notify: reload nginx + + - name: Deploy keyserver nginx site + copy: + dest: /etc/nginx/sites-available/keyserver.conf + content: | + server { + listen 443 ssl; + server_name {{ server_name }}; + + ssl_certificate {{ ssl_cert_path }}; + ssl_certificate_key {{ ssl_key_path }}; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + limit_req zone=authfail burst=2 nodelay; + + location /keys/ { + alias /srv/keys/; + + auth_basic "Restricted"; + auth_basic_user_file /etc/nginx/.htpasswd; + + autoindex off; + + add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always; + } + } + notify: reload nginx + + - name: Enable keyserver site + file: + src: /etc/nginx/sites-available/keyserver.conf + dest: /etc/nginx/sites-enabled/keyserver.conf + state: link + notify: reload nginx + + - name: Remove default site + file: + path: /etc/nginx/sites-enabled/default + state: absent + notify: reload nginx + + - name: Copy SSL certificate to server + copy: + src: "{{ local_ssl_cert }}" + dest: "{{ ssl_cert_path }}" + owner: root + group: root + mode: '0644' + notify: reload nginx + + - name: Copy SSL private key to server + copy: + src: "{{ local_ssl_key }}" + dest: "{{ ssl_key_path }}" + owner: root + group: root + mode: '0644' + notify: reload nginx + + # - name: Create self-signed SSL certificate if missing + # command: > + # openssl req -x509 -newkey rsa:2048 -nodes + # -keyout {{ ssl_key_path }} + # -out {{ ssl_cert_path }} + # -days 365 + # -subj "/CN={{ server_name }}" + # args: + # creates: "{{ ssl_cert_path }}" + notify: reload nginx + + - name: Test nginx config + command: nginx -t + register: nginx_test + failed_when: "'successful' not in nginx_test.stderr" + + - name: Ensure nginx is running + service: + name: nginx + state: started + enabled: true + + handlers: + - name: reload nginx + service: + name: nginx + state: reloaded diff --git a/modules/kubernetes/keyserver/index.md b/modules/kubernetes/keyserver/index.md new file mode 100644 index 00000000..8b6a7b66 --- /dev/null +++ b/modules/kubernetes/keyserver/index.md @@ -0,0 +1,73 @@ +This contains the setup for setting up a remote machine that serves a keyfile for decrypting a luks volume + +1. Install nginx +``` +sudo apt update +sudo apt install nginx apache2-utils -y +``` + +2. Create User for basic auth + +``` +sudo htpasswd -c /etc/nginx/.htpasswd truenas +``` + +3. Create secure directory and key file + +``` +sudo mkdir -p /srv/keys +head -c 128 /dev/urandom | sudo tee /srv/keys/truenas.key >/dev/null +``` + +4. Create rate limit zone +``` +# /etc/nginx/conf.d/ratelimit.conf + +# Allow only 3 key requests per minute per IP +limit_req_zone $binary_remote_addr zone=keylimit:10m rate=3r/m; +``` + +5. Configure nginx virtual host +``` +# /etc/nginx/sites-available/keyserver.conf + +server { + listen 443 ssl; + server_name ; + + # TLS certificate and key (we will set these in the next step) + ssl_certificate /etc/ssl/certs/keyserver.crt; + ssl_certificate_key /etc/ssl/private/keyserver.key; + + # Enforce strong TLS + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + # Rate limiting zone created earlier + limit_req zone=keylimit burst=2 nodelay; + + location /keys/ { + alias /srv/keys/; + + # Basic auth + auth_basic "Restricted"; + auth_basic_user_file /etc/nginx/.htpasswd; + + # Disable directory listing + autoindex off; + + # Prevent caching + add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always; + } +} +``` + +6. Enable the host: +``` +sudo ln -s /etc/nginx/sites-available/keyserver.conf /etc/nginx/sites-enabled/ +``` + +7. Disable default host: +``` +sudo rm /etc/nginx/sites-enabled/default +``` diff --git a/modules/kubernetes/keyserver/inventory.ini b/modules/kubernetes/keyserver/inventory.ini new file mode 100644 index 00000000..55ba5d2e --- /dev/null +++ b/modules/kubernetes/keyserver/inventory.ini @@ -0,0 +1,2 @@ +[keyserver] +130.162.165.220 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_ed25519 diff --git a/terraform.tfstate b/terraform.tfstate index 4fd24c7a..71b944b2 100644 Binary files a/terraform.tfstate and b/terraform.tfstate differ