nixos/docuseal: init

This commit is contained in:
Felix Buehler 2023-10-24 23:33:27 +02:00
parent c70a1e268d
commit cf594a3b83
5 changed files with 271 additions and 0 deletions

View file

@ -1567,6 +1567,7 @@
./services/web-apps/dex.nix
./services/web-apps/discourse.nix
./services/web-apps/documize.nix
./services/web-apps/docuseal.nix
./services/web-apps/dokuwiki.nix
./services/web-apps/dolibarr.nix
./services/web-apps/drupal.nix

View file

@ -0,0 +1,196 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.docuseal;
env = {
RAILS_ENV = "production";
NODE_ENV = "production";
WORKDIR = "/var/lib/docuseal";
PORT = toString (cfg.port);
HOST = cfg.host;
REDIS_URL = "redis://${cfg.redis.host}:${toString cfg.redis.port}";
}
// cfg.extraConfig;
in
{
options.services.docuseal = {
enable = lib.mkEnableOption "DocuSeal, open source document signing";
package = lib.mkPackageOption pkgs "docuseal" { };
secretKeyBaseFile = lib.mkOption {
description = ''
Path to file containing the secret key base.
A new secret key base can be generated by running:
`openssl rand -hex 64`
If this file does not exist, it will be created with a new secret key base.
'';
default = "/var/lib/docuseal/secrets/secret-key-base";
type = lib.types.path;
};
host = lib.mkOption {
description = "DocuSeal host.";
type = lib.types.str;
default = "127.0.0.1";
};
port = lib.mkOption {
description = "DocuSeal port.";
type = lib.types.port;
default = 3000;
};
extraConfig = lib.mkOption {
type = lib.types.attrs;
default = { };
description = ''
Extra environment variables to pass to DocuSeal services.
'';
};
extraEnvFiles = lib.mkOption {
type = with lib.types; listOf path;
default = [ ];
description = ''
Extra environment files to pass to DocuSeal services. Useful for passing down environmental secrets.
e.g. DATABASE_URL
'';
example = [ "/etc/docuseal/s3config.env" ];
};
redis = {
createLocally = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to create a local redis automatically.";
};
name = lib.mkOption {
type = lib.types.str;
default = "docuseal";
description = ''
Name of the redis server. Only used if `createLocally` is set to true.
'';
};
host = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = ''
Redis server address.
'';
};
port = lib.mkOption {
type = lib.types.port;
default = 6379;
description = "Port of the redis server.";
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.redis.createLocally -> cfg.redis.host == "localhost";
message = "the redis host must be localhost if services.docuseal.redis.createLocally is set to true";
}
];
systemd.services.docuseal = {
description = "DocuSeal server";
wantedBy = [ "multi-user.target" ];
environment = env;
serviceConfig = {
Type = "simple";
ExecStartPre = pkgs.writeShellScript "docuseal-pre-script" ''
cat > /var/lib/docuseal/docuseal.env <<EOF
SECRET_KEY_BASE="$(cat ${cfg.secretKeyBaseFile})"
EOF
'';
ExecStart = "${cfg.package}/bin/rails server --pid=/var/lib/docuseal/docuseal.pids";
Restart = "always";
EnvironmentFile = [ "docuseal.env" ] ++ cfg.extraEnvFiles;
# Runtime directory and mode
RuntimeDirectory = "docuseal";
RuntimeDirectoryMode = "0750";
# System Call Filtering
SystemCallFilter = [
"@system-service"
"~@privileged"
];
# User and group
DynamicUser = true;
# Working directory
WorkingDirectory = "/var/lib/docuseal";
# State directory and mode
StateDirectory = "docuseal";
StateDirectoryMode = "0750";
# Logs directory and mode
LogsDirectory = "docuseal";
LogsDirectoryMode = "0750";
# Proc filesystem
ProcSubset = "pid";
ProtectProc = "invisible";
# Access write directories
UMask = "0027";
# Capabilities
CapabilityBoundingSet = "";
# Security
NoNewPrivileges = true;
# Sandboxing
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = (cfg.port >= 1024);
ProtectClock = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = false;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
}
// lib.optionalAttrs (cfg.port < 1024) {
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
};
};
services.redis = lib.optionalAttrs cfg.redis.createLocally {
servers."${cfg.redis.name}" = {
enable = true;
port = cfg.redis.port;
};
};
};
meta.maintainers = with lib.maintainers; [ stunkymonkey ];
}

View file

@ -465,6 +465,8 @@ in
docling-serve = runTest ./docling-serve.nix;
documentation = pkgs.callPackage ../modules/misc/documentation/test.nix { inherit nixosLib; };
documize = runTest ./documize.nix;
docuseal-psql = runTest ./docuseal-postgres.nix;
docuseal-sqlite = runTest ./docuseal-sqlite.nix;
doh-proxy-rust = runTest ./doh-proxy-rust.nix;
dokuwiki = runTest ./dokuwiki.nix;
dolibarr = runTest ./dolibarr.nix;

View file

@ -0,0 +1,46 @@
{ lib, ... }:
{
name = "docuseal";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
nodes.machine =
{ pkgs, ... }:
{
services.docuseal = {
enable = true;
port = 80;
secretKeyBaseFile = pkgs.writeText "secret" "23bec595a1658d136d532af1365b40024b662c0862e9cdf14fd22c0afaeb0dd6322b114fa35bd82e564bae44a896b5abef3a66afd61e1382b8ebd579e2c5c17f";
extraConfig.DATABASEURL = "postgresql://docuseal:db-secret@127.0.0.1:5432/docuseal";
};
services.postgresql = {
package = pkgs.postgresql;
enable = true;
ensureDatabases = [ "docuseal" ];
ensureUsers = [
{
name = "docuseal";
ensureDBOwnership = true;
}
];
initialScript = pkgs.writeText "postgresql-password" ''
CREATE ROLE docuseal WITH LOGIN PASSWORD 'db-secret' CREATEDB;
'';
};
systemd.services."docuseal-config" = {
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("docuseal.service")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: docuseal' http://127.0.0.1:80/setup")
assert "<title>\n DocuSeal | Open Source Document Signing\n</title>" in response, "page didn't load successfully"
'';
}

View file

@ -0,0 +1,26 @@
{ lib, ... }:
{
name = "docuseal";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
nodes.machine =
{ pkgs, ... }:
{
services.docuseal = {
enable = true;
port = 80;
secretKeyBaseFile = pkgs.writeText "secret" "23bec595a1658d136d532af1365b40024b662c0862e9cdf14fd22c0afaeb0dd6322b114fa35bd82e564bae44a896b5abef3a66afd61e1382b8ebd579e2c5c17f";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("docuseal.service")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: docuseal' http://127.0.0.1:80/setup")
assert "<title>\n DocuSeal | Open Source Document Signing\n</title>" in response, "page didn't load successfully"
'';
}