diff --git a/secrets/kanidm-admin-pass.age b/secrets/kanidm-admin-pass.age
new file mode 100644
index 0000000..2b229b2
--- /dev/null
+++ b/secrets/kanidm-admin-pass.age
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 84j9mw W4+Z4WjOyUl4mWPqVykNWRhf2/8qfVOSM7QCFPNMZTA
+0ndQjslMwjQqguN25nBQtCchpCLhoD/vrxh1yNVeTNw
+-> ssh-ed25519 GKhvwg H8XcFJDZTA3IzxmK6wbB+PVM2gCZ4ysAPjL5j0LgeE0
+kehTMRIVOZ5ubtO7w8WF+gU3sjYXMQtd5hH+wcv3uSE
+--- 72ntrRbWq8pdkk/GrsVupTttfY9t+w3l+2KQbQyNn/I
+iydìû$vVl TK$4G[€â· ©âMI[™#t—¹ °ôz:‰ñÍÙr9~½ESÃA»6Œ}×µ
\ No newline at end of file
diff --git a/secrets/kanidm-idm-admin-pass.age b/secrets/kanidm-idm-admin-pass.age
new file mode 100644
index 0000000..0eac321
--- /dev/null
+++ b/secrets/kanidm-idm-admin-pass.age
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> ssh-ed25519 84j9mw 8zYeVXx36dpC8TxMdoM1GdERoNNj902KwTF4h/r4inM
+n3mYra0BeM4gWsZ7Roilu14o/GajX1iWw0fcy0q31yc
+-> ssh-ed25519 GKhvwg cqd7YmVpbxqZxaVluHDZ8Yw0gNfJCKMmoWa4mEoXym8
+Gbcj+PJaqyPRRGX4olr7mmJ5IoEGlQaogYbj7i9E/98
+--- LoQPWI+m8s3NjalUh0+xdW54c8lgddBmhPoIiPbmR8I
+‘ê¢èÒ–ÆœÜ‰ ÈY
+ž9˜ä­Å!4�šÞ2DV³£P²·‘9¡N�]G;ÎÏ?ˆÐ‰S± '
\ No newline at end of file
diff --git a/secrets/secrets.nix b/secrets/secrets.nix
index c36fbb5..6cccbf7 100644
--- a/secrets/secrets.nix
+++ b/secrets/secrets.nix
@@ -93,4 +93,12 @@ in
     keys.system.youko
     keys.other.bootstrap
   ];
+  "kanidm-admin-pass.age".publicKeys = [
+    keys.system.kazuki
+    keys.other.bootstrap
+  ];
+  "kanidm-idm-admin-pass.age".publicKeys = [
+    keys.system.kazuki
+    keys.other.bootstrap
+  ];
 }
diff --git a/services/default.nix b/services/default.nix
index ea3614e..2fde026 100644
--- a/services/default.nix
+++ b/services/default.nix
@@ -4,5 +4,6 @@
     ./forgejo-runner.nix
     ./forgejo.nix
     ./paperless.nix
+    ./kanidm.nix
   ];
 }
diff --git a/services/kanidm.nix b/services/kanidm.nix
new file mode 100644
index 0000000..7ebaac7
--- /dev/null
+++ b/services/kanidm.nix
@@ -0,0 +1,85 @@
+{
+  config.services.kanidm =
+    let
+      port = 8443;
+      domain = "auth.rabulinski.com";
+    in
+    {
+      host = "kazuki";
+      ports = [ port ];
+      module =
+        { config, pkgs, ... }:
+        let
+          cert = config.security.acme.certs.${domain};
+        in
+        {
+          age.secrets.rabulinski-com-cf = {
+            file = ../secrets/rabulinski-com-cf.age;
+            owner = config.services.nginx.user;
+          };
+          age.secrets.kanidm-admin-pass = {
+            file = ../secrets/kanidm-admin-pass.age;
+            owner = "kanidm";
+          };
+          age.secrets.kanidm-idm-admin-pass = {
+            file = ../secrets/kanidm-idm-admin-pass.age;
+            owner = "kanidm";
+          };
+
+          services.kanidm = {
+            enableServer = true;
+            package = pkgs.kanidmWithSecretProvisioning;
+            serverSettings = {
+              bindaddress = "127.0.0.1:${toString port}";
+              inherit domain;
+              origin = "https://${domain}";
+              trust_x_forward_for = true;
+              tls_chain = "${cert.directory}/fullchain.pem";
+              tls_key = "${cert.directory}/key.pem";
+            };
+            provision = {
+              enable = true;
+              idmAdminPasswordFile = config.age.secrets.kanidm-idm-admin-pass.path;
+              adminPasswordFile = config.age.secrets.kanidm-admin-pass.path;
+            };
+          };
+
+          systemd.services.kanidm.serviceConfig = {
+            SupplementaryGroups = [ cert.group ];
+          };
+
+          users.users.nginx.extraGroups = [ "acme" ];
+          networking.firewall.allowedTCPPorts = [
+            80
+            443
+          ];
+
+          services.nginx = {
+            enable = true;
+            recommendedProxySettings = true;
+            recommendedGzipSettings = true;
+            recommendedOptimisation = true;
+            recommendedTlsSettings = true;
+            virtualHosts."auth.rabulinski.com" = {
+              forceSSL = true;
+              enableACME = true;
+              acmeRoot = null;
+              locations."/" = {
+                proxyPass = "https://localhost:${toString port}";
+                proxyWebsockets = true;
+                extraConfig = ''
+                  proxy_ssl_verify off;
+                  proxy_ssl_name ${domain};
+                '';
+              };
+            };
+          };
+
+          security.acme.certs.${domain} = {
+            dnsProvider = "cloudflare";
+            credentialsFile = config.age.secrets.rabulinski-com-cf.path;
+            reloadServices = [ "kanidm" ];
+          };
+        };
+    };
+}
