Tom Hubrecht
f8df18f13c
All checks were successful
Build all the nodes / ap01 (push) Successful in 1m18s
Build all the nodes / bridge01 (push) Successful in 1m58s
Build all the nodes / geo01 (push) Successful in 2m2s
Build all the nodes / geo02 (push) Successful in 2m9s
Build all the nodes / hypervisor01 (push) Successful in 1m29s
Build all the nodes / netcore02 (push) Successful in 37s
Build all the nodes / hypervisor03 (push) Successful in 1m36s
Build all the nodes / hypervisor02 (push) Successful in 1m41s
Build all the nodes / storage01 (push) Successful in 2m8s
Build all the nodes / rescue01 (push) Successful in 2m10s
Build all the nodes / vault01 (push) Successful in 2m7s
Build all the nodes / web01 (push) Successful in 2m28s
Run pre-commit on all files / pre-commit (push) Successful in 42s
Build all the nodes / web02 (push) Successful in 1m44s
Build all the nodes / web03 (push) Successful in 1m46s
Build all the nodes / compute01 (push) Successful in 9m44s
459 lines
14 KiB
Nix
459 lines
14 KiB
Nix
# SPDX-FileCopyrightText: 2023-2024 Tom Hubrecht <tom.hubrecht@dgnum.eu>
|
|
#
|
|
# SPDX-License-Identifier: EUPL-1.2
|
|
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
utils,
|
|
...
|
|
}:
|
|
|
|
let
|
|
inherit (lib)
|
|
getExe
|
|
getExe'
|
|
mapAttrs
|
|
mkDefault
|
|
mkEnableOption
|
|
mkIf
|
|
mkOption
|
|
mkPackageOption
|
|
optional
|
|
;
|
|
|
|
inherit (lib.types)
|
|
attrsOf
|
|
nullOr
|
|
oneOf
|
|
package
|
|
path
|
|
port
|
|
str
|
|
;
|
|
|
|
inherit (utils) escapeSystemdExecArgs;
|
|
|
|
cfg = config.services.demarches-simplifiees;
|
|
|
|
weasyprintEnv = pkgs.python3.withPackages (ps: [
|
|
ps.flask
|
|
ps.sentry-sdk
|
|
ps.weasyprint
|
|
]);
|
|
in
|
|
{
|
|
options.services.demarches-simplifiees = {
|
|
enable = mkEnableOption "Démarches Simplifiées";
|
|
|
|
package = mkPackageOption pkgs "demarches-simplifiees" { };
|
|
|
|
finalPackage = mkOption {
|
|
type = package;
|
|
default = cfg.package.override { inherit (cfg) initialDeploymentDate; };
|
|
};
|
|
|
|
host = mkOption {
|
|
type = str;
|
|
description = ''
|
|
Hostname of the web server.
|
|
'';
|
|
};
|
|
|
|
port = mkOption {
|
|
type = port;
|
|
default = 3000;
|
|
description = ''
|
|
Listening port for the web server.
|
|
'';
|
|
};
|
|
|
|
weasyprintPort = mkOption {
|
|
type = port;
|
|
default = 5000;
|
|
description = ''
|
|
Port of the weasyprint server.
|
|
'';
|
|
};
|
|
|
|
environment = mkOption {
|
|
type = attrsOf (
|
|
nullOr (oneOf [
|
|
package
|
|
path
|
|
str
|
|
])
|
|
);
|
|
description = ''
|
|
Evironment variables available to Démarches Simplifiées.
|
|
'';
|
|
};
|
|
|
|
environmentFile = mkOption {
|
|
type = nullOr path;
|
|
default = null;
|
|
description = ''
|
|
Path to a file containing environment variables.
|
|
Required secrets are `SECRET_KEY_BASE` and `OTP_SECRET_KEY`,
|
|
which can be generated using `rails secret`.
|
|
'';
|
|
};
|
|
|
|
initialDeploymentDate = mkOption {
|
|
type = nullOr str;
|
|
default = null;
|
|
description = ''
|
|
Initial deployment date, used to ignore some migrations,
|
|
which are known to be buggy and are supposed to change old production data.
|
|
'';
|
|
};
|
|
|
|
interactScript = mkOption {
|
|
type = package;
|
|
default = pkgs.writeShellApplication {
|
|
name = "ds-fr";
|
|
|
|
runtimeInputs = [
|
|
cfg.finalPackage
|
|
config.systemd.package
|
|
pkgs.util-linux
|
|
];
|
|
text = ''
|
|
MainPID=$(systemctl show -p MainPID --value demarches-simplifiees.service)
|
|
|
|
nsenter -e -a -w -t "$MainPID" -G follow -S follow "$@"
|
|
'';
|
|
};
|
|
description = ''
|
|
Script to run ds-fr tasks.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
environment.systemPackages = [ cfg.interactScript ];
|
|
|
|
systemd.services =
|
|
let
|
|
serviceConfig = {
|
|
User = "ds-fr";
|
|
DynamicUser = true;
|
|
EnvironmentFile = optional (cfg.environmentFile != null) cfg.environmentFile;
|
|
CacheDirectory = "demarches-simplifiees";
|
|
LogsDirectory = "demarches-simplifiees";
|
|
RuntimeDirectory = "demarches-simplifiees";
|
|
StateDirectory = "demarches-simplifiees";
|
|
WorkingDirectory = cfg.finalPackage;
|
|
};
|
|
in
|
|
{
|
|
demarches-simplifiees = {
|
|
description = "Démarches Simplifiées";
|
|
|
|
inherit (cfg) environment;
|
|
|
|
path = [
|
|
cfg.finalPackage
|
|
pkgs.imagemagick
|
|
];
|
|
|
|
after = [
|
|
"network.target"
|
|
"postgresql.target"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
preStart = ''
|
|
mkdir -p "$STATE_DIRECTORY/storage"
|
|
|
|
if [[ ! -f "$STATE_DIRECTORY/.version" ]]; then
|
|
# Run initial setup
|
|
rails db:environment:set
|
|
rails db:schema:load
|
|
rails db:seed
|
|
rails jobs:schedule
|
|
touch "$STATE_DIRECTORY/.version"
|
|
fi
|
|
|
|
if [[ $(cat "$STATE_DIRECTORY/.version") != "$__DS_VERSION" ]]; then
|
|
# Run migrations on version change
|
|
rake db:migrate
|
|
rake after_party:run
|
|
echo "$__DS_VERSION" > "$STATE_DIRECTORY/.version"
|
|
fi
|
|
'';
|
|
|
|
serviceConfig = serviceConfig // {
|
|
ExecStart = escapeSystemdExecArgs [
|
|
(getExe' cfg.finalPackage "rails")
|
|
"server"
|
|
"-b"
|
|
"127.0.0.1"
|
|
"-p"
|
|
cfg.port
|
|
];
|
|
};
|
|
};
|
|
|
|
demarches-simplifiees-work = {
|
|
description = "Démarches Simplifiées work service";
|
|
|
|
inherit (cfg) environment;
|
|
|
|
after = [ "demarches-simplifiees.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
bindsTo = [ "demarches-simplifiees.service" ];
|
|
partOf = [ "demarches-simplifiees.service" ];
|
|
|
|
serviceConfig = serviceConfig // {
|
|
ExecStart = escapeSystemdExecArgs [
|
|
(getExe' cfg.finalPackage "rails")
|
|
"jobs:work"
|
|
];
|
|
};
|
|
};
|
|
|
|
weasyprint-server = {
|
|
description = "Weasyprint server";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
environment = {
|
|
BASE_URL = "https://${cfg.host}";
|
|
LOG_DIR = "/var/log/weasyprint";
|
|
UWSGI_PYTHONPATH = weasyprintEnv;
|
|
UWSGI_MODULE = "wgsi:app";
|
|
};
|
|
|
|
serviceConfig = {
|
|
DynamicUser = true;
|
|
Type = "notify";
|
|
WorkingDirectory = cfg.finalPackage.weasyprint_server;
|
|
LogsDirectory = "weasyprint";
|
|
ExecStart = escapeSystemdExecArgs [
|
|
(getExe (pkgs.uwsgi.override { plugins = [ "python3" ]; }))
|
|
"--http-socket"
|
|
"127.0.0.1:${builtins.toString cfg.weasyprintPort}"
|
|
"--processes=4"
|
|
"--enable-threads"
|
|
];
|
|
NotifyAccess = "all";
|
|
KillSignal = "SIGQUIT";
|
|
ExecReload = "${getExe' pkgs.coreutils "kill"} -HUP $MainPID";
|
|
ExecStop = "${getExe' pkgs.coreutils "kill"} -INT $MainPID";
|
|
|
|
ProtectSystem = "full";
|
|
ProtectHome = true;
|
|
NoNewPrivileges = true;
|
|
PrivateDevices = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
services = {
|
|
demarches-simplifiees.environment =
|
|
# Hardcoded values
|
|
{
|
|
# Application host name
|
|
#
|
|
# Examples:
|
|
# * For local development: localhost:3000
|
|
# * For preproduction: staging.ds.example.org
|
|
# * For production: ds.example.org
|
|
APP_HOST = cfg.host;
|
|
|
|
# Database credentials
|
|
DB_DATABASE = "ds-fr";
|
|
DB_USERNAME = "ds-fr";
|
|
DB_HOST = "/run/postgresql";
|
|
DB_PORT = "5432";
|
|
|
|
# The variables must be present even if empty...
|
|
DB_PASSWORD = "";
|
|
DB_POOL = "";
|
|
|
|
# Jobs configuration
|
|
RAILS_QUEUE_ADAPTER = "delayed_job";
|
|
|
|
# Log on stdout
|
|
RAILS_LOG_TO_STDOUT = "true";
|
|
|
|
# Package version
|
|
__DS_VERSION = cfg.finalPackage.version;
|
|
|
|
# Weasyprint endpoint generating attestations v2
|
|
# See https://github.com/demarches-simplifiees/weasyprint_server
|
|
WEASYPRINT_URL = "http://127.0.0.1:${builtins.toString cfg.weasyprintPort}/pdf";
|
|
}
|
|
// (mapAttrs (_: mkDefault) {
|
|
RAILS_ENV = "production";
|
|
RAILS_ROOT = builtins.toString cfg.finalPackage;
|
|
|
|
# Rails key for signing sensitive data
|
|
# See https://guides.rubyonrails.org/security.html
|
|
#
|
|
# 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.
|
|
|
|
# Secret key for One-Time-Password codes, used for 2-factors authentication
|
|
# OTP_SECRET_KEY = "";
|
|
|
|
# Protect access to the instance with a static login/password (useful for staging environments)
|
|
BASIC_AUTH_ENABLED = "disabled";
|
|
BASIC_AUTH_USERNAME = "";
|
|
BASIC_AUTH_PASSWORD = "";
|
|
|
|
# ActiveStorage service to use for attached files.
|
|
# Possible values:
|
|
# - "local": store files on the local filesystem
|
|
# - "amazon": store files remotely on an S3 storage service
|
|
# - "openstack": store files remotely on an OpenStack storage service
|
|
#
|
|
# (See config/storage.yml for the configuration of each service.)
|
|
ACTIVE_STORAGE_SERVICE = "local";
|
|
|
|
# Configuration for the OpenStack storage service (if enabled)
|
|
FOG_OPENSTACK_API_KEY = "";
|
|
FOG_OPENSTACK_USERNAME = "";
|
|
FOG_OPENSTACK_URL = "";
|
|
FOG_OPENSTACK_REGION = "";
|
|
DS_PROXY_URL = "";
|
|
|
|
# SAML
|
|
SAML_IDP_ENABLED = "disabled";
|
|
|
|
# External service: integration with HelpScout (optional)
|
|
HELPSCOUT_MAILBOX_ID = "";
|
|
HELPSCOUT_CLIENT_ID = "";
|
|
HELPSCOUT_CLIENT_SECRET = "";
|
|
HELPSCOUT_WEBHOOK_SECRET = "";
|
|
|
|
# External service: external supervision
|
|
SENTRY_ENABLED = "disabled";
|
|
SENTRY_CURRENT_ENV = "development";
|
|
SENTRY_DSN_RAILS = "";
|
|
SENTRY_DSN_JS = "";
|
|
|
|
# External service: Matomo web analytics
|
|
MATOMO_ENABLED = "disabled";
|
|
MATOMO_COOKIE_DOMAIN = "*.www.demarches-simplifiees.fr";
|
|
MATOMO_DOMAIN = "*.www.demarches-simplifiees.fr";
|
|
MATOMO_ID = "";
|
|
MATOMO_HOST = "matomo.example.org";
|
|
|
|
# Default SMTP Provider: Mailjet
|
|
MAILJET_API_KEY = "";
|
|
MAILJET_SECRET_KEY = "";
|
|
|
|
# Alternate SMTP Provider: SendInBlue/DoList
|
|
SENDINBLUE_CLIENT_KEY = "";
|
|
SENDINBLUE_SMTP_KEY = "";
|
|
SENDINBLUE_USER_NAME = "";
|
|
# SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc"
|
|
|
|
# Alternate SMTP Provider: Mailtrap (mail catcher for staging environments)
|
|
# When enabled, all emails will be sent using this provider
|
|
MAILTRAP_ENABLED = "disabled";
|
|
MAILTRAP_USERNAME = "";
|
|
MAILTRAP_PASSWORD = "";
|
|
|
|
# Alternative SMTP Provider: Mailcatcher (Catches mail and serves it through a dream.)
|
|
# When enabled, all emails will be sent using this provider
|
|
MAILCATCHER_ENABLED = "disabled";
|
|
MAILCATCHER_HOST = "";
|
|
MAILCATCHER_PORT = "";
|
|
|
|
# External service: live chat for admins (specific to démarches-simplifiées.fr)
|
|
CRISP_ENABLED = "disabled";
|
|
CRISP_CLIENT_KEY = "";
|
|
|
|
# API Entreprise credentials
|
|
# https://api.gouv.fr/api/api-entreprise.html
|
|
API_ENTREPRISE_KEY = "";
|
|
|
|
# Networks bypassing the email login token that verifies new devices, and rack-attack throttling
|
|
TRUSTED_NETWORKS = "";
|
|
|
|
# External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr)
|
|
SKYLIGHT_AUTHENTICATION_KEY = "";
|
|
# "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0";
|
|
|
|
# Enable or disable Lograge logs
|
|
LOGRAGE_ENABLED = "enabled";
|
|
|
|
# Logs source for Lograge
|
|
#
|
|
# Examples:
|
|
# * For local development: tps_local
|
|
# * For preproduction: tps_staging
|
|
# * For production: tps_prod
|
|
LOGRAGE_SOURCE = "tps_prod";
|
|
|
|
# External service: timestamping a daily archive of dossiers status changes
|
|
UNIVERSIGN_API_URL = "https://ws.universign.eu/tsa/post/";
|
|
UNIVERSIGN_USERPWD = "";
|
|
|
|
# External service: API Geo / Adresse
|
|
API_ADRESSE_URL = "https://api-adresse.data.gouv.fr";
|
|
API_GEO_URL = "https://geo.api.gouv.fr";
|
|
|
|
# External service: API Education
|
|
API_EDUCATION_URL = "https://data.education.gouv.fr/api/records/1.0";
|
|
|
|
# Encryption key for sensitive columns in the database
|
|
ENCRYPTION_SERVICE_SALT = "";
|
|
|
|
# ActiveRecord encryption keys. Generate them with bin/rails db:encryption:init (you can omit deterministic_key)
|
|
AR_ENCRYPTION_PRIMARY_KEY = "";
|
|
AR_ENCRYPTION_KEY_DERIVATION_SALT = "";
|
|
|
|
# Salt for invisible_captcha session data.
|
|
# Must be the same value for all app instances behind a load-balancer.
|
|
INVISIBLE_CAPTCHA_SECRET = "kikooloool";
|
|
|
|
# Clamav antivirus usage
|
|
CLAMAV_ENABLED = "disabled";
|
|
|
|
# Siret number used for API Entreprise, by default we use SIRET from dinum
|
|
API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret";
|
|
|
|
# Date from which email validation requires a TLD in email adresses.
|
|
# This change had been introduced by : cc53946d221d6f64c365ad6c6c4c544802eb94b4
|
|
# Records (users, …) created before this date won't be affected. See #9978
|
|
# To set a date, we recommend using *the day after* you have deployed this commit,
|
|
# so existing records won't be invalid.
|
|
STRICT_EMAIL_VALIDATION_STARTS_ON = "2024-02-19";
|
|
});
|
|
|
|
postgresql = {
|
|
enable = true;
|
|
|
|
ensureDatabases = [ "ds-fr" ];
|
|
|
|
ensureUsers = [
|
|
{
|
|
name = "ds-fr";
|
|
ensureDBOwnership = true;
|
|
}
|
|
];
|
|
|
|
extensions = [ config.services.postgresql.package.pkgs.postgis ];
|
|
};
|
|
|
|
nginx = {
|
|
enable = true;
|
|
|
|
virtualHosts.${cfg.host} = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
root = "${cfg.finalPackage}/public/";
|
|
|
|
locations."/".tryFiles = "$uri @proxy";
|
|
locations."@proxy".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|