From c9456f3e1f4c742843f40415ec960e67a5c455cd Mon Sep 17 00:00:00 2001 From: les Date: Mon, 28 Sep 2020 23:25:35 +0200 Subject: [PATCH] add caddy role --- roles/caddy/defaults/main.yml | 33 +++++++ roles/caddy/handlers/main.yml | 12 +++ roles/caddy/tasks/github-extract.yml | 21 ++++ roles/caddy/tasks/github-url.yml | 20 ++++ roles/caddy/tasks/main.yml | 134 ++++++++++++++++++++++++++ roles/caddy/tasks/packages-apt.yml | 18 ++++ roles/caddy/tasks/packages-dnf.yml | 1 + roles/caddy/tasks/packages-pacman.yml | 1 + roles/caddy/tasks/packages-yum.yml | 1 + roles/caddy/tasks/preflight.yml | 17 ++++ roles/caddy/templates/caddy.service | 73 ++++++++++++++ roles/caddy/vars/main.yml | 21 ++++ tests/caddy/Vagrantfile | 8 ++ tests/caddy/caddy.yml | 6 ++ tests/caddy/roles | 1 + 15 files changed, 367 insertions(+) create mode 100644 roles/caddy/defaults/main.yml create mode 100644 roles/caddy/handlers/main.yml create mode 100644 roles/caddy/tasks/github-extract.yml create mode 100644 roles/caddy/tasks/github-url.yml create mode 100644 roles/caddy/tasks/main.yml create mode 100644 roles/caddy/tasks/packages-apt.yml create mode 100644 roles/caddy/tasks/packages-dnf.yml create mode 100644 roles/caddy/tasks/packages-pacman.yml create mode 100644 roles/caddy/tasks/packages-yum.yml create mode 100644 roles/caddy/tasks/preflight.yml create mode 100644 roles/caddy/templates/caddy.service create mode 100644 roles/caddy/vars/main.yml create mode 100644 tests/caddy/Vagrantfile create mode 100644 tests/caddy/caddy.yml create mode 120000 tests/caddy/roles diff --git a/roles/caddy/defaults/main.yml b/roles/caddy/defaults/main.yml new file mode 100644 index 0000000..d4fc3dd --- /dev/null +++ b/roles/caddy/defaults/main.yml @@ -0,0 +1,33 @@ +--- +# defaults file for caddy-ansible +caddy_user: www-data +caddy_home: /home/caddy +caddy_packages: [] +caddy_update: true +caddy_bin_dir: /usr/local/bin +caddy_conf_dir: /etc/caddy +caddy_github_token: "" +caddy_log_dir: /var/log/caddy +caddy_log_file: stdout +caddy_certs_dir: /etc/ssl/caddy +caddy_http2_enabled: "true" +# additional cli args to pass to caddy +caddy_additional_args: "" +caddy_systemd_network_dependency: true +caddy_systemd_capabilities_enabled: false +caddy_systemd_capabilities: "CAP_NET_BIND_SERVICE" +caddy_systemd_restart: "on-failure" # always, on-success, on-failure, on-abnormal, on-abort, on-watchdog +caddy_systemd_restart_startlimitinterval: "86400" +caddy_systemd_restart_startlimitburst: "5" +caddy_systemd_private_tmp: "true" +caddy_systemd_private_devices: "true" +# Disable this because the git module writes to ~/.ssh +caddy_systemd_protect_home: "false" +caddy_systemd_protect_system: "full" +caddy_systemd_nproc_limit: 0 +caddy_setcap: true +caddy_config: | + http://localhost:2020 + respond "Hello, world!" +caddy_environment_variables: {} +caddy_os: linux diff --git a/roles/caddy/handlers/main.yml b/roles/caddy/handlers/main.yml new file mode 100644 index 0000000..c889ddf --- /dev/null +++ b/roles/caddy/handlers/main.yml @@ -0,0 +1,12 @@ +--- + +- name: Restart caddy + systemd: + daemon_reload: true + name: caddy + state: restarted + +- name: Reload caddy + systemd: + name: caddy + state: reloaded diff --git a/roles/caddy/tasks/github-extract.yml b/roles/caddy/tasks/github-extract.yml new file mode 100644 index 0000000..6c18697 --- /dev/null +++ b/roles/caddy/tasks/github-extract.yml @@ -0,0 +1,21 @@ +--- +- name: Extract Caddy + unarchive: + src: "{{ caddy_home }}/caddy.tar.gz" + dest: "{{ caddy_home }}" + copy: false + mode: 0644 + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" + when: caddy_binary_cache.changed + tags: skip_ansible_lint + +- name: Extract Caddy + unarchive: + src: "{{ caddy_home }}/caddy.tar.gz" + dest: "{{ caddy_home }}" + creates: "{{ caddy_home }}/caddy" + copy: false + mode: 0644 + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" diff --git a/roles/caddy/tasks/github-url.yml b/roles/caddy/tasks/github-url.yml new file mode 100644 index 0000000..8034685 --- /dev/null +++ b/roles/caddy/tasks/github-url.yml @@ -0,0 +1,20 @@ +--- +- name: Get latest Caddy release details + uri: + url: https://api.github.com/repos/mholt/caddy/releases/latest + return_content: true + headers: '{{ caddy_github_headers }}' + register: latest_caddy_release + +- name: Set Caddy tag + set_fact: + caddy_tag: "{{ (latest_caddy_release.content | from_json).get('tag_name') }}" + +- name: Set Caddy version + set_fact: + caddy_version: "{{ caddy_tag | regex_replace('^v', '') }}" + +- name: Set Caddy url + set_fact: + caddy_url: "https://github.com/caddyserver/caddy/releases/download/\ + {{ caddy_tag }}/caddy_{{ caddy_version }}_{{ caddy_os }}_{{ go_arch }}.tar.gz" diff --git a/roles/caddy/tasks/main.yml b/roles/caddy/tasks/main.yml new file mode 100644 index 0000000..472b45f --- /dev/null +++ b/roles/caddy/tasks/main.yml @@ -0,0 +1,134 @@ +--- +- include: preflight.yml +- include: packages-{{ ansible_pkg_mgr }}.yml + +- name: Create Caddy user + user: + name: "{{ caddy_user }}" + system: true + createhome: true + home: "{{ caddy_home }}" + register: caddy_user_details + +- name: Build headers to use when making requests to github + set_fact: + caddy_github_headers: "{{ caddy_github_headers | combine({'Authorization': 'token ' + caddy_github_token}) }}" + when: caddy_github_token | length > 0 + +- name: Get all Caddy releases + get_url: + url: https://api.github.com/repos/mholt/caddy/git/refs/tags + dest: "{{ caddy_home }}/releases.txt" + force: true + headers: '{{ caddy_github_headers }}' + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" + retries: 3 + delay: 2 + when: caddy_update + register: caddy_releases_cache + +- name: Set Caddy features + copy: + content: "{{ ','.join(caddy_packages) }}" + dest: "{{ caddy_home }}/features.txt" + mode: 0640 + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" + when: caddy_update + register: caddy_features_cache + +- include: github-url.yml + when: caddy_use_github + +- name: Download Caddy + get_url: + url: "{{ caddy_url }}" + dest: "{{ caddy_home }}/{{ 'caddy.tar.gz' if caddy_use_github else 'caddy' }}" + force: true + timeout: 300 + mode: 0644 + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" + retries: 3 + delay: 2 + when: caddy_releases_cache.changed or caddy_features_cache.changed + register: caddy_binary_cache + tags: skip_ansible_lint + +- name: Download Caddy + get_url: + url: "{{ caddy_url }}" + dest: "{{ caddy_home }}/{{ 'caddy.tar.gz' if caddy_use_github else 'caddy' }}" + timeout: 300 + mode: 0644 + owner: "{{ caddy_user }}" + group: "{{ caddy_user_details.group }}" + retries: 3 + delay: 2 + register: caddy_download + tags: skip_ansible_lint + +- include: github-extract.yml + when: caddy_use_github + +- name: Copy Caddy Binary + copy: + src: "{{ caddy_home }}/caddy" + dest: "{{ caddy_bin }}" + mode: 0755 + remote_src: true + notify: + - Restart caddy + +- name: Create directories + file: + path: "{{ item }}" + state: directory + owner: "{{ caddy_user }}" + mode: 0770 + with_items: + - "{{ caddy_conf_dir }}" + - "{{ caddy_certs_dir }}" + +- name: Create log directory + file: + path: "{{ caddy_log_dir }}" + state: directory + owner: "{{ caddy_user }}" + mode: 0775 + +- name: Create Caddyfile + copy: + content: "{{ caddy_config }}" + dest: "{{ caddy_conf_dir }}/Caddyfile" + owner: "{{ caddy_user }}" + mode: 0640 + notify: + - Reload caddy + +- name: Template systemd service + template: + src: caddy.service + dest: /etc/systemd/system/caddy.service + owner: root + group: root + mode: 0644 + notify: + - Restart caddy + +- name: Set capability on the binary file to be able to bind to TCP port <1024 + capabilities: + path: "{{ caddy_bin }}" + capability: cap_net_bind_service+eip + state: present + when: caddy_setcap + +- name: Ensue caddy service is up-to-date before starting it + meta: flush_handlers + +- name: Start Caddy service + systemd: + name: caddy + state: started + enabled: true diff --git a/roles/caddy/tasks/packages-apt.yml b/roles/caddy/tasks/packages-apt.yml new file mode 100644 index 0000000..66a4707 --- /dev/null +++ b/roles/caddy/tasks/packages-apt.yml @@ -0,0 +1,18 @@ +--- + +- name: Update cache + apt: + update_cache: true + cache_valid_time: 43200 # 12 hours + +# This is required because it provides the /bin/kill binary used in the service file +- name: Install procps + apt: + name: procps + state: present + +- name: Install libcap + apt: + name: libcap2-bin + state: present + when: caddy_setcap diff --git a/roles/caddy/tasks/packages-dnf.yml b/roles/caddy/tasks/packages-dnf.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/caddy/tasks/packages-dnf.yml @@ -0,0 +1 @@ +--- diff --git a/roles/caddy/tasks/packages-pacman.yml b/roles/caddy/tasks/packages-pacman.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/caddy/tasks/packages-pacman.yml @@ -0,0 +1 @@ +--- diff --git a/roles/caddy/tasks/packages-yum.yml b/roles/caddy/tasks/packages-yum.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/caddy/tasks/packages-yum.yml @@ -0,0 +1 @@ +--- diff --git a/roles/caddy/tasks/preflight.yml b/roles/caddy/tasks/preflight.yml new file mode 100644 index 0000000..1d8ccca --- /dev/null +++ b/roles/caddy/tasks/preflight.yml @@ -0,0 +1,17 @@ +--- +- name: Assert usage of systemd as an init system + assert: + that: ansible_service_mgr == 'systemd' + msg: "This module only works with systemd" + +- name: Get systemd version + command: systemctl --version + changed_when: false + check_mode: false + register: __systemd_version + tags: + - skip_ansible_lint + +- name: Set systemd version fact + set_fact: + caddy_systemd_version: "{{ __systemd_version.stdout_lines[0].split(' ')[-1] }}" diff --git a/roles/caddy/templates/caddy.service b/roles/caddy/templates/caddy.service new file mode 100644 index 0000000..d58ac55 --- /dev/null +++ b/roles/caddy/templates/caddy.service @@ -0,0 +1,73 @@ +{{ ansible_managed | comment(decoration="; ") }} +; source: https://github.com/mholt/caddy/blob/master/dist/init/linux-systemd/caddy.service +; version: 6be0386 +; changes: Set variables via Ansible + +[Unit] +Description=Caddy HTTP/2 web server +Documentation=https://caddyserver.com/docs +After=network-online.target +{% if caddy_systemd_network_dependency == true %} +Wants=network-online.target systemd-networkd-wait-online.service +{% endif %} +{% if caddy_systemd_version | int >= 230 %} +StartLimitIntervalSec={{ caddy_systemd_restart_startlimitinterval }} +StartLimitBurst={{ caddy_systemd_restart_startlimitburst }} +{% endif %} + +[Service] +Restart={{ caddy_systemd_restart }} +{% if caddy_systemd_version | int < 230 %} +StartLimitInterval={{ caddy_systemd_restart_startlimitinterval }} +StartLimitBurst={{ caddy_systemd_restart_startlimitburst }} +{% endif %} + +; User and group the process will run as. +User={{ caddy_user }} +Group={{ caddy_user }} + +; Letsencrypt-issued certificates will be written to this directory. +Environment=CADDYPATH={{ caddy_certs_dir }} + +ExecStart="{{ caddy_bin_dir }}/caddy" run --environ --config "{{ caddy_conf_dir }}/Caddyfile" {{ caddy_additional_args }} +ExecReload="{{ caddy_bin_dir }}/caddy" reload --config "{{ caddy_conf_dir }}/Caddyfile" + +; Limit the number of file descriptors; see `man systemd.exec` for more limit settings. +LimitNOFILE=1048576 +{% if caddy_systemd_nproc_limit > 0 %} +; Limit the number of caddy threads. +LimitNPROC={{ caddy_systemd_nproc_limit }} +{% endif %} + +; Use private /tmp and /var/tmp, which are discarded after caddy stops. +PrivateTmp={{ caddy_systemd_private_tmp }} +; Use a minimal /dev +PrivateDevices={{ caddy_systemd_private_devices }} +; Hide /home, /root, and /run/user. Nobody will steal your SSH-keys. +ProtectHome={{ caddy_systemd_protect_home }} +; Make /usr, /boot, /etc and possibly some more folders read-only. +ProtectSystem={{ caddy_systemd_protect_system }} +; … except {{ caddy_certs_dir }}, because we want Letsencrypt-certificates there. +; This merely retains r/w access rights, it does not add any new. Must still be writable on the host! +ReadWriteDirectories={{ caddy_certs_dir }} + +{% if caddy_systemd_capabilities_enabled %} +; The following additional security directives only work with systemd v229 or later. +; They further retrict privileges that can be gained by caddy. +; Note that you may have to add capabilities required by any plugins in use. +CapabilityBoundingSet={{ caddy_systemd_capabilities }} +AmbientCapabilities={{ caddy_systemd_capabilities }} +NoNewPrivileges=true + +{% endif %} +{% if caddy_environment_variables|length %} + +; Additional environment variables: + +{% for key, value in caddy_environment_variables.items() %} +Environment={{ key }}={{ value }} +{% endfor %} + +{% endif %} +[Install] +WantedBy=multi-user.target diff --git a/roles/caddy/vars/main.yml b/roles/caddy/vars/main.yml new file mode 100644 index 0000000..c0136e8 --- /dev/null +++ b/roles/caddy/vars/main.yml @@ -0,0 +1,21 @@ +--- +# vars file for caddy-ansible +caddy_github_headers: {} + +go_arch_map: + i386: '386' + x86_64: 'amd64' + aarch64: 'arm64' + armv7l: 'arm7' + armv6l: 'arm6' + +go_arch: "{{ go_arch_map[ansible_architecture] | default(ansible_architecture) }}" + +caddy_bin: "{{ caddy_bin_dir }}/caddy" + +caddy_url: "https://caddyserver.com/api/download?os={{ caddy_os }}&arch={{ go_arch }}\ + {% for pkg in caddy_packages %}\ + {% if loop.first %}&{% endif %}p={{ pkg | urlencode() }}{% if not loop.last %},{% endif %}\ + {% endfor %}" + +caddy_use_github: "{{ caddy_packages == [] }}" diff --git a/tests/caddy/Vagrantfile b/tests/caddy/Vagrantfile new file mode 100644 index 0000000..270d0ab --- /dev/null +++ b/tests/caddy/Vagrantfile @@ -0,0 +1,8 @@ +Vagrant.configure("2") do |config| + config.vm.define :node do |node| + node.vm.box = "generic/debian10" + node.vm.provision "ansible" do |ansible| + ansible.playbook = "./nodejs.yml" + end + end +end diff --git a/tests/caddy/caddy.yml b/tests/caddy/caddy.yml new file mode 100644 index 0000000..2c657c0 --- /dev/null +++ b/tests/caddy/caddy.yml @@ -0,0 +1,6 @@ +--- +- name: caddy test + hosts: localhost + become: yes + roles: + - caddy diff --git a/tests/caddy/roles b/tests/caddy/roles new file mode 120000 index 0000000..148b132 --- /dev/null +++ b/tests/caddy/roles @@ -0,0 +1 @@ +../../roles/ \ No newline at end of file