[timetagger,traefik] Adds timetagger back, and attempts to put it behind an oauth proxy, but the traefik config isn't quite right.

This commit is contained in:
2025-05-29 17:05:48 -07:00
parent 07123a0fc2
commit 9411f87dbc
8 changed files with 253 additions and 114 deletions

View File

@@ -11,11 +11,9 @@ focalboard:
offen:
secret: ENC[AES256_GCM,data:sH2siPc/QH1O2M7ZlJwqhqlHRIeLIG9r,iv:eD29ALx2ji0rm1t9j6RulTZT3f6VLK7dxpPOze3qDKA=,tag:zqJTgT2UeA/ecBS4VremUw==,type:str]
smtp-token: ENC[AES256_GCM,data:ZTfe65g3JykPvG2l0AN8UQ==,iv:GTruGo/vcP+imfJyqB3NX9ic8dz5jvTEh6SF+OeqMDM=,tag:kgwd59pG/WUt8OAaVzi39Q==,type:str]
traefik:
oauth2-client-secret: ENC[AES256_GCM,data:c4zU/oH/buelobBo/47V74Xwm6MU76C+UPCFpuARYU8=,iv:7dl0MIjza6B8FGl3i3O/4CxKxlp4z2S+H82xSLUg5iQ=,tag:63E/RNjiw56evIxfhF8acg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1yvdzvuvu5wqztcx6ll2xk6x547uuyqy735tjjdd7zftkz53jsf9qf5ahue
enc: |
@@ -35,8 +33,7 @@ sops:
by9aNFY4dXNxaWxnTXFTQS9reHhuQWMKh5rZ93nFtBV9EpFVRp+E+GXZ6xzVy2Jw
vFh4deGcAb60q4odSaeWfk1Dr7L9Ua69oK9omjbCNUt+P7Kwlfca7Q==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-04-28T23:33:42Z"
mac: ENC[AES256_GCM,data:cZkRcGV5/CPPVUdTDekwC8UjO6K348sBsS7NvR8wnoXS0AmSZsqN594nkvoc0VccM55Hwnm4jZxY56OV+UFMya1IRIkTo6LJRb88/CgZ8bjz30ACe33FKgJfCugimUDKsekbgNX1UFg1DVbqYK9/N4fcEBSxV3Xmzy5QGnQ/8KU=,iv:EprUHNtU5w7569ADMOxw+izDAL22A5OrB12T9iyHxKU=,tag:kRvyUEZwd/RttKdFOY2bJQ==,type:str]
pgp: []
lastmodified: "2025-05-29T23:38:06Z"
mac: ENC[AES256_GCM,data:SImZMvXfUUt2IznmthXEG2o2cUUn485+D44OFZZc3WGmvrPIJ8WjT50HUu3fCEWmwO4mFv1VVBAr/SkN3s6VDgCh7Nbe4clp3zpgyiWamiXlvJP2Y0k1W+KjTd/AQ7jLig9D9UDXHVRBy5rZ5iLZdjZ6s5WQ8rfztcbMpkdi9yk=,iv:XVHHpwFkkhzbO3wYoerIcDeA5Io0GeLxzR2AT+BQij8=,tag:go/0xd1FhG/5h+TXA4xxHg==,type:str]
unencrypted_suffix: _unencrypted
version: 3.9.4
version: 3.10.2

View File

@@ -16,6 +16,7 @@
./containers/searxng.nix
./containers/shared-postgres.nix
./containers/synapse.nix
./containers/timetagger.nix
./containers/traefik.nix
./containers/users.nix
];
@@ -50,7 +51,8 @@
inherit (import ./containers/lib.nix config)
hostRuleHavenisms
localHostRuleHavenisms
havenisms;
havenisms
;
in
{
jellyfin = {

View File

@@ -21,41 +21,62 @@ in
havenisms
blazestar
terakoda
terakoda_net;
terakoda_net
;
mkContainer = {
mkContainer =
{
image,
hostName,
port,
homepageOpts ? {},
dependsOn ? [],
homepageOpts ? { },
dependsOn ? [ ],
domain ? havenisms,
ports ? [],
volumes ? [],
environment ? {},
environmentFiles ? [],
ports ? [ ],
volumes ? [ ],
environment ? { },
environmentFiles ? [ ],
public ? false,
user ? null,
extraOptions ? [],
extraOptions ? [ ],
oauthProxy ? false,
}:
let
routerRule = if public then hostRule hostName domain else localHostRule hostName domain;
homepageLabels = if homepageOpts == {} then {} else {
homepageLabels =
if homepageOpts == { } then
{ }
else
{
"homepage.group" = "${homepageOpts.group}";
"homepage.name" = "${homepageOpts.name}";
"homepage.icon" = "${homepageOpts.icon}";
"homepage.href" = "https://${hostName}.${domain}";
"homepage.description" = "${homepageOpts.description}";
};
oauthLabels =
if oauthProxy then { "traefik.http.routers.${hostName}.middlewares" = "oidc-auth@file"; } else { };
in
{
inherit image dependsOn volumes environment environmentFiles ports user extraOptions;
inherit
image
dependsOn
volumes
environment
environmentFiles
ports
user
extraOptions
;
autoStart = true;
labels = {
labels =
{
"traefik.enable" = "true";
"traefik.http.routers.${hostName}.rule" = "${routerRule}";
"traefik.http.services.${hostName}.loadbalancer.server.port" = "${toString port}";
} // homepageLabels;
}
// oauthLabels
// homepageLabels;
};
# Creates a MariaDB container for a specific app. It should be safe to give
@@ -64,7 +85,8 @@ in
# user.
#
# Note that this returns a _module_ so that it can be imported and provide many different config values.
mkMariaDbContainer = {
mkMariaDbContainer =
{
name,
uid,
gid,
@@ -93,7 +115,8 @@ in
};
};
mkPostgresContainer = {
mkPostgresContainer =
{
name,
uid,
gid,
@@ -102,7 +125,9 @@ in
containerName ? "${name}-postgres",
databaseName ? name,
username ? name,
}: { config, ... }: {
}:
{ config, ... }:
{
virtualisation.oci-containers.containers."${containerName}" = {
image = "postgres";
autoStart = true;

View File

@@ -0,0 +1,50 @@
{ config, ... }:
let
inherit (import ./lib.nix config) mkContainer blazestar havenisms;
in
{
sops.secrets = {
"oauth2-proxy/cookie-secret" = {
restartUnits = [ "podman-oauth2-proxy.service" ];
mode = "0400";
};
"oauth2-proxy/client-secret" = {
restartUnits = [ "podman-oauth2-proxy.service" ];
mode = "0400";
};
};
sops.templates."oauth2-proxy.env".content = ''
OAUTH2_PROXY_HTTP_ADDRESS='0.0.0.0:4180'
OAUTH2_PROXY_COOKIE_SECRET='${config.sops.placehoder."oauth2-proxy/cookie-secret"}'
OAUTH2_PROXY_COOKIE_DOMAINS='.${blazestar} .${havenisms}'
OAUTH2_PROXY_WHITELIST_DOMAINS='.${blazestar} .${havenisms}'
OAUTH2_PROXY_PROVIDER='oidc'
OAUTH2_PROXY_CLIENT_ID='oauth2-proxy'
OAUTH2_PROXY_CLIENT_SECRET='${config.sops.placehoder."oauth2-proxy/client-secret"}'
OAUTH2_PROXY_EMAIL_DOMAINS='*'
OAUTH2_PROXY_OIDC_ISSUER_URL='https://auth.${blazestar}/realms/master'
OAUTH2_PROXY_REDIRECT_URL='https://auth.${blazestar}/oauth2/callback'
OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST=true
OAUTH2_PROXY_COOKIE_CSRF_EXPIRE='5m'
OAUTH2_PROXY_CUSTOM_TEMPLATES_DIR="/templates"
OAUTH2_PROXY_REVERSE_PROXY=true
'';
virtualisation.oci-containers.containers.oauth2-proxy = mkContainer {
image = "quay.io/oauth2-proxy/oauth2-proxy";
hostName = "oauth";
domain = blazestar;
port = "4180";
homepageOpts = {
group = "Infra";
name = "OAuth2-Proxy";
icon = "oauth2-proxy.png";
description = "An OAuth2 Reverse Proxy";
};
volumes = [
];
environment = {
};
};
}

View File

@@ -0,0 +1,31 @@
{ config, ... }:
let
inherit (import ./lib.nix config) mkContainer terakoda_net;
in
{
virtualisation.oci-containers.containers.timetagger = mkContainer {
image = "ghcr.io/almarklein/timetagger:v24.12.2";
hostName = "time";
domain = terakoda_net;
port = "80";
oauthProxy = true;
homepageOpts = {
group = "Apps";
name = "TimeTagger";
icon = "timetagger.png";
description = "Time tracker";
};
volumes = [
"/tank/config/timetagger:/data"
];
environment = {
TIMETAGGER_BIND = "0.0.0.0:80";
TIMETAGGER_DATADIR = "/data";
TIMETAGGER_LOG_LEVEL = "debug";
TIMETAGGER_PROXY_AUTH_ENABLED = "True";
TIMETAGGER_PROXY_AUTH_TRUSTED = "10.88.0.0/16";
TIMETAGGER_PROXY_AUTH_HEADER = "X-Remote-User";
};
};
}

View File

@@ -5,7 +5,36 @@ let
name = "traefik-config";
path = ./traefik;
};
in {
in
{
sops.secrets = {
"traefik/oauth2-client-secret" = {
restartUnits = [ "podman-traefik.service" ];
mode = "0400";
};
};
sops.templates."traefik/oauth2-config.yaml".content = ''
experimental:
plugins:
traefik-oidc-auth:
moduleName: "github.com/sevensolutions/traefik-oidc-auth"
version: "v0.11.0"
http:
middlewares:
oidc-auth:
plugin:
traefik-oidc-auth:
Provider:
Url: "https://auth.blazestar.net/"
ClientId: "3e3f7d9a-a684-4412-866c-ea7281954a9f"
ClientSecret: "${config.sops.placeholder."traefik/oauth2-client-secret"}"
TokenValidation: "IdToken"
Scopes: ["openid", "profile", "email"]
'';
virtualisation.oci-containers.containers.traefik = mkContainer {
image = "traefik";
hostName = "proxy";
@@ -16,10 +45,15 @@ in {
"80:80"
"443:443"
];
volumes =
[
volumes = [
"/var/run/podman/podman.sock:/var/run/docker.sock:ro"
# All the configs from the config directory
"${traefikConfigDir}:/etc/traefik"
# Oauth2 config containing secrets
"${config.sops.templates."traefik/oauth2-config.yaml".path}:/etc/traefik/dynamic/oauth2-config.yaml"
# Persistent storage for acme certificates
# TODO: It may be possible to just use docker storage because persistence
# is not critical when the cert can just be renewed.
"/tank/config/traefik/acme:/etc/traefik/acme"
];
homepageOpts = {
@@ -29,4 +63,4 @@ in {
description = "Reverse Proxy";
};
};
}
}

View File

@@ -21,7 +21,7 @@ providers:
docker:
exposedByDefault: false
file:
directory: /etc/traefik/static
directory: /etc/traefik/dynamic
watch: true
certificatesResolvers: