Begin preparing kas.codes domain
This commit is contained in:
parent
eff84d05da
commit
dec0048a7b
20 changed files with 721 additions and 52 deletions
122
flake.lock
generated
122
flake.lock
generated
|
@ -83,6 +83,22 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"blobs": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1604995301,
|
||||
"narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=",
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "blobs",
|
||||
"rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "blobs",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"cosmic-manager": {
|
||||
"inputs": {
|
||||
"flake-parts": [
|
||||
|
@ -200,6 +216,22 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
|
@ -291,6 +323,54 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"simple-nixos-mailserver",
|
||||
"flake-compat"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"simple-nixos-mailserver",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742649964,
|
||||
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"simple-nixos-mailserver",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gnome-shell": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
@ -440,6 +520,22 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-25_05": {
|
||||
"locked": {
|
||||
"lastModified": 1747610100,
|
||||
"narHash": "sha256-rpR5ZPMkWzcnCcYYo3lScqfuzEw5Uyfh+R0EKZfroAc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ca49c4304acf0973078db0a9d200fd2bae75676d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1751159883,
|
||||
|
@ -494,6 +590,7 @@
|
|||
"nixos-anywhere": "nixos-anywhere",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"simple-nixos-mailserver": "simple-nixos-mailserver",
|
||||
"stylix": "stylix",
|
||||
"systems": "systems_2",
|
||||
"terranix": "terranix",
|
||||
|
@ -521,6 +618,31 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"simple-nixos-mailserver": {
|
||||
"inputs": {
|
||||
"blobs": "blobs",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"git-hooks": "git-hooks",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-25_05": "nixpkgs-25_05"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747965231,
|
||||
"narHash": "sha256-BW3ktviEhfCN/z3+kEyzpDKAI8qFTwO7+S0NVA0C90o=",
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "nixos-mailserver",
|
||||
"rev": "53007af63fade28853408370c4c600a63dd97f41",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixos-mailserver",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"snowfall-lib": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
|
|
|
@ -91,10 +91,16 @@
|
|||
flake-parts.follows = "flake-parts";
|
||||
};
|
||||
};
|
||||
simple-nixos-mailserver = {
|
||||
url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-25.05";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ self, ... }:
|
||||
inputs:
|
||||
let
|
||||
inputNixosModules = [
|
||||
inputs.disko.nixosModules.disko
|
||||
|
|
|
@ -77,6 +77,7 @@ in
|
|||
description = "The server type to create";
|
||||
default = null;
|
||||
};
|
||||
|
||||
extraFirewallRules = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.attrs;
|
||||
description = "Extra firewall rules added to the instance";
|
||||
|
@ -153,7 +154,7 @@ in
|
|||
initial_image = "debian-12";
|
||||
rdns = lib.mkIf cfg.mapRdns fqdn;
|
||||
ssh_keys = [ config.khscodes.hcloud.output.data.ssh_key.khs.id ];
|
||||
user_data = provisioningUserData;
|
||||
user_data = builtins.toJSON provisioningUserData;
|
||||
};
|
||||
khscodes.cloudflare = {
|
||||
enable = true;
|
||||
|
@ -199,8 +200,16 @@ in
|
|||
message = "Must set config.khscodes.networking.fqdn when using opentofu";
|
||||
}
|
||||
];
|
||||
|
||||
khscodes.services.read-vault-auth-from-userdata.url = "http://169.254.169.254/latest/user-data";
|
||||
khscodes.services.openssh = {
|
||||
enable = true;
|
||||
hostCertificate = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
khscodes.services.read-vault-auth-from-userdata = {
|
||||
url = "http://169.254.169.254/latest/user-data";
|
||||
doubleDecodeJsonData = true;
|
||||
};
|
||||
khscodes.infrastructure.provisioning.pre = {
|
||||
modules = modules;
|
||||
};
|
||||
|
|
|
@ -135,7 +135,7 @@ in
|
|||
flavor = cfg.flavor;
|
||||
ssh_public_key = cfg.ssh_key;
|
||||
firewall_rules = firewallRules;
|
||||
user_data = provisioningUserData;
|
||||
user_data = builtins.toJSON provisioningUserData;
|
||||
};
|
||||
khscodes.unifi.enable = true;
|
||||
khscodes.unifi.static_route.compute = {
|
||||
|
|
|
@ -30,6 +30,10 @@ let
|
|||
search = "cloudflare/cloudflare";
|
||||
endpoint = "cloudflare";
|
||||
}
|
||||
{
|
||||
search = "hetznercloud/hcloud";
|
||||
endpoint = "hcloud";
|
||||
}
|
||||
{
|
||||
search = "terraform-provider-openstack/openstack";
|
||||
endpoint = "openstack";
|
||||
|
@ -79,7 +83,7 @@ in
|
|||
pre = provisioning;
|
||||
post = provisioning;
|
||||
instanceUserData = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
type = (pkgs.formats.json { }).type;
|
||||
description = "User data that should be added to the instance during provisioning";
|
||||
default = "";
|
||||
};
|
||||
|
|
|
@ -66,7 +66,9 @@ in
|
|||
owner = "alloy";
|
||||
group = "alloy";
|
||||
perms = "0600";
|
||||
reloadOrRestartUnits = [ "alloy.service" ];
|
||||
# Alloy doesn't seem to reload the certificates when using just reload
|
||||
# so restart the unit.
|
||||
restartUnits = [ "alloy.service" ];
|
||||
}
|
||||
];
|
||||
khscodes.services.alloy = {
|
||||
|
|
|
@ -66,7 +66,7 @@ in
|
|||
owner = "alloy";
|
||||
group = "alloy";
|
||||
perms = "0600";
|
||||
reloadOrRestartUnits = [ "alloy.service" ];
|
||||
restartUnits = [ "alloy.service" ];
|
||||
}
|
||||
];
|
||||
khscodes.services.alloy = {
|
||||
|
|
|
@ -131,11 +131,9 @@ in
|
|||
};
|
||||
# I can only provide the user data if the stage is pre (along with the instance creation)
|
||||
# Also I should probably find a way of injecting this in a nicer way than this mess.
|
||||
khscodes.infrastructure.provisioning.instanceUserData = lib.mkIf (cfg.stage == "pre") ''
|
||||
{
|
||||
"VAULT_ROLE_ID": "''${ vault_approle_auth_backend_role.${lib.khscodes.sanitize-terraform-name cfg.role_name}.role_id }",
|
||||
"VAULT_SECRET_ID_WRAPPED": "''${ vault_approle_auth_backend_role_secret_id.${lib.khscodes.sanitize-terraform-name cfg.role_name}.wrapping_token }"
|
||||
}
|
||||
'';
|
||||
khscodes.infrastructure.provisioning.instanceUserData = lib.mkIf (cfg.stage == "pre") {
|
||||
VAULT_ROLE_ID = "\${ vault_approle_auth_backend_role.${lib.khscodes.sanitize-terraform-name cfg.role_name}.role_id }";
|
||||
VAULT_SECRET_ID_WRAPPED = "\${ vault_approle_auth_backend_role_secret_id.${lib.khscodes.sanitize-terraform-name cfg.role_name}.wrapping_token }";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ let
|
|||
pkgs.uutils-coreutils-noprefix
|
||||
pkgs.nix
|
||||
];
|
||||
name = "nixos-prepare-upgrade";
|
||||
name = "nixos-upgrade-prepare-flake";
|
||||
text = ''
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@ let
|
|||
echo -n ${inputs.self.outPath} > ${upgradeVersion}
|
||||
fi
|
||||
cd ${upgradePath}
|
||||
NIX_CONFIG="extra-experimental-features=flake nix-command" nix flake update
|
||||
nix --extra-experimental-features "nix-command flakes" flake update
|
||||
'';
|
||||
};
|
||||
in
|
||||
|
|
|
@ -29,7 +29,7 @@ in
|
|||
credentialsFile = vaultAgentCredentialsFile;
|
||||
};
|
||||
};
|
||||
khscodes.infrastructure.vault-server-approle = {
|
||||
khscodes.infrastructure.vault-server-approle = lib.mkIf cfg.dns01Enabled {
|
||||
enable = true;
|
||||
policy = {
|
||||
"${cloudflareSecret}" = {
|
||||
|
|
|
@ -10,6 +10,7 @@ in
|
|||
{
|
||||
options.khscodes.services.read-vault-auth-from-userdata = {
|
||||
enable = lib.mkEnableOption "Enables reading vault auth information from instance userdata";
|
||||
doubleDecodeJsonData = lib.mkEnableOption "Enables double decoding the JSON data. Used by the hcloud provider as hetzner encodes the entire user data as a string";
|
||||
url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "URL to retrieve instance metadata from";
|
||||
|
@ -29,6 +30,9 @@ in
|
|||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
environment = {
|
||||
DOUBLE_DECODE = if cfg.doubleDecodeJsonData then "yes" else "no";
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
|
@ -43,7 +47,11 @@ in
|
|||
pkgs.systemd
|
||||
];
|
||||
text = ''
|
||||
DOUBLE_DECODE="''${DOUBLE_DECODE:-no}"
|
||||
userdata="$(curl ${lib.escapeShellArg cfg.url})"
|
||||
if [[ "$DOUBLE_DECODE" == "yes" ]]; then
|
||||
userdata="$(echo "$userdata" | jq --raw-output '.')"
|
||||
fi
|
||||
role_id="$(echo "$userdata" | jq --raw-output '.VAULT_ROLE_ID')"
|
||||
secret_id_wrapped="$(echo "$userdata" | jq --raw-output '.VAULT_SECRET_ID_WRAPPED')"
|
||||
if [[ -f ${cacheFilePath} ]]; then
|
||||
|
|
|
@ -120,6 +120,7 @@ in
|
|||
ignore_changes = [
|
||||
"ssh_keys"
|
||||
"public_net"
|
||||
"user_data"
|
||||
"image"
|
||||
];
|
||||
};
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
...
|
||||
}:
|
||||
{
|
||||
imports = [ "${inputs.self}/nix/profiles/nixos/hetzner-server.nix" ];
|
||||
imports = [
|
||||
"${inputs.self}/nix/profiles/nixos/hetzner-server.nix"
|
||||
./mailserver
|
||||
./forgejo
|
||||
];
|
||||
khscodes.infrastructure.hetzner-instance = {
|
||||
enable = true;
|
||||
mapRdns = true;
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
khscodes.services.vault-agent.templates = [
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/dkim" -}}
|
||||
{{ .Data.data.dkim_private_key }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/mailserver/dkim/private.key";
|
||||
perms = "0600";
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
restartUnits = [
|
||||
"rspamd.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/forgejo-user" -}}
|
||||
{{ .Data.data.hashed_password }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/mailserver/users/forgejo.passwd.hash";
|
||||
perms = "0600";
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
restartUnits = [
|
||||
"rspamd.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
202
nix/systems/aarch64-linux/kas.codes/forgejo/default.nix
Normal file
202
nix/systems/aarch64-linux/kas.codes/forgejo/default.nix
Normal file
|
@ -0,0 +1,202 @@
|
|||
{ config, pkgs, ... }:
|
||||
let
|
||||
home_forgejo = pkgs.writeText "home_forgejo.tmpl" ''
|
||||
<div class="ui stackable middle very relaxed page grid">
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
{{svg "octicon-person"}}
|
||||
</h1>
|
||||
<p class="large">
|
||||
This is just a personal self hosted software forge for my projects. I might publish a few things here for public consumption.
|
||||
</p>
|
||||
</div>
|
||||
<div class="eight wide center column">
|
||||
<h1 class="hero ui icon header">
|
||||
{{svg "octicon-code"}}
|
||||
</h1>
|
||||
<p class="large">
|
||||
This server is running <a target="_blank" rel="noopener noreferrer" href="https://forgejo.org">Forgejo</a>. Click the link to learn more.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
'';
|
||||
# This simply has the <h2> tag removed.
|
||||
home = pkgs.writeText "home.tmpl" ''
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}" class="page-content home">
|
||||
<div class="tw-mb-8 tw-px-8">
|
||||
<div class="center">
|
||||
<img class="logo" width="220" height="220" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}">
|
||||
<div class="hero">
|
||||
<h1 class="ui icon header title">
|
||||
{{AppDisplayName}}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "home_forgejo" .}}
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [ ./oauth.nix ];
|
||||
khscodes.services.vault-agent.templates = [
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/users/forgejo" -}}
|
||||
{{ .Data.data.password }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/forgejo/mailserver/forgejo.passwd";
|
||||
perms = "0600";
|
||||
owner = "git";
|
||||
group = "git";
|
||||
restartUnits = [
|
||||
"forgejo.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
systemd.services.forgejo = {
|
||||
unitConfig = {
|
||||
ConditionPathExists = [ "/var/lib/vault-agent/forgejo/mailserver/forgejo.passwd" ];
|
||||
};
|
||||
};
|
||||
services.forgejo = {
|
||||
enable = true;
|
||||
user = "git";
|
||||
group = "git";
|
||||
settings = {
|
||||
DEFAULT = {
|
||||
APP_NAME = "KAS: Codes";
|
||||
};
|
||||
server = rec {
|
||||
DOMAIN = "kas.codes";
|
||||
ROOT_URL = "https://${DOMAIN}";
|
||||
};
|
||||
session = {
|
||||
COOKIE_SECURE = true;
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
ENABLE_INTERNAL_SIGNIN = false;
|
||||
};
|
||||
repository = {
|
||||
DEFAULT_REPO_UNITS = "repo.code,repo.releases,repo.issues,repo.packages,repo.actions";
|
||||
};
|
||||
mailer = {
|
||||
ENABLED = true;
|
||||
SMTP_ADDR = "kas.codes";
|
||||
FROM = "forgejo@khs.codes";
|
||||
USER = "forgejo@khs.codes";
|
||||
};
|
||||
"ui.meta" = {
|
||||
AUTHOR = "Kaare Hoff Skovgaard <kaare@kaareskovgaard.net>";
|
||||
DESCRIPTION = "A self-hosted software forge for KAS/KHS";
|
||||
KEYWORDS = "khs,kas,kastermester,code";
|
||||
};
|
||||
actions = {
|
||||
DEFAULT_ACTIONS_URL = "https://kas.codes";
|
||||
};
|
||||
oauth2_client = {
|
||||
ENABLE_AUTO_REGISTRATION = true;
|
||||
USERNAME = "nickname";
|
||||
ACCOUNT_LINKING = "disabled";
|
||||
REGISTER_EMAIL_CONFIRM = false;
|
||||
};
|
||||
};
|
||||
secrets.mailer.PASSWD = "/var/lib/vault-agent/forgejo/mailserver/forgejo.passwd";
|
||||
lfs = {
|
||||
enable = true;
|
||||
};
|
||||
database = {
|
||||
type = "postgres";
|
||||
user = "git";
|
||||
name = "git";
|
||||
};
|
||||
dump = {
|
||||
enable = true;
|
||||
file = "forgejo-dump";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.write-forgejo-templates = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
before = [ "forgejo.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "write-forgejo-templates";
|
||||
runtimeInputs = [ pkgs.uutils-coreutils-noprefix ];
|
||||
text = ''
|
||||
if [ ! -d /var/lib/forgejo/custom/templates ]; then
|
||||
mkdir /var/lib/forgejo/custom/templates
|
||||
fi
|
||||
ln -sf ${home_forgejo} /var/lib/forgejo/custom/templates/home_forgejo.tmpl
|
||||
ln -sf ${home} /var/lib/forgejo/custom/templates/home.tmpl
|
||||
'';
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
users.users.forgejo-backup = {
|
||||
isNormalUser = true;
|
||||
home = "/home/forgejo-backup";
|
||||
group = "forgejo-backup";
|
||||
createHome = true;
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ/hn4Q1+5KpViol+Kk7bUvWrka2hhKEXqUJVY0quQLu forgejo-backup@truenas.kaareskovgaard.net"
|
||||
];
|
||||
};
|
||||
users.groups.forgejo-backup = { };
|
||||
|
||||
systemd.timers.forgejo-dump = {
|
||||
timerConfig = {
|
||||
Unit = "forgejo-copy-dump.service";
|
||||
};
|
||||
};
|
||||
systemd.services.forgejo-copy-dump = {
|
||||
requires = [ "forgejo-dump.service" ];
|
||||
after = [ "forgejo-dump.service" ];
|
||||
wantedBy = [ "timers.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "forgejo-copy-dump";
|
||||
runtimeInputs = [ pkgs.uutils-coreutils-noprefix ];
|
||||
text = ''
|
||||
mv /var/lib/forgejo/dump/forgejo-dump.zip /home/forgejo-backup/dump.zip
|
||||
chown forgejo-backup:forgejo-backup /home/forgejo-backup/dump.zip
|
||||
chmod 0640 /home/forgejo-backup/dump.zip
|
||||
'';
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
khscodes.services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
"kas.codes" = {
|
||||
extraConfig = ''
|
||||
client_max_body_size 32M;
|
||||
'';
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:3000";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
users.users.git = {
|
||||
isSystemUser = true;
|
||||
group = "git";
|
||||
home = config.services.forgejo.stateDir;
|
||||
useDefaultShell = true;
|
||||
};
|
||||
users.groups.git = { };
|
||||
}
|
79
nix/systems/aarch64-linux/kas.codes/forgejo/oauth.nix
Normal file
79
nix/systems/aarch64-linux/kas.codes/forgejo/oauth.nix
Normal file
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
oauthSecretIdFile = "/run/forgejo/oauth_secret_id";
|
||||
setApp = pkgs.writeShellApplication {
|
||||
name = "forgejo-set-oauth-app";
|
||||
runtimeInputs = [
|
||||
pkgs.forgejo
|
||||
pkgs.gnugrep
|
||||
];
|
||||
text = ''
|
||||
config="${config.services.forgejo.stateDir}/custom/conf/app.ini"
|
||||
secret="$(cat ${oauthSecretIdFile})"
|
||||
|
||||
if gitea "--config=$config" admin auth list | grep -q "Kanidm" 2> /dev/null; then
|
||||
echo "Oauth2 app already exists, updating not yet implemented"
|
||||
exit 0
|
||||
else
|
||||
gitea "--config=$config" admin auth add-oauth \
|
||||
--name "Kanidm" \
|
||||
--key "forgejo" \
|
||||
--secret "$secret" \
|
||||
--auto-discover-url https://login.kaareskovgaard.net/oauth2/openid/forgejo/.well-known/openid-configuration \
|
||||
--scopes "email profile" \
|
||||
--skip-local-2fa \
|
||||
--provider openidConnect \
|
||||
--group-claim-name groups \
|
||||
--admin-group admin \
|
||||
--group-team-map-removal \
|
||||
--group-team-map '{"nix": ["nix"], "actions": ["actons"]}'
|
||||
fi
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
khscodes.services.vault-agent.templates = [
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "kanidm/data/apps/forgejo" -}}
|
||||
{{ .Data.data.basic_secret }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = oauthSecretIdFile;
|
||||
perms = "0600";
|
||||
owner = "git";
|
||||
group = "git";
|
||||
restartUnits = [
|
||||
"forgejo-setup-oauth.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
khscodes.infrastructure.vault-server-approle.policy = {
|
||||
"kanidm/data/apps/forgejo" = {
|
||||
capabilities = [ "read" ];
|
||||
};
|
||||
};
|
||||
systemd.services.forgejo-setup-oauth = {
|
||||
enable = true;
|
||||
wants = [ "vault-agent-openbao.service" ];
|
||||
requires = [ "forgejo.service" ];
|
||||
after = [
|
||||
"forgejo.service"
|
||||
"vault-agent-openbao.service"
|
||||
];
|
||||
unitConfig = {
|
||||
ConditionPathExists = [ oauthSecretIdFile ];
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "git";
|
||||
Group = "git";
|
||||
ExecStart = lib.getExe setApp;
|
||||
};
|
||||
};
|
||||
}
|
44
nix/systems/aarch64-linux/kas.codes/mailserver/default.nix
Normal file
44
nix/systems/aarch64-linux/kas.codes/mailserver/default.nix
Normal file
|
@ -0,0 +1,44 @@
|
|||
{ inputs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./dkim.nix
|
||||
./forgejo-user.nix
|
||||
inputs.simple-nixos-mailserver.nixosModules.mailserver
|
||||
];
|
||||
khscodes.infrastructure.vault-server-approle.policy = {
|
||||
"forgejo/data/mailserver/*" = {
|
||||
capabilities = [ "read" ];
|
||||
};
|
||||
};
|
||||
khscodes.infrastructure.provisioning.pre.modules = [
|
||||
{
|
||||
khscodes.vault = {
|
||||
enable = true;
|
||||
mount.forgejo = {
|
||||
path = "forgejo";
|
||||
type = "kv";
|
||||
options = {
|
||||
version = "2";
|
||||
};
|
||||
description = "Secrets used for forgejo";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
mailserver = {
|
||||
enable = true;
|
||||
fqdn = "kas.codes";
|
||||
domains = [ "kas.codes" ];
|
||||
loginAccounts = {
|
||||
"forgejo@kas.codes" = {
|
||||
hashedPasswordFile = "/var/lib/vault-agent/mailserver/users/forgejo.passwd.hash";
|
||||
sendOnly = true;
|
||||
};
|
||||
};
|
||||
certificateScheme = "acme";
|
||||
dkimKeyDirectory = "/var/lib/vault-agent/mailserver/dkim/";
|
||||
dkimSelector = "dkim_rsa";
|
||||
# Not sure we need to set this at all.
|
||||
dkimKeyBits = 2048;
|
||||
};
|
||||
}
|
112
nix/systems/aarch64-linux/kas.codes/mailserver/dkim.nix
Normal file
112
nix/systems/aarch64-linux/kas.codes/mailserver/dkim.nix
Normal file
|
@ -0,0 +1,112 @@
|
|||
let
|
||||
publicKeyBegin = ''"-----BEGIN PUBLIC KEY-----\n"'';
|
||||
publicKeyEnd = ''"-----END PUBLIC KEY-----\n"'';
|
||||
dkimPublicKey =
|
||||
tls_key:
|
||||
''''${ replace(trimprefix(trimsuffix(${tls_key}.public_key_pem, ${publicKeyEnd}), ${publicKeyBegin}), "\n", "") }'';
|
||||
in
|
||||
{
|
||||
khscodes.services.vault-agent.templates = [
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/dkim/rsa" -}}
|
||||
{{ .Data.data.dkim_private_key }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/mailserver/dkim/rsa_private.key";
|
||||
perms = "0600";
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
restartUnits = [
|
||||
"rspamd.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/dkim/ed25519" -}}
|
||||
{{ .Data.data.dkim_private_key }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/mailserver/dkim/ed25519_private.key";
|
||||
perms = "0600";
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
restartUnits = [
|
||||
"rspamd.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
khscodes.infrastructure.provisioning.pre.modules = [
|
||||
(
|
||||
{ config, ... }:
|
||||
{
|
||||
terraform.required_providers.tls = {
|
||||
source = "hashicorp/tls";
|
||||
version = "4.1.0";
|
||||
};
|
||||
provider.tls = { };
|
||||
|
||||
resource.tls_private_key.dkim_rsa = {
|
||||
algorithm = "RSA";
|
||||
rsa_bits = 2048;
|
||||
};
|
||||
resource.tls_private_key.dkim_ed25519 = {
|
||||
algorithm = "ED25519";
|
||||
};
|
||||
|
||||
resource.cloudflare_record.dkim_rsa = {
|
||||
name = "snm_rsa._domainkey";
|
||||
zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
|
||||
type = "TXT";
|
||||
content = ''"v=DKIM1;k=rsa;p=${dkimPublicKey "tls_private_key.dkim_rsa"}"'';
|
||||
comment = "app=kas.codes";
|
||||
ttl = 600;
|
||||
};
|
||||
|
||||
resource.cloudflare_record.dkim_ed25519 = {
|
||||
name = "snm_ed25519._domainkey";
|
||||
zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
|
||||
type = "TXT";
|
||||
content = ''"v=DKIM1;k=ed25519;p=${dkimPublicKey "tls_private_key.dkim_ed25519"}"'';
|
||||
comment = "app=kas.codes";
|
||||
ttl = 600;
|
||||
};
|
||||
|
||||
resource.cloudflare_record.spf = {
|
||||
name = "@";
|
||||
zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
|
||||
type = "TXT";
|
||||
content = ''"v=spf1 ip4:${config.khscodes.hcloud.output.server.compute.ipv4_address} ip6:${config.khscodes.hcloud.output.server.compute.ipv6_address} -all"'';
|
||||
comment = "app=kas.codes";
|
||||
ttl = 600;
|
||||
};
|
||||
resource.cloudflare_record.dmarc = {
|
||||
name = "_dmarc";
|
||||
zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
|
||||
type = "TXT";
|
||||
content = ''"v=DMARC1; p=reject; adkim=s; aspf=s;"'';
|
||||
comment = "app=kas.codes";
|
||||
ttl = 600;
|
||||
};
|
||||
|
||||
resource.vault_kv_secret_v2.dkim_rsa_secret = {
|
||||
mount = config.khscodes.vault.output.mount.forgejo.path;
|
||||
name = "mailserver/dkim/rsa";
|
||||
data_json = ''
|
||||
{ "dkim_private_key": ''${ jsonencode(resource.tls_private_key.dkim_rsa.private_key_pem) } }
|
||||
'';
|
||||
};
|
||||
|
||||
resource.vault_kv_secret_v2.dkim_ed25519_secret = {
|
||||
mount = config.khscodes.vault.output.mount.forgejo.path;
|
||||
name = "mailserver/dkim/ed25519";
|
||||
data_json = ''
|
||||
{ "dkim_private_key": ''${ jsonencode(resource.tls_private_key.dkim_ed25519.private_key_pem) } }
|
||||
'';
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
let
|
||||
bcrypt = expr: "\${ jsonencode(bcrypt(${expr})) }";
|
||||
in
|
||||
{
|
||||
khscodes.services.vault-agent.templates = [
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "forgejo/data/mailserver/users/forgejo" -}}
|
||||
{{ .Data.data.hashed_password }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = "/var/lib/vault-agent/mailserver/users/forgejo.passwd.hash";
|
||||
perms = "0600";
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
restartUnits = [
|
||||
"rspamd.service"
|
||||
"postfix.service"
|
||||
];
|
||||
}
|
||||
];
|
||||
khscodes.infrastructure.provisioning.pre.modules = [
|
||||
(
|
||||
{ config, ... }:
|
||||
{
|
||||
terraform.required_providers.random = {
|
||||
source = "hashicorp/random";
|
||||
version = "3.7.2";
|
||||
};
|
||||
provider.random = { };
|
||||
|
||||
resource.random_password.forgejo_mail_passwd = {
|
||||
length = 48;
|
||||
numeric = true;
|
||||
lower = true;
|
||||
upper = true;
|
||||
special = false;
|
||||
};
|
||||
|
||||
resource.vault_kv_secret_v2.forgejo_email_user_password = {
|
||||
mount = config.khscodes.vault.output.mount.forgejo.path;
|
||||
name = "mailserver/users/forgejo";
|
||||
data_json = ''
|
||||
{
|
||||
"hashed_password": ${bcrypt "resource.random_password.forgejo_mail_passwd.result"},
|
||||
"password": ''${ jsonencode(resource.random_password.forgejo_mail_passwd.result) }
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
|
@ -10,6 +10,7 @@ let
|
|||
openbaoAppBasicSecretFile = "/var/lib/vault-agent/kanidm/openbao_basic_secret";
|
||||
openbaoCliAppBasicSecretFile = "/var/lib/vault-agent/kanidm/openbao_cli_basic_secret";
|
||||
monitoringAppBasicSecretFile = "/var/lib/vault-agent/kanidm/monitoring_basic_secret";
|
||||
forgejoAppBasicSecretFile = "/var/lib/vault-agent/kanidm/monitoring_basic_secret";
|
||||
openbaoDomain = config.khscodes.infrastructure.openbao.domain;
|
||||
openbaoAllowedRedirectUrls = [
|
||||
"https://${openbaoDomain}/ui/vault/auth/kanidm/oidc/callback"
|
||||
|
@ -70,6 +71,14 @@ in
|
|||
present = true;
|
||||
members = [ "khs" ];
|
||||
};
|
||||
groups.forgejo_user = {
|
||||
present = true;
|
||||
members = [ "khs" ];
|
||||
};
|
||||
groups.forgejo_comitter = {
|
||||
present = true;
|
||||
members = [ "khs" ];
|
||||
};
|
||||
# We cannot add oauth2 apps before the secrets for them are generated.
|
||||
systems.oauth2 = lib.mkIf (!bootstrapping) {
|
||||
openbao = {
|
||||
|
@ -137,6 +146,30 @@ in
|
|||
];
|
||||
};
|
||||
};
|
||||
forgejo = {
|
||||
present = true;
|
||||
public = false;
|
||||
preferShortUsername = true;
|
||||
basicSecretFile = lib.mkIf (!bootstrapping) forgejoAppBasicSecretFile;
|
||||
originUrl = [ "https://kas.codes/user/oauth2/Kanidm/callback" ];
|
||||
originLanding = "http://kas.codes";
|
||||
displayName = "KAS: Codes";
|
||||
scopeMaps = {
|
||||
"forgejo_user" = [
|
||||
"profile"
|
||||
"email"
|
||||
"openid"
|
||||
];
|
||||
};
|
||||
claimMaps.groups = {
|
||||
joinType = "array";
|
||||
valuesByGroup = {
|
||||
"forgejo_comitter" = [
|
||||
"comitter"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -218,6 +251,20 @@ in
|
|||
{ "basic_secret": "''${ resource.random_password.monitoring.result }" }
|
||||
'';
|
||||
};
|
||||
resource.random_password.forgejo = {
|
||||
length = 48;
|
||||
numeric = true;
|
||||
lower = true;
|
||||
upper = true;
|
||||
special = false;
|
||||
};
|
||||
resource.vault_kv_secret_v2.forgejo_secret = {
|
||||
mount = config.khscodes.vault.output.mount.kanidm.path;
|
||||
name = "apps/forgejo";
|
||||
data_json = ''
|
||||
{ "basic_secret": "''${ resource.random_password.forgejo.result }" }
|
||||
'';
|
||||
};
|
||||
}
|
||||
)
|
||||
# Sets up OIDC authentication within OpenBAO.
|
||||
|
@ -381,6 +428,18 @@ in
|
|||
group = "kanidm";
|
||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
||||
}
|
||||
{
|
||||
contents = ''
|
||||
{{- with secret "kanidm/data/apps/forgejo" -}}
|
||||
{{ .Data.data.basic_secret }}
|
||||
{{- end -}}
|
||||
'';
|
||||
destination = forgejoAppBasicSecretFile;
|
||||
perms = "0600";
|
||||
owner = "kanidm";
|
||||
group = "kanidm";
|
||||
reloadOrRestartUnits = [ "kanidm.service" ];
|
||||
}
|
||||
];
|
||||
|
||||
security.acme.certs.${domain}.reloadServices = [ "kanidm.service" ];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue