feat(conduit): Refactor appservices and add matrix-hookshot
This commit is contained in:
parent
3c17e163de
commit
2a3d66d892
configuration
keys
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
./services/backups.nix
|
./services/backups.nix
|
||||||
./services/battery-manager.nix
|
./services/battery-manager.nix
|
||||||
./services/conduit.nix
|
./services/conduit
|
||||||
./services/crowdsec.nix
|
./services/crowdsec.nix
|
||||||
./services/foundryvtt.nix
|
./services/foundryvtt.nix
|
||||||
./services/gitea.nix
|
./services/gitea.nix
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
pkgs,
|
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
|
@ -12,6 +11,11 @@ let
|
||||||
turn-realm = "turn.${config.services.nginx.domain}";
|
turn-realm = "turn.${config.services.nginx.domain}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./heisenbridge.nix
|
||||||
|
./matrix-hookshot.nix
|
||||||
|
];
|
||||||
|
|
||||||
services.matrix-conduit = {
|
services.matrix-conduit = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings.global = {
|
settings.global = {
|
||||||
|
@ -40,91 +44,6 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.heisenbridge =
|
|
||||||
let
|
|
||||||
replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret";
|
|
||||||
registrationFile = builtins.toFile "heisenbridge-registration.yaml" (
|
|
||||||
builtins.toJSON {
|
|
||||||
id = "heisenbridge";
|
|
||||||
url = "http://127.0.0.1:9898";
|
|
||||||
as_token = "@AS_TOKEN@";
|
|
||||||
hs_token = "@HS_TOKEN@";
|
|
||||||
rate_limited = false;
|
|
||||||
sender_localpart = "heisenbridge";
|
|
||||||
namespaces = {
|
|
||||||
users = [
|
|
||||||
{
|
|
||||||
regex = "@irc_.*";
|
|
||||||
exclusive = true;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
regex = "@heisenbridge:.*";
|
|
||||||
exclusive = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
aliases = [ ];
|
|
||||||
rooms = [ ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
# TODO(tlater): Starting with systemd 253 it will become possible
|
|
||||||
# to do the credential setup as part of ExecStartPre/preStart
|
|
||||||
# instead.
|
|
||||||
#
|
|
||||||
# This will also make it possible to actually set caps on the
|
|
||||||
# heisenbridge process using systemd, so that we can run the
|
|
||||||
# identd process.
|
|
||||||
execScript = pkgs.writeShellScript "heisenbridge" ''
|
|
||||||
cp ${registrationFile} "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
|
|
||||||
chmod 600 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
|
|
||||||
${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_as-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
|
|
||||||
${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/heisenbridge_hs-token" "$RUNTIME_DIRECTORY/heisenbridge-registration.yaml"
|
|
||||||
chmod 400 $RUNTIME_DIRECTORY/heisenbridge-registration.yaml
|
|
||||||
|
|
||||||
${pkgs.heisenbridge}/bin/heisenbridge \
|
|
||||||
--config $RUNTIME_DIRECTORY/heisenbridge-registration.yaml \
|
|
||||||
--owner @tlater:matrix.tlater.net \
|
|
||||||
'http://localhost:${toString cfg.settings.global.port}'
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
description = "Matrix<->IRC bridge";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "conduit.service" ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "simple";
|
|
||||||
|
|
||||||
LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
|
|
||||||
|
|
||||||
ExecStart = execScript;
|
|
||||||
|
|
||||||
DynamicUser = true;
|
|
||||||
RuntimeDirectory = "heisenbridge";
|
|
||||||
RuntimeDirectoryMode = "0700";
|
|
||||||
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
PrivateUsers = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
|
|
||||||
LockPersonality = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProcSubset = "pid";
|
|
||||||
UMask = 77;
|
|
||||||
|
|
||||||
# For the identd port
|
|
||||||
# CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
|
|
||||||
# AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Pass in the TURN secret via EnvironmentFile, not supported by
|
# Pass in the TURN secret via EnvironmentFile, not supported by
|
||||||
# upstream module currently.
|
# upstream module currently.
|
||||||
#
|
#
|
78
configuration/services/conduit/heisenbridge.nix
Normal file
78
configuration/services/conduit/heisenbridge.nix
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
conduitCfg = config.services.matrix-conduit;
|
||||||
|
matrixLib = pkgs.callPackage ./lib.nix { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.heisenbridge =
|
||||||
|
let
|
||||||
|
registration = matrixLib.writeRegistrationScript {
|
||||||
|
id = "heisenbridge";
|
||||||
|
url = "http://127.0.0.1:9898";
|
||||||
|
sender_localpart = "heisenbridge";
|
||||||
|
|
||||||
|
namespaces = {
|
||||||
|
users = [
|
||||||
|
{
|
||||||
|
regex = "@irc_.*";
|
||||||
|
exclusive = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
regex = "@heisenbridge:.*";
|
||||||
|
exclusive = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
aliases = [ ];
|
||||||
|
rooms = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
description = "Matrix<->IRC bridge";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "conduit.service" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "exec";
|
||||||
|
|
||||||
|
LoadCredential = "heisenbridge:/run/secrets/heisenbridge";
|
||||||
|
|
||||||
|
inherit (registration) ExecStartPre;
|
||||||
|
ExecStart = lib.concatStringsSep " " [
|
||||||
|
"${lib.getExe pkgs.heisenbridge}"
|
||||||
|
"--config ${registration.runtimeRegistration}"
|
||||||
|
"--owner @tlater:matrix.tlater.net"
|
||||||
|
"http://localhost:${toString conduitCfg.settings.global.port}"
|
||||||
|
];
|
||||||
|
|
||||||
|
DynamicUser = true;
|
||||||
|
RuntimeDirectory = "heisenbridge";
|
||||||
|
RuntimeDirectoryMode = "0700";
|
||||||
|
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
|
||||||
|
LockPersonality = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProcSubset = "pid";
|
||||||
|
UMask = 77;
|
||||||
|
|
||||||
|
# For the identd port
|
||||||
|
# CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
|
||||||
|
# AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
63
configuration/services/conduit/lib.nix
Normal file
63
configuration/services/conduit/lib.nix
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
writeShellScript,
|
||||||
|
formats,
|
||||||
|
replace-secret,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
replaceSecretBin = "${lib.getExe replace-secret}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Write a script that will set up the service's registration.yaml
|
||||||
|
# with secrets from systemd credentials.
|
||||||
|
#
|
||||||
|
# The credentials should be named `${id}_as-token` and
|
||||||
|
# `${id}_hs-token`.
|
||||||
|
#
|
||||||
|
# This registration file needs to be manually added to conduit by
|
||||||
|
# messaging the admin with the yaml file.
|
||||||
|
writeRegistrationScript =
|
||||||
|
{
|
||||||
|
id, # Must be unique among all registered appservices/bots
|
||||||
|
url, # The URL on which the service listens
|
||||||
|
sender_localpart,
|
||||||
|
rate_limited ? false,
|
||||||
|
namespaces ? {
|
||||||
|
aliases = [ ];
|
||||||
|
rooms = [ ];
|
||||||
|
users = [ ];
|
||||||
|
},
|
||||||
|
extraSettings ? { },
|
||||||
|
# The location to place the file; assumes systemd runtime dir
|
||||||
|
runtimeRegistration ? "$RUNTIME_DIRECTORY/${id}-registration.yaml",
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
registrationFile =
|
||||||
|
(formats.yaml { }).generate "${id}-registration.yaml" {
|
||||||
|
inherit
|
||||||
|
id
|
||||||
|
url
|
||||||
|
sender_localpart
|
||||||
|
rate_limited
|
||||||
|
namespaces
|
||||||
|
;
|
||||||
|
|
||||||
|
as_token = "@AS_TOKEN@";
|
||||||
|
hs_token = "@HS_TOKEN@";
|
||||||
|
}
|
||||||
|
// extraSettings;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit runtimeRegistration;
|
||||||
|
ExecStartPre = writeShellScript "${id}-registration-setup.sh" ''
|
||||||
|
cp -f ${registrationFile} "${runtimeRegistration}"
|
||||||
|
chmod 600 "${runtimeRegistration}"
|
||||||
|
|
||||||
|
# Write actual secrets into config
|
||||||
|
${replaceSecretBin} '@AS_TOKEN@' "$CREDENTIALS_DIRECTORY/${id}_as-token" "${runtimeRegistration}"
|
||||||
|
${replaceSecretBin} '@HS_TOKEN@' "$CREDENTIALS_DIRECTORY/${id}_hs-token" "${runtimeRegistration}"
|
||||||
|
|
||||||
|
chmod 400 "${runtimeRegistration}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
142
configuration/services/conduit/matrix-hookshot.nix
Normal file
142
configuration/services/conduit/matrix-hookshot.nix
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
matrixLib = pkgs.callPackage ./lib.nix { };
|
||||||
|
|
||||||
|
cfg = config.services.matrix-hookshot;
|
||||||
|
conduitCfg = config.services.matrix-conduit;
|
||||||
|
|
||||||
|
address = "${config.services.matrix-hookshot.settings.bridge.bindAddress}";
|
||||||
|
domain = "matrix.${config.services.nginx.domain}";
|
||||||
|
port = config.services.matrix-hookshot.settings.bridge.port;
|
||||||
|
|
||||||
|
registration = matrixLib.writeRegistrationScript {
|
||||||
|
id = "matrix-hookshot";
|
||||||
|
url = "${address}:${toString port}";
|
||||||
|
sender_localpart = "hookshot";
|
||||||
|
|
||||||
|
namespaces = {
|
||||||
|
aliases = [ ];
|
||||||
|
rooms = [ ];
|
||||||
|
users = [
|
||||||
|
{
|
||||||
|
regex = "@${cfg.settings.generic.userIdPrefix}.*:${domain}";
|
||||||
|
exclusive = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Encryption support
|
||||||
|
extraSettings = {
|
||||||
|
"de.sorunome.msc2409.push_ephemeral" = true;
|
||||||
|
push_ephemeral = true;
|
||||||
|
"org.matrix.msc3202" = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
runtimeRegistration = "/var/lib/matrix-hookshot/registration.yaml";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.matrix-hookshot = {
|
||||||
|
serviceConfig = {
|
||||||
|
Type = lib.mkForce "exec";
|
||||||
|
|
||||||
|
LoadCredential = "matrix-hookshot:/run/secrets/matrix-hookshot";
|
||||||
|
inherit (registration) ExecStartPre;
|
||||||
|
|
||||||
|
# Some library in matrix-hookshot wants a home directory
|
||||||
|
Environment = [ "HOME=/var/lib/matrix-hookshot" ];
|
||||||
|
|
||||||
|
DynamicUser = true;
|
||||||
|
StateDirectory = "matrix-hookshot";
|
||||||
|
RuntimeDirectory = "matrix-hookshot";
|
||||||
|
RuntimeDirectoryMode = "0700";
|
||||||
|
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
|
||||||
|
LockPersonality = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProcSubset = "pid";
|
||||||
|
UMask = 77;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.matrix-hookshot = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
serviceDependencies = [
|
||||||
|
"conduit.service"
|
||||||
|
];
|
||||||
|
|
||||||
|
registrationFile = "/var/lib/matrix-hookshot/registration.yaml";
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
bridge = {
|
||||||
|
inherit domain;
|
||||||
|
url = "http://localhost:${toString conduitCfg.settings.global.port}";
|
||||||
|
mediaUrl = conduitCfg.settings.global.well_known.client;
|
||||||
|
port = 9993;
|
||||||
|
bindAddress = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
generic = {
|
||||||
|
enabled = true;
|
||||||
|
outbound = false;
|
||||||
|
# Only allow webhooks from localhost for the moment
|
||||||
|
urlPrefix = "${cfg.settings.bridge.url}/webhook";
|
||||||
|
userIdPrefix = "_webhooks_";
|
||||||
|
};
|
||||||
|
|
||||||
|
encryption.storagePath = "/var/lib/matrix-hookshot/cryptostore";
|
||||||
|
|
||||||
|
permissions = [
|
||||||
|
{
|
||||||
|
actor = "matrix.tlater.net";
|
||||||
|
services = [
|
||||||
|
{
|
||||||
|
service = "*";
|
||||||
|
level = "notifications";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
actor = "@tlater:matrix.tlater.net";
|
||||||
|
services = [
|
||||||
|
{
|
||||||
|
service = "*";
|
||||||
|
level = "admin";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
listeners = [
|
||||||
|
{
|
||||||
|
port = 9000;
|
||||||
|
resources = [
|
||||||
|
"webhooks"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
port = 9001;
|
||||||
|
resources = [
|
||||||
|
"metrics"
|
||||||
|
"provisioning"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -35,6 +35,10 @@
|
||||||
"heisenbridge/as-token" = { };
|
"heisenbridge/as-token" = { };
|
||||||
"heisenbridge/hs-token" = { };
|
"heisenbridge/hs-token" = { };
|
||||||
|
|
||||||
|
# Matrix-hookshot
|
||||||
|
"matrix-hookshot/as-token" = { };
|
||||||
|
"matrix-hookshot/hs-token" = { };
|
||||||
|
|
||||||
# Nextcloud
|
# Nextcloud
|
||||||
"nextcloud/tlater" = {
|
"nextcloud/tlater" = {
|
||||||
owner = "nextcloud";
|
owner = "nextcloud";
|
||||||
|
|
|
@ -16,6 +16,9 @@ steam:
|
||||||
heisenbridge:
|
heisenbridge:
|
||||||
as-token: ENC[AES256_GCM,data:tXbOeo7nv8I=,iv:wJAKcOXX9nGIw4n38ThOoj29u7dUWhsxSQG/p79JlEw=,tag:rTVaGS2UuWcea1uBa8YX2g==,type:str]
|
as-token: ENC[AES256_GCM,data:tXbOeo7nv8I=,iv:wJAKcOXX9nGIw4n38ThOoj29u7dUWhsxSQG/p79JlEw=,tag:rTVaGS2UuWcea1uBa8YX2g==,type:str]
|
||||||
hs-token: ENC[AES256_GCM,data:VBwvwomv0Xg=,iv:q6INtJ+rg+QiXj8uBdBzQYQZUBBXp+9odxDHwvu8Jxc=,tag:XKhm8nxygAkKaiVPJ2Fcdg==,type:str]
|
hs-token: ENC[AES256_GCM,data:VBwvwomv0Xg=,iv:q6INtJ+rg+QiXj8uBdBzQYQZUBBXp+9odxDHwvu8Jxc=,tag:XKhm8nxygAkKaiVPJ2Fcdg==,type:str]
|
||||||
|
matrix-hookshot:
|
||||||
|
as-token: ENC[AES256_GCM,data:uSUOo4f2KqA=,iv:Xb9G8Ecv6m59m51kDw2bOfq3SMJt4g9/6/EdH74R+KM=,tag:K9MSfO2c2Y4rlf0eYrmTnw==,type:str]
|
||||||
|
hs-token: ENC[AES256_GCM,data:0KsyA06InL4=,iv:zAR0Y1fk8SyodcSLBHlQ8I+BAmttz9Hkd8Q3OREFqs4=,tag:t1Et8N/3seq95DeGoUd7Sw==,type:str]
|
||||||
wireguard:
|
wireguard:
|
||||||
server-key: ENC[AES256_GCM,data:FvY897XdKoa/mckE8JQLCkklsnYD6Wz1wpsu5t3uhEnW3iarnDQxF9msuYU=,iv:jqGXfekM+Vs+J9b5nlZ5Skd1ZKHajoUo2Dc4tMYPm1w=,tag:EehikjI/FCU8wqtpvJRamQ==,type:str]
|
server-key: ENC[AES256_GCM,data:FvY897XdKoa/mckE8JQLCkklsnYD6Wz1wpsu5t3uhEnW3iarnDQxF9msuYU=,iv:jqGXfekM+Vs+J9b5nlZ5Skd1ZKHajoUo2Dc4tMYPm1w=,tag:EehikjI/FCU8wqtpvJRamQ==,type:str]
|
||||||
restic:
|
restic:
|
||||||
|
@ -34,8 +37,8 @@ sops:
|
||||||
azure_kv: []
|
azure_kv: []
|
||||||
hc_vault: []
|
hc_vault: []
|
||||||
age: []
|
age: []
|
||||||
lastmodified: "2025-02-01T10:16:31Z"
|
lastmodified: "2025-02-07T17:43:24Z"
|
||||||
mac: ENC[AES256_GCM,data:N4RQHOyWvSXW16fepQvRznNbmGerct03kptyiY3IoTpYaJ+43cyFjW15ZqfpaRFyV66QIeqmceqV8c4eP8YSndj6e55e04w0RCyqREXQlFPR6Eh5elaBenokoJhjF6BCsq+xX1C+LUEcxiR/dgy5cwA3mAD/dLCm+G11a06EG6k=,iv:wt5fEOVP6CXHCzmMH9hNCQDDgPa66bLMOa39Eipux9Y=,tag:kWZPnWD1stANVAmWmvOjCg==,type:str]
|
mac: ENC[AES256_GCM,data:akmD/bfgeTyFzW1quvM16cdj0fC6+CbJ8WyX9173H11yKGxvE1USQYcErpl1SHOx9Jk8LVb7f+MsUm2fjQF1MEq6xaWI74jem12lZ9CGXFaTL7e87JvfbK7pV+aKpxSBBNFyJgbYm30ibdUwxwKmNVfPb1e0HT9qwenvoV7RobM=,iv:mKqOW0ULXL711uczUbRf9NPo6uPTQoS/IbR46S+JID4=,tag:vE6NYzYLbQHDImov1XGTcg==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2025-01-21T17:55:30Z"
|
- created_at: "2025-01-21T17:55:30Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
|
|
Loading…
Reference in a new issue