checkpoint
This commit is contained in:
parent
d60d4badf3
commit
5c1e6807b6
2 changed files with 451 additions and 11 deletions
141
clan.nix
141
clan.nix
|
|
@ -141,6 +141,16 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
persistence = {
|
||||||
|
module = {
|
||||||
|
name = "persistence";
|
||||||
|
input = "self";
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO :: Convert to use tags instead
|
||||||
|
roles.default.tags = ["operational:availability:always-on" "operational:storage:large"];
|
||||||
|
};
|
||||||
|
|
||||||
identity = {
|
identity = {
|
||||||
module = {
|
module = {
|
||||||
name = "identity";
|
name = "identity";
|
||||||
|
|
@ -151,18 +161,137 @@
|
||||||
tags = ["operational:availability:always-on"];
|
tags = ["operational:availability:always-on"];
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
persistence_instance = "persistence";
|
||||||
|
|
||||||
|
organization = {
|
||||||
|
nix = {
|
||||||
|
user = {
|
||||||
|
chris = {
|
||||||
|
email = "chris@kruining.eu";
|
||||||
|
firstName = "Chris";
|
||||||
|
lastName = "Kruining";
|
||||||
|
|
||||||
|
roles = ["ORG_OWNER"];
|
||||||
|
instanceRoles = ["IAM_OWNER"];
|
||||||
|
};
|
||||||
|
|
||||||
|
kaas = {
|
||||||
|
email = "chris+kaas@kruining.eu";
|
||||||
|
firstName = "Kaas";
|
||||||
|
lastName = "Kruining";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
project = {
|
||||||
|
ulmo = {
|
||||||
|
projectRoleCheck = true;
|
||||||
|
projectRoleAssertion = true;
|
||||||
|
hasProjectCheck = true;
|
||||||
|
|
||||||
|
role = {
|
||||||
|
jellyfin = {
|
||||||
|
group = "jellyfin";
|
||||||
|
};
|
||||||
|
jellyfin_admin = {
|
||||||
|
group = "jellyfin";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
assign = {
|
||||||
|
chris = ["jellyfin" "jellyfin_admin"];
|
||||||
|
kaas = ["jellyfin"];
|
||||||
|
};
|
||||||
|
|
||||||
|
application = {
|
||||||
|
jellyfin = {
|
||||||
|
redirectUris = ["https://jellyfin.kruining.eu/sso/OID/redirect/zitadel"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
};
|
||||||
|
|
||||||
|
forgejo = {
|
||||||
|
redirectUris = ["https://git.amarth.cloud/user/oauth2/zitadel/callback"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
};
|
||||||
|
|
||||||
|
vaultwarden = {
|
||||||
|
redirectUris = ["https://vault.kruining.eu/identity/connect/oidc-signin"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
exportMap = {
|
||||||
|
client_id = "SSO_CLIENT_ID";
|
||||||
|
client_secret = "SSO_CLIENT_SECRET";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
matrix = {
|
||||||
|
redirectUris = ["https://matrix.kruining.eu/_synapse/client/oidc/callback"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
};
|
||||||
|
|
||||||
|
mydia = {
|
||||||
|
redirectUris = ["http://localhost:2010/auth/oidc/callback"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
};
|
||||||
|
|
||||||
|
grafana = {
|
||||||
|
redirectUris = ["http://localhost:9001/login/generic_oauth"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
persistence = {
|
convex = {
|
||||||
module = {
|
projectRoleCheck = true;
|
||||||
name = "persistence";
|
projectRoleAssertion = true;
|
||||||
input = "self";
|
hasProjectCheck = true;
|
||||||
|
|
||||||
|
application = {
|
||||||
|
scry = {
|
||||||
|
redirectUris = ["https://nautical-salamander-320.eu-west-1.convex.cloud/api/auth/callback/zitadel"];
|
||||||
|
grantTypes = ["authorizationCode"];
|
||||||
|
responseTypes = ["code"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO :: Convert to use tags instead
|
action = {
|
||||||
roles.default.tags = ["operational:availability:always-on" "operational:storage:large"];
|
flattenRoles = {
|
||||||
|
script = ''
|
||||||
|
(ctx, api) => {
|
||||||
|
if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = ctx.v1.user.grants.grants.flatMap(({ roles, projectId }) => roles.map(role => projectId + ':' + role));
|
||||||
|
|
||||||
|
api.v1.claims.setClaim('nix:zitadel:custom', JSON.stringify({ roles }));
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
triggers = [
|
||||||
|
{
|
||||||
|
flowType = "customiseToken";
|
||||||
|
triggerType = "preUserinfoCreation";
|
||||||
|
actions = ["flattenRoles"];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
flowType = "customiseToken";
|
||||||
|
triggerType = "preAccessTokenCreation";
|
||||||
|
actions = ["flattenRoles"];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
servarr = {
|
servarr = {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ in {
|
||||||
description = '''';
|
description = '''';
|
||||||
|
|
||||||
interface = {lib, ...}: let
|
interface = {lib, ...}: let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types toSentenceCase literalExpression;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
driver = mkOption {
|
driver = mkOption {
|
||||||
|
|
@ -30,16 +30,308 @@ in {
|
||||||
default = "zitadel";
|
default = "zitadel";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
persistence_instance = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = types.port;
|
||||||
default = 9092;
|
default = 9092;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
organization = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||||
|
options =
|
||||||
|
let
|
||||||
|
org = name;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
isDefault = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
example = "true";
|
||||||
|
description = ''
|
||||||
|
True sets the '${org}' org as default org for the instance. Only one org can be default org.
|
||||||
|
Nothing happens if you set it to false until you set another org as default org.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
project = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
hasProjectCheck = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
example = "true";
|
||||||
|
description = ''
|
||||||
|
ZITADEL checks if the org of the user has permission to this project.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
privateLabelingSetting = mkOption {
|
||||||
|
type = types.nullOr (types.enum [ "unspecified" "enforceProjectResourceOwnerPolicy" "allowLoginUserResourceOwnerPolicy" ]);
|
||||||
|
default = null;
|
||||||
|
example = "enforceProjectResourceOwnerPolicy";
|
||||||
|
description = ''
|
||||||
|
Defines from where the private labeling should be triggered,
|
||||||
|
|
||||||
|
supported values:
|
||||||
|
- unspecified
|
||||||
|
- enforceProjectResourceOwnerPolicy
|
||||||
|
- allowLoginUserResourceOwnerPolicy
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
projectRoleAssertion = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
example = "true";
|
||||||
|
description = ''
|
||||||
|
Describes if roles of user should be added in token.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
projectRoleCheck = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
example = "true";
|
||||||
|
description = ''
|
||||||
|
ZITADEL checks if the user has at least one on this project.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
role = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||||
|
options =
|
||||||
|
let
|
||||||
|
roleName = name;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
displayName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = toSentenceCase name;
|
||||||
|
example = "RoleName";
|
||||||
|
description = ''
|
||||||
|
Name used for project role.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = "some_group";
|
||||||
|
description = ''
|
||||||
|
Group used for project role.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
assign = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.listOf types.str);
|
||||||
|
};
|
||||||
|
|
||||||
|
application = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
redirectUris = mkOption {
|
||||||
|
type = types.nonEmptyListOf types.str;
|
||||||
|
example = ''
|
||||||
|
[ "https://example.com/redirect/url" ]
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
grantTypes = mkOption {
|
||||||
|
type = types.nonEmptyListOf (types.enum [ "authorizationCode" "implicit" "refreshToken" "deviceCode" "tokenExchange" ]);
|
||||||
|
example = ''
|
||||||
|
[ "authorizationCode" ]
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
responseTypes = mkOption {
|
||||||
|
type = types.nonEmptyListOf (types.enum [ "code" "idToken" "idTokenToken" ]);
|
||||||
|
example = ''
|
||||||
|
[ "code" ]
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
exportMap =
|
||||||
|
let
|
||||||
|
strOpt = mkOption { type = types.nullOr types.str; default = null; };
|
||||||
|
in
|
||||||
|
mkOption {
|
||||||
|
type = types.submodule { options = { client_id = strOpt; client_secret = strOpt; }; };
|
||||||
|
default = {};
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
client_id = "SSO_CLIENT_ID";
|
||||||
|
client_secret = "SSO_CLIENT_SECRET";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Remap the outputted variables to another key.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||||
|
options =
|
||||||
|
let
|
||||||
|
username = name;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
email = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "someone@some.domain";
|
||||||
|
description = ''
|
||||||
|
Username.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
userName = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = username;
|
||||||
|
example = "some_user_name";
|
||||||
|
description = ''
|
||||||
|
Username. Default value is the key of the config object you created, you can overwrite that by setting this option
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firstName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "John";
|
||||||
|
description = ''
|
||||||
|
First name of the user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
lastName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "Doe";
|
||||||
|
description = ''
|
||||||
|
Last name of the user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
roles = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = "[ \"ORG_OWNER\" ]";
|
||||||
|
description = ''
|
||||||
|
List of roles granted to organisation.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
instanceRoles = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = "[ \"IAM_OWNER\" ]";
|
||||||
|
description = ''
|
||||||
|
List of roles granted to instance.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
action = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||||
|
options = {
|
||||||
|
script = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = ''
|
||||||
|
(ctx, api) => {
|
||||||
|
api.v1.claims.setClaim('some_claim', 'some_value');
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
The script to run. This must be a function that receives 2 parameters, and returns void. During the creation of the action's script this module simly does `const {{name}} = {{script}}`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
timeout = mkOption {
|
||||||
|
type = (types.ints.between 0 20);
|
||||||
|
default = 10;
|
||||||
|
example = "10";
|
||||||
|
description = ''
|
||||||
|
After which time the action will be terminated if not finished.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
allowedToFail = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
example = "true";
|
||||||
|
description = ''
|
||||||
|
Allowed to fail.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
triggers = mkOption {
|
||||||
|
default = [];
|
||||||
|
type = types.listOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
flowType = mkOption {
|
||||||
|
type = types.enum [ "authentication" "customiseToken" "internalAuthentication" "samlResponse" ];
|
||||||
|
example = "customiseToken";
|
||||||
|
description = ''
|
||||||
|
Type of the flow to which the action triggers belong.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
triggerType = mkOption {
|
||||||
|
type = types.enum [ "postAuthentication" "preCreation" "postCreation" "preUserinfoCreation" "preAccessTokenCreation" "preSamlResponse" ];
|
||||||
|
example = "postAuthentication";
|
||||||
|
description = ''
|
||||||
|
Trigger type on when the actions get triggered.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
actions = mkOption {
|
||||||
|
type = types.nonEmptyListOf types.str;
|
||||||
|
example = ''[ "action_name" ]'';
|
||||||
|
description = ''
|
||||||
|
Names of actions to trigger
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
perInstance = {
|
perInstance = {
|
||||||
mkExports,
|
mkExports,
|
||||||
settings,
|
settings,
|
||||||
|
machine,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
database =
|
database =
|
||||||
|
|
@ -117,6 +409,19 @@ in {
|
||||||
settings = {
|
settings = {
|
||||||
Port = settings.port;
|
Port = settings.port;
|
||||||
|
|
||||||
|
ExternalDomain = "auth.kruining.eu";
|
||||||
|
ExternalPort = 443;
|
||||||
|
ExternalSecure = true;
|
||||||
|
|
||||||
|
Metrics.Type = "otel";
|
||||||
|
Tracing.Type = "otel";
|
||||||
|
Telemetry.Enabled = true;
|
||||||
|
|
||||||
|
SystemDefaults = {
|
||||||
|
PasswordHasher.Hasher.Algorithm = "argon2id";
|
||||||
|
SecretHasher.Hasher.Algorithm = "argon2id";
|
||||||
|
};
|
||||||
|
|
||||||
Database.postgres = {
|
Database.postgres = {
|
||||||
Host = database.host;
|
Host = database.host;
|
||||||
Port = database.port;
|
Port = database.port;
|
||||||
|
|
@ -129,6 +434,12 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
steps = {
|
||||||
|
InstanceName = "eu";
|
||||||
|
|
||||||
|
MachineKeyPath = "/var/lib/zitadel/machine-key.json";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue