Merge main

wiki
Lyes Saadi 2025-07-27 16:02:03 +02:00
commit ead3050178
No known key found for this signature in database
GPG Key ID: 55A1D803917CF39A
100 changed files with 1805 additions and 888 deletions

11
.gitlab-ci.yml 100644
View File

@ -0,0 +1,11 @@
image: nixos/nix:latest
before_script:
- echo "extra-experimental-features = nix-command flakes" >> /etc/nix/nix.conf
- nix-daemon &
nix-flake-check:
timeout: 1h
stage: test
script:
- nix flake check --no-build

View File

@ -34,7 +34,10 @@
flake = with nixpkgs.lib; {
nixosConfigurations =
let
baseModules = [ agenix.nixosModules.default ];
baseModules = [
./modules
agenix.nixosModules.default
];
in
{
apprentix = nixosSystem {
@ -62,11 +65,21 @@
modules = [ ./hosts/vm/neo ] ++ baseModules;
};
periodique = nixosSystem {
specialArgs = inputs;
modules = [ ./hosts/vm/periodique ] ++ baseModules;
};
redite = nixosSystem {
specialArgs = inputs;
modules = [ ./hosts/vm/redite ] ++ baseModules;
};
reverseproxy = nixosSystem {
specialArgs = inputs;
modules = [ ./hosts/vm/reverseproxy ] ++ baseModules;
};
thot = nixosSystem {
specialArgs = inputs;
modules = [ ./hosts/physiques/thot ] ++ baseModules;
@ -76,17 +89,17 @@
specialArgs = inputs;
modules = [ ./hosts/vm/two ] ++ baseModules;
};
vaultwarden = nixosSystem {
specialArgs = inputs;
modules = [ ./hosts/vm/vaultwarden ] ++ baseModules;
};
};
};
perSystem =
{ config, pkgs, ... }:
{
treefmt = {
projectRootFile = "flake.nix";
programs.nixpkgs-fmt.enable = true;
};
devShells = {
default = pkgs.callPackage ./devshells/default.nix { inherit (inputs) agenix; };
};

View File

@ -4,10 +4,7 @@
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
../../../modules/services/nginx.nix
../../../modules/services/restic.nix
./nginx.nix
];
networking.hostId = "bbdd1133";
@ -39,5 +36,19 @@
restic
];
crans = {
enable = true;
networking.adm.enable = false;
resticClient.enable = false;
services = {
resticServer = {
enable = true;
port = 4242;
};
};
};
system.stateVersion = "24.05";
}

View File

@ -0,0 +1,15 @@
{ config, ... }:
{
services.nginx = {
enable = true;
virtualHosts = {
"${config.networking.hostName}.adm.crans.org" = {
locations."/" = {
proxyPass = "http://${config.services.restic.server.listenAddress}";
};
};
};
};
}

View File

@ -2,14 +2,34 @@
Voici la liste des machines virtuelles sur NixOS ainsi que leur utilisation (par ordre alphabétique).
## apprentix
Machine des apprenti⋅e⋅s sous NixOS. Toustes les apprenti⋅e⋅s ont le droit de sudo (les home-nounous ne sont donc pas montés).
## jitsi
Serveur jitsi (vidéoconférence), accessible à <https://jitsi.crans.org>.
## livre
Serveur stirling (manipulation de PDF), accessible à <https://pdf.crans.org>.
## neo
Serveur Matrix (encore non déployé).
Serveur Matrix, bridge IRC <-> Matrix et interface admin pour synapse, accessible à <https://matrix.crans.org/admin>.
## redite
Serveur libreddit, accessible à https://redite.crans.org.
Serveur redlib (client WEB alternatif pour Reddit), accessible à <https://redite.crans.org>.
## reverseproxy
Serveur qui héberge un reverseproxy et une instance de anubis.
## two
Serveur NixOS de test. Vous pouvez vous en servir comme base pour la configuration d'une nouvelle machine.
Serveur NixOS de test. Vous pouvez vous en servir comme base pour la configuration d'une nouvelle machine.
## vaultwarden
Serveur vaultwarden (gestionnaire de mots de passe), accessible à <https://vaultwarden.crans.org>.

View File

@ -1,17 +1,29 @@
{ config, lib, ... }:
{ ... }:
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
];
boot.loader.grub.devices = [ "/dev/sda" ];
networking.hostName = "apprentix";
crans = {
enable = true;
networking = {
id = "50";
srvNat.enable = true;
};
resticClient.when = "01:23";
homeNounou.enable = false;
users.root.passwordFile = ../../../secrets/apprentix/root.age;
};
security.sudo.extraRules = [
{
groups = [ "_user" ];
@ -19,15 +31,5 @@
}
];
age.secrets = {
root-passwd-hash.file = ../../../secrets/apprentix/root.age;
};
users.users.root = {
hashedPasswordFile = config.age.secrets.root-passwd-hash.path;
};
crans.home_nounou.enable = false;
system.stateVersion = "24.11";
}

View File

@ -1,65 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [
{
address = "172.16.10.150";
prefixLength = 24;
}
];
};
ipv6 = {
addresses = [
{
address = "fd00::10:0:ff:fe01:5010";
prefixLength = 64;
}
];
};
};
ens19 = {
ipv4 = {
addresses = [
{
address = "172.16.3.150";
prefixLength = 24;
}
];
routes = [
{
address = "0.0.0.0";
via = "172.16.3.99";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:3::ff:fe01:5003";
prefixLength = 64;
}
];
routes = [
{
address = "::";
via = "2a0c:700:3::ff:fe00:9903";
prefixLength = 0;
}
];
};
};
};
};
}

View File

@ -3,15 +3,29 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
../../../modules/services/jitsi.nix
../../../modules/services/acme.nix
./jitsi.nix
];
networking.hostName = "jitsi";
boot.loader.grub.devices = [ "/dev/vda" ];
crans = {
enable = true;
networking = {
id = "63";
srv = {
enable = true;
ipv4 = "185.230.79.15";
};
};
resticClient.when = "02:34";
services = {
acme.enable = true;
};
};
system.stateVersion = "24.11";
}

View File

@ -1,22 +1,34 @@
# 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, pkgs, modulesPath, ... }:
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk" ];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"sr_mod"
"virtio_blk"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/66101184-15ad-4859-addf-95040bac1145";
fsType = "ext4";
};
fileSystems."/" = {
device = "/dev/disk/by-uuid/66101184-15ad-4859-addf-95040bac1145";
fsType = "ext4";
};
swapDevices = [ ];

View File

@ -0,0 +1,28 @@
{ ... }:
{
services.jitsi-meet = {
enable = true;
hostName = "jitsi.crans.org";
config = {
liveStreaming.enabled = true;
};
};
services.jitsi-videobridge = {
enable = true;
openFirewall = true;
# pour le monitoring
colibriRestApi = true;
};
services.prometheus.exporters.jitsi = {
enable = true;
port = 9700;
};
nixpkgs.config.permittedInsecurePackages = [
"jitsi-meet-1.0.8043"
];
}

View File

@ -1,53 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [{
address = "172.16.10.163";
prefixLength = 24;
}];
};
ipv6 = {
addresses = [{
address = "fd00::10:0:ff:fe01:6310";
prefixLength = 64;
}];
};
};
ens19 = {
ipv4 = {
addresses = [{
address = "185.230.79.15";
prefixLength = 26;
}];
routes = [{
address = "0.0.0.0";
via = "185.230.79.62";
prefixLength = 0;
}];
};
ipv6 = {
addresses = [{
address = "2a0c:700:2::ff:fe01:6302";
prefixLength = 64;
}];
routes = [{
address = "::";
via = "2a0c:700:2::ff:fe00:9902";
prefixLength = 0;
}];
};
};
};
};
}

View File

@ -1,24 +1,23 @@
{ config, ... }:
{ ... }:
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
../../../modules/services/nginx.nix
../../../modules/services/stirling.nix
./stirling.nix
];
networking.hostName = "livre";
boot.loader.grub.devices = [ "/dev/sda" ];
services.nginx.virtualHosts = {
"pdf.crans.org" = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.stirling-pdf.environment.SERVER_PORT}";
};
crans = {
enable = true;
networking = {
id = "40";
srvNat.enable = true;
};
resticClient.when = "03:45";
};
system.stateVersion = "24.11";

View File

@ -1,22 +1,35 @@
# 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, pkgs, modulesPath, ... }:
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/9fed1492-e7b2-4ec2-a5f4-8825bf8e89a0";
fsType = "ext4";
};
fileSystems."/" = {
device = "/dev/disk/by-uuid/9fed1492-e7b2-4ec2-a5f4-8825bf8e89a0";
fsType = "ext4";
};
swapDevices = [ ];
@ -30,4 +43,3 @@
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View File

@ -10,4 +10,16 @@
SYSTEM_DEFAULTLOCALE = "fr-FR";
};
};
services.nginx = {
enable = true;
virtualHosts = {
"pdf.crans.org" = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.stirling-pdf.environment.SERVER_PORT}";
};
};
};
};
}

View File

@ -3,15 +3,26 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
./mediawiki.nix
../../../modules
../../../modules/crans/nullmailer.nix
../../../modules/services/mediawiki.nix
];
networking.hostName = "mediakiwi";
boot.loader.grub.devices = [ "/dev/sda" ];
crans = {
enable = true;
networking = {
id = "144";
srvNat.enable = true;
};
# Enable when deploying the real mediakiwi
resticClient.enable = false;
};
system.stateVersion = "25.05";
}

View File

@ -1,57 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [
{
address = "172.16.10.144";
prefixLength = 24;
}
];
};
ipv6 = {
addresses = [
{
address = "fd00::10:0:ff:fe01:4410";
prefixLength = 64;
}
];
};
};
ens19 = {
ipv4 = {
addresses = [{
address = "172.16.3.144";
prefixLength = 24;
}];
routes = [{
address = "0.0.0.0";
via = "172.16.3.99";
prefixLength = 0;
}];
};
ipv6 = {
addresses = [{
address = "2a0c:700:3::ff:fe01:4403";
prefixLength = 64;
}];
routes = [{
address = "::";
via = "2a0c:700:3::ff:fe00:9903";
prefixLength = 0;
}];
};
};
};
};
}

View File

@ -3,16 +3,33 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
../../../modules/services/matrix.nix
../../../modules/services/synapse-admin.nix
./matrix.nix
./matrix-appservice-irc.nix
./synapse-admin.nix
];
boot.loader.grub.devices = [ "/dev/sda" ];
networking.hostName = "neo";
crans = {
enable = true;
networking = {
id = "41";
srv = {
enable = true;
ipv4 = "185.230.79.5";
};
};
resticClient.when = "04:56";
services = {
acme.enable = true;
coturn.enable = true;
};
};
system.stateVersion = "24.11";
}

View File

@ -1,7 +1,8 @@
{ config
, pkgs
, lib
, ...
{
config,
pkgs,
lib,
...
}:
let

View File

@ -1,35 +1,28 @@
{ config, ... }:
{
imports = [
./acme.nix
./coturn.nix
./matrix-appservice-irc.nix
./nginx.nix
];
age.secrets = {
ldap_synapse_password = {
file = ../../secrets/neo/ldap_synapse_password.age;
file = ../../../secrets/neo/ldap_synapse_password.age;
owner = "matrix-synapse";
};
database_extra_config = {
file = ../../secrets/neo/database_extra_config.age;
file = ../../../secrets/neo/database_extra_config.age;
owner = "matrix-synapse";
};
note_oidc_extra_config = {
file = ../../secrets/neo/note_oidc_extra_config.age;
file = ../../../secrets/neo/note_oidc_extra_config.age;
owner = "matrix-synapse";
};
appservice_irc_db_env = {
file = ../../secrets/neo/appservice_irc_db_env.age;
file = ../../../secrets/neo/appservice_irc_db_env.age;
};
coturn_auth_secret = {
file = ../../secrets/neo/coturn_auth_secret.age;
file = ../../../secrets/neo/coturn_auth_secret.age;
owner = "turnserver";
};
};

View File

@ -1,62 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [
{
address = "172.16.10.141";
prefixLength = 24;
}
];
};
ipv6 = {
addresses = [
{
address = "fd00::10:0:ff:fe01:4110";
prefixLength = 64;
}
];
};
};
ens19 = {
ipv4 = {
addresses = [
{
address = "185.230.79.5";
prefixLength = 26;
}
];
routes = [
{
address = "0.0.0.0";
via = "185.230.79.62";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:2::ff:fe01:4102";
prefixLength = 64;
}
];
routes = [{
address = "::";
via = "2a0c:700:2::ff:fe00:9902";
prefixLength = 0;
}];
};
};
};
firewall = {
enable = true;
};
};
}

View File

@ -0,0 +1,29 @@
{ pkgs, ... }:
let
synapse-admin_over = pkgs.synapse-admin-etkecc.overrideAttrs (_: {
yarnBuildFlags = "--base=/admin";
});
synapse-admin = synapse-admin_over.withConfig {
restrictBaseUrl = [
"https://matrix.crans.org"
];
asManagedUsers = [
"^@ircbot:crans\\.org$"
];
};
in
{
services.nginx = {
enable = true;
virtualHosts = {
"matrix.crans.org" = {
locations."/admin/".alias = synapse-admin + "/";
locations."=/admin".extraConfig = ''
return 301 /admin/;
'';
};
};
};
}

View File

@ -0,0 +1,24 @@
{ ... }:
{
imports = [
./element.nix
./hardware-configuration.nix
];
networking.hostName = "periodique";
boot.loader.grub.devices = [ "/dev/sda" ];
crans = {
enable = true;
networking = {
id = "18";
srvNat.enable = true;
};
resticClient.when = "02:56";
};
system.stateVersion = "24.11";
}

View File

@ -0,0 +1,28 @@
{ pkgs, ... }:
{
services.nginx = {
enable = true;
virtualHosts = {
"element.crans.org" = {
root = pkgs.element-web.override {
conf = {
default_server_config = {
"m.homeserver" = {
base_url = "https://matrix.crans.org/";
server_name = "crans.org";
};
};
default_theme = "light";
features = {
feature_video_rooms = true;
feature_group_calls = true;
feature_element_call_video_rooms = true;
};
};
};
};
};
};
}

View File

@ -0,0 +1,32 @@
# 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, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/ad1cdd57-44a2-4e1c-83c7-8810a567e0f7";
fsType = "ext4";
};
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;
# networking.interfaces.ens19.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View File

@ -7,14 +7,14 @@
ipv4 = {
addresses = [{
address = "172.16.10.140";
address = "172.16.10.118";
prefixLength = 24;
}];
};
ipv6 = {
addresses = [{
address = "fd00::10:0:ff:fe01:4010";
address = "fd00::10:0:ff:fe01:1810";
prefixLength = 64;
}];
};
@ -25,7 +25,7 @@
ipv4 = {
addresses = [{
address = "172.16.3.140";
address = "172.16.3.118";
prefixLength = 24;
}];
routes = [{
@ -37,7 +37,7 @@
ipv6 = {
addresses = [{
address = "2a0c:700:3::ff:fe01:4003";
address = "2a0c:700:3::ff:fe01:1803";
prefixLength = 64;
}];
routes = [{

View File

@ -3,14 +3,22 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
../../../modules/services/libreddit.nix
./redlib.nix
];
networking.hostName = "redite";
boot.loader.grub.devices = [ "/dev/sda" ];
crans = {
enable = true;
networking = {
id = "39";
srvNat.enable = true;
};
resticClient.when = "06:18";
};
system.stateVersion = "23.11";
}

View File

@ -1,65 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [
{
address = "172.16.10.139";
prefixLength = 24;
}
];
};
ipv6 = {
addresses = [
{
address = "fd00::10:0:ff:fe01:3910";
prefixLength = 64;
}
];
};
};
ens19 = {
ipv4 = {
addresses = [
{
address = "172.16.3.139";
prefixLength = 24;
}
];
routes = [
{
address = "0.0.0.0";
via = "172.16.3.99";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:3::ff:fe01:3903";
prefixLength = 64;
}
];
routes = [
{
address = "::";
via = "2a0c:700:3::ff:fe00:9903";
prefixLength = 0;
}
];
};
};
};
};
}

View File

@ -1,7 +1,7 @@
{ ... }:
{
services.libreddit = {
services.redlib = {
openFirewall = true;
port = 80;
enable = true;

View File

@ -0,0 +1,34 @@
{ pkgs, ... }:
{
imports = [
./hardware-configuration.nix
./reverseproxy.nix
];
networking.hostName = "reverseproxy";
boot.loader.grub.devices = [ "/dev/sda" ];
users.users."nginx".home = "/var/lib/nginx";
users.users."anubis".extraGroups = [ "nginx" ];
crans = {
enable = true;
networking = {
id = "51";
srvNat.enable = true;
srv = {
enable = true;
interface = "ens20";
ipv4 = "185.230.79.42";
};
};
resticClient.when = "03:42";
};
system.stateVersion = "25.05";
}

View File

@ -0,0 +1,33 @@
# 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, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/c4c2de17-2965-4c0a-b4c5-7d518712c9aa";
fsType = "ext4";
};
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;
# networking.interfaces.ens19.useDHCP = lib.mkDefault true;
# networking.interfaces.ens20.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View File

@ -0,0 +1,198 @@
{ pkgs, ... }:
let
anubisBotsMirror = pkgs.writeText "anubis_bots_mirror.yaml"
''
- name: whitelist-crans
action: ALLOW
remote_addresses:
- 185.230.79.0/22
- 2a0c:700::/32
- 46.105.102.188/32
- 2001:41d0:2:d5bc::/128
- name: no-user-agent-string
action: DENY
expression: userAgent == ""
- name: ban-gpt
user_agent_regex: ".*gpt.*"
action: DENY
- name: ban-bot
user_agent_regex: ".*(b|B)ot.*"
action: DENY
- name: ban-WebKit
action: DENY
expression:
all:
- userAgent.startsWith("Mozilla")
- userAgent.matches("AppleWebKit")
- userAgent.matches("Safari")
- userAgent.matches("Chrome")
- name: ban-Barkrowler
user_agent_regex: ".*Barkrowler.*"
action: DENY
'';
anubisMirror = pkgs.writeText "anubis_mirror.json"
''
{
"bots": [
{
"import": "${anubisBotsMirror}"
},
{
"name": "allow-repo",
"path_regex": "^...*",
"action": "ALLOW"
},
{
"name": "deny-other",
"path_regex": ".*",
"action": "ALLOW"
}
]
}
'';
antibot = pkgs.writeText "antibot.yaml"
''
- name: whitelist-crans
action: ALLOW
remote_addresses:
- 185.230.79.0/22
- 2a0c:700::/32
- 46.105.102.188/32
- 2001:41d0:2:d5bc::/128
- name: no-user-agent-string
action: DENY
expression: userAgent == ""
- name: ban-gpt
user_agent_regex: ".*gpt.*"
action: DENY
- name: ban-bot
user_agent_regex: ".*(b|B)ot.*"
action: DENY
- name: ban-WebKit
action: CHALLENGE
expression:
all:
- userAgent.startsWith("Mozilla")
- userAgent.matches("AppleWebKit")
- userAgent.matches("Safari")
- userAgent.matches("Chrome")
- name: ban-Barkrowler
user_agent_regex: ".*Barkrowler.*"
action: DENY
'';
anubisChallenge = pkgs.writeText "anubis_challenge.json"
''
{
"bots": [
{
"import": "${antibot}"
},
{
"name": "challenge-other",
"path_regex": "^*",
"action": "CHALLENGE"
}
]
}
'';
anubisMirrors = pkgs.writeText "anubis_mirrors.json"
''
{
"bots": [
{
"import": "${antibot}"
},
{
"name": "deny-other",
"path_regex": ".*cdimage-.*",
"action": "ALLOW"
},
{
"name": "allow-repo",
"path_regex": "^...*",
"action": "ALLOW"
},
{
"name": "deny-other",
"path_regex": ".*",
"action": "CHALLENGE"
}
]
}
'';
in {
crans = {
reverseProxy = {
enable = true;
virtualHosts = {
"eclat" = {
anubisConfig = "${anubisMirror}";
httpOnly = true;
target = "172.16.10.104";
};
"eclats" = {
anubisConfig = "${anubisMirrors}";
target = "172.16.10.104";
};
"install-party" = {
anubisConfig = "${anubisChallenge}";
target = "/var/www/install-party.crans.org";
serverAliases = [
"i-p"
"adopteunmanchot"
"adopteunpingouin"
];
};
"lists" = {
anubisConfig = "${anubisChallenge}";
target = "172.16.10.110";
};
"mediawiki" = {
anubisConfig = "${anubisChallenge}";
target = "172.16.10.144";
serverAliases = [
"mediakiwi"
];
};
"mirrors" = {
anubisConfig = "${anubisMirrors}";
target = "172.16.10.104";
};
"mirror" = {
anubisConfig = "${anubisMirror}";
httpOnly = true;
target = "172.16.10.104";
};
"perso" = {
anubisConfig = "${anubisChallenge}";
target = "172.16.10.31";
serverAliases = [
"clubs"
];
};
"wiki" = {
anubisConfig = "${anubisChallenge}";
target = "[fd00::10:0:ff:fe01:6110]"; # l'ipv4 marche pas
serverAliases = [
"wikipedia"
];
};
};
};
services = {
acme.enable = true;
};
};
}

View File

@ -3,13 +3,24 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
../../../modules
];
networking.hostName = "two";
boot.loader.grub.devices = [ "/dev/sda" ];
crans = {
enable = true;
networking = {
id = "35";
srvNat = {
enable = true;
interface = "ens19";
};
};
resticClient.when = "07:29";
};
system.stateVersion = "23.11";
}

View File

@ -1,65 +0,0 @@
{ ... }:
{
networking = {
interfaces = {
ens18 = {
ipv4 = {
addresses = [
{
address = "172.16.10.135";
prefixLength = 24;
}
];
};
ipv6 = {
addresses = [
{
address = "fd00::10:0:ff:fe01:3510";
prefixLength = 64;
}
];
};
};
ens19 = {
ipv4 = {
addresses = [
{
address = "172.16.3.135";
prefixLength = 24;
}
];
routes = [
{
address = "0.0.0.0";
via = "172.16.3.99";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:3::ff:fe01:3503";
prefixLength = 64;
}
];
routes = [
{
address = "::";
via = "2a0c:700:3::ff:fe00:9903";
prefixLength = 0;
}
];
};
};
};
};
}

View File

@ -0,0 +1,24 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
./vaultwarden.nix
];
networking.hostName = "vaultwarden";
boot.loader.grub.devices = [ "/dev/sda" ];
crans = {
enable = true;
networking = {
id = "59";
srvNat.enable = true;
};
resticClient.when = "04:44";
};
system.stateVersion = "24.05";
}

View File

@ -0,0 +1,45 @@
# 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,
pkgs,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/c97aeccd-b88a-407e-a08d-f821a3f34936";
fsType = "ext4";
};
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;
# networking.interfaces.ens19.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View File

@ -0,0 +1,47 @@
{ config, lib, ... }:
{
age.secrets = {
vaultwarden-env = {
file = ../../../secrets/vaultwarden/env.age;
};
};
services.vaultwarden = {
enable = true;
dbBackend = "postgresql";
environmentFile = config.age.secrets.vaultwarden-env.path;
config = {
ROCKET_PORT = 8222;
SENDMAIL_COMMAND = "${config.security.wrapperDir}/sendmail";
};
};
users.users.vaultwarden.extraGroups = [ "nullmailer" ];
systemd.services.vaultwarden = {
path = [ "/run/wrappers" ];
serviceConfig = {
NoNewPrivileges = lib.mkForce false;
PrivateUsers = lib.mkForce false;
SystemCallFilter = lib.mkForce [ "@system-service" ];
RestrictAddressFamilies = [
"AF_LOCAL"
"AF_NETLINK"
];
ReadWritePaths = [ "/var/spool/nullmailer/" ];
};
};
services.nginx = {
enable = true;
virtualHosts."vaultwarden.crans.org" = {
locations."/" = {
proxyPass = "http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT}";
proxyWebsockets = true;
};
};
};
}

View File

@ -12,4 +12,4 @@ Le dossier [`crans`](crans) contient tous les services/programmes communs à tou
## Services
Le dossier [`services`](services) contient tous les services/programmes utilisés par un nombre restreint de machines. On peut y déclarer deux types de configurations : les configurations directement inscrites car seront toujours utilisées de la même façon, et les configurations mettant en place un système d'options et de configuration générée pour avoir plus de granularités. Cette seconde utilisation est plus complexe à mettre en place et nécessite une meilleure compréhension de `nix`.
Le dossier [`services`](services) contient tous les services/programmes utilisés par un nombre restreint de machines. On y déclare les configurations mettant en place un système d'options et de configuration générée pour avoir plus de granularités.

View File

@ -2,9 +2,15 @@
Ce dossier contient tous les modules commun à la majorité des machines virtuelles du Crans. On y retrouve par exemple les utilisateurices, les `home_nounou`, etc.
Ces modules sont présentés sous forme d'option (si besoin), afin de pouvoir contrôler la présence ou l'absence de certains services.
## `default.nix`
Le fichier [`default.nix`](default.nix), comme tous les autres du même nom, importe tous les autres fichiers du dossier. De plus, il déclare des programmes utiles à avoir en permanence, tels que `ssh`, `git`, `nvim`, ...
Le fichier [`default.nix`](default.nix), comme tous les autres du même nom, importe tous les autres fichiers du dossier. De plus, il déclare des programmes utiles à avoir en permanence, tels que `ssh`, `git`, `nvim`, ... et importe les options par défaut qui sont utile pour la majorité des machines.
## `age.nix`
Le fichier [`age.nix`](age.nix) contient la configuration commune d'agenix (voir [`../../secrets/README.md`](../../secrets/README.md)).
## `home.nix`
@ -14,18 +20,38 @@ Le fichier [`home.nix`](home.nix) monte les `home_nounou` par NFS à partir de `
Le fichier [`locale.nix`](locale.nix) déclare simplement les locales à utiliser.
## `monitoring.nix`
Le fichier [`monitoring.nix`] déploie une instance prometheus avec un exporteur node contactable sur le port `9100` par défaut, ainsi qu'un exporteur nginx (si pertinent) sur le port `9117`.
## `networking.nix`
Le fichier [`networking.nix`](networking.nix) a moins d'utilité que ce à quoi on pourrait s'attendre : comme chaque machine possède sa propre configuration réseau, les seules choses communes à déclarer sont : la non-utilisation de DHCP, la non-utilisation d'un pare-feu par défault ainsi que l'ajout d'un serveur DNS.
Le fichier [`networking.nix`](networking.nix) contient toute la configuration réseau des machines : l'option `crans.networking.id` permet de configurer la majorité du réseau automatiquement (il faut alors déployer interface par interface).
## `ntp.nix`
Le fichier [`ntp.nix`](ntp.nix) active simplement le NTP (Network Time Protocol) en ajoutant le serveur `ntp.adm.crans.org` comme serveur de temps.
## `sops.nix`
## `nullmailer.nix`
Le fichier [`sops.nix`](sops.nix) déclare l'utilisation de `sops` dans la configuration (voir [ce `README.md`](../../secrets/README.md) pour plus de détails) et importe la clef publique SSH de la machine pour pouvoir l'utiliser dans la gestion des secrets.
Le fichier [`nullmailer.nix`](nullmailer.nix) déploie un client SMTP sur chaque serveur afin de pouvoir envoyer des mails en le nom du Crans.
## `packages.nix`
Le fichier [`packages.nix`](packages.nix) contient la liste des programmes installés par défaut sur les machines du Crans.
## `restic_client.nix`
Le fichier [`restic_client`](restic_client.nix) permet de configurer un client restic sur chaque machine pour faire des backups et les envoyer sur le serveur thot.
## `ssh.nix`
Le fichier [`ssh.nix`](ssh.nix) contient la configuration SSH pour toutes les machines.
## `users.nix`
Le fichier [`users.nix`](users.nix) configure les `_users` à partir du LDAP d'administration, et configure les droits pour que les `_nounou` aient les accès `sudo`. Il configure également le user `root` en lui donnant son mot de passe haché à travers un fichier `sops`.
Le fichier [`users.nix`](users.nix) configure les `_users` à partir du LDAP d'administration, et configure les droits pour que les `_nounou` aient les accès `sudo`. Il configure également le user `root` en lui donnant son mot de passe haché à travers un fichier `age`.
## `virtualisation.nix`
Le fichier [`virtualisation.nix`](virtualisation.nix) contient des paramètres utiles pour la virtualisation (pour les VM en priorité donc).

View File

@ -1,5 +1,10 @@
{ pkgs, ... }:
{ lib, config, ... }:
let
cfg = config.crans;
inherit (lib) mkEnableOption mkIf;
in
{
imports = [
./age.nix
@ -10,32 +15,28 @@
./restic_client.nix
./monitoring.nix
./nullmailer.nix
./packages.nix
./ssh.nix
./users.nix
./virtualisation.nix
];
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0,115200" ];
services.openssh = {
enable = true;
options.crans = {
enable = mkEnableOption "Configuration commune à toutes les machines du Crans";
};
nixpkgs.config.allowUnfree = true;
# Enable some utility programs.
programs.git.enable = true;
programs.htop.enable = true;
programs.neovim.enable = true;
programs.screen.enable = true;
programs.tmux.enable = true;
programs.vim.enable = true;
environment.systemPackages = with pkgs; [
bat
fd
helix
nfs-utils
ripgrep
shelldap
];
config = mkIf cfg.enable {
crans = {
homeNounou.enable = lib.mkDefault true;
monitoring.enable = true;
networking = {
enable = true;
adm.enable = lib.mkDefault true;
};
resticClient.enable = lib.mkDefault true;
users = {
ldap.enable = true;
};
};
};
}

View File

@ -1,24 +1,17 @@
{
pkgs,
lib,
config,
...
}:
{ lib, config, ... }:
let
cfg = config.crans.home_nounou;
cfg = config.crans.homeNounou;
inherit (lib) mkEnableOption mkIf;
in
{
options.crans.home_nounou = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Monter les home nounous";
};
options.crans.homeNounou = {
enable = mkEnableOption "Monter /home_nounou.";
};
config = lib.mkIf cfg.enable {
config = mkIf cfg.enable {
fileSystems.home_nounou = {
mountPoint = "/home_nounou";
device = "172.16.10.1:/pool/home";

View File

@ -1,17 +1,44 @@
{ config, ... }:
{
services.prometheus.exporters = {
node = {
enable = true;
port = 9100;
{ config, lib, ... }:
openFirewall = true;
};
let
cfg = config.crans.monitoring;
inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
in
{
options.crans.monitoring = {
enable = mkEnableOption "Monitoring prometheus de la machine.";
nginx = {
enable = config.services.nginx.enable;
port = 9117;
scrapeUri = "http://[::1]:6424/stub_status";
enable = mkOption {
type = types.bool;
default = config.services.nginx.enable;
example = true;
description = "Monitoring de Nginx par prometheus.";
};
};
};
config = mkIf cfg.enable {
services.prometheus.exporters = {
node = {
enable = true;
port = 9100;
openFirewall = true;
};
nginx = {
enable = cfg.nginx.enable;
port = 9117;
scrapeUri = "http://[::1]:6424/stub_status";
};
};
};
}

View File

@ -1,10 +1,202 @@
{ lib, ... }:
{ lib, config, ... }:
let
cfg = config.crans.networking;
inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
in
{
# Les interfaces ne sont pas déclarées ici : elles sont propres à chaque VM.
networking = {
useDHCP = false;
firewall.enable = lib.mkDefault false;
nameservers = [ "172.16.10.128" ];
options.crans.networking = {
enable = mkEnableOption "Configuration réseaux commune à toutes les machines du Crans.";
id = mkOption {
type = types.str;
example = "35";
description = "Le numéro de la VM dans Proxmox (sans le `1` devant).";
};
adm = {
enable = mkEnableOption "Configuration du VLAN adm.";
interface = mkOption {
type = types.str;
default = "ens18";
example = "ens20";
description = "Nom de l'interface réseau sur laquelle est située le VLAN adm.";
};
};
srv = {
enable = mkEnableOption "Configuration du VLAN srv.";
interface = mkOption {
type = types.str;
default = "ens19";
example = "ens20";
description = "Nom de l'interface réseau sur laquelle est située le VLAN srv.";
};
ipv4 = mkOption {
type = types.str;
example = "185.230.79.1";
description = "Adresse IPv4 de la machine.";
};
};
srvNat = {
enable = mkEnableOption "Configuration du VLAN srv-nat.";
interface = mkOption {
type = types.str;
default = "ens19";
example = "ens20";
description = "Nom de l'interface réseau sur laquelle est située le VLAN srv-nat.";
};
};
san = {
enable = mkEnableOption "Configuration du VLAN san.";
interface = mkOption {
type = types.str;
example = "ens19";
description = "Nom de l'interface réseau sur laquelle est située le VLAN san.";
};
};
};
config = mkIf cfg.enable {
networking = {
useDHCP = false;
firewall.enable = lib.mkDefault false;
nameservers = [ "172.16.10.128" ];
# La configuration des interfaces se fait de la manière suivante :
# elle est écrite de manière générique pour toutes les machines, puis
# on filtre pour ne garder que les interfaces activées. nix fait de
# l'évaluation paresseuse donc ça fonctionne bien !
interfaces =
# On change le nom des interfaces de "adm", "srv", ... pour leur vrai
# nom (on ne le met pas directement pour faire fonctionner le filter
# plus bas).
lib.attrsets.mapAttrs'
(interface: conf: {
name = cfg."${interface}".interface;
value = conf;
})
(
# On filtre sur les interfaces activées
lib.attrsets.filterAttrs (interface: _: cfg."${interface}".enable) {
# Configuration du VLAN adm
adm = {
ipv4.addresses = [
{
address = "172.16.10.1${cfg.id}";
prefixLength = 24;
}
];
ipv6.addresses = [
{
address = "fd00::10:0:ff:fe01:${cfg.id}10";
prefixLength = 64;
}
];
};
# Configuration du VLAN srv
srv = {
ipv4 = {
addresses = [
{
address = cfg.srv.ipv4;
prefixLength = 26;
}
];
routes = [
{
address = "0.0.0.0";
via = "185.230.79.62";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:2::ff:fe01:${cfg.id}02";
prefixLength = 64;
}
];
routes = [
{
address = "::";
via = "2a0c:700:2::ff:fe00:9902";
prefixLength = 0;
}
];
};
};
# Configuration du VLAN srv-nat
srvNat = {
ipv4 = {
addresses = [
{
address = "172.16.3.1${cfg.id}";
prefixLength = 24;
}
];
routes = [
{
address = "0.0.0.0";
via = "172.16.3.99";
prefixLength = 0;
}
];
};
ipv6 = {
addresses = [
{
address = "2a0c:700:3::ff:fe01:${cfg.id}03";
prefixLength = 64;
}
];
routes = [
{
address = "::";
via = "2a0c:700:3::ff:fe00:9903";
prefixLength = 0;
}
];
};
};
# Configuration du VLAN san
san = {
ipv4.addresses = [
{
address = "172.16.4.1${cfg.id}";
prefixLength = 24;
}
];
ipv6.addresses = [
{
address = "fd00::4:0:ff:fe01:${cfg.id}04";
prefixLength = 64;
}
];
};
}
);
};
};
}

View File

@ -4,6 +4,7 @@
services.nullmailer = {
enable = true;
setSendmail = true;
config = {
remotes = ''
smtp.adm.crans.org smtp

View File

@ -0,0 +1,21 @@
{ pkgs, ... }:
{
programs.git.enable = true;
programs.htop.enable = true;
programs.neovim.enable = true;
programs.screen.enable = true;
programs.tmux.enable = true;
programs.vim.enable = true;
environment.systemPackages = with pkgs; [
bat
coreutils-full
fd
helix
inetutils
nfs-utils
ripgrep
shelldap
];
}

View File

@ -1,36 +1,73 @@
{ config, ... }:
{ config, lib, ... }:
let
cfg = config.crans.resticClient;
inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
in
{
age.secrets = {
restic-base-env.file = ../../secrets/restic/client_env.age;
restic-base-repo.file = ../../secrets/restic/${config.networking.hostName}/base-repo.age;
restic-base-password.file = ../../secrets/restic/${config.networking.hostName}/base-password.age;
options.crans.resticClient = {
enable = mkEnableOption "Configuration générale pour le client restic.";
additionalPaths = mkOption {
type = types.listOf types.path;
default = [ ];
example = [ "/backup" ];
description = "Chemins à backuper en plus de ceux par défaut.";
};
additionalExcludes = mkOption {
type = types.listOf types.path;
default = [ ];
example = [ "/var/lib/<service>/cache" ];
description = "Chemins à exclure des backups en plus de ceux par défaut.";
};
when = mkOption {
type = types.str;
example = "05:42";
description = "À quelle heure faire les backups.";
};
};
services.restic.backups = {
base = {
exclude = [
"/var/cache"
"/var/lib/lxcfs"
];
initialize = true;
passwordFile = config.age.secrets.restic-base-password.path;
repositoryFile = config.age.secrets.restic-base-repo.path;
environmentFile = config.age.secrets.restic-base-env.path;
paths = [
"/etc"
"/var"
];
timerConfig = {
OnCalendar = "00:00";
RandomizedDelaySec = "6h";
config = mkIf cfg.enable {
age.secrets = {
restic-base-env.file = ../../secrets/restic/client_env.age;
restic-base-repo.file = ../../secrets/restic/${config.networking.hostName}/base-repo.age;
restic-base-password.file = ../../secrets/restic/${config.networking.hostName}/base-password.age;
};
services.restic.backups = {
base = {
initialize = true;
passwordFile = config.age.secrets.restic-base-password.path;
repositoryFile = config.age.secrets.restic-base-repo.path;
environmentFile = config.age.secrets.restic-base-env.path;
paths = [
"/etc"
"/var"
] ++ cfg.additionalPaths;
exclude = [
"/var/cache"
"/var/lib/lxcfs"
] ++ cfg.additionalExcludes;
timerConfig = {
OnCalendar = cfg.when;
RandomizedDelaySec = "6h";
};
pruneOpts = [
"--keep-daily 2"
"--keep-weekly 2"
"--keep-monthly 2"
"--keep-yearly 1"
];
};
pruneOpts = [
"--keep-daily 2"
"--keep-weekly 2"
"--keep-monthly 2"
"--keep-yearly 1"
];
};
};
}

View File

@ -0,0 +1,11 @@
{ ... }:
{
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
};
};
}

View File

@ -1,50 +1,75 @@
{ config, lib, ... }:
{
users = {
mutableUsers = false;
let
cfg = config.crans.users;
inherit (lib)
mkEnableOption
mkOption
types
;
in
{
options.crans.users = {
ldap = {
enable = true;
base = "dc=crans,dc=org";
server = "ldaps://ldap-adm.adm.crans.org/";
daemon = {
enable = true;
extraConfig = ''
ldap_version 3
tls_reqcert allow
map passwd loginShell /run/current-system/sw/bin/bash
'';
enable = mkEnableOption "Authentification par le LDAP adm.";
};
root = {
passwordFile = mkOption {
type = types.path;
default = ../../secrets/common/root.age;
example = ../../secrets/apprentix/root.age;
description = "Fichier chiffré par age contenant le mot de passe root.";
};
};
};
security.sudo = {
enable = true;
extraConfig = ''
Defaults passprompt_override
Defaults passprompt="[sudo] mot de passe pour %p sur %h: "
'';
extraRules = [
{
groups = [ "_user" ];
runAs = "root:ALL";
commands = [ "NOPASSWD:/usr/bin/qm list" ];
}
{
groups = [ "_nounou" ];
commands = [ "ALL" ];
}
];
};
config = {
age.secrets.root-passwd-hash = {
file = cfg.root.passwordFile;
};
age.secrets.root-passwd-hash = {
file = lib.mkDefault ../../secrets/common/root.age;
};
users = {
mutableUsers = false;
users.users.root = {
hashedPasswordFile = lib.mkDefault config.age.secrets.root-passwd-hash.path;
};
users.root = {
hashedPasswordFile = config.age.secrets.root-passwd-hash.path;
};
services.openssh.settings.PermitRootLogin = "yes";
ldap = {
enable = cfg.ldap.enable;
base = "dc=crans,dc=org";
server = "ldaps://ldap-adm.adm.crans.org/";
daemon = {
enable = true;
extraConfig = ''
ldap_version 3
tls_reqcert allow
map passwd loginShell /run/current-system/sw/bin/bash
'';
};
};
};
security.sudo = {
enable = true;
extraConfig = ''
Defaults passprompt_override
Defaults passprompt="[sudo] mot de passe pour %p sur %h: "
'';
extraRules = [
{
groups = [ "_user" ];
runAs = "root:ALL";
commands = [ "NOPASSWD:/usr/bin/qm list" ];
}
{
groups = [ "_nounou" ];
commands = [ "ALL" ];
}
];
};
};
}

View File

@ -0,0 +1,6 @@
{ ... }:
{
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0,115200" ];
}

View File

@ -3,10 +3,25 @@
{
imports = [
./crans
./services
];
nix.settings.experimental-features = [
"flakes"
"nix-command"
];
nix = {
settings = {
experimental-features = [
"flakes"
"nix-command"
];
auto-optimise-store = true;
};
};
nixpkgs.config = {
allowUnfree = true;
};
boot.tmp = {
useTmpfs = true;
cleanOnBoot = true;
};
}

View File

@ -1,24 +1,36 @@
{ config, ... }:
{ config, lib, ... }:
let
cfg = config.crans.services.acme;
inherit (lib) mkEnableOption mkIf;
in
{
age.secrets = {
acme-env.file = ../../secrets/acme/env.age;
options.crans.services.acme = {
enable = mkEnableOption "Activer les certificats ACME via let's encrypt.";
};
security.acme = {
acceptTerms = true;
defaults = {
email = "root@crans.org";
dnsPropagationCheck = false;
config = mkIf cfg.enable {
age.secrets = {
acme-env.file = ../../secrets/acme/env.age;
};
certs."crans.org" = {
domain = "*.crans.org";
dnsProvider = "rfc2136";
# Contient le serveur à contacter avec le protocole
# et le mot de passe
environmentFile = config.age.secrets.acme-env.path;
security.acme = {
acceptTerms = true;
defaults = {
email = "root@crans.org";
dnsPropagationCheck = false;
};
certs."crans.org" = {
domain = "*.crans.org";
dnsProvider = "rfc2136";
# Contient le serveur à contacter avec le protocole
# et le mot de passe
environmentFile = config.age.secrets.acme-env.path;
};
};
};
}

View File

@ -1,59 +1,100 @@
{ config, ... }:
{ config, lib, ... }:
let
cfg = config.crans.services.coturn;
inherit (lib)
mkEnableOption
mkOption
mkIf
types
;
in
{
services.coturn = {
enable = true;
no-cli = true;
no-tcp-relay = true;
min-port = 49000;
max-port = 50000;
use-auth-secret = true;
static-auth-secret-file = config.age.secrets.coturn_auth_secret.path;
realm = "crans.org";
cert = "/var/lib/acme/crans.org/full.pem";
pkey = "/var/lib/acme/crans.org/key.pem";
extraConfig = ''
verbose
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
'';
options.crans.services.coturn = {
enable = mkEnableOption "Coturn, un serveur TURN open-source.";
secretFile = mkOption {
type = types.path;
default = config.age.secrets.coturn_auth_secret.path;
description = "Fichier contenant le secret de configuration du serveur.";
};
fqdn = mkOption {
type = types.str;
default = "crans.org";
description = "Domaine pour lequel le serveur coturn est configuré.";
};
certFile = mkOption {
type = types.path;
default = "/var/lib/acme/${cfg.fqdn}/full.pem";
description = "Fichier contenant le certificat associé au FQDN.";
};
keyFile = mkOption {
type = types.path;
default = "/var/lib/acme/${cfg.fqdn}/key.pem";
description = "Fichier contenant la clef associé au FQDN.";
};
};
networking.firewall = {
allowedTCPPorts = [
3478
5349
];
allowedUDPPorts = [
3478
5349
];
allowedUDPPortRanges = [
{
from = config.services.coturn.min-port;
to = config.services.coturn.max-port;
}
];
config = mkIf cfg.enable {
services.coturn = {
enable = true;
no-cli = true;
no-tcp-relay = true;
min-port = 49000;
max-port = 50000;
use-auth-secret = true;
static-auth-secret-file = cfg.secretFile;
realm = cfg.fqdn;
cert = cfg.certFile;
pkey = cfg.keyFile;
extraConfig = ''
verbose
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
'';
};
networking.firewall = {
allowedTCPPorts = [
3478
5349
];
allowedUDPPorts = [
3478
5349
];
allowedUDPPortRanges = [
{
from = config.services.coturn.min-port;
to = config.services.coturn.max-port;
}
];
};
};
}

View File

@ -0,0 +1,11 @@
{ ... }:
{
imports = [
./acme.nix
./coturn.nix
./nginx.nix
./restic.nix
./reverseproxy.nix
];
}

View File

@ -1,37 +0,0 @@
{...}:
{
services.jitsi-meet = {
enable = true;
hostName = "jitsi.crans.org";
config = {
# vient de l'ancienne config liveStreamingEnable = true
liveStreaming.enabled = true;
};
};
services.jitsi-videobridge = {
enable = true;
#xmppConfigs."localhost" = {
# port = 5347;
#};
openFirewall = true;
};
services.jicofo = {
enable = true;
config = {
xmpp = {
trusted-domains = ["recoder.jitsi.crans.org"];
};
};
};
services.prometheus.exporters.jitsi = {
enable = true;
};
}

View File

@ -1,9 +1,7 @@
{ ... }:
{ lib, config, ... }:
{
services.nginx = {
enable = true;
services.nginx = lib.mkIf config.services.nginx.enable {
recommendedProxySettings = true;
recommendedOptimisation = true;

View File

@ -1,19 +1,42 @@
{ config, ... }:
{ config, lib, ... }:
let
cfg = config.crans.services.resticServer;
inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
in
{
services.restic.server = {
enable = true;
options.crans.services.resticServer = {
enable = mkEnableOption "Serveur de backups restic.";
dataDir = "/backups";
listenAddress = "localhost:4242";
privateRepos = true;
dataDir = mkOption {
type = types.path;
default = "/backups";
example = "/var/backups";
description = "Dossier dans lequel les backups seront effectuées.";
};
port = mkOption {
type = types.int;
default = 8080;
example = 4242;
description = "Port sur lequel le serveur restic écoute.";
};
};
services.nginx.virtualHosts = {
"${config.networking.hostName}.adm.crans.org" = {
locations."/" = {
proxyPass = "http://${config.services.restic.server.listenAddress}";
};
config = mkIf cfg.enable {
services.restic.server = {
enable = true;
dataDir = cfg.dataDir;
listenAddress = "localhost:${toString cfg.port}";
privateRepos = true;
};
};
}

View File

@ -0,0 +1,177 @@
{ pkgs, lib, config, ... }:
let
cfg = config.crans.reverseProxy;
allowAll = pkgs.writeText "allow_all.json"
''
{
"bots": [
{
"name": "allow_all",
"path_regex": ".*",
"action": "ALLOW"
}
]
}
'';
inherit (lib)
cartesianProduct
literalExpression
mapAttrs
mapAttrs'
mkEnableOption
mkIf
mkOption
nameValuePair
substring
types
;
in
{
options.crans.reverseProxy = {
enable = mkEnableOption "Configuration du reverseproxy.";
virtualHosts = mkOption {
type = types.attrsOf (
types.submodule {
options = {
serverAliases = mkOption {
type = types.listOf types.str;
default = [ ];
example = [
"everything"
"voyager"
];
description = ''
Déclaration des alias.
'';
};
target = mkOption {
type = types.str;
default = "";
description = ''
Indique la destination. Il peut s'agir du chemin vers des fichiers statiques.
'';
example = "172.16.10.128:8000";
};
anubisConfig = mkOption {
type = types.str;
default = "";
description = ''
Chemin du fichier de configuration
'';
example = "/var/www/anubis.conf";
};
httpOnly = mkOption {
type = types.bool;
default = false;
description = ''
Interdit les connexions en ssh
'';
example = "true";
};
};
}
);
default = {};
example = literalExpression ''
{
"framadate" = {
host = "176.16.10.128:8000";
serverAliases = [
"everything"
"voyager"
]
};
};
'';
description = "Déclaration des machines.";
};
};
config = {
systemd.services = mapAttrs (
vhostName: vhostConfig: {
wantedBy = [ "multi-user.target" ];
}
) cfg.virtualHosts;
services = mkIf cfg.enable {
anubis = {
defaultOptions.group = "nginx";
instances = mapAttrs (
vhostName: vhostConfig: {
enable = true;
settings = {
BIND = "/run/anubis/anubis-${vhostName}.sock";
BIND_NETWORK = "unix";
TARGET = "unix:///run/nginx/nginx-${vhostName}.sock";
COOKIE_DOMAIN = "crans.org";
REDIRECT_DOMAINS = "${vhostName}.crans.org";
SOCKET_MODE = "0660";
POLICY_FNAME =
if (vhostConfig.anubisConfig == "")
then allowAll
else vhostConfig.anubisConfig;
};
}
) cfg.virtualHosts;
};
nginx =
let
domaines = [
"crans.org"
"crans.fr"
"crans.eu"
];
redirectConfig = mapAttrs (
vhostName: vhostConfig: {
locations = mkIf ((substring 0 1 vhostConfig.target) != "/") {
"/favicon.ico".root = "/var/www/logo/";
"/".proxyPass = "http://${vhostConfig.target}";
};
root = mkIf ((substring 0 1 vhostConfig.target) == "/") vhostConfig.target;
listen = [
{ addr = "unix:/run/nginx/nginx-${vhostName}.sock"; }
];
}
) cfg.virtualHosts;
aliasConfig = mapAttrs' (
vhostName: vhostConfig: nameValuePair (vhostName + "-alias") {
enableACME = !vhostConfig.httpOnly;
forceSSL = !vhostConfig.httpOnly;
rejectSSL = vhostConfig.httpOnly;
serverName = "${vhostName}.crans.fr";
serverAliases = let
aliases = cartesianProduct {
name = vhostConfig.serverAliases;
domaine = domaines;
};
in [
"${vhostName}.crans.eu"
] ++ map (value: value.name + "." + value.domaine) aliases;
globalRedirect = "${vhostName}.crans.org";
}
) cfg.virtualHosts;
anubisConfig = mapAttrs' (
vhostName: vhostConfig: nameValuePair (vhostName + "-anubis") {
enableACME = !vhostConfig.httpOnly;
forceSSL = !vhostConfig.httpOnly;
rejectSSL = vhostConfig.httpOnly;
locations."/".proxyPass = "http://unix:/run/anubis/anubis-${vhostName}.sock";
serverName = "${vhostName}.crans.org";
}
) cfg.virtualHosts;
in {
enable = true;
virtualHosts = redirectConfig // aliasConfig // anubisConfig;
};
};
};
}

View File

@ -1,28 +0,0 @@
{ pkgs, ... }:
let
synapse-admin_over = pkgs.synapse-admin-etkecc.overrideAttrs (_: { yarnBuildFlags = "--base=/admin"; });
synapse-admin = synapse-admin_over
.withConfig {
restrictBaseUrl = [
"https://matrix.crans.org"
];
asManagedUsers = [
"^@ircbot:crans\\.org$"
];
};
in
{
imports = [
./nginx.nix
];
services.nginx.virtualHosts = {
"matrix.crans.org" = {
locations."/admin/".alias = synapse-admin + "/";
locations."=/admin".extraConfig = ''
return 301 /admin/;
'';
};
};
}

View File

@ -1,4 +1,12 @@
let
inherit (import <nixpkgs> { }) lib;
inherit (lib)
attrsets
filesystem
lists
path
strings
;
# Nounous
aeltheos_0 = "age1yubikey1qvn7t9hplvnr2w8nsfezfqudz8gq3v8sq99dkdpzmm4a74rng5qgz4v6wzt";
@ -6,7 +14,8 @@ let
korenstin = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIh26Ejn/syhvReixauY8i85+XD8P9RRJrPQGEyAQ07l klin@nixos";
lyes = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHW62pK9A6E8pEwmSnTp6oKXac+bbOJ4VkPvNLa11No8 lyessaadi@crans.org";
lzebulon = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJRSBsRgd/ITK2An7q1VXoeDPbcydR3FkQjHoO+1tAAO lzebulon@archframe";
pigeonmoelleux = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHa+ptSTNG4mnGUEGSkHTNDzyUGeiMnaWS2nDvJwrYTp ratcornu@skryre";
pigeonmoelleux_0 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHa+ptSTNG4mnGUEGSkHTNDzyUGeiMnaWS2nDvJwrYTp ratcornu@skryre";
pigeonmoelleux_1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA41j5jdFj18OSHONx4QN9mMT+oBmtdwb1vstNavGOnz ratcornu@vrrtkin";
nounous = [
aeltheos_0
@ -14,108 +23,90 @@ let
korenstin
lyes
lzebulon
pigeonmoelleux
pigeonmoelleux_0
pigeonmoelleux_1
];
# Machines
apprentix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCJV6jqQWEYuwi+OJ9r/4TbBN/cK9NvYWNiJhpFzcc7 root@apprentix";
cephiroth = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOsBGkhiu6l3jeo15cQHMu3dPyL025zXPV2ZH02EDYEt root@nixos";
jitsi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6jVMIZ5y2oXX9HOkw7r5UUjw95MlFaFuu7FnEC0Q8z root@jitsi";
livre = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVfKNokHG6ig32hhQxTep+fKFmKahlDClPrX/dP4/gb root@livre";
mediakiwi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAiCZU+gdUt2jOxR0niVFsNzw0LIleYvwNhMFIANR5YE root@mediakiwi";
neo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMGfSvxqC2PJYRrxJaivVDujwlwCZ6AwH8hOSA9ktZ1V root@neo";
redite = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOwfVmR3NjZf6qkDlTSiyo39Up5nSNUVW7jYDWXrY8Xr root@redite";
thot = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKNg1b8ft1L55+joXQ/7Dt2QTOdkea8opTEnq4xrhPU root@thot";
two = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPpaGf8A+XWXBdNrs69RiC0qPbjPHdtkl31OjxrktmF6 root@nixos";
hosts = {
inherit
apprentix
cephiroth
jitsi
livre
mediakiwi
neo
redite
thot
two
;
apprentix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCJV6jqQWEYuwi+OJ9r/4TbBN/cK9NvYWNiJhpFzcc7 root@apprentix";
cephiroth = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOsBGkhiu6l3jeo15cQHMu3dPyL025zXPV2ZH02EDYEt root@nixos";
jitsi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6jVMIZ5y2oXX9HOkw7r5UUjw95MlFaFuu7FnEC0Q8z root@jitsi";
livre = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVfKNokHG6ig32hhQxTep+fKFmKahlDClPrX/dP4/gb root@livre";
mediakiwi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAiCZU+gdUt2jOxR0niVFsNzw0LIleYvwNhMFIANR5YE root@mediakiwi";
neo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMGfSvxqC2PJYRrxJaivVDujwlwCZ6AwH8hOSA9ktZ1V root@neo";
periodique = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTdfSIL3AWIv0mjRDam6E/qsjoqwJ8QSm1Cb0xqs1s1 root@periodique";
redite = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOwfVmR3NjZf6qkDlTSiyo39Up5nSNUVW7jYDWXrY8Xr root@redite";
reverseproxy = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOx/lUQE6naP3EBy81sr93X8ktZmivU09ACx6T43Odhb root@reverseproxy";
thot = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKNg1b8ft1L55+joXQ/7Dt2QTOdkea8opTEnq4xrhPU root@thot";
two = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPpaGf8A+XWXBdNrs69RiC0qPbjPHdtkl31OjxrktmF6 root@nixos";
vaultwarden = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICn6vfDlsZVU6TEWg9vTgq9+Fp3irHjytBTky7A4ErRM root@vaultwarden";
};
hostnames = [
"apprentix"
"cephiroth"
"jitsi"
"livre"
"mediakiwi"
"neo"
"redite"
"thot"
"two"
];
# Groupes
all = [
apprentix
cephiroth
jitsi
livre
mediakiwi
neo
thot
two
];
all = attrsets.mapAttrsToList (_: key: key) hosts;
acme = [
jitsi
neo
hosts.jitsi
hosts.neo
hosts.reverseproxy
];
# Secrets
commonSecrets = [ "restic/client_env" ];
acmeSecrets = [ "acme/env" ];
# Fonctions utilitaires
remove = el: list: builtins.filter (x: el != x) list;
listFilesRelative =
dir:
lists.filter (f: strings.hasSuffix ".age" f) (
map (p: path.removePrefix ./. p) (filesystem.listFilesRecursive dir)
);
genAttrs =
paths: groups:
builtins.foldl' (
acc: secret: acc // { "secrets/${secret}.age".publicKeys = groups ++ nounous; }
) { } paths;
builtins.foldl' (acc: secret: acc // { "${secret}".publicKeys = groups ++ nounous; }) { } paths;
# Secrets
commonSecrets = (listFilesRelative ./secrets/common) ++ [
"./secrets/restic/client_env.age"
];
acmeSecrets = listFilesRelative ./secrets/acme;
in
(genAttrs commonSecrets (remove apprentix all))
# Secrets communs à toutes les machines (sauf apprentix)
(genAttrs commonSecrets (lists.remove hosts.apprentix all))
# Secrets pour ACME
// (genAttrs acmeSecrets acme)
// builtins.foldl' (
acc: name:
acc
// (
let
key = hosts.${name};
in
genAttrs
[
"restic/${name}/base-repo"
"restic/${name}/base-password"
]
[ key ]
)
) { } (remove "thot" hostnames)
// builtins.mapAttrs (name: value: { publicKeys = value.publicKeys ++ nounous; }) {
"secrets/common/root.age".publicKeys = remove apprentix all;
"secrets/apprentix/root.age".publicKeys = [ apprentix ];
"secrets/mediakiwi/mediawiki-admin-passwd.age".publicKeys = [ mediakiwi ];
"secrets/mediakiwi/mediawiki-ldap.age".publicKeys = [ mediakiwi ];
"secrets/neo/appservice_irc_db_env.age".publicKeys = [ neo ];
"secrets/neo/coturn_auth_secret.age".publicKeys = [ neo ];
"secrets/neo/database_extra_config.age".publicKeys = [ neo ];
"secrets/neo/note_oidc_extra_config.age".publicKeys = [ neo ];
"secrets/neo/ldap_synapse_password.age".publicKeys = [ neo ];
}
# Secrets pour restic
// attrsets.foldlAttrs (
outacc: host: key:
let
secrets = listFilesRelative (path.append ./secrets/restic host);
in
outacc
// builtins.foldl' (
acc: secret:
acc
// {
"${secret}".publicKeys = [ key ] ++ nounous;
}
) { } secrets
) { } (lib.filterAttrs (host: _: host != "thot" && host != "cephiroth") hosts)
# Secrets spécifiques à chaque VM
// attrsets.foldlAttrs (
outacc: host: key:
let
secrets = listFilesRelative (path.append ./secrets host);
in
outacc
// builtins.foldl' (
acc: secret:
acc
// {
"${secret}".publicKeys = [ key ] ++ nounous;
}
) { } secrets
) { } hosts

View File

Binary file not shown.

View File

Binary file not shown.

View File

View File

Binary file not shown.

View File

View File

View File

Binary file not shown.

View File

@ -1,11 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 /Gpyew GGtk6DYlauerByL2ia9uqYRRnwqwn+oeZZUfRpDzhh8
OJ0qDoPCz5FXCXDOHJyGlcYhBRvMPIyrDuTXVR6pYiE
-> ssh-ed25519 I2EdxQ rHELcLTEsfu0sL3Aw2c290Zf9EmdOIO5gmhLS6lRMiU
AKX6RMwbLn3J1IKsjSTfxn0u/XlT0W76JKXfcfMCkqc
-> ssh-ed25519 GNhSGw LPx7cnjBfMcDwZ4hqfP6y++D2FVtlYbzMxfVkfF86hY
QjXtb0IX9wtvCw1ms4A+kG4Nx6URhIT9e2nzyRSpI0U
-> ssh-ed25519 eXMAtA sB1Ew2t6yjQoYW6OpH/bFCo5PO+a23nF/OrCrl9d+iY
73LkKS8y0bYR+hGPVjHxHc6VDZ5mscAMPfLwS+a0slo
--- B5T496c9WhW9A7EzOhy7vshIjNFgTr/kfW1mi5Cc5fc
ŒƒÏ–åŒþÊãDõÚŽ7üUŽp{ó‡»òüZÐêÏ~°*«‰‡áX—˜ó„Ñ<E2809E>à
-> ssh-ed25519 /Gpyew oaVD79l3EZWfSVKb8XpqWAV8NKXySVAPbWLoT1UA52A
+kOAxHr3zaV5i0JpQAtlAdU95Q9M3rJqGtIJ8XvPbkQ
-> piv-p256 ewCc3w AivgKvbuHgMuIJkXqo2/Cp3IF5MJAbfxKBMngMbKvQq/
OKe5ZZH1BcR02enuqgNYQR1xUk4nwHnHUwFeWNa1+Eg
-> piv-p256 6CL/Pw A9Tk3dUEE9IL2Mke3E3mOe19oqDS9YTDZK3yRV75eJX4
8qCQHjVWgfLk99WfT1694g3DvCozGbfYrf/cvsWygGU
-> ssh-ed25519 I2EdxQ iD7bG+gD5EB6IKt37N5wBIK+gykxKX08nBJmqUMIKyE
xs5EhKazMdwtYiBh8DWyZfp9N6oHUXKAUwJ3ipGnoUo
-> ssh-ed25519 J/iReg z+J9LYzBpAmrk+qs/bKM+dWZADzaCG1Zn2++aqngiUI
ZKj2uEEtSxI+VZmFMTIs/YCN27Dzaez55OHcRRcXGGg
-> ssh-ed25519 GNhSGw QiKR6ruzN9obAMMWEX1SJP6cuWG+zPer1EOEOubWcyQ
EGxT2dlZg9SBCH7MI6HygE6bgeyM2Njj+bfc9HVHAHU
-> ssh-ed25519 eXMAtA iD5onNylX7xPzgCZDnbio6+5GtbuO9lXDE+mwVb/jlU
rdadtpwMGEAwZOhYId9xeryALddEK3T4DQP6dfgSYN4
-> ssh-ed25519 5hXocQ bhNzIK/vKeNNpqhZA9dEtHOlfYQ4sZpwF4Xy2Xm+yA4
pD1xgl7iR1nYEjt7TcMQC2WzBlaMukoMNwBgomm0zzo
--- tMEzkXbsknws8FNrhwbH30AMAvDUtmI+IiQwUYCTLfs
׿ì[ŸÒGl
‡"Š7BáM³Ø»˜ür6Xþó5MÄdº D2És¿Yã’Ǫ ßvüE[p

View File

View File

View File

View File

@ -1,17 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 cZNEGg xSdivGUdE+E04CNUuE8vO0BWwlivoGjcgHBn2yEAFVA
inoMVvbrXvmtCHN5/bYjDV6t68Wv65A3axc5v2RKszc
-> piv-p256 ewCc3w A8VtBFtx4PkpMZh8QpslqUQy8Jfcee5ZBKiopQUDjeC1
2PIRrUn3VeEnj4AeRU37L0aNyuHcA9c3t+dyd3FyyXI
-> piv-p256 6CL/Pw A5Pf7RbMbGtGlk42k/PmLAMZ4VLuqj0CkysWj5g6DERE
lofBqZ5uSCxb+C4KFb2MnB1/+OBR3nOaloiAJp5mAzE
-> ssh-ed25519 I2EdxQ AbWaIVdo6pprA/hwxkyCO6LOIE/2D21nbniJjyI5Zjk
M/+ZOxfgCOkBdUxTc6LDnOamtOtCdP4CiaqS9NkjCpg
-> ssh-ed25519 J/iReg 2qtktO/TZUbk7uboyB7xs81ZT/sAVJIpMANEYy6NNmI
rHMA3gFwwjtjqe4qp0TOUx+amQWGxH9a+usSKTaf+1U
-> ssh-ed25519 GNhSGw w0eT+KN6rb9l0K7eF8V+DYXVvz1HNgotfwm9dSkzHGc
YEI2VLHBXXqNOGR28jIJbs+ok/DkDHWzbWjneI8jja0
-> ssh-ed25519 eXMAtA ioYPo8VmZhcUCbePwClOdwcyJXiNLz1vIz1oQ9K20kI
N7p0/s/S03NE9R5AJWjea8yBLnhPGrEU2/an/fD1A5M
--- M/Ca/BhejCW2s22glGkrx9hbF/voDp0F/oIikcaOcsQ
f^3.&£Û¦4‡oÙȯ]DgÈÐ|d\ûÿ ™™èjf)U`—Ï#éÈ<>RˆRáA'a£•œ Œâeˆù<B…"Có[ ¸ºŠ´C#ƒï2å:§;P°Œ£ØPpcÂmÕ¹>^|I+Åæ: ª,7¡<03>©þqXŠiUÚõ+z¹I<C2B9>\¸ÊQ°FʬAÐÍ¿øËpoÒ&ÛŠi¿ˆW.mÙeea™Žý¾ÅÑ…œ|lŒ`FÝו™<E2809A>4XæH…véˆu7ͬzdÊmEÑØ×Í(T˜ºP'iNuQe0ƒ@·8Š9¹m,i†e´×sbâq#¦Ã~¤!þAv U>_”„J>õAÿÚÃÕ
-> ssh-ed25519 cZNEGg UdZTM/cZThNXXfeZsfUORHdEa2PUOp6Coxok0lyc2Fg
3krjeIXaMcGwu6SfUlkoyxa/6OL5P4qcyShOyef1XCg
-> piv-p256 ewCc3w AmoHURm04LFrZvpmZrcN6S9KNC95r1fLGpY7nDJwPTZj
2YXzoaiRGnmd2DGbpW2LxqPaK0XCzA2OWZ9JSvt35Ys
-> piv-p256 6CL/Pw Az8devhm6EdCVwgKE5318IDuBMpTrcFtxh35xBTkbt9d
74tusNbkmI+fXQDvIKYvUzjDyMhog8USJhBqLSBa3L8
-> ssh-ed25519 I2EdxQ ChMCsoc6YzQQzNoHiXm3kbqAcAy2H6wGQO/oIyyG2mk
iuafwi4YKMYefXoi9RCsZ9KrH4sf2c3Ag072ranSYvA
-> ssh-ed25519 J/iReg VxF6+mO1hPpmh9DPtXe5GPkBihMI8fstrzywSXHvdHM
CnVlioC2CqvTS9OI7W03AbtPqM/WsAqjfI59XIWEbjc
-> ssh-ed25519 GNhSGw 2Dczv1GTTmyXYDSBjeCD9k+dqi2XYWquy/fN5UhHVHA
c3Szd+wRBWRoAAihZ4T5Xhv6XLyW/eFc1Z7pgax0SAg
-> ssh-ed25519 eXMAtA ZBsfLu4nCEfNbzZpYFEuDDD1tByOdeXmtPnyjGcU8xo
MAHtBTuxZ+jcX1rnVy0ttNHIp2FhxQrC7uubt6x8r/c
-> ssh-ed25519 5hXocQ MeFxWiJ3rPEkFdqrQZ8MtEp9p3bqH3foVQjyWq0XU3U
qih9Qvuyi4p04Di/jBYs+gmk7oIuGE5K98g7RJeSQGg
--- zfi4rU7IGCVJCZUi4tg9gK9CSIbswyENcezUKxbJIho
Žâ8<>+,iâñtpúlýkÚ~NB<>å1vz'‘¨ISÑZæLYÜ_Ó·Ã$øl=Ñ3{l Ý<C39D>YQ2w ³g©çKg©Ñ&,@àØ~ÑeHî4¢ºÉ®a_Z˜<5A>—CrmiØó­O§¶7Áµûü¡“Œh^ŽûëDWy3¾Aî±ò+åèM.kT(ÿ4µ<34>€2q±ntŽìà‘ß%aðÞÏIZ#û¥Á^U«[WúÁæÛ2OéÍݳäY9ÍÊòÿÏKºªbØ¿Û5Ù7Å">zÁ¥” kx¯ŠÍŠ®GˆjåwC Ódyqt}úÀÛ| äÃ[ËÝñIoÌÓ÷çØµiÏI1Î@÷G„


Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 FtI9pg IvNSPTRYe4LkaPH0oORuCQt97urcG+ZAbT506tpUwzs
B2OZ+xmNn5uzxbC3fZxEOe9q8mmsQ/sVn5vnPL4W8CQ
-> piv-p256 ewCc3w AtHfFnS9TAmkjv4AAdqqG8t6rOBMRf6MSmzlkYM/ipa5
VAXUz8H2rRPY/u0PEtWERnMA7gM6CHBzFghxYZ3EFx4
-> piv-p256 6CL/Pw A3m5XXDVrbxuZF1IEXy+WWLvKbREJX+vm5cw6Bs94dlm
fcL9jGocTsAAw131d2j220xVeV5A8SBP9Lsr7v+Py5E
-> ssh-ed25519 I2EdxQ Ndto3EUMixgz1+CwXzAmDM/aZj46w0L65zxHL1XL1D8
5SRZO6hGuNRQxvBAeyoazc5TcBfGLHRIT9taRvSLpr0
-> ssh-ed25519 J/iReg ws2Pq45azL74SrCMWUXh4efFHkPUlioVaSKu6jnhcg0
d9i9mjV/PHae53IeSdSZLHY41idxfbPT0q8MzwKeO7Q
-> ssh-ed25519 GNhSGw j4H4RyZ04R5fty9UsseU0KEGg9vXB+VD7pwWm4Fldwk
IW/cdj+p21iAH8qQLWMO79mZkC48JeOjaQvhiH9afHA
-> ssh-ed25519 eXMAtA J3hFWvhvLf+6yuImvebdy//+DxNER7F1VfA1hHOZIik
5p8dWje8b3PaKk94xHsLcztNtfh5eP0U/2Ym13IL1AM
-> ssh-ed25519 5hXocQ TNStI5ozplwR9QBixWnWGoA81jp7R1Wky6X+uU9zREE
CbWTew0F4WCO/AtqwbV91zhrr0yqcdLZVokiROAqQMM
--- WbwYGA5zi+fY5JiK3sgD9W5ROhqYlhX90/mxu5NaPWE
Ìõ·áPÉÐI†õa_¢\L<>…î;ÛÑêÐ#ˆ3/X¿¥W­žƒàIAá°E`'/ëÓác(þJ4ìÊ_<C38A>ƒ÷ö•nÉCn°áhß/  Ò‘”œL`Žå)µÅÜÉä•T=Ÿ ‰Û °Š°ÃÀæAè)&{{Ìä
{"Àë¨rÿlMÚcs`ͯV¸PýuÞéýmÑ÷s,îžy01ÀŠ<C380>@[J"ÇÓ»À@·¹Š9þ×<7F>Óþ÷_à<5F>ÔØ:ëåHþÀŽF]QòMv•£zó$<24>Þ¢BB/Y·&ÂÒ)ˆ €p7jXPh¯nyµµsC)-N…þÐ&9q¬¢Dï<44>¤`ØÅ–ÄÊ?ù‡¾MîÓâÉpä½å<C2BD>DâO

View File

@ -0,0 +1,19 @@
age-encryption.org/v1
-> ssh-ed25519 FtI9pg 699sQyv9A2DsVBx0u2Q+StW7VP8+DiUX+uUOZDP9BXc
7xQrHSWDkEGu9iPBx/jiiDmJ8+KRSfeeLqjtSHHIKxk
-> piv-p256 ewCc3w Amal1a3gRYmqp2KDdlgN7mWzPzJG4EHeDNbBnDp9ZK75
LtEh4MK3tpLh/IIjuD+dXzlOeNK2Efgjwy8L43A8/gw
-> piv-p256 6CL/Pw Ap5uHl9tOPVkCB5/BqxgKGhtGjVxooNiVAAagKiKfxO1
zhMl4yVJOe+dzjwcaYQBCjYs47iikeykXFznYAUoF8E
-> ssh-ed25519 I2EdxQ KXijPMp2Yb2ccGAfmX/xw3TB+Wcw5+WALWLwE2MUJF0
X96+UxQo5R8+sZt0uCdauFdnDUP4otRs4QlAVWbS+ys
-> ssh-ed25519 J/iReg WZykIiadzSf9FrirQODpSPJc/XMggldDUuAUvSA6kDw
JQeaP8u8fo3l8xbZYGTyEft39KYRVYzPXvtQOk9hhqc
-> ssh-ed25519 GNhSGw Iwyy/AoqxB3ZP8L2fh/tIUMo5VhNnB2A2qouHzj34Hs
FFzA/w9lm1EHubBipx6kqQAPw0oBjiFVxkKoZDAqM2g
-> ssh-ed25519 eXMAtA fXjp2bJasqd3A0qO8JHThWgchw9Zb2lnAA5ux+z0+Tc
5UIgx+fg1a5qzEeXHmCzVPlUy3T7uwosjDN5DU3acCc
-> ssh-ed25519 5hXocQ VaoJWjpaDZXOvPgw0oFWuvFWJm2U/wT2KlgaPG7QggU
NpqFs3pzV91c+5dMcdsjHz3br8jxKg3obeMj1M2NBR4
--- 1XXLm39XkQcmHtbW2Gxhw+NtGvB6vaZtavkwBYL7sZQ
¡—X&ỵçr²ïNg:u!`ºg3í”/^1æ1¤¶¾yâ/È-ð:<16>GªâSŠˆ¿ˆ”*P7jälˆ&‡ø Ø w0ø>W¹g„Á¦ä<C2A6>õ13mÉö»-SÃü§ZÁžÒ¨X¯i]Z§b6º %ZÈT®Iu<49>1Þ:—Œ²Òµö33ŸÉýý·~N<>åäÿâbÝ

View File

@ -1,19 +1,22 @@
age-encryption.org/v1
-> ssh-ed25519 hTlmJA GGYgxZ9fef61srcfQRKzWlJxjZvM/aNXbj+VKQKqlh8
hyqXuysxi8cZw7gkL6mzBT46BW7BdTbAq49SbikB6sM
-> piv-p256 ewCc3w AlPrqo8arxIDE7uKZYesXi8v/IScOoctlzSEMaV9SvPS
e98Dsw1FeTY0cQ399Ld2YWM9wt8dRmk4oAkQOal5MLk
-> piv-p256 6CL/Pw A/lTgaxoZsVzFKIWIwoIIpN+jbLcI02ccmpQkloLNj6R
pg9250zjo2S6sZ2+cROojICPpx5dwm6f5GUOaK0sstw
-> ssh-ed25519 I2EdxQ 3u/qjOhvHfxPqyKrnnUXLUy3LjDkHKy+zBQ43LFfDQU
V7dL40BcwNDZLxhkAEgsqZ47taPR0OKIiOo1t3NdVjM
-> ssh-ed25519 J/iReg UT3kqX2XtQUG03DwzIz9JzYop4thDZueEpn98cw/dwY
YlI6tiZ6IjcpPWv9PTY7t0QZEBbBxD3EhfiWboNr4fY
-> ssh-ed25519 GNhSGw sBz4SNHOdt3aZSQXGRfcIc9fo/+ExOcTv5DT9jQGBwU
ZbEg7kdpcT8LfO1NC6CaaVlxAsChq+U+c4p/QW2Tf+U
-> ssh-ed25519 eXMAtA SHIrXyEKX1jaf7TgrWKRVFkiNUas5soelT5OJfEZj00
p9fB+4LLvuP3uqqCq3bjAOS6kS1aUaEzi6O00cqWbZo
--- 79Z0v+RfvqMnF89CMuesb71b+rC+zzZmMfJpAjaWpQ0
KH.Ie Hl C ü‰zQÙfE¾‡ßÊ3<XbîêÐz
R¾·Hì .ÒxTþƒ<C3BE>kdöí¯*­‡#•j@DÕÓ"ïX"+ Q­<>ÚÓ BÒ£K§â®à ÓÛ¬<C39B>ÕÈ|ë`ýU¸„6B¯·e¨SÖ­€Jóä̈®×-éYñÖ´Êöˆoy¯ ÀÎ<C380>±“°D©„TÄ2n²R´†–(æ´à–Šš`ãß÷Mp^ ѽQI&vW«¦+§Q…ój6÷̶ÿõʈž¨Àc«*ÎÔÅÇÌ nAV†ë¨ðjŠ;wö" …¿šRØì²sŒØ_Å<5F>(7J:ª§;ÄxebæÇV|”öa£Ÿ)›äµ<Ä݉
ÿ&³!ÚCÀ
-> ssh-ed25519 hTlmJA Qpkgty4nvIX6hujZOUeXxe3eDAVOwqVKMumHRtLGElg
XAhZAzB38Ke9ksFQOmPJDF4Q9FIyhDEKsidU8yeVj0I
-> piv-p256 ewCc3w A1PBG2IYLVynzRQ8LAEfgl0dUwU90/FOfE/6phOIp05n
QWJvcxD4QVaP1EnxiiKfweh1gU6CrcszeOPZj/hCJpY
-> piv-p256 6CL/Pw Atp4YJbQaBplip1c26/gNGGVNz8ktko9g96s6AA6xhdX
AHAl4myifoCtLsgDKcfhr88fkXFfslgIchFTreRyfIA
-> ssh-ed25519 I2EdxQ 33Sp74Bcnqoef0xRrrEnSUEMMmrWnjH1rEQmQucO6QA
o53n6iMk1QLIlREvovIR5qyd4TN6hnNWQaaD3nKItHs
-> ssh-ed25519 J/iReg 17kg2/A8UwsMqIxFBlbBRCvw6Y/NXknNA+tjKKiQdX8
CkQ8WmM/JVEH4zAUoArOIZJITLMTFcSd6MBqbhwhTe8
-> ssh-ed25519 GNhSGw QIoIrLuT/n9UutWmL3Ei+nLlSfpcL3v5vlavGpFCRC8
/qiAkQkbxmgy73IPCiBpm5FlaixM/jmhvWvS+TJwTqA
-> ssh-ed25519 eXMAtA ZqTSYAKDYO3J2bHyG44E78hkc4pgib0//DwcgujfcHk
H+Yy0+yKYEtqI9r3EfXhTlrrsD7vu2xiT2TCwuctLKU
-> ssh-ed25519 5hXocQ SvYYiI669xqm+FWGce51b3J3KnBYu8mYzgAW5yBl2k8
03+c6rOOJpSq3ZWkeLUtrHvMSLOp1FG8O0D0EBpD/+4
--- hIGT4wmuDnqucqEsFa0/qmFm3ZjhTwWbL8oQKCEIY4Q
±¯øòƲZ!ÖÅ­¨oî÷ƒ¨Ô¦yr<>´¨ß\sG$\ÐýÁ¤ÝT09ï_Ó‡ÔÈLi
£ÚJߤabÂ9b"žÚk<8ÞGî®RÃD*°
´~UlÍsÿ'-æð!5è?viwµ"w½;B¥èj2[ÉÄU ‡ÌúKÃ:×ë¸Å°dÔf,Dî#3† ‰H™¤R͆[Íåˆä[ åÜÌ~ 0­C8dñѽ$õü;ä'kز\<5C>³ñP¦ìŠøcš5 <0B>­¡Á ]O¼«Óß;¥ÞÏFب Ð ÓHäÅ¢±PÎ[j¼ó rmQ9Êô÷Ò½ƒ×W<ë
"S{ gĻޙLBÊe“ŽêNo

View File

@ -1,18 +1,21 @@
age-encryption.org/v1
-> ssh-ed25519 hTlmJA I2GVw7B8cLG70ELKyzF4fLnc9YQ5dp2aky5VeSs4nxw
icMLY2bKmhJO1c+X8Pnd4OTkfiPUcTTQVGabE9T2y+M
-> piv-p256 ewCc3w A6Sm640dC0eI7vxTiGmSPZnFUiwrRBKRmDRLpjjOxy9m
faAyrYesEm1xF4slaYpIAgfFljyJMU6l/lw8Z2JEAOs
-> piv-p256 6CL/Pw A6ZGcdickaz8EzbWrnT+sND+xNYBsELXy7U2D56Exo3r
nVzKn9mGU//H90BbXDjpGtEeJFeVfoJdTraUWSJn0L0
-> ssh-ed25519 I2EdxQ RFx9okc8KX2kso7SIAvScnhtqnafdC0S4fptluSZ2wA
xiVlRHGJOndXQcIu+JDh309oHOFF903BJUdufj0u0A4
-> ssh-ed25519 J/iReg 9Ops0HPnUg9oYSIxGbUrYJxO5TNeIh58AJVxI2DEIHM
6KzqbsvB7oXu5ef7jVoYP8dIYbMMcYBVrR+vgk1CkpE
-> ssh-ed25519 GNhSGw mK4SKOyG7xjKZ/ppGGhOGcXr2ijGGdX0HTktI5A8w1M
WU03oiRLNe2cHbMDX1tmUwsMwgtWTI82TRfAUeuKzEs
-> ssh-ed25519 eXMAtA xOC8dKt8Xh5r1QscxPk34Qu3X78dV8d+CBrp6Krf+Sc
ZE9/cauEllHMpZuZrwp6ZTD08mjbiuTPX0xC+ME/U08
--- N6Zx2Tn9fPvuVS+r37wCGANuf/4QlH7HqZHLGX0p5ko
çFü4ùp¦ÙÔÏâû©;¶È/:"{ŸWljpÔ¡Ðk60Îk—]FU¶r‡Q:¦Eº{¨‰:RçSö½Á¼¼0<>™.ÊŸm€Fê4eÎ"¤˜Š1p©/¥™¤h[2ë¯zËÝí§Bv¡gñ"ãͪ<>ƒ—'<27>Ë3âý $ÿ
œ
-> ssh-ed25519 hTlmJA FwyYHqXJq8FnP/kKDOyZYMsEpOVVvdxcPka7dxH9TEg
hKPhAZz5/6DP1ugpv3bHOZrbSoVs0hpZSP8kycw0hds
-> piv-p256 ewCc3w A0NZ/VH4wQ07JGUjRnD2QU7VlrG4zMeVzHa7g46Av+jU
qCXVqCAtOikfPENz7RJpy0PTdTw1tAwusSWh1iDlVT0
-> piv-p256 6CL/Pw Awzu5nbYg4GuVnEloOsPVwQ47BicdnAb4sS1mG+0w/Hg
CeDZkaghyrRT4Qokg6dTkDLrwND4mix7dhFgMEXzsRo
-> ssh-ed25519 I2EdxQ MrZNzDREuwEhfu7lU21VsJ02Q9orNM0TPB87viA78XM
NSlPC8lW9U2ppLIGySpmU0HJpemN+GUA74RBFhnhroY
-> ssh-ed25519 J/iReg ZWPGgqUI89NVHp7iLK37iRdwBGroJ0pDxI3ZMeIJ/Ak
PxJTCoNmF/c741FTeXYsjUjogf4/ZLZU56IoEKHX140
-> ssh-ed25519 GNhSGw k4VJGNkwALEyUJfqoWNjm7gVS4EL1PDQtigjrJyKJ0Y
f35rY9JCJSiEkXEC8E9O2e8RqikKHL4WG91y+Q/0Dxw
-> ssh-ed25519 eXMAtA 4exKSkUZbK6IGNqms3oXHZjqxdanDxruBIWzlWkud18
fikqarrrB2wEAS8b033Cp2QpAGxy1SGju6wcfcpgWPo
-> ssh-ed25519 5hXocQ A7y23nvH1k2eh9YhzkDfTX8BTsds6HJfTzEPgP7A10g
CXq+VQurL+CrAZKu9ycJp/iSz/S8CTP8F00OAhNzuwg
--- TZLMHnfF4+CThKdhjtmeSzB/66o6MEV6r4Fh5CzEkCA
¬jóšÍâ`ö ¸3H1TCZŠÝ6/ªƒz¾Ýá‰R<>ƒê¤«â©+©¯˜øq…¶рȲÜ óQá¡FK׳8,oH,ëP‡DŽnùfnTö¿ààŸIÈØù\ƒÇYnü´
ïµk
»f š ßM¿µ0ŠYŸÿ`½Š.®\{Ô<>%Ʋkp

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

View File

Binary file not shown.