diff --git a/flake/packages.nix b/flake/packages.nix index b76b9995..289a3712 100644 --- a/flake/packages.nix +++ b/flake/packages.nix @@ -40,7 +40,7 @@ dns-push = pkgs.callPackage ./dns { inherit localLib; - tokenPath = inputs.self.nixosConfigurations.pc.config.sops.secrets."acme/token".path; + tokenPath = inputs.self.nixosConfigurations.pc.config.nixos.system.sops.secrets."acme/token".path; octodns = pkgs.octodns.withProviders (_: with pkgs.octodns-providers; [ cloudflare ]); }; archive = diff --git a/modules/services/acme.nix b/modules/services/acme.nix index 87ece072..d1b669b1 100644 --- a/modules/services/acme.nix +++ b/modules/services/acme.nix @@ -34,21 +34,21 @@ inputs: name = builtins.elemAt cert.value.domains 0; value = { - credentialsFile = inputs.config.sops.templates."acme/cloudflare.ini".path; + credentialsFile = inputs.config.nixos.system.sops.templates."acme/cloudflare.ini".path; extraDomainNames = builtins.tail cert.value.domains; group = inputs.lib.mkIf (cert.value.group != null) cert.value.group; }; }) (inputs.localLib.attrsToList acme.cert)); }; - sops = + nixos.system.sops = { templates."acme/cloudflare.ini".content = '' - CLOUDFLARE_DNS_API_TOKEN=${inputs.config.sops.placeholder."acme/token"} + CLOUDFLARE_DNS_API_TOKEN=${inputs.config.nixos.system.sops.placeholder."acme/token"} CLOUDFLARE_PROPAGATION_TIMEOUT=300 ''; - secrets."acme/token".sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; + secrets."acme/token" = {}; }; }; } diff --git a/modules/services/coturn.nix b/modules/services/coturn.nix index 6da11307..5cf03d6e 100644 --- a/modules/services/coturn.nix +++ b/modules/services/coturn.nix @@ -14,14 +14,17 @@ inputs: { enable = true; use-auth-secret = true; - static-auth-secret-file = inputs.config.sops.secrets."coturn/auth-secret".path; + static-auth-secret-file = inputs.config.nixos.system.sops.secrets."coturn/auth-secret".path; realm = coturn.hostname; cert = "${keydir}/full.pem"; pkey = "${keydir}/key.pem"; no-cli = true; }; - sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User; - nixos.services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group; + nixos = + { + system.sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User; + services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group; + }; networking.firewall = with inputs.config.services.coturn; { allowedUDPPorts = [ listening-port tls-listening-port ]; diff --git a/modules/services/freshrss.nix b/modules/services/freshrss.nix index 220868d6..fde8b64b 100644 --- a/modules/services/freshrss.nix +++ b/modules/services/freshrss.nix @@ -15,19 +15,18 @@ inputs: enable = true; baseUrl = "https://${freshrss.hostname}"; defaultUser = "chn"; - passwordFile = inputs.config.sops.secrets."freshrss/chn".path; - database = { type = "mysql"; passFile = inputs.config.sops.secrets."freshrss/db".path; }; - }; - sops.secrets = - { - "freshrss/chn".owner = inputs.config.users.users.freshrss.name; - "freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; }; + passwordFile = inputs.config.nixos.system.sops.secrets."freshrss/chn".path; + database = { type = "mysql"; passFile = inputs.config.nixos.system.sops.secrets."freshrss/db".path; }; }; systemd.services.freshrss-config.after = [ "mysql.service" ]; - nixos.services = + nixos = { - mariadb = { enable = true; instances.freshrss = {}; }; - nginx.https.${freshrss.hostname}.global.configName = "freshrss"; + services = { mariadb.instances.freshrss = {}; nginx.https.${freshrss.hostname}.global.configName = "freshrss"; }; + system.sops.secrets = + { + "freshrss/chn".owner = inputs.config.users.users.freshrss.name; + "freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; }; + }; }; }; } diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix index b324565f..7264b9cb 100644 --- a/modules/services/gitea.nix +++ b/modules/services/gitea.nix @@ -19,9 +19,13 @@ inputs: { enable = true; lfs.enable = true; - mailerPasswordFile = inputs.config.sops.secrets."gitea/mail".path; + mailerPasswordFile = inputs.config.nixos.system.sops.secrets."gitea/mail".path; database = - { createDatabase = false; type = "postgres"; passwordFile = inputs.config.sops.secrets."gitea/db".path; }; + { + createDatabase = false; + type = "postgres"; + passwordFile = inputs.config.nixos.system.sops.secrets."gitea/db".path; + }; settings = { session.COOKIE_SECURE = true; @@ -48,26 +52,29 @@ inputs: [ "DEFAULT" "MIGRATE" "MIRROR" "CLONE" "PULL" "GC" ]); }; }; - nixos.services = + nixos = { - nginx.https.${gitea.hostname}.location = + system.sops.secrets = { - "/".proxy.upstream = "http://127.0.0.1:3002"; - "/robots.txt".static.root = - let robotsFile = inputs.pkgs.fetchurl - { - url = "https://gitea.com/robots.txt"; - sha256 = "144c5s3la4a85c9lygcnxhbxs3w5y23bkhhqx69fbp9yiqyxdkk2"; - }; - in "${inputs.pkgs.runCommand "robots.txt" {} "mkdir -p $out; cp ${robotsFile} $out/robots.txt"}"; + "gitea/mail" = { owner = "gitea"; key = "mail/bot"; }; + "gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; }; + "mail/bot" = {}; + }; + services = + { + nginx.https.${gitea.hostname}.location = + { + "/".proxy.upstream = "http://127.0.0.1:3002"; + "/robots.txt".static.root = + let robotsFile = inputs.pkgs.fetchurl + { + url = "https://gitea.com/robots.txt"; + sha256 = "144c5s3la4a85c9lygcnxhbxs3w5y23bkhhqx69fbp9yiqyxdkk2"; + }; + in "${inputs.pkgs.runCommand "robots.txt" {} "mkdir -p $out; cp ${robotsFile} $out/robots.txt"}"; + }; + postgresql.instances.gitea = {}; }; - postgresql.instances.gitea = {}; - }; - sops.secrets = - { - "gitea/mail" = { owner = "gitea"; key = "mail/bot"; }; - "gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; }; - "mail/bot" = {}; }; }; } diff --git a/modules/services/grafana.nix b/modules/services/grafana.nix index c22d1efa..cc287d4f 100644 --- a/modules/services/grafana.nix +++ b/modules/services/grafana.nix @@ -24,7 +24,7 @@ inputs: enabled = true; host = "mail.chn.moe"; user = "bot@chn.moe"; - password = "$__file{${inputs.config.sops.secrets."grafana/mail".path}}"; + password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/mail".path}}"; from_address = "bot@chn.moe"; ehlo_identity = grafana.hostname; startTLS_policy = "MandatoryStartTLS"; @@ -32,9 +32,9 @@ inputs: server = { root_url = "https://${grafana.hostname}"; http_port = 3001; enable_gzip = true; }; security = { - secret_key = "$__file{${inputs.config.sops.secrets."grafana/secret".path}}"; + secret_key = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/secret".path}}"; admin_user = "chn"; - admin_password = "$__file{${inputs.config.sops.secrets."grafana/chn".path}}"; + admin_password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/chn".path}}"; admin_email = "chn@chn.moe"; }; database = @@ -42,7 +42,7 @@ inputs: type = "postgres"; host = "127.0.0.1:5432"; user = "grafana"; - password = "$__file{${inputs.config.sops.secrets."grafana/db".path}}"; + password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/db".path}}"; }; }; provision = @@ -78,18 +78,21 @@ inputs: extraFlags = [ "--storage.tsdb.max-block-chunk-segment-size=16MB" ]; }; }; - nixos.services = + nixos = { - nginx.https.${grafana.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3001"; websocket = true; }; - postgresql.instances.grafana = {}; - }; - sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in - { - "grafana/mail" = { owner = owner; key = "mail/bot"; }; - "grafana/secret".owner = owner; - "grafana/chn".owner = owner; - "grafana/db" = { owner = owner; key = "postgresql/grafana"; }; - "mail/bot" = {}; + services = + { + nginx.https.${grafana.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3001"; websocket = true; }; + postgresql.instances.grafana = {}; + }; + system.sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in + { + "grafana/mail" = { owner = owner; key = "mail/bot"; }; + "grafana/secret".owner = owner; + "grafana/chn".owner = owner; + "grafana/db" = { owner = owner; key = "postgresql/grafana"; }; + "mail/bot" = {}; + }; }; environment.persistence."/nix/nodatacow".directories = [{ directory = "/var/lib/prometheus2"; user = "prometheus"; group = "prometheus"; mode = "0700"; }]; diff --git a/modules/services/hpcstat.nix b/modules/services/hpcstat.nix index dd8f350d..62a7d343 100644 --- a/modules/services/hpcstat.nix +++ b/modules/services/hpcstat.nix @@ -15,13 +15,13 @@ inputs: grep = "${inputs.pkgs.gnugrep}/bin/grep"; curl = "${inputs.pkgs.curl}/bin/curl"; cat = "${inputs.pkgs.coreutils}/bin/cat"; - token = inputs.config.sops.secrets."telegram/token".path; - chat = inputs.config.sops.secrets."telegram/user/chn".path; + token = inputs.config.nixos.system.sops.secrets."telegram/token".path; + chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path; date = "${inputs.pkgs.coreutils}/bin/date"; hpcstat = "${inputs.pkgs.localPackages.hpcstat}/bin/hpcstat"; ssh = "${inputs.pkgs.openssh}/bin/ssh -i ${key} -o StrictHostKeyChecking=no" + " -o ForwardAgent=yes -o AddKeysToAgent=yes"; - key = inputs.config.sops.secrets."hpcstat/key".path; + key = inputs.config.nixos.system.sops.secrets."hpcstat/key".path; jykang = "${inputs.topInputs.self}/devices/jykang.xmuhpc/files"; ssh-agent = "${inputs.pkgs.openssh}/bin/ssh-agent"; in @@ -105,10 +105,10 @@ inputs: (inputs.localLib.attrsToList calenders)); tmpfiles.rules = [ "d /var/lib/hpcstat 0700 hpcstat hpcstat" ]; }; - sops.secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in + nixos.system.sops.secrets = { - "telegram/token" = { group = "telegram"; mode = "0440"; inherit sopsFile; }; - "telegram/user/chn" = { group = "telegram"; mode = "0440"; inherit sopsFile; }; + "telegram/token" = { group = "telegram"; mode = "0440"; }; + "telegram/user/chn" = { group = "telegram"; mode = "0440"; }; "hpcstat/key" = { owner = "hpcstat"; group = "hpcstat"; }; }; users = diff --git a/modules/services/httpapi.nix b/modules/services/httpapi.nix index e2b9679c..aa33a963 100644 --- a/modules/services/httpapi.nix +++ b/modules/services/httpapi.nix @@ -10,35 +10,37 @@ inputs: }; config = let inherit (inputs.config.nixos.services) httpapi; in inputs.lib.mkIf (httpapi != null) { - nixos.services = + nixos = { - phpfpm.instances.httpapi = {}; - nginx.https.${httpapi.hostname}.location = + services = { - "/files".static.root = "/srv/api"; - "/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; }; - "/notify.php".php = + phpfpm.instances.httpapi = {}; + nginx.https.${httpapi.hostname}.location = { - root = builtins.dirOf inputs.config.sops.templates."httpapi/notify.php".path; - fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi; + "/files".static.root = "/srv/api"; + "/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; }; + "/notify.php".php = + { + root = builtins.dirOf inputs.config.nixos.system.sops.templates."httpapi/notify.php".path; + fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi; + }; }; }; - }; - sops = - { - templates."httpapi/notify.php" = + system.sops = { - owner = inputs.config.users.users.httpapi.name; - group = inputs.config.users.users.httpapi.group; - content = - let - placeholder = inputs.config.sops.placeholder; - request = "https://api.telegram.org/bot${placeholder."telegram/token"}" - + "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text="; - in ''''; + templates."httpapi/notify.php" = + { + owner = inputs.config.users.users.httpapi.name; + group = inputs.config.users.users.httpapi.group; + content = + let + inherit (inputs.config.sops) placeholder; + request = "https://api.telegram.org/bot${placeholder."telegram/token"}" + + "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text="; + in ''''; + }; + secrets = { "telegram/token" = {}; "telegram/user/chn" = {}; }; }; - secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in - { "telegram/token" = { inherit sopsFile; }; "telegram/user/chn" = { inherit sopsFile; }; }; }; systemd.tmpfiles.rules = [ "d /srv/api 0700 nginx nginx" "Z /srv/api - nginx nginx" ]; }; diff --git a/modules/services/huginn.nix b/modules/services/huginn.nix index 6c8072ea..e7db37e4 100644 --- a/modules/services/huginn.nix +++ b/modules/services/huginn.nix @@ -15,30 +15,7 @@ inputs: image = "ghcr.io/huginn/huginn:latest"; imageFile = inputs.topInputs.self.src.huginn; ports = [ "127.0.0.1:3000:3000/tcp" ]; - environmentFiles = [ inputs.config.sops.templates."huginn/env".path ]; - }; - sops = - { - templates."huginn/env".content = let placeholder = inputs.config.sops.placeholder; in - '' - MYSQL_PORT_3306_TCP_ADDR=host.containers.internal - HUGINN_DATABASE_NAME=huginn - HUGINN_DATABASE_USERNAME=huginn - HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"} - DOMAIN=${huginn.hostname} - RAILS_ENV=production - FORCE_SSL=true - INVITATION_CODE=${placeholder."huginn/invitationCode"} - SMTP_DOMAIN=mail.chn.moe - SMTP_USER_NAME=bot@chn.moe - SMTP_PASSWORD="${placeholder."mail/bot"}" - SMTP_SERVER=mail.chn.moe - SMTP_SSL=true - EMAIL_FROM_ADDRESS=bot@chn.moe - TIMEZONE=Beijing - DO_NOT_CREATE_DATABASE=true - ''; - secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; }; + environmentFiles = [ inputs.config.nixos.system.sops.templates."huginn/env".path ]; }; nixos = { @@ -48,6 +25,29 @@ inputs: mariadb.instances.huginn = {}; podman = {}; }; + system.sops = + { + templates."huginn/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in + '' + MYSQL_PORT_3306_TCP_ADDR=host.containers.internal + HUGINN_DATABASE_NAME=huginn + HUGINN_DATABASE_USERNAME=huginn + HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"} + DOMAIN=${huginn.hostname} + RAILS_ENV=production + FORCE_SSL=true + INVITATION_CODE=${placeholder."huginn/invitationCode"} + SMTP_DOMAIN=mail.chn.moe + SMTP_USER_NAME=bot@chn.moe + SMTP_PASSWORD="${placeholder."mail/bot"}" + SMTP_SERVER=mail.chn.moe + SMTP_SSL=true + EMAIL_FROM_ADDRESS=bot@chn.moe + TIMEZONE=Beijing + DO_NOT_CREATE_DATABASE=true + ''; + secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; }; + }; }; }; } diff --git a/modules/services/mariadb.nix b/modules/services/mariadb.nix index 144e6281..566ee4ae 100644 --- a/modules/services/mariadb.nix +++ b/modules/services/mariadb.nix @@ -40,13 +40,13 @@ inputs: let passwordFile = if db.value.passwordFile or null != null then db.value.passwordFile - else inputs.config.sops.secrets."mariadb/${db.value.user}".path; + else inputs.config.nixos.system.sops.secrets."mariadb/${db.value.user}".path; mysql = "${inputs.config.services.mysql.package}/bin/mysql"; in # force user use password auth ''echo "ALTER USER '${db.value.user}' IDENTIFIED BY '$(cat ${passwordFile})';" | ${mysql} -N'') (inputs.localLib.attrsToList mariadb.instances))); - sops.secrets = builtins.listToAttrs (builtins.map + nixos.system.sops.secrets = builtins.listToAttrs (builtins.map (db: { name = "mariadb/${db.value.user}"; value.owner = inputs.config.users.users.mysql.name; }) (builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList mariadb.instances))); environment.persistence."/nix/nodatacow".directories = diff --git a/modules/services/misskey.nix b/modules/services/misskey.nix index 7d93b8ef..7c8153e9 100644 --- a/modules/services/misskey.nix +++ b/modules/services/misskey.nix @@ -22,7 +22,8 @@ inputs: after = [ "network.target" "redis-misskey-${instance.name}.service" "postgresql.service" ]; requires = after; wantedBy = [ "multi-user.target" ]; - environment.MISSKEY_CONFIG_YML = inputs.config.sops.templates."misskey/${instance.name}.yml".path; + environment.MISSKEY_CONFIG_YML = + inputs.config.nixos.system.sops.templates."misskey/${instance.name}.yml".path; serviceConfig = rec { User = "misskey-${instance.name}"; @@ -53,50 +54,6 @@ inputs: }; }) (inputs.localLib.attrsToList misskey.instances)); - sops.templates = builtins.listToAttrs (builtins.map - (instance: - { - name = "misskey/${instance.name}.yml"; - value = - { - content = - let - placeholder = inputs.config.sops.placeholder; - redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}"; - in - '' - url: https://${instance.value.hostname}/ - port: ${toString instance.value.port} - db: - host: 127.0.0.1 - port: 5432 - db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name} - user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name} - pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"} - extra: - statement_timeout: 600000 - dbReplications: false - redis: - host: 127.0.0.1 - port: ${builtins.toString redis.port} - pass: ${placeholder."redis/misskey-${instance.name}"} - id: 'aid' - proxyBypassHosts: - - api.deepl.com - - api-free.deepl.com - - www.recaptcha.net - - hcaptcha.com - - challenges.cloudflare.com - proxyRemoteFiles: true - signToActivityPubGet: true - maxFileSize: 1073741824 - fulltextSearch: - provider: sqlPgroonga - ''; - owner = "misskey-${instance.name}"; - }; - }) - (inputs.localLib.attrsToList misskey.instances)); users = inputs.lib.mkMerge (builtins.map (instance: { @@ -111,19 +68,66 @@ inputs: groups."misskey-${instance.name}".gid = inputs.config.nixos.user.gid."misskey-${instance.name}"; }) (inputs.localLib.attrsToList misskey.instances)); - nixos.services = + nixos = { - redis.instances = builtins.listToAttrs (builtins.map - (instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; }) - (inputs.localLib.attrsToList misskey.instances)); - postgresql.instances = builtins.listToAttrs (builtins.map - (instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; }) - (inputs.localLib.attrsToList misskey.instances)); - nginx.https = builtins.listToAttrs (builtins.map - (instance: with instance.value; + services = + { + redis.instances = builtins.listToAttrs (builtins.map + (instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; }) + (inputs.localLib.attrsToList misskey.instances)); + postgresql.instances = builtins.listToAttrs (builtins.map + (instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; }) + (inputs.localLib.attrsToList misskey.instances)); + nginx.https = builtins.listToAttrs (builtins.map + (instance: with instance.value; + { + name = hostname; + value.location."/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; }; + }) + (inputs.localLib.attrsToList misskey.instances)); + }; + system.sops.templates = builtins.listToAttrs (builtins.map + (instance: { - name = hostname; - value.location."/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; }; + name = "misskey/${instance.name}.yml"; + value = + { + content = + let + placeholder = inputs.config.nixos.system.sops.placeholder; + redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}"; + in + '' + url: https://${instance.value.hostname}/ + port: ${toString instance.value.port} + db: + host: 127.0.0.1 + port: 5432 + db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name} + user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name} + pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"} + extra: + statement_timeout: 600000 + dbReplications: false + redis: + host: 127.0.0.1 + port: ${builtins.toString redis.port} + pass: ${placeholder."redis/misskey-${instance.name}"} + id: 'aid' + proxyBypassHosts: + - api.deepl.com + - api-free.deepl.com + - www.recaptcha.net + - hcaptcha.com + - challenges.cloudflare.com + proxyRemoteFiles: true + signToActivityPubGet: true + maxFileSize: 1073741824 + fulltextSearch: + provider: sqlPgroonga + ''; + owner = "misskey-${instance.name}"; + }; }) (inputs.localLib.attrsToList misskey.instances)); }; diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index 3f6585c7..4525743a 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -21,9 +21,9 @@ inputs: config = { dbtype = "pgsql"; - dbpassFile = inputs.config.sops.secrets."nextcloud/postgresql".path; + dbpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/postgresql".path; adminuser = "admin"; - adminpassFile = inputs.config.sops.secrets."nextcloud/admin".path; + adminpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/admin".path; }; configureRedis = true; settings = @@ -39,7 +39,7 @@ inputs: overwriteprotocol = "https"; default_phone_region = "CN"; }; - secretFile = inputs.config.sops.templates."nextcloud/secret".path; + secretFile = inputs.config.nixos.system.sops.templates."nextcloud/secret".path; extraApps = let version = inputs.lib.versions.major inputs.config.services.nextcloud.package.version; @@ -59,27 +59,30 @@ inputs: (package: { name = package; value = inputs.pkgs.fetchNextcloudApp (getInfo package); }) [ "phonetrack" "twofactor_webauthn" "calendar" ]); }; - nixos.services = + nixos = { - postgresql.instances.nextcloud = {}; - redis.instances.nextcloud.port = 3499; - nginx.https.${nextcloud.hostname}.global.configName = nextcloud.hostname; - }; - sops = - { - templates."nextcloud/secret" = + system.sops = { - content = builtins.toJSON + templates."nextcloud/secret" = { - redis.password = inputs.config.sops.placeholder."redis/nextcloud"; - mail_smtppassword = inputs.config.sops.placeholder."mail/bot"; + content = builtins.toJSON + { + redis.password = inputs.config.nixos.system.sops.placeholder."redis/nextcloud"; + mail_smtppassword = inputs.config.nixos.system.sops.placeholder."mail/bot"; + }; + owner = inputs.config.users.users.nextcloud.name; + }; + secrets = + { + "nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; }; + "nextcloud/admin".owner = inputs.config.users.users.nextcloud.name; }; - owner = inputs.config.users.users.nextcloud.name; }; - secrets = + services = { - "nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; }; - "nextcloud/admin".owner = inputs.config.users.users.nextcloud.name; + postgresql.instances.nextcloud = {}; + redis.instances.nextcloud.port = 3499; + nginx.https.${nextcloud.hostname}.global.configName = nextcloud.hostname; }; }; systemd.services.nextcloud-setup = rec { requires = [ "postgresql.service" ]; after = requires; }; diff --git a/modules/services/nginx/default.nix b/modules/services/nginx/default.nix index 660540ea..1517a635 100644 --- a/modules/services/nginx/default.nix +++ b/modules/services/nginx/default.nix @@ -95,17 +95,13 @@ inputs: settings = { AccountID = 901296; - LicenseKey = inputs.config.sops.secrets."nginx/maxmind-license".path; + LicenseKey = inputs.config.nixos.system.sops.secrets."nginx/maxmind-license".path; EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ]; }; }; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; - sops.secrets."nginx/maxmind-license" = - { - owner = inputs.config.users.users.nginx.name; - sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; - }; + nixos.system.sops.secrets."nginx/maxmind-license".owner = inputs.config.users.users.nginx.name; systemd.services.nginx.serviceConfig = { CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; diff --git a/modules/services/nginx/https.nix b/modules/services/nginx/https.nix index 4dbc6f41..41d9a017 100644 --- a/modules/services/nginx/https.nix +++ b/modules/services/nginx/https.nix @@ -177,7 +177,7 @@ inputs: basicAuthFile = inputs.lib.mkIf (site.value.global.detectAuth != null) ( let secret = "nginx/templates/detectAuth/${inputs.lib.strings.escapeURL site.name}-global"; - in inputs.config.sops.templates.${secret}.path + in inputs.config.nixos.system.sops.templates.${secret}.path ); extraConfig = builtins.concatStringsSep "\n" ( @@ -227,7 +227,7 @@ inputs: let inherit (inputs.lib.strings) escapeURL; secret = "nginx/templates/detectAuth/${escapeURL site.name}/${escapeURL location.name}"; - in inputs.config.sops.templates.${secret}.path + in inputs.config.nixos.system.sops.templates.${secret}.path ); root = inputs.lib.mkIf (location.value.root or null != null) location.value.root; } @@ -247,7 +247,7 @@ inputs: ++ (inputs.lib.optionals (location.value.addAuth != null) ( let authFile = "nginx/templates/addAuth/${location.value.addAuth}"; - in [ "include ${inputs.config.sops.templates.${authFile}.path};" ] + in [ "include ${inputs.config.nixos.system.sops.templates.${authFile}.path};" ] )) ); }; @@ -285,114 +285,108 @@ inputs: }; }) sites); - nixos.services = + nixos = { - nginx = - # { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; } - let listens = builtins.filter - (listen: listen.value.addToTransparentProxy) - (builtins.concatLists (builtins.map - (site: builtins.map (listen: { inherit (site) name; value = listen; }) site.value.listens) - sites)); - in - { - transparentProxy.map = builtins.listToAttrs (builtins.map - (site: - { - inherit (site) name; - value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0); - }) - (builtins.filter (listen: !listen.value.proxyProtocol) listens)); - streamProxy.map = builtins.listToAttrs (builtins.map - (site: - { - inherit (site) name; - value = + services = + { + nginx = + # { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; } + let listens = builtins.filter + (listen: listen.value.addToTransparentProxy) + (builtins.concatLists (builtins.map + (site: builtins.map (listen: { inherit (site) name; value = listen; }) site.value.listens) + sites)); + in + { + transparentProxy.map = builtins.listToAttrs (builtins.map + (site: { - upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol - + (if site.value.http2 then httpsPortShift.http2 else 0); - proxyProtocol = true; - rewriteHttps = inputs.lib.mkDefault false; - }; - }) - (builtins.filter (listen: listen.value.proxyProtocol) listens)); - http = builtins.listToAttrs (builtins.map - (site: { inherit (site) name; value.rewriteHttps = {}; }) - (builtins.filter (site: site.value.global.rewriteHttps) sites)); - }; - acme.cert = builtins.listToAttrs (builtins.map - (site: { inherit (site) name; value.group = inputs.config.services.nginx.group; }) - sites); - }; - sops = - let - inherit (inputs.lib.strings) escapeURL; - detectAuthUsers = builtins.concatLists (builtins.map - (site: - ( - (builtins.map + inherit (site) name; + value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0); + }) + (builtins.filter (listen: !listen.value.proxyProtocol) listens)); + streamProxy.map = builtins.listToAttrs (builtins.map + (site: + { + inherit (site) name; + value = + { + upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol + + (if site.value.http2 then httpsPortShift.http2 else 0); + proxyProtocol = true; + rewriteHttps = inputs.lib.mkDefault false; + }; + }) + (builtins.filter (listen: listen.value.proxyProtocol) listens)); + http = builtins.listToAttrs (builtins.map + (site: { inherit (site) name; value.rewriteHttps = {}; }) + (builtins.filter (site: site.value.global.rewriteHttps) sites)); + }; + acme.cert = builtins.listToAttrs (builtins.map + (site: { inherit (site) name; value.group = inputs.config.services.nginx.group; }) + sites); + }; + system.sops = + let + inherit (inputs.lib.strings) escapeURL; + detectAuthUsers = builtins.concatLists (builtins.map + (site: + ( + (builtins.map + (location: + { + name = "${escapeURL site.name}/${escapeURL location.name}"; + value = location.value.detectAuth.users; + }) + (builtins.filter (location: location.value.detectAuth or null != null) site.value.locations)) + ++ (inputs.lib.optionals (site.value.global.detectAuth != null) + [ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ]) + )) + sites); + addAuth = builtins.concatLists (builtins.map + (site: builtins.map (location: { name = "${escapeURL site.name}/${escapeURL location.name}"; - value = location.value.detectAuth.users; + value = location.value.addAuth; }) - (builtins.filter (location: location.value.detectAuth or null != null) site.value.locations)) - ++ (inputs.lib.optionals (site.value.global.detectAuth != null) - [ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ]) - )) - sites); - addAuth = builtins.concatLists (builtins.map - (site: builtins.map - (location: - { - name = "${escapeURL site.name}/${escapeURL location.name}"; - value = location.value.addAuth; - }) - (builtins.filter (location: location.value.addAuth or null != null) site.value.locations) - ) - sites); - in - { - templates = builtins.listToAttrs - ( - (builtins.map - (detectAuth: - { - name = "nginx/templates/detectAuth/${detectAuth.name}"; - value = + (builtins.filter (location: location.value.addAuth or null != null) site.value.locations) + ) + sites); + in + { + templates = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.listToAttrs + ( + (builtins.map + (detectAuth: inputs.lib.nameValuePair "nginx/templates/detectAuth/${detectAuth.name}" { owner = inputs.config.users.users.nginx.name; content = builtins.concatStringsSep "\n" (builtins.map - (user: "${user}:{PLAIN}${inputs.config.sops.placeholder."nginx/detectAuth/${user}"}") + (user: "${user}:{PLAIN}${placeholder."nginx/detectAuth/${user}"}") detectAuth.value); - }; - }) - detectAuthUsers) - ++ (builtins.map - (addAuth: - { - name = "nginx/templates/addAuth/${addAuth.name}"; - value = + }) + detectAuthUsers) + ++ (builtins.map + (addAuth: inputs.lib.nameValuePair "nginx/templates/addAuth/${addAuth.name}" { owner = inputs.config.users.users.nginx.name; content = - let placeholder = inputs.config.sops.placeholder."nginx/addAuth/${addAuth.value}"; - in ''proxy_set_header Authorization "Basic ${placeholder}";''; - }; - }) - addAuth) - ); - secrets = builtins.listToAttrs - ( - (builtins.map - (secret: { name = "nginx/detectAuth/${secret}"; value = {}; }) - (inputs.lib.unique (builtins.concatLists (builtins.map (detectAuth: detectAuth.value) - detectAuthUsers)))) - ++ (builtins.map - (secret: { name = "nginx/addAuth/${secret}"; value = {}; }) - (inputs.lib.unique (builtins.map (addAuth: addAuth.value) addAuth))) - ); - }; + ''proxy_set_header Authorization "Basic ${placeholder."nginx/addAuth/${addAuth.value}"}";''; + }) + addAuth) + ); + secrets = builtins.listToAttrs + ( + (builtins.map + (secret: { name = "nginx/detectAuth/${secret}"; value = {}; }) + (inputs.lib.unique (builtins.concatLists (builtins.map (detectAuth: detectAuth.value) + detectAuthUsers)))) + ++ (builtins.map + (secret: { name = "nginx/addAuth/${secret}"; value = {}; }) + (inputs.lib.unique (builtins.map (addAuth: addAuth.value) addAuth))) + ); + }; + }; } ) ]); diff --git a/modules/services/nix-serve.nix b/modules/services/nix-serve.nix index 7f9d0f93..acd9a27f 100644 --- a/modules/services/nix-serve.nix +++ b/modules/services/nix-serve.nix @@ -15,12 +15,15 @@ inputs: enable = true; package = inputs.pkgs.nix-serve-ng; openFirewall = true; - secretKeyFile = inputs.config.sops.secrets."store/signingKey".path; + secretKeyFile = inputs.config.nixos.system.sops.secrets."store/signingKey".path; # curl -L cache.nixos.org/nix-cache-info # use this cache after official one extraParams = "--priority 50"; }; - sops.secrets."store/signingKey" = {}; - nixos.services.nginx.https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000"; + nixos = + { + system.sops.secrets."store/signingKey" = {}; + services.nginx.https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000"; + }; }; } diff --git a/modules/services/nixvirt.nix b/modules/services/nixvirt.nix index eb4feb7d..71f8819d 100644 --- a/modules/services/nixvirt.nix +++ b/modules/services/nixvirt.nix @@ -83,7 +83,7 @@ inputs: domains = builtins.map (vm: { - definition = inputs.config.sops.templates."nixvirt/${vm.name}.xml".path; + definition = inputs.config.nixos.system.sops.templates."nixvirt/${vm.name}.xml".path; active = true; restart = false; }) @@ -122,146 +122,142 @@ inputs: vnc_listen = "0.0.0.0" ''; }; - nixos.services = + nixos = { - nginx = - let hosts = builtins.concatLists (builtins.map - (vm: builtins.map - (domain: - { - inherit domain; - ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}"; - }) - vm.network.portForward.web) - (builtins.attrValues nixvirt.instance)); - in - { - transparentProxy.map = builtins.listToAttrs (builtins.map - (host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts); - http = builtins.listToAttrs (builtins.map - (host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts); - }; - kvm = {}; - }; - sops = - { - templates = builtins.listToAttrs (builtins.map - (vm: - { - name = "nixvirt/${vm.name}.xml"; - value.content = inputs.topInputs.nixvirt.lib.domain.getXML - # port from 8bcc23e27a62297254d0e9c87281e650ff777132 + system.sops = + { + templates = inputs.lib.mapAttrs' + (n: v: inputs.lib.nameValuePair "nixvirt/${n}.xml" { - inherit (vm) name; - inherit (vm.value) uuid; - type = "kvm"; - vcpu = { placement = "static"; count = vm.value.cpu.count; }; - cputune = inputs.lib.optionalAttrs (vm.value.cpu.set != null) + content = inputs.topInputs.nixvirt.lib.domain.getXML + # port from 8bcc23e27a62297254d0e9c87281e650ff777132 { - vcpupin = builtins.genList - (cpu: { vcpu = cpu; cpuset = builtins.elemAt vm.value.cpu.set cpu; }) - vm.value.cpu.count; - }; - memory = - { - count = vm.value.memory.sizeMB; - unit = "MiB"; - nosharepages = vm.value.memory.dedicated; - locked = vm.value.memory.dedicated; - }; - os = - { - type = "hvm"; - arch = "x86_64"; - machine = "q35"; - bootmenu = { enable = true; timeout = 15000; }; - loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; }; - nvram = + name = n; + inherit (v) uuid; + type = "kvm"; + vcpu = { placement = "static"; count = v.cpu.count; }; + cputune = inputs.lib.optionalAttrs (v.cpu.set != null) { - template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd"; - path = "/var/lib/libvirt/qemu/nvram/${vm.name}_VARS.fd"; - templateFormat = "raw"; - format = "raw"; + vcpupin = builtins.genList (cpu: { vcpu = cpu; cpuset = builtins.elemAt v.cpu.set cpu; }) v.cpu.count; }; - }; - features = { acpi = {}; apic = {}; }; - cpu = - { - mode = "host-passthrough"; - topology = + memory = { - sockets = 1; - dies = 1; - cores = if vm.value.cpu.hyprthread then vm.value.cpu.count / 2 else vm.value.cpu.count; - threads = if vm.value.cpu.hyprthread then 2 else 1; + count = v.memory.sizeMB; + unit = "MiB"; + nosharepages = v.memory.dedicated; + locked = v.memory.dedicated; }; - }; - clock = - { - offset = "utc"; - timer = - [ - { name = "rtc"; tickpolicy = "catchup"; } - { name = "pit"; tickpolicy = "delay"; } - { name = "hpet"; present = false; } - ]; - }; - devices = - { - emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64"; - disk = - [ + os = + { + type = "hvm"; + arch = "x86_64"; + machine = "q35"; + bootmenu = { enable = true; timeout = 15000; }; + loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; }; + nvram = { - type = "file"; - device = "disk"; - driver = { name = "qemu"; type = "raw"; cache = "writeback"; discard = "unmap"; }; - source.file = "${if vm.value.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/" - + "${vm.value.storage.name}.img"; - target = { dev = "vda"; bus = "virtio"; }; - boot.order = 1; - } + template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd"; + path = "/var/lib/libvirt/qemu/nvram/${n}_VARS.fd"; + templateFormat = "raw"; + format = "raw"; + }; + }; + features = { acpi = {}; apic = {}; }; + cpu = + { + mode = "host-passthrough"; + topology = { - type = "file"; - device = "cdrom"; - driver = { name = "qemu"; type = "raw"; }; - source.file = "${inputs.topInputs.self.src.iso.netboot}"; - target = { dev = "sdc"; bus = "sata"; }; - readonly = true; - boot.order = 10; - } - ]; - interface = - { - type = "bridge"; - model.type = "virtio"; - mac.address = vm.value.network.mac; - source.bridge = if vm.value.network.bridge then "nixvirt" else "virbr0"; + sockets = 1; + dies = 1; + cores = if v.cpu.hyprthread then v.cpu.count / 2 else v.cpu.count; + threads = if v.cpu.hyprthread then 2 else 1; + }; }; - input = - [ - { type = "tablet"; bus = "usb"; } - { type = "mouse"; bus = "ps2"; } - { type = "keyboard"; bus = "ps2"; } - ]; - graphics = + clock = { - type = "vnc"; - autoport = false; - port = vm.value.network.vnc.port; - listen.type = "address"; - passwd = inputs.config.sops.placeholder."nixvirt/${vm.name}"; + offset = "utc"; + timer = + [ + { name = "rtc"; tickpolicy = "catchup"; } + { name = "pit"; tickpolicy = "delay"; } + { name = "hpet"; present = false; } + ]; + }; + devices = + { + emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64"; + disk = + [ + { + type = "file"; + device = "disk"; + driver = { name = "qemu"; type = "raw"; cache = "writeback"; discard = "unmap"; }; + source.file = "${if v.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/" + + "${v.storage.name}.img"; + target = { dev = "vda"; bus = "virtio"; }; + boot.order = 1; + } + { + type = "file"; + device = "cdrom"; + driver = { name = "qemu"; type = "raw"; }; + source.file = "${inputs.topInputs.self.src.iso.netboot}"; + target = { dev = "sdc"; bus = "sata"; }; + readonly = true; + boot.order = 10; + } + ]; + interface = + { + type = "bridge"; + model.type = "virtio"; + mac.address = v.network.mac; + source.bridge = if v.network.bridge then "nixvirt" else "virbr0"; + }; + input = + [ + { type = "tablet"; bus = "usb"; } + { type = "mouse"; bus = "ps2"; } + { type = "keyboard"; bus = "ps2"; } + ]; + graphics = + { + type = "vnc"; + autoport = false; + port = v.network.vnc.port; + listen.type = "address"; + passwd = inputs.config.sops.placeholder."nixvirt/${n}"; + }; + video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; }; + rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; }; }; - video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; }; - rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; }; }; + }) + nixvirt.instance; + secrets = inputs.lib.mapAttrs' (n: _: inputs.lib.nameValuePair "nixvirt/${n}" {}) nixvirt.instance; + }; + services = + { + nginx = + let hosts = builtins.concatLists (builtins.map + (vm: builtins.map + (domain: + { + inherit domain; + ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}"; + }) + vm.network.portForward.web) + (builtins.attrValues nixvirt.instance)); + in + { + transparentProxy.map = builtins.listToAttrs (builtins.map + (host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts); + http = builtins.listToAttrs (builtins.map + (host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts); }; - }) - (inputs.localLib.attrsToList nixvirt.instance)); - secrets = builtins.listToAttrs (builtins.map - (vm: { name = "nixvirt/${vm}"; value = {}; }) (builtins.attrNames nixvirt.instance)); - placeholder = builtins.listToAttrs (builtins.map - (vm: { name = "nixvirt/${vm}"; value = builtins.hashString "sha256" "nixvirt/${vm}"; }) - (builtins.attrNames nixvirt.instance)); + kvm = {}; + }; }; security.wrappers.vm = { diff --git a/modules/services/open-webui.nix b/modules/services/open-webui.nix index 8bcda869..d9ca258d 100644 --- a/modules/services/open-webui.nix +++ b/modules/services/open-webui.nix @@ -28,19 +28,22 @@ inputs: ENABLE_IMAGE_GENERATION = "True"; IMAGES_OPENAI_API_BASE_URL = "https://oa.api2d.net/v1"; }; - environmentFile = inputs.config.sops.templates."open-webui.env".path; + environmentFile = inputs.config.nixos.system.sops.templates."open-webui.env".path; }; - sops = + nixos = { - templates."open-webui.env".content = let inherit (inputs.config.sops) placeholder; in - '' - OPENAI_API_KEY=${placeholder."open-webui/openai"} - WEBUI_SECRET_KEY=${placeholder."open-webui/webui"} - IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"} - ''; - secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; }; + system.sops = + { + templates."open-webui.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in + '' + OPENAI_API_KEY=${placeholder."open-webui/openai"} + WEBUI_SECRET_KEY=${placeholder."open-webui/webui"} + IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"} + ''; + secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; }; + }; + services.nginx.https."${open-webui.hostname}".location."/".proxy = + { upstream = "http://127.0.0.1:8080"; websocket = true; }; }; - nixos.services.nginx.https."${open-webui.hostname}".location."/".proxy = - { upstream = "http://127.0.0.1:8080"; websocket = true; }; }; } diff --git a/modules/services/peertube.nix b/modules/services/peertube.nix index 694f6f05..a4ed13d4 100644 --- a/modules/services/peertube.nix +++ b/modules/services/peertube.nix @@ -17,48 +17,46 @@ inputs: listenHttp = 5046; listenWeb = 443; enableWebHttps = true; - serviceEnvironmentFile = inputs.config.sops.templates."peertube/env".path; - secrets.secretsFile = inputs.config.sops.secrets."peertube/secrets".path; + serviceEnvironmentFile = inputs.config.nixos.system.sops.templates."peertube/env".path; + secrets.secretsFile = inputs.config.nixos.system.sops.secrets."peertube/secrets".path; configureNginx = true; database = { createLocally = true; host = "127.0.0.1"; - passwordFile = inputs.config.sops.secrets."peertube/postgresql".path; + passwordFile = inputs.config.nixos.system.sops.secrets."peertube/postgresql".path; }; redis = { host = "127.0.0.1"; port = 7599; - passwordFile = inputs.config.sops.secrets."redis/peertube".path; - }; - smtp.passwordFile = inputs.config.sops.secrets."peertube/smtp".path; - settings.smtp = - { - host = "mail.chn.moe"; - username = "bot@chn.moe"; - from_address = "bot@chn.moe"; + passwordFile = inputs.config.nixos.system.sops.secrets."redis/peertube".path; }; + smtp.passwordFile = inputs.config.nixos.system.sops.secrets."peertube/smtp".path; + settings.smtp = { host = "mail.chn.moe"; username = "bot@chn.moe"; from_address = "bot@chn.moe"; }; }; - sops = + nixos = { - templates."peertube/env".content = - '' - PT_INITIAL_ROOT_PASSWORD=${inputs.config.sops.placeholder."peertube/password"} - ''; - secrets = + system.sops = { - "peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; }; - "peertube/password" = {}; - "peertube/secrets".owner = inputs.config.services.peertube.user; - "peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; }; + templates."peertube/env".content = + '' + PT_INITIAL_ROOT_PASSWORD=${inputs.config.nixos.system.sops.placeholder."peertube/password"} + ''; + secrets = + { + "peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; }; + "peertube/password" = {}; + "peertube/secrets".owner = inputs.config.services.peertube.user; + "peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; }; + }; + }; + services = + { + nginx.https.${peertube.hostname}.global.configName = peertube.hostname; + postgresql.instances.peertube = {}; + redis.instances.peertube.port = 7599; }; - }; - nixos.services = - { - nginx.https.${peertube.hostname}.global.configName = peertube.hostname; - postgresql.instances.peertube = {}; - redis.instances.peertube.port = 7599; }; systemd.services.peertube.after = [ "redis-peertube.service" ]; }; diff --git a/modules/services/photoprism.nix b/modules/services/photoprism.nix index 7d391e70..8a56a9bf 100644 --- a/modules/services/photoprism.nix +++ b/modules/services/photoprism.nix @@ -23,21 +23,24 @@ inputs: { after = [ "mariadb.service" ]; requires = [ "mariadb.service" ]; - serviceConfig.EnvironmentFile = inputs.config.sops.templates."photoprism/env".path; + serviceConfig.EnvironmentFile = inputs.config.nixos.system.sops.templates."photoprism/env".path; }; - sops = + nixos = { - templates."photoprism/env".content = let placeholder = inputs.config.sops.placeholder; in - '' - PHOTOPRISM_ADMIN_PASSWORD=${placeholder."photoprism/adminPassword"} - PHOTOPRISM_DATABASE_PASSWORD=${placeholder."mariadb/photoprism"} - ''; - secrets."photoprism/adminPassword" = {}; - }; - nixos.services = - { - mariadb.instances.photoprism = {}; - nginx.https."photoprism.chn.moe".location."/".proxy = { upstream = "http://127.0.0.1:2342"; websocket = true; }; + system.sops = + { + templates."photoprism/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in + '' + PHOTOPRISM_ADMIN_PASSWORD=${placeholder."photoprism/adminPassword"} + PHOTOPRISM_DATABASE_PASSWORD=${placeholder."mariadb/photoprism"} + ''; + secrets."photoprism/adminPassword" = {}; + }; + services = + { + mariadb.instances.photoprism = {}; + nginx.https."photoprism.chn.moe".location."/".proxy = { upstream = "http://127.0.0.1:2342"; websocket = true; }; + }; }; }; } diff --git a/modules/services/postgresql.nix b/modules/services/postgresql.nix index 1487f977..8e737534 100644 --- a/modules/services/postgresql.nix +++ b/modules/services/postgresql.nix @@ -63,7 +63,7 @@ inputs: let passwordFile = if db.value.passwordFile or null != null then db.value.passwordFile - else inputs.config.sops.secrets."postgresql/${db.value.user}".path; + else inputs.config.nixos.system.sops.secrets."postgresql/${db.value.user}".path; initializeFlag = if db.value.initializeFlags != {} then " WITH " @@ -85,7 +85,7 @@ inputs: + " | grep -E '^${db.value.user}$' -q" + " || $PSQL -tAc \"ALTER DATABASE ${db.value.database} OWNER TO ${db.value.user}\"") (inputs.localLib.attrsToList postgresql.instances))); - sops.secrets = builtins.listToAttrs (builtins.map + nixos.system.sops.secrets = builtins.listToAttrs (builtins.map (db: { name = "postgresql/${db.value.user}"; value.owner = inputs.config.users.users.postgres.name; }) (builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList postgresql.instances))); environment.persistence."/nix/nodatacow".directories = inputs.lib.mkIf postgresql.nodatacow diff --git a/modules/services/redis.nix b/modules/services/redis.nix index 10b40615..c393ffe0 100644 --- a/modules/services/redis.nix +++ b/modules/services/redis.nix @@ -28,12 +28,13 @@ inputs: # unixSocket = null; # bug unixSocketPerm = 600; requirePassFile = - if server.value.passwordFile == null then inputs.config.sops.secrets."redis/${server.name}".path + if server.value.passwordFile == null + then inputs.config.nixos.system.sops.secrets."redis/${server.name}".path else server.value.passwordFile; }; }) (inputs.localLib.attrsToList redis.instances)); - sops.secrets = builtins.listToAttrs (builtins.map + nixos.system.sops.secrets = builtins.listToAttrs (builtins.map (server: { name = "redis/${server.name}"; value.owner = inputs.config.users.users.${server.value.user}.name; }) (builtins.filter (server: server.value.passwordFile == null) (inputs.localLib.attrsToList redis.instances))); systemd.services = builtins.listToAttrs (builtins.map diff --git a/modules/services/rsshub.nix b/modules/services/rsshub.nix index d8015d43..120c9977 100644 --- a/modules/services/rsshub.nix +++ b/modules/services/rsshub.nix @@ -15,34 +15,37 @@ inputs: image = "rsshub:latest"; imageFile = inputs.topInputs.self.src.rsshub; ports = [ "127.0.0.1:5221:5221/tcp" ]; - environmentFiles = [ inputs.config.sops.templates."rsshub/env".path ]; + environmentFiles = [ inputs.config.nixos.system.sops.templates."rsshub/env".path ]; }; - sops = + nixos = { - templates."rsshub/env".content = let placeholder = inputs.config.sops.placeholder; in - '' - PORT=5221 - CACHE_TYPE=memory - PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}' - YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}' - YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}' - YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}' - YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}' - TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}' - ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}' - XDG_CONFIG_HOME='/var/cache/rsshub/chromium' - XDG_CACHE_HOME='/var/cache/rsshub/chromium' - BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}' - ''; - secrets = (builtins.listToAttrs (builtins.map (secret: { name = "rsshub/${secret}"; value = {}; }) - [ - "pixiv-refreshtoken" - "youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token" - "twitter-auth-token" - "bilibili-cookie" - "zhihu-cookies" - ])); + system.sops = + { + templates."rsshub/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in + '' + PORT=5221 + CACHE_TYPE=memory + PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}' + YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}' + YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}' + YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}' + YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}' + TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}' + ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}' + XDG_CONFIG_HOME='/var/cache/rsshub/chromium' + XDG_CACHE_HOME='/var/cache/rsshub/chromium' + BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}' + ''; + secrets = (builtins.listToAttrs (builtins.map (secret: inputs.lib.nameValuePair "rsshub/${secret}" {}) + [ + "pixiv-refreshtoken" + "youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token" + "twitter-auth-token" + "bilibili-cookie" + "zhihu-cookies" + ])); + }; + services.nginx.https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221"; }; - nixos.services.nginx.https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221"; }; } diff --git a/modules/services/searx.nix b/modules/services/searx.nix index 5bc7f306..6ffd9c37 100644 --- a/modules/services/searx.nix +++ b/modules/services/searx.nix @@ -14,16 +14,19 @@ inputs: { enable = true; settings.server = { port = 8081; bind_address = "127.0.0.1"; secret_key = "@SEARX_SECRET_KEY@"; }; - environmentFile = inputs.config.sops.templates."searx.env".path; + environmentFile = inputs.config.nixos.system.sops.templates."searx.env".path; }; - sops = + nixos = { - templates."searx.env".content = let inherit (inputs.config.sops) placeholder; in - '' - SEARX_SECRET_KEY=${placeholder."searx/secret-key"} - ''; - secrets."searx/secret-key" = {}; + system.sops = + { + templates."searx.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in + '' + SEARX_SECRET_KEY=${placeholder."searx/secret-key"} + ''; + secrets."searx/secret-key" = {}; + }; + services.nginx.https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081"; }; - nixos.services.nginx.https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081"; }; } diff --git a/modules/services/send.nix b/modules/services/send.nix index 8ca06f1f..8ce27c23 100644 --- a/modules/services/send.nix +++ b/modules/services/send.nix @@ -20,7 +20,7 @@ inputs: createLocally = false; host = "127.0.0.1"; port = 9184; - passwordFile = inputs.config.sops.secrets."redis/send".path; + passwordFile = inputs.config.nixos.system.sops.secrets."redis/send".path; }; }; systemd.services.send.after = [ "redis-send.service" ]; diff --git a/modules/services/slurm.nix b/modules/services/slurm.nix index 79d1c957..55c96ddd 100644 --- a/modules/services/slurm.nix +++ b/modules/services/slurm.nix @@ -177,7 +177,7 @@ inputs: # ConstrainDevices=yes ''; }; - munge = { enable = true; password = inputs.config.sops.secrets."munge.key".path; }; + munge = { enable = true; password = inputs.config.nixos.system.sops.secrets."munge.key".path; }; }; systemd.services.slurmd.environment = let gpus = slurm.node.${inputs.config.nixos.model.hostname}.gpus or null; @@ -186,12 +186,16 @@ inputs: CUDA_PATH = "${inputs.pkgs.cudatoolkit}"; LD_LIBRARY_PATH = "${inputs.config.hardware.nvidia.package}/lib"; }; - sops.secrets."munge.key" = + nixos.system.sops.secrets."munge.key" = { format = "binary"; - sopsFile = inputs.localLib.mkConditional (inputs.config.nixos.model.cluster == null) - "${builtins.dirOf inputs.config.sops.defaultSopsFile}/munge.key" - "${inputs.config.nixos.system.sops.clusterSopsDir}/munge.key"; + sopsFile = + let + devicePath = "${inputs.topInputs.self}/devices"; + inherit (inputs.config.nixos) model; + in inputs.localLib.mkConditional (model.cluster == null) + "${devicePath}/${model.hostname}/secrets/munge.key" + "${devicePath}/${model.cluster.clusterName}/secrets/munge.key"; owner = inputs.config.systemd.services.munged.serviceConfig.User; }; environment.sessionVariables = { SLURM_UNBUFFEREDIO = "1"; SLURM_CPU_BIND = "v"; }; @@ -206,7 +210,7 @@ inputs: { enable = true; dbdHost = "localhost"; - storagePassFile = inputs.config.sops.secrets."slurm/db".path; + storagePassFile = inputs.config.nixos.system.sops.secrets."slurm/db".path; extraConfig = '' StorageHost=* @@ -224,24 +228,20 @@ inputs: services.slurmctld = { after = [ "suid-sgid-wrappers.service" ]; serviceConfig.MemorySwapMax = "0"; }; tmpfiles.rules = [ "d /var/log/slurmctld 700 slurm slurm" ]; }; - sops = + nixos.system.sops = { secrets = { "slurm/db" = { owner = "slurm"; key = "mariadb/slurm"; }; } // builtins.listToAttrs (builtins.map - (n: - { - name = "telegram/${n}"; - value.sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; - }) + (n: inputs.lib.nameValuePair "telegram/${n}" {}) [ "token" "user/chn" "user/hjp" ]); templates."info.yaml" = { owner = "slurm"; - content = let inherit (inputs.config.sops) placeholder; in builtins.toJSON + content = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.toJSON { token = placeholder."telegram/token"; - user = builtins.listToAttrs (builtins.map (n: { name = n; value = placeholder."telegram/user/${n}"; }) - [ "chn" "hjp" ]); + user = builtins.listToAttrs (builtins.map + (n: inputs.lib.nameValuePair n placeholder."telegram/user/${n}") [ "chn" "hjp" ]); slurmConf = "${inputs.config.services.slurm.etcSlurm}/slurm.conf"; }; }; @@ -252,7 +252,7 @@ inputs: let info = inputs.pkgs.localPackages.info.override { slurm = inputs.config.services.slurm.package; - configFile = inputs.config.sops.templates."info.yaml".path; + configFile = inputs.config.nixos.system.sops.templates."info.yaml".path; }; in "${info}/bin/info"; program = "slurm-info"; diff --git a/modules/services/synapse.nix b/modules/services/synapse.nix index 58697fc5..b2364b97 100644 --- a/modules/services/synapse.nix +++ b/modules/services/synapse.nix @@ -43,7 +43,7 @@ inputs: let package = inputs.pkgs.matrix-synapse.override { extras = [ "url-preview" "postgres" "redis" ]; plugins = []; }; - config = inputs.config.sops.templates."synapse/${instance.name}/config.yaml".path; + config = inputs.config.nixos.system.sops.templates."synapse/${instance.name}/config.yaml".path; homeserver = "${package}/bin/synapse_homeserver"; in { @@ -100,143 +100,145 @@ inputs: ]; }) (inputs.localLib.attrsToList synapse.instances)); - sops = inputs.lib.mkMerge (builtins.map - (instance: - { - templates."synapse/${instance.name}/config.yaml" = - { - owner = "synapse-${instance.name}"; - group = "synapse-${instance.name}"; - content = - let - inherit (inputs.config.sops) placeholder; - in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml" - { - server_name = instance.value.matrixHostname; - public_baseurl = "https://${instance.value.hostname}/"; - listeners = - [{ - bind_addresses = [ "127.0.0.1" ]; - inherit (instance.value) port; - resources = [{ names = [ "client" "federation" ]; compress = false; }]; - tls = false; - type = "http"; - x_forwarded = true; - }]; - database = - { - name = "psycopg2"; - args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in - { - user = name; - password = placeholder."postgresql/${name}"; - database = name; - host = "127.0.0.1"; - port = "5432"; - }; - allow_unsafe_locale = true; - }; - redis = - { - enabled = true; - port = instance.value.redisPort; - password = placeholder."redis/synapse-${instance.name}"; - }; - turn_shared_secret = placeholder."synapse/${instance.name}/coturn"; - registration_shared_secret = placeholder."synapse/${instance.name}/registration"; - macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon"; - form_secret = placeholder."synapse/${instance.name}/form"; - signing_key_path = inputs.config.sops.secrets."synapse/${instance.name}/signing-key".path; - email = - { - smtp_host = "mail.chn.moe"; - smtp_port = 25; - smtp_user = "bot@chn.moe"; - smtp_pass = placeholder."mail/bot"; - require_transport_security = true; - notif_from = "Your Friendly %(app)s homeserver "; - app_name = "Haonan Chen's synapse"; - }; - admin_contact = "mailto:chn@chn.moe"; - enable_registration = true; - registrations_require_3pid = [ "email" ]; - registration_requires_token = true; - turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ]; - max_upload_size = "1024M"; - web_client_location = "https://element.chn.moe/"; - report_stats = true; - trusted_key_servers = - [{ - server_name = "matrix.org"; - verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; - }]; - suppress_key_server_warning = true; - log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml" - { - version = 1; - formatters.precise.format = - "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s"; - handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; }; - root = { level = "INFO"; handlers = [ "console" ]; }; - disable_existing_loggers = true; - }; - pid_file = "/run/synapse-${instance.name}.pid"; - media_store_path = "/var/lib/synapse/${instance.name}/media_store"; - presence.enabled = true; - url_preview_enabled = true; - url_preview_ip_range_blacklist = - [ - "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24" - "192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32" - "203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8" - ]; - max_image_pixels = "32M"; - dynamic_thumbnails = false; - # this is required for displaying thumbnails in sticker widgets - enable_authenticated_media = false; - }); - }; - secrets = (builtins.listToAttrs (builtins.map - (secret: { name = "synapse/${instance.name}/${secret}"; value = {}; }) - [ "coturn" "registration" "macaroon" "form" ])) - // { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; } - // { "mail/bot" = {}; }; - }) - (inputs.localLib.attrsToList synapse.instances)); - nixos.services = + nixos = { - postgresql.instances = builtins.listToAttrs (builtins.map + system.sops = inputs.lib.mkMerge (builtins.map (instance: { - name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; - value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; }; - }) - (inputs.localLib.attrsToList synapse.instances)); - redis.instances = builtins.listToAttrs (builtins.map - (instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; }) - (inputs.localLib.attrsToList synapse.instances)); - nginx.https = builtins.listToAttrs (builtins.map - (instance: with instance.value; - { - name = hostname; - value.location = + templates."synapse/${instance.name}/config.yaml" = { - "/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; }; - "/.well-known/matrix/server".static = - { - root = builtins.toString (inputs.pkgs.writeTextFile + owner = "synapse-${instance.name}"; + content = + let + inherit (inputs.config.nixos.system.sops) placeholder; + in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml" { - name = "server"; - text = builtins.toJSON + server_name = instance.value.matrixHostname; + public_baseurl = "https://${instance.value.hostname}/"; + listeners = + [{ + bind_addresses = [ "127.0.0.1" ]; + inherit (instance.value) port; + resources = [{ names = [ "client" "federation" ]; compress = false; }]; + tls = false; + type = "http"; + x_forwarded = true; + }]; + database = { - "m.server" = "${hostname}:443"; + name = "psycopg2"; + args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in + { + user = name; + password = placeholder."postgresql/${name}"; + database = name; + host = "127.0.0.1"; + port = "5432"; + }; + allow_unsafe_locale = true; }; - destination = "/.well-known/matrix/server"; + redis = + { + enabled = true; + port = instance.value.redisPort; + password = placeholder."redis/synapse-${instance.name}"; + }; + turn_shared_secret = placeholder."synapse/${instance.name}/coturn"; + registration_shared_secret = placeholder."synapse/${instance.name}/registration"; + macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon"; + form_secret = placeholder."synapse/${instance.name}/form"; + signing_key_path = inputs.config.nixos.system.sops.secrets."synapse/${instance.name}/signing-key".path; + email = + { + smtp_host = "mail.chn.moe"; + smtp_port = 25; + smtp_user = "bot@chn.moe"; + smtp_pass = placeholder."mail/bot"; + require_transport_security = true; + notif_from = "Your Friendly %(app)s homeserver "; + app_name = "Haonan Chen's synapse"; + }; + admin_contact = "mailto:chn@chn.moe"; + enable_registration = true; + registrations_require_3pid = [ "email" ]; + registration_requires_token = true; + turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ]; + max_upload_size = "1024M"; + web_client_location = "https://element.chn.moe/"; + report_stats = true; + trusted_key_servers = + [{ + server_name = "matrix.org"; + verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + }]; + suppress_key_server_warning = true; + log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml" + { + version = 1; + formatters.precise.format = + "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s"; + handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; }; + root = { level = "INFO"; handlers = [ "console" ]; }; + disable_existing_loggers = true; + }; + pid_file = "/run/synapse-${instance.name}.pid"; + media_store_path = "/var/lib/synapse/${instance.name}/media_store"; + presence.enabled = true; + url_preview_enabled = true; + url_preview_ip_range_blacklist = + [ + "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24" + "192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32" + "203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8" + ]; + max_image_pixels = "32M"; + dynamic_thumbnails = false; + # this is required for displaying thumbnails in sticker widgets + enable_authenticated_media = false; }); - }; }; + secrets = (builtins.listToAttrs (builtins.map + (secret: { name = "synapse/${instance.name}/${secret}"; value = {}; }) + [ "coturn" "registration" "macaroon" "form" ])) + // { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; } + // { "mail/bot" = {}; }; }) (inputs.localLib.attrsToList synapse.instances)); + services = + { + postgresql.instances = builtins.listToAttrs (builtins.map + (instance: + { + name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; + value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; }; + }) + (inputs.localLib.attrsToList synapse.instances)); + redis.instances = builtins.listToAttrs (builtins.map + (instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; }) + (inputs.localLib.attrsToList synapse.instances)); + nginx.https = builtins.listToAttrs (builtins.map + (instance: with instance.value; + { + name = hostname; + value.location = + { + "/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; }; + "/.well-known/matrix/server".static = + { + root = builtins.toString (inputs.pkgs.writeTextFile + { + name = "server"; + text = builtins.toJSON + { + "m.server" = "${hostname}:443"; + }; + destination = "/.well-known/matrix/server"; + }); + }; + }; + }) + (inputs.localLib.attrsToList synapse.instances)); + }; }; }; } diff --git a/modules/services/vaultwarden.nix b/modules/services/vaultwarden.nix index fddd9cd0..77b1d80a 100644 --- a/modules/services/vaultwarden.nix +++ b/modules/services/vaultwarden.nix @@ -25,29 +25,32 @@ inputs: SMTP_SECURITY = "force_tls"; SMTP_USERNAME = "bot@chn.moe"; }; - environmentFile = inputs.config.sops.templates."vaultwarden.env".path; + environmentFile = inputs.config.nixos.system.sops.templates."vaultwarden.env".path; }; - sops = + nixos = { - templates."vaultwarden.env" = let placeholder = inputs.config.sops.placeholder; in + system.sops = { - owner = "vaultwarden"; - group = "vaultwarden"; - content = - '' - DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden - ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"} - SMTP_PASSWORD=${placeholder."mail/bot"} - ''; + templates."vaultwarden.env" = let inherit (inputs.config.nixos.system.sops) placeholder; in + { + owner = "vaultwarden"; + group = "vaultwarden"; + content = + '' + DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden + ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"} + SMTP_PASSWORD=${placeholder."mail/bot"} + ''; + }; + secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; }; + }; + services = + { + postgresql.instances.vaultwarden = {}; + nginx.https.${vaultwarden.hostname}.location."/".proxy = + { upstream = "http://127.0.0.1:8000"; websocket = true; }; }; - secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; }; }; systemd.services.vaultwarden.after = [ "postgresql.service" ]; - nixos.services = - { - postgresql.instances.vaultwarden = {}; - nginx.https.${vaultwarden.hostname}.location."/".proxy = - { upstream = "http://127.0.0.1:8000"; websocket = true; }; - }; }; } diff --git a/modules/services/wireguard.nix b/modules/services/wireguard.nix index 3f436e7a..7ade84f0 100644 --- a/modules/services/wireguard.nix +++ b/modules/services/wireguard.nix @@ -33,7 +33,7 @@ inputs: { inherit (wg.value) listenPort; ips = [ "${wg.value.ip}/${builtins.toString wg.value.netmask}" ]; - privateKeyFile = inputs.config.sops.secrets.wireguard.path; + privateKeyFile = inputs.config.nixos.system.sops.secrets.wireguard.path; peers = builtins.map (peer: { @@ -45,6 +45,6 @@ inputs: }; }) (inputs.localLib.attrsToList wireguard)); - sops.secrets.wireguard = {}; + nixos.system.sops.secrets.wireguard = {}; }; } diff --git a/modules/services/xray/client.nix b/modules/services/xray/client.nix index 1e27956e..ec4fe45d 100644 --- a/modules/services/xray/client.nix +++ b/modules/services/xray/client.nix @@ -43,7 +43,7 @@ inputs: }; resolved.enable = false; }; - sops = + nixos.system.sops = { templates."xray-client.json" = { @@ -120,7 +120,7 @@ inputs: port = 443; users = [{ - id = inputs.config.sops.placeholder."xray-client/uuid"; + id = inputs.config.nixos.system.sops.placeholder."xray-client/uuid"; encryption = "none"; flow = "xtls-rprx-vision-udp443"; }]; @@ -179,7 +179,8 @@ inputs: { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-client.json".path}"; + script = let config = inputs.config.nixos.system.sops.templates."xray-client.json".path; in + "exec ${inputs.pkgs.xray}/bin/xray -config ${config}"; serviceConfig = { User = "v2ray"; @@ -191,7 +192,7 @@ inputs: LimitNOFILE = 524288; CPUSchedulingPolicy = "rr"; }; - restartTriggers = [ inputs.config.sops.templates."xray-client.json".file ]; + restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-client.json".file ]; }; v2ray-forwarder = { diff --git a/modules/services/xray/server.nix b/modules/services/xray/server.nix index 0c4e275d..756d96d7 100644 --- a/modules/services/xray/server.nix +++ b/modules/services/xray/server.nix @@ -10,136 +10,144 @@ inputs: }; config = let inherit (inputs.config.nixos.services.xray) server; in inputs.lib.mkIf (server != null) ( - let userList = builtins.attrNames - (inputs.pkgs.localPackages.fromYaml (builtins.readFile inputs.config.sops.defaultSopsFile)).xray-server.clients; + let userList = builtins.map (user: builtins.elemAt user 2) (builtins.filter + (user: builtins.elem user == 3 && inputs.lib.lists.hasPrefix [ "xray-server" "clients" ]) + inputs.config.nixos.system.sops.availableKeys); in { - sops = + nixos = { - templates."xray-server.json" = + system.sops = { - owner = inputs.config.users.users.v2ray.name; - group = inputs.config.users.users.v2ray.group; - content = builtins.toJSON + templates."xray-server.json" = { - log.loglevel = "warning"; - inbounds = - [ - ( - let fallbackPort = builtins.toString - (with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2); - in + owner = inputs.config.users.users.v2ray.name; + group = inputs.config.users.users.v2ray.group; + content = builtins.toJSON + { + log.loglevel = "warning"; + inbounds = + [ + ( + let fallbackPort = builtins.toString + (with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2); + in + { + port = 4726; + listen = "127.0.0.1"; + protocol = "vless"; + settings = + { + clients = builtins.map + (n: + { + id = inputs.config.nixos.system.sops.placeholder."xray-server/clients/${n}"; + flow = "xtls-rprx-vision"; + email = "${n}@xray.chn.moe"; + }) + userList; + decryption = "none"; + fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }]; + }; + streamSettings = + { + network = "raw"; + security = "reality"; + realitySettings = + { + dest = "127.0.0.1:${fallbackPort}"; + serverNames = [ server.serverName ]; + privateKey = inputs.config.nixos.system.sops.placeholder."xray-server/private-key"; + minClientVer = "1.8.0"; + shortIds = [ "" ]; + }; + }; + sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; }; + tag = "in-legacy"; + } + ) { - port = 4726; + port = 4638; listen = "127.0.0.1"; protocol = "vless"; - settings = - { - clients = builtins.map - (n: - { - id = inputs.config.sops.placeholder."xray-server/clients/${n}"; - flow = "xtls-rprx-vision"; - email = "${n}@xray.chn.moe"; - }) - userList; - decryption = "none"; - fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }]; - }; - streamSettings = - { - network = "raw"; - security = "reality"; - realitySettings = - { - dest = "127.0.0.1:${fallbackPort}"; - serverNames = [ server.serverName ]; - privateKey = inputs.config.sops.placeholder."xray-server/private-key"; - minClientVer = "1.8.0"; - shortIds = [ "" ]; - }; - }; - sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; }; - tag = "in-legacy"; + settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; }; + streamSettings.network = "raw"; + sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; }; + tag = "in-localdns"; } - ) - { - port = 4638; - listen = "127.0.0.1"; - protocol = "vless"; - settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; }; - streamSettings.network = "raw"; - sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; }; - tag = "in-localdns"; - } - { - listen = "127.0.0.1"; - port = 6149; - protocol = "dokodemo-door"; - settings.address = "127.0.0.1"; - tag = "api"; - } - ]; - outbounds = - [ - { protocol = "freedom"; tag = "freedom"; } - { - protocol = "vless"; - settings.vnext = - [{ - address = "127.0.0.1"; - port = 4638; - users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }]; - }]; - streamSettings.network = "raw"; - tag = "loopback-localdns"; - } - ]; - routing = - { - domainStrategy = "AsIs"; - rules = builtins.map (rule: rule // { type = "field"; }) - [ { - inboundTag = [ "in-legacy" ]; - domain = [ "domain:openai.com" ]; - outboundTag = "loopback-localdns"; + listen = "127.0.0.1"; + port = 6149; + protocol = "dokodemo-door"; + settings.address = "127.0.0.1"; + tag = "api"; } - { inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; } - { inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; } - { inboundTag = [ "api" ]; outboundTag = "api"; } ]; - }; - stats = {}; - api = { tag = "api"; services = [ "StatsService" ]; }; - policy = - { - levels."0" = { statsUserUplink = true; statsUserDownlink = true; }; - system = + outbounds = + [ + { protocol = "freedom"; tag = "freedom"; } + { + protocol = "vless"; + settings.vnext = + [{ + address = "127.0.0.1"; + port = 4638; + users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }]; + }]; + streamSettings.network = "raw"; + tag = "loopback-localdns"; + } + ]; + routing = { - statsInboundUplink = true; - statsInboundDownlink = true; - statsOutboundUplink = true; - statsOutboundDownlink = true; + domainStrategy = "AsIs"; + rules = builtins.map (rule: rule // { type = "field"; }) + [ + { + inboundTag = [ "in-legacy" ]; + domain = [ "domain:openai.com" ]; + outboundTag = "loopback-localdns"; + } + { inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; } + { inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; } + { inboundTag = [ "api" ]; outboundTag = "api"; } + ]; + }; + stats = {}; + api = { tag = "api"; services = [ "StatsService" ]; }; + policy = + { + levels."0" = { statsUserUplink = true; statsUserDownlink = true; }; + system = + { + statsInboundUplink = true; + statsInboundDownlink = true; + statsOutboundUplink = true; + statsOutboundDownlink = true; + }; }; }; }; + secrets = builtins.listToAttrs + (builtins.map (n: inputs.lib.nameValuePair "xray-server/clients/${n}" {}) userList) + // (builtins.listToAttrs (builtins.map + (name: inputs.lib.nameValuePair "telegram/${name}" { group = "telegram"; mode = "0440"; }) + [ "token" "user/chn" ])) + // { "xray-server/private-key" = {}; }; }; - secrets = builtins.listToAttrs - (builtins.map (n: { name = "xray-server/clients/${n}"; value = {}; }) userList) - // (builtins.listToAttrs (builtins.map - (name: + services = + { + acme.cert.${server.serverName}.group = inputs.config.users.users.nginx.group; + nginx = + { + transparentProxy.map.${server.serverName} = 4726; + https.${server.serverName} = { - name = "telegram/${name}"; - value = - { - group = "telegram"; - mode = "0440"; - sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; - }; - }) - [ "token" "user/chn" ])) - // { "xray-server/private-key" = {}; }; + listen.main = { proxyProtocol = false; addToTransparentProxy = false; }; + location."/".return.return = "400"; + }; + }; + }; }; systemd = { @@ -149,8 +157,8 @@ inputs: { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = - "exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-server.json".path}"; + script = let config = inputs.config.nixos.system.sops.templates."xray-server.json".path; in + "exec ${inputs.pkgs.xray}/bin/xray -config ${config}"; serviceConfig = { User = "v2ray"; @@ -160,7 +168,7 @@ inputs: LimitNPROC = 65536; LimitNOFILE = 524288; }; - restartTriggers = [ inputs.config.sops.templates."xray-server.json".file ]; + restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-server.json".file ]; }; xray-stat = { @@ -172,8 +180,8 @@ inputs: jq = "${inputs.pkgs.jq}/bin/jq"; sed = "${inputs.pkgs.gnused}/bin/sed"; cat = "${inputs.pkgs.coreutils}/bin/cat"; - token = inputs.config.sops.secrets."telegram/token".path; - chat = inputs.config.sops.secrets."telegram/user/chn".path; + token = inputs.config.nixos.system.sops.secrets."telegram/token".path; + chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path; in '' message='${inputs.config.nixos.model.hostname} xray:\n' @@ -216,19 +224,6 @@ inputs: telegram.gid = inputs.config.nixos.user.gid.telegram; }; }; - nixos.services = - { - acme.cert.${server.serverName}.group = inputs.config.users.users.nginx.group; - nginx = - { - transparentProxy.map.${server.serverName} = 4726; - https.${server.serverName} = - { - listen.main = { proxyProtocol = false; addToTransparentProxy = false; }; - location."/".return.return = "400"; - }; - }; - }; } ); } diff --git a/modules/services/xray/xmuClient.nix b/modules/services/xray/xmuClient.nix index 78252255..fe5e2c3b 100644 --- a/modules/services/xray/xmuClient.nix +++ b/modules/services/xray/xmuClient.nix @@ -10,7 +10,7 @@ inputs: }; config = let inherit (inputs.config.nixos.services.xray) xmuClient; in inputs.lib.mkIf (xmuClient != null) { - sops = + nixos.system.sops = { templates."xray-xmu-client.json" = { @@ -37,7 +37,8 @@ inputs: [{ address = "webvpn.xmu.edu.cn"; port = 443; - users = [{ id = inputs.config.sops.placeholder."xray-xmu-client/uuid"; encryption = "none"; }]; + users = + [{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/uuid"; encryption = "none"; }]; }]; streamSettings = { @@ -61,8 +62,9 @@ inputs: in "/https/${prefix}${paddedHex}/xsession"; mode = "packet-up"; security = "tls"; - extra.headers.Cookie = "show_vpn=0; heartbeat=1; show_faq=0; " - + "wengine_vpn_ticketwebvpn_xmu_edu_cn=${inputs.config.sops.placeholder."xray-xmu-client/cookie"}"; + extra.headers.Cookie = + let ticket = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/cookie"; + in "show_vpn=0; heartbeat=1; show_faq=0; wengine_vpn_ticketwebvpn_xmu_edu_cn=${ticket}"; }; tlsSettings.alpn = [ "http/1.1" ]; }; @@ -77,8 +79,8 @@ inputs: { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = - "exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-xmu-client.json".path}"; + script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-client.json".path; in + "exec ${inputs.pkgs.xray}/bin/xray -config ${config}"; serviceConfig = { User = "v2ray"; @@ -90,7 +92,7 @@ inputs: LimitNOFILE = 524288; CPUSchedulingPolicy = "rr"; }; - restartTriggers = [ inputs.config.sops.templates."xray-xmu-client.json".file ]; + restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-client.json".file ]; }; }; users = diff --git a/modules/services/xray/xmuServer.nix b/modules/services/xray/xmuServer.nix index 59d86a8b..686e43b7 100644 --- a/modules/services/xray/xmuServer.nix +++ b/modules/services/xray/xmuServer.nix @@ -10,12 +10,11 @@ inputs: }; config = let inherit (inputs.config.nixos.services.xray) xmuServer; in inputs.lib.mkIf (xmuServer != null) { - sops = + nixos.system.sops = { templates."xray-xmu-server.json" = { owner = inputs.config.users.users.v2ray.name; - group = inputs.config.users.users.v2ray.group; content = builtins.toJSON { log.loglevel = "warning"; @@ -24,7 +23,11 @@ inputs: port = 4727; listen = "127.0.0.1"; protocol = "vless"; - settings = { clients = [{ id = inputs.config.sops.placeholder."xray-xmu-server"; }]; decryption = "none"; }; + settings = + { + clients = [{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-server"; }]; + decryption = "none"; + }; streamSettings = { network = "xhttp"; xhttpSettings = { mode = "stream-one"; path = "/xsession"; }; }; tag = "in"; }]; @@ -37,8 +40,8 @@ inputs: { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = - "exec ${inputs.pkgs.xray}/bin/xray -config ${inputs.config.sops.templates."xray-xmu-server.json".path}"; + script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-server.json".path; in + "exec ${inputs.pkgs.xray}/bin/xray -config ${config}"; serviceConfig = { User = "v2ray"; @@ -49,7 +52,7 @@ inputs: LimitNPROC = 65536; LimitNOFILE = 524288; }; - restartTriggers = [ inputs.config.sops.templates."xray-xmu-server.json".file ]; + restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-server.json".file ]; }; users = { diff --git a/modules/system/network.nix b/modules/system/network.nix index f1544a56..be16939f 100644 --- a/modules/system/network.nix +++ b/modules/system/network.nix @@ -146,19 +146,19 @@ inputs: # wpa_passphrase SSID password networks = builtins.listToAttrs (builtins.map (network: { name = network; value.pskRaw = "ext:${network}"; }) network.wireless); - secretsFile = inputs.config.sops.templates."wireless.env".path; + secretsFile = inputs.config.nixos.system.sops.templates."wireless.env".path; }; firewall.trustedInterfaces = network.trust; }; # dnsable dns fallback, use provided dns servers or no dns services.resolved.fallbackDns = []; - sops = inputs.lib.mkIf (network.wireless != null) + nixos.system.sops = inputs.lib.mkIf (network.wireless != null) { templates."wireless.env".content = builtins.concatStringsSep "\n" (builtins.map - (network: "${network}=${inputs.config.sops.placeholder."wireless/${network}"}") + (network: "${network}=${inputs.config.nixos.system.sops.placeholder."wireless/${network}"}") network.wireless); secrets = builtins.listToAttrs (builtins.map - (network: { name = "wireless/${network}"; value = {}; }) + (network: inputs.lib.nameValuePair "wireless/${network}" {}) network.wireless); }; }) diff --git a/modules/system/nix.nix b/modules/system/nix.nix index 1c2f8e96..92d34a72 100644 --- a/modules/system/nix.nix +++ b/modules/system/nix.nix @@ -105,26 +105,26 @@ inputs: protocol = "ssh-ng"; systems = [ "x86_64-linux" ]; sshUser = "nix-ssh"; - sshKey = inputs.config.sops.secrets."nix/remote".path; + sshKey = inputs.config.nixos.system.sops.secrets."nix/remote".path; maxJobs = 1; mandatoryFeatures = [ "big-parallel" ]; supportedFeatures = builtins.map (f: "gccarch-${f}") v; }) nix.remote.master.host; }; - sops.secrets."nix/remote" = {}; + nixos.system.sops.secrets."nix/remote" = {}; }) (inputs.lib.mkIf nix.githubToken.enable { - nix.extraOptions = "!include ${inputs.config.sops.templates."nix-github.conf".path}"; - sops = + nix.extraOptions = "!include ${inputs.config.nixos.system.sops.templates."nix-github.conf".path}"; + nixos.system.sops = { templates."nix-github.conf" = { - content = "access-tokens = github.com=${inputs.config.sops.placeholder."github/token"}"; + content = "access-tokens = github.com=${inputs.config.nixos.system.sops.placeholder."github/token"}"; mode = "0444"; }; - secrets."github/token".sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; + secrets."github/token" = {}; }; }) # c++ include path diff --git a/modules/system/sops.nix b/modules/system/sops.nix index fbac04bb..c9f1126b 100644 --- a/modules/system/sops.nix +++ b/modules/system/sops.nix @@ -2,38 +2,113 @@ inputs: { options.nixos.system.sops = let inherit (inputs.lib) mkOption types; in { - crossSopsDir = mkOption + secrets = mkOption { - type = types.nonEmptyStr; - default = "${inputs.topInputs.self}/devices/cross/secrets"; - readOnly = true; + type = types.attrsOf (types.submodule (submoduleInputs: { options = + { + path = mkOption + { + type = types.path; + default = inputs.config.sops.secrets.${submoduleInputs.config.key}.path; + readOnly = true; + }; + key = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; }; + format = mkOption { type = types.enum [ "yaml" "binary" ]; default = "yaml"; }; + mode = mkOption { type = types.str; default = "0400"; }; + owner = mkOption { type = types.nullOr types.str; default = null; }; + group = mkOption { type = types.nullOr types.str; default = null; }; + sopsFile = mkOption + { + type = types.path; + default = + let secretFileIndex = + inputs.lib.lists.findFirstIndex (x: x) null + (builtins.map + (file: inputs.lib.hasAttrByPath (inputs.lib.splitString "/" submoduleInputs.config.key) + (inputs.pkgs.localPackages.fromYaml (builtins.readFile file))) + inputs.config.nixos.system.sops.defaultSopsFile); + in + if secretFileIndex == null then builtins.abort "No sops file found for ${submoduleInputs.config.key}" + else builtins.elemAt inputs.config.nixos.system.sops.defaultSopsFile secretFileIndex; + }; + neededForUsers = mkOption { type = types.bool; default = false; }; + };})); + default = {}; }; - clusterSopsDir = mkOption + templates = mkOption { - type = types.nullOr types.nonEmptyStr; - default = if (inputs.config.nixos.model.cluster == null) then null - else "${inputs.topInputs.self}/devices/${inputs.config.nixos.model.cluster.clusterName}/secrets"; + type = types.attrsOf (types.submodule (submoduleInputs: { options = + { + content = mkOption { type = types.str; }; + path = mkOption + { + type = types.path; + default = inputs.config.sops.templates.${submoduleInputs.config._module.args.name}.path; + readOnly = true; + }; + owner = mkOption { type = types.nullOr types.str; default = null; }; + group = mkOption { type = types.nullOr types.str; default = null; }; + mode = mkOption { type = types.str; default = "0400"; }; + file = mkOption + { + type = types.path; + default = inputs.config.sops.templates.${submoduleInputs.config._module.args.name}.file; + readOnly = true; + }; + };})); + default = {}; + }; + # define default in config + placeholder = mkOption { type = types.attrsOf types.str; }; + defaultSopsFile = mkOption + { + type = types.nonEmptyListOf types.path; readOnly = true; + default = + let + defaultSopsFile = path: + if builtins.pathExists "${path}/secrets.yaml" then [ "${path}/secrets.yaml" ] + else if builtins.pathExists "${path}/secrets/default.yaml" then [ "${path}/secrets/default.yaml" ] + else []; + devicePath = "${inputs.topInputs.self}/devices"; + inherit (inputs.config.nixos) model; + in + [] + ++ (inputs.lib.optionals (model.cluster == null) (defaultSopsFile "${devicePath}/${model.hostname}")) + ++ (inputs.lib.optionals (model.cluster != null) + ( + (defaultSopsFile "${devicePath}/${model.cluster.clusterName}/${model.cluster.nodeName}") + ++ (defaultSopsFile "${devicePath}/${model.cluster.clusterName}") + )) + ++ (inputs.lib.optionals model.private [ "${devicePath}/cross/secrets/chn.yaml" ]) + ++ (defaultSopsFile "${devicePath}/cross"); + }; + availableKeys = mkOption + { + type = types.listOf (types.listOf types.str); + readOnly = true; + default = + let getPath = x: + if builtins.typeOf x == "string" then [] + else if builtins.typeOf x == "set" then inputs.lib.mapAttrsToList (n: v: [ n ] ++ getPath v) x + else builtins.abort "Invalid type for availableKeys"; + in builtins.concatLists (builtins.map getPath inputs.config.nixos.system.sops.defaultSopsFile); }; }; config = { + nixos.system.sops.placeholder = builtins.mapAttrs + (n: _: inputs.lib.mkOptionDefault "sops${builtins.hashString "sha256" n}sops") + inputs.config.nixos.system.sops.secrets; sops = { - defaultSopsFile = - let deviceDir = - if (inputs.config.nixos.model.cluster == null) then - "${inputs.topInputs.self}/devices/${inputs.config.nixos.model.hostname}" - else - "${inputs.topInputs.self}/devices/${inputs.config.nixos.model.cluster.clusterName}" - + "/${inputs.config.nixos.model.cluster.nodeName}"; - in inputs.lib.mkMerge - [ - (inputs.lib.mkIf (builtins.pathExists "${deviceDir}/secrets.yaml") "${deviceDir}/secrets.yaml") - (inputs.lib.mkIf (builtins.pathExists "${deviceDir}/secrets/default.yaml") - "${deviceDir}/secrets/default.yaml") - ]; - # sops start before impermanence, so we need to use the absolute path + secrets = builtins.mapAttrs + (n: v: { inherit (v) key format mode owner group sopsFile neededForUsers; }) + inputs.config.nixos.system.sops.secrets; + templates = builtins.mapAttrs + (n: v: { inherit (v) content owner group mode; }) + inputs.config.nixos.system.sops.templates; + inherit (inputs.config.nixos.system.sops) placeholder; age.sshKeyPaths = [ "/nix/persistent/etc/ssh/ssh_host_ed25519_key" ]; }; }; diff --git a/modules/user/chn/age.nix b/modules/user/chn/age.nix index 517cb06d..c968a179 100644 --- a/modules/user/chn/age.nix +++ b/modules/user/chn/age.nix @@ -5,12 +5,8 @@ inputs: home-manager.users.chn = homeInputs: { config.xdg.configFile."sops/age/keys.txt".source = - homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.sops.secrets."chn/age".path; - }; - sops.secrets."chn/age" = - { - owner = "chn"; - sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; + homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.nixos.system.sops.secrets."chn/age".path; }; + nixos.system.sops.secrets."chn/age".owner = "chn"; }; } diff --git a/modules/user/chn/ssh.nix b/modules/user/chn/ssh.nix index 938e23bb..4779c764 100644 --- a/modules/user/chn/ssh.nix +++ b/modules/user/chn/ssh.nix @@ -40,30 +40,23 @@ inputs: { name = ".ssh/id_${type}"; value.source = homeInputs.config.lib.file.mkOutOfStoreSymlink - inputs.config.sops.secrets."chn/${type}".path; + inputs.config.nixos.system.sops.secrets."chn/${type}".path; }) [ "rsa" "rsa.ppk" "ed25519" "ed25519_sk" ] )) // { ".ssh/xmuhk_id_rsa".source = - homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.sops.secrets."chn/xmuhk".path; + homeInputs.config.lib.file.mkOutOfStoreSymlink inputs.config.nixos.system.sops.secrets."chn/xmuhk".path; } ); }; }; - sops.secrets = inputs.lib.mkIf inputs.config.nixos.model.private (inputs.lib.mkMerge + nixos.system.sops.secrets = inputs.lib.mkIf inputs.config.nixos.model.private (inputs.lib.mkMerge [ (builtins.listToAttrs (builtins.map - (name: - { - name = "chn/${name}"; - value = { owner = "chn"; sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; }; - }) + (name: inputs.lib.nameValuePair "chn/${name}" { owner = "chn"; }) [ "rsa" "rsa.ppk" "ed25519" "ed25519_sk" "xmuhk" ])) - { - "root/ed25519_sk" = - { key = "chn/ed25519_sk"; sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/chn.yaml"; }; - } + { "root/ed25519_sk".key = "chn/ed25519_sk"; } ]); }; } diff --git a/modules/user/default.nix b/modules/user/default.nix index 8bc6a109..c13ccf10 100644 --- a/modules/user/default.nix +++ b/modules/user/default.nix @@ -101,17 +101,15 @@ inputs: } # set hashedPassword if it exist in secrets ( - let - sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; - secrets = inputs.pkgs.localPackages.fromYaml (builtins.readFile sopsFile); - hashedPasswordExist = userName: (secrets ? users) && ((secrets.users or {}) ? ${userName}); + let hashedPasswordExist = userName: inputs.lib.lists.any + (inputs.lib.lists.hasPrefix [ "users" userName ]) inputs.config.nixos.system.sops.availableKeys; in { users.users = builtins.listToAttrs (builtins.map (name: { inherit name; value.hashedPasswordFile = inputs.config.sops.secrets."users/${name}".path; }) (builtins.filter (user: hashedPasswordExist user) user.users)); - sops.secrets = builtins.listToAttrs (builtins.map - (name: { name = "users/${name}"; value = { neededForUsers = true; inherit sopsFile; }; }) + nixos.system.sops.secrets = builtins.listToAttrs (builtins.map + (name: inputs.lib.nameValuePair "users/${name}" { neededForUsers = true; }) (builtins.filter (user: hashedPasswordExist user) user.users)); } ) @@ -143,7 +141,7 @@ inputs: home.file = inputs.lib.mkIf inputs.config.nixos.model.private { ".ssh/id_ed25519_sk".source = homeInputs.config.lib.file.mkOutOfStoreSymlink - inputs.config.sops.secrets."root/ed25519_sk".path; + inputs.config.nixos.system.sops.secrets."root/ed25519_sk".path; }; }; };