checkpoint
This commit is contained in:
parent
d60d4badf3
commit
5c1e6807b6
2 changed files with 451 additions and 11 deletions
149
clan.nix
149
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 = {
|
||||
module = {
|
||||
name = "identity";
|
||||
|
|
@ -151,20 +161,139 @@
|
|||
tags = ["operational:availability:always-on"];
|
||||
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
convex = {
|
||||
projectRoleCheck = true;
|
||||
projectRoleAssertion = true;
|
||||
hasProjectCheck = true;
|
||||
|
||||
application = {
|
||||
scry = {
|
||||
redirectUris = ["https://nautical-salamander-320.eu-west-1.convex.cloud/api/auth/callback/zitadel"];
|
||||
grantTypes = ["authorizationCode"];
|
||||
responseTypes = ["code"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
action = {
|
||||
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"];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
persistence = {
|
||||
module = {
|
||||
name = "persistence";
|
||||
input = "self";
|
||||
};
|
||||
|
||||
# TODO :: Convert to use tags instead
|
||||
roles.default.tags = ["operational:availability:always-on" "operational:storage:large"];
|
||||
};
|
||||
|
||||
servarr = {
|
||||
module = {
|
||||
name = "servarr";
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ in {
|
|||
description = '''';
|
||||
|
||||
interface = {lib, ...}: let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (lib) mkOption types toSentenceCase literalExpression;
|
||||
in {
|
||||
options = {
|
||||
driver = mkOption {
|
||||
|
|
@ -30,16 +30,308 @@ in {
|
|||
default = "zitadel";
|
||||
};
|
||||
|
||||
persistence_instance = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
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 = {
|
||||
mkExports,
|
||||
settings,
|
||||
machine,
|
||||
...
|
||||
}: let
|
||||
database =
|
||||
|
|
@ -117,6 +409,19 @@ in {
|
|||
settings = {
|
||||
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 = {
|
||||
Host = database.host;
|
||||
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