diff --git a/ansible/hosts.ini b/ansible/hosts.ini index 21c112e..118cd50 100644 --- a/ansible/hosts.ini +++ b/ansible/hosts.ini @@ -10,3 +10,4 @@ wiki srib-radio azuracast-srib beszel +kanidm diff --git a/ansible/playbook_infra.yml b/ansible/playbook_infra.yml index 85672e3..71ca108 100644 --- a/ansible/playbook_infra.yml +++ b/ansible/playbook_infra.yml @@ -9,3 +9,13 @@ agent_token: "{{ beszel_agent_token }}" agent_hub_url: "{{ beszel_agent_hub_url }}" become: true + +- name: Kanidm host config + hosts: kanidm + pre_tasks: + - name: Install nginx + ansible.builtin.include_role: + name: nginxinc.nginx + roles: + - kanidm + become: true diff --git a/ansible/requirements.yml b/ansible/requirements.yml index ae673fc..6fe23b1 100644 --- a/ansible/requirements.yml +++ b/ansible/requirements.yml @@ -4,3 +4,6 @@ collections: version: "2.2.2" - name: community.beszel version: "2.0.0" +roles: + - name: nginxinc.nginx + version: "0.26.0" diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml index f4817b3..b6f4b21 100644 --- a/ansible/roles/common/tasks/main.yml +++ b/ansible/roles/common/tasks/main.yml @@ -27,3 +27,6 @@ - nmap - tmux - dnsutils + - qemu-guest-agent + - podman + become: true diff --git a/ansible/roles/kanidm/handlers/main.yml b/ansible/roles/kanidm/handlers/main.yml new file mode 100644 index 0000000..75da11e --- /dev/null +++ b/ansible/roles/kanidm/handlers/main.yml @@ -0,0 +1,17 @@ +--- +- name: Reload Systemd + ansible.builtin.systemd_service: + daemon_reload: true + become: true + +- name: Restart kanidm + ansible.builtin.systemd_service: + name: kanidm + state: restarted + become: true + +- name: Restart nginx + ansible.builtin.systemd_service: + name: nginx + state: restarted + become: true diff --git a/ansible/roles/kanidm/tasks/main.yml b/ansible/roles/kanidm/tasks/main.yml new file mode 100644 index 0000000..a196ce5 --- /dev/null +++ b/ansible/roles/kanidm/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: Install common packages + ansible.builtin.apt: + pkg: + - nginx + - nginx-module-acme + state: present + become: true + +- name: Write kanidm container file + ansible.builtin.template: + src: templates/kanidm.container + dest: /etc/containers/systemd/ + mode: "0644" + notify: + - Reload Systemd + - Restart kanidm + become: true + +- name: Write kanidm config file + ansible.builtin.template: + src: templates/server.toml + dest: /var/lib/kanidm/ + mode: "0644" + notify: Restart kanidm + become: true + +- name: Write kanidm nginx config + ansible.builtin.template: + src: templates/nginx.conf + dest: /etc/nginx/ + mode: "0644" + validate: /usr/sbin/nginx -t -c %s + notify: Restart nginx + become: true diff --git a/ansible/roles/kanidm/templates/kanidm.container b/ansible/roles/kanidm/templates/kanidm.container new file mode 100644 index 0000000..0d6c9d6 --- /dev/null +++ b/ansible/roles/kanidm/templates/kanidm.container @@ -0,0 +1,21 @@ +[Container] +Image=docker.io/kanidm/server:1.11.2 +ContainerName=kanidm +# Uncomment to enable auto-updates +# AutoUpdate=registry +PublishPort=8443:8443 +Volume=/var/lib/kanidm:/data:z + +[Unit] +After=default.target + +[Install] +# Start by default on boot +WantedBy=default.target + +[Service] +# Give the container time to start in case it needs to pull the image +TimeoutStartSec=600 +TimeoutStopSec=30 +# Creates the state directory of /var/lib/kanidm on the host +StateDirectory=kanidm diff --git a/ansible/roles/kanidm/templates/nginx.conf b/ansible/roles/kanidm/templates/nginx.conf new file mode 100644 index 0000000..c80c682 --- /dev/null +++ b/ansible/roles/kanidm/templates/nginx.conf @@ -0,0 +1,70 @@ +load_module modules/ngx_http_acme_module.so; + +user nginx nginx; +worker_processes auto; +worker_rlimit_nofile 2048; + +pid /run/nginx.pid; +error_log /var/log/nginx/error.log notice; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + gzip on; + keepalive_timeout 10; + server_tokens off; + + resolver 1.1.1.1; + + ### For ssl cert + acme_issuer letsencrypt { + uri https://acme-v02.api.letsencrypt.org/directory; + # contact admin@example.test; + state_path /var/cache/nginx/acme-letsencrypt; + + accept_terms_of_service; + } + + ### General listener on port 80 is required to process ACME HTTP-01 challenges + server { + listen 80 default_server; + listen [::]:80 default_server; + + ### Redirect to https + return 301 https://$host$request_uri; + } + + server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name id.fribyte.no; + + ### SSL + acme_certificate letsencrypt; + ssl_certificate $acme_certificate; + ssl_certificate_key $acme_certificate_key; + ssl_certificate_cache max=2; + + location / { + proxy_pass https://localhost:8443; + proxy_http_version 1.1; + proxy_set_header Host $server_name; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + } + } +} \ No newline at end of file diff --git a/ansible/roles/kanidm/templates/server.toml b/ansible/roles/kanidm/templates/server.toml new file mode 100644 index 0000000..71e3d59 --- /dev/null +++ b/ansible/roles/kanidm/templates/server.toml @@ -0,0 +1,148 @@ +# The server configuration file version. +version = "2" + +# The webserver bind address. Requires TLS certificates. +# If the port is set to 443 you may require the +# NET_BIND_SERVICE capability. This accepts a single address +# or an array of addresses to listen on. +# Defaults to "127.0.0.1:8443" +bindaddress = "0.0.0.0:8443" +# +# The read-only ldap server bind address. Requires +# TLS certificates. If set to 636 you may require the +# NET_BIND_SERVICE capability. This accepts a single address +# or an array of addresses to listen on. +# Defaults to "" (disabled) +# ldapbindaddress = "0.0.0.0:3636" +# +# The path to the kanidm database. +db_path = "/data/kanidm.db" +# +# If you have a known filesystem, kanidm can tune the +# database page size to match. Valid choices are: +# [zfs, other] +# If you are unsure about this leave it as the default +# (other). After changing this +# value you must run a vacuum task. +# - zfs: +# * sets database pagesize to 64k. You must set +# recordsize=64k on the zfs filesystem. +# - other: +# * sets database pagesize to 4k, matching most +# filesystems block sizes. +# db_fs_type = "zfs" +# +# The number of entries to store in the in-memory cache. +# Minimum value is 256. If unset +# an automatic heuristic is used to scale this. +# You should only adjust this value if you experience +# memory pressure on your system. +# db_arc_size = 2048 +# +# TLS chain and key in pem format. Both must be present. +# If the server receives a SIGHUP, these files will be +# re-read and reloaded if their content is valid. +tls_chain = "/data/chain.pem" +tls_key = "/data/key.pem" + +# The path where entry migrations will be read from. +# This path should contain files that match the pattern +# xx-name.json where xx are two number. For example: +# 00-base.json +# 10-groups.json +# Migrations are applied in order. Migrations that fail +# to apply, or have invalid syntax are skipped without +# preventing server start up or reload. +# migration_path = "/data/migrations.d" + +# +# The log level of the server. May be one of info, debug, trace +# +# NOTE: this can be overridden by the environment variable +# `KANIDM_LOG_LEVEL` at runtime +# Defaults to "info" +# log_level = "info" +# +# The DNS domain name of the server. This is used in a +# number of security-critical contexts +# such as webauthn, so it *must* match your DNS +# hostname. It is used to create +# security principal names such as `william@idm.example.com` +# so that in a (future) trust configuration it is possible +# to have unique Security Principal Names (spns) throughout +# the topology. +# +# ⚠️ WARNING ⚠️ +# +# Changing this value WILL break many types of registered +# credentials for accounts including but not limited to +# webauthn, oauth tokens, and more. +# If you change this value you *must* run +# `kanidmd domain rename` immediately after. +domain = "id.fribyte.no" +# +# The origin for webauthn. This is the url to the server, +# with the port included if it is non-standard (any port +# except 443). This must match or be a descendent of the +# domain name you configure above. If these two items are +# not consistent, the server WILL refuse to start! +# origin = "https://idm.example.com" +# # OR +# origin = "https://idm.example.com:8443" +origin = "https://id.fribyte.no" + +# HTTPS requests can be reverse proxied by a loadbalancer. +# To preserve the original IP of the caller, these systems +# will often add a header such as "Forwarded" or +# "X-Forwarded-For". Some other proxies can use the PROXY +# protocol v2 header. While we support the PROXY protocol +# v1 header, we STRONGLY discourage it's use as it has +# significantly greater overheads compared to v2 during +# processing. +# This setting allows configuration of the list of trusted +# IPs or IP ranges which can supply this header information, +# and which format the information is provided in. +# Defaults to "none" (no trusted sources) +# Only one option can be used at a time. +# [http_client_address_info] +# proxy-v2 = ["10.88.0.1", "10.88.0.0/16"] +# # OR +[http_client_address_info] +# x-forward-for = ["127.0.0.1", "127.0.0.0/8"] +x-forward-for = ["10.88.0.1", "10.88.0.0/16"] # Podman network subnet named 'podman' +# # OR +# [http_client_address_info] +# # AVOID IF POSSIBLE!!! +# proxy-v1 = ["127.0.0.1", "127.0.0.0/8"] + +# LDAPS requests can be reverse proxied by a loadbalancer. +# To preserve the original IP of the caller, these systems +# can add a header such as the PROXY protocol v2 header. +# While we support the PROXY protocol v1 header, we STRONGLY +# discourage it's use as it has significantly greater +# overheads compared to v2 during processing. +# This setting allows configuration of the list of trusted +# IPs or IP ranges which can supply this header information, +# and which format the information is provided in. +# Defaults to "none" (no trusted sources) +# [ldap_client_address_info] +# proxy-v2 = ["127.0.0.1", "127.0.0.0/8"] +# # OR +# [ldap_client_address_info] +# # AVOID IF POSSIBLE!!! +# proxy-v1 = ["127.0.0.1", "127.0.0.0/8"] + +[online_backup] +# The path to the output folder for online backups +path = "/data/kanidm/backups/" +# The schedule to run online backups (see https://crontab.guru/) +# every day at 22:00 UTC (default) +schedule = "00 22 * * *" +# four times a day at 3 minutes past the hour, every 6th hours +# schedule = "03 */6 * * *" +# We also support non standard cron syntax, with the following format: +# sec min hour day of month month day of week year +# (it's very similar to the standard cron syntax, it just allows to specify the seconds +# at the beginning and the year at the end) +# Number of backups to keep (default 7) +# versions = 7 diff --git a/local_run_config.sh b/local_run_config.sh new file mode 100755 index 0000000..b1d9217 --- /dev/null +++ b/local_run_config.sh @@ -0,0 +1,19 @@ +#! /usr/bin/bash + +cd ansible + +echo "Running homelab Ansible local test configuration" + +if ! tailscale status > /dev/null; then + echo "Starting tailscale" + tailscale up +fi + +tailscale switch headscale.fribyte.no + +if [ -e local_config.yml ] +then + ansible-playbook local_config.yml --verbose --become-password-file .ansible_sudo_password --vault-password-file .ansible_vault_key +else + echo "No local config found please create it first." +fi