Compare commits

..

1 commit

Author SHA1 Message Date
Rouven Seifert 348e6b9fb6
allow users to use the server as remote builder 2023-09-17 22:49:28 +02:00
93 changed files with 1359 additions and 4243 deletions

27
.github/workflows/fmt.yaml vendored Normal file
View file

@ -0,0 +1,27 @@
name: main
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
check-flake:
name: Nixpkgs Formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Nix
uses: cachix/install-nix-action@v18
with:
extra_nix_config: |
experimental-features = nix-command flakes
- run: nix-channel --add https://nixos.org/channels/nixos-22.11 nixos
- run: nix-channel --update
- run: nix shell nixpkgs#nixpkgs-fmt -c nixpkgs-fmt . --check

34
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,34 @@
name: main
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
check-flake:
name: Check Flake
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Nix
uses: cachix/install-nix-action@v18
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
extra_nix_config: |
experimental-features = nix-command flakes
- uses: cachix/cachix-action@v12
with:
name: fruitbasket
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
extraPullNames: nix-community
- run: nix build
- run: nix flake check

View file

@ -7,11 +7,9 @@ keys:
- &helene B43C3A8A92CA28486AC6C4E2F115100C787C1C19
- &fugi BF37903AE6FD294C4C674EE24472A20091BFA792
- &emmanuel E83F398E6423179FE4F63D4FF085CAD394DE329D
- &jonas A4F92BC7B792108A463995827C1F2DA2BC929412
- &joachim B1A16011B86BACB56ADB713DB712039D23133661
- &jonasga FB44F0746DF25F0B24A2EAE586C8A257C3EC82AB
- &hendrik FBBFAC260D9283D1EF2397DD3CA65E9DD6EB319D
- &quitte age1wvdnprpnq2rcc4se3zpx2p267n0apxg2jucvlm93e3pfj439ephqh2506t
- &tomate age18lwgjazaxujqgcc5j0gjllnykhtjn6p0q44jzrsk4au2a5k6nd9s77kd6d
creation_rules:
- path_regex: secrets/quitte\.yaml$
@ -23,23 +21,9 @@ creation_rules:
- *rouven
- *fugi
- *joachim
- *jonasga
- *hendrik
- *jonas
age:
- *quitte
- path_regex: secrets/tomate\.yaml$
key_groups:
- pgp:
- *bennofs
- *revol-xut
- *felix
- *rouven
- *fugi
- *joachim
- *jonasga
- *hendrik
age:
- *tomate
- path_regex: secrets/admin\.yaml$
key_groups:
- pgp:
@ -49,5 +33,4 @@ creation_rules:
- *rouven
- *fugi
- *joachim
- *jonasga
- *hendrik
- *jonas

View file

@ -9,11 +9,11 @@
"poetry2nix": "poetry2nix"
},
"locked": {
"lastModified": 1730751072,
"narHash": "sha256-+FQjzCNV3k8U4BfNcFmoZTRf8aO9ufn3s7kkzHj/b7s=",
"lastModified": 1694358978,
"narHash": "sha256-gHWIIYJZepq1/3oFVkUkl0n52bRJWnNgmGaiZ2aGEwc=",
"owner": "fsr",
"repo": "course-management",
"rev": "60b7062ce47ee9f0609e701ad5eb5e3e0a857ff2",
"rev": "5ccbee8151c5caa519ebdb2ce2b8ec52b7749949",
"type": "github"
},
"original": {
@ -22,52 +22,16 @@
"type": "github"
}
},
"ese-manual": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1730889586,
"narHash": "sha256-SLgo7UjWLaFaaUPFqzKbr9DLAGzm5kparfxuJHEpK3w=",
"ref": "refs/heads/main",
"rev": "a111147ce5eaea4f1d691afe1203e7529d68522d",
"revCount": 9,
"type": "git",
"url": "https://git.ifsr.de/ese/manual-website"
},
"original": {
"type": "git",
"url": "https://git.ifsr.de/ese/manual-website"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1687709756,
"narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7",
"type": "github"
},
"original": {
@ -81,47 +45,11 @@
"systems": "systems_2"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1687709756,
"narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_4"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"inputs": {
"systems": "systems_5"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7",
"type": "github"
},
"original": {
@ -137,11 +65,11 @@
]
},
"locked": {
"lastModified": 1724255946,
"narHash": "sha256-YVT/QE2PCDzx4eq1i3PqOOpQVXJstN18e0sFB/UbAY0=",
"lastModified": 1693305731,
"narHash": "sha256-ku0FU1pn6eXGdoEx0Tg0Kp8c8wmd6TF7IrdOnX0Uco0=",
"owner": "fsr",
"repo": "kpp",
"rev": "ce98b985201a5453aee708a3fc13bbccf2357f8e",
"rev": "7c04f958bb652de680ae3311b6eab080ac64b3ad",
"type": "github"
},
"original": {
@ -150,172 +78,66 @@
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"course-management",
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1729742964,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nix-index-database": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1731209121,
"narHash": "sha256-BF7FBh1hIYPDihdUlImHGsQzaJZVLLfYqfDx41wjuF0=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "896019f04b22ce5db4c0ee4f89978694f44345c3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-index-database",
"type": "github"
}
},
"nix-minecraft": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_3",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1731375802,
"narHash": "sha256-CvWPEzrl2EA3xrtg9X6K8aqV7T5r0SaDz6PLpGA0yIY=",
"owner": "Infinidoge",
"repo": "nix-minecraft",
"rev": "b873a123366b9a62f9262414ada8d83b03f1f0bf",
"type": "github"
},
"original": {
"owner": "Infinidoge",
"repo": "nix-minecraft",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1731239293,
"narHash": "sha256-q2yjIWFFcTzp5REWQUOU9L6kHdCDmFDpqeix86SOvDc=",
"lastModified": 1694499547,
"narHash": "sha256-R7xMz1Iia6JthWRHDn36s/E248WB1/je62ovC/dUVKI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "9256f7c71a195ebe7a218043d9f93390d49e6884",
"rev": "e5f018cf150e29aac26c61dac0790ea023c46b24",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-24.05",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1730602179,
"narHash": "sha256-efgLzQAWSzJuCLiCaQUCDu4NudNlHdg2NzGLX5GYaEY=",
"lastModified": 1693675694,
"narHash": "sha256-2pIOyQwGyy2FtFAUIb8YeKVmOCcPOTVphbAvmshudLE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3c2f1c4ca372622cb2f9de8016c9a0b1cbd0f37c",
"rev": "5601118d39ca9105f8e7b39d4c221d3388c0419d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"ref": "release-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1682134069,
"narHash": "sha256-TnI/ZXSmRxQDt2sjRYK/8j8iha4B4zP2cnQCZZ3vp7k=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fd901ef4bf93499374c5af385b2943f5801c0833",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": [
"course-management",
"nixpkgs"
],
"systems": "systems_3",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1730284601,
"narHash": "sha256-eHYcKVLIRRv3J1vjmxurS6HVdGphB53qxUeAkylYrZY=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "43a898b4d76f7f3f70df77a2cc2d40096bc9d75e",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"print-interface": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1706540741,
"narHash": "sha256-4/JI3xhw76Z1oa8Ivn3AzR6zNqXkmSEgHl+v0PRGnTc=",
"owner": "fsr",
"repo": "print-interface",
"rev": "ca830bc64ee92ec24562e707ddf36c19a5607a94",
"lastModified": 1688440303,
"narHash": "sha256-hFfOyityHdVFI0HNM+sqZfpi9Fbvjvy0N9O7FjuqPWY=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "04714155bae013fb9b207e54d1faf9f0c3d08706",
"type": "github"
},
"original": {
"owner": "fsr",
"repo": "print-interface",
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"root": {
"inputs": {
"course-management": "course-management",
"ese-manual": "ese-manual",
"kpp": "kpp",
"nix-index-database": "nix-index-database",
"nix-minecraft": "nix-minecraft",
"nixpkgs": "nixpkgs",
"print-interface": "print-interface",
"sops-nix": "sops-nix",
"vscode-server": "vscode-server"
"sops-nix": "sops-nix"
}
},
"sops-nix": {
@ -326,11 +148,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1731364708,
"narHash": "sha256-HC0anOL+KmUQ2hdRl0AtunbAckasxrkn4VLmxbW/WaA=",
"lastModified": 1694495315,
"narHash": "sha256-sZEYXs9T1NVHZSSbMqBEtEm2PGa7dEDcx0ttQkArORc=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "4c91d52db103e757fc25b58998b0576ae702d659",
"rev": "ea208e55f8742fdcc0986b256bdfa8986f5e4415",
"type": "github"
},
"original": {
@ -368,91 +190,6 @@
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"id": "systems",
"type": "indirect"
}
},
"systems_4": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_5": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"course-management",
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730120726,
"narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "9ef337e492a5555d8e17a51c911ff1f02635be15",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"vscode-server": {
"inputs": {
"flake-utils": "flake-utils_4",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1729422940,
"narHash": "sha256-DlvJv33ml5UTKgu4b0HauOfFIoDx6QXtbqUF3vWeRCY=",
"owner": "nix-community",
"repo": "nixos-vscode-server",
"rev": "8b6db451de46ecf9b4ab3d01ef76e59957ff549f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-vscode-server",
"type": "github"
}
}
},
"root": "root",

125
flake.nix
View file

@ -1,128 +1,61 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
sops-nix.url = "github:Mic92/sops-nix";
nixpkgs.url = github:nixos/nixpkgs/nixos-23.05;
sops-nix.url = github:Mic92/sops-nix;
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
nix-index-database.url = "github:nix-community/nix-index-database";
nix-index-database.inputs.nixpkgs.follows = "nixpkgs";
kpp.url = "github:fsr/kpp";
kpp.inputs.nixpkgs.follows = "nixpkgs";
print-interface = {
url = "github:fsr/print-interface";
inputs.nixpkgs.follows = "nixpkgs";
};
ese-manual.url = "git+https://git.ifsr.de/ese/manual-website";
ese-manual.inputs.nixpkgs.follows = "nixpkgs";
vscode-server.url = "github:nix-community/nixos-vscode-server";
course-management = {
url = "github:fsr/course-management";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-minecraft.url = "github:Infinidoge/nix-minecraft";
nix-minecraft.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
{ self
, nixpkgs
, sops-nix
, nix-index-database
, kpp
, ese-manual
, vscode-server
, course-management
, print-interface
, nix-minecraft
, ...
}@inputs:
let
supportedSystems = [ "x86_64-linux" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
in
outputs = { self, nixpkgs, sops-nix, kpp, course-management, ... }@inputs:
{
packages = forAllSystems (system: rec {
default = quitte;
quitte = self.nixosConfigurations.quitte.config.system.build.toplevel;
tomate = self.nixosConfigurations.tomate.config.system.build.toplevel;
});
formatter = forAllSystems (system: pkgs.${system}.nixpkgs-fmt);
hydraJobs = forAllSystems (system: {
quitte = self.packages.${system}.quitte;
});
packages."x86_64-linux".quitte = self.nixosConfigurations.quitte.config.system.build.toplevel;
packages."x86_64-linux".default = self.packages."x86_64-linux".quitte;
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;
hydraJobs."x86-64-linux".quitte = self.packages."x86_64-linux".quitte;
devShells = forAllSystems (system: {
default = pkgs.${system}.mkShell {
packages = with pkgs.${system}; [
sops
];
};
});
overlays.default = import ./overlays;
nixosConfigurations = {
quitte = nixpkgs.lib.nixosSystem rec {
quitte = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs // { inherit system; };
modules = [
inputs.sops-nix.nixosModules.sops
inputs.kpp.nixosModules.default
inputs.nix-index-database.nixosModules.nix-index
ese-manual.nixosModules.default
course-management.nixosModules.default
vscode-server.nixosModules.default
nix-minecraft.nixosModules.minecraft-servers
./hosts/quitte/configuration.nix
./options
./modules/core
./modules/bacula.nix
./modules/options.nix
./modules/base.nix
./modules/sops.nix
./modules/kpp.nix
./modules/ldap
./modules/mail
./modules/web
./modules/courses
./modules/wiki
./modules/matrix
./modules/minecraft
./modules/keycloak
./modules/monitoring
./modules/nix-serve.nix
./modules/mailman.nix
./modules/nginx.nix
./modules/hydra.nix
./modules/userdir.nix
./modules/hedgedoc.nix
./modules/padlist.nix
./modules/nextcloud.nix
./modules/vaultwarden.nix
./modules/forgejo
./modules/kanboard.nix
./modules/zammad.nix
# ./modules/decisions.nix
./modules/postgres.nix
./modules/wiki.nix
./modules/ftp.nix
./modules/stream.nix
# ./modules/struktur-bot.nix
./modules/nextcloud.nix
./modules/matrix.nix
./modules/mautrix-telegram.nix
./modules/sogo.nix
./modules/vaultwarden.nix
./modules/website.nix
./modules/zsh.nix
./modules/course-management.nix
./modules/gitea.nix
{
nixpkgs.overlays = [
self.overlays.default
nix-minecraft.overlay
];
sops.defaultSopsFile = ./secrets/quitte.yaml;
}
];
};
tomate = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs;
modules = [
inputs.sops-nix.nixosModules.sops
inputs.nix-index-database.nixosModules.nix-index
vscode-server.nixosModules.default
print-interface.nixosModules.default
./hosts/tomate/configuration.nix
./modules/core/base.nix
./modules/core/zsh.nix
./modules/core/sssd.nix
{
sops.defaultSopsFile = ./secrets/tomate.yaml;
}
];
};
};
};
}

View file

@ -7,61 +7,47 @@
./network.nix
];
boot.loader.systemd-boot = {
enable = true;
extraInstallCommands = ''
${pkgs.coreutils}/bin/cp -r /boot/* /boot2
'';
};
# boot.kernelParams = [ "video=VGA-1:1024x768@30" ];
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
#boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
#boot.kernelParams = [ "video=VGA-1:1024x768@30" ];
boot.loader.efi.canTouchEfiVariables = true;
boot.supportedFilesystems = [ "zfs" ];
#boot.supportedFilesystems = [ "zfs" ];
#boot.zfs.devNodes = "/dev/";
services.zfs = {
trim.enable = true;
autoScrub.enable = true;
};
services.qemuGuest.enable = true;
# don't freeze the whole system while building something
nix.settings.cores = 16;
# allows everyone in the nix-trusted group to perform builds
nix.settings.trusted-users = [ "@nix-trusted" ];
# Set your time zone.
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "en_US.UTF-8";
security.sudo.extraRules = [
{
commands = [
{
command = "ALL";
options = [ "NOPASSWD" ];
}
];
groups = [ "admins" ];
}
];
# prevent fork bombs
security.pam.loginLimits = [
{
domain = "@users";
item = "nproc";
type = "hard";
value = "2000";
}
{
domain = "@nixbld";
item = "nproc";
type = "hard";
value = "10000";
}
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
vim
wget
git
];
systemd = {
services.nix-daemon.serviceConfig = {
MemoryMax = "32G";
};
# all users together may not use more than $MemoryMax of RAM
slices."user".sliceConfig = {
MemoryMax = "32G";
};
};
# Enable the OpenSSH daemon.
services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = "yes";
# Open ports in the firewall.
networking.firewall.allowedTCPPorts = [ 443 80 ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# Copy the NixOS configuration file and link it from the resulting system
# (/run/current-system/configuration.nix). This is useful in case you
# accidentally delete configuration.nix.
# system.copySystemConfiguration = true;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions

View file

@ -1,52 +1,42 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, modulesPath, ... }:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
imports =
[
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "megaraid_sas" "xhci_pci" "nvme" "ahci" "usbhid" "usb_storage" "sd_mod" "sr_mod" ];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "rpool/nixos/root";
fsType = "zfs";
};
fileSystems."/" =
{
device = "/dev/disk/by-uuid/4d57c7c1-ed70-4fb1-af4c-4ba027b75248";
fsType = "ext4";
};
fileSystems."/home" = {
device = "rpool/nixos/home";
fsType = "zfs";
};
boot.initrd.luks.devices."luksroot".device = "/dev/disk/by-uuid/cfb9b37e-152d-45e9-b75d-88d71471be45";
fileSystems."/nix" = {
device = "rpool/nixos/nixnew";
fsType = "zfs";
};
fileSystems."/var/lib" = {
device = "rpool/nixos/var/lib";
fsType = "zfs";
};
fileSystems."/var/log" = {
device = "rpool/nixos/var/log";
fsType = "zfs";
};
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" ];
};
fileSystems."/boot" =
{
device = "/dev/disk/by-uuid/06C4-1FDB";
fsType = "vfat";
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.ens18.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -1,35 +1,46 @@
{ config, lib, ... }:
{ config, ... }:
let
wireguard_port = 51820;
in
{
networking = {
# portunus module does weird things to this, so we force it to some sane values
hosts = {
"127.0.0.1" = lib.mkForce [ "quitte.ifsr.de" "quitte" ];
"::1" = lib.mkForce [ "quitte.ifsr.de" "quitte" ];
sops.secrets = {
"wg-fsr" = {
owner = config.users.users.systemd-network.name;
};
};
networking = {
hostId = "a71c81fc";
domain = "ifsr.de";
hostName = "quitte";
rDNS = config.networking.fqdn;
enableIPv6 = true;
useDHCP = true;
interfaces.ens18.useDHCP = true;
useNetworkd = true;
nftables.enable = true;
firewall = {
logRefusedConnections = false;
};
firewall.allowedUDPPorts = [ wireguard_port ];
wireguard.enable = true;
};
services.resolved = {
enable = true;
fallbackDns = [ "9.9.9.9" ];
#dnssec = "false";
fallbackDns = [ "1.1.1.1" ];
};
# workaround for networkd waiting for shit
systemd.services.systemd-networkd-wait-online.serviceConfig.ExecStart = [
"" # clear old command
"${config.systemd.package}/lib/systemd/systemd-networkd-wait-online --any"
];
systemd.network = {
enable = true;
wait-online.anyInterface = true;
# Interfaces on the machine
networks."10-wired-default" = {
matchConfig.Name = "enp65s0f0np0";
networks."10-ether-bond" = {
matchConfig.Name = "ens18";
address = [ "141.30.30.169/25" ];
routes = [
@ -39,8 +50,39 @@
];
networkConfig = {
DNS = "141.30.1.1";
LLDP = true;
EmitLLDP = "nearest-bridge";
#IPv6AcceptRA = true;
};
};
# defining network device for wireguard connections
netdevs."fsr-wg" = {
netdevConfig = {
Kind = "wireguard";
Name = "fsr-wg";
Description = "fsr enterprise wireguard";
};
wireguardConfig = {
PrivateKeyFile = config.sops.secrets."wg-fsr".path;
ListenPort = wireguard_port;
};
wireguardPeers = [
{
# tassilo
wireguardPeerConfig = {
PublicKey = "vgo3le9xrFsIbbDZsAhQZpIlX+TuWjfEyUcwkoqUl2Y=";
AllowedIPs = [ "10.66.66.100/32" ];
PersistentKeepalive = 25;
};
}
];
};
# fsr wireguard server
networks."fsr-wg" = {
matchConfig.Name = "fsr-wg";
networkConfig = {
Address = "10.66.66.1/24";
IPForward = "ipv4";
};
};
};

View file

@ -1,177 +0,0 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, ... }:
{
imports =
[
# Include the results of the hardware scan.
./network.nix
./hardware-configuration.nix
];
# Bootloader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
nix = {
settings = {
substituters = [
"https://cache.ifsr.de"
];
trusted-public-keys = [
"cache.ifsr.de:y55KBAMF4YkjIzXwYOKVk9fcQS+CZ9RM1zAAMYQJtsg="
];
};
};
# Set your time zone.
time.timeZone = "Europe/Berlin";
# Select internationalisation properties.
i18n.defaultLocale = "de_DE.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "de_DE.UTF-8";
LC_IDENTIFICATION = "de_DE.UTF-8";
LC_MEASUREMENT = "de_DE.UTF-8";
LC_MONETARY = "de_DE.UTF-8";
LC_NAME = "de_DE.UTF-8";
LC_NUMERIC = "de_DE.UTF-8";
LC_PAPER = "de_DE.UTF-8";
LC_TELEPHONE = "de_DE.UTF-8";
LC_TIME = "de_DE.UTF-8";
};
# Enable the X11 windowing system.
services.xserver.enable = true;
# Enable the KDE Plasma Desktop Environment.
services.displayManager.sddm.enable = true;
services.xserver.desktopManager.plasma5.enable = true;
# Configure keymap in X11
services.xserver = {
xkb.layout = "de";
xkb.variant = "";
};
# Configure console keymap
console.keyMap = "de";
services.printing = {
enable = true;
stateless = true;
drivers = with pkgs; [ cups-kyocera ];
browsing = true;
defaultShared = true;
# todo fix
allowFrom = [ "all" ];
listenAddresses = [ "0.0.0.0:631" ];
};
sops.secrets."print/smtp-password" = {
owner = config.services.print-interface.user;
group = config.services.print-interface.group;
};
services.print-interface = {
enable = true;
smtp = {
username = "print";
passwordFile = config.sops.secrets."print/smtp-password".path;
};
};
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
publish = {
enable = true;
userServices = true;
};
};
networking.firewall = {
allowedTCPPorts = [
631
config.services.print-interface.listenPort
];
allowedUDPPorts = [ 631 ];
};
# Enable sound with pipewire.
sound.enable = true;
hardware.pulseaudio.enable = false;
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
# If you want to use JACK applications, uncomment this
#jack.enable = true;
# use the example session manager (no others are packaged yet so this is enabled by default,
# no need to redefine it in your config for now)
#media-session.enable = true;
};
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
# wget
];
security = {
pam = {
u2f = {
enable = true;
};
services = {
login.u2fAuth = true;
sudo.u2fAuth = true;
};
};
};
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
services.openssh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "23.05"; # Did you read the comment?
}

View file

@ -1,42 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, modulesPath, ... }:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "ohci_pci" "ehci_pci" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{
device = "/dev/disk/by-uuid/618e281f-a8bf-4129-bfc1-aa47f86a8c54";
fsType = "ext4";
};
fileSystems."/boot" =
{
device = "/dev/disk/by-uuid/0844-2A73";
fsType = "vfat";
};
swapDevices =
[{ device = "/dev/disk/by-uuid/8bdeb0c1-8f1e-43a7-b4b9-c06e27a94460"; }];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp3s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -1,40 +0,0 @@
{ 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";
};
};
};
}

View file

@ -1,23 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEZNJqYBYJKwYBBAHaRw8BAQdAKncDaEdOUQGOqVBQuEsJ42wCcyLB7x1XcNDZ
VEQpVyO0JkhlbmRyaWsgV29sZmYgPGhlbmRyaWsud29sZmZAYWdkc24ubWU+iJAE
ExYIADgWIQT7v6wmDZKD0e8jl908pl6d1usxnQUCZNJqYAIbAwULCQgHAgYVCgkI
CwIEFgIDAQIeAQIXgAAKCRA8pl6d1usxnX6zAP9Rut+Yg31zBAiRdQxV4tlK+hko
wCq9WIKtIbBvrqv5/AEAujkRCgBpFeHzhId55QmvK0FXZgFgfy9wm/QtXb4+lQ64
MwRk0mrEFgkrBgEEAdpHDwEBB0AidcMADt+W+eSbrInHeCPZThyd1V7NKEMhk3sL
xJApx4j1BBgWCAAmFiEE+7+sJg2Sg9HvI5fdPKZendbrMZ0FAmTSasQCGwIFCQeE
zgAAgQkQPKZendbrMZ12IAQZFggAHRYhBEK0YmsN4JpCoNWvKp5LZR/BVBjgBQJk
0mrEAAoJEJ5LZR/BVBjg6ogBAOcFh/S99L/aN6bQu9bYRPomakbNqypHA1YbodjG
1IQgAPwLj19BXNnQmTgYzY3bWmtcAc8lsGWTNkDDTZMRRTP+BSS1AP9qBuCeU/fj
2hpa17LiV6sjdRquxWQXjKxTlBRV8oKj1gD/WarlxiHt8nMn527FXuBrGZC+mZq2
NvvoTb+uvZNliAq4OARk0mtEEgorBgEEAZdVAQUBAQdAkK0jBo/37NbRHMOYCal0
9vGuK3KaxU3Cl9No+VbZDEYDAQgHiH4EGBYIACYWIQT7v6wmDZKD0e8jl908pl6d
1usxnQUCZNJrRAIbDAUJB4TOAAAKCRA8pl6d1usxnbaqAP9abTf+DibaAR6hdU9y
CEE5TD32EB+ySw/v45yCi28B8AEA5PcpwMD6emVrNQGeVChkOlwauwA3HkE6DDTO
yeebAwi4MwRk0mvNFgkrBgEEAdpHDwEBB0DSYGCNq15sOLj1wDJjoKoCRMGH8I/y
ARMUws7PQ4KPkYh+BBgWCAAmFiEE+7+sJg2Sg9HvI5fdPKZendbrMZ0FAmTSa80C
GyAFCQeEzgAACgkQPKZendbrMZ1HggEAxSBYuJ4BTr9GCl8e79HTSwg8iIIJx8Nc
REFvro0BrnEA/3AbyQYBQVAhqIwSSza5dr4+FiLbbVhPFcxU98TLBTQJ
=sA2V
-----END PGP PUBLIC KEY BLOCK-----

77
keys/pgp/jonas.asc Normal file
View file

@ -0,0 +1,77 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=Fs3l
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -1,92 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
q0Mleg==
=M2wX
-----END PGP PUBLIC KEY BLOCK-----

78
modules/bacula.nix Normal file
View file

@ -0,0 +1,78 @@
{ pkgs, config, lib, ... }:
with lib;
let
# We write a custom config file because the upstream config has some flaws
fd_cfg = config.services.bacula-fd;
fd_conf = pkgs.writeText "bacula-fd.conf" ''
Client {
Name = ${fd_cfg.name}
FDPort = ${toString fd_cfg.port}
WorkingDirectory = /var/lib/bacula
Pid Directory = /run
${fd_cfg.extraClientConfig}
}
${concatStringsSep "\n" (mapAttrsToList (name: value: ''
Director {
Name = ${name}
Password = ${value.password}
Monitor = ${value.monitor}
}
'') fd_cfg.director)}
Messages {
Name = Standard;
syslog = all, !skipped, !restored
${fd_cfg.extraMessagesConfig}
}
'';
# AGDSN is running an outdated version that we have to comply to
bacula_package = (pkgs.bacula.overrideAttrs (old: rec {
version = "9.6.7";
src = pkgs.fetchurl {
url = "mirror://sourceforge/bacula/${old.pname}-${version}.tar.gz";
sha256 = "sha256-3w+FJezbo4DnS1N8pxrfO3WWWT8CGJtZqw6//IXMyN4=";
};
}));
in
{
sops.secrets = {
"bacula/password".owner = "bacula";
"bacula/keypair".owner = "bacula";
"bacula/masterkey".owner = "bacula";
};
networking.firewall.allowedTCPPorts = [ config.services.bacula-fd.port ];
networking.firewall.allowedUDPPorts = [ config.services.bacula-fd.port ];
services.bacula-fd = {
enable = true;
name = "ifsr-quitte";
extraClientConfig = ''
Maximum Concurrent Jobs = 20
FDAddress = 141.30.30.169
PKI Signatures = Yes
PKI Encryption = Yes
PKI Keypair = ${config.sops.secrets."bacula/keypair".path}
PKI Master Key = ${config.sops.secrets."bacula/masterkey".path}
'';
extraMessagesConfig = ''
director = abel-dir = all, !skipped, !restored
mailcommand = "${bacula_package}/bin/bsmtp -f \"Bacula <bacula@${config.networking.domain}>\" -s \"Bacula report" %r"
mail = root+backup = all, !skipped
'';
director."abel-dir".password = "@${config.sops.secrets."bacula/password".path}";
};
environment.etc."bacula/bconsole.conf".text = ''
Director {
Name = abel-dir
DIRport = 9101
address = 10.144.0.11
Password = @${config.sops.secrets."bacula/password".path}
}
Console {
Name = ifsr-quitte-console
Password = @${config.sops.secrets."bacula/password".path}
}
'';
systemd.services.bacula-fd.serviceConfig.ExecStart = lib.mkForce "${bacula_package}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
}

View file

@ -1,5 +1,6 @@
{ pkgs, config, ... }: {
nix = {
package = pkgs.nixUnstable; # or versioned attributes like nix_2_4
extraOptions = ''
experimental-features = nix-command flakes
'';
@ -10,17 +11,10 @@
echo System package diff:
${config.nix.package}/bin/nix store diff-closures /run/current-system $systemConfig || true
fi
NO_FORMAT="\033[0m"
F_BOLD="\033[1m"
C_RED="\033[38;5;9m"
${pkgs.diffutils}/bin/cmp --silent \
<(readlink /run/current-system/{kernel,kernel-modules}) \
<(readlink $systemConfig/{kernel,kernel-modules}) \
|| echo -e "''${F_BOLD}''${C_RED}Kernel version changed, reboot is advised.''${NO_FORMAT}"
'';
# Select internationalisation properties.
i18n.defaultLocale = "en_US.UTF-8";
console = {
#font = "Lat2-Terminus16";
font = "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz";
@ -28,17 +22,7 @@
};
# Enable the OpenSSH daemon.
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
PasswordAuthentication = false;
};
};
programs.mosh.enable = true;
# vs code server
services.vscode-server.enable = true;
services.openssh.enable = true;
# set root ssh keys
users.users.root.openssh.authorizedKeys = {
@ -56,17 +40,17 @@
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEXMHwy4AZ9B4pMRBa/P/rb7N3SCas9e7Lp89plTHdFS halcyon@eisvogel.moe"
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAJ7qUGZUjiDhQ6Se+aXr9DbgRTG2tx69owqVMkd2bna simon@mayushii"
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLlITzcTVnSi8EpEW3leSuqYCDhbnJyoGCjFOtIJ0Dl5uRNm0UNXS7AbQtLLylEeI1+/qinQDEWAJ6cBDAaPfNw= rouven@thinkpad"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJgYI2rXmw4uPXAMmOgqgJEwYfwj/IBExTCzs9Dgo+R w0lff"
];
keyFiles = [
../../keys/ssh/marcus-sapphire
../../keys/ssh/schrader
../../keys/ssh/jannusch
../../keys/ssh/jannusch-arch
../../keys/ssh/tassilo
../../keys/ssh/jonasga
../../keys/ssh/rouven
../../keys/ssh/joachim
../keys/ssh/marcus-sapphire
../keys/ssh/schrader
../keys/ssh/jannusch
../keys/ssh/jannusch-arch
../keys/ssh/tassilo
../keys/ssh/jonasga
../keys/ssh/rouven
../keys/ssh/joachim
];
};
@ -79,10 +63,9 @@
# $ nix search wget
environment.systemPackages = with pkgs; [
atop
btop
bat
git
htop-vim
htop
fd
ripgrep
tldr
@ -90,7 +73,6 @@
usbutils
wget
neovim
helix
nmap
tcpdump
bat
@ -109,10 +91,8 @@
sysstat
tree
whois
eza
exa
zsh
unzip
yazi
];
}

View file

@ -1,47 +0,0 @@
{ pkgs, config, ... }:
{
sops.secrets = {
"bacula/password".owner = "bacula";
"bacula/keypair".owner = "bacula";
"bacula/masterkey".owner = "bacula";
};
networking.firewall = {
extraInputRules = ''
ip saddr 10.144.0.11 tcp dport ${builtins.toString config.services.bacula-fd.port} accept comment "Only allow Bacula access from Abel"
'';
};
services.bacula-fd = {
enable = true;
name = "ifsr-quitte";
extraClientConfig = ''
Comm Compression = no
Maximum Concurrent Jobs = 20
FDAddress = 141.30.30.169
PKI Signatures = Yes
PKI Encryption = Yes
PKI Keypair = ${config.sops.secrets."bacula/keypair".path}
PKI Master Key = ${config.sops.secrets."bacula/masterkey".path}
'';
extraMessagesConfig = ''
director = abel-dir = all, !skipped, !restored
mailcommand = "${pkgs.bacula}/bin/bsmtp -f \"Bacula <bacula@${config.networking.domain}>\" -s \"Bacula report" %r"
mail = root+backup = all, !skipped
'';
director."abel-dir" = {
password = "@${config.sops.secrets."bacula/password".path}";
tls.enable = false;
};
};
environment.etc."bacula/bconsole.conf".text = ''
Director {
Name = abel-dir
DIRport = 9101
address = 10.144.0.11
Password = @${config.sops.secrets."bacula/password".path}
}
Console {
Name = ifsr-quitte-console
Password = @${config.sops.secrets."bacula/password".path}
}
'';
}

View file

@ -1,15 +0,0 @@
{ ... }: {
imports = [
./base.nix
./logging.nix
./bacula.nix
./fail2ban.nix
./initrd-ssh.nix
./mysql.nix
./nginx.nix
./podman.nix
./postgres.nix
./sssd.nix
./zsh.nix
];
}

View file

@ -1,27 +0,0 @@
{ ... }:
{
services.fail2ban = {
enable = true;
ignoreIP = [
"141.30.0.0/16"
"141.76.0.0/16"
];
bantime-increment = {
enable = true;
};
jails = {
dovecot = ''
enabled = true
# aggressive mode to add blocking for aborted connections
filter = dovecot[mode=aggressive]
maxretry = 3
'';
postfix = ''
enabled = true
filter = postfix[mode=aggressive]
maxretry = 3
'';
};
};
}

View file

@ -1,29 +0,0 @@
# Find the required kernel module for the network adapter using `lspci -v` and add it to `boot.initrd.availableKernelModules`.
# Enable `networking.useDHCP` or set a static ip using the `ip=` kernel parameter.
# Generate another SSH host key for the machine:
# $ ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key_initrd -C HOSTNAME-initrd
# Add the public key to your known_hosts and create an ssh config entry.
{ 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/systemd-tty-ask-password-agent";
};
network = {
enable = true;
ssh = {
enable = true;
port = 222;
hostKeys = [ "/etc/ssh/ssh_host_ed25519_key_initrd" ];
# authorizedKeys option inherits root's authorizedKeys.keys, but not keyFiles
};
};
};
}

View file

@ -1,34 +0,0 @@
{ pkgs, ... }:
{
services.rsyslogd = {
enable = true;
defaultConfig = ''
$FileCreateMode 0640
:programname, isequal, "postfix" /var/log/postfix.log
auth.* -/var/log/auth.log
'';
};
services.logrotate.configFile = pkgs.writeText "logrotate.conf" ''
weekly
missingok
notifempty
rotate 4
"/var/log/postfix.log" {
compress
delaycompress
weekly
rotate 156
}
"/var/log/nginx/*.log" {
compress
delaycompress
weekly
postrotate
[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`
endscript
rotate 26
su nginx nginx
}
'';
}

View file

@ -1,20 +0,0 @@
{ pkgs, ... }:
{
services.mysql = {
enable = true;
package = pkgs.mariadb;
settings.mysqld.bind_address = "127.0.0.1";
};
services.mysqlBackup = {
enable = true;
user = "mysql";
location = "/var/lib/backup/mysql";
databases = [
"decisions"
"fsrewsp"
"nightline"
"wiki_ese"
"wiki_vernetzung"
];
};
}

View file

@ -1,60 +0,0 @@
{ lib, config, pkgs, ... }:
{
# set default options for virtualHosts
options = with lib; {
services.nginx.virtualHosts = mkOption {
type = types.attrsOf (types.submodule
({ name, ... }: {
enableACME = true;
forceSSL = 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;
'';
})
);
};
};
config = {
networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.allowedUDPPorts = [ 443 ];
services.nginx = {
enable = true;
package = pkgs.nginxQuic;
additionalModules = [ pkgs.nginxModules.pam ];
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
# appendHttpConfig = ''
# map $remote_addr $remote_addr_anon {
# ~(?P<ip>\d+\.\d+\.\d+)\. $ip.0;
# ~(?P<ip>[^:]+:[^:]+): $ip::;
# # IP addresses to not anonymize
# 127.0.0.1 $remote_addr;
# ::1 $remote_addr;
# default 0.0.0.0;
# }
# log_format anon_ip '$remote_addr_anon - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
# access_log /var/log/nginx/access.log anon_ip;
# '';
};
security.acme = {
acceptTerms = true;
defaults = {
#server = "https://acme-staging-v02.api.letsencrypt.org/directory";
email = "root@${config.networking.domain}";
};
};
security.pam.services.nginx.text = ''
auth required ${pkgs.nss_pam_ldapd}/lib/security/pam_ldap.so
account required ${pkgs.nss_pam_ldapd}/lib/security/pam_ldap.so
'';
};
}

View file

@ -1,26 +0,0 @@
{ 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
];
}

View file

@ -1,41 +0,0 @@
{ config, ... }:
{
sops.secrets = {
"sssd/env" = { };
};
services.sssd = {
enable = true;
environmentFile = config.sops.secrets."sssd/env".path;
sshAuthorizedKeysIntegration = true;
config = ''
[sssd]
config_file_version = 2
services = nss, pam, ssh
domains = ldap
[ssh]
[nss]
[pam]
[domain/ldap]
auth_provider = ldap
ldap_uri = ldaps://auth.ifsr.de
ldap_default_authtok_type = password
ldap_default_authtok = $SSSD_LDAP_DEFAULT_AUTHTOK
ldap_search_base = dc=ifsr,dc=de
id_provider = ldap
ldap_default_bind_dn = uid=search,ou=users,dc=ifsr,dc=de
cache_credentials = True
ldap_tls_cacert = /etc/ssl/certs/ca-bundle.crt
ldap_tls_reqcert = hard
'';
};
security.pam.services = {
sshd.makeHomeDir = true;
login.makeHomeDir = true;
};
}

View file

@ -1,35 +0,0 @@
{ 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; [
# fzf
bat
duf
];
programs.fzf = {
keybindings = true;
};
programs.zsh = {
enable = true;
autosuggestions = {
enable = true;
highlightStyle = "fg=#00bbbb,bold";
};
# don't override agdsn-zsh-config aliases
shellAliases = lib.mkForce { };
shellInit = ''
zsh-newuser-install () {}
'';
interactiveShellInit = ''
source ${pkgs.zsh-fzf-tab}/share/fzf-tab/fzf-tab.plugin.zsh
HW_CONF_ALIASES_GIT_AUTHOR_REMINDER=0
source ${pkgs.agdsn-zsh-config}/etc/zsh/zshrc
'';
promptInit = "";
};
}

View file

@ -38,28 +38,15 @@ in
enable = lib.mkForce true; # upstream bacula config wants to disable it, so we need to force
ensureUsers = [{
name = "course-management";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE \"course-management\"" = "ALL PRIVILEGES";
};
}];
ensureDatabases = [ "course-management" ];
};
services.nginx.virtualHosts.${hostName} = {
# phil redirects
locations =
let
philDomain = "https://kurse-phil.ifsr.de";
courses = [ "238" "239" "240" "241" "242" "243" ];
subjects = [
"ESE 2023 PHIL Campustour"
"ESE 2023 PHIL Bowlingabend"
"ESE 2023 PHIL Filmabend"
"ESE 2023 PHIL Wandern"
"ESE 2023 PHIL Spieleabend Pen and Paper"
];
in
{
"~ \"^/course/(${builtins.concatStringsSep "|" courses})/\"".return = "301 ${philDomain}/course/$1";
"~ \"^/subject/(${builtins.concatStringsSep "|" subjects})/\"".return = "301 ${philDomain}/subject/$1";
};
enableACME = true;
forceSSL = true;
};
}

View file

@ -1,93 +0,0 @@
{ config, lib, course-management, ... }:
let
hostName = "kurse-phil.${config.networking.domain}";
in
{
services.nginx.virtualHosts."${hostName}" = {
locations."/".proxyPass = "http://127.0.0.1:8084";
enableACME = true;
forceSSL = true;
};
sops.secrets = {
"course-management-phil/secret-key" = { };
"course-management-phil/adminpass" = { };
};
containers."courses-phil" = {
autoStart = true;
extraFlags = [
"--load-credential=course-secret-key:${config.sops.secrets."course-management-phil/secret-key".path}"
"--load-credential=course-adminpass:${config.sops.secrets."course-management-phil/adminpass".path}"
];
config = { config, ... }: {
system.stateVersion = "23.05";
networking.domain = "ifsr.de";
imports = [
course-management.nixosModules.default
];
systemd.services.course-management = {
after = [ "postgresql.service" ];
serviceConfig = {
LoadCredential = [
"secret-key:course-secret-key"
"adminpass:course-adminpass"
];
};
};
services.course-management = {
inherit hostName;
enable = true;
listenPort = 5001;
settings = {
secretKeyFile = "$CREDENTIALS_DIRECTORY/secret-key";
adminPassFile = "$CREDENTIALS_DIRECTORY/adminpass";
admins = [{
name = "Root iFSR";
email = "root@${config.networking.domain}";
}];
database = {
ENGINE = "django.db.backends.postgresql";
NAME = "course-management";
};
email = lib.mkDefault {
fromEmail = "noreply@${config.networking.domain}";
serverEmail = "root@${config.networking.domain}";
};
};
};
security.acme = {
acceptTerms = true;
defaults = {
email = "root@${config.networking.domain}";
};
};
services.postgresql = {
enable = true;
enableTCPIP = lib.mkForce false;
ensureUsers = [{
name = "course-management";
ensureDBOwnership = true;
}];
ensureDatabases = [ "course-management" ];
};
systemd.services.postgresql.serviceConfig.ExecStart = lib.mkForce "${config.services.postgresql.package}/bin/postgres -c listen_addresses=''";
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts.${hostName} = {
listen = [{
addr = "127.0.0.1";
port = 8084;
}];
};
};
};
};
}

View file

@ -1,46 +0,0 @@
{ config, ... }:
let
domain = "decisions.${config.networking.domain}";
in
{
sops.secrets."decisions_env" = { };
virtualisation.oci-containers = {
containers.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
];
};
};
services.nginx = {
virtualHosts."${domain}" = {
locations."/" = {
proxyPass = "http://127.0.0.1:5055";
};
};
};
systemd.timers."decisions-to-db" = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "01:11:00";
Unit = "decisions-to-db.service";
};
};
# systemd.services."decisions-to-db" = {
# script = ''
# set -eu
# ${pkgs.podman}/bin/podman exec decisions python tex_to_db.py
# '';
# serviceConfig = {
# Type = "oneshot";
# User = "root";
# };
# };
}

View file

@ -1,30 +0,0 @@
{ config, pkgs, ... }:
{
sops.secrets."forgejo/runner-token" = { };
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"
];
tokenFile = config.sops.secrets."forgejo/runner-token".path;
url = "https://git.ifsr.de";
name = "quitte";
settings = {
container = {
# use podman's default network, otherwise dns was not working for some reason
network = "podman";
# don't mount the docker socket into the build containers,
# this would basically mean root on the host...
docker_host = "-";
};
};
};
};
}

23
modules/ftp.nix Normal file
View file

@ -0,0 +1,23 @@
{ config, pkgs, ... }:
let
domain = "ftp.${config.networking.domain}";
in
{
services.nginx.additionalModules = [ pkgs.nginxModules.fancyindex ];
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
root = "/srv/ftp";
extraConfig = ''
fancyindex on;
fancyindex_exact_size off;
'';
locations."~/(klausuren|uebungen|skripte|abschlussarbeiten)".extraConfig = ''
allow 141.30.0.0/16;
allow 141.76.0.0/16;
allow 172.16.0.0/16;
deny all;
'';
};
}

View file

@ -1,45 +1,40 @@
{ config, lib, pkgs, ... }:
let
domain = "git.${config.networking.domain}";
gitUser = "git";
giteaUser = "git";
in
{
imports = [
./actions.nix
];
sops.secrets.gitea_ldap_search = {
key = "portunus/search-password";
owner = config.services.forgejo.user;
owner = config.services.gitea.user;
};
users.users.${gitUser} = {
users.users.${giteaUser} = {
isSystemUser = true;
home = config.services.forgejo.stateDir;
group = gitUser;
home = config.services.gitea.stateDir;
group = giteaUser;
useDefaultShell = true;
};
users.groups.${gitUser} = { };
users.groups.${giteaUser} = { };
services.forgejo = {
services.gitea = {
enable = true;
user = gitUser;
group = gitUser;
package = pkgs.forgejo; # community fork
user = giteaUser;
group = giteaUser;
appName = "iFSR Git";
lfs.enable = true;
database = {
type = "postgres";
name = "git"; # legacy
createDatabase = true;
user = gitUser;
user = giteaUser;
};
# TODO: enable periodic dumps of the DB and repos, maybe use this for backups?
# dump = { };
settings = {
DEFAULT = {
APP_NAME = "iFSR Git";
};
server = {
PROTOCOL = "http+unix";
DOMAIN = domain;
@ -47,7 +42,6 @@ in
ROOT_URL = "https://${domain}";
OFFLINE_MODE = true; # disable use of CDNs
};
log.LEVEL = "Warn";
database.LOG_SQL = false;
service = {
DISABLE_REGISTRATION = true;
@ -69,15 +63,12 @@ in
COOKIE_SECURE = true;
PROVIDER = "db";
};
actions.ENABLED = true;
# federation.ENABLED = true;
webhook.ALLOWED_HOST_LIST = "*.ifsr.de";
};
};
systemd.services.forgejo.preStart =
systemd.services.gitea.preStart =
let
exe = lib.getExe config.services.forgejo.package;
exe = lib.getExe config.services.gitea.package;
portunus = config.services.portunus;
basedn = "ou=users,${portunus.ldap.suffix}";
ldapConfigArgs = ''
@ -114,8 +105,10 @@ in
'';
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/";
proxyPass = "http://unix:${config.services.gitea.settings.server.HTTP_ADDR}:/";
proxyWebsockets = true;
};
locations."/api/v1/users/search".return = "403";

View file

@ -14,7 +14,9 @@ in
ensureUsers = [
{
name = "hedgedoc";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE hedgedoc" = "ALL PRIVILEGES";
};
}
];
ensureDatabases = [ "hedgedoc" ];
@ -68,16 +70,12 @@ in
recommendedProxySettings = true;
virtualHosts = {
"${domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://[::1]:${toString config.services.hedgedoc.settings.port}";
proxyWebsockets = true;
};
locations."/robots.txt" = {
extraConfig = ''
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
'';
};
};
};
};

View file

@ -4,7 +4,6 @@ let
in
{
sops.secrets."hydra_ldap_search" = { owner = "hydra"; group = "hydra"; mode = "440"; };
nix.settings.allowed-uris = [ "https://github.com/nix-community" ]; # whitelisted to fetch nix-index
services.hydra = {
enable = true;
port = 4000;
@ -60,6 +59,8 @@ in
};
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString config.services.hydra.port}";
};

View file

@ -1,34 +0,0 @@
{ config, pkgs, ... }:
let
domain = "kanboard.${config.networking.domain}";
domain_short = "kb.${config.networking.domain}";
in
{
sops.secrets."kanboard_env" = { };
virtualisation.oci-containers = {
containers.kanboard = {
image = "ghcr.io/kanboard/kanboard:v1.2.41";
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
];
};
};
services.nginx = {
virtualHosts."${domain_short}" = {
locations."/".return = "301 $scheme://${domain}$request_uri";
};
virtualHosts."${domain}" = {
locations."/" = {
proxyPass = "http://127.0.0.1:8045";
};
};
};
}

View file

@ -1,37 +0,0 @@
{ config, pkgs, ... }:
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";
themes = with pkgs ; {
ifsr = keycloak_ifsr_theme;
};
};
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;
'';
};
};
}

View file

@ -1,15 +0,0 @@
{ stdenv }:
stdenv.mkDerivation rec {
name = "keycloak_ifsr_theme";
version = "1.1";
src = ./theme;
nativeBuildInputs = [ ];
buildInputs = [ ];
installPhase = ''
mkdir -p $out
cp -a login $out
'';
}

View file

@ -1,772 +0,0 @@
.login-pf {
background: none;
}
.login-pf body {
background: url(../img/background.jpg) no-repeat center center fixed;
background-size: cover;
height: 100%;
}
/*IE compatibility*/
.pf-c-form-control {
font-size: 14px;
font-size: var(--pf-global--FontSize--sm);
border-width: 1px;
border-width: var(--pf-global--BorderWidth--sm);;
border-color: #EDEDED #EDEDED #8A8D90 #EDEDED;
border-color: var(--pf-global--BorderColor--300) var(--pf-global--BorderColor--300) var(--pf-global--BorderColor--200) var(--pf-global--BorderColor--300);
background-color: #FFFFFF;
background-color: var(--pf-global--BackgroundColor--100);
height: 36px;
height: calc(var(--pf-c-form-control--FontSize) * var(--pf-c-form-control--LineHeight) + var(--pf-c-form-control--BorderWidth) * 2 + var(--pf-c-form-control--PaddingTop) + var(--pf-c-form-control--PaddingBottom));
padding: 5px 0.5rem;
padding: var(--pf-c-form-control--PaddingTop) var(--pf-c-form-control--PaddingRight) var(--pf-c-form-control--PaddingBottom) var(--pf-c-form-control--PaddingLeft);
}
textarea.pf-c-form-control {
height: auto;
}
.pf-c-form-control:hover, .pf-c-form-control:focus {
border-bottom-color: #0066CC;
border-bottom-color: var(--pf-global--primary-color--100);
border-bottom-width: 2px;
border-bottom-width: var(--pf-global--BorderWidth--md);
}
.pf-c-form-control[aria-invalid=true] {
border-bottom-color: #C9190B;
border-bottom-color: var(--pf-global--danger-color--100);
border-bottom-width: 2px;
border-bottom-width: var(--pf-global--BorderWidth--md);
}
.pf-c-check__label, .pf-c-radio__label {
font-size: 14px;
font-size: var(--pf-global--FontSize--sm);
}
.pf-c-alert.pf-m-inline {
margin-bottom: 0.5rem; /* default - IE compatibility */
margin-bottom: var(--pf-global--spacer--sm);
padding: 0.25rem;
padding: var(--pf-global--spacer--xs);
border: solid #ededed;
border: solid var(--pf-global--BorderColor--300);
border-width: 1px;
border-width: var(--pf-c-alert--m-inline--BorderTopWidth) var(--pf-c-alert--m-inline--BorderRightWidth) var(--pf-c-alert--m-inline--BorderBottomWidth) var(--pf-c-alert--m-inline--BorderLeftWidth);
display: -ms-flexbox;
display: grid;
-ms-grid-columns: max-content 1fr max-content;
grid-template-columns:max-content 1fr max-content;
grid-template-columns: var(--pf-c-alert--grid-template-columns);
grid-template-rows: 1fr auto;
grid-template-rows: var(--pf-c-alert--grid-template-rows);
}
.pf-c-alert.pf-m-inline::before {
position: absolute;
top: -1px;
top: var(--pf-c-alert--m-inline--before--Top);
bottom: -1px;
bottom: var(--pf-c-alert--m-inline--before--Bottom);
left: 0;
width: 3px;
width: var(--pf-c-alert--m-inline--before--Width);
content: ;
background-color: #FFFFFF;
background-color: var(--pf-global--BackgroundColor--100);
}
.pf-c-alert.pf-m-inline.pf-m-success::before {
background-color: #92D400;
background-color: var(--pf-global--success-color--100);
}
.pf-c-alert.pf-m-inline.pf-m-danger::before {
background-color: #C9190B;
background-color: var(--pf-global--danger-color--100);
}
.pf-c-alert.pf-m-inline.pf-m-warning::before {
background-color: #F0AB00;
background-color: var(--pf-global--warning-color--100);
}
.pf-c-alert.pf-m-inline .pf-c-alert__icon {
padding: 1rem 0.5rem 1rem 1rem;
padding: var(--pf-c-alert--m-inline__icon--PaddingTop) var(--pf-c-alert--m-inline__icon--PaddingRight) var(--pf-c-alert--m-inline__icon--PaddingBottom) var(--pf-c-alert--m-inline__icon--PaddingLeft);
font-size: 16px;
font-size: var(--pf-c-alert--m-inline__icon--FontSize);
}
.pf-c-alert.pf-m-success .pf-c-alert__icon {
color: #92D400;
color: var(--pf-global--success-color--100);
}
.pf-c-alert.pf-m-success .pf-c-alert__title {
color: #486B00;
color: var(--pf-global--success-color--200);
}
.pf-c-alert.pf-m-danger .pf-c-alert__icon {
color: #C9190B;
color: var(--pf-global--danger-color--100);
}
.pf-c-alert.pf-m-danger .pf-c-alert__title {
color: #A30000;
color: var(--pf-global--danger-color--200);
}
.pf-c-alert.pf-m-warning .pf-c-alert__icon {
color: #F0AB00;
color: var(--pf-global--warning-color--100);
}
.pf-c-alert.pf-m-warning .pf-c-alert__title {
color: #795600;
color: var(--pf-global--warning-color--200);
}
.pf-c-alert__title {
font-size: 14px; /* default - IE compatibility */
font-size: var(--pf-global--FontSize--sm);
padding: 5px 8px;
padding: var(--pf-c-alert__title--PaddingTop) var(--pf-c-alert__title--PaddingRight) var(--pf-c-alert__title--PaddingBottom) var(--pf-c-alert__title--PaddingLeft);
}
.pf-c-button{
padding:0.375rem 1rem;
padding: var(--pf-global--spacer--form-element) var(--pf-global--spacer--md);
}
/* default - IE compatibility */
.pf-m-primary {
color: #FFFFFF;
background-color: #0066CC;
background-color: var(--pf-global--primary-color--100);
}
/* default - IE compatibility */
.pf-m-primary:hover {
background-color: #004080;
background-color: var(--pf-global--primary-color--200);
}
/* default - IE compatibility */
.pf-c-button.pf-m-control {
border: solid 1px;
border: solid var(--pf-global--BorderWidth--sm);
border-color: rgba(230, 230, 230, 0.5);
}
/*End of IE compatibility*/
h1#kc-page-title {
margin-top: 10px;
}
#kc-locale ul {
background-color: #FFF;
background-color: var(--pf-global--BackgroundColor--100);
display: none;
top: 20px;
min-width: 100px;
padding: 0;
}
#kc-locale-dropdown{
display: inline-block;
}
#kc-locale-dropdown:hover ul {
display:block;
}
/* IE compatibility */
#kc-locale-dropdown a {
color: #6A6E73;
color: var(--pf-global--Color--200);
text-align: right;
font-size: 14px;
font-size: var(--pf-global--FontSize--sm);
}
/* IE compatibility */
a#kc-current-locale-link::after {
content: 2c5;
margin-left: 4px;
margin-left: var(--pf-global--spacer--xs)
}
.login-pf .container {
padding-top: 40px;
}
.login-pf a:hover {
color: #0099d3;
}
#kc-logo {
width: 100%;
}
div.kc-logo-text {
background-image: url(../img/agdsn_logo.png);
background-repeat: no-repeat;
background-size: auto;
position: relative;
top: 0%;
left: 25%;
width: 950px;
height: 250px;
}
div.kc-logo-text span {
display: none;
}
#kc-header {
color: #ededed;
overflow: visible;
white-space: nowrap;
}
#kc-header-wrapper {
font-size: 29px;
text-transform: uppercase;
letter-spacing: 3px;
line-height: 1.2em;
padding: 62px 10px 20px;
white-space: normal;
}
#kc-content {
width: 100%;
}
#kc-attempted-username {
font-size: 20px;
font-family: inherit;
font-weight: normal;
padding-right: 10px;
}
#kc-username {
text-align: center;
margin-bottom:-10px;
}
#kc-webauthn-settings-form {
padding-top: 8px;
}
#kc-form-webauthn .select-auth-box-parent {
pointer-events: none;
}
#kc-form-webauthn .select-auth-box-desc {
color: var(--pf-global--palette--black-600);
}
#kc-form-webauthn .select-auth-box-headline {
color: var(--pf-global--Color--300);
}
#kc-form-webauthn .select-auth-box-icon {
flex: 0 0 3em;
}
#kc-form-webauthn .select-auth-box-icon-properties {
margin-top: 10px;
font-size: 1.8em;
}
#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class {
margin-top: 3px;
}
#kc-form-webauthn .pf-l-stack__item {
margin: -1px 0;
}
#kc-content-wrapper {
margin-top: 20px;
}
#kc-form-wrapper {
margin-top: 10px;
}
#kc-info {
margin: 20px -40px -30px;
}
#kc-info-wrapper {
font-size: 13px;
padding: 15px 35px;
background-color: #F0F0F0;
}
#kc-form-options span {
display: block;
}
#kc-form-options .checkbox {
margin-top: 0;
color: #72767b;
}
#kc-terms-text {
margin-bottom: 20px;
}
#kc-registration {
margin-bottom: 0;
}
/* TOTP */
.subtitle {
text-align: right;
margin-top: 30px;
color: #909090;
}
.required {
color: #A30000; /* default - IE compatibility */
color: var(--pf-global--danger-color--200);
}
ol#kc-totp-settings {
margin: 0;
padding-left: 20px;
}
ul#kc-totp-supported-apps {
margin-bottom: 10px;
}
#kc-totp-secret-qr-code {
max-width:150px;
max-height:150px;
}
#kc-totp-secret-key {
background-color: #fff;
color: #333333;
font-size: 16px;
padding: 10px 0;
}
/* OAuth */
#kc-oauth h3 {
margin-top: 0;
}
#kc-oauth ul {
list-style: none;
padding: 0;
margin: 0;
}
#kc-oauth ul li {
border-top: 1px solid rgba(255, 255, 255, 0.1);
font-size: 12px;
padding: 10px 0;
}
#kc-oauth ul li:first-of-type {
border-top: 0;
}
#kc-oauth .kc-role {
display: inline-block;
width: 50%;
}
/* Code */
#kc-code textarea {
width: 100%;
height: 8em;
}
/* Social */
.kc-social-links {
margin-top: 20px;
}
.kc-social-provider-logo {
font-size: 23px;
width: 30px;
height: 25px;
float: left;
}
.kc-social-gray {
color: #737679; /* default - IE compatibility */
color: var(--pf-global--Color--200);
}
.kc-social-item {
margin-bottom: 0.5rem; /* default - IE compatibility */
margin-bottom: var(--pf-global--spacer--sm);
font-size: 15px;
text-align: center;
}
.kc-social-provider-name {
position: relative;
top: 3px;
}
.kc-social-icon-text {
left: -15px;
}
.kc-social-grid {
display:grid;
grid-column-gap: 10px;
grid-row-gap: 5px;
grid-column-end: span 6;
--pf-l-grid__item--GridColumnEnd: span 6;
}
.kc-social-grid .kc-social-icon-text {
left: -10px;
}
.kc-login-tooltip {
position: relative;
display: inline-block;
}
.kc-social-section {
text-align: center;
}
.kc-social-section hr{
margin-bottom: 10px
}
.kc-login-tooltip .kc-tooltip-text{
top:-3px;
left:160%;
background-color: black;
visibility: hidden;
color: #fff;
min-width:130px;
text-align: center;
border-radius: 2px;
box-shadow:0 1px 8px rgba(0,0,0,0.6);
padding: 5px;
position: absolute;
opacity:0;
transition:opacity 0.5s;
}
/* Show tooltip */
.kc-login-tooltip:hover .kc-tooltip-text {
visibility: visible;
opacity:0.7;
}
/* Arrow for tooltip */
.kc-login-tooltip .kc-tooltip-text::after {
content: ;
position: absolute;
top: 15px;
right: 100%;
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent black transparent transparent;
}
@media (min-width: 768px) {
#kc-container-wrapper {
position: absolute;
width: 100%;
}
.login-pf .container {
padding-right: 80px;
}
#kc-locale {
position: relative;
text-align: right;
z-index: 9999;
}
}
@media (max-width: 767px) {
.login-pf body {
background: white;
}
#kc-header {
padding-left: 15px;
padding-right: 15px;
float: none;
text-align: left;
}
#kc-header-wrapper {
font-size: 16px;
font-weight: bold;
padding: 20px 60px 0 0;
color: #72767b;
letter-spacing: 0;
}
div.kc-logo-text {
margin: 0;
width: 150px;
height: 32px;
background-size: 100%;
}
#kc-form {
float: none;
}
#kc-info-wrapper {
border-top: 1px solid rgba(255, 255, 255, 0.1);
background-color: transparent;
}
.login-pf .container {
padding-top: 15px;
padding-bottom: 15px;
}
#kc-locale {
position: absolute;
width: 200px;
top: 20px;
right: 20px;
text-align: right;
z-index: 9999;
}
}
@media (min-height: 646px) {
#kc-container-wrapper {
bottom: 12%;
}
}
@media (max-height: 645px) {
#kc-container-wrapper {
padding-top: 50px;
top: 20%;
}
}
.card-pf form.form-actions .btn {
float: right;
margin-left: 10px;
}
#kc-form-buttons {
margin-top: 20px;
}
.login-pf-page .login-pf-brand {
margin-top: 20px;
max-width: 360px;
width: 40%;
}
/* Internet Explorer 11 compatibility workaround for select-authenticator screen */
@media all and (-ms-high-contrast: none),
(-ms-high-contrast: active) {
.select-auth-box-parent {
border-top: 1px solid #f0f0f0;
padding-top: 1rem;
padding-bottom: 1rem;
cursor: pointer;
}
.select-auth-box-headline {
font-size: 16px;
color: #06c;
font-weight: bold;
}
.select-auth-box-desc {
font-size: 14px;
}
.pf-l-stack {
flex-basis: 100%;
}
}
/* End of IE11 workaround for select-authenticator screen */
.select-auth-box-arrow{
display: flex;
align-items: center;
margin-right: 2rem;
}
.select-auth-box-icon{
display: flex;
flex: 0 0 2em;
justify-content: center;
margin-right: 1rem;
margin-left: 3rem;
}
.select-auth-box-parent{
border-top: 1px solid var(--pf-global--palette--black-200);
padding-top: 1rem;
padding-bottom: 1rem;
cursor: pointer;
}
.select-auth-box-parent:hover{
background-color: #f7f8f8;
}
.select-auth-container {
}
.select-auth-box-headline {
font-size: var(--pf-global--FontSize--md);
color: var(--pf-global--primary-color--100);
font-weight: bold;
}
.select-auth-box-desc {
font-size: var(--pf-global--FontSize--sm);
}
.select-auth-box-paragraph {
text-align: center;
font-size: var(--pf-global--FontSize--md);
margin-bottom: 5px;
}
.card-pf {
margin: 0 auto;
box-shadow: var(--pf-global--BoxShadow--lg);
padding: 0 20px;
max-width: 500px;
border-top: 4px solid;
border-color: #0066CC; /* default - IE compatibility */
border-color: var(--pf-global--primary-color--100);
}
/*phone*/
@media (max-width: 767px) {
.login-pf-page .card-pf {
max-width: none;
margin-left: 0;
margin-right: 0;
padding-top: 0;
border-top: 0;
box-shadow: 0 0;
}
.kc-social-grid {
grid-column-end: 12;
--pf-l-grid__item--GridColumnEnd: span 12;
}
.kc-social-grid .kc-social-icon-text {
left: -15px;
}
}
.login-pf-page .login-pf-signup {
font-size: 15px;
color: #72767b;
}
#kc-content-wrapper .row {
margin-left: 0;
margin-right: 0;
}
.login-pf-page.login-pf-page-accounts {
margin-left: auto;
margin-right: auto;
}
.login-pf-page .btn-primary {
margin-top: 0;
}
.login-pf-page .list-view-pf .list-group-item {
border-bottom: 1px solid #ededed;
}
.login-pf-page .list-view-pf-description {
width: 100%;
}
#kc-form-login div.form-group:last-of-type,
#kc-register-form div.form-group:last-of-type,
#kc-update-profile-form div.form-group:last-of-type {
margin-bottom: 0px;
}
.no-bottom-margin {
margin-bottom: 0;
}
#kc-back {
margin-top: 5px;
}
/* Recovery codes */
.kc-recovery-codes-warning {
margin-bottom: 32px;
}
.kc-recovery-codes-warning .pf-c-alert__description p {
font-size: 0.875rem;
}
.kc-recovery-codes-list {
list-style: none;
columns: 2;
margin: 16px 0;
padding: 16px 16px 8px 16px;
border: 1px solid #D2D2D2;
}
.kc-recovery-codes-list li {
margin-bottom: 8px;
font-size: 11px;
}
.kc-recovery-codes-list li span {
color: #6A6E73;
width: 16px;
text-align: right;
display: inline-block;
margin-right: 1px;
}
.kc-recovery-codes-actions {
margin-bottom: 24px;
}
.kc-recovery-codes-actions button {
padding-left: 0;
}
.kc-recovery-codes-actions button i {
margin-right: 8px;
}
.kc-recovery-codes-confirmation {
align-items: baseline;
margin-bottom: 16px;
}
/* End Recovery codes */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -1,4 +0,0 @@
parent=keycloak
import=common/keycloak
styles=css/login.css

View file

@ -7,4 +7,9 @@ in
enable = true;
hostName = domain;
};
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
};
}

View file

@ -1,35 +1,25 @@
diff --git a/cmd/portunus-orchestrator/config.go b/cmd/portunus-orchestrator/config.go
index 4db19f2..290128a 100644
--- a/cmd/portunus-orchestrator/config.go
+++ b/cmd/portunus-orchestrator/config.go
@@ -23,7 +23,7 @@ type valueCheck struct {
}
var (
- userOrGroupPattern = `^[a-z_][a-z0-9_-]*\$?$`
+ userOrGroupPattern = `^[a-z_][a-z0-9._-]*\$?$`
envDefaults = map[string]string{
//empty value = not optional
"PORTUNUS_DEBUG": "false",
diff --git a/internal/grammars/grammars.go b/internal/grammars/grammars.go
index 1253c05..e458fd0 100644
--- a/internal/grammars/grammars.go
+++ b/internal/grammars/grammars.go
@@ -39,7 +39,7 @@ const (
// This regex is based on the respective format description in the useradd(8) manpage.
//
// This is only shown for documentation purposes here; use func IsPOSIXAccountName instead.
- POSIXAccountNameRegex = `^[a-z_][a-z0-9_-]*\$?$`
+ POSIXAccountNameRegex = `^[a-z_][a-z0-9._-]*\$?$`
From f5c68898be345fb0dca5ab7b596b9cbe674f5dfb Mon Sep 17 00:00:00 2001
From: Rouven Seifert <rouven@rfive.de>
Date: Tue, 4 Jul 2023 15:14:00 +0200
Subject: [PATCH] update user validation regex
---
internal/core/validation.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/internal/core/validation.go b/internal/core/validation.go
index 3e168b5..10dfc0a 100644
--- a/internal/core/validation.go
+++ b/internal/core/validation.go
@@ -30,7 +30,7 @@ import (
)
//TODO There is also some `import "regexp"` in cmd/orchestrator/ldap.go to render
@@ -159,7 +159,7 @@ func checkByteInPOSIXAccountName(idx, length int, b byte) bool {
switch {
case (b >= 'a' && b <= 'z') || b == '_':
return true
- case (b >= '0' && b <= '9') || b == '-':
+ case (b >= '0' && b <= '9') || b == '-' || b == '.':
return idx != 0 // not allowed at start
default:
return false
//this regexp copied from useradd(8) manpage
-const posixAccountNamePattern = `[a-z_][a-z0-9_-]*\$?`
+const posixAccountNamePattern = `[a-z_][a-z0-9._-]*\$?`
var (
errIsMissing = errors.New("is missing")
--
2.41.0

View file

@ -1,8 +1,8 @@
diff --git a/cmd/portunus-orchestrator/ldap.go b/cmd/portunus-orchestrator/ldap.go
index 9564c5e..40cd2d7 100644
--- a/cmd/portunus-orchestrator/ldap.go
+++ b/cmd/portunus-orchestrator/ldap.go
@@ -134,7 +134,7 @@ func runLDAPServer(environment map[string]string) {
diff --git a/cmd/orchestrator/ldap.go b/cmd/orchestrator/ldap.go
index ed0d466..a672046 100644
--- a/cmd/orchestrator/ldap.go
+++ b/cmd/orchestrator/ldap.go
@@ -130,7 +130,7 @@ func runLDAPServer(environment map[string]string) {
bindURL := "ldap:///"
if environment["PORTUNUS_SLAPD_TLS_CERTIFICATE"] != "" {

View file

@ -1,26 +1,24 @@
diff --git a/internal/ldap/object.go b/internal/ldap/object.go
index d4e5c6f..fcefec7 100644
--- a/internal/ldap/object.go
+++ b/internal/ldap/object.go
@@ -8,6 +8,7 @@ package ldap
diff --git a/internal/core/user.go b/internal/core/user.go
index e74ccfe..291c75b 100644
--- a/internal/core/user.go
+++ b/internal/core/user.go
@@ -8,6 +8,7 @@ package core
import (
"fmt"
+ "regexp"
"github.com/majewsky/portunus/internal/core"
+ "strconv"
)
@@ -94,10 +95,11 @@ func renderUser(u core.User, dnSuffix string, allGroups []core.Group) Object {
if u.POSIX.LoginShell != "" {
// User represents a single user account.
@@ -86,9 +87,9 @@ func (u User) RenderToLDAP(suffix string, allGroups map[string]Group) LDAPObject
obj.Attributes["loginShell"] = []string{u.POSIX.LoginShell}
}
+ var nonASCII = regexp.MustCompile("[^\\x00-\\x7F]")
if u.POSIX.GECOS == "" {
- obj.Attributes["gecos"] = []string{u.FullName()}
+ obj.Attributes["gecos"] = []string{nonASCII.ReplaceAllString(u.FullName(), "")}
+ obj.Attributes["gecos"] = []string{strconv.QuoteToASCII(u.FullName())}
} else {
- obj.Attributes["gecos"] = []string{u.POSIX.GECOS}
+ obj.Attributes["gecos"] = []string{nonASCII.ReplaceAllString(u.POSIX.GECOS, "")}
+ obj.Attributes["gecos"] = []string{strconv.QuoteToASCII(u.POSIX.GECOS)}
}
obj.Attributes["objectClass"] = append(obj.Attributes["objectClass"], "posixAccount")
}

View file

@ -1,20 +1,8 @@
diff --git a/internal/core/user.go b/internal/core/user.go
index f45fdf7..4f93b37 100644
index e74ccfe..ce03eeb 100644
--- a/internal/core/user.go
+++ b/internal/core/user.go
@@ -76,7 +76,6 @@ func (u User) validateLocal(cfg *ValidationConfig) (errs errext.ErrorSet) {
MustBePosixAccountNameIf(u.LoginName, u.POSIX != nil),
))
errs.Add(ref.Field("given_name").WrapFirst(
- MustNotBeEmpty(u.GivenName),
MustNotHaveSurroundingSpaces(u.GivenName),
))
errs.Add(ref.Field("family_name").WrapFirst(
diff --git a/internal/ldap/object.go b/internal/ldap/object.go
index d4e5c6f..1225084 100644
--- a/internal/ldap/object.go
+++ b/internal/ldap/object.go
@@ -73,7 +73,6 @@ func renderUser(u core.User, dnSuffix string, allGroups []core.Group) Object {
@@ -64,7 +64,6 @@ func (u User) RenderToLDAP(suffix string, allGroups map[string]Group) LDAPObject
"uid": {u.LoginName},
"cn": {u.FullName()},
"sn": {u.FamilyName},
@ -22,7 +10,7 @@ index d4e5c6f..1225084 100644
"userPassword": {u.PasswordHash},
"isMemberOf": memberOfGroupDNames,
"objectClass": {"portunusPerson", "inetOrgPerson", "organizationalPerson", "person", "top"},
@@ -83,6 +82,9 @@ func renderUser(u core.User, dnSuffix string, allGroups []core.Group) Object {
@@ -74,6 +73,9 @@ func (u User) RenderToLDAP(suffix string, allGroups map[string]Group) LDAPObject
if u.EMailAddress != "" {
obj.Attributes["mail"] = []string{u.EMailAddress}
}
@ -32,3 +20,15 @@ index d4e5c6f..1225084 100644
if len(u.SSHPublicKeys) > 0 {
obj.Attributes["sshPublicKey"] = u.SSHPublicKeys
}
diff --git a/internal/frontend/users.go b/internal/frontend/users.go
index 225c5b3..1a961ca 100644
--- a/internal/frontend/users.go
+++ b/internal/frontend/users.go
@@ -168,7 +168,6 @@ func buildUserMasterdataFieldset(e core.Engine, u *core.User, state *h.FormState
Name: "given_name",
Label: "Given name",
Rules: []h.ValidationRule{
- core.MustNotBeEmpty,
core.MustNotHaveSurroundingSpaces,
},
},

View file

@ -1,7 +1,7 @@
{ config, pkgs, ... }:
{ config, lib, pkgs, ... }:
let
domain = "auth.${config.networking.domain}";
seedSettings = {
seed = {
groups = [
{
name = "admins";
@ -46,6 +46,11 @@ 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;
nslcd_ldap_search = {
key = "portunus/search-password";
owner = config.systemd.services.nslcd.serviceConfig.User;
};
};
services.portunus = {
@ -57,11 +62,13 @@ in
./0003-gecos-ascii-escape.patch
./0004-make-givenName-optional.patch
];
doCheck = false; # posix regex related tests break
});
inherit domain seedSettings;
inherit domain;
port = 8681;
dex.enable = true;
seedPath = pkgs.writeText "portunus-seed.json" (builtins.toJSON seed);
ldap = {
suffix = "dc=ifsr,dc=de";
searchUserName = "search";
@ -72,19 +79,47 @@ in
};
};
services.dex.settings.oauth2.skipApprovalScreen = true;
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 = { };
ldap =
let portunus = config.services.portunus; in
rec {
enable = true;
server = "ldap://localhost";
base = "${portunus.ldap.suffix}";
bind = {
distinguishedName = "uid=${portunus.ldap.searchUserName},ou=users,${base}";
passwordFile = config.sops.secrets.nslcd_ldap_search.path;
};
daemon.enable = true;
};
};
security.pam.services.sshd.makeHomeDir = true;
services.nginx = {
enable = true;
virtualHosts."${config.services.portunus.domain}" = {
forceSSL = true;
enableACME = true;
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, 141.30.30.169, 10.88.0.1/16 } tcp dport 636 accept comment "Allow ldaps access from office nets and podman"
'';
};
}

View file

@ -1,17 +1,298 @@
{ config, ... }:
{ config, pkgs, ... }:
let
hostname = "mail.${config.networking.domain}";
domain = config.networking.domain;
rspamd-domain = "rspamd.${config.networking.domain}";
dovecot-ldap-args = pkgs.writeText "ldap-args" ''
uris = ldap://localhost
dn = uid=search, ou=users, dc=ifsr, dc=de
auth_bind = yes
!include ${config.sops.secrets."dovecot_ldap_search".path}
ldap_version = 3
scope = subtree
base = dc=ifsr, dc=de
user_filter = (&(objectClass=posixAccount)(uid=%n))
pass_filter = (&(objectClass=posixAccount)(uid=%n))
'';
# see https://www.kuketz-blog.de/e-mail-anbieter-ip-stripping-aus-datenschutzgruenden/
header_cleanup = pkgs.writeText "header_cleanup_outgoing" ''
/^\s*(Received: from)[^\n]*(.*)/ REPLACE $1 127.0.0.1 (localhost [127.0.0.1])$2
/^\s*User-Agent/ IGNORE
/^\s*X-Enigmail/ IGNORE
/^\s*X-Mailer/ IGNORE
/^\s*X-Originating-IP/ IGNORE
/^\s*Mime-Version/ IGNORE
'';
in
{
imports = [
./postfix.nix
./dovecot2.nix
./rspamd.nix
./sogo.nix
./mailman.nix
];
sops.secrets."rspamd-password".owner = config.users.users.rspamd.name;
sops.secrets."dovecot_ldap_search".owner = config.services.dovecot2.user;
sops.secrets."postfix_ldap_aliases".owner = config.services.postfix.user;
security.acme.certs."${hostname}" = {
networking.firewall.allowedTCPPorts = [
25 # insecure SMTP
143
465
587 # SMTP
993 # IMAP
4190 # sieve
];
users.users.postfix.extraGroups = [ "opendkim" ];
environment.etc = {
"dovecot/sieve-pipe/sa-learn-spam.sh" = {
text = ''
#!/bin/sh
${pkgs.rspamd}/bin/rspamc learn_spam
'';
mode = "0555";
};
"dovecot/sieve-pipe/sa-learn-ham.sh" = {
text = ''
#!/bin/sh
${pkgs.rspamd}/bin/rspamc learn_ham
'';
mode = "0555";
};
"dovecot/sieve/report-spam.sieve" = {
source = ./report-spam.sieve;
user = "dovecot2";
group = "dovecot2";
mode = "0544";
};
"dovecot/sieve/report-ham.sieve" = {
source = ./report-ham.sieve;
user = "dovecot2";
group = "dovecot2";
mode = "0544";
};
};
services = {
postfix = {
enable = true;
enableSubmission = true;
enableSubmissions = true;
hostname = "${hostname}";
domain = "${domain}";
origin = "${domain}";
destination = [ "${hostname}" "${domain}" "localhost" ];
networksStyle = "host"; # localhost and own public IP
sslCert = "/var/lib/acme/${hostname}/fullchain.pem";
sslKey = "/var/lib/acme/${hostname}/key.pem";
relayDomains = [ "hash:/var/lib/mailman/data/postfix_domains" ];
config = {
home_mailbox = "Maildir/";
# hostname used in helo command. It is recommended to have this match the reverse dns entry
smtp_helo_name = config.networking.rDNS;
smtp_use_tls = true;
# smtp_tls_security_level = "encrypt";
smtpd_use_tls = true;
# smtpd_tls_security_level = lib.mkForce "encrypt";
# smtpd_tls_auth_only = true;
smtpd_tls_protocols = [
"!SSLv2"
"!SSLv3"
"!TLSv1"
"!TLSv1.1"
];
# "reject_non_fqdn_hostname"
smtpd_recipient_restrictions = [
"permit_sasl_authenticated"
"permit_mynetworks"
"reject_unauth_destination"
"reject_non_fqdn_sender"
"reject_non_fqdn_recipient"
"reject_unknown_sender_domain"
"reject_unknown_recipient_domain"
"reject_unauth_destination"
"reject_unauth_pipelining"
"reject_invalid_hostname"
"check_policy_service inet:localhost:12340"
];
smtpd_relay_restrictions = [
"permit_sasl_authenticated"
"permit_mynetworks"
"reject_unauth_destination"
];
smtp_header_checks = "pcre:${header_cleanup}";
# smtpd_sender_login_maps = [ "ldap:${ldap-senders}" ];
alias_maps = [ "hash:/etc/aliases" ];
alias_database = [ "hash:/etc/aliases" ];
# alias_maps = [ "hash:/etc/aliases" "ldap:${ldap-aliases}" ];
smtpd_milters = [ "local:/run/opendkim/opendkim.sock" ];
non_smtpd_milters = [ "local:/var/run/opendkim/opendkim.sock" ];
smtpd_sasl_auth_enable = true;
smtpd_sasl_path = "/var/lib/postfix/auth";
smtpd_sasl_type = "dovecot";
#mailman stuff
mailbox_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
virtual_alias_maps = [ "hash:/var/lib/mailman/data/postfix_vmap" ];
local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" "ldap:${config.sops.secrets."postfix_ldap_aliases".path}" "$alias_maps" ];
};
};
dovecot2 = {
enable = true;
enableImap = true;
enableQuota = true;
quotaGlobalPerUser = "10G";
enableLmtp = true;
mailLocation = "maildir:~/Maildir";
sslServerCert = "/var/lib/acme/${hostname}/fullchain.pem";
sslServerKey = "/var/lib/acme/${hostname}/key.pem";
protocols = [ "imap" "sieve" ];
mailPlugins = {
perProtocol = {
imap = {
enable = [ "imap_sieve" ];
};
lmtp = {
enable = [ "sieve" ];
};
};
};
mailboxes = {
Spam = {
auto = "subscribe";
specialUse = "Junk";
autoexpunge = "60d";
};
Sent = {
auto = "subscribe";
specialUse = "Sent";
};
Drafts = {
auto = "subscribe";
specialUse = "Drafts";
};
Trash = {
auto = "subscribe";
specialUse = "Trash";
};
};
modules = [
pkgs.dovecot_pigeonhole
];
extraConfig = ''
auth_username_format = %Ln
passdb {
driver = ldap
args = ${dovecot-ldap-args}
}
userdb {
driver = ldap
args = ${dovecot-ldap-args}
}
service auth {
unix_listener /var/lib/postfix/auth {
group = postfix
mode = 0660
user = postfix
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
service_count = 1
}
namespace inbox {
separator = /
inbox = yes
}
service lmtp {
unix_listener dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
client_limit = 1
}
mail_plugins = $mail_plugins listescape
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_global_extensions = +vnd.dovecot.pipe
sieve_pipe_bin_dir = /etc/dovecot/sieve-pipe
# Spam: From elsewhere to Spam folder or flag changed in Spam folder
imapsieve_mailbox1_name = Spam
imapsieve_mailbox1_causes = COPY APPEND FLAG
imapsieve_mailbox1_before = file:/etc/dovecot/sieve/report-spam.sieve
# Ham: From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Spam
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/etc/dovecot/sieve/report-ham.sieve
# https://doc.dovecot.org/configuration_manual/plugins/listescape_plugin/
listescape_char = "\\"
}
'';
};
opendkim = {
enable = true;
domains = "csl:${config.networking.domain}";
selector = config.networking.hostName;
configFile = pkgs.writeText "opendkim-config" ''
UMask 0117
'';
};
rspamd = {
enable = true;
postfix.enable = true;
locals = {
"worker-controller.inc".source = config.sops.secrets."rspamd-password".path;
"redis.conf".text = ''
read_servers = "127.0.0.1";
write_servers = "127.0.0.1";
'';
# headers in spamassasin style to not break old sieve scripts
"worker-proxy.inc".text = ''
spam_header = "X-Spam-Flag";
'';
"milter_headers.conf".text = ''
use = ["x-spam-level", "x-spam-status"];
'';
};
};
redis = {
vmOverCommit = true;
servers.rspamd = {
enable = true;
port = 6379;
};
};
nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts."${hostname}" = {
forceSSL = true;
enableACME = true;
};
virtualHosts."${rspamd-domain}" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://127.0.0.1:11334";
proxyWebsockets = true;
};
};
};
};
};
security.acme.certs."${domain}" = {
reloadServices = [
"postfix.service"
"dovecot2.service"

View file

@ -1,158 +0,0 @@
{ lib, config, pkgs, ... }:
let
hostname = "mail.${config.networking.domain}";
dovecot-ldap-args = pkgs.writeText "ldap-args" ''
uris = ldap://localhost
dn = uid=search, ou=users, dc=ifsr, dc=de
auth_bind = yes
!include ${config.sops.secrets."dovecot_ldap_search".path}
ldap_version = 3
scope = subtree
base = dc=ifsr, dc=de
user_filter = (&(objectClass=posixAccount)(uid=%n))
pass_filter = (&(objectClass=posixAccount)(uid=%n))
'';
in
{
networking.firewall.allowedTCPPorts = [
993 # IMAPS
4190 # Managesieve
];
sops.secrets."dovecot_ldap_search".owner = config.services.dovecot2.user;
services.dovecot2 = {
enable = true;
enableImap = true;
enableQuota = true;
quotaGlobalPerUser = "10G";
enableLmtp = true;
enablePAM = false;
mailLocation = "maildir:~/Maildir";
sslServerCert = "/var/lib/acme/${hostname}/fullchain.pem";
sslServerKey = "/var/lib/acme/${hostname}/key.pem";
protocols = [ "imap" "sieve" ];
mailPlugins = {
globally.enable = [ "listescape" ];
perProtocol = {
imap = {
enable = [ "imap_sieve" "imap_filter_sieve" ];
};
lmtp = {
enable = [ "sieve" ];
};
};
};
mailboxes = {
Spam = {
auto = "subscribe";
specialUse = "Junk";
autoexpunge = "60d";
};
Sent = {
auto = "subscribe";
specialUse = "Sent";
};
Drafts = {
auto = "subscribe";
specialUse = "Drafts";
};
Trash = {
auto = "subscribe";
specialUse = "Trash";
};
Archive = {
auto = "no";
specialUse = "Archive";
};
};
modules = [
pkgs.dovecot_pigeonhole
];
# set to satisfy the sieveScripts check, will be overridden by userdb lookups anyways
mailUser = "vmail";
mailGroup = "vmail";
sieve = {
# just pot something in here to prevent empty strings
extensions = [ "notify" ];
pipeBins = map lib.getExe [
(pkgs.writeShellScriptBin "learn-ham.sh" "exec ${pkgs.rspamd}/bin/rspamc learn_ham")
(pkgs.writeShellScriptBin "learn-spam.sh" "exec ${pkgs.rspamd}/bin/rspamc learn_spam")
];
plugins = [
"sieve_imapsieve"
"sieve_extprograms"
];
scripts = {
before = pkgs.writeText "spam.sieve" ''
require "fileinto";
if anyof(
header :contains "x-spam-flag" "yes",
header :contains "X-Spam-Status" "Yes"){
fileinto "Spam";
}
'';
};
};
imapsieve.mailbox = [
{
# Spam: From elsewhere to Spam folder or flag changed in Spam folder
name = "Spam";
causes = [ "COPY" "APPEND" "FLAG" ];
before = ./report-spam.sieve;
}
{
# From Junk folder to elsewhere
name = "*";
from = "Spam";
causes = [ "COPY" ];
before = ./report-ham.sieve;
}
];
extraConfig = ''
auth_username_format = %Ln
passdb {
driver = ldap
args = ${dovecot-ldap-args}
}
userdb {
driver = ldap
args = ${dovecot-ldap-args}
}
service auth {
unix_listener /var/lib/postfix/auth {
group = postfix
mode = 0660
user = postfix
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
service_count = 1
}
namespace inbox {
separator = /
inbox = yes
}
service lmtp {
unix_listener dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
client_limit = 1
}
plugin {
# https://doc.dovecot.org/configuration_manual/plugins/listescape_plugin/
listescape_char = "\\"
}
'';
};
}

View file

@ -1,98 +0,0 @@
{ config, pkgs, ... }:
let
domain = config.networking.domain;
hostname = "mail.${config.networking.domain}";
# see https://www.kuketz-blog.de/e-mail-anbieter-ip-stripping-aus-datenschutzgruenden/
header_cleanup = pkgs.writeText "header_cleanup_outgoing" ''
/^\s*(Received: from)[^\n]*(.*)/ REPLACE $1 127.0.0.1 (localhost [127.0.0.1])$2
/^\s*User-Agent/ IGNORE
/^\s*X-Enigmail/ IGNORE
/^\s*X-Mailer/ IGNORE
/^\s*X-Originating-IP/ IGNORE
/^\s*Mime-Version/ IGNORE
'';
# https://unix.stackexchange.com/questions/294300/postfix-prevent-users-from-changing-the-real-e-mail-address
login_maps = pkgs.writeText "login_maps.pcre" ''
# basic username => username@ifsr.de
/^([^@+]*)(\+[^@]*)?@ifsr\.de$/ ''${1}
'';
in
{
sops.secrets."postfix_ldap_aliases".owner = config.services.postfix.user;
networking.firewall.allowedTCPPorts = [
25 # SMTP
465 # Submissions
587 # Submission
];
services = {
postfix = {
enable = true;
enableSubmission = true;
enableSubmissions = true;
hostname = "${hostname}";
domain = "${domain}";
origin = "${domain}";
destination = [ "${hostname}" "${domain}" "localhost" ];
networksStyle = "host"; # localhost and own public IP
sslCert = "/var/lib/acme/${hostname}/fullchain.pem";
sslKey = "/var/lib/acme/${hostname}/key.pem";
config = {
home_mailbox = "Maildir/";
# 25 MiB
message_size_limit = "26214400";
# hostname used in helo command. It is recommended to have this match the reverse dns entry
smtp_helo_name = config.networking.rDNS;
smtpd_banner = "${config.networking.rDNS} ESMTP $mail_name";
smtp_tls_security_level = "may";
smtpd_tls_security_level = "may";
smtpd_tls_auth_only = true;
smtpd_tls_protocols = [
"!SSLv2"
"!SSLv3"
"!TLSv1"
"!TLSv1.1"
];
# "reject_non_fqdn_hostname"
smtpd_recipient_restrictions = [
"permit_sasl_authenticated"
"permit_mynetworks"
"reject_unauth_destination"
"reject_non_fqdn_sender"
"reject_non_fqdn_recipient"
"reject_unknown_sender_domain"
"reject_unknown_recipient_domain"
"reject_unauth_destination"
"reject_unauth_pipelining"
"reject_invalid_hostname"
"check_policy_service inet:localhost:12340"
];
smtpd_relay_restrictions = [
"permit_sasl_authenticated"
"permit_mynetworks"
"reject_unauth_destination"
];
# https://www.postfix.org/smtp-smuggling.html
smtpd_data_restrictions = [
"reject_unauth_pipelining"
];
smtpd_sender_restrictions = [
"reject_authenticated_sender_login_mismatch"
];
smtpd_sender_login_maps = [
"pcre:/etc/special-aliases.pcre"
"pcre:${login_maps}"
];
smtp_header_checks = "pcre:${header_cleanup}";
# smtpd_sender_login_maps = [ "ldap:${ldap-senders}" ];
alias_maps = [ "hash:/etc/aliases" ];
alias_database = [ "hash:/etc/aliases" ];
# alias_maps = [ "hash:/etc/aliases" "ldap:${ldap-aliases}" ];
smtpd_sasl_auth_enable = true;
smtpd_sasl_path = "/var/lib/postfix/auth";
smtpd_sasl_type = "dovecot";
local_recipient_maps = [ "ldap:${config.sops.secrets."postfix_ldap_aliases".path}" "$alias_maps" ];
};
};
};
}

View file

@ -12,4 +12,4 @@ if environment :matches "imap.user" "*" {
set "username" "${1}";
}
pipe :copy "learn-ham.sh" [ "${username}" ];
pipe :copy "sa-learn-ham.sh" [ "${username}" ];

View file

@ -4,4 +4,4 @@ if environment :matches "imap.user" "*" {
set "username" "${1}";
}
pipe :copy "learn-spam.sh" [ "${username}" ];
pipe :copy "sa-learn-spam.sh" [ "${username}" ];

View file

@ -1,218 +0,0 @@
{ config, pkgs, ... }:
let
domain = "rspamd.${config.networking.domain}";
in
{
sops.secrets."rspamd-password".owner = config.users.users.rspamd.name;
users.users.rspamd.extraGroups = [ "redis-rspamd" ];
services = {
rspamd = {
enable = true;
postfix.enable = true;
locals = {
"worker-controller.inc".source = config.sops.secrets."rspamd-password".path;
"redis.conf".text = ''
read_servers = "/run/redis-rspamd/redis.sock";
write_servers = "/run/redis-rspamd/redis.sock";
'';
# headers in spamassasin style to not break old sieve scripts
"worker-proxy.inc".text = ''
spam_header = "X-Spam-Flag";
'';
"milter_headers.conf".text = ''
use = ["x-spam-level", "x-spam-status", "x-spamd-result", "authentication-results" ];
'';
"neural.conf".text = ''
servers = "/run/redis-rspamd/redis.sock";
enabled = true;
'';
"neural_group.conf".text = ''
symbols = {
"NEURAL_SPAM" {
weight = 0.5; # fairly low weight since we don't know how this will behave
description = "Neural network spam";
}
"NEURAL_HAM" {
weight = -0.5;
description = "Neural network ham";
}
}
'';
"dmarc.conf".text = ''
reporting {
enabled = true;
email = 'noreply-dmarc@${config.networking.domain}';
domain = '${config.networking.domain}';
org_name = '${config.networking.domain}';
from_name = 'DMARC Aggregate Report';
}
'';
"dkim_signing.conf".text = ''
selector = "quitte2024";
allow_username_mismatch = true;
allow_hdrfrom_mismatch = true;
use_domain_sign_local = "ifsr.de";
path = /var/lib/rspamd/dkim/$domain.$selector.key;
'';
"reputation.conf".text = ''
rules {
ip_reputation = {
selector "ip" {
}
backend "redis" {
servers = "/run/redis-rspamd/redis.sock";
}
symbol = "IP_REPUTATION";
}
spf_reputation = {
selector "spf" {
}
backend "redis" {
servers = "/run/redis-rspamd/redis.sock";
}
symbol = "SPF_REPUTATION";
}
dkim_reputation = {
selector "dkim" {
}
backend "redis" {
servers = "/run/redis-rspamd/redis.sock";
}
symbol = "DKIM_REPUTATION"; # Also adjusts scores for DKIM_ALLOW, DKIM_REJECT
}
generic_reputation = {
selector "generic" {
selector = "ip"; # see https://rspamd.com/doc/configuration/selectors.html
}
backend "redis" {
servers = "/run/redis-rspamd/redis.sock";
}
symbol = "GENERIC_REPUTATION";
}
}
'';
"groups.conf".text = ''
group "reputation" {
symbols = {
"IP_REPUTATION_HAM" {
weight = 1.0;
}
"IP_REPUTATION_SPAM" {
weight = 4.0;
}
"DKIM_REPUTATION" {
weight = 1.0;
}
"SPF_REPUTATION_HAM" {
weight = 1.0;
}
"SPF_REPUTATION_SPAM" {
weight = 2.0;
}
"GENERIC_REPUTATION" {
weight = 1.0;
}
}
}
'';
"multimap.conf".text =
let
local_ips = pkgs.writeText "localhost.map" ''
::1
127.0.0.1
'';
tud_ips = pkgs.writeText "tud.map" ''
141.30.0.0/16
141.76.0.0/16
'';
in
''
WHITELIST_SENDER_DOMAIN {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/whitelist.sender.domain.map";
action = "accept";
regexp = true;
}
WHITELIST_SENDER_EMAIL {
type = "from";
map = "/var/lib/rspamd/whitelist.sender.email.map";
action = "accept";
regexp = true;
}
BLACKLIST_SENDER_DOMAIN {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/blacklist.sender.domain.map";
action = "reject";
regexp = true;
}
BLACKLIST_SENDER_EMAIL {
type = "from";
map = "/var/lib/rspamd/blacklist.sender.email.map";
action = "reject";
regexp = true;
}
BLACKLIST_SUBJECT_KEYWORDS {
type = "header";
header = "Subject"
map = "/var/lib/rspamd/blacklist.keyword.subject.map";
action = "reject";
regexp = true;
}
RECEIVED_LOCALHOST {
type = "ip";
action = "accept";
map = ${local_ips};
}
RECEIVED_TU_NETWORKS {
type = "ip";
map = ${tud_ips};
}
'';
};
};
redis = {
vmOverCommit = true;
servers.rspamd = {
enable = true;
};
};
nginx = {
virtualHosts."${domain}" = {
locations = {
"/" = {
proxyPass = "http://127.0.0.1:11334";
proxyWebsockets = true;
extraConfig = ''
allow 141.30.0.0/16;
allow 141.76.0.0/16;
deny all;
'';
};
};
};
};
};
systemd = {
services.rspamd-dmarc-report = {
description = "rspamd dmarc reporter";
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.rspamd}/bin/rspamadm dmarc_report -v";
User = "rspamd";
Group = "rspamd";
};
startAt = "daily";
};
};
}

View file

@ -20,10 +20,8 @@
webSettings = {
DATABASES.default = {
ENGINE = "django.db.backends.postgresql";
NAME = "mailman-web";
NAME = "mailmanweb";
};
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = false;
ACCOUNT_PREVENT_ENUMERATION = false;
};
ldap = {
enable = true;
@ -42,43 +40,26 @@
superUserGroup = "cn=admins,ou=groups,dc=ifsr,dc=de";
};
};
services.postfix = {
relayDomains = [ "hash:/var/lib/mailman/data/postfix_domains" ];
config = {
mailbox_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
virtual_alias_maps = [ "hash:/var/lib/mailman/data/postfix_vmap" ];
local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
};
};
services.postgresql = {
enable = true;
ensureUsers = [
{
name = "mailman";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE mailman" = "ALL PRIVILEGES";
};
}
{
name = "mailman-web";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE mailmanweb" = "ALL PRIVILEGES";
};
}
];
ensureDatabases = [ "mailman" "mailman-web" ];
ensureDatabases = [ "mailman" "mailmanweb" ];
};
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;
return 200 "User-agent: *\nDisallow: /\n";
'';
};
enableACME = true;
forceSSL = true;
};
}

View file

@ -1,7 +1,7 @@
{ config, pkgs, ... }:
let
domainServer = "matrix.${config.networking.domain}";
domainClient = "chat.${config.networking.domain}";
domainServer = "matrix.staging.${config.networking.domain}";
domainClient = "chat.staging.${config.networking.domain}";
clientConfig = {
"m.homeserver" = {
@ -19,17 +19,15 @@ let
return 200 '${builtins.toJSON data}';
'';
matrix-synapse-ldap3 = config.services.matrix-synapse.package.plugins.matrix-synapse-ldap3;
# build ldap3 plugin from git because it's very outdated in nixpkgs
matrix-synapse-ldap3 = pkgs.python3.pkgs.callPackage ../pkgs/matrix-synapse-ldap3.nix { };
# matrix-synapse-ldap3 = config.services.matrix-synapse.package.plugins.matrix-synapse-ldap3;
in
{
imports = [ ./mautrix-telegram.nix ];
sops.secrets.matrix_ldap_search = {
key = "portunus/search-password";
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
};
nixpkgs.config.permittedInsecurePackages = [
"olm-3.2.16"
];
services = {
postgresql = {
@ -44,6 +42,9 @@ in
virtualHosts = {
# synapse
"${domainServer}" = {
enableACME = true;
forceSSL = true;
# homeserver discovery
locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
@ -58,12 +59,12 @@ in
# element
"${domainClient}" = {
enableACME = true;
forceSSL = true;
root = pkgs.element-web.override {
conf = {
default_server_config = {
inherit (clientConfig) "m.homeserver";
"m.identity_server".base_url = "";
};
default_server_config = clientConfig;
disable_3pid_login = true;
};
};
@ -76,10 +77,6 @@ in
plugins = [ matrix-synapse-ldap3 ];
log = {
root.level = "WARNING";
};
settings = {
server_name = domainServer;

View file

@ -10,7 +10,9 @@ in
enable = true;
ensureUsers = [{
name = "mautrix-telegram";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE \"mautrix-telegram\"" = "ALL PRIVILEGES";
};
}];
ensureDatabases = [ "mautrix-telegram" ];
};
@ -44,13 +46,12 @@ in
# Use postgresql instead of sqlite
database = "postgresql:///mautrix-telegram?host=/run/postgresql";
port = 8082;
address = "http://localhost:${toString port}";
address = "localhost:${toString port}";
};
bridge = {
relaybot.authless_portals = false;
permissions = {
# Add yourself here temporarily
"@admin:${homeserverDomain}" = "admin";
};
relay_user_distinguishers = [ ];

View file

@ -1,52 +0,0 @@
{ pkgs, config, lib, ... }:
{
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"minecraft-server"
];
services.minecraft-servers = {
enable = true;
eula = true;
servers.ifsr = {
enable = true;
package = pkgs.fabricServers.fabric-1_21;
jvmOpts = "-Xmx8192M -Xms8192M";
};
};
services.bluemap = {
enable = true;
host = "map.mc.ifsr.de";
eula = true;
onCalendar = "hourly";
defaultWorld = "/srv/minecraft/ifsr/world";
};
services.nginx.virtualHosts."map.mc.ifsr.de".extraConfig = ''
allow 141.30.0.0/16;
allow 141.76.0.0/16;
allow 217.160.244.15/32; # jonas uptime kuma
deny all;
'';
networking.firewall = {
extraInputRules = ''
ip saddr { 141.30.0.0/16, 141.76.0.0/16, 217.160.244.15/32 } tcp dport 25565 accept comment "Allow minecraft access from TU network and jonas monitoring"
'';
};
users.users.minecraft = {
isNormalUser = true;
isSystemUser = lib.mkForce false;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILkxTuzjS3EswMfj+wSKu9ciRyStvjDlDUXzkqEUGDaP rouven@thinkpad"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOhdjiPvtAo/ZV36RjBBPSlixzeP3VN6cqa4YAmM5uXM ff00005@ff00005-laptop" # malte
];
};
security.sudo.extraRules = [
{
users = [ "minecraft" ];
commands = [
{ command = "/run/current-system/sw/bin/systemctl restart minecraft-server-ifsr"; options = [ "NOPASSWD" ]; }
{ command = "/run/current-system/sw/bin/systemctl start minecraft-server-ifsr"; options = [ "NOPASSWD" ]; }
{ command = "/run/current-system/sw/bin/systemctl stop minecraft-server-ifsr"; options = [ "NOPASSWD" ]; }
];
}
];
}

View file

@ -1,90 +0,0 @@
{ 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;
};
};
scrapeConfigs = [
{
job_name = "node";
static_configs = [{
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ];
}];
scrape_interval = "15s";
}
{
job_name = "rspamd";
static_configs = [{
targets = [ "rspamd.ifsr.de:11334" ];
}];
scrape_interval = "15s";
}
];
};
# nginx reverse proxy
services.nginx.virtualHosts.${domain} = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}";
proxyWebsockets = true;
};
};
}

View file

@ -1,6 +1,7 @@
{ config, pkgs, lib, ... }:
let
domain = "nc.${config.networking.domain}";
domain = "nc.staging.${config.networking.domain}";
legacy_domain = "oc.${config.networking.domain}";
in
{
sops.secrets = {
@ -14,8 +15,8 @@ in
services = {
nextcloud = {
enable = true;
configureRedis = true;
package = pkgs.nextcloud29;
package = pkgs.nextcloud25;
enableBrokenCiphersForSSE = false; # disable the openssl warning
hostName = domain;
https = true; # Use https for all urls
phpExtraExtensions = all: [
@ -28,22 +29,17 @@ in
};
# postgres database is configured automatically
database.createLocally = true;
};
# enable HEIC image preview
settings.enabledPreviewProviders = [
"OC\\Preview\\BMP"
"OC\\Preview\\GIF"
"OC\\Preview\\JPEG"
"OC\\Preview\\Krita"
"OC\\Preview\\MarkDown"
"OC\\Preview\\MP3"
"OC\\Preview\\OpenDocument"
"OC\\Preview\\PNG"
"OC\\Preview\\TXT"
"OC\\Preview\\XBitmap"
"OC\\Preview\\HEIC"
];
# Enable ACME and force SSL
nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
};
nginx.virtualHosts.${legacy_domain} = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://nc.ifsr.de";
};
};
@ -78,9 +74,6 @@ in
preStart = pkgs.writeScript "nextcloud-preStart" ''
# enable included LDAP app
${occ} app:enable user_ldap
${occ} app:enable calendar
${occ} app:enable tasks
${occ} app:enable polls
# set up new LDAP config if it does not exist
if ! ${occ} ldap:show-config s01 > /dev/null; then

39
modules/nginx.nix Normal file
View file

@ -0,0 +1,39 @@
{ config, pkgs, ... }:
{
services.nginx = {
additionalModules = [ pkgs.nginxModules.pam ];
enable = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
appendHttpConfig = ''
map $remote_addr $remote_addr_anon {
~(?P<ip>\d+\.\d+\.\d+)\. $ip.0;
~(?P<ip>[^:]+:[^:]+): $ip::;
# IP addresses to not anonymize
127.0.0.1 $remote_addr;
::1 $remote_addr;
default 0.0.0.0;
}
log_format anon_ip '$remote_addr_anon - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log anon_ip;
'';
};
security.acme = {
acceptTerms = true;
defaults = {
#server = "https://acme-staging-v02.api.letsencrypt.org/directory";
email = "root@${config.networking.domain}";
};
};
security.pam.services.nginx.text = ''
auth required ${pkgs.nss_pam_ldapd}/lib/security/pam_ldap.so
account required ${pkgs.nss_pam_ldapd}/lib/security/pam_ldap.so
'';
}

View file

@ -1,18 +0,0 @@
{ config, pkgs, ... }:
let
domain = "cache.${config.networking.domain}";
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;
};
services.nginx.virtualHosts."${domain}" = {
locations."/" = {
proxyPass = "http://127.0.0.1:${toString config.services.nix-serve.port}";
};
};
}

View file

@ -24,7 +24,13 @@ in
services.nginx = {
virtualHosts.${domain} = {
root = "/srv/web/padlist";
root = pkgs.callPackage ../pkgs/padlist { };
enableACME = true;
forceSSL = true;
extraConfig = ''
auth_pam "LDAP Authentication Required";
auth_pam_service_name "nginx";
'';
locations = {
"= /" = {
extraConfig = ''
@ -35,15 +41,13 @@ in
extraConfig = ''
try_files $uri =404;
fastcgi_pass unix:${config.services.phpfpm.pools.padlist.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;
'';
};
"/vendor".return = "403";
};
};
};
}

View file

@ -6,10 +6,8 @@
location = "/var/lib/backup/postgresql";
databases = [
"course-management"
"git"
"grafana"
"gitea"
"hedgedoc"
"keycloak"
"matrix-synapse"
"mautrix-telegram"
"mediawiki"
@ -18,10 +16,7 @@
"sogo"
"vaultwarden"
"mailman"
"mailman-web"
"zammad"
"mailmanweb"
];
};
services.postgresql.settings.max_connections = 1000;
}

View file

@ -51,7 +51,9 @@ in
ensureUsers = [
{
name = "sogo";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE sogo" = "ALL PRIVILEGES";
};
}
];
ensureDatabases = [ "sogo" ];
@ -65,7 +67,11 @@ in
proxy_buffers 8 64k;
proxy_buffer_size 64k;
'';
forceSSL = true;
enableACME = true;
locations = {
"^~/SOGo".extraConfig = lib.mkForce ''
proxy_pass http://127.0.0.1:20000;
proxy_redirect http://127.0.0.1:20000 default;

5
modules/sops.nix Normal file
View file

@ -0,0 +1,5 @@
{ ... }:
{
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
sops.age.generateKey = false;
}

View file

@ -4,6 +4,8 @@
nginx = {
virtualHosts = {
"stream.${config.networking.domain}" = {
enableACME = true;
forceSSL = true;
locations."/" =
let
cfg = config.services.owncast;

View file

@ -1,32 +0,0 @@
{ config, pkgs, ... }:
{
sops.secrets."strukturbot_env" = { };
# virtualisation.docker.daemon.settings.dns = [ "141.30.1.1" "141.76.14.1" ];
virtualisation.oci-containers = {
containers.struktur-bot = {
image = "struktur-bot";
environmentFiles = [
config.sops.secrets."strukturbot_env".path
];
extraOptions = [ "--network=host" ];
};
};
systemd.timers."overleaf-backup" = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "02:22:00";
Unit = "overleaf-backup.service";
};
};
systemd.services."overleaf-backup" = {
script = ''
set -eu
${pkgs.docker}/bin/docker exec struktur-bot python3 backup.py
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
};
}

View file

@ -1,4 +1,4 @@
{ config, pkgs, ... }:
{ config, ... }:
let
domain = "users.${config.networking.domain}";
port = 8083;
@ -18,21 +18,18 @@ in
mkdir -p $HOME/public_html
# public_html dir: apache and $USER have rwx on everything inside
setfacl -m u:${apacheUser}:rwx,d:u:${apacheUser}:rwx,d:u:''${USER}:rwx $HOME/public_html
setfacl -m u:${apacheUser}:rwx,d:u:${apacheUser}:rwx,d:u:$USER:rwx $HOME/public_html
fi
'';
services.httpd = {
enable = true;
enablePHP = true;
maxClients = 10;
mpm = "prefork";
extraModules = [ "userdir" ];
virtualHosts.${domain} = {
enableUserDir = true;
extraConfig = ''
UserDir disabled root
UserDir /home/users/*/public_html/
UserDir /home/users/*/public_html
<Directory "/home/users/*/public_html">
Options -Indexes +MultiViews +SymLinksIfOwnerMatch +IncludesNoExec
DirectoryIndex index.php index.html
@ -50,33 +47,14 @@ in
inherit port;
}];
};
phpPackage = pkgs.php.buildEnv {
extraConfig = ''
display_errors=0
post_max_size = 40M
upload_max_filesize = 40M
extension=sysvsem.so
'';
};
};
services.nginx.virtualHosts.${domain} = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:${toString port}";
extraConfig = ''
proxy_intercept_errors on;
error_page 403 404 =404 /404.html;
client_max_body_size 40M;
'';
};
locations."/robots.txt" = {
extraConfig = ''
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
'';
};
};
}

View file

@ -25,12 +25,16 @@ in
ensureUsers = [
{
name = "vaultwarden";
ensureDBOwnership = true;
ensurePermissions = {
"DATABASE vaultwarden" = "ALL PRIVILEGES";
};
}
];
ensureDatabases = [ "vaultwarden" ];
};
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString config.services.vaultwarden.config.rocketPort}";
};

View file

@ -1,16 +0,0 @@
{ ... }:
{
imports = [
./ifsrde.nix
./ese.nix
./infoscreen.nix
./kpp.nix
./nightline.nix
./fsrewsp.nix
./manual.nix
./sharepic.nix
./userdir.nix
./ftp.nix
./hyperilo.nix
];
}

View file

@ -1,34 +0,0 @@
{ config, pkgs, ... }:
let
domain = "ese.${config.networking.domain}";
webRoot = "/srv/web/ese";
in
{
services.nginx = {
virtualHosts."${domain}" = {
locations."= /" = {
# temporary redirect, to avoid caching problems
return = "302 /2024/";
};
locations."/" = {
root = webRoot;
tryFiles = "$uri $uri/ =404";
};
# cache static assets
locations."~* \.(?:css|svg|webp|jpg|jpeg|gif|png|ico|mp4|mp3|ogg|ogv|webm|ttf|woff2|woff)$" = {
root = webRoot;
extraConfig = ''
expires 1y;
'';
};
};
};
users.users."ese-deploy" = {
isNormalUser = true;
openssh.authorizedKeys.keys = [
''command="${pkgs.rrsync}/bin/rrsync ${webRoot}",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEWGdTdobZN2oSLsTQmHOahdc9vqyuwUBS0PSk5IQhGV''
];
};
}

View file

@ -1,73 +0,0 @@
{ pkgs, config, lib, ... }:
let
domain = "fsrewsp.de";
user = "fsrewsp";
group = "fsrewsp";
in
{
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.groups.${group} = { };
users.users.nginx = {
extraGroups = [ group ];
};
services.phpfpm.pools.fsrewsp = {
user = "fsrewsp";
group = "fsrewsp";
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;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx.enable = true;
services.nginx = {
virtualHosts."www.${domain}" = {
locations."/".return = "301 $scheme://${domain}$request_uri";
};
virtualHosts."${domain}" = {
root = "/srv/web/fsrewsp";
extraConfig = ''
index index.php index.html;
'';
locations = {
"/" = {
tryFiles = "$uri $uri/ /index.php?$args";
};
"~ \.php$" = {
extraConfig = ''
try_files $uri =404;
fastcgi_pass unix:${config.services.phpfpm.pools.fsrewsp.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;
fastcgi_param HTTP_HOST $host;
'';
};
"~ \.log$".return = "403";
"~ ^/\.user\.ini".return = "403";
"~* \.(js|css|png|jpg|jpeg|gif|ico)$".extraConfig = ''
expires max;
log_not_found off;
'';
};
};
};
}

View file

@ -1,38 +0,0 @@
{ config, pkgs, ... }:
let
domain = "ftp.${config.networking.domain}";
in
{
services.nginx.additionalModules = [ pkgs.nginxModules.fancyindex ];
services.nginx.virtualHosts."${domain}" = {
root = "/srv/ftp";
extraConfig = ''
fancyindex on;
fancyindex_exact_size off;
error_page 403 /403.html;
fancyindex_localtime on;
'';
locations."~/(klausuren|uebungen|skripte|abschlussarbeiten)".extraConfig = ''
allow 141.30.0.0/16;
allow 141.76.0.0/16;
deny all;
'';
locations."~ /komplexpruef".extraConfig = ''
default_type text/plain;
'';
locations."=/403.html" = {
root = pkgs.writeTextDir "403.html" ''
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<center><h1>403 Forbidden</h1></center>
<center>Dieser Ordner ist nur aus dem Uni-Netz zug&aumlnglich.</center>
<center>This directory is only accessible from the TUD network.</center>
</body>
</html>
'';
};
};
}

View file

@ -1,34 +0,0 @@
{ ... }:
{
# provide access to iLO of colocated server
# in case of questions, contact @bennofs
services.nginx.virtualHosts."hyperilo.deutschland.gmbh" = {
forceSSL = true;
locations."/".proxyPass = "https://192.168.0.120:443";
locations."/".basicAuthFile = "/run/secrets/hyperilo_htaccess";
locations."/".extraConfig = ''
proxy_ssl_verify off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_capitalized;
'';
};
# HP iLO requires uppercase Upgrade, not lowercase "upgrade"
services.nginx.commonHttpConfig = ''
map $http_upgrade $connection_upgrade_capitalized {
default Upgrade;
''' close;
}
'';
systemd.network.networks."20-hyperilo" = {
matchConfig.Name = "eno8303";
address = [ "192.168.0.1/24" ];
networkConfig.LLDP = true;
networkConfig.EmitLLDP = "nearest-bridge";
};
sops.secrets."hyperilo_htaccess".owner = "nginx";
}

View file

@ -1,12 +0,0 @@
{ config, ... }:
let
domain = "infoscreen.${config.networking.domain}";
in
{
services.nginx = {
enable = true;
virtualHosts."${domain}" = {
root = "/srv/web/infoscreen/dist";
};
};
}

View file

@ -1,10 +0,0 @@
{ config, ... }:
let
domain = "manual.${config.networking.domain}";
in
{
services.ese-manual = {
enable = true;
hostName = domain;
};
}

View file

@ -1,70 +0,0 @@
{ pkgs, config, lib, ... }:
let
domain = "nightline-dresden.de";
user = "nightline";
group = "nightline";
in
{
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.users.nginx = {
extraGroups = [ group ];
};
users.groups.${group} = { };
services.phpfpm.pools.nightline = {
user = "nightline";
group = "nightline";
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;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx = {
virtualHosts."www.${domain}" = {
locations."/".return = "301 $scheme://${domain}$request_uri";
};
virtualHosts."${domain}" = {
root = "/srv/web/nightline";
extraConfig = ''
index index.php index.html;
'';
locations = {
"/" = {
tryFiles = "$uri $uri/ /index.php?$args";
};
"~ \.php$" = {
extraConfig = ''
try_files $uri =404;
fastcgi_pass unix:${config.services.phpfpm.pools.nightline.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;
fastcgi_param HTTP_HOST $host;
'';
};
"~ \.log$".return = "403";
"~ ^/\.user\.ini".return = "403";
"~* \.(js|css|png|jpg|jpeg|gif|ico)$".extraConfig = ''
expires max;
log_not_found off;
'';
};
};
};
}

View file

@ -1,60 +0,0 @@
{ pkgs, config, lib, ... }:
let
domain = "sharepic.${config.networking.domain}";
user = "sharepic";
group = "sharepic";
in
{
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.groups.${group} = { };
services.phpfpm.pools.sharepic = {
user = "sharepic";
group = "sharepic";
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;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx = {
enable = true;
virtualHosts."${domain}" = {
root = "/srv/web/sharepic";
extraConfig = ''
index index.php index.html;
'';
locations = {
"/" = {
tryFiles = "$uri $uri/ =404";
};
"~ \.php$" = {
extraConfig = ''
try_files $uri =404;
fastcgi_pass unix:${config.services.phpfpm.pools.sharepic.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";
};
};
};
}

View file

@ -10,9 +10,7 @@ in
isSystemUser = true;
};
users.groups.${group} = { };
users.users.nginx = {
extraGroups = [ group ];
};
services.phpfpm.pools.ifsrde = {
user = user;
group = group;
@ -34,9 +32,14 @@ in
services.nginx = {
virtualHosts."www.${config.networking.domain}" = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 $scheme://ifsr.de$request_uri";
};
virtualHosts."${config.networking.domain}" = {
enableACME = true;
forceSSL = true;
root = "/srv/web/ifsrde";
extraConfig = ''
index index.html index.php;
@ -60,7 +63,6 @@ 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

View file

@ -63,12 +63,11 @@ 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" => "https://sso.ifsr.de/realms/internal",
"providerURL" => "${config.services.portunus.domain}/dex",
"clientID" => "wiki",
"clientsecret" => file_get_contents('${config.sops.secrets."mediawiki/oidc_secret".path}'),
],
@ -77,33 +76,30 @@ in
extensions = {
PluggableAuth = pkgs.fetchzip {
url = "https://extdist.wmflabs.org/dist/extensions/PluggableAuth-REL1_41-b92b48e.tar.gz";
hash = "sha256-Fv5reEqFVVpSvmb4cy4oZBzeKc/fVddoJIsalnW4wUY=";
url = "https://web.archive.org/web/20230615112924/https://extdist.wmflabs.org/dist/extensions/PluggableAuth-REL1_39-068be5d.tar.gz";
hash = "sha256-kmdSPMQNaO0qgEzb8j0+eLlsNQLmfJfo0Ls4yvYgOFI=";
};
OpenIDConnect = pkgs.fetchzip {
url = "https://extdist.wmflabs.org/dist/extensions/OpenIDConnect-REL1_41-520f4bf.tar.gz";
hash = "sha256-gLHaveEzfmpqU9fWATZsUU377FJj2yq//raHZUR/VWk=";
url = "https://web.archive.org/web/20230615113527/https://extdist.wmflabs.org/dist/extensions/OpenIDConnect-REL1_39-42e4d75.tar.gz";
hash = "sha256-VN0G0Crjlx0DTLeDvaSFtMmYsfB7VzgYkSNDS+nkIyQ=";
};
VisualEditor = pkgs.fetchzip {
url = "https://extdist.wmflabs.org/dist/extensions/VisualEditor-REL1_41-1bdb5a0.tar.gz";
hash = "sha256-HtKV9Uru0SRtl61nP3PgMcT9t8okB8jGPKFmtYIV1XM=";
};
SyntaxHighlight = pkgs.fetchzip {
url = "https://extdist.wmflabs.org/dist/extensions/SyntaxHighlight_GeSHi-REL1_41-e5818be.tar.gz";
hash = "sha256-dvXfOUlvT2Y8ELx83JlEx0S51oKyW4DDbVyUzyh5zag=";
url = "https://web.archive.org/web/20230723212424/https://extdist.wmflabs.org/dist/extensions/VisualEditor-REL1_39-b1204c9.tar.gz";
hash = "sha256-g/ATW3xkecHynwbwLbmYgawNW+LCVTth0ZlhY7A3N5U=";
};
};
};
portunus.dex.oidcClients = [{
id = "wiki";
callbackURL = "https://${domain}/Spezial:PluggableAuthLogin";
}];
nginx = {
recommendedProxySettings = true;
virtualHosts.${domain} = {
locations."/robots.txt" = {
extraConfig = ''
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
'';
};
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString listenPort}";
proxyWebsockets = true;

View file

@ -1,8 +0,0 @@
{ ... }:
{
imports = [
./fsr.nix
./vernetzung.nix
./ese.nix
];
}

View file

@ -1,83 +0,0 @@
{ config, lib, pkgs, ... }:
let
domain = "wiki.ese.${config.networking.domain}";
user = "wiki-ese";
group = "wiki-ese";
in
{
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.groups.${group} = { };
services.phpfpm.pools.wiki-ese = {
user = user;
group = group;
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;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx = {
virtualHosts."${domain}" = {
root = "/srv/web/wiki.ese";
extraConfig = ''
index index.php;
'';
locations = {
"/" = {
tryFiles = "$uri $uri/ @rewrite";
};
"@rewrite".extraConfig = ''
rewrite ^/(.*)$ /index.php?title=$1&$args;
'';
"^~ /maintenance/".return = "403";
"~ \.php$" = {
extraConfig = ''
fastcgi_pass unix:${config.services.phpfpm.pools.wiki-ese.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;
'';
};
"/rest.php" = {
tryFiles = "$uri $uri/ /rest.php?$args";
};
"~* \.(js|css|png|jpg|jpeg|gif|ico)$" = {
tryFiles = "$uri /index.php";
extraConfig = ''
expires max;
log_not_found off;
'';
};
"/_.gif" = {
extraConfig = ''
expires max;
empty_gif;
'';
};
"^~ /cache/".extraConfig = ''
deny all;
'';
"/dumps" = {
root = "/srv/web/wiki-ese/local";
extraConfig = ''
autoindex on;
'';
};
};
};
};
}

View file

@ -1,83 +0,0 @@
{ config, lib, pkgs, ... }:
let
domain = "vernetzung.${config.networking.domain}";
user = "vernetzung";
group = "vernetzung";
in
{
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.groups.${group} = { };
services.phpfpm.pools.vernetzung = {
user = user;
group = group;
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;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx = {
virtualHosts."${domain}" = {
root = "/srv/web/vernetzung";
extraConfig = ''
index index.php;
'';
locations = {
"/" = {
tryFiles = "$uri $uri/ @rewrite";
};
"@rewrite".extraConfig = ''
rewrite ^/(.*)$ /index.php?title=$1&$args;
'';
"^~ /maintenance/".return = "403";
"~ \.php$" = {
extraConfig = ''
fastcgi_pass unix:${config.services.phpfpm.pools.vernetzung.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;
'';
};
"/rest.php" = {
tryFiles = "$uri $uri/ /rest.php?$args";
};
"~* \.(js|css|png|jpg|jpeg|gif|ico)$" = {
tryFiles = "$uri /index.php";
extraConfig = ''
expires max;
log_not_found off;
'';
};
"/_.gif" = {
extraConfig = ''
expires max;
empty_gif;
'';
};
"^~ /cache/".extraConfig = ''
deny all;
'';
"/dumps" = {
root = "/srv/web/vernetzung/local";
extraConfig = ''
autoindex on;
'';
};
};
};
};
}

View file

@ -1,33 +0,0 @@
{ config, ... }:
let
domain = "tickets.${config.networking.domain}";
in
{
services.zammad = {
enable = true;
database = {
createLocally = true;
type = "PostgreSQL";
};
port = 8085;
secretKeyBaseFile = config.sops.secrets."zammad_secret".path;
};
# disably spammy logs
systemd.services.zammad-web.preStart = ''
sed -i -e "s|debug|warn|" ./config/environments/production.rb
'';
services.nginx.virtualHosts.${domain} = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.zammad.port}";
};
locations."/ws" = {
proxyPass = "http://localhost:${toString config.services.zammad.websocketPort}";
proxyWebsockets = true;
};
};
sops.secrets."zammad_secret".owner = "zammad";
}

36
modules/zsh.nix Normal file
View file

@ -0,0 +1,36 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# fzf
bat
duf
];
users.defaultUserShell = pkgs.zsh;
programs.fzf = {
fuzzyCompletion = true;
keybindings = true;
};
programs.zsh = {
enable = true;
shellAliases = {
l = "ls -l";
ll = "ls -la";
la = "ls -a";
less = "bat";
};
histSize = 100000;
histFile = "~/.local/share/zsh/history";
autosuggestions = {
enable = true;
highlightStyle = "fg=#00bbbb,bold";
};
shellInit =
''
source ${pkgs.zsh-fzf-tab}/share/fzf-tab/fzf-tab.plugin.zsh
zsh-newuser-install () {}
'';
};
}

View file

@ -1,27 +0,0 @@
_final: prev:
let
inherit (prev) fetchurl;
inherit (prev) callPackage;
in
{
# AGDSN is running an outdated version that we have to comply to
bacula = (prev.bacula.overrideAttrs (old: rec {
version = "9.6.7";
src = fetchurl {
url = "mirror://sourceforge/bacula/${old.pname}-${version}.tar.gz";
sha256 = "sha256-3w+FJezbo4DnS1N8pxrfO3WWWT8CGJtZqw6//IXMyN4=";
};
}));
# Mailman internal server error fix
# https://gitlab.com/mailman/mailman/-/issues/1137
# https://github.com/NixOS/nixpkgs/pull/321136
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
(_python-final: python-prev: {
readme-renderer = python-prev.readme-renderer.overridePythonAttrs (_oldAttrs: {
propagatedBuildInputs = [ python-prev.cmarkgfm ];
});
})
];
keycloak_ifsr_theme = callPackage ../modules/keycloak/theme.nix { };
}

View file

@ -1,25 +0,0 @@
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

View file

@ -0,0 +1,21 @@
{ isPy3k, buildPythonPackage, pkgs, service-identity, ldap3, twisted, ldaptor, mock }:
buildPythonPackage rec {
pname = "matrix-synapse-ldap3";
version = "0.2.2";
format = "pyproject";
src = pkgs.fetchFromGitHub {
owner = "matrix-org";
repo = "matrix-synapse-ldap3";
rev = "2584736204165f16c176567183f9c350ee253f74";
sha256 = "gMsC5FpC2zt5hypPdGgPbWT/Rwz38EoQz3tj5dQ9BQ8=";
};
propagatedBuildInputs = [ service-identity ldap3 twisted ];
# ldaptor is not ready for py3 yet
doCheck = !isPy3k;
checkInputs = [ ldaptor mock ];
}

10
pkgs/padlist/default.nix Normal file
View file

@ -0,0 +1,10 @@
{ stdenvNoCC, ... }:
stdenvNoCC.mkDerivation {
name = "padlister";
src = ./.;
phases = [ "unpackPhase" "installPhase" ];
installPhase = ''
mkdir -p $out
cp -r $src/index.php $out
'';
}

79
pkgs/padlist/index.php Normal file
View file

@ -0,0 +1,79 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$host = '/run/postgresql';
$dbname = 'hedgedoc';
$user = 'hedgedoc';
try {
$dbh = new PDO("pgsql:host=$host;dbname=$dbname", $user);
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
die();
}
$query = 'SELECT "Notes".title, "Notes"."updatedAt", "Notes"."shortid", "Users".profile FROM "Notes" JOIN "Users" ON "Notes"."ownerId" = "Users".id WHERE (permission = \'freely\' OR permission = \'editable\' OR permission = \'limited\') AND strpos(content, \'tags: listed\')>0 ORDER BY "Notes"."updatedAt" DESC';
try {
$stmt = $dbh->query($query);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
die();
}
function formatDateString($stringDate)
{
$datetime = DateTime::createFromFormat('Y-m-d H:i:s.uP', $stringDate);
$formattedDate = $datetime->format('d.m.Y H:i');
return $formattedDate;
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pad lister</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
</head>
<body>
<div class="container">
<br><br>
<table>
<tr>
<th>Titel</th>
<th>Owner</th>
<th>Last edit</th>
</tr>
<?php
foreach ($rows as $row) {
?>
<tr>
<td>
<a href="https://pad.ifsr.de/<?= $row['shortid'] ?>"><?= $row['title'] ?></a>
</td>
<td>
<?= json_decode($row['profile'])->username ?>
</td>
<td>
<?= formatDateString($row['updatedAt']) ?>
</td>
</tr>
<?php
}
?>
</table>
<br><br>
</div>
</body>
</html>

View file

@ -1,147 +1,135 @@
cachix_password: ENC[AES256_GCM,data:SjzpKHIFRvXDARjidS03eA0EmzXtsNjfkSnPTsafNhc=,iv:mAr67t4jvLc7cUn7WQaY/oU3AN1w28tCBJBI1ZfeS3U=,tag:VSPF158J1iP5x6qkytGeGA==,type:str]
cachix_password: ENC[AES256_GCM,data:7SleCWYfyhlde2vuIr6hGtAwuSbiz5W8PpUHd8TIh4I=,iv:mAr67t4jvLc7cUn7WQaY/oU3AN1w28tCBJBI1ZfeS3U=,tag:Dodk7V+nnswtSuEH6R5LGw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2023-12-26T17:03:43Z"
mac: ENC[AES256_GCM,data:RJ1qczvz9tRPf0krPFbSDURZJSx5Bx/K7Pz3urNYn8wt4/M1B9EJI0nlHMuun/QjCDYMmiOzvvJMEdOBI/OeRZaQrp9+9LBB+9r4jOhU8BIP5czzKaGpDpZ9o/6avZf38SfrjR0M8NHVuTRGW8vzstu92KyeXaIRqfJ1JX+ucbo=,iv:93dkoIJHFVQaGqNBW/9/QxobRLiv+hd73lsV2ZXJHX4=,tag:H7IJVW+c4EaMPdmJDr+7oA==,type:str]
lastmodified: "2023-08-14T09:08:46Z"
mac: ENC[AES256_GCM,data:Vb5iZpE0D0kQrhrtm18y4WQj7W4c8oT+oFeFPgQBCJ1EJyHemREgn2RskCZeevad896qjWAR3xtk2uGc9SOEqFhWX4OkyhTGAo5h66YygNw3LbCsarfUcYQ7Jthdw2rnozLLIOEZ0yykeaayWEULbdHZjgaJwI+DIwOyTkBgmK8=,iv:96/Ph7+HDjT8su+vmtUB7d24OVY4h4BmfiTudwW+7DQ=,tag:F9JfGnSZOMN3GHdMXCVRPg==,type:str]
pgp:
- created_at: "2024-02-29T15:23:18Z"
enc: |-
- created_at: "2023-08-14T09:08:12Z"
enc: |
-----BEGIN PGP MESSAGE-----
hF4DntlvaG5T7wcSAQdAnAE456PXzGekxSnrumXHqeCY5tm0/20vrPDDidjy3Wcw
k4WIu4Sglhukn5LrQkzzcskoFpGHrPj5tN84jilNDjMz8nVR1zniAlrKTP59C/fQ
0l4BIQYlqkqkEDc+kuWzy2O0mteKrlo86Byv6NryvY5DseXUFd6pVde8n8ns5tSZ
/jSh5Fo3/xkmJ+aS2SturNqUixHYbGBHUpfQ/IakxriSfLdtkf3N82M8e5jJUWB3
=ZaVg
hF4DntlvaG5T7wcSAQdASuJ50zZbRm83JgWvBkhhqb9CYA7I5b4erFYEG4YAugMw
r0nWOEVjWhMiYuvgQkNbD2QLioNbmYrElL7zRpLW66HhXX0F+SSF07SGxBY3DFX5
0l4BqOepz3eG9yUO3rWewZZmdFmtgSSgutCqHSA3Z/3dmNupSoScGUl2qVTFTZ0n
pZqfDRnLrrRLGdqQ8ChgyzkaD4g6wQULApScmewit/QlRi4s84JBvqVcro6OXXof
=8TRl
-----END PGP MESSAGE-----
fp: B8E1727497FC48AA14158BDF947F769D7B95EC2B
- created_at: "2024-02-29T15:23:18Z"
enc: |-
- created_at: "2023-08-14T09:08:12Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA/YLzOYaRIJJAQ/9F9PE1/Dpehh2HvyzkbBMxar0ZrWItB9UpMN4VJjipI7x
8cMU7iIp3gDrVfwEzdARzXOUGugoxYPttJMe4ZRrIHtjnQBWf+e0TcDy4eqdHqYH
COAWRBctYAWqSU7n4Gq/mqtNGe1VDY9Q5rhpDqhPc01KWO72AgLUwH6zoyGM4YBN
7u7eF0vqcaZGQyzo4IjasnYlPjgIDehVzdl8Zpy/yYOFNozLFBV7HLqItEl7vdEq
DPGzz7vKAK1pHK0Qie5MBTbEMJ2yIBiGIJ/rZv5h9RvAuVu0uqjFbehis5yK2N4s
hEBVaECXfvuvc0wP7EIgxdUoDeh+o4OUL6OneQRXeMqdlsw+oq8WnKywi4bf8dDl
1gNs7PLa0ROQKyOiB/LAZn4GmnNLSD2KnlTYoyrt3s8tgfRCHOhoWxGmBGfV3Z2C
KjbucxT0Wz0gSSBr6ht0lL0DD0UFQ9WJbz2Dns82CCr5T+ehHk5YVGQPSSxPaDlz
qnNdS+OvrgbofKAk7JcR9Po/ajoOAEvv6GfA0ujFi3FxyjwgaPS6Je4fC2gUVrwb
2z7OCzmpp3vGrFB0BvKSwrCQLIeffWl8M4bOoCDKM+XyMEUML7TsTrFkoQ+wzvqN
V53askywgCRfSkfBsEWV1Aoms4QmPnvkuoD0N4F40MRtD2HmhxrgqwmSh3Iu9qPS
XgGkJ/TnuWJ0KkBePo8xBqokVTfbhiGufYXXz6B80tHl6Xrmd5rcz8km0tCc/GUZ
R8yygpt4uFujJEQzaCdT7Y8kt+WRXaNq7pZ0lsQF7lYtpusZhPBv3pDkb4/6ALs=
=nVIs
hQIMA/YLzOYaRIJJAQ//aIBDcdbJwRjT0xgiRjmMIpiM9ZXfipl/UGP6N3y9Xndx
IaVp4trITGXIIvChYo0WylCvPPrXdnUdwthu7sR7P7yjF/ZyDorYnSGB856/bUaV
nX6to+zNnk6Zo7VBXW9HIqH+nG1JQW2kv8uF7hZSIvXVTYuuS2FfZMV3Vye1eQJ+
5hbraPc0ioJFZe+sz9vLICGGdS7aY73lGrWllgpOgmtKc+S6OAHSH6zSkJ0rGzxq
AhkaVytNeB6Wc9QZw0YETwRv5ZKEZNCuMLDsB6OvP11T5Bod+SK59uFk4qFyHk40
AcZ/FpdVPyH38rpBEjR68ARypLCXQqcTCUcVMtqW3+xm+msOF5Oax7psqBFLd1C3
C1X7MnXNWIcUiqm0Cl/d8DQUB4SNoKLwKMFGH9voPmpcht/1aqudMuloiSJrR8ia
B7out4PhQh4UGtdqilbEsntWmoiDmftvYKQiK+iA2PaNZPvFaDET6a21L9Ezk4mW
XVZ8AiSxyQRH2c7l2jVPZZ3KZa40EOvdP1lIiCvlrp2KBlj+r+lqduFR/qG7vr/E
avRT2qxqR4y+wVlXGcPONyTrb9qGZrn1bnwkZ5at4O0QYYyiOt2PTe16WBgEhOyd
WDT2dnb7lG7fDSiY6iVzhYmnywEOREDEZ7ZoGzfGpgz9fDwrVvfpWgWkfLayHDLS
XgEGvE2F1rGyAQVrAaLWNH01WL/7waZd8C/M3R0tbvyNVl+cEWnVmtz/LhRQuji1
qVXKzZSkc/YKuDLoJnIl4x9pVoi42AWf23YGltdk8osyq5b4eOMmoExhsdXItLg=
=dCdG
-----END PGP MESSAGE-----
fp: 91EBE87016391323642A6803B966009D57E69CC6
- created_at: "2024-02-29T15:23:18Z"
enc: |-
- created_at: "2023-08-14T09:08:12Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA8uqUsBLHj6XAQ/+Ofo4GZUZEca+ThmZmF8g5OlPOfgPxRUHuTHoiOthXTuS
IO7BSCYPHdZlnDqNMELdQfKZHRFirehibMIFedfoiKEuhJaQ1p9go0CnIhcX7tzA
aNaBbbJBmAYxUfPdExkJK9SqDxV7aXC8OHzXHwcZqCc/G38E4fOMVsvUVdD+Nymf
lEXmgXpU1ib5vRaH1oCOf8d1C6LFFC+peBBbyzwhNgFgVYP8NrXWkeIiRSiKpFpx
3lsLODLIYXteoO0DkkuT2z/0G86EYo+bmSx5Ubi0waxfO3sLdUnDaIIC/6pJqbS8
QM3HtEL1kQaAFure/r+K7Ck8l0eTKbfnd52jLoMFK+1g5587KjV70fpx4QBvyq0X
d0xJAfJSRptkIlMOS5+tYOXd2SOtoG7XwprrUs+lleE/Z4SaOjyGWkLE0L1D+Qhp
/8jw0cU46O69ig0p47H1klvJ5TkZkSroCkarVRUS4AHhpnLLnDMYDkuVoZeKM+rz
tOF8Sj/ySF3PA0W5cGf8dK8u8EXgIlApLbo4ZOBHff9yJJvuDJjt2b3hWPZh/uHF
ASxPF26cz6+ysGLl8COvWLRlxDD22aP27P2A7+9LYi9p1csNL+wuYwfnF7/rrrLx
Suv2InJqsUV5JkLlhoTYnv6kIwrz0oVSnTOFIBgQ3dex3T0DUn/eEdFO1BHY7BfU
aAEJAhDp5eds7PB2IJhFuHuYcsYquRDlwlQ6CY0fWTR3cI3bzNTLAe+ITv19CBUV
eGi9XUc05QDgUapvUewGXZXlFxo7iDDw1H7S1exSeRY/sbmeDE1G8beZxEqD2Rbq
Rlwq7HypFnxX
=M/ss
hQIMA8uqUsBLHj6XAQ//b1bA73WQ0H2rYX/scP68fDjnkeIRq227YW6sY3Fm/ob1
4vmllEgZBTlzQwZb84fc0FBIP2xBzHXgKCmzt/+EEb0VUAc0KvNyJwa65apOV1MV
juzNYzL1rPph+rlk0NVkWQvop6OTGZ1rsq8GgJoffm3dYUAZysoyKJFwn+zy2sh6
Q9kbWCsX8O/6ImLp6WgJXGUGt2MkkXUkMTdIvWHQntNuQtgh2E4Fz/HCdSW5TT3z
FoV/FaVNPMP1JiG3ym+q4p9zRQTynWb8JqGlWgt86vKdyqf/sBDMZHpjbZeX5O4m
RKiTpjAgDoJJYCB7WrnHhHJkVo2E0vi8bM86BJ0G4rubWTYhYlpLOMNIl+iVo1j5
H11vtJ/dphat1/8006dpeyA7xlw6Woq09Org6dRGV43sBK2oiNNznbigt6BCKylw
m2sUY/VyAEqkd2knYsfkfiVUy6R/yHkgGUJo94QUtfEs7Yw0VMwx8U/N7Gwrx5zB
8CUxxOnCNeynDPP3sPsei61RXretbJ0wXxoOv8P1GHIPYhAbEX9Oi3u81FnAmykJ
NxM+Ip9RbeS9lRvuasMJSFawqJU10v7XLp6EjB+Ed+vNDzxPBnhbUYNKJRE/Gq4k
Phx/ySn900r+MX/1097TvL0GQH5TDK94R/Pip6K+iAeZPoFQFbhh0r4aYlARTpnU
aAEJAhCiPLz6o+/CDSsM7HQuATjywPk487/2PZ7SVYXNl1mXPgTfQJaDvOHjlinU
yPO2XNwDkKQwtq72AY1oSEODJvFQyTLHSNNCt3Wbfm7LNbzp3UAarQ8g8dFOfCuY
p6vOQwd0oQ4B
=ZwoK
-----END PGP MESSAGE-----
fp: F8634A1CFF7D61608503A70B24363525EA0E8A99
- created_at: "2024-02-29T15:23:18Z"
- created_at: "2023-08-14T09:08:12Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAzUXo8ZPJwGLAQ/+Jbtq6OyOcXYHWj6T74BDA1hcilHrP7yp5w3Za7DwKWpp
sLTcXo1ZywokwSBH8lm1zmhnho5BN968YTbwqb/y4FMX2MJP/VIgjgpkl9KoiZHM
py818xRsVttggsqoTnN6mtOYIEOu9lQCtA8zXgc5BIr1xDpRlVmz8VyeG70a32vI
PaG6BAmOoIQXNikNqhzyinSKkHHzDFGyxfdYGR2bMuGNSbpIr42DHOHVKWd7mzHW
Wm3BOaFHe76aYUByXujBPJ1oXm3PYLAPxXVudc4GCj23V3fj7oczCU74ggmmFLGk
PJkRRIRHHqAjb3C6LZ2V1sF2+eazlpSLcvf/KVRc12wFMzoPSpEb+Ft3MHYEhBn6
o+7+BC94RhGUzu7OI2dK0oMUMZaeByLqFLHH0iZ171TuD3Tqr3NnsUBTJWT7hPw+
FN/yFsf0ZbRiShv4Vvxyib3NRZZfZ3VTG11qlV1xEBEsBnA3QzUr+J923FxPwOkj
jBzxv9EJX/imXCj965R3vevCbc/6xf8Hy4x4GlqtTTFsw8uKwaQgoqL9eSejEcpU
TXrMaKN4zUEgT/ZPI76teU7HKBxNfS+1yocznaZ6dr3SN5IwX0tX9q3k9Y7D0DyR
LI1U0Wrx7JmbXQa/6ArKzp3fuwNFVkfQNbjvNFh7ghBTWQ8rWXtOU920KzAKwL/S
XgHlxl1gj7/YMrifU01zjSOerzzLetDRBtBQkl0DKeTUXwIjM82Hd8CP2yFaTAFx
AqjVgiJBB5ffCnKLz2wB8QP7BX0IzbVaNAgxwM+dx1tBH5riSXuzCIgrPnuEq8c=
=0rd1
wcFMAzUXo8ZPJwGLAQ//YGciouPJhSuo1gEi8A31dsuXM0ka9INVTCtOP1kcZmAT
4ov/00GfaCd0XkoX43ZEV7lZrpQ8zW1iBFNi2Ojknu3HRJrmiRtTj2wv6ZOtsyvz
2Ac2ADp91AMaACibt+XzEPGtnU9FitVEl0MM7pbllcu6jqcV/sa8CNf2564OTTQ0
6Fy1NsvbpAwJ5lyk5fXxsUlR/SGN8HWJRjytal0DLwyhgQZpnbZro+pMfM771x6U
5JztJVTILMGhfomSa5Tjotkncfilymjhg4eVGoD2MVbc9pjmze+pLzH2cjP8NyyA
4zrp7UgNT/EQM8RNgYg1KxIPGYYIEa+83253bjfCexR2gh0xlyVqc5o0Ql2xBUVY
LckLYVFAowgxuTOFDLIEgs5t0qFotHbLxQsfy1grFShhp/4p+vPRq8UgAHBjTzTJ
NKw69yaJySeZ47hR7p+AUODTfjyZ0UrdFraI8qT16LRa9xPH7S8+F50dj8aeeEU+
ss+3g1ionuNGztLWJOK7yIm3ZHh/RIP6DyLp7r+PAII9jyWQLOOWZ1+Ugo8irevb
xGBMxt7FhqWAxzGMBL+x7qSOGAh+hDv4aIP2692nBjSOwmao5LF5A5jsLk7JbJ3e
6DJz435wCdbNklHu09oSn6hoD5LuTFNP1K/q+FmOd8GZKhaqR6SXJuTN6RfPwyHS
UQHZexhIfUx4aUQFzY/PbFxjI6QnHoW8PgaZ8vrL598Mpb5Sqd8Dx+NSnN8ifEXz
ophXLjNmlamF0wyx8z9bEitGwZvckt5rSdu+KxkF+duVAQ==
=QRWO
-----END PGP MESSAGE-----
fp: 116987A8DD3F78FF8601BF4DB95E8FE6B11C4D09
- created_at: "2024-02-29T15:23:18Z"
enc: |-
- created_at: "2023-08-14T09:08:12Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA30JDs8MiK29ARAAvPwNXd3KkiVXNtNsOg1udXh08URE59ZJJUPBbe/XOHZI
aUlrU5kwfswTcpmbHok1Faw8ppw9u9HMmL5HoUQ3LpdYBoZFDUmnu2AAhWjEilMB
EoQ/Er+Nq+EfZ1XDufZT3DkHydPVHEIPrau3U+Lf92xzOi6Gqcdx655orHrZSyXl
Z7xRUZi/Py43olmJm3jaLhhju3nVTOPJWAr/im+lVEtTL0jEw/OuSo+63GFmkILi
bESz682YVL4ZtrPwQKZpdoIzsqwTGUSEO4yjuLEshM5QDL1HFE2E9whtehBAfOt+
4wTt756hHFpaweQDUm9e+Ce3sA7lifTVjX/h4ZJ55etW53EPP59bTW327mk4Sxxj
X85wo2kD7CaUxwrk01QBkAptuSdUf9d03cw6t3EH/uXYER2mc0BNPdlJB44eYtXE
mwUIk1UZ5rZ2tUPKIdUj0xFNywbTJPN+FKgW44y7k1/PcEKQpwndK1Xoi45HemY7
cMxMptNSldv1DAQank0CG3xYdCLfkLXfixOrI64Cqx8owTPLvUCic29e7Rw3+vAw
LOR6+mSpF2bGMt1NvpZAP0nHTijWWuGg4V8eMyJcdQ6eHnhFjVaq+EVqQlYas9ym
gPHLZ+eQ2Zy39nutaV/CgmgeniXS45l/H1K6QFhJahg7bpa4Z/qWRAkF/jaUfBbS
XgFhjoVIe3SO2E8YUh+Z0pFyHo5GlKkgENBeO7KJbiOYzwLoIpvpO1baIhHGPyrj
Th/Qj0uYyPYknrwgNivl/c+1nZbkNU4Btsp22+bw+4vq8c8jHKgtvMCwKsNbU4Y=
=beaI
hQIMA30JDs8MiK29AQ//bWhIT9dYWez0pXeu/NGoMFBa2OxsxxRiJh4Yz0FPTpBl
meDjRhVgg5avcGQT30bFzN8YAxFjoLns0/eWTZvoXWA2boSIwGbH9Yi5tmXp2OKD
mKxtxOQzBsDnzCR5wdUYNbgDX7ebgeRL4dodDpG3MSzWaydSLogCvhDgCE6Spfyc
N/ZvdN4pFzeylQUMgtMinfuAnqSplU1mgkE6Fpzi/BG1mUZyqDEIwlEzJ8uxQqMj
DbiE0aZkt7tOoYaSaX6X/wCkncToIjoVBm3Vvy4nVD/U3HwJMWW+xxZKHEyg3bwm
jySJ8bSoj3u9B0OVn3x/CQpRbGfYvWleCgSR/AbB8x7ccL49x+n5U72q3zsijSGJ
NmS8HZfEvYCEP82Zp7pCZOphrjZg1TKgHB3MXkRdo6tmy/jtznnMbQyobYkj6lFB
NsLg9wcGwG9nK5PK0kB3YrBTi+wSsu8ExxD0MaNpOm12v9ygMbNU0n+bNyUyEseI
KZLapICHWSLSRuQWbbk682CadXmqLlzzzF/FP+4mhx1z+S7f6nuzbariK+ccI4XY
JeeIE9M0vX1foO782WBYI3TvGUAA/MCWdrze3j304RgTxSOl6m3IKq7e89HCt0xo
PUQyfD/e7lsC46dxhuqI62ikKrTgtadVEjTCSUqRlVkJ4DGCkGae5BPsPcF7GpvS
XgHm3czu9w4jda9Qhqv3aqNZhletlYeyJEbY8/7V+mSDvvgjRTZxrxfDcPslraLm
WqqT1IAZRL339pJnPXtPnvAZyjxU6INTzGQfV8j0AAZbIzCGqMU6xkuaStugASY=
=vPdd
-----END PGP MESSAGE-----
fp: BF37903AE6FD294C4C674EE24472A20091BFA792
- created_at: "2024-02-29T15:23:18Z"
- created_at: "2023-08-14T09:08:12Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hF4DNffZWjBmO5ASAQdAluq9PmE0yZUumm/G4UtwQpohy8vpNzAh8D1EWVj2KgIw
CkO+UYwhgB0Sl4rqYYgyGI1FK0aVQQYEV8jlvVpzWvaKga2bm3yT7kAp1o8b5Nv4
1GgBCQIQp3OqASoqHK2MGQURJr/NY3aHQVBltEe2bkgXj4FgBXu9a1L5hwxow9Ze
YMDBVLkDaH8oCBBwvQVdqBmQe+LEwyr5eb/r0PtTksOfuQQ1TV3kX1Gj1XN31ilQ
LHXyhm6gI7zslw==
=zVpt
wV4DNffZWjBmO5ASAQdAKSKcjuQ4oCCz1foAgnTSXiRz5FRTE8kGfFMVnZxOpF0w
FCTf4e/KeNBkkHs3fU8KikPirMmbO57MxU+w578efXrM8LRgJFvvkkxLr6tMpfkh
0lEB6rCNiRb0PzqkowhMZqL6vwqBA7TF0hog1BGkdQPjac7V52oIVdqMyMJU1le2
lb6NWDgi4mqYlrX/6+cTHnXC9Mub75r5iYzKV935PmUb3JA=
=U9Xi
-----END PGP MESSAGE-----
fp: B1A16011B86BACB56ADB713DB712039D23133661
- created_at: "2024-02-29T15:23:18Z"
enc: |-
- created_at: "2023-08-14T09:08:12Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA1tId/HHLgxAARAAkoe0CqLnz2Nythjm3wnMVrwv+U/ZeaVGemBJCaS9MWXd
inmKUj9fmGdrbqoIhxwgbMBjuHFWrHWO10ahMjQ+X8qOH22SJEDYhZ7H3I+KkuFa
dBrubZizjI7STYSC4vsLftcgNkVtaIWNhc34t4Gv5Dk5rjSXuM3WORm9xrIvJ0N1
KXBUP6JF9LF0JZTwn86EWeb7Fa3QDKuQ3T7tM+8kypqyh40gd7sKLx7onXLRacbq
U6fcls4Z3m2N+NayNyi+EoKDCUOkDJfms49I21acq7wiigGE/pIDA6MFhL2X5N82
lj1V3SySHNXfm3QeHi0HvWiNtLp5W7yDoN/T2kLf76gIsiXlrnSR9BnvY0LrnYTR
wY+j9q+942eG3QL0g9gG7L0mM8wZ8QcvdVmbgw3WpbValHSEXwfg4kSuCroZH38e
XEzSgqbuBMrEprGnH8/+gp2VxxDcOnpUQApe6tvrSk0d3GmGxoIriIQonrvEPnNJ
B/25jIns9X3DK3FxL2tYzUSIXv00plLLuy5P0Sl1fvD3/J3faTJ1uX8xB0z4c9Nv
/GG88hE4Al+2da5XRdDhgrS8L5YX0gxKPvwFcALO58v4YU9UxNjp12kEnteqbfPh
0X57Tin/2cvPdH3e3g7CDi1RPHK7mcxqpcshmuiPNVhou7I7tTh7BGJpP6vpJB7S
XgHwQVfKx/rmB//dUZ3ZcZ6IXActfAxm+F1uXjhRi3hbctLV4GlMAV2/ijLX92Ob
WZv+zdCH1fioicsObmRgYuyk6gPlpMyAA9u915MH12o0G/AwZaquIfocmRlDwuU=
=zv+X
hQIMA6MARpDCLIz2AQ/7Bvm+qrO0UdHN3goHTwAcy2TKmthBOrknBjTN12ZVPV0L
21fmywd1MAJrARYnshhUkaaZrjd/hkeRfk2GfRAM58sHQi7J16xVxhvurqErVTTF
3vOyDeZ1VkscmB9kWYpg9B6dkffs87Yq17N6wTPh/bxStYImRuHx1TmzhdsEZ+9k
QmBeOY1nEGeaHYcXsVLNrfHwcL+VX8kCG9f5W0voR5wOcoJwOEQzz8URzKlzgV8L
uRAhtEt6zWmXv7BiVW39r1JnWNgTjVwp9PhJI6knghiIfibXndGc9pDhJRuWnSQK
d9SrCEPmtWfQxzhdAlFobLI3XkagrZvSj1fIyYbT1dwEiR+4p+FoOp4YuN87xs0I
WeDPUoEMABVpYG6PoICWxCvaFU1cv9yqAc7TKhM8vDFQn1tJ4Ante4U9dLZ+iEbw
LxFr2XdQXLiqYUOI4dtEWO8IQqjyxva3AxU92clN7LIi3CeCDoEJZcg3l4eCtwyP
NUOXozZjnEixw4Q+1EVZZACCTPyAb5Gd994JqtjYmb5575xApWWiQNXf4hGo/WGn
zV0ZIfvohRBKxpWvgv3KUZwwHzz13AbWlBjrPIextRDdnQRZWv9jU6xRUFLM99XO
PlYbAPp5amaYRmwvG86opjcqmPuUTT/W+ss/aK8ddU69KYM+YI7OzqUXC0zPg4bS
XgGpDo6bqCP2YYkSzLYwKzMUHgHz9Ml0IyL5DQw3DMvu54IGL9nkgEd3DyIHdvsn
roJxHvGw18eBhHT0mXuWi9iK0vVMJW8tPw7CVZVSKuLFFsm+3LgkC1UftLvT2yY=
=NSHU
-----END PGP MESSAGE-----
fp: FB44F0746DF25F0B24A2EAE586C8A257C3EC82AB
- created_at: "2024-02-29T15:23:18Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hF4Da5T//DC6DJkSAQdAtDsm8pgrR36jWw5qeWr2Ezxa0Y/feoC5R2rDatrPySsw
rXez9HoJLmHPJf5iFMxpEhgO8LAeRkSOUVDoMQAKnwP76CRAI+Y6uDa9qlWvWFDQ
0l4Byo0ib5MviXkFCy0ZslKpwAL5NR4VllC87HhndwkynizQgRevmB+ITU4QeNZo
+eNJaGphJdn0CuAO1F4vOw/qTHSzVxrLaux9J7Ovy1oM/jbFcAbUIelfkLZc13xR
=5kVn
-----END PGP MESSAGE-----
fp: FBBFAC260D9283D1EF2397DD3CA65E9DD6EB319D
fp: A4F92BC7B792108A463995827C1F2DA2BC929412
unencrypted_suffix: _unencrypted
version: 3.7.3

File diff suppressed because one or more lines are too long

View file

@ -1,162 +0,0 @@
portunus:
search-password: ENC[AES256_GCM,data:lUG8qGioYZOAQHRhDMCBq6rRRFOs9R4ohMHEctxi/f6soE4aQZHyENEW,iv:6wgDgre5wr630SkRlT2kHak4nnOkx3DVFbNcq4FehGw=,tag:S5EiXEsoId+pGYaQ8lq7JA==,type:str]
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: []
azure_kv: []
hc_vault: []
age:
- recipient: age18lwgjazaxujqgcc5j0gjllnykhtjn6p0q44jzrsk4au2a5k6nd9s77kd6d
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4bW5yM1o5SHNXZldjcWtO
NkxENWNqTlpVeXVRS0MvNFhCUnNlWmVDSkZJCi9KNiszcUZHTXl0WXdJMExtcGYw
WFZVNGJkZVRrdkNRV3llUEJjay83NmMKLS0tIEhWNGRkREJuYWhaamFWQ2lEZUo2
TXVrMHZCNU5zOG5hVnNkdEoxcTZqWXMKA9eG1zM6HeLAAOpIo8Z5+5KD4Z5P3rdc
kE8sUXHD3d8SMmSKcTYe6gGVzFuw0xxnMb/AmjAQosvDFTQsWy1sTw==
-----END AGE ENCRYPTED FILE-----
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: |-
-----BEGIN PGP MESSAGE-----
hF4DntlvaG5T7wcSAQdAVYr0vThE6byTzCZiUrErtuouL9k2b3uTQKR3pnk1qmcw
Pw8+vdUOal5i/M9jFWexJzJ1nenzhIogFWry4FdXRX7V39/nRJQ1mbF3+3T/yldD
0l4BdQ3xmtVUiz+PYCzazHC5+wPB4iCVs3fkTiLvNBNzUDEHvj6T7w72eKhld9VT
NFcOI2lSDea9EYksEdLef4VnE8gI1DeYxJAc60GXydmBJZO30xeOFMru+XE2N7Cy
=S7ex
-----END PGP MESSAGE-----
fp: B8E1727497FC48AA14158BDF947F769D7B95EC2B
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA/YLzOYaRIJJARAA0fWU9NbHhvooG/4gYcadlwNPtQqOIw+6g/L9Gx8wKEhR
i9451S9oez3ElkwIeiF1YPCzokF6TuKv/++nV5SjC9PZVSHnrixrQscdN1FtMvH9
ad2dC4GD69fXebq3f1vj77fAZxif6OMcEMpDiRRXHHJetzuUDkLpk0YSR/ZM23m/
ag/JrHNUNgSJPLFRjvSNqX/DO/Etf/RfEwuMoPmwpGrQFhBTwtcIjjrJ2zT38q21
PhWrjAL0Mxjnt1zFOGLLXwV5wkpmLOj2GGIBJJ+/B1zEawkbOx/ROuzPFKrDmrrh
xz29AVi7Ok9JanwgPGRNytnUHmxToisIH+FZqwpDTsop0ZQOCtiUWIZot+i8XGxs
rJhHTKxetJfsJCQUe4K2RJtHnVKIluzLDFyxoOb5SVmXoslY/EIQEYJz2lFPG2sc
PbP6XUh5ObZTK3IRIFqeQzjjLI1eaLdYjEOr+a4Do98Dd7+vJ1nLwkC9Wo7JLaaR
yd4emYpyB8R72Zf5+TPhN6ZWAL97OQdCZCSxyh3hDUZt4Wckg3I2yjw1mh56yVJF
fFOCOA/nXWpYXyRTbxuPuvCqjVsmVDEh+STZLIFsARzvz+yrlpEFoQw0G+Xa/XfO
aUt+HWGYji15+KVZJnSOXHhN4z4amsg8mtAEKfhCU7pl3jyrxa2MvArPBIU8FB/S
XgG8vs/FjyRkm+BvmHHEHmh8JkC9B9Lx1kmMpHw+fMis90IqZ52I82RmA6aO5jqR
ywlIrtvDLC/5STZaBdTt6EJwf3OAvRY+H1Br+SLtz9xXUxgzV9JOHWTefzRH2JQ=
=3Wnv
-----END PGP MESSAGE-----
fp: 91EBE87016391323642A6803B966009D57E69CC6
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA8uqUsBLHj6XAQ//SVU6B8zLxtpp1gQ/U+EGpgbP8N3IrIcUPrPVx72dIu+y
7acCmdgralvEe/MLG4vNSnkrJdCCk7piBG2JFTMUFbqbFkUVSyZyG1yRsyezB3AZ
czSdffSQ0SbxWL73ANO7Z4asRwXkqjDTTKTl3xL3Iw8tDu22INeFwmcZPFV9F19J
K/BanSBuofUOiQB73BNv/8lA6ssxqufj+9pDDoutzF5XWpd8wUPn2hIcNWtr6NyY
wl9U/Jb/gkhnUR/UHGO2Nz5kAWz1lhysa/dur6I1mrxBJ0mO9I0j8A6U2cBPxdG5
JBiTuKlFi4RhKUAraPDC+c3fM3Zp6zIOWhZgRNGlnR0Tu3fTeqdt7DwYh0bCOpJy
tTtj779hRj+cnleKG0QB89MY3XFpHQR60iBEMnqg522LLlTzLbvu6BEUvM/4jv+j
2aq45zyYyIHC99k8xG9vl5Ou+3XhDqqVRUQ3qCRbavupWRKdibaNqjcaMr/zDqQ3
TxmDluLnsbCGnyYmZDocwAqVvTVorHEr8yumjViFpXPImRe+na/0JCuxRHbBcVt+
9WynLgKy83rHY3tWKhqYobh20mLXNNcCiUvdGFYI2X/wyUmSRMkuNpT8fsvdr179
BtERX0a3VpzaBV41pMsEIj7okx1MScMxXEmAktnDEQgyPBwV2CZpp2lM3YJajVjU
aAEJAhBKMkW8iDDTeG/ISzhGv3Qz4B2ujOvb22N1j/LVH6HUcq/Kg9tNJ3nDuT0v
zP1O6zxkwZsm23at68ZkfxXdBm6Qwf/sblfxYi2SOvWn+fXSmkSfGPVgw0vDG3+G
0DskmbWWbRuD
=9+VA
-----END PGP MESSAGE-----
fp: F8634A1CFF7D61608503A70B24363525EA0E8A99
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAzUXo8ZPJwGLAQ/+MGbYqzJX74UDkNrAC1QUvA54pROBzoKnI45ODtT9gp/5
9Cv5Hx3d/1UA/IGjGh6Wjv7ljCjH335R47bWBDmnE4WmrD9O2gopjBqAuF/k/tIs
Vc4+8AD7F85PTSSdb1t/2hu/gYO/FAmwpwxLBmWD7iwAwpDZoPB3lBYwvqNOlnmX
8cFYALyacBBMskwp5ydNEUtQO02ycHUfr3WVC3TponHva971Bsif2Lq4aQW2jCfm
0a+RvO9cdv4RjVkd0/eKXnjpsFRkmggTAmXrlrer1hydENbdq9Fl9QHPxRG/jp6b
SjzqSEc38wbxX2zo9GihPWRHPNjXEJbXGWfwAA6MZpHpI16NEU98+B3OOsrFZ6D7
Zr7BAhVqYXgriICx9K/czFN+oDp5Dpsy1/9NGhx2mg+KJXx6F66MN4ZB24u/rgTR
iC3YGoXfx9vq0tbv2m8zPOoJ3PjmmLzfSwXQszK/GOFvu89r57Hz92K4UpyFiLPf
jUoT7GDfEnU+4OFKdmBDzqFV2xm5TCnoCpjCfi+kbpszThoaF2L3ZvgypxK5K4cf
SkPoU2HgXwL79sXfFknajKKtBFcE55eLggtKmANoBN2NOf+yUQuqwnJRaN+ELtKp
1HJ+ztoPEcrEG3zljNZ77/n8B8kprVA+E4sxzLrNHM+sRzoiDixq+nEB7p5F6+zS
XgH/wanI8NFYgP4w48mM50rboUeeadwGoju7XNNoEcaLzCaGWkoUWNbtH+NGnaAR
OGux0gslpa4mPnHWySU7b/1LZiIop9PyXCqGDyUzjBCaNKQypMMO3BhmvdHf0ug=
=oRNh
-----END PGP MESSAGE-----
fp: 116987A8DD3F78FF8601BF4DB95E8FE6B11C4D09
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA30JDs8MiK29AQ/+JcDqCXFj6/8NsrMx+mv92Xgqo5b8hQC92DxOEVd2kBrE
aqe7LPbhpm8ujuR5rRRNKmnJX1QQXn7GHAua8tA2+7oYVhVJfpIp1m3FlOkv6Jt0
Mz2FMotFfts/Lq5MGUB2WU1fkXMcZ2J9gXZGoEwVRFFATu4lHy6IZKtbYHm8onlM
WXuhX3+uM1Tw4TCaqnyfi8fEGvocpwD1kT4Y2F7VipNVoSbP9DNf9rVIuKfTzLMX
NxueFmfUcLt3Z1/HSV40KkYseaZcLhWOtKbpFTwG/zdzdSIWzCjxPGwcK+nVBDeS
OhFdcoKC7c9GKb1bbxaPq5BwSpy29/PBv7SBM2vfUvyc9MrKvXdh1VzOgTkSAjdH
DxeEtFNMIhrCeCuMZwjBrIckSr3dFh73YqvEbSV/1Z2nK8qLBWKEy4noAOhI0Kxe
T05cCaGFHVJxy34lmb1AMHATLt6ZDDUn+kgiOD13SozMAsS9045MSnJgcVCb953/
cxx5LfyN3KJO/17YFgNlq28yVavFTp5h5en/DexY35nvvACBi7uah5WQh8Y3fbB6
5Eb0t2FcsHY3L11tbjnVz16oFRE/SuS2NK+k20QEo36eBc272cKjkj9CS1w6D3lq
7qFQCBD4NWITn1FgHDNfDVNZI3rocMMp8VgBzpknvBZmRc2PQlW1+jIt/7x+JP3S
XgFd5m3vvtbLhJVG5X0GMbFHC4QaBTou6buKdfvuQ8ZqUb8o52MPNXKmTDW99ywM
5pItfzPtHZ7q8T+rZKEnNcL2TBhgfHsuFzqC06D2jeC/tulvbhw0VtBcnJzSlSg=
=ihPC
-----END PGP MESSAGE-----
fp: BF37903AE6FD294C4C674EE24472A20091BFA792
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hF4DNffZWjBmO5ASAQdAD+Em/15kuzC0vIaYSkTGQS5SwwCGRmBc9V5u5ChsunAw
RiXIlOl3EhpR6qzxCfUgLSr+WEXK20AFGo8gEfCpKqAVE3orPGh4btwcV/AzZyID
1GgBCQIQO4OYcDhulX1kReGuRHVJWLsjvWlUJQjlYPXPaS7QD6vCmie986wNEOAN
kqDyuSsoetM3OdZgTvyj0tmTdNNm9X90xKjyV+wcYKlAkVL82PbnEwIqQhlMoZv/
0Uhdu9hQ3VXC1Q==
=0iem
-----END PGP MESSAGE-----
fp: B1A16011B86BACB56ADB713DB712039D23133661
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA1tId/HHLgxAAQ/+P7hzNKzSA3JVSSAqfAV5umI1hACWf3ticSkT9tlfGYx6
+xWvkwmtLBAumPYwIrVVvKSG2KBdiD/p0CugbpMUA2164IGrJVQsnBpeyV3fgaNQ
GMbb+Jq1Nfh5QsmI0X+D4xcNcPae3Ml+4TXtjXkDlowG2c4x7AHiHKnQj9Agszry
F+IUdlVt4dESbMGv+ck6fz6AqJ3OiQaesRps+FTrWtVhzuu9DIuup4E+nb7qaADz
knmjPfPxX7rSwfAVbvgmGZ0hRM4KaIqt26Fyd0pnnxc37KslgBcQDl2bIu214SKT
vmaSwqCOF1JXe3MAKJjFu0e1Rq+6/Dt9sZxWcXi+uKVqXaQznHXrxXywG8dmV2jZ
SS1rLoHKZ7Sk+3EG9WAfNA0SDNpcRQ11TXCXKYaNkbhsNucKBa3ipGO+l3ypFWNj
zmJMHR9mZuH/cV/DRC7eyWihbcYSAVfOuNYp61KUsW5Z4aYN/yrBZIDi8wqbN2J5
TNI13Opj/3Xvu8mVC4fipORvwRpwlFX5hT1ioDZ/vmtgufWWPNSc7XEN6HIie3OY
8nljJqPOhdYuTStejtBkt/qvqWWGlpPILCKndqTEFoMv5h7ussNV/+6eGUIx3+1Q
G1Hj0Dptw+w9dx/CAh6BVjSCF05892o8UNljOzr0mdxvZYfOrnrMjm2aqWLYO37S
XgGHuVKMpj8zFhIERSZj9q5ZZuH4f7AFgEzeRBghNZCGeMlA9T8BW1ctZ7v20wpL
q5F3s6h/Vpif4WrdcuVwxrsF5Sar08mJaVRQdJrps6hFENwy0qs0zn55gKIae/Q=
=HZ7i
-----END PGP MESSAGE-----
fp: FB44F0746DF25F0B24A2EAE586C8A257C3EC82AB
- created_at: "2024-02-29T15:23:28Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hF4Da5T//DC6DJkSAQdALa6lkOmkWCMYVZj7SE95wbejf6w18ouzh0NeKx1SeTEw
NoAN13YgKuk1b30zfSbjbr1LeGvk4xvDF+1nk+8dLccUPFQO8svT0/L2DhAQ8EV3
0l4Bf3h1T3Hoc28my9LvjvMo7brUGqX6TDRsZiLdOe/wk/EbnuGnTUCtHytxGUIy
dtQa263hpVrA1xRIxHyhHRKACp+4PD3SvmDpQ2u33bVfZ9F9vzRPGXvE6E3Rw8jD
=Dxdr
-----END PGP MESSAGE-----
fp: FBBFAC260D9283D1EF2397DD3CA65E9DD6EB319D
unencrypted_suffix: _unencrypted
version: 3.8.1