2024-02-02 10:51:31 +01:00
|
|
|
{
|
|
|
|
config,
|
|
|
|
lib,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
2023-09-27 22:33:18 +02:00
|
|
|
|
|
|
|
let
|
2024-02-02 10:51:31 +01:00
|
|
|
inherit (lib)
|
|
|
|
mkDefault
|
|
|
|
mkEnableOption
|
|
|
|
mkIf
|
|
|
|
mkOption
|
|
|
|
types
|
|
|
|
;
|
2023-09-27 22:33:18 +02:00
|
|
|
|
|
|
|
yamlFormat = pkgs.formats.yaml { };
|
|
|
|
|
|
|
|
configFile = yamlFormat.generate "proxy_conf.yaml" cfg.proxyConf;
|
|
|
|
|
|
|
|
cfg = config.services.satosa;
|
|
|
|
|
2024-02-02 10:51:31 +01:00
|
|
|
mkYamlFiles =
|
|
|
|
files: builtins.attrValues (builtins.mapAttrs (name: yamlFormat.generate "${name}.yaml") files);
|
|
|
|
|
|
|
|
pyEnv = cfg.package.python.withPackages (
|
|
|
|
ps: [
|
|
|
|
cfg.package
|
|
|
|
ps.gunicorn
|
|
|
|
]
|
|
|
|
);
|
|
|
|
in
|
|
|
|
{
|
2023-09-27 22:33:18 +02:00
|
|
|
options.services.satosa = {
|
|
|
|
enable = mkEnableOption "SATOSA, a SAML and OIDC proxy.";
|
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
type = types.package;
|
2023-12-12 14:45:01 +01:00
|
|
|
default = import ./package { inherit pkgs; };
|
2023-09-27 22:33:18 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
|
|
|
type = types.port;
|
|
|
|
default = 8080;
|
|
|
|
};
|
|
|
|
|
|
|
|
host = mkOption { type = types.str; };
|
|
|
|
|
|
|
|
workers = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
configureNginx = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
proxyConf = mkOption {
|
|
|
|
inherit (yamlFormat) type;
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
|
|
|
|
envFile = mkOption {
|
|
|
|
type = with types; nullOr path;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
internalAttributes = mkOption {
|
|
|
|
inherit (yamlFormat) type;
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
|
|
|
|
frontendModules = mkOption {
|
|
|
|
type = types.attrsOf yamlFormat.type;
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
|
|
|
|
backendModules = mkOption {
|
|
|
|
type = types.attrsOf yamlFormat.type;
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
|
|
|
|
microServices = mkOption {
|
|
|
|
type = types.attrsOf yamlFormat.type;
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services.satosa.proxyConf = builtins.mapAttrs (_: mkDefault) {
|
|
|
|
BASE = "https://${cfg.host}";
|
|
|
|
COOKIE_STATE_NAME = "satosa_state";
|
|
|
|
COOKIE_SECURE = true;
|
|
|
|
COOKIE_HTTPONLY = true;
|
|
|
|
COOKIE_SAMESITE = "None";
|
|
|
|
COOKIE_MAX_AGE = "1200";
|
|
|
|
CONTEXT_STATE_DELETE = true;
|
|
|
|
INTERNAL_ATTRIBUTES = yamlFormat.generate "internal_attributes.yaml" {
|
|
|
|
attributes = cfg.internalAttributes;
|
|
|
|
};
|
|
|
|
BACKEND_MODULES = mkYamlFiles cfg.backendModules;
|
|
|
|
FRONTEND_MODULES = mkYamlFiles cfg.frontendModules;
|
|
|
|
MICRO_SERVICES = mkYamlFiles cfg.microServices;
|
|
|
|
LOGGING = {
|
|
|
|
version = 1;
|
2024-02-02 10:51:31 +01:00
|
|
|
formatters.simple.format = "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s";
|
2023-09-27 22:33:18 +02:00
|
|
|
handlers.stdout = {
|
|
|
|
class = "logging.StreamHandler";
|
|
|
|
stream = "ext://sys.stdout";
|
|
|
|
level = "DEBUG";
|
|
|
|
formatter = "simple";
|
|
|
|
};
|
|
|
|
loggers = {
|
|
|
|
satosa.level = "DEBUG";
|
|
|
|
saml2.level = "DEBUG";
|
|
|
|
oidcendpoint.level = "DEBUG";
|
|
|
|
pyop.level = "DEBUG";
|
|
|
|
oic.level = "DEBUG";
|
|
|
|
root = {
|
|
|
|
level = "DEBUG";
|
|
|
|
handlers = [ "stdout" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services = {
|
|
|
|
satosa-metadata = {
|
|
|
|
script = ''
|
|
|
|
umask 077
|
|
|
|
|
|
|
|
# Generate a secret key/certificate if none are present
|
|
|
|
mkdir -p ssl
|
|
|
|
if [ ! -f "ssl/.created" ]; then
|
|
|
|
${pkgs.openssl}/bin/openssl req -x509 \
|
|
|
|
-newkey rsa:2048 \
|
|
|
|
-keyout ssl/key.pem \
|
|
|
|
-out ssl/cert.pem \
|
|
|
|
-sha256 \
|
|
|
|
-days 3650 \
|
|
|
|
-nodes \
|
|
|
|
-subj "/C=FR/ST=Île de France/L=Paris/O=DGNum/OU=./CN=saml-idp.dgnum.eu" \
|
|
|
|
&& touch ssl/.created
|
|
|
|
fi
|
|
|
|
|
|
|
|
mkdir -p metadata
|
|
|
|
|
|
|
|
${cfg.package}/bin/satosa-saml-metadata \
|
|
|
|
--dir metadata \
|
|
|
|
--sign ${configFile} ssl/key.pem ssl/cert.pem
|
|
|
|
'';
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
User = "satosa";
|
|
|
|
Group = "satosa";
|
|
|
|
DynamicUser = true;
|
|
|
|
StateDirectory = "satosa";
|
|
|
|
WorkingDirectory = "/var/lib/satosa";
|
|
|
|
EnvironmentFile = lib.optional (cfg.envFile != null) cfg.envFile;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
satosa = {
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
after = [ "network.target" ];
|
|
|
|
wants = [ "satosa-metadata.service" ];
|
|
|
|
serviceConfig = {
|
|
|
|
User = "satosa";
|
|
|
|
Group = "satosa";
|
|
|
|
DynamicUser = true;
|
|
|
|
Type = "notify";
|
|
|
|
RuntimeDirectory = "satosa";
|
|
|
|
StateDirectory = "satosa";
|
|
|
|
WorkingDirectory = cfg.package;
|
|
|
|
ExecStart = ''
|
|
|
|
${pyEnv}/bin/gunicorn \
|
|
|
|
-w ${builtins.toString cfg.workers} \
|
|
|
|
-b 127.0.0.1:${builtins.toString cfg.port} \
|
|
|
|
--pythonpath ${pyEnv}/${pkgs.python3.sitePackages} \
|
|
|
|
satosa.wsgi:app
|
|
|
|
'';
|
|
|
|
ExecReload = "${pkgs.util-linux}/bin/kill -s HUP $MAINPID";
|
|
|
|
KillMode = "mixed";
|
|
|
|
TimeoutStopSec = "5";
|
|
|
|
EnvironmentFile = lib.optional (cfg.envFile != null) cfg.envFile;
|
|
|
|
};
|
2024-02-02 10:51:31 +01:00
|
|
|
environment = {
|
|
|
|
SATOSA_CONFIG = configFile;
|
|
|
|
};
|
2023-09-27 22:33:18 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.nginx = mkIf cfg.configureNginx {
|
|
|
|
enable = true;
|
|
|
|
|
|
|
|
virtualHosts.${cfg.host} = {
|
2024-02-02 10:51:31 +01:00
|
|
|
locations."/".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}";
|
2023-09-27 22:33:18 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
users.users.satosa = {
|
|
|
|
isSystemUser = true;
|
|
|
|
group = "satosa";
|
|
|
|
home = "/var/lib/satosa";
|
|
|
|
};
|
|
|
|
users.groups.satosa = { };
|
|
|
|
};
|
|
|
|
}
|