services/clanServices/zitadel/default.nix
2025-11-05 13:45:23 +01:00

276 lines
8.3 KiB
Nix

{ lib, pkgs, ... }:
let
inherit (builtins) readFile;
inherit (lib) mkOption types;
in
{
_class = "clan.service";
manifest = {
name = "amarth-services/zitadel";
description = "Zitadel service module";
categories = [ "System" "Identity" "IAM" ];
readme = readFile ./README.md;
};
#==============================================================================================================
# Controller configuration
#==============================================================================================================
roles.controller = {
description = "A controller that manages the instance";
interface = {
options = {
hostName = mkOption {
type = types.str;
example = "auth.example.com";
description = ''
The domain at which zitadel will be hosted
'';
};
displayName = mkOption {
type = types.str;
example = "My awesome org";
description = ''
The Name of the zitadel organisation
'';
};
emergencyAccessPublicKey = mkOption {
type = types.str;
example = "ssh-ed25519 ...";
description = ''
The public key with which you want access to
'';
};
};
};
perInstance = { instanceName, settings, machine, roles, ... }: {
nixosModule = { config, pkgs, inputs, system, ... }:
let
terraform = inputs.terranix.lib.terranixConfiguration {
inherit pkgs system;
modules = [
({ config, ... }: {
config = {
terraform.required_providers.zitadel = {
source = "zitadel/zitadel";
version = "2.2.0";
};
provider.zitadel = {
domain = "localhost";
insecure = "true";
port = "8080";
jwt_profile_file = "local-token";
};
resource.zitadel_human_user.default = {
org_id = "";
};
};
})
];
};
valuesYamlKey = "amarth/service/zitadel-${instanceName}-values.yml";
in
{
assertions =
let
inherit (lib) attrValues any;
in
[
{
assertion =
config.services.k3s.enable == true;
# config.clan.inventory.instances
# |> attrValues
# |> any ({ module, ... }: module.name == "k3s");
message = "This module requires k3s in order to run";
}
];
clan.core.vars.generators.zitadel = {
share = false;
files.masterKey = { deploy = true; secret = true; owner = "zitadel"; group = "zitadel"; mode = "0400"; };
files.initialAdminPassword = { deploy = false; secret = false; };
files.emailPassword = { deploy = false; secret = true; };
runtimeInputs = with pkgs; [ pwgen ];
script = ''
pwgen 50 1 > "$out/initialAdminPassword"
# https://zitadel.com/docs/self-hosting/manage/configure#masterkey
# The master key has to be 32 bytes
head -c 32 /dev/urandom > "$out/masterKey"
touch $out/emailPassword
'';
};
services.k3s.autoDeployCharts.zitadel = {
name = "zitadel";
repo = "https://charts.zitadel.com";
version = "9.12.3";
hash = "sha256-eSpqy2vK1tJp0Ci20R7+zGLfUDKPuKOz1iWyvawqEpc=";
targetNamespace = "zitadel-system";
createNamespace = true;
values = config.sops.templates.${valuesYamlKey}.path;
};
sops = {
templates.${valuesYamlKey}.content = ''
zitadel:
masterKey: ${config.sops.placeholder."vars/zitadel/masterKey"}
'';
};
# services.zitadel = {
# enable = true;
# openFirewall = true;
# masterKeyFile = config.clan.core.vars.generators.zitadel.files.masterKey.path;
# tlsMode = "external";
# settings = {
# Port = 9092;
# ExternalDomain = settings.hostName;
# ExternalPort = 443;
# ExternalSecure = true;
# Metrics.Type = "otel";
# Tracing.Type = "otel";
# Telemetry.Enabled = true;
# SystemDefaults = {
# PasswordHasher.Hasher.Algorithm = "argon2id";
# SecretHasher.Hasher.Algorithm = "argon2id";
# };
# DefaultInstance = {
# PasswordComplexityPolicy = {
# MinLength = 20;
# HasLowercase = false;
# HasUppercase = false;
# HasNumber = false;
# HasSymbol = false;
# };
# LoginPolicy = {
# AllowRegister = false;
# ForceMFA = true;
# };
# LockoutPolicy = {
# MaxPasswordAttempts = 5;
# MaxOTPAttempts = 10;
# };
# SMTPConfiguration = {
# SMTP = {
# Host = "black-mail.nl:587";
# User = "info@amarth.cloud";
# Password = ""; #config.clan.core.vars.generators.zitadel.files.emailPassword.value;
# };
# FromName = "Amarth Zitadel";
# };
# };
# Database.postgres = {
# Host = "localhost";
# # Zitadel will report error if port is not set
# Port = 5432;
# Database = "zitadel";
# User = {
# Username = "zitadel";
# SSL.Mode = "disable";
# };
# Admin = {
# Username = "postgres";
# SSL.Mode = "disable";
# };
# };
# Machine.Identification = {
# PrivateIp.Enabled = true;
# # In the docs this uses a google service. I want a self hosted one
# # TODO :: Figure out how to self-host webhooks, if I want them at all
# Webhook.Enabled = false;
# };
# SystemAPIUsers = {
# emergencyAccess = {
# # Path = settings.emergencyAccessPublicKey;
# KeyData = settings.emergencyAccessPublicKey;
# # This is the default value
# # Memberships = [
# # { MemberType = "System"; Roles = [ "SYSTEM_OWNER" ]; }
# # ];
# };
# };
# };
# steps.FirstInstance = {
# InstanceName = settings.hostName;
# Org = {
# Name = settings.displayName;
# Human = {
# UserName = "chris";
# FirstName = "Chris";
# LastName = "Kruining";
# Email = {
# Address = "chris@kruining.eu";
# Verified = true;
# };
# Password = config.clan.core.vars.generators.zitadel.files.initialAdminPassword.value;
# };
# };
# };
# };
# services.postgresql = {
# enable = true;
# authentication = ''
# # Generated file, do not edit!
# # TYPE DATABASE USER ADDRESS METHOD
# local all all trust
# host all all 127.0.0.1/32 trust
# host all all ::1/128 trust
# '';
# ensureDatabases = [ "zitadel" ];
# ensureUsers = [
# {
# name = "zitadel";
# ensureDBOwnership = true;
# }
# ];
# };
};
};
};
#==============================================================================================================
# Peer configuration
#==============================================================================================================
roles.peer = {
description = "A peer";
interface = {
options = {};
};
perInstance = { instanceName, settings, machine, roles, ... }: {
nixosModule = {};
};
};
}