authentik yay
This commit is contained in:
parent
d3a93fd115
commit
f2fcbfb679
34 changed files with 612 additions and 363 deletions
|
|
@ -19,7 +19,7 @@ let
|
|||
};
|
||||
groups = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
meta_description = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
|
|
@ -47,7 +47,13 @@ let
|
|||
modules = [
|
||||
./authentik/provider.nix
|
||||
{
|
||||
inherit (cfg) oauthApps ldapApps proxyApps;
|
||||
inherit (cfg)
|
||||
oauthApps
|
||||
ldapApps
|
||||
proxyApps
|
||||
url
|
||||
insecure
|
||||
;
|
||||
stateFile = "${terrraformStateDir}/state.tfstate";
|
||||
}
|
||||
];
|
||||
|
|
@ -89,6 +95,18 @@ in
|
|||
})
|
||||
);
|
||||
};
|
||||
options.xyno.services.authentik.url = mkOption {
|
||||
type = types.str;
|
||||
default = "https://auth.hailsatan.eu";
|
||||
};
|
||||
options.xyno.services.authentik.insecure = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
options.xyno.services.authentik.after = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.etc."authentik-config/config.tf.json".source = terranixConfig;
|
||||
xyno.impermanence.directories = [
|
||||
|
|
@ -98,13 +116,20 @@ in
|
|||
enable = true;
|
||||
createDatabase = true;
|
||||
environmentFile = config.sops.secrets."authentik/env".path;
|
||||
settings = {
|
||||
disable_startup_analytics = true;
|
||||
};
|
||||
};
|
||||
systemd.services.authentik.after = cfg.after;
|
||||
systemd.services.authentik-ldap.after = [ "authentik-config.service" ];
|
||||
systemd.services.authentik-ldap.environment.AUTHENTIK_LISTEN__METRICS = "[::1]:9302";
|
||||
services.authentik-ldap = {
|
||||
environmentFile = "${environmentFileDir}/ldap_config";
|
||||
enable = true;
|
||||
};
|
||||
systemd.services.authentik-proxy.after = [ "authentik-config.service" ];
|
||||
systemd.services.authentik-proxy.environment.AUTHENTIK_LISTEN__HTTP = "[::1]:9001";
|
||||
systemd.services.authentik-proxy.environment.AUTHENTIK_LISTEN__METRICS = "[::1]:9301";
|
||||
services.authentik-proxy = {
|
||||
enable = true;
|
||||
environmentFile = "${environmentFileDir}/proxy_config";
|
||||
|
|
@ -112,49 +137,80 @@ in
|
|||
|
||||
systemd.services.authentik-config = {
|
||||
after = [ "authentik.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
before = [
|
||||
"authentik-ldap.service"
|
||||
"authentik-proxy.service"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
StateDirectory = terrraformStateDir;
|
||||
EnvironmentFile = [ config.services.authentik.environmentFile ];
|
||||
Restart = "on-failure";
|
||||
RestartSec = 30;
|
||||
StateDirectory = "authentik-config";
|
||||
};
|
||||
script = ''
|
||||
umask u=rw,go=
|
||||
export PATH=$PATH:${pkgs.opentofu}/bin
|
||||
cd terrraformStateDir
|
||||
cp ${terranixConfig} ./main.tf.json
|
||||
source ${config.services.authentik.environmentFile}
|
||||
export AUTHENTIK_URL=http://localhost:9000
|
||||
export AUTHENTIK_TOKEN=$AUTHENTIK_BOOTSTRAP_TOKEN
|
||||
script =
|
||||
let
|
||||
opentofu = pkgs.opentofu.withPlugins (p: [
|
||||
inputs.authentik.packages.${pkgs.system}.terraform-provider-authentik
|
||||
]);
|
||||
in
|
||||
''
|
||||
set -xeuo pipefail
|
||||
umask u=rw,go=
|
||||
export PATH=$PATH:${opentofu}/bin:${pkgs.curl}/bin
|
||||
cd $STATE_DIRECTORY
|
||||
cp ${terranixConfig} ./main.tf.json
|
||||
export AUTHENTIK_URL=${cfg.url}
|
||||
export AUTHENTIK_INSECURE=${toString cfg.insecure}
|
||||
export AUTHENTIK_TOKEN=$AUTHENTIK_BOOTSTRAP_TOKEN
|
||||
|
||||
tofu init
|
||||
tofu validate || exit 1
|
||||
tofu apply
|
||||
tofu init
|
||||
tofu validate || exit 1
|
||||
|
||||
tofu output -raw proxy_config > ${environmentFileDir}/proxy_config
|
||||
tofu output -raw ldap_config > ${environmentFileDir}/ldap_config
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "tofu output -raw ${n}_environment > ${v.environmentFile}") cfg.oauthApps
|
||||
)}
|
||||
'';
|
||||
while [[ "$(curl -L -s -o /dev/null -I -w "%{http_code}" ''${AUTHENTIK_URL}/api/v3/flows/instances/)" =~ (502|000) ]]; do
|
||||
echo "[+] Authentik still starting, sleeping for 2s"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
tofu apply -auto-approve
|
||||
|
||||
tofu show -state
|
||||
|
||||
mkdir ${environmentFileDir}
|
||||
tofu output -show-sensitive -raw proxy_config > ${environmentFileDir}/proxy_config
|
||||
cat ${environmentFileDir}/proxy_config
|
||||
tofu output -show-sensitive -raw ldap_config > ${environmentFileDir}/ldap_config
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (
|
||||
n: v: "tofu output -show-sensitive -raw ${n}_environment > ${v.environmentFile}"
|
||||
) cfg.oauthApps
|
||||
)}
|
||||
'';
|
||||
|
||||
};
|
||||
sops.secrets."authentik/env" = {
|
||||
|
||||
sopsFile = ../../instances/${config.networking.hostName}/secrets/authentik.yaml;
|
||||
};
|
||||
|
||||
services.caddy.extraConfig = ''
|
||||
(reverse_proxy_auth) {
|
||||
route {
|
||||
# always forward outpost path to actual outpost
|
||||
reverse_proxy /outpost.goauthentik.io/* http://[::1]:9000 {
|
||||
reverse_proxy /outpost.goauthentik.io/* http://[::1]:9001 {
|
||||
}
|
||||
forward_auth http://[::1]:9000 {
|
||||
forward_auth http://[::1]:9001 {
|
||||
uri /outpost.goauthentik.io/auth/caddy
|
||||
copy_headers X-Authentik-Username X-Copyparty-Group X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version X-Grafana-Role
|
||||
}
|
||||
reverse_proxy {args[:]}
|
||||
}
|
||||
'';
|
||||
xyno.services.monitoring.exporters.authentik = 9300;
|
||||
xyno.services.monitoring.exporters.authentik-proxy = 9301;
|
||||
xyno.services.monitoring.exporters.authentik-ldap = 9302;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
2
modules/services/authentik/fakesops.yaml
Normal file
2
modules/services/authentik/fakesops.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
authentik:
|
||||
env: meow
|
||||
|
|
@ -6,6 +6,7 @@ let
|
|||
|
||||
authorizationFlow = tfRef "data.authentik_flow.default-authorization-flow.id";
|
||||
authenticationFlow = tfRef "data.authentik_flow.default-authentication-flow.id";
|
||||
invalidationFlow = tfRef "data.authentik_flow.default-provider-invalidation-flow.id";
|
||||
genApp = provider: n: v: {
|
||||
protocol_provider = provider;
|
||||
slug = n;
|
||||
|
|
@ -25,29 +26,34 @@ in
|
|||
oauthApps = mkOption { type = types.attrs; };
|
||||
proxyApps = mkOption { type = types.attrs; };
|
||||
ldapApps = mkOption { type = types.attrs; };
|
||||
url = mkOption { type = types.str; };
|
||||
insecure = mkOption { type = types.bool; };
|
||||
|
||||
};
|
||||
config = {
|
||||
terraform.backend.local.path = config.stateFile;
|
||||
provider.authentik = { };
|
||||
terraform.required_providers.authentik.source = "goauthentik/authentik";
|
||||
data.authentik_flow."default-authorization-flow" = {
|
||||
slug = "default-provider-authorization-implicit-consent";
|
||||
};
|
||||
data."authentik_flow"."default-authentication-flow" = {
|
||||
slug = "default-authentication-flow";
|
||||
};
|
||||
data."authentik_flow"."default-provider-invalidation-flow" = {
|
||||
slug = "default-provider-invalidation-flow";
|
||||
};
|
||||
resource.authentik_outpost.proxy = {
|
||||
name = "proxy";
|
||||
type = "proxy";
|
||||
protocol_providers = mapAttrsToList (
|
||||
n: v: (tfRef "authentik_provider_proxy.${n}.id")
|
||||
n: v: (tfRef "resource.authentik_provider_proxy.${n}.id")
|
||||
) config.proxyApps;
|
||||
};
|
||||
resource.authentik_outpost.ldap = {
|
||||
name = "ldap";
|
||||
type = "ldap";
|
||||
protocol_providers = mapAttrsToList (
|
||||
n: v: (tfRef "authentik_provider_ldap.${n}.id")
|
||||
n: v: (tfRef "resource.authentik_provider_ldap.${n}.id")
|
||||
) config.ldapApps;
|
||||
};
|
||||
|
||||
|
|
@ -55,6 +61,7 @@ in
|
|||
name = n;
|
||||
client_id = n;
|
||||
authorization_flow = authorizationFlow;
|
||||
invalidation_flow = invalidationFlow;
|
||||
}) config.oauthApps;
|
||||
data.authentik_provider_oauth2_config = mapAttrs (n: v: {
|
||||
provider_id = tfRef "resource.authentik_provider_oauth2.${n}.id";
|
||||
|
|
@ -62,19 +69,23 @@ in
|
|||
|
||||
resource.authentik_provider_proxy = mapAttrs (n: v: {
|
||||
name = n;
|
||||
mode = "forward-single";
|
||||
mode = "forward_single";
|
||||
external_host = v.externalHost;
|
||||
authorization_flow = authorizationFlow;
|
||||
invalidation_flow = invalidationFlow;
|
||||
}) config.proxyApps;
|
||||
resource.authentik_provider_ldap = mapAttrs (n: v: {
|
||||
name = n;
|
||||
base_dn = "dc=ldap,dc=goauthentik,dc=io";
|
||||
bind_flow = authenticationFlow;
|
||||
unbind_flow = invalidationFlow;
|
||||
}) config.ldapApps;
|
||||
|
||||
output =
|
||||
(mapAttrs' (
|
||||
n: v:
|
||||
nameValuePair ("${n}_environment") ({
|
||||
sensitive = true;
|
||||
value =
|
||||
let
|
||||
val = val: tfRef "resource.authentik_provider_oauth2.${n}.${val}";
|
||||
|
|
@ -90,10 +101,39 @@ in
|
|||
})
|
||||
) config.oauthApps)
|
||||
// {
|
||||
proxy_config.value = tfRef "resource.authentik_outpost.proxy.config";
|
||||
ldap_config.value = tfRef "resource.authentik_outpost.ldap.config";
|
||||
proxy_config.sensitive = true;
|
||||
proxy_config.value = ''
|
||||
AUTHENTIK_HOST=http://localhost:9000
|
||||
AUTHENTIK_HOST_BROWSER=${config.url}
|
||||
AUTHENTIK_TOKEN=${tfRef "resource.authentik_token.proxy_outpost.key"}
|
||||
'';
|
||||
ldap_config.sensitive = true;
|
||||
ldap_config.value = ''
|
||||
AUTHENTIK_HOST=http://localhost:9000
|
||||
AUTHENTIK_HOST_BROWSER=${config.url}
|
||||
AUTHENTIK_TOKEN=${tfRef "resource.authentik_token.ldap_outpost.key"}
|
||||
'';
|
||||
};
|
||||
|
||||
data.authentik_user."proxy" = {
|
||||
username = "ak-outpost-${tfRef ''replace(resource.authentik_outpost.proxy.id,"-","")''}";
|
||||
};
|
||||
data.authentik_user."ldap" = {
|
||||
username = "ak-outpost-${tfRef ''replace(resource.authentik_outpost.ldap.id,"-","")''}";
|
||||
};
|
||||
resource.authentik_token."proxy_outpost" = {
|
||||
identifier = "proxy-outpost-token";
|
||||
user = tfRef "data.authentik_user.proxy.id";
|
||||
expiring = false;
|
||||
retrieve_key = true;
|
||||
};
|
||||
resource.authentik_token."ldap_outpost" = {
|
||||
identifier = "ldap-outpost-token";
|
||||
user = tfRef "data.authentik_user.ldap.id";
|
||||
expiring = false;
|
||||
retrieve_key = true;
|
||||
};
|
||||
|
||||
resource.authentik_application = mkMerge [
|
||||
(mapAttrs (n: v: genApp (tfRef "authentik_provider_oauth2.${n}.id") n v) config.oauthApps)
|
||||
(mapAttrs (n: v: genApp (tfRef "authentik_provider_proxy.${n}.id") n v) config.proxyApps)
|
||||
|
|
@ -122,7 +162,7 @@ in
|
|||
let
|
||||
genEnts =
|
||||
apps:
|
||||
lib.flatten (
|
||||
flatten (
|
||||
mapAttrsToList (
|
||||
n: v:
|
||||
(map (g: {
|
||||
|
|
@ -135,10 +175,6 @@ in
|
|||
) apps
|
||||
);
|
||||
in
|
||||
mkMerge [
|
||||
(genEnts config.oauthApps)
|
||||
(genEnts config.proxyApps)
|
||||
(genEnts config.ldapApps)
|
||||
];
|
||||
mkMerge ((genEnts config.oauthApps) ++ (genEnts config.proxyApps) ++ (genEnts config.ldapApps));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
30
modules/services/authentik/test.nix
Normal file
30
modules/services/authentik/test.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
name = "authentik";
|
||||
nodes.machine = {lib, config, pkgs, ...}: {
|
||||
virtualisation = {
|
||||
cores = 3;
|
||||
memorySize = 2048;
|
||||
};
|
||||
xyno.services.authentik = {
|
||||
enable = true;
|
||||
url = "http://[::1]:9000";
|
||||
oauthApps."app1".name = "app1-name";
|
||||
ldapApps."app2".name = "app2-name";
|
||||
proxyApps."app3".name = "app3-name";
|
||||
proxyApps."app3".externalHost = "https://test.example.org";
|
||||
};
|
||||
services.authentik.environmentFile = lib.mkForce "/etc/authentik-env";
|
||||
sops.defaultSopsFile = ../../../secrets/common.yaml;
|
||||
environment.etc."authentik-env".text = ''
|
||||
AUTHENTIK_SECRET_KEY=db6363ba033b111c6835489c5c0aca5ec192c20ee1ea3116a601065c3b118c3d
|
||||
AUTHENTIK_BOOTSTRAP_TOKEN=75c041b7e79aac71ff0a74f7905c9f818ab2f0d21d8618fa5fd753f9e57a02f8
|
||||
'';
|
||||
sops.secrets."authentik/env" = lib.mkForce { sopsFile = ../../../instances/ds9/secrets/authentik.yaml; };
|
||||
};
|
||||
testScript = ''
|
||||
machine.wait_for_unit("authentik-config.service")
|
||||
print(machine.succeed("cat /run/authentik-terraform-config/app1_environment"))
|
||||
machine.wait_for_unit("authentik-proxy.service")
|
||||
machine.wait_for_unit("authentik-ldap.service")
|
||||
'';
|
||||
}
|
||||
|
|
@ -57,16 +57,22 @@ in
|
|||
type = str;
|
||||
default = "";
|
||||
};
|
||||
hosts = attrsOf (submodule {
|
||||
options = {
|
||||
extraConfig = mkOption { type = lines; };
|
||||
};
|
||||
});
|
||||
hosts = mkOption {
|
||||
default = {};
|
||||
type = attrsOf (submodule {
|
||||
options = {
|
||||
extraConfig = mkOption { type = lines; };
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80
|
||||
443
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [ 443 ];
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
|
|
@ -78,7 +84,6 @@ in
|
|||
metrics {
|
||||
per_host
|
||||
}
|
||||
admin ${config.xyno.monitoring.ip}:2019
|
||||
'';
|
||||
extraConfig = ''
|
||||
(blockBots) {
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ let
|
|||
(lib.optional (c?publicHostname) {
|
||||
# if peer is publicly on the internet
|
||||
AllowedIPs =
|
||||
(lib.optionals (c.wg.server) [
|
||||
(lib.optionals ( c?wg.server && c.wg.server) [
|
||||
"${ulaPrefix}::/48" # all traffic in the ula shall be sent to the server
|
||||
])
|
||||
++ (lib.optionals (!c.wg.server) [
|
||||
++ (lib.optionals (!c?wg.server || !c.wg.server) [
|
||||
"${genUlaForHost ulaPrefix c.hostName}/128" # if a host is reachable but shouldn't play server, send only to the hosts ip
|
||||
]);
|
||||
Endpoint = "${c.publicHostname}:51820";
|
||||
|
|
@ -90,9 +90,15 @@ in
|
|||
name = (genUlaForHost monitoringUlaPrefix v.hostName);
|
||||
}
|
||||
) instanceConfigs);
|
||||
networking.firewall.allowedUDPPorts = lib.optional wgServer [ 51820 ];
|
||||
networking.firewall.interfaces."wg0".allowedUDPPorts = lib.optional wgServer [ 53 ];
|
||||
networking.firewall.allowedUDPPorts = lib.optional wgServer 51820;
|
||||
networking.firewall.interfaces."wg0".allowedUDPPorts = lib.optional wgServer 53;
|
||||
systemd.network.netdevs."wg0" = {
|
||||
netdevConfig = {
|
||||
Name = "wg0";
|
||||
Kind = "wireguard";
|
||||
Description = "main wireguard tunnel";
|
||||
|
||||
};
|
||||
wireguardConfig = {
|
||||
ListenPort = lib.mkIf wgServer 51820;
|
||||
PrivateKeyFile = config.sops.secrets."wg/privkey".path; # TODO
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue