From 217364bf5c612ac0ee1818419e47d4631aa42cfe Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Sun, 15 Oct 2023 23:30:44 +0200 Subject: initial version for whawty-auth app (WIP) --- inventory/host_vars/ch-apps.yml | 118 --------------------- inventory/host_vars/ch-apps/vars.yml | 118 +++++++++++++++++++++ inventory/host_vars/ch-apps/whawty.yml | 34 ++++++ roles/apps/whawty/auth/instance/tasks/main.yml | 101 ++++++++++++++++++ .../whawty/auth/instance/templates/pod-spec.yml.j2 | 69 ++++++++++++ .../whawty/auth/instance/templates/store.yml.j2 | 4 + .../whawty/auth/instance/templates/sync.toml.j2 | 8 ++ .../apps/whawty/auth/instance/templates/web.yml.j2 | 13 +++ roles/apps/whawty/auth/tasks/main.yml | 7 ++ 9 files changed, 354 insertions(+), 118 deletions(-) delete mode 100644 inventory/host_vars/ch-apps.yml create mode 100644 inventory/host_vars/ch-apps/vars.yml create mode 100644 inventory/host_vars/ch-apps/whawty.yml create mode 100644 roles/apps/whawty/auth/instance/tasks/main.yml create mode 100644 roles/apps/whawty/auth/instance/templates/pod-spec.yml.j2 create mode 100644 roles/apps/whawty/auth/instance/templates/store.yml.j2 create mode 100644 roles/apps/whawty/auth/instance/templates/sync.toml.j2 create mode 100644 roles/apps/whawty/auth/instance/templates/web.yml.j2 create mode 100644 roles/apps/whawty/auth/tasks/main.yml diff --git a/inventory/host_vars/ch-apps.yml b/inventory/host_vars/ch-apps.yml deleted file mode 100644 index e0a92644..00000000 --- a/inventory/host_vars/ch-apps.yml +++ /dev/null @@ -1,118 +0,0 @@ ---- -install_jumphost: ch-jump - -system_lvm_volume_size_root: 4G -install: - vm: - memory: 12G - numcpus: 8 - autostart: True - virtiofs: - music: - src: /srv/storage/music - dest: /srv/music - mnt_opts: ro - disks: - primary: /dev/sda - scsi: - sda: - type: zfs - name: root - size: 25g - sdb: - type: zfs - name: data - size: 100g - properties: - 'syncoid:sync': 'false' - interfaces: - - bridge: br-svc - name: svc0 - -network: - nameservers: "{{ network_zones.svc.dns }}" - domain: "{{ host_domain }}" - systemd_link: - interfaces: "{{ install.interfaces }}" - primary: &_network_primary_ - name: svc0 - address: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets[inventory_hostname]) }}" - gateway: "{{ network_zones.svc.gateway }}" - static_routes: - - destination: "{{ network_zones.lan.prefix }}" - gateway: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets['ch-gw-lan']) | ansible.utils.ipaddr('address') }}" - interfaces: - - *_network_primary_ - - -apt_repo_components: -- main -- contrib ## for zfs - -spreadspace_apt_repo_components: - - container - - prometheus - - -ssh_keys_root_extra: - - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBjZEFZLrl2KIqYl/GU8Vkp7mlhAbFbjwf4Ht9zQRmI8 ZFS Backup syncoid@epimetheus - - -prometheus_exporters_extra: - - standalone-kubelet - -prometheus_job_multitarget_blackbox__probe: - ch-mon: - - instance: "ssh-{{ inventory_hostname }}" - target: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}:{{ ansible_port | default(22) }}" - module: ssh_banner - - -zfs_arc_size: - min: 512MB - max: 2GB - -zfs_pools: - storage: - mountpoint: /srv/storage - create_vdevs: /dev/sdb - properties: - ashift: 12 - autotrim: "on" - -zfs_sanoid_modules: - storage: - use_template: production - recursive: yes - process_children_only: yes - storage/docker: - use_template: ignore - recursive: yes - storage/kubelet: - use_template: ignore - recursive: yes - - -docker_pkg_provider: docker-com - -docker_storage: - type: zfs - pool: storage - name: docker - properties: - quota: 10G - 'syncoid:sync': 'false' - -kubelet_storage: - type: zfs - pool: storage - name: kubelet - properties: - quota: 10G - 'syncoid:sync': 'false' - -kubernetes_version: 1.28.2 -kubernetes_cri_tools_pkg_version: 1.26.0-00 -kubernetes_container_runtime: docker -kubernetes_standalone_max_pods: 42 -kubernetes_standalone_cni_variant: with-portmap diff --git a/inventory/host_vars/ch-apps/vars.yml b/inventory/host_vars/ch-apps/vars.yml new file mode 100644 index 00000000..e0a92644 --- /dev/null +++ b/inventory/host_vars/ch-apps/vars.yml @@ -0,0 +1,118 @@ +--- +install_jumphost: ch-jump + +system_lvm_volume_size_root: 4G +install: + vm: + memory: 12G + numcpus: 8 + autostart: True + virtiofs: + music: + src: /srv/storage/music + dest: /srv/music + mnt_opts: ro + disks: + primary: /dev/sda + scsi: + sda: + type: zfs + name: root + size: 25g + sdb: + type: zfs + name: data + size: 100g + properties: + 'syncoid:sync': 'false' + interfaces: + - bridge: br-svc + name: svc0 + +network: + nameservers: "{{ network_zones.svc.dns }}" + domain: "{{ host_domain }}" + systemd_link: + interfaces: "{{ install.interfaces }}" + primary: &_network_primary_ + name: svc0 + address: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets[inventory_hostname]) }}" + gateway: "{{ network_zones.svc.gateway }}" + static_routes: + - destination: "{{ network_zones.lan.prefix }}" + gateway: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets['ch-gw-lan']) | ansible.utils.ipaddr('address') }}" + interfaces: + - *_network_primary_ + + +apt_repo_components: +- main +- contrib ## for zfs + +spreadspace_apt_repo_components: + - container + - prometheus + + +ssh_keys_root_extra: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBjZEFZLrl2KIqYl/GU8Vkp7mlhAbFbjwf4Ht9zQRmI8 ZFS Backup syncoid@epimetheus + + +prometheus_exporters_extra: + - standalone-kubelet + +prometheus_job_multitarget_blackbox__probe: + ch-mon: + - instance: "ssh-{{ inventory_hostname }}" + target: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}:{{ ansible_port | default(22) }}" + module: ssh_banner + + +zfs_arc_size: + min: 512MB + max: 2GB + +zfs_pools: + storage: + mountpoint: /srv/storage + create_vdevs: /dev/sdb + properties: + ashift: 12 + autotrim: "on" + +zfs_sanoid_modules: + storage: + use_template: production + recursive: yes + process_children_only: yes + storage/docker: + use_template: ignore + recursive: yes + storage/kubelet: + use_template: ignore + recursive: yes + + +docker_pkg_provider: docker-com + +docker_storage: + type: zfs + pool: storage + name: docker + properties: + quota: 10G + 'syncoid:sync': 'false' + +kubelet_storage: + type: zfs + pool: storage + name: kubelet + properties: + quota: 10G + 'syncoid:sync': 'false' + +kubernetes_version: 1.28.2 +kubernetes_cri_tools_pkg_version: 1.26.0-00 +kubernetes_container_runtime: docker +kubernetes_standalone_max_pods: 42 +kubernetes_standalone_cni_variant: with-portmap diff --git a/inventory/host_vars/ch-apps/whawty.yml b/inventory/host_vars/ch-apps/whawty.yml new file mode 100644 index 00000000..fe6bcea0 --- /dev/null +++ b/inventory/host_vars/ch-apps/whawty.yml @@ -0,0 +1,34 @@ +--- +whawty_auth_instances: + test: + version: 0.2-rc8 + port: 3080 + store: + default: 1 + params: + - id: 1 + argon2id: + time: 1 + memory: 65536 + threads: 4 + length: 32 + hostnames: + - passwd.example.com + tls: + certificate_provider: selfsigned + cert: + organization_name: "chaos-at-home" + organizational_unit_name: "ansible" + key_usage: + - digitalSignature + - keyAgreement + key_usage_critical: yes + extended_key_usage: + - serverAuth + extended_key_usage_critical: yes + create_subject_key_identifier: yes + not_after: +52w + renew_margin: +42d + sync: + port: 3022 + authorized_keys: "{{ users.equinox.ssh }}" diff --git a/roles/apps/whawty/auth/instance/tasks/main.yml b/roles/apps/whawty/auth/instance/tasks/main.yml new file mode 100644 index 00000000..2de99efa --- /dev/null +++ b/roles/apps/whawty/auth/instance/tasks/main.yml @@ -0,0 +1,101 @@ +--- +## TODO: add storage handling! +- set_fact: + whawty_auth_instance_basepath: "/srv/whawty/{{ whawty_auth_instance }}" +## + +## TODO: custom user + +- name: create instance directories + loop: + - config + - store + file: + path: "{{ whawty_auth_instance_basepath }}/{{ item }}" + state: directory + +- name: generate store config + template: + src: store.yml.j2 + dest: "{{ whawty_auth_instance_basepath }}/config/store.yml" + mode: 0400 + +- name: set up tls config + when: "'tls' in whawty_auth_instances[whawty_auth_instance]" + block: + - name: create tls directory + file: + path: "{{ whawty_auth_instance_basepath }}/config/tls" + state: directory + mode: 0400 + + - name: generate/install/fetch TLS certificate + vars: + x509_certificate_name: "whawty-auth-{{ whawty_auth_instance }}" + x509_certificate_hostnames: "{{ whawty_auth_instances[whawty_auth_instance].hostnames }}" + x509_certificate_renewal: + install: + - dest: "{{ whawty_auth_instance_basepath }}/config/tls/cert.pem" + src: + - fullchain + mode: "0400" + - dest: "{{ whawty_auth_instance_basepath }}/config/tls/key.pem" + src: + - key + mode: "0400" + reload: | + pod_id=$(crictl pods -q --state ready --name "^whawty-auth-{{ whawty_auth_instance }}-{{ ansible_nodename }}$") + [ -n "$pod_id" ] || exit 0 + container_id=$(crictl ps -q --name '^app$' -p "$pod_id") + [ -n "$container_id" ] || exit 0 + crictl stop "$container_id" + include_role: + name: "x509/{{ whawty_auth_instances[whawty_auth_instance].tls.certificate_provider }}/cert" + + - name: generate store config + template: + src: web.yml.j2 + dest: "{{ whawty_auth_instance_basepath }}/config/web.yml" + mode: 0400 + +- name: set up sync config + when: "'sync' in whawty_auth_instances[whawty_auth_instance]" + block: + - name: create sync directory + file: + path: "{{ whawty_auth_instance_basepath }}/sync/gokr-rsyncd" + state: directory + + - name: generate sync config + template: + src: sync.toml.j2 + dest: "{{ whawty_auth_instance_basepath }}/sync/config.toml" + + - name: generate authorized_keys for sync + copy: + content: "{{ whawty_auth_instances[whawty_auth_instance].sync.authorized_keys | join('\n') }}\n" + dest: "{{ whawty_auth_instance_basepath }}/sync/authorized_keys" + + - name: generate ssh host key for sync + command: "ssh-keygen -q -t ed25519 -f '{{ whawty_auth_instance_basepath }}/sync/gokr-rsyncd/ssh_host_ed25519_key' -C '' -N ''" + args: + creates: "{{ whawty_auth_instance_basepath }}/sync/gokr-rsyncd/ssh_host_ed25519_key" + +- name: install pod manifest + vars: + whawty_auth_instance_config_hash_items__yaml: | + - path: "{{ whawty_auth_instance_basepath }}/config/store.yml" + {% if 'tls' in whawty_auth_instances[whawty_auth_instance] %} + - path: "{{ whawty_auth_instance_basepath }}/config/web.yml" + {% endif %} + {% if 'sync' in whawty_auth_instances[whawty_auth_instance] %} + - path: "{{ whawty_auth_instance_basepath }}/sync/config.toml" + - path: "{{ whawty_auth_instance_basepath }}/sync/authorized_keys" + - path: "{{ whawty_auth_instance_basepath }}/sync/gokr-rsyncd/ssh_host_ed25519_key" + {% endif %} + kubernetes_standalone_pod: + name: "whawty-auth-{{ whawty_auth_instance }}" + spec: "{{ lookup('template', 'pod-spec.yml.j2') }}" + config_hash_items: "{{ whawty_auth_instance_config_hash_items__yaml | from_yaml }}" + include_role: + name: kubernetes/standalone/pod diff --git a/roles/apps/whawty/auth/instance/templates/pod-spec.yml.j2 b/roles/apps/whawty/auth/instance/templates/pod-spec.yml.j2 new file mode 100644 index 00000000..45c692e9 --- /dev/null +++ b/roles/apps/whawty/auth/instance/templates/pod-spec.yml.j2 @@ -0,0 +1,69 @@ +securityContext: + allowPrivilegeEscalation: false +{# runAsUser: {{ whawty_auth_app_uid }} #} +{# runAsGroup: {{ whawty_auth_app_gid }} #} +containers: +- name: app + image: "ghcr.io/whawty/auth/app:v{{ whawty_auth_instances[whawty_auth_instance].version }}" + args: + - "--store" + - "/config/store.yml" + - "run" + - "--web-addr" + - ":{{ whawty_auth_instances[whawty_auth_instance].port }}" +{% if 'tls' in whawty_auth_instances[whawty_auth_instance] %} + - "--web-config" + - "/config/web.yml" +{% endif %} + volumeMounts: + - name: config + mountPath: /config + readOnly: true + - name: store + mountPath: /store + env: +{# TODO: remove debug output #} + - name: WHAWTY_AUTH_DEBUG + value: "1" + ports: + - containerPort: {{ whawty_auth_instances[whawty_auth_instance].port }} + hostPort: {{ whawty_auth_instances[whawty_auth_instance].port }} +{% if 'sync' in whawty_auth_instances[whawty_auth_instance] %} +- name: sync + image: "ghcr.io/whawty/auth/sync:v{{ whawty_auth_instances[whawty_auth_instance].version }}" + command: + - "/gokr-rsyncd" + args: + - "--daemon" + - "--gokr.config=/sync/config.toml" +{# TODO: remove debug output #} + - "-v" + volumeMounts: + - name: sync + mountPath: /sync + readOnly: true + - name: store + mountPath: /store + readOnly: true + env: + - name: XDG_CONFIG_HOME + value: "/sync" + ports: + - containerPort: {{ whawty_auth_instances[whawty_auth_instance].sync.port }} + hostPort: {{ whawty_auth_instances[whawty_auth_instance].sync.port }} +{% endif %} +volumes: +- name: config + hostPath: + path: "{{ whawty_auth_instance_basepath }}/config" + type: Directory +- name: store + hostPath: + path: "{{ whawty_auth_instance_basepath }}/store" + type: Directory +{% if 'sync' in whawty_auth_instances[whawty_auth_instance] %} +- name: sync + hostPath: + path: "{{ whawty_auth_instance_basepath }}/sync" + type: Directory +{% endif %} diff --git a/roles/apps/whawty/auth/instance/templates/store.yml.j2 b/roles/apps/whawty/auth/instance/templates/store.yml.j2 new file mode 100644 index 00000000..afaea6f4 --- /dev/null +++ b/roles/apps/whawty/auth/instance/templates/store.yml.j2 @@ -0,0 +1,4 @@ +basedir: /store +default: {{ whawty_auth_instances[whawty_auth_instance].store.default }} +params: + {{ whawty_auth_instances[whawty_auth_instance].store.params | to_nice_yaml(indent=2) | indent(2) }} diff --git a/roles/apps/whawty/auth/instance/templates/sync.toml.j2 b/roles/apps/whawty/auth/instance/templates/sync.toml.j2 new file mode 100644 index 00000000..ddea4da5 --- /dev/null +++ b/roles/apps/whawty/auth/instance/templates/sync.toml.j2 @@ -0,0 +1,8 @@ +dont_namespace = true +[[listener]] + [listener.authorized_ssh] + address = ":{{ whawty_auth_instances[whawty_auth_instance].sync.port }}" + authorized_keys = "/sync/authorized_keys" +[[module]] + name = "store" + path = "/store" diff --git a/roles/apps/whawty/auth/instance/templates/web.yml.j2 b/roles/apps/whawty/auth/instance/templates/web.yml.j2 new file mode 100644 index 00000000..705e056d --- /dev/null +++ b/roles/apps/whawty/auth/instance/templates/web.yml.j2 @@ -0,0 +1,13 @@ +--- +tls: + certificate: /config/tls/cert.pem + certificate-key: /config/tls/key.pem + min-protocol-version: "TLSv1.2" + ciphers: + - ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + - TLS_AES_128_GCM_SHA256 + - TLS_AES_256_GCM_SHA384 + - TLS_CHACHA20_POLY1305_SHA256 + prefer-server-ciphers: true diff --git a/roles/apps/whawty/auth/tasks/main.yml b/roles/apps/whawty/auth/tasks/main.yml new file mode 100644 index 00000000..c81bf455 --- /dev/null +++ b/roles/apps/whawty/auth/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: instance specific tasks + loop: "{{ whawty_auth_instances | list }}" + loop_control: + loop_var: whawty_auth_instance + include_role: + name: apps/whawty/auth/instance -- cgit v1.2.3