From 8e10d9adeb7764979ccc2cdbe12dad65c7f6e7b6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 9 Mar 2025 13:17:49 +0100 Subject: [PATCH] added headscale state --- states/headscale/config.sls | 29 +++++ states/headscale/defaults.yaml | 106 ++++++++++++++++++ states/headscale/init.sls | 5 + states/headscale/install.sls | 50 +++++++++ states/headscale/kernelmap.yaml | 3 + states/headscale/map.jinja | 14 +++ states/headscale/osarchmap.yaml | 24 ++++ states/headscale/service.sls | 15 +++ states/headscale/templates/config.yaml.j2 | 4 + states/headscale/templates/derp.yaml.j2 | 4 + .../headscale/templates/headscale.service.j2 | 51 +++++++++ 11 files changed, 305 insertions(+) create mode 100644 states/headscale/config.sls create mode 100644 states/headscale/defaults.yaml create mode 100644 states/headscale/init.sls create mode 100644 states/headscale/install.sls create mode 100644 states/headscale/kernelmap.yaml create mode 100644 states/headscale/map.jinja create mode 100644 states/headscale/osarchmap.yaml create mode 100644 states/headscale/service.sls create mode 100644 states/headscale/templates/config.yaml.j2 create mode 100644 states/headscale/templates/derp.yaml.j2 create mode 100644 states/headscale/templates/headscale.service.j2 diff --git a/states/headscale/config.sls b/states/headscale/config.sls new file mode 100644 index 0000000..09f1622 --- /dev/null +++ b/states/headscale/config.sls @@ -0,0 +1,29 @@ +--- +headscale-configpath-dir: + file.directory: + - name: {{ headscale.config_path }} + - user: {{ headscale.user.uid }} + - group: {{ headscale.group.gid }} + - makedirs: true + - watch_in: + - service: headscale-service + +headscale-config: + file.managed: + - name: {{ headscale.config_path }}/config.yaml + - source: salt://headscale/templates/config.yml.j2 + - user: {{ headscale.user.uid }} + - group: {{ headscale.group.gid }} + - template: jinja + - watch_in: + - service: headscale-service + +headscale-config-derp: + file.managed: + - name: {{ headscale.config_path }}/derp.yaml + - source: salt://headscale/templates/derp.yml.j2 + - user: {{ headscale.user.uid }} + - group: {{ headscale.group.gid }} + - template: jinja + - watch_in: + - service: headscale-service diff --git a/states/headscale/defaults.yaml b/states/headscale/defaults.yaml new file mode 100644 index 0000000..7845115 --- /dev/null +++ b/states/headscale/defaults.yaml @@ -0,0 +1,106 @@ +--- +headscale: + enabled: true + mirror: "https://github.com/juanfont/headscale/releases/download" + install_dir: "/usr/local/apps" + release_dir: "/usr/local/apps/releases" + config_path: "/etc/headscale" + var_dir: "/var/lib/headscale" + version: "0.25.1" + os: linux + arch: amd64 + user: + name: headscale + uid: 915 + group: + name: headscale + gid: 915 + config: + server_url: http://127.0.0.1:8080 + listen_addr: 127.0.0.1:8080 + metrics_listen_addr: 127.0.0.1:9090 + grpc_listen_addr: 127.0.0.1:50443 + grpc_allow_insecure: false + noise: + private_key_path: /var/lib/headscale/noise_private.key + prefixes: + v4: 100.64.0.0/10 + v6: fd7a:115c:a1e0::/48 + allocation: sequential + derp: + server: + enabled: false + region_id: 999 + region_code: "headscale" + region_name: "Headscale Embedded DERP" + stun_listen_addr: "0.0.0.0:3478" + private_key_path: /var/lib/headscale/derp_server_private.key + automatically_add_embedded_derp_region: true + ipv4: 1.2.3.4 + ipv6: 2001:db8::1 + urls: + - https://controlplane.tailscale.com/derpmap/default + paths: [] + auto_update_enabled: true + update_frequency: 24h + disable_check_updates: false + ephemeral_node_inactivity_timeout: 30m + database: + type: sqlite + debug: false + gorm: + prepare_stmt: true + parameterized_queries: true + skip_err_record_not_found: true + slow_threshold: 1000 + sqlite: + path: /var/lib/headscale/db.sqlite + write_ahead_log: true + wal_autocheckpoint: 1000 + acme_url: https://acme-v02.api.letsencrypt.org/directory + acme_email: "" + tls_letsencrypt_hostname: "" + tls_letsencrypt_cache_dir: /var/lib/headscale/cache + tls_letsencrypt_challenge_type: HTTP-01 + tls_letsencrypt_listen: ":http" + tls_cert_path: "" + tls_key_path: "" + log: + format: text + level: info + policy: + mode: file + path: "" + dns: + magic_dns: true + base_domain: example.com + nameservers: + global: + - 1.1.1.1 + - 1.0.0.1 + - 2606:4700:4700::1111 + - 2606:4700:4700::1001 + split: + {} + search_domains: [] + extra_records: [] + unix_socket: /var/run/headscale/headscale.sock + unix_socket_permission: "0770" + logtail: + enabled: false + randomize_client_port: false + derp_config: + regions: + 900: + regionid: 900 + regioncode: custom + regionname: My Region + nodes: + - name: 900a + regionid: 900 + hostname: myderp.mydomain.no + ipv4: 123.123.123.123 + ipv6: "2604:a880:400:d1::828:b001" + stunport: 0 + stunonly: false + derpport: 0 diff --git a/states/headscale/init.sls b/states/headscale/init.sls new file mode 100644 index 0000000..63261f2 --- /dev/null +++ b/states/headscale/init.sls @@ -0,0 +1,5 @@ +--- +include: + - .install + - .config + - .service \ No newline at end of file diff --git a/states/headscale/install.sls b/states/headscale/install.sls new file mode 100644 index 0000000..83c601f --- /dev/null +++ b/states/headscale/install.sls @@ -0,0 +1,50 @@ +--- +{%- from "headscale/map.jinja" import headscale with context %} +headscale-group: + group.present: + - name: headscale + - gid: {{ headscale.group.gid }} + - watch_in: + - service: headscale-service + +headscale-user: + user.present: + - name: headscale + - uid: {{ headscale.user.uid }} + - gid: {{ headscale.group.gid }} + - allow_uid_change: true + - allow_gid_change: true + - home: /var/lib/headscale + - watch_in: + - service: headscale-service + +headscale-release-dir: + file.directory: + - name: {{ headscale.release_dir }}/headscale-{{ headscale.version }} + +headscale-install-dir: + file.directory: + - name: {{ headscale.release_install }} + +headscale-bin-download: + file.managed: + - name: {{ headscale.release_dir }}/headscale-{{ headscale.version }}/headscale + - source: {{ headscale.mirror }}/v{{ headscale.version }}/headscale_{{ headscale.version }}_{{ headscale.os }}_{{ headscale.arch }} + - skip_verify: true + - user: root + - group: root + - if_missing: {{ headscale.release_dir }}/headscale-{{ headscale.version }}/headscale + - watch_in: + - service: headscale-service + +headscale-bin-symlink: + file.symlink: + - name: {{ headscale.install_dir }}/headscale + - target: {{ headscale.release_dir }}/headscale-{{ headscale.version }}/headscale + - force: true + +headscale-cleanup: + software.cleanup: + - name: headscale + - path: {{ headscale.release_dir }} + - version: "{{ headscale.version }}" diff --git a/states/headscale/kernelmap.yaml b/states/headscale/kernelmap.yaml new file mode 100644 index 0000000..40943f2 --- /dev/null +++ b/states/headscale/kernelmap.yaml @@ -0,0 +1,3 @@ +--- +Linux: + os: "linux" diff --git a/states/headscale/map.jinja b/states/headscale/map.jinja new file mode 100644 index 0000000..d640cda --- /dev/null +++ b/states/headscale/map.jinja @@ -0,0 +1,14 @@ +{%- import_yaml "headscale/defaults.yaml" as default_settings -%} + +{%- import_yaml "headscale/kernelmap.yaml" as kernelmap -%} +{%- import_yaml "headscale/osarchmap.yaml" as osarchmap -%} + +{%- set defaults = salt['grains.filter_by'](default_settings, + default='headscale', + merge=salt['grains.filter_by'](osarchmap, grain='osarch', + merge=salt['grains.filter_by'](kernelmap, grain='kernel') + ) + ) +-%} + +{%- set headscale = salt['pillar.get']('headscale', default=defaults, merge=True) -%} \ No newline at end of file diff --git a/states/headscale/osarchmap.yaml b/states/headscale/osarchmap.yaml new file mode 100644 index 0000000..05f0f25 --- /dev/null +++ b/states/headscale/osarchmap.yaml @@ -0,0 +1,24 @@ +--- +amd64: + arch: "amd64" + +x86_64: + arch: "amd64" + +386: + arch: "386" + +arm64: + arch: "arm64" + +aarch64: + arch: "arm64" + +armv6l: + arch: "arm" + +armv7l: + arch: "arm" + +armhf: + arch: "arm" diff --git a/states/headscale/service.sls b/states/headscale/service.sls new file mode 100644 index 0000000..71b37f4 --- /dev/null +++ b/states/headscale/service.sls @@ -0,0 +1,15 @@ +--- +{%- from "headscale/map.jinja" import headscale with context %} +headscale-service-file: + file.managed: + - name: /etc/systemd/system/headscale.service + - source: salt://headscale/templates/headscale.service.j2 + - user: root + - group: root + - mode: 644 + - template: jinja + +headscale-service: + service.{{ 'running' if headscale.enabled else 'dead' }}: + - name: headscale + - enable: {{ headscale.enabled }} diff --git a/states/headscale/templates/config.yaml.j2 b/states/headscale/templates/config.yaml.j2 new file mode 100644 index 0000000..7ef5721 --- /dev/null +++ b/states/headscale/templates/config.yaml.j2 @@ -0,0 +1,4 @@ +{%- from "headscale/map.jinja" import headscale with context -%} +## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }} +--- +{{ headscale.config|yaml(False) }} diff --git a/states/headscale/templates/derp.yaml.j2 b/states/headscale/templates/derp.yaml.j2 new file mode 100644 index 0000000..a6f70c0 --- /dev/null +++ b/states/headscale/templates/derp.yaml.j2 @@ -0,0 +1,4 @@ +{%- from "headscale/map.jinja" import headscale with context -%} +## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }} +--- +{{ headscale.derp_config|yaml(False) }} diff --git a/states/headscale/templates/headscale.service.j2 b/states/headscale/templates/headscale.service.j2 new file mode 100644 index 0000000..89e9e36 --- /dev/null +++ b/states/headscale/templates/headscale.service.j2 @@ -0,0 +1,51 @@ +{%- from "headscale/map.jinja" import headscale with context -%} +## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }} +[Unit] +After=syslog.target +After=network.target +Description=headscale coordination server for Tailscale +X-Restart-Triggers=/etc/headscale/config.yaml + +[Service] +Type=simple +User={{ headscale.user.name }} +Group={{ headscale.group.name }} +LimitNOFILE=65536 +ExecStart={{ headscale.install_dir }}/headscale/headscale serve +ExecReload=/usr/bin/kill -HUP $MAINPID +Restart=always +RestartSec=5 +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN +LockPersonality=true +NoNewPrivileges=true +PrivateDevices=true +PrivateMounts=true +PrivateTmp=true +ProcSubset=pid +ProtectClock=true +ProtectControlGroups=true +ProtectHome=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectProc=invisible +ProtectSystem=strict +RemoveIPC=true +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +RestrictNamespaces=true +RestrictRealtime=true +RestrictSUIDSGID=true +RuntimeDirectory=headscale +RuntimeDirectoryMode=0750 +StateDirectory=headscale +StateDirectoryMode=0750 +SystemCallArchitectures=native +SystemCallFilter=@chown +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +UMask=0077 + +[Install] +WantedBy=multi-user.target