Compare commits
71 commits
a94ec1eab8
...
df66ad3870
Author | SHA1 | Date | |
---|---|---|---|
Rouven Seifert | df66ad3870 | ||
Rouven Seifert | 05152b6db4 | ||
Rouven Seifert | 6a8559fb33 | ||
66519d8196 | |||
1c8fe9ec66 | |||
68138c0a31 | |||
c7f3120c9d | |||
616b3c64f7 | |||
bb697f3a50 | |||
b34c53ddf8 | |||
c8afe48290 | |||
16f8ec19f9 | |||
7f00d6746a | |||
Jonas Gaffke | 0c19d4e565 | ||
Jonas Gaffke | fa964bf950 | ||
Rouven Seifert | 727f5464ae | ||
Rouven Seifert | f5f4bf1b24 | ||
Rouven Seifert | b70c5b14b3 | ||
Rouven Seifert | 763a71c93f | ||
Rouven Seifert | 071c0aa464 | ||
Rouven Seifert | c595af81e7 | ||
Rouven Seifert | 077138401e | ||
Rouven Seifert | cb828a2188 | ||
Rouven Seifert | 7b7e8858cf | ||
Rouven Seifert | f40e47f871 | ||
Rouven Seifert | 7c87808bc1 | ||
Rouven Seifert | 8ea250e387 | ||
Rouven Seifert | a339235b33 | ||
Rouven Seifert | 02535cca08 | ||
Rouven Seifert | 5384918ce6 | ||
Rouven Seifert | 6abc1e75b9 | ||
Rouven Seifert | 395ca48ac0 | ||
Rouven Seifert | 6a2bcecb5e | ||
Rouven Seifert | a832b8d2a5 | ||
Rouven Seifert | 2c4be79f32 | ||
Rouven Seifert | 5294cd68f8 | ||
Rouven Seifert | 4fa9a2fe7d | ||
Rouven Seifert | 5930da6bdf | ||
Rouven Seifert | 81ac3b4c0d | ||
Jonas Gaffke | 7630dc4494 | ||
Jonas Gaffke | 993a554396 | ||
Rouven Seifert | bdc6185fce | ||
Rouven Seifert | 197956ea90 | ||
1f4e9a620b | |||
ab5df354ff | |||
cf7ff37367 | |||
f0c73a1763 | |||
d92eff80ce | |||
d1147621e1 | |||
3f47b32983 | |||
7526b9273b | |||
795e3db47f | |||
Rouven Seifert | 126cff2263 | ||
9327314ec9 | |||
Rouven Seifert | d03f4c6fb1 | ||
Rouven Seifert | ebe977672a | ||
Rouven Seifert | 579ad274d5 | ||
Rouven Seifert | 15299bcb99 | ||
Rouven Seifert | d5ab09207a | ||
Rouven Seifert | 375674b1b4 | ||
Rouven Seifert | 6cd1ba6aa5 | ||
Rouven Seifert | 08893439e7 | ||
Rouven Seifert | 0d4283f109 | ||
Rouven Seifert | ceca1b3798 | ||
Rouven Seifert | 3a47c43741 | ||
Rouven Seifert | f24793bbb6 | ||
Rouven Seifert | 5b95918c29 | ||
Rouven Seifert | 83db5399d7 | ||
Rouven Seifert | 4b173581dc | ||
Rouven Seifert | be638b274d | ||
Rouven Seifert | c534e2a8e1 |
40
flake.lock
40
flake.lock
|
@ -9,11 +9,11 @@
|
|||
"poetry2nix": "poetry2nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710843969,
|
||||
"lastModified": 1714117615,
|
||||
"narHash": "sha256-Ilu7j7tihFI0jtnsQS+7H0SZX4C61NZHaV/7fJ39t/E=",
|
||||
"owner": "fsr",
|
||||
"repo": "course-management",
|
||||
"rev": "07b173b4ea458e5a08b3aa9ec677153c08657c98",
|
||||
"rev": "9e5ab11788b926a9a26d2aaa0e0958c3c5865cc9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -145,11 +145,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711854532,
|
||||
"narHash": "sha256-JPStavwlT7TfxxiXHk6Q7sbNxtnXAIjXQJMLO0KB6M0=",
|
||||
"lastModified": 1716170277,
|
||||
"narHash": "sha256-fCAiox/TuzWGVaAz16PxrR4Jtf9lN5dwWL2W74DS0yI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "2844b5f3ad3b478468151bd101370b9d8ef8a3a7",
|
||||
"rev": "e0638db3db43b582512a7de8c0f8363a162842b9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -160,11 +160,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1712168706,
|
||||
"narHash": "sha256-XP24tOobf6GGElMd0ux90FEBalUtw6NkBSVh/RlA6ik=",
|
||||
"lastModified": 1716361217,
|
||||
"narHash": "sha256-mzZDr00WUiUXVm1ujBVv6A0qRd8okaITyUp4ezYRgc4=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1487bdea619e4a7a53a4590c475deabb5a9d1bfb",
|
||||
"rev": "46397778ef1f73414b03ed553a3368f0e7e33c2f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -176,11 +176,11 @@
|
|||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1711819797,
|
||||
"narHash": "sha256-tNeB6emxj74Y6ctwmsjtMlzUMn458sBmwnD35U5KIM4=",
|
||||
"lastModified": 1716061101,
|
||||
"narHash": "sha256-H0eCta7ahEgloGIwE/ihkyGstOGu+kQwAiHvwVoXaA0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2b4e3ca0091049c6fbb4908c66b05b77eaef9f0c",
|
||||
"rev": "e7cc61784ddf51c81487637b3031a6dd2d6673a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -192,11 +192,11 @@
|
|||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1712163089,
|
||||
"narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
|
||||
"lastModified": 1716509168,
|
||||
"narHash": "sha256-4zSIhSRRIoEBwjbPm3YiGtbd8HDWzFxJjw5DYSDy1n8=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
|
||||
"rev": "bfb7a882678e518398ce9a31a881538679f6f092",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -286,11 +286,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711855048,
|
||||
"narHash": "sha256-HxegAPnQJSC4cbEbF4Iq3YTlFHZKLiNTk8147EbLdGg=",
|
||||
"lastModified": 1716400300,
|
||||
"narHash": "sha256-0lMkIk9h3AzOHs1dCL9RXvvN4PM8VBKb+cyGsqOKa4c=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "99b1e37f9fc0960d064a7862eb7adfb92e64fa10",
|
||||
"rev": "b549832718b8946e875c016a4785d204fcfc2e53",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -386,11 +386,11 @@
|
|||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709622318,
|
||||
"narHash": "sha256-bTscF0366xtoIXgH7Zq+Mn0mpX3w4h/2xKpHiYMyLNc=",
|
||||
"lastModified": 1713958148,
|
||||
"narHash": "sha256-8PDNi/dgoI2kyM7uSiU4eoLBqUKoA+3TXuz+VWmuCOc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-vscode-server",
|
||||
"rev": "d0ed9b8cf1f0a71f110df9119489ab047e0726bd",
|
||||
"rev": "fc900c16efc6a5ed972fb6be87df018bcf3035bc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -83,12 +83,14 @@
|
|||
./modules/hedgedoc.nix
|
||||
./modules/padlist.nix
|
||||
./modules/nextcloud.nix
|
||||
./modules/keycloak.nix
|
||||
./modules/monitoring.nix
|
||||
./modules/vaultwarden.nix
|
||||
./modules/forgejo
|
||||
./modules/kanboard.nix
|
||||
./modules/zammad.nix
|
||||
./modules/decisions.nix
|
||||
./modules/struktur-bot.nix
|
||||
# ./modules/struktur-bot.nix
|
||||
{
|
||||
nixpkgs.overlays = [ self.overlays.default ];
|
||||
sops.defaultSopsFile = ./secrets/quitte.yaml;
|
||||
|
@ -106,7 +108,6 @@
|
|||
./hosts/tomate/configuration.nix
|
||||
./modules/core/base.nix
|
||||
./modules/core/zsh.nix
|
||||
./modules/core/fail2ban.nix
|
||||
./modules/core/sssd.nix
|
||||
{
|
||||
sops.defaultSopsFile = ./secrets/tomate.yaml;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ config, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
|
@ -7,11 +7,27 @@
|
|||
./network.nix
|
||||
];
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.systemd-boot = {
|
||||
enable = true;
|
||||
extraInstallCommands = ''
|
||||
${pkgs.coreutils}/bin/cp -r /boot/* /boot2
|
||||
'';
|
||||
};
|
||||
# boot.kernelParams = [ "video=VGA-1:1024x768@30" ];
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.supportedFilesystems = [ "zfs" ];
|
||||
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
# boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
# Pin Kernel Version as 6.6.28 has a broken networking driver
|
||||
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux_6_6.override {
|
||||
argsOverride = rec {
|
||||
src = pkgs.fetchurl {
|
||||
url = "mirror://kernel/linux/kernel/v6.x/linux-${version}.tar.xz";
|
||||
sha256 = "sha256-Y55QBg48jyPtAXyxDP6sxrqI/1WDgSu3aFm0zGoSgpE=";
|
||||
};
|
||||
version = "6.6.27";
|
||||
modDirVersion = "6.6.27";
|
||||
};
|
||||
});
|
||||
|
||||
services.zfs = {
|
||||
trim.enable = true;
|
||||
|
@ -37,9 +53,6 @@
|
|||
value = "10000";
|
||||
}
|
||||
];
|
||||
# Enable the OpenSSH daemon.
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.PermitRootLogin = "yes";
|
||||
|
||||
systemd = {
|
||||
services.nix-daemon.serviceConfig = {
|
||||
|
|
|
@ -10,41 +10,41 @@
|
|||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "rpool/nixos/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/" = {
|
||||
device = "rpool/nixos/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/home" =
|
||||
{
|
||||
device = "rpool/nixos/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/home" = {
|
||||
device = "rpool/nixos/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/nix" =
|
||||
{
|
||||
device = "rpool/nixos/nixnew";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/nix" = {
|
||||
device = "rpool/nixos/nixnew";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/var/lib" =
|
||||
{
|
||||
device = "rpool/nixos/var/lib";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/var/lib" = {
|
||||
device = "rpool/nixos/var/lib";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/var/log" =
|
||||
{
|
||||
device = "rpool/nixos/var/log";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/var/log" = {
|
||||
device = "rpool/nixos/var/log";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/3278-8D00";
|
||||
fsType = "vfat";
|
||||
};
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/3278-8D00";
|
||||
fsType = "vfat";
|
||||
options = [ "nofail" ];
|
||||
};
|
||||
fileSystems."/boot2" = {
|
||||
device = "/dev/disk/by-uuid/3366-F71E";
|
||||
fsType = "vfat";
|
||||
options = [ "nofail" ];
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
imports =
|
||||
[
|
||||
# Include the results of the hardware scan.
|
||||
./network.nix
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
|
@ -15,8 +16,6 @@
|
|||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
networking.hostName = "tomate"; # Define your hostname.
|
||||
networking.nftables.enable = true;
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
|
@ -29,9 +28,6 @@
|
|||
};
|
||||
};
|
||||
|
||||
# Enable networking
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
|
|
40
hosts/tomate/network.nix
Normal file
40
hosts/tomate/network.nix
Normal file
|
@ -0,0 +1,40 @@
|
|||
{ config, ... }:
|
||||
{
|
||||
sops.secrets.ifsr-apb-auth = { };
|
||||
networking = {
|
||||
domain = "ifsr.de";
|
||||
hostName = "tomate";
|
||||
useNetworkd = true;
|
||||
nftables.enable = true;
|
||||
# Radius authentification
|
||||
supplicant."enp3s0" = {
|
||||
driver = "wired";
|
||||
configFile.path = config.sops.secrets.ifsr-apb-auth.path;
|
||||
};
|
||||
};
|
||||
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
fallbackDns = [ "9.9.9.9" ];
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
|
||||
networks."10-wired-default" = {
|
||||
matchConfig.Name = "enp3s0";
|
||||
|
||||
address = [ "141.30.86.196/26" ];
|
||||
routes = [
|
||||
{
|
||||
routeConfig.Gateway = "141.30.86.193";
|
||||
}
|
||||
];
|
||||
networkConfig = {
|
||||
DNS = "141.30.1.1";
|
||||
LLDP = true;
|
||||
EmitLLDP = "nearest-bridge";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -29,7 +29,13 @@
|
|||
};
|
||||
|
||||
# Enable the OpenSSH daemon.
|
||||
services.openssh.enable = true;
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "yes";
|
||||
PasswordAuthentication = false;
|
||||
};
|
||||
};
|
||||
programs.mosh.enable = true;
|
||||
|
||||
# vs code server
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
./initrd-ssh.nix
|
||||
./mysql.nix
|
||||
./nginx.nix
|
||||
./podman.nix
|
||||
./postgres.nix
|
||||
./sssd.nix
|
||||
./zsh.nix
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
{ config, ... }:
|
||||
{
|
||||
boot.initrd = {
|
||||
availableKernelModules = [ "mlx5_core" ];
|
||||
systemd = {
|
||||
enable = true;
|
||||
network = {
|
||||
enable = true;
|
||||
networks."10-wired-default" = config.systemd.network.networks."10-wired-default";
|
||||
};
|
||||
users.root.shell = "/bin/zfs load-key rpool/nixos";
|
||||
users.root.shell = "/bin/systemd-tty-ask-password-agent";
|
||||
};
|
||||
network = {
|
||||
enable = true;
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
({ name, ... }: {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
# enable http3 for all hosts
|
||||
quic = true;
|
||||
http3 = true;
|
||||
# split up nginx access logs per vhost
|
||||
extraConfig = ''
|
||||
access_log /var/log/nginx/${name}_access.log;
|
||||
error_log /var/log/nginx/${name}_error.log;
|
||||
add_header Alt-Svc 'h3=":443"; ma=86400';
|
||||
'';
|
||||
})
|
||||
);
|
||||
|
@ -22,6 +26,7 @@
|
|||
networking.firewall.allowedUDPPorts = [ 443 ];
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
package = pkgs.nginxQuic;
|
||||
additionalModules = [ pkgs.nginxModules.pam ];
|
||||
recommendedProxySettings = true;
|
||||
recommendedGzipSettings = true;
|
||||
|
|
26
modules/core/podman.nix
Normal file
26
modules/core/podman.nix
Normal file
|
@ -0,0 +1,26 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
# From: https://nixos.wiki/wiki/Podman
|
||||
virtualisation.containers.enable = true;
|
||||
virtualisation = {
|
||||
podman = {
|
||||
enable = true;
|
||||
|
||||
# Create a `docker` alias for podman, to use it as a drop-in replacement
|
||||
dockerCompat = true;
|
||||
|
||||
# Required for containers under podman-compose to be able to talk to each other.
|
||||
defaultNetwork.settings.dns_enabled = true;
|
||||
};
|
||||
};
|
||||
virtualisation.oci-containers.backend = "podman";
|
||||
|
||||
|
||||
# Useful otherdevelopment tools
|
||||
environment.systemPackages = with pkgs; [
|
||||
dive # look into docker image layers
|
||||
podman-tui # status of containers in the terminal
|
||||
#docker-compose # start group of containers for dev
|
||||
#podman-compose # start group of containers for dev
|
||||
];
|
||||
}
|
|
@ -8,7 +8,9 @@
|
|||
"directus_ese"
|
||||
"course-management"
|
||||
"git"
|
||||
"grafana"
|
||||
"hedgedoc"
|
||||
"keycloak"
|
||||
"matrix-synapse"
|
||||
"mautrix-telegram"
|
||||
"mediawiki"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{ lib, pkgs, ... }:
|
||||
{
|
||||
users.users.root.shell = pkgs.zsh;
|
||||
programs.command-not-found.enable = false;
|
||||
programs.nix-index-database.comma.enable = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
|
|
@ -6,14 +6,14 @@ in
|
|||
sops.secrets."decisions_env" = { };
|
||||
virtualisation.oci-containers = {
|
||||
containers.decisions = {
|
||||
image = "decisions";
|
||||
image = "ghcr.io/fsr/decisions";
|
||||
volumes = [
|
||||
"/var/lib/nextcloud/data/root/files/FSR/protokolle:/protokolle:ro"
|
||||
];
|
||||
extraOptions = [ "--network=host" ];
|
||||
environmentFiles = [
|
||||
config.sops.secrets."decisions_env".path
|
||||
];
|
||||
extraOptions = [ "--network=host" ];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -25,11 +25,6 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
services.portunus.dex.oidcClients = [{
|
||||
id = "decisions";
|
||||
callbackURL = "https://decisions.ifsr.de/auth";
|
||||
}];
|
||||
|
||||
systemd.timers."decisions-to-db" = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
|
|
19
modules/forgejo/actions.nix
Normal file
19
modules/forgejo/actions.nix
Normal file
|
@ -0,0 +1,19 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
services.gitea-actions-runner = {
|
||||
package = pkgs.forgejo-actions-runner;
|
||||
instances."quitte" = {
|
||||
enable = true;
|
||||
labels = [
|
||||
# provide a debian base with nodejs for actions
|
||||
"debian-latest:docker://node:18-bullseye"
|
||||
# fake the ubuntu name, because node provides no ubuntu builds
|
||||
"ubuntu-latest:docker://node:18-bullseye"
|
||||
# provide native execution on the host
|
||||
"native:host"
|
||||
];
|
||||
#TODO get a token from git.ifsr.de and use it
|
||||
# tokenfile = /"dev/null";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -4,9 +4,9 @@ let
|
|||
gitUser = "git";
|
||||
in
|
||||
{
|
||||
# imports = [
|
||||
# ./actions.nix
|
||||
# ];
|
||||
imports = [
|
||||
./actions.nix
|
||||
];
|
||||
sops.secrets.gitea_ldap_search = {
|
||||
key = "portunus/search-password";
|
||||
owner = config.services.forgejo.user;
|
||||
|
|
|
@ -1,65 +1,33 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
domain = "kanboard.${config.networking.domain}";
|
||||
domain_short = "kb.${config.networking.domain}";
|
||||
user = "kanboard";
|
||||
group = "kanboard";
|
||||
in
|
||||
{
|
||||
users.users.${user} = {
|
||||
group = group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.${group} = { };
|
||||
|
||||
services.phpfpm.pools.kanboard = {
|
||||
user = "kanboard";
|
||||
group = "kanboard";
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_admin_value[error_log]" = "stderr";
|
||||
"php_admin_flag[log_errors]" = true;
|
||||
"catch_workers_output" = true;
|
||||
sops.secrets."kanboard_env" = { };
|
||||
|
||||
virtualisation.oci-containers = {
|
||||
containers.kanboard = {
|
||||
image = "ghcr.io/kanboard/kanboard:v1.2.36";
|
||||
volumes = [
|
||||
"kanboard_data:/var/www/app/data"
|
||||
"kanboard_plugins:/var/www/app/plugins"
|
||||
];
|
||||
ports = [ "127.0.0.1:8045:80" ];
|
||||
environmentFiles = [
|
||||
config.sops.secrets."kanboard_env".path
|
||||
];
|
||||
};
|
||||
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
|
||||
};
|
||||
|
||||
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx = {
|
||||
virtualHosts."${domain_short}" = {
|
||||
locations."/".return = "301 $scheme://${domain}$request_uri";
|
||||
};
|
||||
|
||||
virtualHosts."${domain}" = {
|
||||
root = "/srv/web/kanboard";
|
||||
extraConfig = ''
|
||||
index index.html index.php;
|
||||
'';
|
||||
|
||||
locations = {
|
||||
"/" = {
|
||||
tryFiles = "$uri $uri/ =404";
|
||||
};
|
||||
"~ \.php$" = {
|
||||
extraConfig = ''
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools.kanboard.socket};
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_index index.php;
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
'';
|
||||
};
|
||||
"/data".return = "403";
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8045";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
34
modules/keycloak.nix
Normal file
34
modules/keycloak.nix
Normal file
|
@ -0,0 +1,34 @@
|
|||
{ config, nixpkgs-unstable, ... }:
|
||||
let
|
||||
domain = "sso.${config.networking.domain}";
|
||||
in
|
||||
{
|
||||
sops.secrets."keycloak/db" = { };
|
||||
services.keycloak = {
|
||||
enable = true;
|
||||
# we use unstable as the release in stable is insecure
|
||||
package = nixpkgs-unstable.legacyPackages.x86_64-linux.keycloak;
|
||||
settings = {
|
||||
http-port = 8086;
|
||||
https-port = 19000;
|
||||
hostname = domain;
|
||||
proxy = "edge";
|
||||
};
|
||||
# The module requires a password for the DB and works best with its own DB config
|
||||
# Does an automatic Postgresql configuration
|
||||
database = {
|
||||
passwordFile = config.sops.secrets."keycloak/db".path;
|
||||
};
|
||||
initialAdminPassword = "plschangeme";
|
||||
};
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString config.services.keycloak.settings.http-port}";
|
||||
extraConfig = ''
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, nixpkgs-unstable, system, ... }:
|
||||
{ config, pkgs, nixpkgs-unstable, system, ... }:
|
||||
let
|
||||
domain = "auth.${config.networking.domain}";
|
||||
seedSettings = {
|
||||
|
@ -55,7 +55,6 @@ in
|
|||
sops.secrets = {
|
||||
"portunus/admin-password".owner = config.services.portunus.user;
|
||||
"portunus/search-password".owner = config.services.portunus.user;
|
||||
"dex/environment".owner = config.systemd.services.dex.serviceConfig.User;
|
||||
};
|
||||
|
||||
services.portunus = {
|
||||
|
@ -72,8 +71,6 @@ in
|
|||
|
||||
inherit domain seedSettings;
|
||||
port = 8681;
|
||||
dex.enable = true;
|
||||
|
||||
ldap = {
|
||||
suffix = "dc=ifsr,dc=de";
|
||||
searchUserName = "search";
|
||||
|
@ -84,30 +81,6 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
services.dex.settings = {
|
||||
oauth2.skipApprovalScreen = true;
|
||||
frontend = {
|
||||
issuer = "iFSR Schliboleth";
|
||||
logoURL = "https://wiki.ifsr.de/images/3/3b/LogoiFSR.png";
|
||||
theme = "dark";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.dex.serviceConfig = {
|
||||
DynamicUser = lib.mkForce false;
|
||||
EnvironmentFile = config.sops.secrets."dex/environment".path;
|
||||
StateDirectory = "dex";
|
||||
User = "dex";
|
||||
};
|
||||
|
||||
users = {
|
||||
users.dex = {
|
||||
group = "dex";
|
||||
isSystemUser = true;
|
||||
};
|
||||
groups.dex = { };
|
||||
};
|
||||
|
||||
security.pam.services.sshd.makeHomeDir = true;
|
||||
|
||||
services.nginx = {
|
||||
|
@ -115,13 +88,12 @@ in
|
|||
virtualHosts."${config.services.portunus.domain}" = {
|
||||
locations = {
|
||||
"/".proxyPass = "http://localhost:${toString config.services.portunus.port}";
|
||||
"/dex".proxyPass = "http://localhost:${toString config.services.portunus.dex.port}";
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall = {
|
||||
extraInputRules = ''
|
||||
ip saddr { 141.30.86.192/26, 141.76.100.128/25 } tcp dport 636 accept comment "Allow ldaps access from office nets"
|
||||
ip saddr { 141.30.86.192/26, 141.76.100.128/25, 141.30.30.169, 10.88.0.1/16 } tcp dport 636 accept comment "Allow ldaps access from office nets and podman"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -66,6 +66,14 @@
|
|||
ensureDatabases = [ "mailman" "mailman-web" ];
|
||||
};
|
||||
services.nginx.virtualHosts."lists.${config.networking.domain}" = {
|
||||
locations."/accounts/signup" = {
|
||||
extraConfig = ''
|
||||
allow 141.30.0.0/16;
|
||||
allow 141.76.0.0/16;
|
||||
deny all;
|
||||
uwsgi_pass unix:/run/mailman-web.socket;
|
||||
'';
|
||||
};
|
||||
locations."/robots.txt" = {
|
||||
extraConfig = ''
|
||||
add_header Content-Type text/plain;
|
||||
|
|
98
modules/monitoring.nix
Normal file
98
modules/monitoring.nix
Normal file
|
@ -0,0 +1,98 @@
|
|||
{ config, ... }:
|
||||
let
|
||||
domain = "monitoring.${config.networking.domain}";
|
||||
in
|
||||
{
|
||||
sops.secrets."grafana/oidc_secret" = {
|
||||
owner = "grafana";
|
||||
};
|
||||
# grafana configuration
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
inherit domain;
|
||||
http_addr = "127.0.0.1";
|
||||
http_port = 2342;
|
||||
root_url = "https://monitoring.ifsr.de";
|
||||
};
|
||||
database = {
|
||||
type = "postgres";
|
||||
user = "grafana";
|
||||
host = "/run/postgresql";
|
||||
};
|
||||
"auth.generic_oauth" = {
|
||||
enabled = true;
|
||||
name = "iFSR";
|
||||
allow_sign_up = true;
|
||||
client_id = "grafana";
|
||||
client_secret = "$__file{${config.sops.secrets."grafana/oidc_secret".path}}";
|
||||
scopes = "openid email profile offline_access roles";
|
||||
|
||||
email_attribute_path = "email";
|
||||
login_attribute_path = "username";
|
||||
name_attribute_path = "full_name";
|
||||
|
||||
auth_url = "https://sso.ifsr.de/realms/internal/protocol/openid-connect/auth";
|
||||
token_url = "https://sso.ifsr.de/realms/internal/protocol/openid-connect/token";
|
||||
api_url = "https://sso.ifsr.de/realms/internal/protocol/openid-connect/userinfo";
|
||||
role_attribute_path = "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'";
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "grafana";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
ensureDatabases = [ "grafana" ];
|
||||
};
|
||||
|
||||
services.prometheus = {
|
||||
enable = true;
|
||||
port = 9001;
|
||||
exporters = {
|
||||
node = {
|
||||
enable = true;
|
||||
enabledCollectors = [ "systemd" ];
|
||||
port = 9002;
|
||||
};
|
||||
postfix = {
|
||||
enable = true;
|
||||
port = 9003;
|
||||
};
|
||||
};
|
||||
scrapeConfigs = [
|
||||
{
|
||||
job_name = "node";
|
||||
static_configs = [{
|
||||
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ];
|
||||
}];
|
||||
scrape_interval = "15s";
|
||||
}
|
||||
{
|
||||
job_name = "postfix";
|
||||
static_configs = [{
|
||||
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.postfix.port}" ];
|
||||
}];
|
||||
# scrape_interval = "60s";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# nginx reverse proxy
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
{ config, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
domain = "cache.${config.networking.domain}";
|
||||
in
|
||||
|
@ -6,6 +6,7 @@ in
|
|||
sops.secrets."nix-serve/key" = { };
|
||||
services.nix-serve = {
|
||||
enable = true;
|
||||
package = pkgs.nix-serve-ng;
|
||||
secretKeyFile = config.sops.secrets."nix-serve/key".path;
|
||||
port = 5002;
|
||||
};
|
||||
|
|
|
@ -46,10 +46,4 @@ in
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.portunus.dex.oidcClients = [{
|
||||
id = "padlist";
|
||||
callbackURL = "https://list.pad.ifsr.de/callback.php";
|
||||
}];
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
sops.secrets."strukturbot_env" = { };
|
||||
virtualisation.docker.daemon.settings.dns = [ "141.30.1.1" "141.76.14.1" ];
|
||||
# virtualisation.docker.daemon.settings.dns = [ "141.30.1.1" "141.76.14.1" ];
|
||||
virtualisation.oci-containers = {
|
||||
containers.struktur-bot = {
|
||||
image = "struktur-bot";
|
||||
|
|
7
modules/web/crimecampus.nix
Normal file
7
modules/web/crimecampus.nix
Normal file
|
@ -0,0 +1,7 @@
|
|||
{ config, pkgs, ... }:
|
||||
let
|
||||
domain = "cc.${config.networking.domain}";
|
||||
in
|
||||
{
|
||||
services.nginx.virtualHosts."${domain}".root = "/srv/web/regex";
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./crimecampus.nix
|
||||
./ifsrde.nix
|
||||
./ese.nix
|
||||
./infoscreen.nix
|
||||
|
|
|
@ -7,14 +7,12 @@ in
|
|||
sops.secrets."directus_env" = { };
|
||||
environment.systemPackages = [ pkgs.nodejs_21 ];
|
||||
virtualisation.oci-containers = {
|
||||
backend = "docker";
|
||||
containers.directus-ese = {
|
||||
image = "directus/directus:latest";
|
||||
volumes = [
|
||||
"/srv/web/directus-ese/uploads:/directus/uploads"
|
||||
"/srv/web/directus-ese/database:/directus/database"
|
||||
];
|
||||
ports = [ "127.0.0.1:8055:8055" ];
|
||||
extraOptions = [ "--network=host" ];
|
||||
environment = {
|
||||
"DB_CLIENT" = "pg";
|
||||
|
@ -22,6 +20,14 @@ in
|
|||
"DB_PORT" = "5432";
|
||||
"DB_DATABASE" = "directus_ese";
|
||||
"DB_USER" = "directus_ese";
|
||||
"PUBLIC_URL" = "https://directus-ese.ifsr.de";
|
||||
"AUTH_PROVIDERS"="keycloak";
|
||||
"AUTH_KEYCLOAK_DRIVER" = "openid";
|
||||
"AUTH_KEYCLOAK_CLIENT_ID" = "directus-ese";
|
||||
"AUTH_KEYCLOAK_ISSUER_URL" = "https://sso.ifsr.de/realms/internal/.well-known/openid-configuration";
|
||||
"AUTH_KEYCLOAK_IDENTIFIER_KEY" = "email";
|
||||
"AUTH_KEYCLOAK_ALLOW_PUBLIC_REGISTRATION"="true";
|
||||
"AUTH_KEYCLOAK_DEFAULT_ROLE_ID"="a6b7a1b6-a6fa-442c-87fd-e37c2a16424b";
|
||||
};
|
||||
environmentFiles = [
|
||||
config.sops.secrets."directus_env".path
|
||||
|
|
|
@ -58,6 +58,7 @@ in
|
|||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
fastcgi_param HTTP_HOST $host;
|
||||
'';
|
||||
};
|
||||
"~ \.log$".return = "403";
|
||||
|
|
|
@ -60,6 +60,7 @@ in
|
|||
"~ ^/cmd(/?[^\\n|\\r]*)$".return = "301 https://pad.ifsr.de$1";
|
||||
"/bbb".return = "301 https://bbb.tu-dresden.de/b/fsr-58o-tmf-yy6";
|
||||
"/kpp".return = "301 https://kpp.ifsr.de";
|
||||
"/sso".return = "301 https://sso.ifsr.de/realms/internal/account";
|
||||
# security
|
||||
"~* /(\.git|cache|bin|logs|backup|tests)/.*$".return = "403";
|
||||
# deny running scripts inside core system folders
|
||||
|
@ -72,9 +73,4 @@ in
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.portunus.dex.oidcClients = [{
|
||||
id = "grav";
|
||||
callbackURL = "https://ifsr.de/admin/task:callback.oauth2";
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ in
|
|||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
fastcgi_param HTTP_HOST $host;
|
||||
'';
|
||||
};
|
||||
"~ \.log$".return = "403";
|
||||
|
|
|
@ -63,11 +63,12 @@ in
|
|||
# Auth
|
||||
# https://www.mediawiki.org/wiki/Extension:PluggableAuth
|
||||
# https://www.mediawiki.org/wiki/Extension:OpenID_Connect
|
||||
$wgOpenIDConnect_MigrateUsersByEmail = true;
|
||||
$wgPluggableAuth_EnableLocalLogin = true;
|
||||
$wgPluggableAuth_Config["iFSR Login"] = [
|
||||
"plugin" => "OpenIDConnect",
|
||||
"data" => [
|
||||
"providerURL" => "${config.services.portunus.domain}/dex",
|
||||
"providerURL" => "https://sso.ifsr.de/realms/internal",
|
||||
"clientID" => "wiki",
|
||||
"clientsecret" => file_get_contents('${config.sops.secrets."mediawiki/oidc_secret".path}'),
|
||||
],
|
||||
|
@ -94,11 +95,6 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
portunus.dex.oidcClients = [{
|
||||
id = "wiki";
|
||||
callbackURL = "https://${domain}/Spezial:PluggableAuthLogin";
|
||||
}];
|
||||
|
||||
nginx = {
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts.${domain} = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
_final: prev:
|
||||
let
|
||||
inherit (prev) fetchurl;
|
||||
inherit (prev) fetchFromGitHub;
|
||||
in
|
||||
{
|
||||
# AGDSN is running an outdated version that we have to comply to
|
||||
|
@ -11,5 +12,17 @@ in
|
|||
sha256 = "sha256-3w+FJezbo4DnS1N8pxrfO3WWWT8CGJtZqw6//IXMyN4=";
|
||||
};
|
||||
}));
|
||||
# (hopefully) fix systemd journal reading
|
||||
prometheus-postfix-exporter = prev.prometheus-postfix-exporter.overrideAttrs (_old: {
|
||||
patches = [
|
||||
./prometheus-postfix-exporter/0001-cleanup-also-catch-milter-reject.patch
|
||||
];
|
||||
src = fetchFromGitHub {
|
||||
owner = "adangel";
|
||||
repo = "postfix_exporter";
|
||||
rev = "414ac12ee63415eede46cb3084d755a6da6fba23";
|
||||
hash = "sha256-m1kVaO3N7XC1vtnxXX9kMiEFPmZuoopRUYgA7gQzP8w=";
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
From f4c5dd5628c873981b2d6d6b8f3bbf036b9fd724 Mon Sep 17 00:00:00 2001
|
||||
From: Rouven Seifert <rouven.seifert@ifsr.de>
|
||||
Date: Thu, 2 May 2024 11:20:27 +0200
|
||||
Subject: [PATCH] cleanup: also catch milter-reject
|
||||
|
||||
---
|
||||
postfix_exporter.go | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/postfix_exporter.go b/postfix_exporter.go
|
||||
index f20d99c..676d767 100644
|
||||
--- a/postfix_exporter.go
|
||||
+++ b/postfix_exporter.go
|
||||
@@ -335,6 +335,8 @@ func (e *PostfixExporter) CollectFromLogLine(line string) {
|
||||
e.cleanupProcesses.Inc()
|
||||
} else if strings.Contains(remainder, ": reject: ") {
|
||||
e.cleanupRejects.Inc()
|
||||
+ } else if strings.Contains(remainder, ": milter-reject: ") {
|
||||
+ e.cleanupRejects.Inc()
|
||||
} else {
|
||||
e.addToUnsupportedLine(line, subprocess, level)
|
||||
}
|
||||
--
|
||||
2.44.0
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -4,6 +4,7 @@ print:
|
|||
smtp-password: ENC[AES256_GCM,data:XoaLiEpqAdKapeS9YoBfh2w7HFuTCV9rHIciH+qUbhHcdsgVpnPMsSlC,iv:WxfP5d2K9soJPoRPuS6O6PbNvo4TBQjPGiV0e+a501Q=,tag:ZsTdR+b/oYFAYz/MN73PFg==,type:str]
|
||||
sssd:
|
||||
env: ENC[AES256_GCM,data:9IbU7uaElmemQHVUvsM88hcyNl3WFehgQeLZPtUxt2Sd0IECm8qNkQhWJ4kuvoBnQsdsUrFm/0QuW7AfDFOeE7FxMxg0,iv:dyzsYHlqClWbfzsoJ36iYjaXWpidB1ZqHXI7RP7js2Y=,tag:97FMOeVwAEy8Ka79uZKC8Q==,type:str]
|
||||
ifsr-apb-auth: ENC[AES256_GCM,data:hxJOvRbgjB//YU3wy04P7yrQbV0Ggoi18wQxwy4hHgbXizTHbmlfiZ/MstITrZQ6qEPVBEW41/iGU3DO2Cg2ofpWvFU5Gr8FM1AC9DKq8SppLGqzel1mEejPfrh4RbQUMe0zZlc/YfhCah5sM0oPnBQNg8bPpveEO+5/bRq5S24jkkv7w6/AAS8tGvjALVf/g95jsCrQO2MYg9jCCEkdhORU0bowGD8cjTr6wnPkNhwzn5tiKoPn6eH6TFBkqNC+Q/5E+os10i9F1c3z/sv8Snrcl7V5higqrQekhEvGRDmax/4lE8Yb3AoxC/2M4/+9x+OPi0JUkkhC6rghETXpmYkuaD7E8+eEtLeSbiJPlPijq2HTtbtsHcSoMUdoGO8644TVe/jDxaEe54p9OWEFjRRpONijQKsfH3wENlUXmqDQDLfMSpoANxIHMh+RmRzktGIvTgvs6rlKXsWp7/gggFVxdM/5QPbE3pUvGr+JPWz4,iv:6c1HxYGrItPwKzAnQ0zUvO3TSejVZ/aWF9zs99ufzl4=,tag:fELOskceJWKmkm74MCsfoA==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
|
@ -19,8 +20,8 @@ sops:
|
|||
TXVrMHZCNU5zOG5hVnNkdEoxcTZqWXMKA9eG1zM6HeLAAOpIo8Z5+5KD4Z5P3rdc
|
||||
kE8sUXHD3d8SMmSKcTYe6gGVzFuw0xxnMb/AmjAQosvDFTQsWy1sTw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2024-01-29T13:36:12Z"
|
||||
mac: ENC[AES256_GCM,data:CnoH4KmYy72E0L+X7SHYXrFH6z0KhRhfYXmIO8HnPlkYnwKXDeAYezv4kL3ItZG+8pnmbFdoyHxxVMT6rWtV//x16YPMI0zhwIEBs67ZxM+gzeei4fniktolydKmlXUgbtWw3/y3OtxzAn9Dne2LPz7CwN/imGOTgrWFYGWRhtU=,iv:gcurHYWPSijYRlt9FoutrGInWDOfSkjrNqwU6jxiHDk=,tag:qWhpQ9vLuuihOzJeOGYEog==,type:str]
|
||||
lastmodified: "2024-04-16T08:58:21Z"
|
||||
mac: ENC[AES256_GCM,data:2aOOVZK7kshJFBWphvW/BqRUXht4p80Q15nGJNA1EbjT05f3tYdrr8QuM5Xd1vJO07rgmokWv4XwbzodRIwqidEXD5xuJ1v+kHC/jJnO3yrBKY7kVMHkia2Wq00bcN/iwdW6G6AP5D4HQbmFNo+rLHyjIVwPvtu9jutKpz12NH0=,iv:YCBX2gSEmiUa6HrHi0VEcRGWDJrXGajD8ZbOZcppFnM=,tag:FK2E4hukl8oL5aZNTCQESA==,type:str]
|
||||
pgp:
|
||||
- created_at: "2024-02-29T15:23:28Z"
|
||||
enc: |-
|
||||
|
|
Loading…
Reference in a new issue