feat(shell): Add pre-commit hooks and reformat the repo

This commit is contained in:
Tom Hubrecht 2024-02-02 10:51:31 +01:00
parent 988c44d461
commit 5e3819c9b2
91 changed files with 3772 additions and 2282 deletions

1
.pre-commit-config.yaml Symbolic link
View file

@ -0,0 +1 @@
/nix/store/sbc33iwjwgwj0cklac3qjffvi93i723k-pre-commit-config.json

93
default.nix Normal file
View file

@ -0,0 +1,93 @@
/* Copyright :
- Maurice Debray <maurice.debray@dgnum.eu> 2023
- Tom Hubrecht <tom.hubrecht@dgnum.eu> 2023
Ce logiciel est un programme informatique servant à déployer des
configurations de serveurs via NixOS.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.
A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/
let
sources = import ./npins;
pkgs = import sources.nixpkgs { };
pre-commit-check = (import sources.pre-commit-hooks).run {
src = ./.;
hooks = {
# Nix Hooks
statix.enable = true;
deadnix.enable = true;
rfc101 = {
enable = true;
name = "RFC-101 formatting";
entry = "${pkgs.lib.getExe pkgs.nixfmt-rfc-style}";
files = "\\.nix$";
};
# Misc Hooks
commitizen.enable = true;
};
};
in
{
shells = {
default = pkgs.mkShell {
name = "dgnum-infra";
packages =
(
with pkgs;
[
npins
colmena
nixos-generators
]
++ (builtins.map (p: callPackage p { }) [ (sources.disko + "/package.nix") ])
)
++ (import ./scripts { inherit pkgs; });
shellHook = ''
${pre-commit-check.shellHook}
'';
preferLocalBuild = true;
};
pre-commit = pkgs.mkShell {
name = "pre-commit-shell";
shellHook = ''
${pre-commit-check.shellHook}
'';
};
};
}

View file

@ -1,4 +1,5 @@
{ config, pkgs, ... }: { { config, pkgs, ... }:
{
imports = [ ./secrets ]; imports = [ ./secrets ];
services = { services = {
@ -8,8 +9,7 @@
listenAddress = "127.0.0.1"; listenAddress = "127.0.0.1";
settings = { settings = {
ALLOWED_HOSTS = [ "netbox.dgnum.sinavir.fr" ]; ALLOWED_HOSTS = [ "netbox.dgnum.sinavir.fr" ];
REMOTE_AUTH_BACKEND = REMOTE_AUTH_BACKEND = "social_core.backends.open_id_connect.OpenIdConnectAuth";
"social_core.backends.open_id_connect.OpenIdConnectAuth";
}; };
extraConfig = '' extraConfig = ''
@ -27,12 +27,8 @@
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations."/".proxyPass = locations."/".proxyPass = "http://${config.services.netbox.listenAddress}:${builtins.toString config.services.netbox.port}";
"http://${config.services.netbox.listenAddress}:${ locations."/static/".alias = "${config.services.netbox.dataDir}/static/";
builtins.toString config.services.netbox.port
}";
locations."/static/".alias =
"${config.services.netbox.dataDir}/static/";
}; };
}; };
@ -50,5 +46,8 @@
}; };
users.users.nginx.extraGroups = [ "netbox" ]; users.users.nginx.extraGroups = [ "netbox" ];
networking.firewall.allowedTCPPorts = [ 443 80 ]; networking.firewall.allowedTCPPorts = [
443
80
];
} }

View file

@ -6,10 +6,15 @@ let
inherit ((import ../../../meta).members) groups; inherit ((import ../../../meta).members) groups;
publicKeys = lib.splitString "\n" publicKeys =
(builtins.readFile (./maurice.keys)) # maurice servers' keys lib.splitString "\n" (builtins.readFile (./maurice.keys)) # maurice servers' keys
++ nix-lib.getAllKeys (groups.netbox ++ groups.root); ++ nix-lib.getAllKeys (groups.netbox ++ groups.root);
in { in
"netbox.age" = { inherit publicKeys; }; {
"netbox_env.age" = { inherit publicKeys; }; "netbox.age" = {
inherit publicKeys;
};
"netbox_env.age" = {
inherit publicKeys;
};
} }

View file

@ -6,32 +6,34 @@ let
patch = import sources.nix-patches { patchFile = ./patches; }; patch = import sources.nix-patches { patchFile = ./patches; };
mkNode = node: mkNode = node: _: {
{ name, nodes, pkgs, ... }: { # Import the base configuration for each node
# Import the base configuration for each node imports = builtins.map (lib.mkRel ./machines/${node}) [
imports = builtins.map (lib.mkRel ./machines/${node}) [ "_configuration.nix"
"_configuration.nix" "_hardware-configuration.nix"
"_hardware-configuration.nix" ];
];
# Include default secrets # Include default secrets
age-secrets.sources = [ ./machines/${node}/secrets ]; age-secrets.sources = [ ./machines/${node}/secrets ];
# Deployment config is specified in meta.nodes.${node}.deployment # Deployment config is specified in meta.nodes.${node}.deployment
inherit (metadata.nodes.${node}) deployment; inherit (metadata.nodes.${node}) deployment;
# Set NIX_PATH to the patched version of nixpkgs # Set NIX_PATH to the patched version of nixpkgs
nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ]; nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ];
nix.optimise.automatic = true; nix.optimise.automatic = true;
# Allow unfree packages # Allow unfree packages
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
# Use the stateVersion declared in the metadata # Use the stateVersion declared in the metadata
system = { inherit (metadata.nodes.${node}) stateVersion; }; system = {
inherit (metadata.nodes.${node}) stateVersion;
}; };
};
mkNixpkgs = node: mkNixpkgs =
node:
patch.mkNixpkgsSrc rec { patch.mkNixpkgsSrc rec {
src = sources.${version}; src = sources.${version};
version = "nixos-${metadata.nodes.${node}.nixpkgs}"; version = "nixos-${metadata.nodes.${node}.nixpkgs}";
@ -42,9 +44,12 @@ let
### ###
# Function to create arguments based on the node # Function to create arguments based on the node
# #
mkArgs = node: mkArgs =
let lib' = (mkNixpkgs' node).lib; node:
in { let
lib' = (mkNixpkgs' node).lib;
in
{
lib = import sources.nix-lib { lib = import sources.nix-lib {
lib = lib'; lib = lib';
keysRoot = ./keys; keysRoot = ./keys;
@ -52,8 +57,8 @@ let
}; };
nodes = builtins.attrNames metadata.nodes; nodes = builtins.attrNames metadata.nodes;
in
in { {
meta = { meta = {
nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes; nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes;
@ -65,8 +70,9 @@ in {
nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes; nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
}; };
defaults = { pkgs, ... }: { defaults = _: {
# Import the default modules # Import the default modules
imports = [ ./modules ]; imports = [ ./modules ];
}; };
} // (lib.mapSingleFuse mkNode nodes) }
// (lib.mapSingleFuse mkNode nodes)

View file

@ -34,5 +34,6 @@ in
}; };
users.users.root.openssh.authorizedKeys.keyFiles = users.users.root.openssh.authorizedKeys.keyFiles =
builtins.map (m: dgn-lib.mkRel ../keys "${m}.keys") dgn-members; builtins.map (m: dgn-lib.mkRel ../keys "${m}.keys")
dgn-members;
} }

View file

@ -2,4 +2,7 @@ let
inherit (import ../npins) nixpkgs; inherit (import ../npins) nixpkgs;
in in
(import nixpkgs { }).srcOnly { name = "nixpkgs-for-iso"; src = nixpkgs; } (import nixpkgs { }).srcOnly {
name = "nixpkgs-for-iso";
src = nixpkgs;
}

View file

@ -3,20 +3,24 @@ _:
let let
sources = import ../npins; sources = import ../npins;
nix-lib = (import sources.nix-lib { nix-lib =
inherit ((import sources.nixpkgs { })) lib; (import sources.nix-lib {
inherit ((import sources.nixpkgs { })) lib;
keysRoot = ../keys; keysRoot = ../keys;
}).extra; }).extra;
in
in nix-lib // (with nix-lib; { nix-lib
// (with nix-lib; {
# Get publickeys associated to a node # Get publickeys associated to a node
getNodeKeys = node: getNodeKeys =
node:
let let
meta = import ../meta; meta = import ../meta;
names = names =
builtins.foldl' (names: group: names ++ meta.members.groups.${group}) builtins.foldl' (names: group: names ++ meta.members.groups.${group})
(meta.nodes.${node}.admins ++ [ "/machines/${node}" ]) (meta.nodes.${node}.admins ++ [ "/machines/${node}" ])
(meta.nodes.${node}.adminGroups ++ [ "root" ]); (meta.nodes.${node}.adminGroups ++ [ "root" ]);
in getAllKeys names; in
getAllKeys names;
}) })

View file

@ -29,6 +29,5 @@
fsType = "vfat"; fsType = "vfat";
}; };
swapDevices = swapDevices = [ { device = "/dev/disk/by-uuid/30547280-00e9-4ee1-8a07-d116590d9fbf"; } ];
[{ device = "/dev/disk/by-uuid/30547280-00e9-4ee1-8a07-d116590d9fbf"; }];
} }

View file

@ -1,7 +1,9 @@
{ config, ... }: { config, ... }:
let host = "demarches.dgnum.eu"; let
in { host = "demarches.dgnum.eu";
in
{
imports = [ ./module.nix ]; imports = [ ./module.nix ];
services.demarches-simplifiees = { services.demarches-simplifiees = {
@ -62,5 +64,7 @@ in {
}; };
}; };
age-secrets.matches."^ds_fr-.*$" = { owner = "ds-fr"; }; age-secrets.matches."^ds_fr-.*$" = {
owner = "ds-fr";
};
} }

View file

@ -31,15 +31,26 @@
# The fact that you are presently reading this means that you have had # The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms. # knowledge of the CeCILL license and that you accept its terms.
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
mdDoc mkDefault mkEnableOption mkIf mkOption mdDoc
mkDefault
mkEnableOption
mkIf
mkOption
optional optionalString optional
optionalString
types; types
;
cfg = config.services.demarches-simplifiees; cfg = config.services.demarches-simplifiees;
@ -64,16 +75,14 @@ let
$SUDO ${cfg.package}/bin/$BIN "$@" $SUDO ${cfg.package}/bin/$BIN "$@"
''; '';
in
in { {
options.services.demarches-simplifiees = { options.services.demarches-simplifiees = {
enable = mkEnableOption "demarches-simplifiees."; enable = mkEnableOption "demarches-simplifiees.";
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = pkgs.callPackage ./package { default = pkgs.callPackage ./package { inherit (cfg) initialDeploymentDate dataDir logDir; };
inherit (cfg) initialDeploymentDate dataDir logDir;
};
}; };
user = mkOption { user = mkOption {
@ -127,15 +136,17 @@ in {
description = "Demarches Simplifiees setup"; description = "Demarches Simplifiees setup";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
path = [ pkgs.bash ds-fr ]; path = [
pkgs.bash
ds-fr
];
after = [ "postgresql.service" ]; after = [ "postgresql.service" ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
EnvironmentFile = [ env ] EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile);
++ (optional (cfg.secretFile != null) cfg.secretFile);
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr";
LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr"; LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr";
}; };
@ -155,14 +166,19 @@ in {
ds-fr-work = { ds-fr-work = {
description = "Demarches Simplifiees work service"; description = "Demarches Simplifiees work service";
wantedBy = [ "multi-user.target" "ds-fr.service" ]; wantedBy = [
after = [ "network.target" "ds-fr-setup.service" ]; "multi-user.target"
"ds-fr.service"
];
after = [
"network.target"
"ds-fr-setup.service"
];
requires = [ "ds-fr-setup.service" ]; requires = [ "ds-fr-setup.service" ];
serviceConfig = { serviceConfig = {
ExecStart = "${ds-fr}/bin/ds-fr rails jobs:work"; ExecStart = "${ds-fr}/bin/ds-fr rails jobs:work";
EnvironmentFile = [ env ] EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile);
++ (optional (cfg.secretFile != null) cfg.secretFile);
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr";
@ -174,15 +190,17 @@ in {
description = "Demarches Simplifiees web service"; description = "Demarches Simplifiees web service";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
after = [ "network.target" "ds-fr-setup.service" ]; after = [
"network.target"
"ds-fr-setup.service"
];
requires = [ "ds-fr-setup.service" ]; requires = [ "ds-fr-setup.service" ];
path = [ pkgs.imagemagick ]; path = [ pkgs.imagemagick ];
serviceConfig = { serviceConfig = {
ExecStart = "${ds-fr}/bin/ds-fr rails server"; ExecStart = "${ds-fr}/bin/ds-fr rails server";
Environment = [ "RAILS_QUEUE_ADAPTER=delayed_job" ]; Environment = [ "RAILS_QUEUE_ADAPTER=delayed_job" ];
EnvironmentFile = [ env ] EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile);
++ (optional (cfg.secretFile != null) cfg.secretFile);
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr";
@ -192,171 +210,173 @@ in {
}; };
services = { services = {
demarches-simplifiees.settings = (builtins.mapAttrs (_: mkDefault) { demarches-simplifiees.settings =
RAILS_ENV = "production"; (builtins.mapAttrs (_: mkDefault) {
RAILS_ROOT = builtins.toString cfg.package; RAILS_ENV = "production";
RAILS_ROOT = builtins.toString cfg.package;
# Application host name # Application host name
# #
# Examples: # Examples:
# * For local development: localhost:3000 # * For local development: localhost:3000
# * For preproduction: staging.ds.example.org # * For preproduction: staging.ds.example.org
# * For production: ds.example.org # * For production: ds.example.org
APP_HOST = "localhost:3000"; APP_HOST = "localhost:3000";
# Rails key for signing sensitive data # Rails key for signing sensitive data
# See https://guides.rubyonrails.org/security.html # See https://guides.rubyonrails.org/security.html
# #
# For production you MUST generate a new key, and keep it secret. # For production you MUST generate a new key, and keep it secret.
# Secrets must be long and random. Use bin/rails secret to get new unique secrets. # Secrets must be long and random. Use bin/rails secret to get new unique secrets.
# Secret key for One-Time-Password codes, used for 2-factors authentication # Secret key for One-Time-Password codes, used for 2-factors authentication
# OTP_SECRET_KEY = ""; # OTP_SECRET_KEY = "";
# Protect access to the instance with a static login/password (useful for staging environments) # Protect access to the instance with a static login/password (useful for staging environments)
BASIC_AUTH_ENABLED = "disabled"; BASIC_AUTH_ENABLED = "disabled";
BASIC_AUTH_USERNAME = ""; BASIC_AUTH_USERNAME = "";
BASIC_AUTH_PASSWORD = ""; BASIC_AUTH_PASSWORD = "";
# ActiveStorage service to use for attached files. # ActiveStorage service to use for attached files.
# Possible values: # Possible values:
# - "local": store files on the local filesystem # - "local": store files on the local filesystem
# - "amazon": store files remotely on an S3 storage service # - "amazon": store files remotely on an S3 storage service
# - "openstack": store files remotely on an OpenStack storage service # - "openstack": store files remotely on an OpenStack storage service
# #
# (See config/storage.yml for the configuration of each service.) # (See config/storage.yml for the configuration of each service.)
ACTIVE_STORAGE_SERVICE = "local"; ACTIVE_STORAGE_SERVICE = "local";
# Configuration for the OpenStack storage service (if enabled) # Configuration for the OpenStack storage service (if enabled)
FOG_OPENSTACK_API_KEY = ""; FOG_OPENSTACK_API_KEY = "";
FOG_OPENSTACK_USERNAME = ""; FOG_OPENSTACK_USERNAME = "";
FOG_OPENSTACK_URL = ""; FOG_OPENSTACK_URL = "";
FOG_OPENSTACK_REGION = ""; FOG_OPENSTACK_REGION = "";
DS_PROXY_URL = ""; DS_PROXY_URL = "";
# SAML # SAML
SAML_IDP_ENABLED = "disabled"; SAML_IDP_ENABLED = "disabled";
# External service: authentication through France Connect # External service: authentication through France Connect
FC_PARTICULIER_ID = ""; FC_PARTICULIER_ID = "";
FC_PARTICULIER_SECRET = ""; FC_PARTICULIER_SECRET = "";
FC_PARTICULIER_BASE_URL = ""; FC_PARTICULIER_BASE_URL = "";
# External service: authentication through Agent Connect # External service: authentication through Agent Connect
AGENT_CONNECT_ID = ""; AGENT_CONNECT_ID = "";
AGENT_CONNECT_SECRET = ""; AGENT_CONNECT_SECRET = "";
AGENT_CONNECT_BASE_URL = ""; AGENT_CONNECT_BASE_URL = "";
AGENT_CONNECT_JWKS = ""; AGENT_CONNECT_JWKS = "";
AGENT_CONNECT_REDIRECT = ""; AGENT_CONNECT_REDIRECT = "";
# External service: integration with HelpScout (optional) # External service: integration with HelpScout (optional)
HELPSCOUT_MAILBOX_ID = ""; HELPSCOUT_MAILBOX_ID = "";
HELPSCOUT_CLIENT_ID = ""; HELPSCOUT_CLIENT_ID = "";
HELPSCOUT_CLIENT_SECRET = ""; HELPSCOUT_CLIENT_SECRET = "";
HELPSCOUT_WEBHOOK_SECRET = ""; HELPSCOUT_WEBHOOK_SECRET = "";
# External service: external supervision # External service: external supervision
SENTRY_ENABLED = "disabled"; SENTRY_ENABLED = "disabled";
SENTRY_CURRENT_ENV = "development"; SENTRY_CURRENT_ENV = "development";
SENTRY_DSN_RAILS = ""; SENTRY_DSN_RAILS = "";
SENTRY_DSN_JS = ""; SENTRY_DSN_JS = "";
# External service: Matomo web analytics # External service: Matomo web analytics
MATOMO_ENABLED = "disabled"; MATOMO_ENABLED = "disabled";
MATOMO_COOKIE_DOMAIN = "*.www.demarches-simplifiees.fr"; MATOMO_COOKIE_DOMAIN = "*.www.demarches-simplifiees.fr";
MATOMO_DOMAIN = "*.www.demarches-simplifiees.fr"; MATOMO_DOMAIN = "*.www.demarches-simplifiees.fr";
MATOMO_ID = ""; MATOMO_ID = "";
MATOMO_HOST = "matomo.example.org"; MATOMO_HOST = "matomo.example.org";
# Default SMTP Provider: Mailjet # Default SMTP Provider: Mailjet
MAILJET_API_KEY = ""; MAILJET_API_KEY = "";
MAILJET_SECRET_KEY = ""; MAILJET_SECRET_KEY = "";
# Alternate SMTP Provider: SendInBlue/DoList # Alternate SMTP Provider: SendInBlue/DoList
SENDINBLUE_CLIENT_KEY = ""; SENDINBLUE_CLIENT_KEY = "";
SENDINBLUE_SMTP_KEY = ""; SENDINBLUE_SMTP_KEY = "";
SENDINBLUE_USER_NAME = ""; SENDINBLUE_USER_NAME = "";
# SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc" # SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc"
# Alternate SMTP Provider: Mailtrap (mail catcher for staging environments) # Alternate SMTP Provider: Mailtrap (mail catcher for staging environments)
# When enabled, all emails will be sent using this provider # When enabled, all emails will be sent using this provider
MAILTRAP_ENABLED = "disabled"; MAILTRAP_ENABLED = "disabled";
MAILTRAP_USERNAME = ""; MAILTRAP_USERNAME = "";
MAILTRAP_PASSWORD = ""; MAILTRAP_PASSWORD = "";
# Alternative SMTP Provider: Mailcatcher (Catches mail and serves it through a dream.) # Alternative SMTP Provider: Mailcatcher (Catches mail and serves it through a dream.)
# When enabled, all emails will be sent using this provider # When enabled, all emails will be sent using this provider
MAILCATCHER_ENABLED = "disabled"; MAILCATCHER_ENABLED = "disabled";
MAILCATCHER_HOST = ""; MAILCATCHER_HOST = "";
MAILCATCHER_PORT = ""; MAILCATCHER_PORT = "";
# External service: live chat for admins (specific to démarches-simplifiées.fr) # External service: live chat for admins (specific to démarches-simplifiées.fr)
CRISP_ENABLED = "disabled"; CRISP_ENABLED = "disabled";
CRISP_CLIENT_KEY = ""; CRISP_CLIENT_KEY = "";
# API Entreprise credentials # API Entreprise credentials
# https://api.gouv.fr/api/api-entreprise.html # https://api.gouv.fr/api/api-entreprise.html
API_ENTREPRISE_KEY = ""; API_ENTREPRISE_KEY = "";
# External service: CRM for following admin accounts pipeline (specific to démarches-simplifiées.fr) # External service: CRM for following admin accounts pipeline (specific to démarches-simplifiées.fr)
PIPEDRIVE_KEY = ""; PIPEDRIVE_KEY = "";
# Networks bypassing the email login token that verifies new devices, and rack-attack throttling # Networks bypassing the email login token that verifies new devices, and rack-attack throttling
TRUSTED_NETWORKS = ""; TRUSTED_NETWORKS = "";
# External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr) # External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr)
SKYLIGHT_AUTHENTICATION_KEY = ""; SKYLIGHT_AUTHENTICATION_KEY = "";
# "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0"; # "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0";
# Enable or disable Lograge logs # Enable or disable Lograge logs
LOGRAGE_ENABLED = "disabled"; LOGRAGE_ENABLED = "disabled";
# Logs source for Lograge # Logs source for Lograge
# #
# Examples: # Examples:
# * For local development: tps_local # * For local development: tps_local
# * For preproduction: tps_staging # * For preproduction: tps_staging
# * For production: tps_prod # * For production: tps_prod
LOGRAGE_SOURCE = "tps_prod"; LOGRAGE_SOURCE = "tps_prod";
# External service: timestamping a daily archive of dossiers status changes # External service: timestamping a daily archive of dossiers status changes
UNIVERSIGN_API_URL = "https://ws.universign.eu/tsa/post/"; UNIVERSIGN_API_URL = "https://ws.universign.eu/tsa/post/";
UNIVERSIGN_USERPWD = ""; UNIVERSIGN_USERPWD = "";
# External service: API Geo / Adresse # External service: API Geo / Adresse
API_ADRESSE_URL = "https://api-adresse.data.gouv.fr"; API_ADRESSE_URL = "https://api-adresse.data.gouv.fr";
API_GEO_URL = "https://geo.api.gouv.fr"; API_GEO_URL = "https://geo.api.gouv.fr";
# External service: API Education # External service: API Education
API_EDUCATION_URL = "https://data.education.gouv.fr/api/records/1.0"; API_EDUCATION_URL = "https://data.education.gouv.fr/api/records/1.0";
# Encryption key for sensitive columns in the database # Encryption key for sensitive columns in the database
ENCRYPTION_SERVICE_SALT = ""; ENCRYPTION_SERVICE_SALT = "";
# ActiveRecord encryption keys. Generate them with bin/rails db:encryption:init (you can omit deterministic_key) # ActiveRecord encryption keys. Generate them with bin/rails db:encryption:init (you can omit deterministic_key)
AR_ENCRYPTION_PRIMARY_KEY = ""; AR_ENCRYPTION_PRIMARY_KEY = "";
AR_ENCRYPTION_KEY_DERIVATION_SALT = ""; AR_ENCRYPTION_KEY_DERIVATION_SALT = "";
# Salt for invisible_captcha session data. # Salt for invisible_captcha session data.
# Must be the same value for all app instances behind a load-balancer. # Must be the same value for all app instances behind a load-balancer.
INVISIBLE_CAPTCHA_SECRET = "kikooloool"; INVISIBLE_CAPTCHA_SECRET = "kikooloool";
# Clamav antivirus usage # Clamav antivirus usage
CLAMAV_ENABLED = "disabled"; CLAMAV_ENABLED = "disabled";
# Siret number used for API Entreprise, by default we use SIRET from dinum # Siret number used for API Entreprise, by default we use SIRET from dinum
API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret"; API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret";
}) // { })
# Database credentials // {
DB_DATABASE = "ds-fr"; # Database credentials
DB_USERNAME = cfg.user; DB_DATABASE = "ds-fr";
DB_PASSWORD = ""; DB_USERNAME = cfg.user;
DB_HOST = "/run/postgresql"; DB_PASSWORD = "";
DB_POOL = ""; DB_HOST = "/run/postgresql";
DB_POOL = "";
# Log on stdout # Log on stdout
RAILS_LOG_TO_STDOUT = true; RAILS_LOG_TO_STDOUT = true;
}; };
postgresql = { postgresql = {
enable = true; enable = true;
@ -368,8 +388,7 @@ in {
ensureDBOwnership = true; ensureDBOwnership = true;
}; };
extraPlugins = with config.services.postgresql.package.pkgs; extraPlugins = with config.services.postgresql.package.pkgs; [ postgis ];
[ postgis ];
}; };
nginx = { nginx = {
@ -381,7 +400,9 @@ in {
root = "${cfg.package}/public/"; root = "${cfg.package}/public/";
locations."/".tryFiles = "$uri @proxy"; locations."/".tryFiles = "$uri @proxy";
locations."@proxy" = { proxyPass = "http://127.0.0.1:3000"; }; locations."@proxy" = {
proxyPass = "http://127.0.0.1:3000";
};
}; };
}; };
}; };

View file

@ -1,6 +1,18 @@
{ lib, stdenv, fetchFromGitHub, git, fetchYarnDeps, yarn, fixup_yarn_lock, imagemagick {
, nodejs, ruby_3_2, bundlerEnv, logDir ? "/var/log/ds-fr" lib,
, dataDir ? "/var/lib/ds-fr", initialDeploymentDate ? "17941030" }: stdenv,
fetchFromGitHub,
git,
fetchYarnDeps,
yarn,
fixup_yarn_lock,
nodejs,
ruby_3_2,
bundlerEnv,
logDir ? "/var/log/ds-fr",
dataDir ? "/var/lib/ds-fr",
initialDeploymentDate ? "17941030",
}:
let let
pname = "ds-fr"; pname = "ds-fr";
@ -43,7 +55,12 @@ let
}; };
buildInputs = [ rubyEnv ]; buildInputs = [ rubyEnv ];
nativeBuildInputs = [ fixup_yarn_lock nodejs yarn rubyEnv.wrappedRuby ]; nativeBuildInputs = [
fixup_yarn_lock
nodejs
yarn
rubyEnv.wrappedRuby
];
RAILS_ENV = "production"; RAILS_ENV = "production";
NODE_ENV = "dev"; NODE_ENV = "dev";
@ -53,8 +70,9 @@ let
./patches/build.patch ./patches/build.patch
]; ];
postPatch = builtins.concatStringsSep "\n" postPatch = builtins.concatStringsSep "\n" (
(builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches); builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches
);
OTP_SECRET_KEY = "precompile_placeholder"; OTP_SECRET_KEY = "precompile_placeholder";
SECRET_KEY_BASE = "precompile_placeholder"; SECRET_KEY_BASE = "precompile_placeholder";
@ -82,8 +100,8 @@ let
}; };
dgn-patches = import ./dgnum.nix { }; dgn-patches = import ./dgnum.nix { };
in
in stdenv.mkDerivation { stdenv.mkDerivation {
name = "demarches-simplifiees.fr-${version}"; name = "demarches-simplifiees.fr-${version}";
inherit src; inherit src;
@ -98,8 +116,9 @@ in stdenv.mkDerivation {
./patches/secrets-fc.patch ./patches/secrets-fc.patch
]; ];
postPatch = builtins.concatStringsSep "\n" postPatch = builtins.concatStringsSep "\n" (
(builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches); builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches
);
buildPhase = '' buildPhase = ''
rm -rf public rm -rf public
@ -132,8 +151,7 @@ in stdenv.mkDerivation {
meta = with lib; { meta = with lib; {
description = "Dématérialiser et simplifier les démarches administratives"; description = "Dématérialiser et simplifier les démarches administratives";
homepage = homepage = "https://github.com/demarches-simplifiees/demarches-simplifiees.fr";
"https://github.com/demarches-simplifiees/demarches-simplifiees.fr";
license = licenses.agpl3Only; license = licenses.agpl3Only;
maintainers = with maintainers; [ thubrecht ]; maintainers = with maintainers; [ thubrecht ];
}; };

View file

@ -1,6 +1,5 @@
_: _:
builtins.map (id: builtins.map
builtins.fetchurl (id: builtins.fetchurl "https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${id}.patch")
"https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${id}.patch") [ "0b9b32483a700ad3060b3d4ef723d5f40c290c62" ]
[ "0b9b32483a700ad3060b3d4ef723d5f40c290c62" ]

View file

@ -1,5 +1,5 @@
{ {
version = "2024-01-31-02"; version = "2024-01-31-02";
src-hash = "sha256-4ATsSXbjkIMGn5yuyYiI+N+C2R/MSzecMLs5hWCCAM4="; src-hash = "sha256-4ATsSXbjkIMGn5yuyYiI+N+C2R/MSzecMLs5hWCCAM4=";
deps-hash = "sha256-UR5K6DQMvmpWWTH8O9/zJ3Nd+Kkl7xofktFdmBB9z6M="; deps-hash = "sha256-UR5K6DQMvmpWWTH8O9/zJ3Nd+Kkl7xofktFdmBB9z6M=";
} }

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,8 @@
let let
host = "pads.dgnum.eu"; host = "pads.dgnum.eu";
port = 3007; port = 3007;
in { in
{
services = { services = {
hedgedoc = { hedgedoc = {
enable = true; enable = true;
@ -43,13 +44,17 @@ in {
ensureDatabases = [ "hedgedoc" ]; ensureDatabases = [ "hedgedoc" ];
ensureUsers = [{ ensureUsers = [
name = "hedgedoc"; {
ensureDBOwnership = true; name = "hedgedoc";
}]; ensureDBOwnership = true;
}
];
}; };
}; };
systemd.services.hedgedoc.serviceConfig.StateDirectory = systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce [
lib.mkForce [ "hedgedoc" "hedgedoc/uploads" ]; "hedgedoc"
"hedgedoc/uploads"
];
} }

View file

@ -40,22 +40,23 @@
}; };
authTokenFile = config.age.secrets."radius-auth_token_file".path; authTokenFile = config.age.secrets."radius-auth_token_file".path;
privateKeyPasswordFile = privateKeyPasswordFile = config.age.secrets."radius-private_key_password_file".path;
config.age.secrets."radius-private_key_password_file".path;
certs = builtins.listToAttrs (builtins.map (name: certs = builtins.listToAttrs (
lib.nameValuePair name builtins.map (name: lib.nameValuePair name config.age.secrets."radius-${name}_pem_file".path) [
config.age.secrets."radius-${name}_pem_file".path) [
"ca" "ca"
"cert" "cert"
"dh" "dh"
"key" "key"
]); ]
);
radiusClients = { }; radiusClients = { };
}; };
age-secrets.matches."^radius-.*$" = { owner = "radius"; }; age-secrets.matches."^radius-.*$" = {
owner = "radius";
};
networking.firewall.allowedTCPPorts = [ 1812 ]; networking.firewall.allowedTCPPorts = [ 1812 ];
networking.firewall.allowedUDPPorts = [ 1812 ]; networking.firewall.allowedUDPPorts = [ 1812 ];

View file

@ -1,17 +1,27 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkEnableOption mkIf mkOption types; inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
settingsFormat = pkgs.formats.toml { }; settingsFormat = pkgs.formats.toml { };
py-pkgs = import ./packages/python { inherit pkgs; }; py-pkgs = import ./packages/python { inherit pkgs; };
pykanidm = pykanidm = pkgs.callPackage ./packages/pykanidm.nix { inherit (py-pkgs) pydantic; };
pkgs.callPackage ./packages/pykanidm.nix { inherit (py-pkgs) pydantic; };
rlm_python = pkgs.callPackage ./packages/rlm_python.nix { inherit pykanidm; }; rlm_python = pkgs.callPackage ./packages/rlm_python.nix { inherit pykanidm; };
cfg = config.services.k-radius; cfg = config.services.k-radius;
in { in
{
options.services.k-radius = { options.services.k-radius = {
enable = mkEnableOption "a freeradius service linked to kanidm."; enable = mkEnableOption "a freeradius service linked to kanidm.";
@ -19,17 +29,17 @@ in {
freeradius = mkOption { freeradius = mkOption {
type = types.package; type = types.package;
default = pkgs.freeradius.overrideAttrs (old: { default = pkgs.freeradius.overrideAttrs (
buildInputs = (old.buildInputs or [ ]) old: {
++ [ (pkgs.python3.withPackages (ps: [ ps.kanidm ])) ]; buildInputs = (old.buildInputs or [ ]) ++ [ (pkgs.python3.withPackages (ps: [ ps.kanidm ])) ];
}); }
);
}; };
configDir = mkOption { configDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/radius/raddb"; default = "/var/lib/radius/raddb";
description = description = "The path of the freeradius server configuration directory.";
"The path of the freeradius server configuration directory.";
}; };
authTokenFile = mkOption { authTokenFile = mkOption {
@ -38,12 +48,14 @@ in {
}; };
radiusClients = mkOption { radiusClients = mkOption {
type = types.attrsOf (types.submodule { type = types.attrsOf (
options = { types.submodule {
secret = mkOption { type = types.path; }; options = {
ipaddr = mkOption { type = types.str; }; secret = mkOption { type = types.path; };
}; ipaddr = mkOption { type = types.str; };
}); };
}
);
default = { }; default = { };
description = "A mapping of clients and their authentication tokens."; description = "A mapping of clients and their authentication tokens.";
}; };
@ -55,8 +67,7 @@ in {
}; };
dh = mkOption { dh = mkOption {
type = types.str; type = types.str;
description = description = "The output of `openssl dhparam -in ca.pem -out dh.pem 2048`.";
"The output of `openssl dhparam -in ca.pem -out dh.pem 2048`.";
}; };
cert = mkOption { cert = mkOption {
type = types.str; type = types.str;
@ -113,26 +124,32 @@ in {
# write the clients configuration # write the clients configuration
rm ${cfg.configDir}/clients.conf && touch ${cfg.configDir}/clients.conf rm ${cfg.configDir}/clients.conf && touch ${cfg.configDir}/clients.conf
${builtins.concatStringsSep "\n" (builtins.attrValues (builtins.mapAttrs ${builtins.concatStringsSep "\n" (
(name: builtins.attrValues (
{ secret, ipaddr }: '' builtins.mapAttrs
cat <<EOF >> ${cfg.configDir}/client.conf (
client ${name} { name:
ipaddr = ${ipaddr} { secret, ipaddr }:
secret = $(cat "${secret}") ''
proto = * cat <<EOF >> ${cfg.configDir}/client.conf
} client ${name} {
EOF ipaddr = ${ipaddr}
'') cfg.radiusClients))} secret = $(cat "${secret}")
proto = *
}
EOF
''
)
cfg.radiusClients
)
)}
# Copy the kanidm configuration # Copy the kanidm configuration
cat <<EOF > /var/lib/radius/kanidm.toml cat <<EOF > /var/lib/radius/kanidm.toml
auth_token = "$(cat "${cfg.authTokenFile}")" auth_token = "$(cat "${cfg.authTokenFile}")"
EOF EOF
cat ${ cat ${settingsFormat.generate "kanidm.toml" cfg.settings} >> /var/lib/radius/kanidm.toml
settingsFormat.generate "kanidm.toml" cfg.settings
} >> /var/lib/radius/kanidm.toml
chmod u+w /var/lib/radius/kanidm.toml chmod u+w /var/lib/radius/kanidm.toml
# Copy the certificates to the correct directory # Copy the certificates to the correct directory
@ -154,11 +171,13 @@ in {
# ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout # ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout
''; '';
path = [ pkgs.openssl pkgs.gnused ]; path = [
pkgs.openssl
pkgs.gnused
];
serviceConfig = { serviceConfig = {
ExecStart = ExecStart = "${cfg.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout";
"${cfg.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout";
ExecReload = [ ExecReload = [
"${cfg.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" "${cfg.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout"
"${pkgs.coreutils}/bin/kill -HUP $MAINPID" "${pkgs.coreutils}/bin/kill -HUP $MAINPID"

View file

@ -1,25 +1,38 @@
{ lib, fetchFromGitHub, python3, pydantic }: {
lib,
fetchFromGitHub,
python3,
pydantic,
}:
let let
pname = "kanidm"; pname = "kanidm";
version = "0.0.3"; version = "0.0.3";
in python3.pkgs.buildPythonPackage { in
python3.pkgs.buildPythonPackage {
inherit pname version; inherit pname version;
format = "pyproject"; format = "pyproject";
disabled = python3.pythonOlder "3.8"; disabled = python3.pythonOlder "3.8";
src = (fetchFromGitHub { src =
owner = pname; (fetchFromGitHub {
repo = pname; owner = pname;
# Latest 1.1.0-rc.15 tip repo = pname;
rev = "a5ca8018e3a636dbb0a79b3fd869db059d92979d"; # Latest 1.1.0-rc.15 tip
hash = "sha256-PFGoeGn7a/lVR6rOmOKA3ydAoo3/+9RlkwBAKS22Psg="; rev = "a5ca8018e3a636dbb0a79b3fd869db059d92979d";
}) + "/pykanidm"; hash = "sha256-PFGoeGn7a/lVR6rOmOKA3ydAoo3/+9RlkwBAKS22Psg=";
})
+ "/pykanidm";
nativeBuildInputs = with python3.pkgs; [ poetry-core ]; nativeBuildInputs = with python3.pkgs; [ poetry-core ];
propagatedBuildInputs = with python3.pkgs; [ aiohttp pydantic toml (authlib.overridePythonAttrs (_: { doCheck = false; })) ]; propagatedBuildInputs = with python3.pkgs; [
aiohttp
pydantic
toml
(authlib.overridePythonAttrs (_: { doCheck = false; }))
];
doCheck = false; doCheck = false;
@ -29,6 +42,9 @@ in python3.pkgs.buildPythonPackage {
description = "Kanidm client library"; description = "Kanidm client library";
homepage = "https://github.com/kanidm/kanidm/tree/master/pykanidm"; homepage = "https://github.com/kanidm/kanidm/tree/master/pykanidm";
license = licenses.mpl20; license = licenses.mpl20;
maintainers = with maintainers; [ arianvp hexa ]; maintainers = with maintainers; [
arianvp
hexa
];
}; };
} }

View file

@ -5,8 +5,16 @@ let
callPackage = lib.callPackageWith (pkgs // pkgs.python3.pkgs // self); callPackage = lib.callPackageWith (pkgs // pkgs.python3.pkgs // self);
self = builtins.listToAttrs (builtins.map (name: { self = builtins.listToAttrs (
inherit name; builtins.map
value = callPackage (./. + "/${name}.nix") { }; (name: {
}) [ "pydantic" "pydantic-core" ]); inherit name;
in self value = callPackage (./. + "/${name}.nix") { };
})
[
"pydantic"
"pydantic-core"
]
);
in
self

View file

@ -1,17 +1,18 @@
{ stdenv {
, lib stdenv,
, buildPythonPackage lib,
, fetchFromGitHub buildPythonPackage,
, cargo fetchFromGitHub,
, rustPlatform cargo,
, rustc rustPlatform,
, libiconv rustc,
, typing-extensions libiconv,
, pytestCheckHook typing-extensions,
, hypothesis pytestCheckHook,
, pytest-timeout hypothesis,
, pytest-mock pytest-timeout,
, dirty-equals pytest-mock,
dirty-equals,
}: }:
let let
@ -27,9 +28,7 @@ let
hash = "sha256-UguZpA3KEutOgIavjx8Ie//0qJq+4FTZNQTwb/ZIgb8="; hash = "sha256-UguZpA3KEutOgIavjx8Ie//0qJq+4FTZNQTwb/ZIgb8=";
}; };
patches = [ patches = [ ./01-remove-benchmark-flags.patch ];
./01-remove-benchmark-flags.patch
];
cargoDeps = rustPlatform.fetchCargoTarball { cargoDeps = rustPlatform.fetchCargoTarball {
inherit src; inherit src;
@ -45,13 +44,9 @@ let
typing-extensions typing-extensions
]; ];
buildInputs = lib.optionals stdenv.isDarwin [ buildInputs = lib.optionals stdenv.isDarwin [ libiconv ];
libiconv
];
propagatedBuildInputs = [ propagatedBuildInputs = [ typing-extensions ];
typing-extensions
];
pythonImportsCheck = [ "pydantic_core" ]; pythonImportsCheck = [ "pydantic_core" ];
@ -85,4 +80,5 @@ let
maintainers = with maintainers; [ blaggacao ]; maintainers = with maintainers; [ blaggacao ];
}; };
}; };
in pydantic-core in
pydantic-core

View file

@ -1,27 +1,28 @@
{ lib {
, buildPythonPackage lib,
, fetchFromGitHub buildPythonPackage,
, pythonOlder fetchFromGitHub,
pythonOlder,
# build-system # build-system
, hatchling hatchling,
, hatch-fancy-pypi-readme hatch-fancy-pypi-readme,
# native dependencies # native dependencies
, libxcrypt libxcrypt,
# dependencies # dependencies
, annotated-types annotated-types,
, pydantic-core pydantic-core,
, typing-extensions typing-extensions,
# tests # tests
, cloudpickle cloudpickle,
, email-validator email-validator,
, dirty-equals dirty-equals,
, faker faker,
, pytestCheckHook pytestCheckHook,
, pytest-mock pytest-mock,
}: }:
buildPythonPackage rec { buildPythonPackage rec {
@ -38,9 +39,7 @@ buildPythonPackage rec {
hash = "sha256-D0gYcyrKVVDhBgV9sCVTkGq/kFmIoT9l0i5bRM1qxzM="; hash = "sha256-D0gYcyrKVVDhBgV9sCVTkGq/kFmIoT9l0i5bRM1qxzM=";
}; };
buildInputs = lib.optionals (pythonOlder "3.9") [ buildInputs = lib.optionals (pythonOlder "3.9") [ libxcrypt ];
libxcrypt
];
nativeBuildInputs = [ nativeBuildInputs = [
hatch-fancy-pypi-readme hatch-fancy-pypi-readme
@ -54,9 +53,7 @@ buildPythonPackage rec {
]; ];
passthru.optional-dependencies = { passthru.optional-dependencies = {
email = [ email = [ email-validator ];
email-validator
];
}; };
nativeCheckInputs = [ nativeCheckInputs = [
@ -93,4 +90,3 @@ buildPythonPackage rec {
maintainers = with maintainers; [ wd15 ]; maintainers = with maintainers; [ wd15 ];
}; };
} }

View file

@ -1,8 +1,14 @@
{ stdenv, fetchFromGitHub, python3, pykanidm }: {
stdenv,
fetchFromGitHub,
python3,
pykanidm,
}:
let pythonPath = with python3.pkgs; makePythonPath [ pykanidm ]; let
pythonPath = with python3.pkgs; makePythonPath [ pykanidm ];
in stdenv.mkDerivation rec { in
stdenv.mkDerivation rec {
pname = "rlm_python"; pname = "rlm_python";
version = "1.1.0-rc.15"; version = "1.1.0-rc.15";
@ -25,9 +31,15 @@ in stdenv.mkDerivation rec {
cp -R rlm_python/{mods-available,sites-available} $out/etc/raddb/ cp -R rlm_python/{mods-available,sites-available} $out/etc/raddb/
''; '';
phases = [ "unpackPhase" "patchPhase" "installPhase" ]; phases = [
"unpackPhase"
"patchPhase"
"installPhase"
];
passthru = { inherit pythonPath; }; passthru = {
inherit pythonPath;
};
preferLocalBuild = true; preferLocalBuild = true;
} }

View file

@ -5,8 +5,16 @@ let
cert = config.security.acme.certs.${domain}; cert = config.security.acme.certs.${domain};
allowedSubDomains = [ "cloud" "git" "videos" "social" "demarches" "netbird" ]; allowedSubDomains = [
in { "cloud"
"git"
"videos"
"social"
"demarches"
"netbird"
];
in
{
services.kanidm = { services.kanidm = {
enableServer = true; enableServer = true;

View file

@ -7,4 +7,3 @@ lib.setDefault { inherit publicKeys; } [
"kanidm-password_admin" "kanidm-password_admin"
"kanidm-password_idm_admin" "kanidm-password_idm_admin"
] ]

View file

@ -1,7 +1,9 @@
{ config, ... }: { config, ... }:
let host = "social.dgnum.eu"; let
in { host = "social.dgnum.eu";
in
{
services.mastodon = { services.mastodon = {
enable = true; enable = true;
@ -9,7 +11,6 @@ in {
smtp = { smtp = {
# TODO: smtp setup # TODO: smtp setup
fromAddress = "social@services.dgnum.eu"; fromAddress = "social@services.dgnum.eu";
}; };
streamingProcesses = 4; streamingProcesses = 4;
@ -38,5 +39,7 @@ in {
extraEnvFiles = [ config.age.secrets."mastodon-extra_env_file".path ]; extraEnvFiles = [ config.age.secrets."mastodon-extra_env_file".path ];
}; };
age-secrets.matches."^mastodon-.*$" = { owner = "mastodon"; }; age-secrets.matches."^mastodon-.*$" = {
owner = "mastodon";
};
} }

View file

@ -3,7 +3,8 @@
let let
host = "cloud.dgnum.eu"; host = "cloud.dgnum.eu";
nextcloud-occ = "${config.services.nextcloud.occ}/bin/nextcloud-occ"; nextcloud-occ = "${config.services.nextcloud.occ}/bin/nextcloud-occ";
in { in
{
services.nextcloud = { services.nextcloud = {
enable = true; enable = true;
hostName = host; hostName = host;
@ -102,8 +103,7 @@ in {
image = "collabora/code"; image = "collabora/code";
imageFile = pkgs.dockerTools.pullImage { imageFile = pkgs.dockerTools.pullImage {
imageName = "collabora/code"; imageName = "collabora/code";
imageDigest = imageDigest = "sha256:a8cce07c949aa59cea0a7f1f220266a1a6d886c717c3b5005782baf6f384d645";
"sha256:a8cce07c949aa59cea0a7f1f220266a1a6d886c717c3b5005782baf6f384d645";
sha256 = "sha256-lN6skv62x+x7G7SNOUyZ8W6S/uScrkqE1nbBwwSEWXQ="; sha256 = "sha256-lN6skv62x+x7G7SNOUyZ8W6S/uScrkqE1nbBwwSEWXQ=";
}; };
ports = [ "9980:9980" ]; ports = [ "9980:9980" ];
@ -111,7 +111,12 @@ in {
domain = "cloud.dgnum.eu"; domain = "cloud.dgnum.eu";
extra_params = "--o:ssl.enable=false --o:ssl.termination=true --o:remote_font_config.url=https://cloud.dgnum.eu/apps/richdocuments/settings/fonts.json"; extra_params = "--o:ssl.enable=false --o:ssl.termination=true --o:remote_font_config.url=https://cloud.dgnum.eu/apps/richdocuments/settings/fonts.json";
}; };
extraOptions = [ "--cap-add" "MKNOD" "--cap-add" "SYS_ADMIN" ]; extraOptions = [
"--cap-add"
"MKNOD"
"--cap-add"
"SYS_ADMIN"
];
}; };
}; };
@ -180,7 +185,9 @@ in {
description = "Generate preview for nextcloud media."; description = "Generate preview for nextcloud media.";
script = "${nextcloud-occ} preview:pre-generate -vvv"; script = "${nextcloud-occ} preview:pre-generate -vvv";
startAt = "*-*-* 01:00:00 UTC"; startAt = "*-*-* 01:00:00 UTC";
serviceConfig = { Restart = "on-failure"; }; serviceConfig = {
Restart = "on-failure";
};
}; };
nextcloud-cron.path = [ pkgs.perl ]; nextcloud-cron.path = [ pkgs.perl ];
@ -188,9 +195,13 @@ in {
environment.systemPackages = [ pkgs.ffmpeg_6-headless ]; environment.systemPackages = [ pkgs.ffmpeg_6-headless ];
networking.hosts = { "129.199.146.148" = [ "s3.dgnum.eu" ]; }; networking.hosts = {
"129.199.146.148" = [ "s3.dgnum.eu" ];
};
age-secrets.matches."^nextcloud-.*$" = { owner = "nextcloud"; }; age-secrets.matches."^nextcloud-.*$" = {
owner = "nextcloud";
};
system.activationScripts = { system.activationScripts = {
restart-nextcloud.text = '' restart-nextcloud.text = ''

View file

@ -1,7 +1,9 @@
{ config, ... }: { config, ... }:
let host = "docs.dgnum.eu"; let
in { host = "docs.dgnum.eu";
in
{
services.outline = { services.outline = {
enable = true; enable = true;
@ -27,8 +29,7 @@ in {
userinfoUrl = "https://sso.dgnum.eu/oauth2/openid/outline_dgn/userinfo"; userinfoUrl = "https://sso.dgnum.eu/oauth2/openid/outline_dgn/userinfo";
displayName = "DGNum SSO"; displayName = "DGNum SSO";
clientSecretFile = clientSecretFile = config.age.secrets."outline-oidc_client_secret_file".path;
config.age.secrets."outline-oidc_client_secret_file".path;
}; };
defaultLanguage = "fr_FR"; defaultLanguage = "fr_FR";
@ -51,5 +52,7 @@ in {
}; };
}; };
age-secrets.matches."^outline-.*$" = { owner = "outline"; }; age-secrets.matches."^outline-.*$" = {
owner = "outline";
};
} }

View file

@ -1,9 +1,10 @@
{ pkgs, ... }: { pkgs, ... }:
let let
host = "rstudio.dgnum.eu"; # host = "rstudio.dgnum.eu";
port = 19000; port = 19000;
in { in
{
services.rstudio-server = { services.rstudio-server = {
enable = true; enable = true;
rserverExtraConfig = '' rserverExtraConfig = ''
@ -11,14 +12,17 @@ in {
''; '';
package = pkgs.rstudioServerWrapper.override { package = pkgs.rstudioServerWrapper.override {
packages = with pkgs.rPackages; [ ggplot2 rmarkdown dplyr ]; packages = with pkgs.rPackages; [
ggplot2
rmarkdown
dplyr
];
}; };
}; };
users.users.ruser = { users.users.ruser = {
isNormalUser = true; isNormalUser = true;
hashedPassword = hashedPassword = "$6$pTXXVh8NfE.M8VPc$q0fFh3Y7Y0DauLCcZLgJzFciq1wkjoHmO61XpOrZLH3a1M32ZzOMbjx2XMm2QxrUncbx6hGerY/lD8rQ8InS4.";
"$6$pTXXVh8NfE.M8VPc$q0fFh3Y7Y0DauLCcZLgJzFciq1wkjoHmO61XpOrZLH3a1M32ZzOMbjx2XMm2QxrUncbx6hGerY/lD8rQ8InS4.";
}; };
dgn-access-control.users.ruser = [ "jemagius" ]; dgn-access-control.users.ruser = [ "jemagius" ];

View file

@ -1,7 +1,9 @@
{ config, ... }: { config, ... }:
let host = "saml-idp.dgnum.eu"; let
in { host = "saml-idp.dgnum.eu";
in
{
imports = [ ./module.nix ]; imports = [ ./module.nix ];
@ -20,8 +22,7 @@ in {
config = { config = {
endpoints.single_sign_on_service = { endpoints.single_sign_on_service = {
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" = "sso/post"; "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" = "sso/post";
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" = "sso/redirect";
"sso/redirect";
}; };
entityid_endpoint = true; entityid_endpoint = true;
enable_metadata_reload = false; enable_metadata_reload = false;
@ -32,11 +33,13 @@ in {
url = "https://dgnum.eu"; url = "https://dgnum.eu";
}; };
contact_person = [{ contact_person = [
contact_type = "technical"; {
email_address = "mailto:tom.hubrecht@dgnum.eu"; contact_type = "technical";
given_name = "Tom Hubrecht"; email_address = "mailto:tom.hubrecht@dgnum.eu";
}]; given_name = "Tom Hubrecht";
}
];
key_file = "/var/lib/satosa/ssl/key.pem"; key_file = "/var/lib/satosa/ssl/key.pem";
cert_file = "/var/lib/satosa/ssl/cert.pem"; cert_file = "/var/lib/satosa/ssl/cert.pem";
@ -50,10 +53,12 @@ in {
endpoints.single_sign_on_service = [ ]; endpoints.single_sign_on_service = [ ];
name = "DGNum proxy IdP"; name = "DGNum proxy IdP";
ui_info = { ui_info = {
display_name = [{ display_name = [
lang = "fr"; {
text = "Service de connexion DGNum"; lang = "fr";
}]; text = "Service de connexion DGNum";
}
];
}; };
name_id_format = [ name_id_format = [
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
@ -63,9 +68,10 @@ in {
default = { default = {
attribute_restrictions = null; attribute_restrictions = null;
fail_on_missing_requested = false; fail_on_missing_requested = false;
lifetime = { minutes = 15; }; lifetime = {
name_form = minutes = 15;
"urn:oasis:names:tc:SAML:2.0:attrname-format:uri"; };
name_form = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri";
encrypt_assertion = false; encrypt_assertion = false;
encrypted_advice_attributes = false; encrypted_advice_attributes = false;
}; };
@ -121,12 +127,15 @@ in {
module = "satosa.backends.openid_connect.OpenIDConnectBackend"; module = "satosa.backends.openid_connect.OpenIDConnectBackend";
name = "kanidm"; name = "kanidm";
config = { config = {
provider_metadata.issuer = provider_metadata.issuer = "https://sso.dgnum.eu/oauth2/openid/satosa_dgn/";
"https://sso.dgnum.eu/oauth2/openid/satosa_dgn/";
client = { client = {
auth_req_params = { auth_req_params = {
response_type = "code"; response_type = "code";
scope = [ "openid" "profile" "email" ]; scope = [
"openid"
"profile"
"email"
];
}; };
client_metadata = { client_metadata = {
client_id = "satosa_dgn"; client_id = "satosa_dgn";
@ -144,5 +153,7 @@ in {
forceSSL = true; forceSSL = true;
}; };
age-secrets.matches."^satosa-.*$" = { owner = "satosa"; }; age-secrets.matches."^satosa-.*$" = {
owner = "satosa";
};
} }

View file

@ -1,7 +1,18 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkDefault mkEnableOption mkIf mkOption types; inherit (lib)
mkDefault
mkEnableOption
mkIf
mkOption
types
;
yamlFormat = pkgs.formats.yaml { }; yamlFormat = pkgs.formats.yaml { };
@ -9,12 +20,17 @@ let
cfg = config.services.satosa; cfg = config.services.satosa;
mkYamlFiles = files: mkYamlFiles =
builtins.attrValues files: builtins.attrValues (builtins.mapAttrs (name: yamlFormat.generate "${name}.yaml") files);
(builtins.mapAttrs (name: yamlFormat.generate "${name}.yaml") files);
pyEnv = cfg.package.python.withPackages (ps: [ cfg.package ps.gunicorn ]); pyEnv = cfg.package.python.withPackages (
in { ps: [
cfg.package
ps.gunicorn
]
);
in
{
options.services.satosa = { options.services.satosa = {
enable = mkEnableOption "SATOSA, a SAML and OIDC proxy."; enable = mkEnableOption "SATOSA, a SAML and OIDC proxy.";
@ -88,8 +104,7 @@ in {
MICRO_SERVICES = mkYamlFiles cfg.microServices; MICRO_SERVICES = mkYamlFiles cfg.microServices;
LOGGING = { LOGGING = {
version = 1; version = 1;
formatters.simple.format = formatters.simple.format = "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s";
"[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s";
handlers.stdout = { handlers.stdout = {
class = "logging.StreamHandler"; class = "logging.StreamHandler";
stream = "ext://sys.stdout"; stream = "ext://sys.stdout";
@ -171,7 +186,9 @@ in {
TimeoutStopSec = "5"; TimeoutStopSec = "5";
EnvironmentFile = lib.optional (cfg.envFile != null) cfg.envFile; EnvironmentFile = lib.optional (cfg.envFile != null) cfg.envFile;
}; };
environment = { SATOSA_CONFIG = configFile; }; environment = {
SATOSA_CONFIG = configFile;
};
}; };
}; };
@ -179,8 +196,7 @@ in {
enable = true; enable = true;
virtualHosts.${cfg.host} = { virtualHosts.${cfg.host} = {
locations."/".proxyPass = locations."/".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}";
"http://127.0.0.1:${builtins.toString cfg.port}";
}; };
}; };

View file

@ -1,6 +1,7 @@
{ lib {
, python3 lib,
, fetchPypi python3,
fetchPypi,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {

View file

@ -13,5 +13,5 @@ let
pydantic = callPackage ./pydantic.nix { }; pydantic = callPackage ./pydantic.nix { };
pydantic-core = callPackage ./pydantic-core.nix { }; pydantic-core = callPackage ./pydantic-core.nix { };
}; };
in
in self.satosa self.satosa

View file

@ -1,7 +1,8 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, pydantic-settings fetchPypi,
pydantic-settings,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {

View file

@ -1,9 +1,10 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, cargo fetchPypi,
, rustPlatform cargo,
, rustc rustPlatform,
rustc,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {
@ -31,9 +32,7 @@ python3.pkgs.buildPythonPackage rec {
rustc rustc
]; ];
propagatedBuildInputs = with python3.pkgs; [ propagatedBuildInputs = with python3.pkgs; [ typing-extensions ];
typing-extensions
];
pythonImportsCheck = [ "pydantic_core" ]; pythonImportsCheck = [ "pydantic_core" ];

View file

@ -1,7 +1,8 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, pydantic fetchPypi,
pydantic,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {
@ -15,9 +16,7 @@ python3.pkgs.buildPythonPackage rec {
hash = "sha256-li3DZySVqtaulqQ5D6x+WTWR4URiXlES01n49n+3WUU="; hash = "sha256-li3DZySVqtaulqQ5D6x+WTWR4URiXlES01n49n+3WUU=";
}; };
nativeBuildInputs = [ nativeBuildInputs = [ python3.pkgs.hatchling ];
python3.pkgs.hatchling
];
propagatedBuildInputs = with python3.pkgs; [ propagatedBuildInputs = with python3.pkgs; [
pydantic pydantic

View file

@ -1,7 +1,8 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, pydantic-core fetchPypi,
pydantic-core,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {
@ -26,9 +27,7 @@ python3.pkgs.buildPythonPackage rec {
]; ];
passthru.optional-dependencies = with python3.pkgs; { passthru.optional-dependencies = with python3.pkgs; {
email = [ email = [ email-validator ];
email-validator
];
}; };
pythonImportsCheck = [ "pydantic" ]; pythonImportsCheck = [ "pydantic" ];

View file

@ -1,7 +1,8 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, oic fetchPypi,
oic,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {

View file

@ -1,8 +1,9 @@
{ lib {
, python3 lib,
, fetchPypi python3,
, cookies-samesite-compat fetchPypi,
, pyop cookies-samesite-compat,
pyop,
}: }:
python3.pkgs.buildPythonPackage rec { python3.pkgs.buildPythonPackage rec {
@ -36,15 +37,9 @@ python3.pkgs.buildPythonPackage rec {
]; ];
passthru.optional-dependencies = with python3.pkgs; { passthru.optional-dependencies = with python3.pkgs; {
ldap = [ ldap = [ ldap3 ];
ldap3 pyop_mongo = [ pyop ];
]; pyop_redis = [ pyop ];
pyop_mongo = [
pyop
];
pyop_redis = [
pyop
];
}; };
passthru.python = python3; passthru.python = python3;

View file

@ -1,8 +1,9 @@
{ config, ... }: { config, ... }:
let host = "pass.dgnum.eu"; let
host = "pass.dgnum.eu";
in { in
{
services.vaultwarden = { services.vaultwarden = {
enable = true; enable = true;
@ -62,10 +63,12 @@ in {
ensureDatabases = [ "vaultwarden" ]; ensureDatabases = [ "vaultwarden" ];
ensureUsers = [{ ensureUsers = [
name = "vaultwarden"; {
ensureDBOwnership = true; name = "vaultwarden";
}]; ensureDBOwnership = true;
}
];
}; };
}; };
} }

View file

@ -5,7 +5,8 @@ let
port = 3005; port = 3005;
websocketPort = 6902; websocketPort = 6902;
in { in
{
services.zammad = { services.zammad = {
enable = true; enable = true;
@ -38,10 +39,9 @@ in {
proxyWebsockets = true; proxyWebsockets = true;
}; };
"~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png)".extraConfig = "~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png)".extraConfig = ''
'' expires max;
expires max; '';
'';
}; };
extraConfig = '' extraConfig = ''
@ -51,5 +51,7 @@ in {
}; };
}; };
age-secrets.matches."^zammad-.*$" = { owner = "zammad"; }; age-secrets.matches."^zammad-.*$" = {
owner = "zammad";
};
} }

View file

@ -29,6 +29,5 @@
fsType = "vfat"; fsType = "vfat";
}; };
swapDevices = swapDevices = [ { device = "/dev/disk/by-uuid/65a6f6e4-e996-4718-a4d0-cd0c78dcb15b"; } ];
[{ device = "/dev/disk/by-uuid/65a6f6e4-e996-4718-a4d0-cd0c78dcb15b"; }];
} }

View file

@ -1,8 +1,14 @@
{ config, pkgs, sources, ... }: {
config,
pkgs,
sources,
...
}:
let host = "cachix.dgnum.eu"; let
host = "cachix.dgnum.eu";
in { in
{
services = { services = {
atticd = { atticd = {
enable = true; enable = true;
@ -68,10 +74,12 @@ in {
ensureDatabases = [ "atticd" ]; ensureDatabases = [ "atticd" ];
ensureUsers = [{ ensureUsers = [
name = "atticd"; {
ensureDBOwnership = true; name = "atticd";
}]; ensureDBOwnership = true;
}
];
}; };
}; };
} }

View file

@ -3,18 +3,29 @@
let let
url = "https://git.dgnum.eu"; url = "https://git.dgnum.eu";
mkRunner = { labels, name, token }: { mkRunner =
enable = true; {
labels,
name,
token,
}:
{
enable = true;
inherit name labels token url; inherit
name
labels
token
url
;
settings.container = { settings.container = {
network = "host"; network = "host";
options = "--cpus=4"; options = "--cpus=4";
};
}; };
}; in
{
in {
services.forgejo-nix-runners = { services.forgejo-nix-runners = {
enable = true; enable = true;
@ -23,7 +34,11 @@ in {
storePath = "/data/slow/nix"; storePath = "/data/slow/nix";
tokenFile = config.age.secrets."forgejo_runners-token_file".path; tokenFile = config.age.secrets."forgejo_runners-token_file".path;
dependencies = [ pkgs.colmena pkgs.npins pkgs.tea ]; dependencies = [
pkgs.colmena
pkgs.npins
pkgs.tea
];
containerOptions = [ "--cpus=4" ]; containerOptions = [ "--cpus=4" ];

View file

@ -3,7 +3,8 @@
let let
port = 3000; port = 3000;
host = "git.dgnum.eu"; host = "git.dgnum.eu";
in { in
{
services = { services = {
forgejo = { forgejo = {
enable = true; enable = true;
@ -19,7 +20,9 @@ in {
}; };
settings = { settings = {
DEFAULT = { APP_NAME = "Forge git de la DGNum"; }; DEFAULT = {
APP_NAME = "Forge git de la DGNum";
};
server = { server = {
ROOT_URL = "https://${host}/"; ROOT_URL = "https://${host}/";
@ -62,7 +65,9 @@ in {
virtualHosts.${host} = { virtualHosts.${host} = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations."/" = { proxyPass = "http://127.0.0.1:${toString port}"; }; locations."/" = {
proxyPass = "http://127.0.0.1:${toString port}";
};
}; };
}; };
}; };
@ -77,5 +82,7 @@ in {
users.groups.git = { }; users.groups.git = { };
age-secrets.matches."^forgejo-.*$" = { owner = "git"; }; age-secrets.matches."^forgejo-.*$" = {
owner = "git";
};
} }

View file

@ -8,20 +8,22 @@ let
metadata_dir = "/data/fast/garage/meta"; metadata_dir = "/data/fast/garage/meta";
buckets = [ "peertube-videos-dgnum" ]; buckets = [ "peertube-videos-dgnum" ];
in
in { {
services.garage = { services.garage = {
enable = true; enable = true;
package = pkgs.garage_0_9.overrideAttrs (old: { package = pkgs.garage_0_9.overrideAttrs (
patches = (old.patches or [ ]) ++ [ old: {
# Allow 0 as a part number marker patches = (old.patches or [ ]) ++ [
(pkgs.fetchpatch { # Allow 0 as a part number marker
url = "https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/670.patch"; (pkgs.fetchpatch {
hash = "sha256-28ctLl1qscMRj2JEVnmhuLyK1Avub8QeyfQFxAK0y08="; url = "https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/670.patch";
}) hash = "sha256-28ctLl1qscMRj2JEVnmhuLyK1Avub8QeyfQFxAK0y08=";
]; })
}); ];
}
);
settings = { settings = {
inherit data_dir metadata_dir; inherit data_dir metadata_dir;
@ -56,7 +58,10 @@ in {
systemd.services.garage.serviceConfig = { systemd.services.garage.serviceConfig = {
User = "garage"; User = "garage";
ReadWriteDirectories = [ data_dir metadata_dir ]; ReadWriteDirectories = [
data_dir
metadata_dir
];
}; };
users.users.garage = { users.users.garage = {

View file

@ -1,8 +1,24 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
filterAttrs literalExpression maintainers mkDefault mkEnableOption mkIf filterAttrs
mkMerge mkOption optionalAttrs optionalString optionals types; literalExpression
maintainers
mkDefault
mkEnableOption
mkIf
mkMerge
mkOption
optionalAttrs
optionalString
optionals
types
;
inherit ((import ./package { inherit pkgs; })) dashboard; inherit ((import ./package { inherit pkgs; })) dashboard;
@ -13,92 +29,100 @@ let
settingsFormat = pkgs.formats.keyValue { }; settingsFormat = pkgs.formats.keyValue { };
managementFormat = pkgs.formats.json { }; managementFormat = pkgs.formats.json { };
settingsFile = settingsFormat.generate "setup.env" (builtins.mapAttrs (_: val: settingsFile = settingsFormat.generate "setup.env" (
if builtins.isList val then builtins.mapAttrs
''"${builtins.concatStringsSep " " val}"'' (_: val: if builtins.isList val then ''"${builtins.concatStringsSep " " val}"'' else val)
else settings
val) settings); );
managementFile = managementFormat.generate "config.json" cfg.managementConfig; managementFile = managementFormat.generate "config.json" cfg.managementConfig;
settings = rec { settings =
TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; rec {
TURN_PORT = 3478; TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN;
TURN_USER = "netbird"; TURN_PORT = 3478;
TURN_MIN_PORT = 49152; TURN_USER = "netbird";
TURN_MAX_PORT = 65535; TURN_MIN_PORT = 49152;
TURN_PASSWORD = TURN_MAX_PORT = 65535;
if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null; TURN_PASSWORD = if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null;
TURN_SECRET = TURN_SECRET = if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret";
if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret";
STUN_USERNAME = ""; STUN_USERNAME = "";
STUN_PASSWORD = STUN_PASSWORD = if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null;
if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null;
NETBIRD_DASHBOARD_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:443"; NETBIRD_DASHBOARD_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:443";
NETBIRD_MGMT_API_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ NETBIRD_MGMT_API_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${
builtins.toString builtins.toString cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT
cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT
}"; }";
NETBIRD_SIGNAL_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ NETBIRD_SIGNAL_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${
builtins.toString builtins.toString cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT
cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT
}"; }";
NETBIRD_SIGNAL_PROTOCOL = "https"; NETBIRD_SIGNAL_PROTOCOL = "https";
NETBIRD_SIGNAL_PORT = 443; NETBIRD_SIGNAL_PORT = 443;
NETBIRD_AUTH_USER_ID_CLAIM = "sub"; NETBIRD_AUTH_USER_ID_CLAIM = "sub";
NETBIRD_AUTH_CLIENT_SECRET = NETBIRD_AUTH_CLIENT_SECRET =
if cfg.secretFiles.AUTH_CLIENT_SECRET != null then if cfg.secretFiles.AUTH_CLIENT_SECRET != null then "$AUTH_CLIENT_SECRET" else "";
"$AUTH_CLIENT_SECRET" NETBIRD_AUTH_SUPPORTED_SCOPES = [
else "openid"
""; "profile"
NETBIRD_AUTH_SUPPORTED_SCOPES = "email"
[ "openid" "profile" "email" "offline_access" "api" ]; "offline_access"
"api"
];
NETBIRD_AUTH_REDIRECT_URI = ""; NETBIRD_AUTH_REDIRECT_URI = "";
NETBIRD_AUTH_SILENT_REDIRECT_URI = ""; NETBIRD_AUTH_SILENT_REDIRECT_URI = "";
NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none"; NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none";
NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID;
NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE; NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE;
NETBIRD_AUTH_DEVICE_AUTH_SCOPE = NETBIRD_AUTH_DEVICE_AUTH_SCOPE = [
[ "openid" "profile" "email" "offline_access" "api" ]; "openid"
NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false; "profile"
"email"
"offline_access"
"api"
];
NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false;
NETBIRD_MGMT_API_PORT = 443; NETBIRD_MGMT_API_PORT = 443;
NETBIRD_MGMT_IDP = "none"; NETBIRD_MGMT_IDP = "none";
NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID;
NETBIRD_IDP_MGMT_CLIENT_SECRET = NETBIRD_IDP_MGMT_CLIENT_SECRET =
if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then
"$IDP_MGMT_CLIENT_SECRET" "$IDP_MGMT_CLIENT_SECRET"
else else
cfg.settings.NETBIRD_AUTH_CLIENT_SECRET; cfg.settings.NETBIRD_AUTH_CLIENT_SECRET;
NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials"; NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials";
NETBIRD_TOKEN_SOURCE = "accessToken"; NETBIRD_TOKEN_SOURCE = "accessToken";
NETBIRD_DRAG_QUERY_PARAMS = false; NETBIRD_DRAG_QUERY_PARAMS = false;
NETBIRD_USE_AUTH0 = false; NETBIRD_USE_AUTH0 = false;
NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = ""; NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "";
NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ]; NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ];
NETBIRD_AUTH_PKCE_REDIRECT_URLS = builtins.map (p: "http://localhost:${p}") NETBIRD_AUTH_PKCE_REDIRECT_URLS =
cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS; builtins.map (p: "http://localhost:${p}")
} // (optionalAttrs cfg.setupAutoOidc { cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS;
NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT = }
"$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT"; // (optionalAttrs cfg.setupAutoOidc {
NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"; NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT = "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT";
NETBIRD_AUTH_TOKEN_ENDPOINT = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT";
NETBIRD_AUTH_JWT_CERTS = "$NETBIRD_AUTH_JWT_CERTS"; NETBIRD_AUTH_TOKEN_ENDPOINT = "$NETBIRD_AUTH_TOKEN_ENDPOINT";
NETBIRD_AUTH_AUTHORITY = "$NETBIRD_AUTH_AUTHORITY"; NETBIRD_AUTH_JWT_CERTS = "$NETBIRD_AUTH_JWT_CERTS";
}) // cfg.settings; NETBIRD_AUTH_AUTHORITY = "$NETBIRD_AUTH_AUTHORITY";
in { })
meta = { maintainers = with maintainers; [ thubrecht ]; }; // cfg.settings;
in
{
meta = {
maintainers = with maintainers; [ thubrecht ];
};
options.services.netbird-server = { options.services.netbird-server = {
enable = mkEnableOption (lib.mdDoc "netbird management service."); enable = mkEnableOption (lib.mdDoc "netbird management service.");
@ -111,8 +135,19 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = with types; type =
attrsOf (nullOr (oneOf [ (listOf str) bool int float str ])); with types;
attrsOf (
nullOr (
oneOf [
(listOf str)
bool
int
float
str
]
)
);
defaultText = lib.literalExpression '' defaultText = lib.literalExpression ''
{ {
TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN;
@ -195,15 +230,19 @@ in {
}; };
logLevel = mkOption { logLevel = mkOption {
type = types.enum [ "ERROR" "WARN" "INFO" "DEBUG" ]; type = types.enum [
"ERROR"
"WARN"
"INFO"
"DEBUG"
];
default = "INFO"; default = "INFO";
description = lib.mdDoc "Log level of the netbird services."; description = lib.mdDoc "Log level of the netbird services.";
}; };
enableDeviceAuthorizationFlow = enableDeviceAuthorizationFlow = mkEnableOption "device authorization flow for netbird." // {
mkEnableOption "device authorization flow for netbird." // { default = true;
default = true; };
};
enableNginx = mkEnableOption "NGINX reverse-proxy for the netbird server."; enableNginx = mkEnableOption "NGINX reverse-proxy for the netbird server.";
@ -232,8 +271,7 @@ in {
disableAnonymousMetrics = mkOption { disableAnonymousMetrics = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = description = lib.mdDoc "Disables push of anonymous usage metrics to NetBird.";
lib.mdDoc "Disables push of anonymous usage metrics to NetBird.";
}; };
disableSingleAccountMode = mkOption { disableSingleAccountMode = mkOption {
@ -250,38 +288,32 @@ in {
TURN_PASSWORD = mkOption { TURN_PASSWORD = mkOption {
type = with types; nullOr path; type = with types; nullOr path;
default = null; default = null;
description = description = lib.mdDoc "Path to a file containing the secret TURN_PASSWORD.";
lib.mdDoc "Path to a file containing the secret TURN_PASSWORD.";
}; };
TURN_SECRET = mkOption { TURN_SECRET = mkOption {
type = with types; nullOr path; type = with types; nullOr path;
default = null; default = null;
description = description = lib.mdDoc "Path to a file containing the secret TURN_SECRET.";
lib.mdDoc "Path to a file containing the secret TURN_SECRET.";
}; };
STUN_PASSWORD = mkOption { STUN_PASSWORD = mkOption {
type = with types; nullOr path; type = with types; nullOr path;
default = null; default = null;
description = description = lib.mdDoc "Path to a file containing the secret STUN_PASSWORD.";
lib.mdDoc "Path to a file containing the secret STUN_PASSWORD.";
}; };
AUTH_CLIENT_SECRET = mkOption { AUTH_CLIENT_SECRET = mkOption {
type = with types; nullOr path; type = with types; nullOr path;
default = null; default = null;
description = lib.mdDoc description = lib.mdDoc "Path to a file containing the secret NETBIRD_AUTH_CLIENT_SECRET.";
"Path to a file containing the secret NETBIRD_AUTH_CLIENT_SECRET.";
}; };
IDP_MGMT_CLIENT_SECRET = mkOption { IDP_MGMT_CLIENT_SECRET = mkOption {
type = with types; nullOr path; type = with types; nullOr path;
default = cfg.secretFiles.AUTH_CLIENT_SECRET; default = cfg.secretFiles.AUTH_CLIENT_SECRET;
defaultText = defaultText = lib.literalExpression "cfg.secretFiles.AUTH_CLIENT_SECRET;";
lib.literalExpression "cfg.secretFiles.AUTH_CLIENT_SECRET;"; description = lib.mdDoc "Path to a file containing the secret NETBIRD_IDP_MGMT_CLIENT_SECRET.";
description = lib.mdDoc
"Path to a file containing the secret NETBIRD_IDP_MGMT_CLIENT_SECRET.";
}; };
}; };
}; };
@ -289,19 +321,23 @@ in {
config = mkMerge [ config = mkMerge [
(mkIf cfg.enable { (mkIf cfg.enable {
services.netbird-server.managementConfig = with settings; { services.netbird-server.managementConfig = with settings; {
Stuns = mkDefault [{ Stuns = mkDefault [
Proto = "udp"; {
URI = "stun:${TURN_DOMAIN}:${builtins.toString TURN_PORT}";
Username = STUN_USERNAME;
Password = STUN_PASSWORD;
}];
TURNConfig = {
Turns = [{
Proto = "udp"; Proto = "udp";
URI = "turn:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; URI = "stun:${TURN_DOMAIN}:${builtins.toString TURN_PORT}";
Username = TURN_USER; Username = STUN_USERNAME;
Password = TURN_PASSWORD; Password = STUN_PASSWORD;
}]; }
];
TURNConfig = {
Turns = [
{
Proto = "udp";
URI = "turn:${TURN_DOMAIN}:${builtins.toString TURN_PORT}";
Username = TURN_USER;
Password = TURN_PASSWORD;
}
];
CredentialsTTL = "12h"; CredentialsTTL = "12h";
Secret = TURN_SECRET; Secret = TURN_SECRET;
TimeBasedCredentials = false; TimeBasedCredentials = false;
@ -340,8 +376,7 @@ in {
ClientID = NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID; ClientID = NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID;
TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT; TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT;
DeviceAuthEndpoint = NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT; DeviceAuthEndpoint = NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT;
Scope = Scope = builtins.concatStringsSep " " NETBIRD_AUTH_DEVICE_AUTH_SCOPE;
builtins.concatStringsSep " " NETBIRD_AUTH_DEVICE_AUTH_SCOPE;
UseIDToken = NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN; UseIDToken = NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN;
}; };
}; };
@ -377,13 +412,10 @@ in {
grpc_socket_keepalive on; grpc_socket_keepalive on;
''; '';
"/api".proxyPass = "/api".proxyPass = "http://localhost:${builtins.toString cfg.ports.management}";
"http://localhost:${builtins.toString cfg.ports.management}";
"/management.ManagementService/".extraConfig = '' "/management.ManagementService/".extraConfig = ''
grpc_pass grpc://localhost:${ grpc_pass grpc://localhost:${builtins.toString cfg.ports.management};
builtins.toString cfg.ports.management
};
grpc_read_timeout 1d; grpc_read_timeout 1d;
grpc_send_timeout 1d; grpc_send_timeout 1d;
grpc_socket_keepalive on; grpc_socket_keepalive on;
@ -411,59 +443,81 @@ in {
StartLimitBurst = 10; StartLimitBurst = 10;
}; };
path = (with pkgs; [ coreutils findutils gettext gnused ]) path =
++ (optionals cfg.setupAutoOidc (with pkgs; [ curl jq ])); (with pkgs; [
coreutils
findutils
gettext
gnused
])
++ (optionals cfg.setupAutoOidc (
with pkgs;
[
curl
jq
]
));
script = '' script =
cp ${managementFile} ${stateDir}/management.json.copy ''
'' + (optionalString cfg.setupAutoOidc '' cp ${managementFile} ${stateDir}/management.json.copy
mv ${stateDir}/management.json.copy ${stateDir}/management.json ''
echo "loading OpenID configuration from $NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT to the openid-configuration.json file" + (optionalString cfg.setupAutoOidc ''
curl "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" -q -o ${stateDir}/openid-configuration.json mv ${stateDir}/management.json.copy ${stateDir}/management.json
echo "loading OpenID configuration from $NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT to the openid-configuration.json file"
curl "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" -q -o ${stateDir}/openid-configuration.json
export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${stateDir}/openid-configuration.json) export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${stateDir}/openid-configuration.json)
export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${stateDir}/openid-configuration.json) export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${stateDir}/openid-configuration.json)
export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${stateDir}/openid-configuration.json) export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${stateDir}/openid-configuration.json)
export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${stateDir}/openid-configuration.json) export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${stateDir}/openid-configuration.json)
export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${stateDir}/openid-configuration.json) export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${stateDir}/openid-configuration.json)
envsubst '$NETBIRD_AUTH_AUTHORITY $NETBIRD_AUTH_JWT_CERTS $NETBIRD_AUTH_TOKEN_ENDPOINT $NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT $NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT' < ${stateDir}/management.json > ${stateDir}/management.json.copy envsubst '$NETBIRD_AUTH_AUTHORITY $NETBIRD_AUTH_JWT_CERTS $NETBIRD_AUTH_TOKEN_ENDPOINT $NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT $NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT' < ${stateDir}/management.json > ${stateDir}/management.json.copy
'') + '' '')
# Update secrets in management.json + ''
${builtins.concatStringsSep "\n" (builtins.attrValues # Update secrets in management.json
(builtins.mapAttrs (name: path: "export ${name}=$(cat ${path})") ${builtins.concatStringsSep "\n" (
(filterAttrs (_: p: p != null) cfg.secretFiles)))} builtins.attrValues (
builtins.mapAttrs (name: path: "export ${name}=$(cat ${path})") (
filterAttrs (_: p: p != null) cfg.secretFiles
)
)
)}
envsubst '$TURN_PASSWORD $TURN_SECRET $STUN_PASSWORD $AUTH_CLIENT_SECRET $IDP_MGMT_CLIENT_SECRET' < ${stateDir}/management.json.copy > ${stateDir}/management.json envsubst '$TURN_PASSWORD $TURN_SECRET $STUN_PASSWORD $AUTH_CLIENT_SECRET $IDP_MGMT_CLIENT_SECRET' < ${stateDir}/management.json.copy > ${stateDir}/management.json
rm -rf ${stateDir}/web-ui rm -rf ${stateDir}/web-ui
mkdir -p ${stateDir}/web-ui mkdir -p ${stateDir}/web-ui
cp -R ${dashboard}/* ${stateDir}/web-ui cp -R ${dashboard}/* ${stateDir}/web-ui
export AUTH_AUTHORITY="$NETBIRD_AUTH_AUTHORITY" export AUTH_AUTHORITY="$NETBIRD_AUTH_AUTHORITY"
export AUTH_CLIENT_ID="$NETBIRD_AUTH_CLIENT_ID" export AUTH_CLIENT_ID="$NETBIRD_AUTH_CLIENT_ID"
${optionalString (cfg.secretFiles.AUTH_CLIENT_SECRET == null) ${optionalString (cfg.secretFiles.AUTH_CLIENT_SECRET == null)
''export AUTH_CLIENT_SECRET="$NETBIRD_AUTH_CLIENT_SECRET"''} ''export AUTH_CLIENT_SECRET="$NETBIRD_AUTH_CLIENT_SECRET"''}
export AUTH_AUDIENCE="$NETBIRD_AUTH_AUDIENCE" export AUTH_AUDIENCE="$NETBIRD_AUTH_AUDIENCE"
export AUTH_REDIRECT_URI="$NETBIRD_AUTH_REDIRECT_URI" export AUTH_REDIRECT_URI="$NETBIRD_AUTH_REDIRECT_URI"
export AUTH_SILENT_REDIRECT_URI="$NETBIRD_AUTH_SILENT_REDIRECT_URI" export AUTH_SILENT_REDIRECT_URI="$NETBIRD_AUTH_SILENT_REDIRECT_URI"
export USE_AUTH0="$NETBIRD_USE_AUTH0" export USE_AUTH0="$NETBIRD_USE_AUTH0"
export AUTH_SUPPORTED_SCOPES=$(echo $NETBIRD_AUTH_SUPPORTED_SCOPES | sed -E 's/"//g') export AUTH_SUPPORTED_SCOPES=$(echo $NETBIRD_AUTH_SUPPORTED_SCOPES | sed -E 's/"//g')
export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//') export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
MAIN_JS=$(find ${stateDir}/web-ui/static/js/main.*js) MAIN_JS=$(find ${stateDir}/web-ui/static/js/main.*js)
OIDC_TRUSTED_DOMAINS=${stateDir}/web-ui/OidcTrustedDomains.js OIDC_TRUSTED_DOMAINS=${stateDir}/web-ui/OidcTrustedDomains.js
mv "$MAIN_JS" "$MAIN_JS".copy mv "$MAIN_JS" "$MAIN_JS".copy
envsubst '$USE_AUTH0 $AUTH_AUTHORITY $AUTH_CLIENT_ID $AUTH_CLIENT_SECRET $AUTH_SUPPORTED_SCOPES $AUTH_AUDIENCE $NETBIRD_MGMT_API_ENDPOINT $NETBIRD_MGMT_GRPC_API_ENDPOINT $NETBIRD_HOTJAR_TRACK_ID $AUTH_REDIRECT_URI $AUTH_SILENT_REDIRECT_URI $NETBIRD_TOKEN_SOURCE $NETBIRD_DRAG_QUERY_PARAMS' < "$MAIN_JS".copy > "$MAIN_JS" envsubst '$USE_AUTH0 $AUTH_AUTHORITY $AUTH_CLIENT_ID $AUTH_CLIENT_SECRET $AUTH_SUPPORTED_SCOPES $AUTH_AUDIENCE $NETBIRD_MGMT_API_ENDPOINT $NETBIRD_MGMT_GRPC_API_ENDPOINT $NETBIRD_HOTJAR_TRACK_ID $AUTH_REDIRECT_URI $AUTH_SILENT_REDIRECT_URI $NETBIRD_TOKEN_SOURCE $NETBIRD_DRAG_QUERY_PARAMS' < "$MAIN_JS".copy > "$MAIN_JS"
envsubst '$NETBIRD_MGMT_API_ENDPOINT' < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS" envsubst '$NETBIRD_MGMT_API_ENDPOINT' < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
''; '';
}; };
netbird-signal = { netbird-signal = {
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "netbird-management.service" ]; wantedBy = [ "netbird-management.service" ];
restartTriggers = [ settingsFile managementFile ]; restartTriggers = [
settingsFile
managementFile
];
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''
@ -487,24 +541,27 @@ in {
netbird-management = { netbird-management = {
description = "The management server for Netbird, a wireguard VPN"; description = "The management server for Netbird, a wireguard VPN";
documentation = [ "https://netbird.io/docs/" ]; documentation = [ "https://netbird.io/docs/" ];
after = [ "network.target" "netbird-setup.service" ]; after = [
"network.target"
"netbird-setup.service"
];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
wants = [ "netbird-signal.service" "netbird-setup.service" ]; wants = [
restartTriggers = [ settingsFile managementFile ]; "netbird-signal.service"
"netbird-setup.service"
];
restartTriggers = [
settingsFile
managementFile
];
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''
${cfg.package}/bin/netbird-mgmt management \ ${cfg.package}/bin/netbird-mgmt management \
--config ${stateDir}/management.json \ --config ${stateDir}/management.json \
--datadir ${stateDir}/data \ --datadir ${stateDir}/data \
${ ${optionalString cfg.management.disableAnonymousMetrics "--disable-anonymous-metrics"} \
optionalString cfg.management.disableAnonymousMetrics ${optionalString cfg.management.disableSingleAccountMode "--disable-single-account-mode"} \
"--disable-anonymous-metrics"
} \
${
optionalString cfg.management.disableSingleAccountMode
"--disable-single-account-mode"
} \
--dns-domain ${cfg.management.dnsDomain} \ --dns-domain ${cfg.management.dnsDomain} \
--single-account-mode-domain ${cfg.management.singleAccountModeDomain} \ --single-account-mode-domain ${cfg.management.singleAccountModeDomain} \
--idp-sign-key-refresh-enabled \ --idp-sign-key-refresh-enabled \
@ -514,7 +571,10 @@ in {
''; '';
Restart = "always"; Restart = "always";
RuntimeDirectory = "netbird-mgmt"; RuntimeDirectory = "netbird-mgmt";
StateDirectory = [ "netbird-mgmt" "netbird-mgmt/data" ]; StateDirectory = [
"netbird-mgmt"
"netbird-mgmt/data"
];
WorkingDirectory = stateDir; WorkingDirectory = stateDir;
}; };
unitConfig = { unitConfig = {
@ -549,18 +609,25 @@ in {
5349 5349
5350 5350
]; ];
allowedTCPPorts = with settings; [ TURN_PORT (TURN_PORT + 1) ]; allowedTCPPorts = with settings; [
allowedUDPPortRanges = [{ TURN_PORT
from = settings.TURN_MIN_PORT; (TURN_PORT + 1)
to = settings.TURN_MAX_PORT; ];
}]; allowedUDPPortRanges = [
{
from = settings.TURN_MIN_PORT;
to = settings.TURN_MAX_PORT;
}
];
}; };
}) })
(mkIf (cfg.enableNginx && cfg.enableCoturn) { (mkIf (cfg.enableNginx && cfg.enableCoturn) {
services.coturn = services.coturn =
let cert = config.security.acme.certs.${settings.TURN_DOMAIN}; let
in { cert = config.security.acme.certs.${settings.TURN_DOMAIN};
in
{
cert = "${cert.directory}/fullchain.pem"; cert = "${cert.directory}/fullchain.pem";
pkey = "${cert.directory}/key.pem"; pkey = "${cert.directory}/key.pem";
}; };
@ -570,8 +637,7 @@ in {
# share certs with coturn and restart on renewal # share certs with coturn and restart on renewal
security.acme.certs.${settings.TURN_DOMAIN} = { security.acme.certs.${settings.TURN_DOMAIN} = {
group = "turnserver"; group = "turnserver";
postRun = postRun = "systemctl reload nginx.service; systemctl restart coturn.service";
"systemctl reload nginx.service; systemctl restart coturn.service";
}; };
}) })
]; ];

View file

@ -1,4 +1,8 @@
{ lib, buildNpmPackage, fetchFromGitHub }: {
lib,
buildNpmPackage,
fetchFromGitHub,
}:
buildNpmPackage rec { buildNpmPackage rec {
pname = "netbird-dashboard"; pname = "netbird-dashboard";

View file

@ -1,4 +1,6 @@
{ pkgs ? import <nixpkgs> {} }: {
pkgs ? import <nixpkgs> { },
}:
{ {
dashboard = pkgs.callPackage ./dashboard.nix { }; dashboard = pkgs.callPackage ./dashboard.nix { };

View file

@ -1,7 +1,9 @@
{ config, ... }: { config, ... }:
let host = "videos.dgnum.eu"; let
in { host = "videos.dgnum.eu";
in
{
services.peertube = { services.peertube = {
enable = true; enable = true;
@ -53,8 +55,7 @@ in {
database.createLocally = true; database.createLocally = true;
smtp.passwordFile = config.age.secrets."peertube-smtp_password_file".path; smtp.passwordFile = config.age.secrets."peertube-smtp_password_file".path;
serviceEnvironmentFile = serviceEnvironmentFile = config.age.secrets."peertube-service_environment_file".path;
config.age.secrets."peertube-service_environment_file".path;
secrets.secretsFile = config.age.secrets."peertube-secrets_file".path; secrets.secretsFile = config.age.secrets."peertube-secrets_file".path;
}; };
@ -63,5 +64,7 @@ in {
forceSSL = true; forceSSL = true;
}; };
age-secrets.matches."^peertube-.*$" = { owner = "peertube"; }; age-secrets.matches."^peertube-.*$" = {
owner = "peertube";
};
} }

View file

@ -1,8 +1,8 @@
let let
lib = import ../../../lib { }; lib = import ../../../lib { };
publicKeys = lib.getNodeKeys "storage01"; publicKeys = lib.getNodeKeys "storage01";
in
in lib.setDefault { inherit publicKeys; } [ lib.setDefault { inherit publicKeys; } [
"atticd-credentials_file" "atticd-credentials_file"
"forgejo-database_password_file" "forgejo-database_password_file"
"forgejo_runners-token_file" "forgejo_runners-token_file"

View file

@ -11,8 +11,10 @@ lib.extra.mkConfig {
]; ];
extraConfig = { extraConfig = {
dgn-fail2ban.jails = dgn-fail2ban.jails = lib.extra.enableAttrs' "enabled" [
lib.extra.enableAttrs' "enabled" [ "sshd-bruteforce" "sshd-timeout" ]; "sshd-bruteforce"
"sshd-timeout"
];
services.netbird.enable = true; services.netbird.enable = true;

View file

@ -8,8 +8,14 @@
boot = { boot = {
initrd = { initrd = {
availableKernelModules = availableKernelModules = [
[ "xhci_pci" "megaraid_sas" "ehci_pci" "ahci" "usb_storage" "sd_mod" ]; "xhci_pci"
"megaraid_sas"
"ehci_pci"
"ahci"
"usb_storage"
"sd_mod"
];
kernelModules = [ ]; kernelModules = [ ];
}; };
@ -30,6 +36,5 @@
}; };
}; };
swapDevices = swapDevices = [ { device = "/dev/disk/by-uuid/954ecb9c-ccd1-4e98-9eb6-3514bd3c01d1"; } ];
[{ device = "/dev/disk/by-uuid/954ecb9c-ccd1-4e98-9eb6-3514bd3c01d1"; }];
} }

View file

@ -1,6 +1,5 @@
let let
lib = import ../../../lib { }; lib = import ../../../lib { };
publicKeys = lib.getNodeKeys "vault01"; publicKeys = lib.getNodeKeys "vault01";
in
in lib.setDefault { inherit publicKeys; } [ lib.setDefault { inherit publicKeys; } [ ]
]

View file

@ -6,7 +6,12 @@
{ {
imports = [ imports = [
(modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/profiles/qemu-guest.nix")
(let sources = import ../../npins; in sources.disko + "/module.nix") (
let
sources = import ../../npins;
in
sources.disko + "/module.nix"
)
./disko.nix ./disko.nix
]; ];
} }

View file

@ -3,31 +3,31 @@ let
cfg = config.services.castopod; cfg = config.services.castopod;
fpm = config.services.phpfpm.pools.castopod; fpm = config.services.phpfpm.pools.castopod;
in in
{ {
services.nginx = { services.nginx = {
resolver.addresses = [ "127.0.0.53" ]; resolver.addresses = [ "127.0.0.53" ];
virtualHosts."${cfg.localDomain}" = { virtualHosts."${cfg.localDomain}" = {
locations."@force_get" = { locations."@force_get" = {
extraConfig = lib.mkForce '' extraConfig = lib.mkForce ''
recursive_error_pages on; recursive_error_pages on;
proxy_method GET; proxy_method GET;
proxy_pass https://podcasts.dgnum.eu/$request_uri; proxy_pass https://podcasts.dgnum.eu/$request_uri;
''; '';
}; };
locations."~ \.php$" = { locations."~ .php$" = {
extraConfig = lib.mkForce '' extraConfig = lib.mkForce ''
error_page 550 = @force_get; error_page 550 = @force_get;
if ($request_method = HEAD) { return 550; } if ($request_method = HEAD) { return 550; }
fastcgi_intercept_errors on; fastcgi_intercept_errors on;
fastcgi_index index.php; fastcgi_index index.php;
fastcgi_pass unix:${fpm.socket}; fastcgi_pass unix:${fpm.socket};
try_files $uri =404; try_files $uri =404;
fastcgi_read_timeout 3600; fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600; fastcgi_send_timeout 3600;
''; '';
};
}; };
}; };
} };
}

View file

@ -1,38 +1,41 @@
{ config, pkgs, ...}: { config, pkgs, ... }:
let let
host = "podcasts.dgnum.eu"; host = "podcasts.dgnum.eu";
in in
{ {
imports = [ imports = [ ./castopod-head-proxy.nix ];
./castopod-head-proxy.nix
];
services.castopod = {
enable = true;
localDomain = host;
environmentFile = config.age.secrets.castopod-environment_file.path;
maxUploadSize = 512;
settings = {
"email.fromEmail"="noreply@infra.dgnum.eu";
"email.SMTPHost"="kurisu.lahfa.xyz";
"email.SMTPUser"="web-services@infra.dgnum.eu";
"email.SMTPPort"="587";
"media.fileManager"="s3"; services = {
"media.s3.endpoint"="https://s3.dgnum.eu/"; castopod = {
"media.s3.region"="garage"; enable = true;
"media.s3.bucket"="castopod-dgnum"; localDomain = host;
"media.s3.pathStyleEndpoint"=true; environmentFile = config.age.secrets.castopod-environment_file.path;
maxUploadSize = 512;
settings = {
"email.fromEmail" = "noreply@infra.dgnum.eu";
"email.SMTPHost" = "kurisu.lahfa.xyz";
"email.SMTPUser" = "web-services@infra.dgnum.eu";
"email.SMTPPort" = "587";
"restapi.enabled"=true; "media.fileManager" = "s3";
"restapi.basicAuthUsername"="castopod"; "media.s3.endpoint" = "https://s3.dgnum.eu/";
"restapi.basicAuth"=true; "media.s3.region" = "garage";
"media.s3.bucket" = "castopod-dgnum";
"media.s3.pathStyleEndpoint" = true;
"restapi.enabled" = true;
"restapi.basicAuthUsername" = "castopod";
"restapi.basicAuth" = true;
};
database.createLocally = true;
configureNginx = true;
};
mysql.package = pkgs.mariadb;
nginx.virtualHosts.${host} = {
forceSSL = true;
enableACME = true;
}; };
database.createLocally = true;
configureNginx = true;
};
services.mysql.package = pkgs.mariadb;
services.nginx.virtualHosts.${host} = {
forceSSL = true;
enableACME = true;
}; };
} }

View file

@ -56,7 +56,10 @@ in
mountpoint = "/var/log"; mountpoint = "/var/log";
}; };
"/nix" = { "/nix" = {
mountOptions = [ "noatime" "compress=zstd" ]; mountOptions = [
"noatime"
"compress=zstd"
];
mountpoint = "/nix"; mountpoint = "/nix";
}; };
}; };

View file

@ -1,5 +1,4 @@
{ ... }: _: {
{
services.dolibarr = { services.dolibarr = {
enable = true; enable = true;
domain = "erp.dgnum.eu"; domain = "erp.dgnum.eu";

View file

@ -1,4 +1,9 @@
{ sources, pkgs, lib, ... }: {
sources,
pkgs,
lib,
...
}:
let let
host = "cal.dgnum.eu"; host = "cal.dgnum.eu";
@ -26,7 +31,8 @@ let
calendars = metis2linkal sources.metis; calendars = metis2linkal sources.metis;
}; };
}; };
in { in
{
imports = [ ./module.nix ]; imports = [ ./module.nix ];
dgn-linkal = { dgn-linkal = {

View file

@ -7,18 +7,10 @@ let
inherit (import source { inherit pkgs; }) providers; inherit (import source { inherit pkgs; }) providers;
# helper function to map 2-level deep attribute-sets # helper function to map 2-level deep attribute-sets
mapDeepAttrs = mapFct: mapDeepAttrs =
lib.concatMapAttrs (name: value: mapFct:
lib.mapAttrs' (name': value': lib.concatMapAttrs (name: value: lib.mapAttrs' (name': value': mapFct name name' value') value);
mapFct name name' value'
) value
);
toLinkal = upstream: identifier:
lib.nameValuePair
"${providers.${upstream}}${identifier}"
;
toLinkal = upstream: identifier: lib.nameValuePair "${providers.${upstream}}${identifier}";
in in
mapDeepAttrs toLinkal calendars mapDeepAttrs toLinkal calendars

View file

@ -1,14 +1,28 @@
{ config, lib, pkgs, sources, ... }: {
config,
lib,
pkgs,
sources,
...
}:
let let
inherit (lib) mapAttrs' mkEnableOption mkIf mkOption nameValuePair types; inherit (lib)
mapAttrs'
mkEnableOption
mkIf
mkOption
nameValuePair
types
;
package = import sources.linkal { inherit pkgs; }; package = import sources.linkal { inherit pkgs; };
cfg = config.dgn-linkal; cfg = config.dgn-linkal;
jsonFormat = pkgs.formats.json { }; jsonFormat = pkgs.formats.json { };
in { in
{
options.dgn-linkal = { options.dgn-linkal = {
enable = mkEnableOption "the linkal server."; enable = mkEnableOption "the linkal server.";
@ -20,32 +34,40 @@ in {
domain = mkOption { type = types.str; }; domain = mkOption { type = types.str; };
calendarGroups = mkOption { calendarGroups = mkOption {
type = let inherit (types) attrsOf port submodule; type =
in attrsOf (submodule { let
options = { inherit (types) attrsOf port submodule;
port = mkOption { type = port; }; in
calendars = mkOption { inherit (jsonFormat) type; }; attrsOf (
}; submodule {
}); options = {
port = mkOption { type = port; };
calendars = mkOption { inherit (jsonFormat) type; };
};
}
);
default = { }; default = { };
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.services = mapAttrs' (name: systemd.services =
{ port, calendars }: mapAttrs'
nameValuePair "linkal-${name}" { (
description = "Linkal - ${name}"; name:
wantedBy = [ "multi-user.target" ]; { port, calendars }:
serviceConfig = { nameValuePair "linkal-${name}" {
Type = "simple"; description = "Linkal - ${name}";
ExecStart = "${cfg.package}/bin/linkal --port ${ wantedBy = [ "multi-user.target" ];
builtins.toString port serviceConfig = {
} --calendar-file ${ Type = "simple";
jsonFormat.generate "linkal-${name}.json" { inherit calendars; } ExecStart = "${cfg.package}/bin/linkal --port ${builtins.toString port} --calendar-file ${
}"; jsonFormat.generate "linkal-${name}.json" { inherit calendars; }
}; }";
}) cfg.calendarGroups; };
}
)
cfg.calendarGroups;
# Configure bind for DNS certificate validation on *.cal.dgnum.eu. # Configure bind for DNS certificate validation on *.cal.dgnum.eu.
# services.bind = { # services.bind = {
@ -85,16 +107,20 @@ in {
services.nginx = { services.nginx = {
enable = true; enable = true;
virtualHosts = mapAttrs' (name: virtualHosts =
{ port, ... }: mapAttrs'
nameValuePair "${name}.${cfg.domain}" { (
enableACME = true; name:
# acmeRoot = null; # Use DNS-01 validation { port, ... }:
forceSSL = true; nameValuePair "${name}.${cfg.domain}" {
enableACME = true;
# acmeRoot = null; # Use DNS-01 validation
forceSSL = true;
locations."/".proxyPass = locations."/".proxyPass = "http://127.0.0.1:${builtins.toString port}/";
"http://127.0.0.1:${builtins.toString port}/"; }
}) cfg.calendarGroups; )
cfg.calendarGroups;
}; };
}; };
} }

View file

@ -6,5 +6,7 @@
configPath = config.age.secrets."matterbridge-config_file".path; configPath = config.age.secrets."matterbridge-config_file".path;
}; };
age-secrets.matches."^matterbridge-.*$" = { owner = "matterbridge"; }; age-secrets.matches."^matterbridge-.*$" = {
owner = "matterbridge";
};
} }

View file

@ -1,24 +1,35 @@
{ lib, pkgs, sources, ... }: {
lib,
pkgs,
sources,
...
}:
let let
metis = import sources.metis { inherit pkgs; }; metis = import sources.metis { inherit pkgs; };
inherit (metis) providers; inherit (metis) providers;
in { in
{
services.nginx.virtualHosts."calendrier.dgnum.eu" = { services.nginx.virtualHosts."calendrier.dgnum.eu" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
root = metis.production; root = metis.production;
locations = lib.mapAttrs' (name: value: locations =
lib.nameValuePair "/cal/${name}/" { lib.mapAttrs'
extraConfig = '' (
proxy_set_header X-Forwarded-Host $host; name: value:
proxy_set_header X-Forwarded-Server $host; lib.nameValuePair "/cal/${name}/" {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; extraConfig = ''
proxy_pass ${value}; proxy_set_header X-Forwarded-Host $host;
''; proxy_set_header X-Forwarded-Server $host;
}) providers; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass ${value};
'';
}
)
providers;
extraConfig = '' extraConfig = ''
rewrite ^/calendrier(.*)$ $1 permanent; rewrite ^/calendrier(.*)$ $1 permanent;

View file

@ -1,8 +1,9 @@
{ config, ... }: { config, ... }:
let host = "push.dgnum.eu"; let
host = "push.dgnum.eu";
in { in
{
services.ntfy-sh = { services.ntfy-sh = {
enable = true; enable = true;
@ -26,6 +27,7 @@ in {
}; };
}; };
systemd.services.ntfy-sh.serviceConfig.EnvironmentFile = systemd.services.ntfy-sh.serviceConfig.EnvironmentFile = [
[ config.age.secrets."ntfy_sh-environment_file".path ]; config.age.secrets."ntfy_sh-environment_file".path
];
} }

View file

@ -3,15 +3,19 @@ _:
let let
retired_host = "retired.dgnum.eu"; retired_host = "retired.dgnum.eu";
mkRetired = hosts: mkRetired =
builtins.listToAttrs (builtins.map (name: { hosts:
inherit name; builtins.listToAttrs (
value.to = retired_host; builtins.map
}) hosts); (name: {
inherit name;
value.to = retired_host;
})
hosts
);
mkSub = domain: builtins.map (s: "${s}.${domain}"); mkSub = domain: builtins.map (s: "${s}.${domain}");
mkSubs = attrs: mkSubs = attrs: builtins.concatLists (builtins.attrValues (builtins.mapAttrs mkSub attrs));
builtins.concatLists (builtins.attrValues (builtins.mapAttrs mkSub attrs));
redirections = { redirections = {
"calendrier.eleves.ens.fr".to = "calendrier.dgnum.eu"; "calendrier.eleves.ens.fr".to = "calendrier.dgnum.eu";
@ -23,9 +27,15 @@ let
} // (mkRetired retired); } // (mkRetired retired);
retired = mkSubs { retired = mkSubs {
"ens.fr" = [ "alevins" "www.climatenavigator" ]; "ens.fr" = [
"alevins"
"www.climatenavigator"
];
"ens.wtf" = [ "photos" ]; "ens.wtf" = [ "photos" ];
"rz.ens.wtf" = [ "s3" "cdn" ]; "rz.ens.wtf" = [
"s3"
"cdn"
];
"beta.rz.ens.wtf" = [ "beta.rz.ens.wtf" = [
"todo" "todo"
"minecraft" "minecraft"
@ -39,14 +49,25 @@ let
"rstudio" "rstudio"
]; ];
}; };
in
in { {
services.nginx.virtualHosts = { services.nginx.virtualHosts =
${retired_host}.default = true; {
} // (builtins.mapAttrs (host: ${retired_host}.default = true;
{ to, ssl ? true }: { }
globalRedirect = to; // (builtins.mapAttrs
enableACME = ssl; (
forceSSL = ssl; _:
}) redirections); {
to,
ssl ? true,
}:
{
globalRedirect = to;
enableACME = ssl;
forceSSL = ssl;
}
)
redirections
);
} }

View file

@ -1,7 +1,8 @@
let let
lib = import ../../../lib { }; lib = import ../../../lib { };
publicKeys = lib.getNodeKeys "web01"; publicKeys = lib.getNodeKeys "web01";
in lib.setDefault { inherit publicKeys; } [ in
lib.setDefault { inherit publicKeys; } [
"acme-certs_secret" "acme-certs_secret"
"matterbridge-config_file" "matterbridge-config_file"
"named-bind_dnskeys_conf" "named-bind_dnskeys_conf"

View file

@ -1,20 +1,34 @@
# Generated by npins. Do not modify; will be overwritten regularly # Generated by npins. Do not modify; will be overwritten regularly
let let
data = builtins.fromJSON (builtins.readFile ./sources.json); data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version; inherit (data) version;
mkSource = spec: mkSource =
assert spec ? type; let spec:
assert spec ? type;
let
path = path =
if spec.type == "Git" then mkGitSource spec if spec.type == "Git" then
else if spec.type == "GitRelease" then mkGitSource spec mkGitSource spec
else if spec.type == "PyPi" then mkPyPiSource spec else if spec.type == "GitRelease" then
else if spec.type == "Channel" then mkChannelSource spec mkGitSource spec
else builtins.throw "Unknown source type ${spec.type}"; else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in in
spec // { outPath = path; }; spec // { outPath = path; };
mkGitSource = { repository, revision, url ? null, hash, ... }: mkGitSource =
{
repository,
revision,
url ? null,
hash,
...
}:
assert repository ? type; assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball # In the latter case, there we will always be an url to the tarball
@ -23,19 +37,23 @@ let
inherit url; inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes sha256 = hash; # FIXME: check nix version & use SRI hashes
}) })
else assert repository.type == "Git"; builtins.fetchGit { else
url = repository.url; assert repository.type == "Git";
rev = revision; builtins.fetchGit {
# hash = hash; inherit (repository) url;
}; rev = revision;
# hash = hash;
};
mkPyPiSource = { url, hash, ... }: mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl { builtins.fetchurl {
inherit url; inherit url;
sha256 = hash; sha256 = hash;
}; };
mkChannelSource = { url, hash, ... }: mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball { builtins.fetchTarball {
inherit url; inherit url;
sha256 = hash; sha256 = hash;

View file

@ -1,7 +1,9 @@
{ pkgs, sources, ... }: { pkgs, sources, ... }:
let wp4nix = pkgs.callPackage sources.wp4nix { }; let
in { wp4nix = pkgs.callPackage sources.wp4nix { };
in
{
imports = [ ./module.nix ]; imports = [ ./module.nix ];
services.wp-containers = { services.wp-containers = {
@ -9,26 +11,38 @@ in {
sites = { sites = {
"lavoixduntexte.normalesup.eu" = { "lavoixduntexte.normalesup.eu" = {
themes = { inherit (wp4nix.themes) avant; }; themes = {
inherit (wp4nix.themes) avant;
};
plugins = { inherit (wp4nix.plugins) wordpress-importer; }; plugins = {
inherit (wp4nix.plugins) wordpress-importer;
};
languages = [ pkgs.wordpressPackages.languages.fr_FR ]; languages = [ pkgs.wordpressPackages.languages.fr_FR ];
}; };
"bds.wp.dgnum.eu" = { "bds.wp.dgnum.eu" = {
plugins = { inherit (wp4nix.plugins) user-role-editor; }; plugins = {
inherit (wp4nix.plugins) user-role-editor;
};
languages = [ pkgs.wordpressPackages.languages.fr_FR ]; languages = [ pkgs.wordpressPackages.languages.fr_FR ];
themes = { inherit (wp4nix.themes) gateway twentytwentythree; }; themes = {
inherit (wp4nix.themes) gateway twentytwentythree;
};
}; };
"bda.wp.dgnum.eu" = { "bda.wp.dgnum.eu" = {
plugins = { inherit (wp4nix.plugins) user-role-editor; }; plugins = {
inherit (wp4nix.plugins) user-role-editor;
};
languages = [ pkgs.wordpressPackages.languages.fr_FR ]; languages = [ pkgs.wordpressPackages.languages.fr_FR ];
}; };
"cineclub.wp.dgnum.eu" = { "cineclub.wp.dgnum.eu" = {
plugins = { inherit (wp4nix.plugins) user-role-editor; }; plugins = {
inherit (wp4nix.plugins) user-role-editor;
};
languages = [ pkgs.wordpressPackages.languages.fr_FR ]; languages = [ pkgs.wordpressPackages.languages.fr_FR ];
}; };
}; };

View file

@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkEnableOption mkIf mkOption; inherit (lib) mkEnableOption mkIf mkOption;
@ -13,41 +18,52 @@ let
mkHost = mkIp "10.31.41"; mkHost = mkIp "10.31.41";
mkLocal = mkIp "10.0.0"; mkLocal = mkIp "10.0.0";
mkConfig = { name, value, i }: { mkConfig =
services.wordpress = { {
webserver = "nginx"; name,
sites.${name} = value; value,
i,
}:
{
services.wordpress = {
webserver = "nginx";
sites.${name} = value;
};
services.nginx.virtualHosts.${name} = {
onlySSL = true;
sslCertificate = "${certs.${name}.directory}/fullchain.pem";
sslCertificateKey = "${certs.${name}.directory}/key.pem";
sslTrustedCertificate = "${certs.${name}.directory}/chain.pem";
};
networking = {
hostName = mkName name;
hosts.${mkLocal i} = [ name ];
firewall.allowedTCPPorts = [ 443 ];
};
environment.systemPackages = [
pkgs.wp-cli
pkgs.neovim
];
system.stateVersion = "23.11";
}; };
services.nginx.virtualHosts.${name} = {
onlySSL = true;
sslCertificate = "${certs.${name}.directory}/fullchain.pem";
sslCertificateKey = "${certs.${name}.directory}/key.pem";
sslTrustedCertificate = "${certs.${name}.directory}/chain.pem";
};
networking = {
hostName = mkName name;
hosts.${mkLocal i} = [ name ];
firewall.allowedTCPPorts = [ 443 ];
};
environment.systemPackages = [ pkgs.wp-cli pkgs.neovim ];
system.stateVersion = "23.11";
};
mkContainer = i: site: { mkContainer = i: site: {
name = mkName site.name; name = mkName site.name;
value = { value = {
privateNetwork = true; privateNetwork = true;
forwardPorts = [{ forwardPorts = [
containerPort = 443; {
hostPort = cfg.basePort + i; containerPort = 443;
}]; hostPort = cfg.basePort + i;
}
];
bindMounts.certs = { bindMounts.certs = {
hostPath = certs.${site.name}.directory; hostPath = certs.${site.name}.directory;
@ -69,13 +85,13 @@ let
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations."/".proxyPass = locations."/".proxyPass = "https://${mkHost i}:${builtins.toString (cfg.basePort + i)}";
"https://${mkHost i}:${builtins.toString (cfg.basePort + i)}";
}; };
}; };
siteList = lib.attrsToList cfg.sites; siteList = lib.attrsToList cfg.sites;
in { in
{
options.services.wp-containers = { options.services.wp-containers = {
enable = mkEnableOption "wordpress sites in containers"; enable = mkEnableOption "wordpress sites in containers";
@ -93,7 +109,6 @@ in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
containers = builtins.listToAttrs (lib.imap1 mkContainer siteList); containers = builtins.listToAttrs (lib.imap1 mkContainer siteList);
services.nginx.virtualHosts = services.nginx.virtualHosts = builtins.listToAttrs (lib.imap1 mkVhost siteList);
builtins.listToAttrs (lib.imap1 mkVhost siteList);
}; };
} }

View file

@ -11,8 +11,10 @@ lib.extra.mkConfig {
]; ];
extraConfig = { extraConfig = {
dgn-fail2ban.jails = dgn-fail2ban.jails = lib.extra.enableAttrs' "enabled" [
lib.extra.enableAttrs' "enabled" [ "sshd-bruteforce" "sshd-timeout" ]; "sshd-bruteforce"
"sshd-timeout"
];
services.netbird.enable = true; services.netbird.enable = true;
}; };

View file

@ -8,8 +8,14 @@
boot = { boot = {
initrd = { initrd = {
availableKernelModules = availableKernelModules = [
[ "ata_piix" "uhci_hcd" "ehci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; "ata_piix"
"uhci_hcd"
"ehci_pci"
"virtio_pci"
"sr_mod"
"virtio_blk"
];
kernelModules = [ ]; kernelModules = [ ];
}; };
@ -30,6 +36,5 @@
}; };
}; };
swapDevices = swapDevices = [ { device = "/dev/disk/by-uuid/d64ae21e-693c-4c77-b62c-97d5e2a960cb"; } ];
[{ device = "/dev/disk/by-uuid/d64ae21e-693c-4c77-b62c-97d5e2a960cb"; }];
} }

View file

@ -1,6 +1,5 @@
let let
lib = import ../../../lib { }; lib = import ../../../lib { };
publicKeys = lib.getNodeKeys "web02"; publicKeys = lib.getNodeKeys "web02";
in
in lib.setDefault { inherit publicKeys; } [ lib.setDefault { inherit publicKeys; } [ ]
]

View file

@ -8,9 +8,7 @@
]; ];
# Jourdan # Jourdan
par02 = [ par02 = [ "vault01" ];
"vault01"
];
# VMs du SPI/NPS/Whatever # VMs du SPI/NPS/Whatever
dmi01 = [ dmi01 = [

View file

@ -26,15 +26,25 @@ let
groups = { groups = {
# members of this group are root on all nodes # members of this group are root on all nodes
root = [ "thubrecht" "raito" "mdebray" ]; root = [
"thubrecht"
"raito"
"mdebray"
];
# members of this group will have root access on the installation isos # members of this group will have root access on the installation isos
iso = [ "thubrecht" "mdebray" "raito" ]; iso = [
"thubrecht"
"mdebray"
"raito"
];
# members of this group can access netbox's secret # members of this group can access netbox's secret
netbox = []; netbox = [ ];
bureau = [ "gdd" ]; bureau = [ "gdd" ];
}; };
in
in { inherit groups members; } {
inherit groups members;
}

View file

@ -1,27 +1,47 @@
let let
mkDefaultInterface = _: attrs: { ipv4 = [ ]; ipv6 = [ ]; gateways = [ ]; } // attrs; mkDefaultInterface =
_: attrs:
{
ipv4 = [ ];
ipv6 = [ ];
gateways = [ ];
}
// attrs;
mkBase = config: config // { interfaces = builtins.mapAttrs mkDefaultInterface (config.interfaces or { }); }; mkBase =
config: config // { interfaces = builtins.mapAttrs mkDefaultInterface (config.interfaces or { }); };
getAddresses = version: interface: builtins.map (builtins.getAttr "address") interface.${version}; getAddresses = version: interface: builtins.map (builtins.getAttr "address") interface.${version};
filterIPv4 = ip: builtins.substring 0 7 ip != "192.168"; filterIPv4 = ip: builtins.substring 0 7 ip != "192.168";
filterIPv6 = _: true; filterIPv6 = _: true;
mkNet = _: value: mkNet =
let base = mkBase value; in _: value:
base // { let
base = mkBase value;
in
base
// {
addresses = addresses =
let let
_addresses = builtins.foldl' _addresses =
({ ipv4, ipv6 }: net: { builtins.foldl'
ipv4 = ipv4 ++ getAddresses "ipv4" net; (
ipv6 = ipv6 ++ getAddresses "ipv6" net; { ipv4, ipv6 }:
}) net: {
{ ipv4 = [ ]; ipv6 = [ ]; } ipv4 = ipv4 ++ getAddresses "ipv4" net;
(builtins.attrValues base.interfaces); ipv6 = ipv6 ++ getAddresses "ipv6" net;
}
)
{
ipv4 = [ ];
ipv6 = [ ];
}
(builtins.attrValues base.interfaces);
in in
_addresses // rec { _addresses
// rec {
publicV4 = builtins.filter filterIPv4 _addresses.ipv4; publicV4 = builtins.filter filterIPv4 _addresses.ipv4;
publicV6 = builtins.filter filterIPv6 _addresses.ipv6; publicV6 = builtins.filter filterIPv6 _addresses.ipv6;
public = publicV4 ++ publicV6; public = publicV4 ++ publicV6;
@ -34,8 +54,14 @@ builtins.mapAttrs mkNet {
interfaces = { interfaces = {
eno1 = { eno1 = {
ipv4 = [ ipv4 = [
{ address = "129.199.146.147"; prefixLength = 24; } {
{ address = "192.168.1.147"; prefixLength = 24; } address = "129.199.146.147";
prefixLength = 24;
}
{
address = "192.168.1.147";
prefixLength = 24;
}
]; ];
gateways = [ "129.199.146.254" ]; gateways = [ "129.199.146.254" ];
@ -49,8 +75,14 @@ builtins.mapAttrs mkNet {
interfaces = { interfaces = {
eno1 = { eno1 = {
ipv4 = [ ipv4 = [
{ address = "129.199.146.148"; prefixLength = 24; } {
{ address = "192.168.1.148"; prefixLength = 24; } address = "129.199.146.148";
prefixLength = 24;
}
{
address = "192.168.1.148";
prefixLength = 24;
}
]; ];
gateways = [ "129.199.146.254" ]; gateways = [ "129.199.146.254" ];
@ -64,7 +96,10 @@ builtins.mapAttrs mkNet {
interfaces = { interfaces = {
enp130s0f0 = { enp130s0f0 = {
ipv4 = [ ipv4 = [
{ address = "129.199.210.85"; prefixLength = 24; } {
address = "129.199.210.85";
prefixLength = 24;
}
]; ];
gateways = [ "129.199.210.254" ]; gateways = [ "129.199.210.254" ];
@ -77,7 +112,12 @@ builtins.mapAttrs mkNet {
web01 = { web01 = {
interfaces = { interfaces = {
ens3 = { ens3 = {
ipv4 = [{ address = "129.199.129.53"; prefixLength = 24; }]; ipv4 = [
{
address = "129.199.129.53";
prefixLength = 24;
}
];
gateways = [ "129.199.129.1" ]; gateways = [ "129.199.129.1" ];
}; };
@ -89,7 +129,12 @@ builtins.mapAttrs mkNet {
web02 = { web02 = {
interfaces = { interfaces = {
ens3 = { ens3 = {
ipv4 = [{ address = "129.199.129.235"; prefixLength = 24; }]; ipv4 = [
{
address = "129.199.129.235";
prefixLength = 24;
}
];
gateways = [ "129.199.129.1" ]; gateways = [ "129.199.129.1" ];
}; };

View file

@ -11,14 +11,17 @@
# } # }
let let
mkNode = _: attrs: { mkNode =
adminGroups = [ ]; _: attrs:
admins = [ ]; {
adminGroups = [ ];
admins = [ ];
deployment = { }; deployment = { };
nixpkgs = "23.11"; nixpkgs = "23.11";
} // attrs; }
// attrs;
in in
builtins.mapAttrs mkNode { builtins.mapAttrs mkNode {

View file

@ -35,22 +35,25 @@
{ lib, sources, ... }: { lib, sources, ... }:
{ {
imports = (lib.extra.mkImports ./. [ imports =
"dgn-access-control" (lib.extra.mkImports ./. [
"dgn-acme" "dgn-access-control"
"dgn-console" "dgn-acme"
"dgn-fail2ban" "dgn-console"
"dgn-hardware" "dgn-fail2ban"
"dgn-network" "dgn-hardware"
"dgn-ssh" "dgn-network"
"dgn-web" "dgn-ssh"
"dgn-vm-variant" "dgn-web"
]) ++ [ "dgn-vm-variant"
"${sources.agenix}/modules/age.nix" ])
"${sources.attic}/nixos/atticd.nix" ++ [
] ++ ((import sources.nix-modules { inherit lib; }).importModules [ "${sources.agenix}/modules/age.nix"
"age-secrets" "${sources.attic}/nixos/atticd.nix"
"services/crabfit" ]
"services/forgejo-nix-runners" ++ ((import sources.nix-modules { inherit lib; }).importModules [
]); "age-secrets"
"services/crabfit"
"services/forgejo-nix-runners"
]);
} }

View file

@ -31,7 +31,13 @@
# pris connaissance de la licence CeCILL, et que vous en avez accepté les # pris connaissance de la licence CeCILL, et que vous en avez accepté les
# termes. # termes.
{ config, lib, meta, name, ... }: {
config,
lib,
meta,
name,
...
}:
let let
inherit (lib) inherit (lib)
@ -40,10 +46,13 @@ let
mkIf mkIf
mkOption mkOption
types; types
;
nodeMeta = meta.nodes.${name}; nodeMeta = meta.nodes.${name};
admins = meta.members.groups.root ++ nodeMeta.admins admins =
meta.members.groups.root
++ nodeMeta.admins
++ (builtins.concatMap (g: meta.members.groups.${g}) nodeMeta.adminGroups); ++ (builtins.concatMap (g: meta.members.groups.${g}) nodeMeta.adminGroups);
cfg = config.dgn-access-control; cfg = config.dgn-access-control;
@ -51,7 +60,9 @@ in
{ {
options.dgn-access-control = { options.dgn-access-control = {
enable = mkEnableOption "DGNum access control." // { default = true; }; enable = mkEnableOption "DGNum access control." // {
default = true;
};
users = mkOption { users = mkOption {
type = with types; attrsOf (listOf str); type = with types; attrsOf (listOf str);
@ -72,8 +83,8 @@ in
# Admins have root access to the node # Admins have root access to the node
dgn-access-control.users.root = mkDefault admins; dgn-access-control.users.root = mkDefault admins;
users.users = builtins.mapAttrs users.users =
(u: members: { openssh.authorizedKeys.keys = lib.extra.getAllKeys members; }) builtins.mapAttrs (_: members: { openssh.authorizedKeys.keys = lib.extra.getAllKeys members; })
cfg.users; cfg.users;
}; };
} }

View file

@ -34,15 +34,15 @@
{ config, lib, ... }: { config, lib, ... }:
let let
inherit (lib) inherit (lib) mkEnableOption mkIf;
mkEnableOption
mkIf;
cfg = config.dgn-acme; cfg = config.dgn-acme;
in in
{ {
options.dgn-acme.enable = mkEnableOption "ACME settings." // { default = true; }; options.dgn-acme.enable = mkEnableOption "ACME settings." // {
default = true;
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
security.acme = { security.acme = {

View file

@ -1,13 +1,20 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkEnableOption mkOption mkIf; inherit (lib) mkEnableOption mkOption mkIf;
cfg = config.dgn-console; cfg = config.dgn-console;
in
in { {
options.dgn-console = { options.dgn-console = {
enable = mkEnableOption "DGNum console setup." // { default = true; }; enable = mkEnableOption "DGNum console setup." // {
default = true;
};
pg-upgrade-to = mkOption { pg-upgrade-to = mkOption {
type = lib.types.package; type = lib.types.package;
@ -18,7 +25,9 @@ in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
time.timeZone = "Europe/Paris"; time.timeZone = "Europe/Paris";
console = { keyMap = "fr"; }; console = {
keyMap = "fr";
};
environment.variables.EDITOR = "nvim"; environment.variables.EDITOR = "nvim";
@ -26,7 +35,7 @@ in {
# services.nscd.enableNsncd = false; # services.nscd.enableNsncd = false;
nixpkgs.overlays = [ nixpkgs.overlays = [
(final: prev: { (_: _: {
nsncd = pkgs.rustPlatform.buildRustPackage { nsncd = pkgs.rustPlatform.buildRustPackage {
pname = "nsncd"; pname = "nsncd";
version = "unstable-2023-10-26"; version = "unstable-2023-10-26";
@ -70,29 +79,36 @@ in {
hardware.enableRedistributableFirmware = true; hardware.enableRedistributableFirmware = true;
environment.systemPackages = (with pkgs; [ neovim wget kitty.terminfo ]) environment.systemPackages =
++ lib.optional (config.services.postgresql.enable (with pkgs; [
&& config.services.postgresql.package != cfg.pg-upgrade-to) neovim
(pkgs.writeScriptBin "upgrade-pg-cluster" '' wget
set -eux kitty.terminfo
# XXX it's perhaps advisable to stop all services that depend on postgresql ])
systemctl stop postgresql ++ lib.optional
(config.services.postgresql.enable && config.services.postgresql.package != cfg.pg-upgrade-to)
(
pkgs.writeScriptBin "upgrade-pg-cluster" ''
set -eux
# XXX it's perhaps advisable to stop all services that depend on postgresql
systemctl stop postgresql
export NEWDATA="/var/lib/postgresql/${cfg.pg-upgrade-to.psqlSchema}" export NEWDATA="/var/lib/postgresql/${cfg.pg-upgrade-to.psqlSchema}"
export NEWBIN="${cfg.pg-upgrade-to}/bin" export NEWBIN="${cfg.pg-upgrade-to}/bin"
export OLDDATA="${config.services.postgresql.dataDir}" export OLDDATA="${config.services.postgresql.dataDir}"
export OLDBIN="${config.services.postgresql.package}/bin" export OLDBIN="${config.services.postgresql.package}/bin"
install -d -m 0700 -o postgres -g postgres "$NEWDATA" install -d -m 0700 -o postgres -g postgres "$NEWDATA"
cd "$NEWDATA" cd "$NEWDATA"
sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" sudo -u postgres $NEWBIN/initdb -D "$NEWDATA"
sudo -u postgres $NEWBIN/pg_upgrade \ sudo -u postgres $NEWBIN/pg_upgrade \
--old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \
--old-bindir $OLDBIN --new-bindir $NEWBIN \ --old-bindir $OLDBIN --new-bindir $NEWBIN \
"$@" "$@"
''); ''
);
}; };
} }

View file

@ -1,10 +1,19 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) inherit (lib)
mkDefault mkEnableOption mkIf mkOption mkDefault
mkEnableOption
mkIf
mkOption
types; types
;
cfg = config.dgn-fail2ban; cfg = config.dgn-fail2ban;
@ -22,8 +31,7 @@ let
}; };
filter = mkOption { filter = mkOption {
type = type = types.nullOr (types.submodule { freeformType = configFormat.type; });
types.nullOr (types.submodule { freeformType = configFormat.type; });
description = "Content of the filter used for this jail."; description = "Content of the filter used for this jail.";
}; };
@ -36,8 +44,8 @@ let
}; };
}; };
}; };
in
in { {
options.dgn-fail2ban = { options.dgn-fail2ban = {
enable = mkEnableOption "fail2ban service."; enable = mkEnableOption "fail2ban service.";
@ -50,9 +58,9 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
dgn-fail2ban.jails = dgn-fail2ban.jails = builtins.mapAttrs (_: j: j // { enabled = mkDefault false; }) (
builtins.mapAttrs (_: j: j // { enabled = mkDefault false; }) import ./jails.nix { }
(import ./jails.nix { }); );
services.fail2ban = { services.fail2ban = {
enable = true; enable = true;

View file

@ -33,8 +33,7 @@
_: { _: {
nginx-spam = { nginx-spam = {
filter.Definition.failregex = '' filter.Definition.failregex = ''^<HOST>.*GET.*(matrix/server|\.php|admin|wp\-).* HTTP/\d.\d\" 404.*$'';
^<HOST>.*GET.*(matrix/server|\.php|admin|wp\-).* HTTP/\d.\d\" 404.*$'';
settings = { settings = {
logpath = "/var/log/nginx/access.log"; logpath = "/var/log/nginx/access.log";

View file

@ -1,11 +1,16 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
inherit (lib) mkEnableOption mkIf mkMerge; inherit (lib) mkEnableOption mkIf mkMerge;
cfg = config.dgn-hardware; cfg = config.dgn-hardware;
in
in { {
options.dgn-hardware = { options.dgn-hardware = {
enable = mkEnableOption "default hardware configuration." // { enable = mkEnableOption "default hardware configuration." // {
default = true; default = true;
@ -19,45 +24,56 @@ in {
useBcachefs = mkEnableOption "bcachefs configuration"; useBcachefs = mkEnableOption "bcachefs configuration";
}; };
config = mkIf cfg.enable (mkMerge [ config = mkIf cfg.enable (
{ mkMerge [
hardware.enableRedistributableFirmware = true; {
hardware.cpu.intel.updateMicrocode = true; hardware.enableRedistributableFirmware = true;
hardware.cpu.intel.updateMicrocode = true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
boot = { boot = {
initrd.availableKernelModules = initrd.availableKernelModules = [
[ "ata_piix" "uhci_hcd" "ehci_pci" "virtio_pci" "ahci" "virtio_blk" ]; "ata_piix"
kernelModules = [ "kvm-intel" ]; "uhci_hcd"
kernelParams = [ "ehci_pci"
"cgroup_enable=cpu" "virtio_pci"
"cgroup_enable=cpuset" "ahci"
"cgroup_enable=memory" "virtio_blk"
"cgroup_memory=1" ];
]; kernelModules = [ "kvm-intel" ];
}; kernelParams = [
} "cgroup_enable=cpu"
"cgroup_enable=cpuset"
(mkIf cfg.useSystemd { "cgroup_enable=memory"
boot.loader = { "cgroup_memory=1"
systemd-boot.enable = true; ];
efi.canTouchEfiVariables = true;
};
})
(mkIf cfg.useBcachefs { boot.supportedFilesystems = [ "bcachefs" ]; })
(mkIf cfg.useZfs {
boot = {
supportedFilesystems = [ "zfs" ];
zfs = {
forceImportRoot = false;
extraPools = [ "fast01" "work01" ];
package = pkgs.zfs_2_1;
}; };
}; }
})
]); (mkIf cfg.useSystemd {
boot.loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
})
(mkIf cfg.useBcachefs { boot.supportedFilesystems = [ "bcachefs" ]; })
(mkIf cfg.useZfs {
boot = {
supportedFilesystems = [ "zfs" ];
zfs = {
forceImportRoot = false;
extraPools = [
"fast01"
"work01"
];
package = pkgs.zfs_2_1;
};
};
})
]
);
} }

View file

@ -1,12 +1,22 @@
{ config, lib, meta, name, ... }: {
config,
lib,
meta,
name,
...
}:
let let
inherit (lib) mapAttrs' mkEnableOption mkIf optionalAttrs; inherit (lib)
mapAttrs'
mkEnableOption
mkIf
optionalAttrs
;
net = meta.network.${name}; net = meta.network.${name};
mkAddress = { address, prefixLength, ... }: mkAddress = { address, prefixLength, ... }: "${address}/${builtins.toString prefixLength}";
"${address}/${builtins.toString prefixLength}";
mkRoute = gateway: { mkRoute = gateway: {
routeConfig = { routeConfig = {
Gateway = gateway; Gateway = gateway;
@ -38,12 +48,11 @@ let
}; };
cfg = config.dgn-network; cfg = config.dgn-network;
in
in { {
options.dgn-network.enable = options.dgn-network.enable = mkEnableOption "automatic network configuration based on metadata" // {
mkEnableOption "automatic network configuration based on metadata" // { default = true;
default = true; };
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
networking = { networking = {

View file

@ -1,14 +1,14 @@
{ config, lib, ... }: { config, lib, ... }:
let let
inherit (lib) inherit (lib) mkEnableOption mkIf;
mkEnableOption
mkIf;
cfg = config.dgn-vmVariant; cfg = config.dgn-vmVariant;
in in
{ {
options.dgn-vmVariant.enable = mkEnableOption "ACME settings." // { default = true; }; options.dgn-vmVariant.enable = mkEnableOption "ACME settings." // {
default = true;
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
virtualisation.vmVariant = { virtualisation.vmVariant = {
@ -16,4 +16,3 @@ in
}; };
}; };
} }

View file

@ -4,7 +4,8 @@ let
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
cfg = config.dgn-web; cfg = config.dgn-web;
in { in
{
options.dgn-web = { options.dgn-web = {
enable = mkEnableOption "sane defaults for web services."; enable = mkEnableOption "sane defaults for web services.";
}; };
@ -21,6 +22,9 @@ in {
recommendedZstdSettings = true; recommendedZstdSettings = true;
}; };
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [
80
443
];
}; };
} }

View file

@ -1,20 +1,34 @@
# Generated by npins. Do not modify; will be overwritten regularly # Generated by npins. Do not modify; will be overwritten regularly
let let
data = builtins.fromJSON (builtins.readFile ./sources.json); data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version; inherit (data) version;
mkSource = spec: mkSource =
assert spec ? type; let spec:
assert spec ? type;
let
path = path =
if spec.type == "Git" then mkGitSource spec if spec.type == "Git" then
else if spec.type == "GitRelease" then mkGitSource spec mkGitSource spec
else if spec.type == "PyPi" then mkPyPiSource spec else if spec.type == "GitRelease" then
else if spec.type == "Channel" then mkChannelSource spec mkGitSource spec
else builtins.throw "Unknown source type ${spec.type}"; else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in in
spec // { outPath = path; }; spec // { outPath = path; };
mkGitSource = { repository, revision, url ? null, hash, ... }: mkGitSource =
{
repository,
revision,
url ? null,
hash,
...
}:
assert repository ? type; assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball # In the latter case, there we will always be an url to the tarball
@ -23,19 +37,23 @@ let
inherit url; inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes sha256 = hash; # FIXME: check nix version & use SRI hashes
}) })
else assert repository.type == "Git"; builtins.fetchGit { else
url = repository.url; assert repository.type == "Git";
rev = revision; builtins.fetchGit {
# hash = hash; inherit (repository) url;
}; rev = revision;
# hash = hash;
};
mkPyPiSource = { url, hash, ... }: mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl { builtins.fetchurl {
inherit url; inherit url;
sha256 = hash; sha256 = hash;
}; };
mkChannelSource = { url, hash, ... }: mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball { builtins.fetchTarball {
inherit url; inherit url;
sha256 = hash; sha256 = hash;

View file

@ -118,6 +118,18 @@
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.05pre578430.5ad9903c1612/nixexprs.tar.xz", "url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.05pre578430.5ad9903c1612/nixexprs.tar.xz",
"hash": "1zg01pxmaf56gqxdf59mj1aanlvkpw5b3gmsx4mawxi6m1f2l6c6" "hash": "1zg01pxmaf56gqxdf59mj1aanlvkpw5b3gmsx4mawxi6m1f2l6c6"
}, },
"pre-commit-hooks": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "cachix",
"repo": "pre-commit-hooks.nix"
},
"branch": "master",
"revision": "7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf",
"url": "https://github.com/cachix/pre-commit-hooks.nix/archive/7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf.tar.gz",
"hash": "0gj03fzsqcybzr4shj7x62l0xc34w20zhphd2jg7sd2rxaw42x23"
},
"wp4nix": { "wp4nix": {
"type": "Git", "type": "Git",
"repository": { "repository": {
@ -132,4 +144,4 @@
} }
}, },
"version": 3 "version": 3
} }

View file

@ -8,19 +8,25 @@ let
coreutils coreutils
nvd nvd
git git
jq; jq
;
}; };
mkShellScript = name: (pkgs.substituteAll ({ mkShellScript =
inherit name; name:
src = ./. + "/${name}.sh"; (pkgs.substituteAll (
dir = "/bin/"; {
isExecutable = true; inherit name;
src = ./. + "/${name}.sh";
dir = "/bin/";
isExecutable = true;
checkPhase = '' checkPhase = ''
${pkgs.stdenv.shellDryRun} "$target" ${pkgs.stdenv.shellDryRun} "$target"
''; '';
} // substitutions)); }
// substitutions
));
scripts = [ scripts = [
"check-deployment" "check-deployment"

View file

@ -1,52 +1 @@
/* (import ./.).shells.default
Copyright :
- Maurice Debray <maurice.debray@dgnum.eu> 2023
- Tom Hubrecht <tom.hubrecht@dgnum.eu> 2023
Ce logiciel est un programme informatique servant à déployer des
configurations de serveurs via NixOS.
Ce logiciel est régi par la licence CeCILL soumise au droit français et
respectant les principes de diffusion des logiciels libres. Vous pouvez
utiliser, modifier et/ou redistribuer ce programme sous les conditions
de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
sur le site "http://www.cecill.info".
En contrepartie de l'accessibilité au code source et des droits de copie,
de modification et de redistribution accordés par cette licence, il n'est
offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
seule une responsabilité restreinte pèse sur l'auteur du programme, le
titulaire des droits patrimoniaux et les concédants successifs.
A cet égard l'attention de l'utilisateur est attirée sur les risques
associés au chargement, à l'utilisation, à la modification et/ou au
développement et à la reproduction du logiciel par l'utilisateur étant
donné sa spécificité de logiciel libre, qui peut le rendre complexe à
manipuler et qui le réserve donc à des développeurs et des professionnels
avertis possédant des connaissances informatiques approfondies. Les
utilisateurs sont donc invités à charger et tester l'adéquation du
logiciel à leurs besoins dans des conditions permettant d'assurer la
sécurité de leurs systèmes et ou de leurs données et, plus généralement,
à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
pris connaissance de la licence CeCILL, et que vous en avez accepté les
termes.
*/
let
sources = import ./npins;
pkgs = import sources.nixpkgs { };
in
pkgs.mkShell {
packages = (with pkgs; [
npins
colmena
nixos-generators
] ++ (builtins.map (p: callPackage p { }) [
(sources.disko + "/package.nix")
])) ++ (import ./scripts { inherit pkgs; });
preferLocalBuild = true;
}