This commit is contained in:
xyno (Philipp Hochkamp) 2023-09-14 15:50:04 +02:00
parent 0342390b6f
commit 91259d02e7
11 changed files with 154 additions and 99 deletions

View file

@ -25,9 +25,9 @@ in
services.syncthing.enable = true;
services.syncthing.user = "ragon";
ragon.agenix.secrets."ds9OffsiteBackupSSH" = { owner = config.services.syncoid.user; };
ragon.agenix.secrets."ds9SyncoidHealthCheckUrl" = { owner = config.services.syncoid.user; mode = "444"; };
ragon.agenix.secrets."gatebridgeHostKeys" = { owner = config.services.syncoid.user; };
ragon.agenix.secrets."ds9OffsiteBackupSSH" = { };
ragon.agenix.secrets."ds9SyncoidHealthCheckUrl" = { };
ragon.agenix.secrets."gatebridgeHostKeys" = { };
ragon.agenix.secrets."borgmaticEncryptionKey" = { };
# services.syncoid =
# let
@ -79,7 +79,7 @@ in
};
exclude_if_present = [ ".nobackup" ];
encryption_passcommand = "cat ${config.age.secrets.borgmaticEncryptionKey.path}";
compression = "zstd,10";
compression = "auto,zstd,10";
upload_rate_limit = "4000";
ssh_command = "ssh -o GlobalKnownHostsFile=${config.age.secrets.gatebridgeHostKeys.path} -i ${config.age.secrets.ds9OffsiteBackupSSH.path}";
before_actions = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.ds9SyncoidHealthCheckUrl.path})/start" ];
@ -130,22 +130,16 @@ in
boot.kernel.sysctl."fs.inotify.max_user_instances" = 512;
services.openssh.sftpServerExecutable = "internal-sftp";
services.openssh.extraConfig = ''
Match User picardbackup
ChrootDirectory ${config.users.users.picardbackup.home}
ForceCommand internal-sftp
AllowTcpForwarding no
'';
# Backup Target
users.users.picardbackup = {
createHome = false;
group = "users";
uid = 993;
home = "/backups/restic/picard";
home = "/backups/picard";
isSystemUser = true;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvCF8KGgpF9O8Q7k+JXqZ5eMeEeTaMhCIk/2ZFOzXL0"
''command="${pkgs.borgbackup}/bin/borg serve --restrict-to-path /backups/picard/",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvCF8KGgpF9O8Q7k+JXqZ5eMeEeTaMhCIk/2ZFOzXL0''
];
};

View file

@ -42,10 +42,6 @@
users.mutableUsers = false;
services.postgresql.package = pkgs.postgresql_13;
ragon.agenix.secrets."picardResticPassword" = { };
ragon.agenix.secrets."picardResticSSHKey" = { };
ragon.agenix.secrets."picardResticHealthCheckUrl" = { };
ragon.agenix.secrets."picardSlidingSyncSecret" = { };
services.nginx.recommendedOptimisation = true;
@ -76,14 +72,15 @@
];
credentialsFile = "${config.age.secrets.cloudflareAcme.path}";
};
ragon.agenix.secrets."desec" = { };
security.acme.certs."xyno.systems" = {
dnsProvider = "ionos";
dnsProvider = "desec";
dnsResolver = "1.1.1.1:53";
group = "nginx";
extraDomainNames = [
"*.xyno.systems"
];
credentialsFile = "${config.age.secrets.cloudflareAcme.path}";
credentialsFile = "${config.age.secrets.desec.path}";
};
services.nginx.appendHttpConfig = ''
@ -111,38 +108,36 @@
access_log /var/log/nginx/access.log anonymized;
'';
services.restic.backups."picard" = {
passwordFile = config.age.secrets.picardResticPassword.path;
extraOptions = [
"sftp.command='ssh picardbackup@ds9 -i ${config.age.secrets.picardResticSSHKey.path} -s sftp'"
];
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 5"
"--keep-monthly 12"
"--keep-yearly 75"
];
initialize = true;
repository = "sftp:picardbackup@ds9:/restic";
paths = [
"/persistent"
];
};
systemd.services.restic-backups-picard = {
# ExecStartPost commands are only run if the ExecStart command succeeded
serviceConfig.ExecStartPost = pkgs.writeShellScript "backupSuccessful" ''
${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.picardResticHealthCheckUrl.path})
'';
unitConfig.OnFailure = "backupFailure.service";
};
systemd.services.backupFailure = {
ragon.agenix.secrets."picardResticPassword" = { };
ragon.agenix.secrets."picardResticSSHKey" = { };
ragon.agenix.secrets."picardResticHealthCheckUrl" = { };
ragon.agenix.secrets."picardSlidingSyncSecret" = { };
services.borgmatic = {
enable = true;
script = "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.picardResticHealthCheckUrl.path})/fail";
configurations."picard-ds9" = {
location = {
source_directories = [ "/persistent" ];
repositories = [ "picardbackup@ds9:/backups/picard/borgmatic" ];
};
exclude_if_present = [ ".nobackup" ];
encryption_passcommand = "cat ${config.age.secrets.picardResticPassword.path}";
compression = "auto,zstd,10";
ssh_command =
let
pks = import ../../data/pubkeys.nix;
hst = pks.ragon.host "ds9";
lst = map (h: "daedalus ${h}") hst;
s = lib.concatStringsSep "\n" lst;
fl = pkgs.writeText "ds9-offsite-ssh-known-hosts" s;
in
"ssh -o GlobalKnownHostsFile=${fl} -i ${config.age.secrets.picardResticSSHKey.path}";
before_actions = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.picardResticHealthCheckUrl.path})/start" ];
after_actions = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.picardResticHealthCheckUrl.path})" ];
on_error = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(cat ${config.age.secrets.picardResticHealthCheckUrl.path})/fail" ];
postgresql_databases = [ "all" ];
};
};
nixpkgs.overlays = [
(self: super: {
zfs = super.zfs.override { enableMail = true; };
@ -163,7 +158,8 @@
gitlab.enable = false; # TODO gitlab-runner
synapse.enable = true;
tailscale.enable = true;
hedgedoc.enable = false;
hedgedoc.enable = true;
authelia.enable = true;
ts3.enable = true;
nginx.enable = true;
nginx.domain = "ragon.xyz";

View file

@ -25,7 +25,7 @@ rec {
in
if hasDomain then {
forceSSL = true;
useACMEHost = "${domain}";
useACMEHost = "${outerDomain}";
} else
{
forceSSL = true;

View file

@ -1,8 +1,8 @@
{ config, lib, pkgs, ... }:
let
cfg = config.ragon.services.authelia;
stateDir = "/var/lib/authelia";
instanceName = "main";
stateDir = "/var/lib/authelia-${instanceName}";
in
{
options.ragon.services.authelia.enable = lib.mkEnableOption "Enables the authelia SSO Server";
@ -13,12 +13,12 @@ in
};
config = lib.mkIf cfg.enable {
ragon.agenix.secrets.autheliaStorageEncryption = { };
ragon.agenix.secrets.autheliaSessionSecret = { };
ragon.agenix.secrets.autheliaOidcIssuerPrivateKey = { };
ragon.agenix.secrets.autheliaOidcHmacSecret = { };
ragon.agenix.secrets.autheliaJwtSecret = { };
ragon.agenix.secrets.autheliaEmail = { user = "authelia"; };
ragon.agenix.secrets.autheliaStorageEncryption = { owner = "authelia-main"; };
ragon.agenix.secrets.autheliaSessionSecret = { owner = "authelia-main"; };
ragon.agenix.secrets.autheliaOidcIssuerPrivateKey = { owner = "authelia-main"; };
ragon.agenix.secrets.autheliaOidcHmacSecret = { owner = "authelia-main"; };
ragon.agenix.secrets.autheliaJwtSecret = { owner = "authelia-main"; };
ragon.agenix.secrets.autheliaEmail = { owner = "authelia-main"; };
services.authelia.instances.${instanceName} = {
enable = true;
secrets = {
@ -28,38 +28,35 @@ in
oidcHmacSecretFile = config.age.secrets.autheliaOidcHmacSecret.path;
jwtSecretFile = config.age.secrets.autheliaJwtSecret.path;
};
settingstFiles = [
settingsFiles = [
config.age.secrets.autheliaEmail.path
];
settings = {
theme = "auto";
default_2fa_method = "webauthn";
access_control = {
default_policy = "one_factor";
};
authentication_backend = {
file = {
path = "${stateDir}/users.yml";
};
};
session = {
domain = cfg.domain;
};
storage = {
postgres = {
host = "/run/postgresql";
};
};
notifier = {
smtp = {
address = "smtp://smtp.ionos.de:465";
sender = "xyno.systems SSO <machdas@xyno.space>";
username = "machdas@xyno.space";
subject = "[xyno.systems SSO] {title}";
startup_check_address = "autodelete@phochkamp.de";
port = "5432";
database = "authelia";
username = "authelia-main";
password = "dosentmatter";
};
};
};
};
systemd.tmpfiles.rules = [
"d ${stateDir} 0755 authelia authelia -"
];
ragon.agenix.secrets.autheliaSecret.owner = "authelia";
services.nginx.virtualHosts."${cfg.domain}" = {
locations."/".proxyWebsockets = true;
locations."/".proxyPass = "http://127.0.0.1:${toString config.services.authelia.instances.${instanceName}.settings.server.port}";
@ -71,7 +68,7 @@ in
ensureDatabases = [ "authelia" ];
ensureUsers = [
{
name = "authelia";
name = "authelia-main";
ensurePermissions."DATABASE authelia" = "ALL PRIVILEGES";
}
];

View file

@ -1,7 +1,6 @@
{ config, lib, pkgs, ... }:
let
cfg = config.ragon.services.hedgedoc;
domain = config.ragon.services.nginx.domain;
in
{
options.ragon.services.hedgedoc.enable = lib.mkEnableOption "Enables the hedgedoc BitWarden Server";
@ -11,14 +10,14 @@ in
default = "md.xyno.systems";
};
config = lib.mkIf cfg.enable {
ragon.agenix.secrets.autheliaHedgedoc = { user = "authelia"; };
ragon.agenix.secrets.autheliaHedgedoc = { owner = "authelia-main"; };
services.authelia.instances.main.settingsFiles = [
config.age.secrets.autheliaHedgedoc.path
];
services.hedgedoc = {
enable = true;
environmentFile = "${config.age.secrets.hedgedocSecret.path}";
configuration = {
settings = {
protocolUseSSL = true;
sessionSecret = "$SESSION_SECRET";
allowAnonymous = false;
@ -26,12 +25,12 @@ in
allowFreeURL = true;
email = false;
oauth2 = {
clientID = "$OAUTH2_CLIENT_ID";
clientSecret = "$OAUTH2_CLIENT_SECRET";
clientID = "$CLIENT_ID";
clientSecret = "$CLIENT_SECRET";
providerName = "xyno.systems SSO";
authorizationURL = "https://sso.xyno.systems/oauth2/authorize";
tokenURL = "https://sso.xyno.systems/oauth2/token";
userProfileURL = "https://sso.xyno.systems/oauth2/userinfo";
authorizationURL = "https://sso.xyno.systems/api/oidc/authorize";
tokenURL = "https://sso.xyno.systems/api/oidc/token";
userProfileURL = "https://sso.xyno.systems/api/oidc/userinfo";
scope = "openid profile email";
userProfileUsernameAttr = "sub";
userProfileEmailAttr = "email";
@ -47,9 +46,9 @@ in
};
ragon.agenix.secrets.hedgedocSecret.owner = "hedgedoc";
services.nginx.virtualHosts."${cfg.domainPrefix}.${domain}" = {
services.nginx.virtualHosts."${cfg.domain}" = {
locations."/".proxyWebsockets = true;
locations."/".proxyPass = "http://127.0.0.1:${toString config.services.hedgedoc.configuration.port}";
locations."/".proxyPass = "http://[::1]:${toString config.services.hedgedoc.settings.port}";
} // (lib.my.findOutTlsConfig cfg.domain config);
services.postgresql = {

View file

@ -0,0 +1,68 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.ragon.tailscaleToVpn;
ovpnConfigPath = cfg.ovpnConfigPath;
stateVer = config.system.stateVersion;
in
{
options.ragon.tailscaleToVpn = {
enable = mkEnableOption "tailscale-to-vpn. you need to enable nat to ve-+ able to use this";
ovpnConfigPath = mkOption {
type = types.str;
default = "/etc/openvpn/client.conf";
description = "full path to the OpenVPN client configuration file, is expected to be in /run";
};
};
config = mkIf cfg.enable {
networking.bridges.br-ovpn-ts = {
interfaces = [ ];
};
containers.TSTVPN-openvpn = {
ephemeral = true;
enableTun = true;
interfaces = [ "br-ovpn-ts" ];
localAddress = "192.168.102.11";
hostAddress = "192.168.102.10";
config = { config, pkgs, ... }: {
system.stateVersion = stateVer;
networking.interfaces.br-ovpn-ts = {
ipv4.addresses = [ "192.168.101.1/24" ];
};
services.openvpn.servers.bridge = {
config = ''
config /host${ovpnConfigPath}
dev ovpn-bridge
dev-type tun
'';
};
networking.nat = {
externalInterface = "ovpn-bridge";
internalInterfaces = [ "br-ovpn-ts" ];
};
};
privateNetwork = true;
bindMounts = {
"/host/run" = { hostPath = "/run"; isReadOnly = true; };
"/run/agenix.d" = { hostPath = "/run/agenix.d"; isReadOnly = true; };
};
};
containers.TSTVPN-tailscale = {
enableTun = true;
hostBridge = "br-ovpn-ts";
localAddress = "192.168.101.2/24";
privateNetwork = true;
config = { config, pkgs, ... }: {
system.stateVersion = stateVer;
services.tailscale = {
enable = true;
useRoutingFeatures = "both";
};
};
};
};
}

Binary file not shown.

Binary file not shown.

BIN
secrets/desec.age Normal file

Binary file not shown.

View file

@ -1,18 +1,18 @@
age-encryption.org/v1
-> ssh-ed25519 WceKOQ GcDlLhmeGS/8+Ys+yg4y5HrtrWmTZPpK5CJaJS9Vf2o
dBv7O2071zyETP7YBULVb93piXcmJLlUr6KQ1yh3YGo
-> ssh-ed25519 ugHWWw HL7ah8Ph+OvzyAkWes7emassnvg0mb2BFjS3lENOOXo
f55TwOwdzDOB8WAI0YI1mRGJCkoogzKO4uY8se0HIxo
-> ssh-ed25519 UU9RSA PWutyEvhn9RFJl1WVo20EM3nZ8y45Hws/iKoLx5DLDg
i2z5zpJjtH2U8dyxBMs35psqWX30voIZrq6S4SfIZWY
-> ssh-ed25519 RJI3BA zbta8hMmFRNuRzZ8wW1A9UlOOZPkEHyNAXkGBvfzsi0
dSHHJejtCyOd26ghK7bf6xIbONL1CqhOxiXOYaUKmjQ
-> ssh-ed25519 XnvJKw lKCzLY6byaLljPQoSgjs/g00lOKFqj4cTqiy5G6J8yI
aGwmKCRNm45f0514aA0KtdadW52SrdXkDz5XfYntaPc
-> ssh-ed25519 7NL5Ng U5fh3TxL66KG6aIomhOPiICDD2pjqvPXE359f6U0Q0A
AzKIYGHxHKfH4aSCfGofzoxD+Ha8ECNms4G3TM58vxA
-> ?.M5S&-grease
sdkHMhaSu82PCOdggWv/mrAe0eJtFbtzPRJki/jDp1Cd38UqcVJWLNku5FXMoB2h
rQYqNZY
--- /uvXrkejiMZSC9NRjFym9u48TAQr1Dk4smBjqnJVWmw
IÄüµ c§yïsÆV·#\ Üç± ö¼c÷£ å¯Ç`3Iè”xqŽLSkÊ<6B>Ã(¿ä<×(Ÿ;Ž<>HüÔ^o³Ð©y@E¯•˜½LWb¦q1Uå}Tþc˜ºéÉI»<49>oq}Y¸)  µ>ª]8§$q$;d ·?’¸¡ƒ[]:,ƒÞë³ƘæåoJmÞ=1#ÌcÄTcîWŸHÈût;Ї®âu&3U»1 `ŠjÏÿ1I}<7D>ÔLŒüÒå©eô! } ´iýúÁ†?èT<C3A8>ùA§HÑàV…KÔÜáÃñ;ľ+ˆe¥š¨I vR2<52>N¼Ì§yËW<1E>­ÖP•̦J&zda¦Dx#[PCÚ iKcñ¦N#_ᆇÚ?0>P•ò¥ æ†íËÎxÌa
-> ssh-ed25519 WceKOQ 6ebLhKuQn8Fk7/+XdPUa7JQHU7P7Vmn9X9OrL6Q/I3Y
ix7aAfsC7z61AXifvYEukna5DU5MLwend7mSakjVXU4
-> ssh-ed25519 ugHWWw HhRMxpmNBXz1jvGEtn8tYeDu9Vj/XnG+i4Env9jY63g
kC9Fzp6x4Q2JbMQAMKOaaADrc9AJorXe5Du8vsAsUvw
-> ssh-ed25519 UU9RSA d4jm9JBpsbvrCpTBP6QZFepbVsWFEuzzzQUi+wxdLyc
r65piB4wLsaWuFRFc3VVLRUJKOK9H8sXolCslgBBDSA
-> ssh-ed25519 RJI3BA uCiUzUC/xtpnnXdUCNxyslvF0UWgCzVIyXLUxNhuvjM
v7fNePcgjSQ7CH7SJyAa0MXBYwxqZemTDaXlrwUn5vQ
-> ssh-ed25519 XnvJKw mEfaPU/XCI4XiD0HnA5GgqsOCp6K5LfI1XbRC+vn7wk
p0uxLfIIsh5TUlVOx1+D7CxugiX+qJG8sLpjnkligy8
-> ssh-ed25519 7NL5Ng C8noYIrcAYxqZrr+iNHrVIGv9wLB7XQ6TVlbbtH6pzs
jmW5O2PN8K0JLPgLky/va0tUgopZwULeMEC24xhhIP0
-> )R]<#-grease X]~$Bl|F
5PW3yj3XspbEEtzrEyFg+bJSsxeVnu3DAPwk0UZ0RUvNyqTfZwhButEokYqk3Y9e
BaYsEzZPCw8hfclEqk8
--- xdvVLx/w1FbAuKxygp2zsfHb0BKBymAFlBcQFobLgcY
IÛ´ÚiÅÚïØÕ²™ @^÷•)[ÑM"°…Óé><13>wªØãtr$í u 5Ý¥FÖ<46>á0þÉܬnÖÚ»1s <0B> ݳ?½WÎÆyÙA3'ÿ) շ盧GR2ŽóiøÝ1Úïeˆè¶Æöª[üò­U<C2AD>à˜ÔJÚêÚ*ñ€’gTÁËŒâ£-ëöSÁT©Ø˜ K·¶Ï•s¤„)PÁâä¤:{´+0Ÿæ›{O£WE;€ÑKgõºŽÅÒµÐÚ¤d(ï'¤)ïJujxV¦n™‡à§, Ñwƒ]1%f)òs½<73>ˆ CV‰í¢ç´éˆ<>¾5«½ö*Ä«S¬yÞ‡BŒ#Ç<>O^QºÃq ^ç·”Š"8—“°ŸÀWÒEaë¤Yn<59>ç

View file

@ -38,6 +38,7 @@ in
"picardSlidingSyncSecret.age".publicKeys = pubkeys.ragon.host "picard";
"picardResticPassword.age".publicKeys = pubkeys.ragon.host "picard";
"picardResticHealthCheckUrl.age".publicKeys = pubkeys.ragon.host "picard";
"desec.age".publicKeys = pubkeys.ragon.host "picard";
"autheliaStorageEncryption.age".publicKeys = pubkeys.ragon.host "picard";
"autheliaSessionSecret.age".publicKeys = pubkeys.ragon.host "picard";
"autheliaOidcIssuerPrivateKey.age".publicKeys = pubkeys.ragon.host "picard";