mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-11 07:10:39 +02:00
chore: remove firezone again (waiting for upstream PR)
This commit is contained in:
parent
a3f74254e7
commit
2406dddd8e
21 changed files with 0 additions and 4208 deletions
|
@ -43,6 +43,5 @@
|
||||||
unifi = uidGid 968;
|
unifi = uidGid 968;
|
||||||
plugdev.gid = 967;
|
plugdev.gid = 967;
|
||||||
tss = uidGid 966;
|
tss = uidGid 966;
|
||||||
firezone-client = uidGid 965;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
globals,
|
|
||||||
inputs,
|
inputs,
|
||||||
lib,
|
lib,
|
||||||
minimal,
|
minimal,
|
||||||
|
@ -89,28 +88,6 @@
|
||||||
# };
|
# };
|
||||||
#};
|
#};
|
||||||
|
|
||||||
# FIXME: the ui is not directly accessible via environment.systemPackages
|
|
||||||
# FIXME: to control it as a user (and to allow SSO) we need to be in the netbird-home group
|
|
||||||
services.netbird.ui.enable = true;
|
|
||||||
services.netbird.clients.home = {
|
|
||||||
port = 51820;
|
|
||||||
name = "netbird-home";
|
|
||||||
interface = "wt-home";
|
|
||||||
autoStart = false;
|
|
||||||
openFirewall = true;
|
|
||||||
config.ServerSSHAllowed = false;
|
|
||||||
environment = rec {
|
|
||||||
NB_MANAGEMENT_URL = "https://${globals.services.netbird.domain}";
|
|
||||||
NB_ADMIN_URL = NB_MANAGEMENT_URL;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
environment.persistence."/persist".directories = [
|
|
||||||
{
|
|
||||||
directory = "/var/lib/netbird-home";
|
|
||||||
mode = "0700";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.nix-ld.enable = true;
|
programs.nix-ld.enable = true;
|
||||||
topology.self.icon = "devices.desktop";
|
topology.self.icon = "devices.desktop";
|
||||||
|
|
||||||
|
@ -122,9 +99,4 @@
|
||||||
dockerCompat = true;
|
dockerCompat = true;
|
||||||
defaultNetwork.settings.dns_enabled = true;
|
defaultNetwork.settings.dns_enabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.firezone.server.domain.enable = true;
|
|
||||||
services.firezone.server.domain.enableLocalDB = true;
|
|
||||||
services.firezone.server.web.enable = true;
|
|
||||||
services.firezone.server.api.enable = true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
./backups.nix
|
./backups.nix
|
||||||
./deterministic-ids.nix
|
./deterministic-ids.nix
|
||||||
./distributed-config.nix
|
./distributed-config.nix
|
||||||
./firezone-relay.nix
|
|
||||||
./firezone-gateways.nix
|
|
||||||
./firezone-server.nix
|
|
||||||
./globals.nix
|
./globals.nix
|
||||||
./meta.nix
|
./meta.nix
|
||||||
./netbird-client.nix
|
./netbird-client.nix
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib)
|
|
||||||
boolToString
|
|
||||||
concatMapAttrs
|
|
||||||
flip
|
|
||||||
getExe
|
|
||||||
mkEnableOption
|
|
||||||
mkOption
|
|
||||||
mkPackageOption
|
|
||||||
types
|
|
||||||
;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
services.firezone.gateways = mkOption {
|
|
||||||
description = ''
|
|
||||||
A set of gateway clients to deploy on this machine. Each gateway can
|
|
||||||
connect to exactly one firezone server.
|
|
||||||
'';
|
|
||||||
default = { };
|
|
||||||
type = types.attrsOf (
|
|
||||||
types.submodule (gatewaysSubmod: {
|
|
||||||
options = {
|
|
||||||
package = mkPackageOption pkgs "firezone-gateway" { };
|
|
||||||
|
|
||||||
name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = gatewaysSubmod.config._module.args.name;
|
|
||||||
description = "The name of this gateway as shown in firezone";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.strMatching "^[a-zA-Z0-9_-]{1,32}$";
|
|
||||||
default = "firezone-gw-${gatewaysSubmod.config._module.args.name}";
|
|
||||||
description = "The DynamicUser name under which the gateway will run. Cannot exceed 32 characters.";
|
|
||||||
};
|
|
||||||
|
|
||||||
interface = mkOption {
|
|
||||||
type = types.strMatching "^[a-zA-Z0-9_-]{1,15}$";
|
|
||||||
default = "tun-${gatewaysSubmod.config._module.args.name}";
|
|
||||||
description = "The name of the TUN interface which will be created by this gateway";
|
|
||||||
};
|
|
||||||
|
|
||||||
apiUrl = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "wss://firezone.example.com/api";
|
|
||||||
description = ''
|
|
||||||
The URL of your firezone server's API. This should be the same
|
|
||||||
as your server's setting for {option}`services.firezone.server.settings.api.externalUrl`,
|
|
||||||
but with `wss://` instead of `https://`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
tokenFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
example = "/run/secrets/firezone-gateway-token";
|
|
||||||
description = ''
|
|
||||||
A file containing the firezone gateway token. Do not use a nix-store path here
|
|
||||||
as it will make the token publicly readable!
|
|
||||||
|
|
||||||
This file will be passed via systemd credentials, it should only be accessible
|
|
||||||
by the root user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
logLevel = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "info";
|
|
||||||
description = ''
|
|
||||||
The log level for the firezone application. See
|
|
||||||
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
|
|
||||||
for the format.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
enableTelemetry = mkEnableOption "telemetry";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
systemd.services = flip concatMapAttrs config.services.firezone.gateways (
|
|
||||||
gatewayName: gatewayCfg: {
|
|
||||||
"firezone-gateway-${gatewayName}" = {
|
|
||||||
description = "Gateway service for the Firezone zero-trust access platform";
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
path = [ pkgs.util-linux ];
|
|
||||||
script = ''
|
|
||||||
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
|
|
||||||
if [[ -z "''${FIREZONE_ID:-}" ]]; then
|
|
||||||
if [[ ! -e gateway_id ]]; then
|
|
||||||
uuidgen -r > gateway_id
|
|
||||||
fi
|
|
||||||
export FIREZONE_ID=$(< gateway_id)
|
|
||||||
fi
|
|
||||||
|
|
||||||
export FIREZONE_TOKEN=$(< "$CREDENTIALS_DIRECTORY/firezone-token")
|
|
||||||
exec ${getExe gatewayCfg.package}
|
|
||||||
'';
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
FIREZONE_API_URL = gatewayCfg.apiUrl;
|
|
||||||
FIREZONE_NAME = gatewayCfg.name;
|
|
||||||
FIREZONE_NO_TELEMETRY = boolToString gatewayCfg.enableTelemetry;
|
|
||||||
FIREZONE_TUN_INTERFACE = gatewayCfg.interface;
|
|
||||||
RUST_LOG = gatewayCfg.logLevel;
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateUsers = false;
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = "@system-service";
|
|
||||||
UMask = "077";
|
|
||||||
|
|
||||||
Type = "exec";
|
|
||||||
DynamicUser = true;
|
|
||||||
User = gatewayCfg.user;
|
|
||||||
LoadCredential = [ "firezone-token:${gatewayCfg.tokenFile}" ];
|
|
||||||
|
|
||||||
DeviceAllow = "/dev/net/tun";
|
|
||||||
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
|
||||||
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
|
||||||
|
|
||||||
StateDirectory = "firezone-gateways/${gatewayName}";
|
|
||||||
WorkingDirectory = "/var/lib/firezone-gateways/${gatewayName}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
meta.maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib)
|
|
||||||
boolToString
|
|
||||||
getExe
|
|
||||||
mkEnableOption
|
|
||||||
mkIf
|
|
||||||
mkOption
|
|
||||||
mkPackageOption
|
|
||||||
types
|
|
||||||
;
|
|
||||||
|
|
||||||
cfg = config.services.firezone.relay;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
services.firezone.relay = {
|
|
||||||
enable = mkEnableOption "the firezone relay server";
|
|
||||||
package = mkPackageOption pkgs "firezone-relay" { };
|
|
||||||
|
|
||||||
publicIpv4 = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The public ipv4 address of this relay";
|
|
||||||
};
|
|
||||||
|
|
||||||
publicIpv6 = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The public ipv6 address of this relay";
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Opens up the main STUN port and the TURN allocation range.";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 3478;
|
|
||||||
description = "The port to listen on for STUN messages";
|
|
||||||
};
|
|
||||||
|
|
||||||
lowestPort = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 49152;
|
|
||||||
description = "The lowest port to use in TURN allocation";
|
|
||||||
};
|
|
||||||
|
|
||||||
highestPort = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 65535;
|
|
||||||
description = "The highest port to use in TURN allocation";
|
|
||||||
};
|
|
||||||
|
|
||||||
apiUrl = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "wss://firezone.example.com/api";
|
|
||||||
description = ''
|
|
||||||
The URL of your firezone server's API. This should be the same
|
|
||||||
as your server's setting for {option}`services.firezone.server.settings.api.externalUrl`,
|
|
||||||
but with `wss://` instead of `https://`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
tokenFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
example = "/run/secrets/firezone-relay-token";
|
|
||||||
description = ''
|
|
||||||
A file containing the firezone relay token. Do not use a nix-store path here
|
|
||||||
as it will make the token publicly readable!
|
|
||||||
|
|
||||||
This file will be passed via systemd credentials, it should only be accessible
|
|
||||||
by the root user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
logLevel = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "firezone_relay=info,firezone_tunnel=info,connlib_shared=info,tunnel_state=info,phoenix_channel=info,snownet=info,str0m=info,warn";
|
|
||||||
description = ''
|
|
||||||
The log level for the firezone application. See
|
|
||||||
[RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
|
|
||||||
for the format.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
enableTelemetry = mkEnableOption "telemetry";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
systemd.services."firezone-relay" = {
|
|
||||||
description = "relay service for the Firezone zero-trust access platform";
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
path = [ pkgs.util-linux ];
|
|
||||||
script = ''
|
|
||||||
# If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
|
|
||||||
if [[ -z "''${FIREZONE_ID:-}" ]]; then
|
|
||||||
if [[ ! -e relay_id ]]; then
|
|
||||||
uuidgen -r > relay_id
|
|
||||||
fi
|
|
||||||
export FIREZONE_ID=$(< relay_id)
|
|
||||||
fi
|
|
||||||
|
|
||||||
export FIREZONE_TOKEN=$(< "$CREDENTIALS_DIRECTORY/firezone-token")
|
|
||||||
exec ${getExe cfg.package}
|
|
||||||
'';
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
FIREZONE_API_URL = cfg.apiUrl;
|
|
||||||
FIREZONE_NAME = cfg.name;
|
|
||||||
FIREZONE_TELEMETRY = boolToString cfg.enableTelemetry;
|
|
||||||
|
|
||||||
PUBLIC_IPV4_ADDRESS = cfg.publicIpv4;
|
|
||||||
PUBLIC_IPV6_ADDRESS = cfg.publicIpv6;
|
|
||||||
|
|
||||||
LISTEN_PORT = toString cfg.port;
|
|
||||||
LOWEST_PORT = toString cfg.lowestPort;
|
|
||||||
HIGHEST_PORT = toString cfg.highestPort;
|
|
||||||
|
|
||||||
RUST_LOG = cfg.logLevel;
|
|
||||||
LOG_FORMAT = "human";
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateUsers = false;
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = "@system-service";
|
|
||||||
UMask = "077";
|
|
||||||
|
|
||||||
Type = "exec";
|
|
||||||
DynamicUser = true;
|
|
||||||
User = "firezone-relay";
|
|
||||||
LoadCredential = [ "firezone-token:${cfg.tokenFile}" ];
|
|
||||||
|
|
||||||
StateDirectory = "firezone-relay";
|
|
||||||
WorkingDirectory = "/var/lib/firezone-relay";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
meta.maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,948 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib)
|
|
||||||
attrNames
|
|
||||||
boolToString
|
|
||||||
concatLines
|
|
||||||
concatLists
|
|
||||||
concatMapAttrs
|
|
||||||
concatStringsSep
|
|
||||||
filterAttrs
|
|
||||||
filterAttrsRecursive
|
|
||||||
flip
|
|
||||||
forEach
|
|
||||||
getExe
|
|
||||||
isBool
|
|
||||||
mapAttrs
|
|
||||||
mapAttrsToList
|
|
||||||
mkDefault
|
|
||||||
mkEnableOption
|
|
||||||
mkIf
|
|
||||||
mkMerge
|
|
||||||
mkOption
|
|
||||||
mkPackageOption
|
|
||||||
optionalAttrs
|
|
||||||
recursiveUpdate
|
|
||||||
subtractLists
|
|
||||||
toUpper
|
|
||||||
types
|
|
||||||
;
|
|
||||||
|
|
||||||
cfg = config.services.firezone.server;
|
|
||||||
jsonFormat = pkgs.formats.json { };
|
|
||||||
availableAuthAdapters = [
|
|
||||||
"email"
|
|
||||||
"openid_connect"
|
|
||||||
"userpass"
|
|
||||||
"token"
|
|
||||||
"google_workspace"
|
|
||||||
"microsoft_entra"
|
|
||||||
"okta"
|
|
||||||
"jumpcloud"
|
|
||||||
];
|
|
||||||
|
|
||||||
# All non-secret environment variables or the given component
|
|
||||||
collectEnvironment =
|
|
||||||
component:
|
|
||||||
mapAttrs (_: v: if isBool v then boolToString v else toString v) (
|
|
||||||
cfg.settings // cfg.${component}.settings
|
|
||||||
);
|
|
||||||
|
|
||||||
# All mandatory secrets which were not explicitly provided by the user will
|
|
||||||
# have to be generated, if they do not yet exist.
|
|
||||||
generateSecrets =
|
|
||||||
let
|
|
||||||
requiredSecrets = filterAttrs (_: v: v == null) cfg.settingsSecret;
|
|
||||||
in
|
|
||||||
''
|
|
||||||
mkdir -p secrets
|
|
||||||
chmod 700 secrets
|
|
||||||
''
|
|
||||||
+ concatLines (
|
|
||||||
forEach (attrNames requiredSecrets) (secret: ''
|
|
||||||
if [[ ! -e secrets/${secret} ]]; then
|
|
||||||
echo "Generating ${secret}"
|
|
||||||
# Some secrets like TOKENS_KEY_BASE require a value >=64 bytes.
|
|
||||||
head -c 64 /dev/urandom | base64 -w 0 > secrets/${secret}
|
|
||||||
chmod 600 secrets/${secret}
|
|
||||||
fi
|
|
||||||
'')
|
|
||||||
);
|
|
||||||
|
|
||||||
# All secrets given in `cfg.settingsSecret` must be loaded from a file and
|
|
||||||
# exported into the environment. Also exclude any variables that were
|
|
||||||
# overwritten by the local component settings.
|
|
||||||
loadSecretEnvironment =
|
|
||||||
component:
|
|
||||||
let
|
|
||||||
relevantSecrets = subtractLists (attrNames cfg.${component}.settings) (
|
|
||||||
attrNames cfg.settingsSecret
|
|
||||||
);
|
|
||||||
in
|
|
||||||
concatLines (
|
|
||||||
forEach relevantSecrets (
|
|
||||||
secret:
|
|
||||||
''export ${secret}=$(< ${
|
|
||||||
if cfg.settingsSecret.${secret} == null then
|
|
||||||
"secrets/${secret}"
|
|
||||||
else
|
|
||||||
"\"$CREDENTIALS_DIRECTORY/${secret}\""
|
|
||||||
})''
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
provisionStateJson =
|
|
||||||
let
|
|
||||||
# Convert clientSecretFile options into the real counterpart
|
|
||||||
augmentedAccounts = flip mapAttrs cfg.provision.accounts (
|
|
||||||
accountName: account:
|
|
||||||
account
|
|
||||||
// {
|
|
||||||
auth = flip mapAttrs account.auth (
|
|
||||||
authName: auth:
|
|
||||||
recursiveUpdate auth (
|
|
||||||
optionalAttrs (auth.adapter_config.clientSecretFile != null) {
|
|
||||||
adapter_config.client_secret = "{env:AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}}";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
in
|
|
||||||
jsonFormat.generate "provision-state.json" {
|
|
||||||
# Do not include any clientSecretFile attributes in the resulting json
|
|
||||||
accounts = filterAttrsRecursive (k: _: k != "clientSecretFile") augmentedAccounts;
|
|
||||||
};
|
|
||||||
|
|
||||||
commonServiceConfig = {
|
|
||||||
AmbientCapablities = [ ];
|
|
||||||
CapabilityBoundingSet = [ ];
|
|
||||||
LockPersonality = true;
|
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateMounts = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateUsers = false;
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
RestrictSUIDSGID = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = "@system-service";
|
|
||||||
UMask = "077";
|
|
||||||
|
|
||||||
DynamicUser = true;
|
|
||||||
User = "firezone";
|
|
||||||
|
|
||||||
Slice = "system-firezone.slice";
|
|
||||||
StateDirectory = "firezone";
|
|
||||||
WorkingDirectory = "/var/lib/firezone";
|
|
||||||
|
|
||||||
LoadCredential = mapAttrsToList (secretName: secretFile: "${secretName}:${secretFile}") (
|
|
||||||
filterAttrs (_: v: v != null) cfg.settingsSecret
|
|
||||||
);
|
|
||||||
Type = "exec";
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentOptions = component: {
|
|
||||||
enable = mkEnableOption "the Firezone ${component} server";
|
|
||||||
package = mkPackageOption pkgs "firezone-server-${component}" { };
|
|
||||||
|
|
||||||
settings = mkOption {
|
|
||||||
description = ''
|
|
||||||
Environment variables for this component of the Firezone server. For a
|
|
||||||
list of available variables, please refer to the [upstream definitions](https://github.com/firezone/firezone/blob/main/elixir/apps/domain/lib/domain/config/definitions.ex).
|
|
||||||
Some variables like `OUTBOUND_EMAIL_ADAPTER_OPTS` require json values
|
|
||||||
for which you can use `VAR = builtins.toJSON { /* ... */ }`.
|
|
||||||
|
|
||||||
This component will automatically inherit all variables defined via
|
|
||||||
{option}`services.firezone.server.settings` and
|
|
||||||
{option}`services.firezone.server.settingsSecret`, but which can be
|
|
||||||
overwritten by this option.
|
|
||||||
'';
|
|
||||||
default = { };
|
|
||||||
type = types.submodule {
|
|
||||||
freeformType = types.attrsOf (
|
|
||||||
types.oneOf [
|
|
||||||
types.bool
|
|
||||||
types.float
|
|
||||||
types.int
|
|
||||||
types.str
|
|
||||||
types.path
|
|
||||||
types.package
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.firezone.server = {
|
|
||||||
enable = mkEnableOption "all Firezone components";
|
|
||||||
enableLocalDB = mkEnableOption "a local postgresql database for Firezone";
|
|
||||||
nginx.enable = mkEnableOption "nginx virtualhost definition";
|
|
||||||
|
|
||||||
openClusterFirewall = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Opens up the erlang distribution port of all enabled components to
|
|
||||||
allow reaching the server cluster from the internet. You only need to
|
|
||||||
set this if you are actually distributing your cluster across multiple
|
|
||||||
machines.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
clusterHosts = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [
|
|
||||||
"api@localhost.localdomain"
|
|
||||||
"web@localhost.localdomain"
|
|
||||||
"domain@localhost.localdomain"
|
|
||||||
];
|
|
||||||
description = ''
|
|
||||||
A list of components and their hosts that are part of this cluster. For
|
|
||||||
a single-machine setup, the default value will be sufficient. This
|
|
||||||
value will automatically set `ERLANG_CLUSTER_ADAPTER_CONFIG`.
|
|
||||||
|
|
||||||
The format is `<COMPONENT_NAME>@<HOSTNAME>`.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
settingsSecret = mkOption {
|
|
||||||
default = { };
|
|
||||||
description = ''
|
|
||||||
This is a convenience option which allows you to set secret values for
|
|
||||||
environment variables by specifying a file which will contain the value
|
|
||||||
at runtime. Before starting the server, the content of each file will
|
|
||||||
be loaded into the respective environment variable.
|
|
||||||
|
|
||||||
Otherwise, this option is equivalent to
|
|
||||||
{option}`services.firezone.server.settings`. Refer to the settings
|
|
||||||
option for more information regarding the actual variables and how
|
|
||||||
filtering rules are applied for each component.
|
|
||||||
'';
|
|
||||||
type = types.submodule {
|
|
||||||
freeformType = types.attrsOf types.path;
|
|
||||||
options = {
|
|
||||||
RELEASE_COOKIE = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique secret identifier for the Erlang
|
|
||||||
cluster. All Firezone components in your cluster must use the
|
|
||||||
same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
TOKENS_KEY_BASE = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`TOKENS_KEY_BASE`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
SECRET_KEY_BASE = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`SECRET_KEY_BASE`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
TOKENS_SALT = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`TOKENS_SALT`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
LIVE_VIEW_SIGNING_SALT = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`LIVE_VIEW_SIGNING_SALT`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
COOKIE_SIGNING_SALT = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`COOKIE_SIGNING_SALT`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
COOKIE_ENCRYPTION_SALT = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a unique base64 encoded secret for the
|
|
||||||
`COOKIE_ENCRYPTION_SALT`. All Firezone components in your cluster must
|
|
||||||
use the same value.
|
|
||||||
|
|
||||||
If this is `null`, a shared value will automatically be generated
|
|
||||||
on startup and used for all components on this machine. You do
|
|
||||||
not need to set this except when you spread your cluster over
|
|
||||||
multiple hosts.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = mkOption {
|
|
||||||
description = ''
|
|
||||||
Environment variables for the Firezone server. For a list of available
|
|
||||||
variables, please refer to the [upstream definitions](https://github.com/firezone/firezone/blob/main/elixir/apps/domain/lib/domain/config/definitions.ex).
|
|
||||||
Some variables like `OUTBOUND_EMAIL_ADAPTER_OPTS` require json values
|
|
||||||
for which you can use `VAR = builtins.toJSON { /* ... */ }`.
|
|
||||||
|
|
||||||
Each component has an additional `settings` option which allows you to
|
|
||||||
override specific variables passed to that component.
|
|
||||||
'';
|
|
||||||
default = { };
|
|
||||||
type = types.submodule {
|
|
||||||
freeformType = types.attrsOf (
|
|
||||||
types.oneOf [
|
|
||||||
types.bool
|
|
||||||
types.float
|
|
||||||
types.int
|
|
||||||
types.str
|
|
||||||
types.path
|
|
||||||
types.package
|
|
||||||
]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
configureManually = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Outbound email configuration is mandatory for Firezone and supports
|
|
||||||
many different delivery adapters. Yet, most users will only need an
|
|
||||||
SMTP relay to send emails, so this configuration enforced by default.
|
|
||||||
|
|
||||||
If you want to utilize an alternative way to send emails (e.g. via a
|
|
||||||
supportd API-based service), enable this option and define
|
|
||||||
`OUTBOUND_EMAIL_FROM`, `OUTBOUND_EMAIL_ADAPTER` and
|
|
||||||
`OUTBOUND_EMAIL_ADAPTER_OPTS` manually via
|
|
||||||
{option}`services.firezone.server.settings` and/or
|
|
||||||
{option}`services.firezone.server.settingsSecret`.
|
|
||||||
|
|
||||||
The Firezone documentation holds [a list of supported Swoosh adapters](https://github.com/firezone/firezone/blob/main/website/src/app/docs/reference/env-vars/readme.mdx#outbound-emails).
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
from = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "firezone@example.com";
|
|
||||||
description = "Outbound SMTP FROM address";
|
|
||||||
};
|
|
||||||
|
|
||||||
host = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "mail.example.com";
|
|
||||||
description = "Outbound SMTP host";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
example = 465;
|
|
||||||
description = "Outbound SMTP port";
|
|
||||||
};
|
|
||||||
|
|
||||||
implicitTls = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Whether to use implicit TLS instead of STARTTLS (usually port 465)";
|
|
||||||
};
|
|
||||||
|
|
||||||
username = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "firezone@example.com";
|
|
||||||
description = "Username to authenticate against the SMTP relay";
|
|
||||||
};
|
|
||||||
|
|
||||||
passwordFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
example = "/run/secrets/smtp-password";
|
|
||||||
description = "File containing the password for the given username. Beware that a file in the nix store will be world readable.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
domain = componentOptions "domain";
|
|
||||||
|
|
||||||
web = componentOptions "web" // {
|
|
||||||
externalUrl = mkOption {
|
|
||||||
type = types.strMatching "^https://.+/$";
|
|
||||||
example = "https://firezone.example.com/";
|
|
||||||
description = ''
|
|
||||||
The external URL under which you will serve the web interface. You
|
|
||||||
need to setup a reverse proxy for TLS termination, either with
|
|
||||||
{option}`services.firezone.server.nginx.enable` or manually.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
address = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The address to listen on";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 8080;
|
|
||||||
description = "The port under which the web interface will be served locally";
|
|
||||||
};
|
|
||||||
|
|
||||||
trustedProxies = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
description = "A list of trusted proxies";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
api = componentOptions "api" // {
|
|
||||||
externalUrl = mkOption {
|
|
||||||
type = types.strMatching "^https://.+/$";
|
|
||||||
example = "https://firezone.example.com/api/";
|
|
||||||
description = ''
|
|
||||||
The external URL under which you will serve the api. You need to
|
|
||||||
setup a reverse proxy for TLS termination, either with
|
|
||||||
{option}`services.firezone.server.nginx.enable` or manually.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
address = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The address to listen on";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 8081;
|
|
||||||
description = "The port under which the api will be served locally";
|
|
||||||
};
|
|
||||||
|
|
||||||
trustedProxies = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
description = "A list of trusted proxies";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
provision = {
|
|
||||||
enable = mkEnableOption "provisioning of the Firezone domain server";
|
|
||||||
accounts = mkOption {
|
|
||||||
type = types.attrsOf (
|
|
||||||
types.submodule {
|
|
||||||
freeformType = jsonFormat.type;
|
|
||||||
options = {
|
|
||||||
name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The account name";
|
|
||||||
example = "My Organization";
|
|
||||||
};
|
|
||||||
|
|
||||||
features =
|
|
||||||
let
|
|
||||||
mkFeatureOption =
|
|
||||||
name: default:
|
|
||||||
mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
inherit default;
|
|
||||||
description = "Whether to enable the `${name}` feature for this account.";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
flow_activities = mkFeatureOption "flow_activities" true;
|
|
||||||
policy_conditions = mkFeatureOption "policy_conditions" true;
|
|
||||||
multi_site_resources = mkFeatureOption "multi_site_resources" true;
|
|
||||||
traffic_filters = mkFeatureOption "traffic_filters" true;
|
|
||||||
self_hosted_relays = mkFeatureOption "self_hosted_relays" true;
|
|
||||||
idp_sync = mkFeatureOption "idp_sync" true;
|
|
||||||
rest_api = mkFeatureOption "rest_api" true;
|
|
||||||
internet_resource = mkFeatureOption "internet_resource" true;
|
|
||||||
};
|
|
||||||
|
|
||||||
actors = mkOption {
|
|
||||||
type = types.attrsOf (
|
|
||||||
types.submodule {
|
|
||||||
freeformType = jsonFormat.type;
|
|
||||||
options = {
|
|
||||||
type = mkOption {
|
|
||||||
type = types.enum [
|
|
||||||
"account_admin_user"
|
|
||||||
"account_user"
|
|
||||||
"service_account"
|
|
||||||
"api_client"
|
|
||||||
];
|
|
||||||
description = "The account type";
|
|
||||||
};
|
|
||||||
|
|
||||||
email = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The email address used to authenticate as this account";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
default = { };
|
|
||||||
example = {
|
|
||||||
admin = {
|
|
||||||
type = "account_admin_user";
|
|
||||||
email = "admin@myorg.example.com";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
description = "All actors (users) to provision.";
|
|
||||||
};
|
|
||||||
|
|
||||||
auth = mkOption {
|
|
||||||
type = types.attrsOf (
|
|
||||||
types.submodule {
|
|
||||||
freeformType = jsonFormat.type;
|
|
||||||
options = {
|
|
||||||
adapter = mkOption {
|
|
||||||
type = types.enum availableAuthAdapters;
|
|
||||||
description = "The auth adapter type";
|
|
||||||
};
|
|
||||||
|
|
||||||
adapter_config.clientSecretFile = mkOption {
|
|
||||||
type = types.nullOr types.path;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
A file containing a the client secret for an openid_connect adapter.
|
|
||||||
You only need to set this if this is an openid_connect provider.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
default = { };
|
|
||||||
example = {
|
|
||||||
myoidcprovider = {
|
|
||||||
adapter = "openid_connect";
|
|
||||||
adapter_config = {
|
|
||||||
client_id = "clientid";
|
|
||||||
clientSecretFile = "/run/secrets/oidc-client-secret";
|
|
||||||
response_type = "code";
|
|
||||||
scope = "openid email name";
|
|
||||||
discorvery_document_uri = "https://auth.example.com/.well-known/openid-configuration";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
description = "All authentication providers to provision.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
default = { };
|
|
||||||
example = {
|
|
||||||
main = {
|
|
||||||
name = "My Account / Organization";
|
|
||||||
metadata.stripe.billing_email = "org@myorg.example.com";
|
|
||||||
features.rest_api = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
description = ''
|
|
||||||
All accounts to provision. The key specified here will become the
|
|
||||||
account slug. By using `"{file:/path/to/file}"` as a string value
|
|
||||||
anywhere in these settings, the provisioning script will replace that
|
|
||||||
value with the content of the given file at runtime.
|
|
||||||
|
|
||||||
Please refer to the [Firezone source code](https://github.com/firezone/firezone/blob/main/elixir/apps/domain/lib/domain/accounts/account.ex)
|
|
||||||
for all available properties.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkMerge [
|
|
||||||
{
|
|
||||||
assertions =
|
|
||||||
[
|
|
||||||
{
|
|
||||||
assertion = cfg.provision.enable -> cfg.domain.enable;
|
|
||||||
message = "Provisioning must be done on a machine running the firezone domain server";
|
|
||||||
}
|
|
||||||
]
|
|
||||||
++ concatLists (
|
|
||||||
flip mapAttrsToList cfg.provision.accounts (
|
|
||||||
accountName: accountCfg:
|
|
||||||
[
|
|
||||||
{
|
|
||||||
assertion = (builtins.match "^[[:lower:]_-]+$" accountName) != null;
|
|
||||||
message = "An account name must contain only lowercase characters and underscores, as it will be used as the URL slug for this account.";
|
|
||||||
}
|
|
||||||
]
|
|
||||||
++ flip mapAttrsToList accountCfg.auth (
|
|
||||||
authName: _: {
|
|
||||||
assertion = (builtins.match "^[[:alnum:]_-]+$" authName) != null;
|
|
||||||
message = "An authentication provider name must contain only letters, numbers, underscores or dashes.";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
# Enable all components if the main server is enabled
|
|
||||||
(mkIf cfg.enable {
|
|
||||||
services.firezone.server.domain.enable = true;
|
|
||||||
services.firezone.server.web.enable = true;
|
|
||||||
services.firezone.server.api.enable = true;
|
|
||||||
})
|
|
||||||
# Create (and configure) a local database if desired
|
|
||||||
(mkIf cfg.enableLocalDB {
|
|
||||||
services.postgresql = {
|
|
||||||
enable = true;
|
|
||||||
ensureUsers = [
|
|
||||||
{
|
|
||||||
name = "firezone";
|
|
||||||
ensureDBOwnership = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
ensureDatabases = [ "firezone" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.firezone.server.settings = {
|
|
||||||
DATABASE_SOCKET_DIR = "/run/postgresql";
|
|
||||||
DATABASE_PORT = "5432";
|
|
||||||
DATABASE_NAME = "firezone";
|
|
||||||
DATABASE_USER = "firezone";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
# Create a local nginx reverse proxy
|
|
||||||
(mkIf cfg.nginx.enable {
|
|
||||||
services.nginx = mkMerge [
|
|
||||||
{
|
|
||||||
enable = true;
|
|
||||||
}
|
|
||||||
(
|
|
||||||
let
|
|
||||||
urlComponents = builtins.elemAt (builtins.split "https://([^/]*)(/?.*)" cfg.web.externalUrl) 1;
|
|
||||||
domain = builtins.elemAt urlComponents 0;
|
|
||||||
location = builtins.elemAt urlComponents 1;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
virtualHosts.${domain} = {
|
|
||||||
forceSSL = mkDefault true;
|
|
||||||
locations.${location} = {
|
|
||||||
# The trailing slash is important to strip the location prefix from the request
|
|
||||||
proxyPass = "http://${cfg.web.address}:${toString cfg.web.port}/";
|
|
||||||
proxyWebsockets = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
(
|
|
||||||
let
|
|
||||||
urlComponents = builtins.elemAt (builtins.split "https://([^/]*)(/?.*)" cfg.api.externalUrl) 1;
|
|
||||||
domain = builtins.elemAt urlComponents 0;
|
|
||||||
location = builtins.elemAt urlComponents 1;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
virtualHosts.${domain} = {
|
|
||||||
forceSSL = mkDefault true;
|
|
||||||
locations.${location} = {
|
|
||||||
# The trailing slash is important to strip the location prefix from the request
|
|
||||||
proxyPass = "http://${cfg.api.address}:${toString cfg.api.port}/";
|
|
||||||
proxyWebsockets = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
|
||||||
})
|
|
||||||
# Specify sensible defaults
|
|
||||||
{
|
|
||||||
services.firezone.server = {
|
|
||||||
settings = {
|
|
||||||
LOG_LEVEL = mkDefault "info";
|
|
||||||
RELEASE_HOSTNAME = mkDefault "localhost.localdomain";
|
|
||||||
|
|
||||||
ERLANG_CLUSTER_ADAPTER = mkDefault "Elixir.Cluster.Strategy.Epmd";
|
|
||||||
ERLANG_CLUSTER_ADAPTER_CONFIG = mkDefault (
|
|
||||||
builtins.toJSON {
|
|
||||||
hosts = cfg.clusterHosts;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
TZDATA_DIR = mkDefault "/var/lib/firezone/tzdata";
|
|
||||||
TELEMETRY_ENABLED = mkDefault false;
|
|
||||||
|
|
||||||
# By default this will open nproc * 2 connections for each component,
|
|
||||||
# which can exceeds the (default) maximum of 100 connections for
|
|
||||||
# postgresql on a 12 core +SMT machine. 16 connections will be
|
|
||||||
# sufficient for small to medium deployments
|
|
||||||
DATABASE_POOL_SIZE = "16";
|
|
||||||
|
|
||||||
AUTH_PROVIDER_ADAPTERS = mkDefault (concatStringsSep "," availableAuthAdapters);
|
|
||||||
|
|
||||||
FEATURE_FLOW_ACTIVITIES_ENABLED = mkDefault true;
|
|
||||||
FEATURE_POLICY_CONDITIONS_ENABLED = mkDefault true;
|
|
||||||
FEATURE_MULTI_SITE_RESOURCES_ENABLED = mkDefault true;
|
|
||||||
FEATURE_SELF_HOSTED_RELAYS_ENABLED = mkDefault true;
|
|
||||||
FEATURE_IDP_SYNC_ENABLED = mkDefault true;
|
|
||||||
FEATURE_REST_API_ENABLED = mkDefault true;
|
|
||||||
FEATURE_INTERNET_RESOURCE_ENABLED = mkDefault true;
|
|
||||||
FEATURE_TRAFFIC_FILTERS_ENABLED = mkDefault true;
|
|
||||||
FEATURE_SIGN_UP_ENABLED = mkDefault true;
|
|
||||||
};
|
|
||||||
|
|
||||||
domain.settings = {
|
|
||||||
ERLANG_DISTRIBUTION_PORT = mkDefault 9000;
|
|
||||||
HEALTHZ_PORT = mkDefault 4000;
|
|
||||||
BACKGROUND_JOBS_ENABLED = mkDefault true;
|
|
||||||
};
|
|
||||||
|
|
||||||
web.settings = {
|
|
||||||
ERLANG_DISTRIBUTION_PORT = mkDefault 9001;
|
|
||||||
HEALTHZ_PORT = mkDefault 4001;
|
|
||||||
BACKGROUND_JOBS_ENABLED = mkDefault false;
|
|
||||||
|
|
||||||
PHOENIX_LISTEN_ADDRESS = mkDefault cfg.web.address;
|
|
||||||
PHOENIX_EXTERNAL_TRUSTED_PROXIES = mkDefault (builtins.toJSON cfg.web.trustedProxies);
|
|
||||||
PHOENIX_HTTP_WEB_PORT = mkDefault cfg.web.port;
|
|
||||||
PHOENIX_HTTP_API_PORT = mkDefault cfg.api.port;
|
|
||||||
PHOENIX_SECURE_COOKIES = mkDefault true; # enforce HTTPS on cookies
|
|
||||||
WEB_EXTERNAL_URL = mkDefault cfg.web.externalUrl;
|
|
||||||
API_EXTERNAL_URL = mkDefault cfg.api.externalUrl;
|
|
||||||
};
|
|
||||||
|
|
||||||
api.settings = {
|
|
||||||
ERLANG_DISTRIBUTION_PORT = mkDefault 9002;
|
|
||||||
HEALTHZ_PORT = mkDefault 4002;
|
|
||||||
BACKGROUND_JOBS_ENABLED = mkDefault false;
|
|
||||||
|
|
||||||
PHOENIX_LISTEN_ADDRESS = mkDefault cfg.api.address;
|
|
||||||
PHOENIX_EXTERNAL_TRUSTED_PROXIES = mkDefault (builtins.toJSON cfg.api.trustedProxies);
|
|
||||||
PHOENIX_HTTP_WEB_PORT = mkDefault cfg.web.port;
|
|
||||||
PHOENIX_HTTP_API_PORT = mkDefault cfg.api.port;
|
|
||||||
PHOENIX_SECURE_COOKIES = mkDefault true; # enforce HTTPS on cookies
|
|
||||||
WEB_EXTERNAL_URL = mkDefault cfg.web.externalUrl;
|
|
||||||
API_EXTERNAL_URL = mkDefault cfg.api.externalUrl;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(mkIf (!cfg.smtp.configureManually) {
|
|
||||||
services.firezone.server.settings = {
|
|
||||||
OUTBOUND_EMAIL_ADAPTER = "Elixir.Swoosh.Adapters.Mua";
|
|
||||||
OUTBOUND_EMAIL_ADAPTER_OPTS = builtins.toJSON { };
|
|
||||||
OUTBOUND_EMAIL_FROM = cfg.smtp.from;
|
|
||||||
OUTBOUND_EMAIL_SMTP_HOST = cfg.smtp.host;
|
|
||||||
OUTBOUND_EMAIL_SMTP_PORT = toString cfg.smtp.port;
|
|
||||||
OUTBOUND_EMAIL_SMTP_PROTOCOL = if cfg.smtp.implicitTls then "ssl" else "tcp";
|
|
||||||
OUTBOUND_EMAIL_SMTP_USERNAME = cfg.smtp.username;
|
|
||||||
};
|
|
||||||
services.firezone.server.settingsSecret = {
|
|
||||||
OUTBOUND_EMAIL_SMTP_PASSWORD = cfg.smtp.passwordFile;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(mkIf cfg.provision.enable {
|
|
||||||
# Load client secrets from authentication providers
|
|
||||||
services.firezone.server.settingsSecret = flip concatMapAttrs cfg.provision.accounts (
|
|
||||||
accountName: accountCfg:
|
|
||||||
flip concatMapAttrs accountCfg.auth (
|
|
||||||
authName: authCfg:
|
|
||||||
optionalAttrs (authCfg.adapter_config.clientSecretFile != null) {
|
|
||||||
"AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}" =
|
|
||||||
authCfg.adapter_config.clientSecretFile;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
(mkIf (cfg.openClusterFirewall && cfg.domain.enable) {
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
cfg.domain.settings.ERLANG_DISTRIBUTION_PORT
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(mkIf (cfg.openClusterFirewall && cfg.web.enable) {
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
cfg.web.settings.ERLANG_DISTRIBUTION_PORT
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(mkIf (cfg.openClusterFirewall && cfg.api.enable) {
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
cfg.api.settings.ERLANG_DISTRIBUTION_PORT
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(mkIf (cfg.domain.enable || cfg.web.enable || cfg.api.enable) {
|
|
||||||
systemd.slices.system-firezone = {
|
|
||||||
description = "Firezone Slice";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.targets.firezone = {
|
|
||||||
description = "Common target for all Firezone services.";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.firezone-initialize = {
|
|
||||||
description = "Backend initialization service for the Firezone zero-trust access platform";
|
|
||||||
|
|
||||||
after = mkIf cfg.enableLocalDB [ "postgresql.service" ];
|
|
||||||
requires = mkIf cfg.enableLocalDB [ "postgresql.service" ];
|
|
||||||
wantedBy = [ "firezone.target" ];
|
|
||||||
partOf = [ "firezone.target" ];
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
mkdir -p "$TZDATA_DIR"
|
|
||||||
|
|
||||||
# Generate and load secrets
|
|
||||||
${generateSecrets}
|
|
||||||
${loadSecretEnvironment "domain"}
|
|
||||||
|
|
||||||
echo "Running migrations"
|
|
||||||
${getExe cfg.domain.package} eval Domain.Release.migrate
|
|
||||||
'';
|
|
||||||
|
|
||||||
# We use the domain environment to be able to run migrations
|
|
||||||
environment = collectEnvironment "domain";
|
|
||||||
serviceConfig = commonServiceConfig // {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.firezone-server-domain = mkIf cfg.domain.enable {
|
|
||||||
description = "Backend domain server for the Firezone zero-trust access platform";
|
|
||||||
after = [ "firezone-initialize.service" ];
|
|
||||||
bindsTo = [ "firezone-initialize.service" ];
|
|
||||||
wantedBy = [ "firezone.target" ];
|
|
||||||
partOf = [ "firezone.target" ];
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
${loadSecretEnvironment "domain"}
|
|
||||||
exec ${getExe cfg.domain.package} start;
|
|
||||||
'';
|
|
||||||
|
|
||||||
path = [ pkgs.curl ];
|
|
||||||
postStart = mkIf cfg.provision.enable ''
|
|
||||||
${loadSecretEnvironment "domain"}
|
|
||||||
|
|
||||||
# Wait for the firezone server to come online
|
|
||||||
count=0
|
|
||||||
while [[ "$(curl -s "http://localhost:${toString cfg.domain.settings.HEALTHZ_PORT}" 2>/dev/null || echo)" != '{"status":"ok"}' ]]
|
|
||||||
do
|
|
||||||
sleep 1
|
|
||||||
if [[ "$count" -eq 30 ]]; then
|
|
||||||
echo "Tried for at least 30 seconds, giving up..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
count=$((count++))
|
|
||||||
done
|
|
||||||
|
|
||||||
sleep 1 # Wait for server to fully come up. Not ideal to use sleep, but at least it works.
|
|
||||||
ln -sTf ${provisionStateJson} provision-state.json
|
|
||||||
${getExe cfg.domain.package} rpc 'Code.eval_file("${./provision.exs}")'
|
|
||||||
'';
|
|
||||||
|
|
||||||
environment = collectEnvironment "domain";
|
|
||||||
serviceConfig = commonServiceConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.firezone-server-web = mkIf cfg.web.enable {
|
|
||||||
description = "Backend web server for the Firezone zero-trust access platform";
|
|
||||||
after = [ "firezone-initialize.service" ];
|
|
||||||
bindsTo = [ "firezone-initialize.service" ];
|
|
||||||
wantedBy = [ "firezone.target" ];
|
|
||||||
partOf = [ "firezone.target" ];
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
${loadSecretEnvironment "web"}
|
|
||||||
exec ${getExe cfg.web.package} start;
|
|
||||||
'';
|
|
||||||
|
|
||||||
environment = collectEnvironment "web";
|
|
||||||
serviceConfig = commonServiceConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.firezone-server-api = mkIf cfg.api.enable {
|
|
||||||
description = "Backend api server for the Firezone zero-trust access platform";
|
|
||||||
after = [ "firezone-initialize.service" ];
|
|
||||||
bindsTo = [ "firezone-initialize.service" ];
|
|
||||||
wantedBy = [ "firezone.target" ];
|
|
||||||
partOf = [ "firezone.target" ];
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
${loadSecretEnvironment "api"}
|
|
||||||
exec ${getExe cfg.api.package} start;
|
|
||||||
'';
|
|
||||||
|
|
||||||
environment = collectEnvironment "api";
|
|
||||||
serviceConfig = commonServiceConfig;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
meta.maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
defmodule Provision do
|
|
||||||
alias Domain.{Repo, Accounts, Auth, Actors}
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
defp resolve_references(value) when is_map(value) do
|
|
||||||
Enum.into(value, %{}, fn {k, v} -> {k, resolve_references(v)} end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp resolve_references(value) when is_list(value) do
|
|
||||||
Enum.map(value, &resolve_references/1)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp resolve_references(value) when is_binary(value) do
|
|
||||||
Regex.replace(~r/\{env:([^}]+)\}/, value, fn _, var ->
|
|
||||||
System.get_env(var) || raise "Environment variable #{var} not set"
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp resolve_references(value), do: value
|
|
||||||
|
|
||||||
defp atomize_keys(map) when is_map(map) do
|
|
||||||
Enum.into(map, %{}, fn {k, v} ->
|
|
||||||
{
|
|
||||||
if(is_binary(k), do: String.to_atom(k), else: k),
|
|
||||||
if(is_map(v), do: atomize_keys(v), else: v)
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
def provision() do
|
|
||||||
IO.inspect("Starting provisioning", label: "INFO")
|
|
||||||
json_file = "provision-state.json"
|
|
||||||
{:ok, raw_json} = File.read(json_file)
|
|
||||||
{:ok, %{"accounts" => accounts}} = Jason.decode(raw_json)
|
|
||||||
accounts = resolve_references(accounts)
|
|
||||||
|
|
||||||
multi = Enum.reduce(accounts, Ecto.Multi.new(), fn {slug, account_data}, multi ->
|
|
||||||
account_attrs = atomize_keys(%{
|
|
||||||
name: account_data["name"],
|
|
||||||
slug: slug,
|
|
||||||
features: Map.get(account_data, "features", %{}),
|
|
||||||
metadata: Map.get(account_data, "metadata", %{}),
|
|
||||||
limits: Map.get(account_data, "limits", %{}),
|
|
||||||
})
|
|
||||||
|
|
||||||
multi = multi
|
|
||||||
|> Ecto.Multi.run({:account, slug}, fn repo, _changes ->
|
|
||||||
case Accounts.fetch_account_by_id_or_slug(slug) do
|
|
||||||
{:ok, acc} ->
|
|
||||||
IO.inspect("Updating existing account #{slug}", label: "INFO")
|
|
||||||
updated_acc = acc |> Ecto.Changeset.change(account_attrs) |> repo.update!()
|
|
||||||
{:ok, {:existing, updated_acc}}
|
|
||||||
_ ->
|
|
||||||
IO.inspect("Creating new account #{slug}", label: "INFO")
|
|
||||||
{:ok, account} = Accounts.create_account(account_attrs)
|
|
||||||
{:ok, {:new, account}}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|> Ecto.Multi.run({:everyone_group, slug}, fn _repo, changes ->
|
|
||||||
case Map.get(changes, {:account, slug}) do
|
|
||||||
{:new, account} ->
|
|
||||||
IO.inspect("Creating Everyone group for new account", label: "INFO")
|
|
||||||
Actors.create_managed_group(account, %{name: "Everyone", membership_rules: [%{operator: true}]})
|
|
||||||
{:existing, _account} ->
|
|
||||||
{:ok, :skipped}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|> Ecto.Multi.run({:provider, slug}, fn _repo, changes ->
|
|
||||||
case Map.get(changes, {:account, slug}) do
|
|
||||||
{:new, account} ->
|
|
||||||
IO.inspect("Creating default email provider for new account", label: "INFO")
|
|
||||||
Auth.create_provider(account, %{name: "Email", adapter: :email, adapter_config: %{}})
|
|
||||||
{:existing, account} ->
|
|
||||||
Auth.Provider.Query.not_disabled()
|
|
||||||
|> Auth.Provider.Query.by_adapter(:email)
|
|
||||||
|> Auth.Provider.Query.by_account_id(account.id)
|
|
||||||
|> Repo.fetch(Auth.Provider.Query, [])
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
multi = Enum.reduce(account_data["actors"] || %{}, multi, fn {name, actor_data}, multi ->
|
|
||||||
actor_attrs = atomize_keys(%{
|
|
||||||
name: name,
|
|
||||||
type: String.to_atom(actor_data["type"]),
|
|
||||||
})
|
|
||||||
|
|
||||||
Ecto.Multi.run(multi, {:actor, slug, name}, fn repo, changes ->
|
|
||||||
{_, account} = changes[{:account, slug}]
|
|
||||||
case Repo.get_by(Actors.Actor, account_id: account.id, name: name) do
|
|
||||||
nil ->
|
|
||||||
IO.inspect("Creating new actor #{name}", label: "INFO")
|
|
||||||
{:ok, actor} = Actors.create_actor(account, actor_attrs)
|
|
||||||
{:ok, {:new, actor}}
|
|
||||||
act ->
|
|
||||||
IO.inspect("Updating existing actor #{name}", label: "INFO")
|
|
||||||
updated_act = act |> Ecto.Changeset.change(actor_attrs) |> repo.update!()
|
|
||||||
{:ok, {:existing, updated_act}}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|> Ecto.Multi.run({:actor_identity, slug, name}, fn repo, changes ->
|
|
||||||
email_provider = changes[{:provider, slug}]
|
|
||||||
case Map.get(changes, {:actor, slug, name}) do
|
|
||||||
{:new, actor} ->
|
|
||||||
IO.inspect("Creating actor email identity", label: "INFO")
|
|
||||||
Auth.create_identity(actor, email_provider, %{
|
|
||||||
provider_identifier: actor_data["email"],
|
|
||||||
provider_identifier_confirmation: actor_data["email"]
|
|
||||||
})
|
|
||||||
{:existing, actor} ->
|
|
||||||
IO.inspect("Updating actor email identity", label: "INFO")
|
|
||||||
{:ok, identity} = Auth.Identity.Query.not_deleted()
|
|
||||||
|> Auth.Identity.Query.by_actor_id(actor.id)
|
|
||||||
|> Auth.Identity.Query.by_provider_id(email_provider.id)
|
|
||||||
|> Repo.fetch(Auth.Identity.Query, [])
|
|
||||||
|
|
||||||
{:ok, identity |> Ecto.Changeset.change(%{
|
|
||||||
provider_identifier: actor_data["email"],
|
|
||||||
}) |> repo.update!()}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
multi = Enum.reduce(account_data["auth"] || %{}, multi, fn {name, provider_data}, multi ->
|
|
||||||
provider_attrs = %{
|
|
||||||
name: name,
|
|
||||||
adapter: String.to_atom(provider_data["adapter"]),
|
|
||||||
adapter_config: provider_data["adapter_config"],
|
|
||||||
}
|
|
||||||
|
|
||||||
Ecto.Multi.run(multi, {:provider, slug, name}, fn repo, changes ->
|
|
||||||
{_, account} = changes[{:account, slug}]
|
|
||||||
case Repo.get_by(Auth.Provider, account_id: account.id, name: name) do
|
|
||||||
nil ->
|
|
||||||
IO.inspect("Creating new provider #{name}", label: "INFO")
|
|
||||||
Auth.create_provider(account, provider_attrs)
|
|
||||||
existing ->
|
|
||||||
IO.inspect("Updating existing provider #{name}", label: "INFO")
|
|
||||||
{:ok, existing |> Ecto.Changeset.change(provider_attrs) |> repo.update!()}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
multi
|
|
||||||
end)
|
|
||||||
|
|
||||||
case Repo.transaction(multi) do
|
|
||||||
{:ok, _result} ->
|
|
||||||
Logger.info("Provisioning completed successfully.")
|
|
||||||
{:error, step, reason, _changes} ->
|
|
||||||
Logger.error("Provisioning failed at step #{inspect(step)}: #{inspect(reason)}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Provision.provision()
|
|
|
@ -19,13 +19,6 @@ _inputs: [
|
||||||
# (_pythonFinal: pythonPrev: {
|
# (_pythonFinal: pythonPrev: {
|
||||||
# })
|
# })
|
||||||
# ];
|
# ];
|
||||||
firezone-server-domain = prev.callPackage ./firezone-server-domain/package.nix { };
|
|
||||||
firezone-server-web = prev.callPackage ./firezone-server-web/package.nix { };
|
|
||||||
firezone-server-api = prev.callPackage ./firezone-server-api/package.nix { };
|
|
||||||
firezone-gateway = prev.callPackage ./firezone-gateway/package.nix { };
|
|
||||||
firezone-relay = prev.callPackage ./firezone-relay/package.nix { };
|
|
||||||
firezone-gui-client = prev.callPackage ./firezone-gui-client/package.nix { };
|
|
||||||
firezone-headless-client = prev.callPackage ./firezone-headless-client/package.nix { };
|
|
||||||
|
|
||||||
mdns-repeater = prev.callPackage ./mdns-repeater.nix { };
|
mdns-repeater = prev.callPackage ./mdns-repeater.nix { };
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
rustPlatform,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nix-update-script,
|
|
||||||
}:
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "firezone-gateway";
|
|
||||||
version = "1.4.2";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "oddlama";
|
|
||||||
repo = "firezone";
|
|
||||||
rev = "feat/configurable-gateway-interface";
|
|
||||||
hash = "sha256-dsGQubRs/ZHdAd6MHpa+3K4vGm4OnCdf1yMlGG1AIJk=";
|
|
||||||
};
|
|
||||||
|
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-odrexu5mBGmvHNF4cUu9PDIEdxZC451lWV7dsLYT/Sg=";
|
|
||||||
sourceRoot = "${src.name}/rust";
|
|
||||||
buildAndTestSubdir = "gateway";
|
|
||||||
|
|
||||||
# Required to remove profiling arguments which conflict with this builder
|
|
||||||
postPatch = ''
|
|
||||||
rm .cargo/config.toml
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.updateScript = nix-update-script { };
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "WireGuard tunnel server for the Firezone zero-trust access platform";
|
|
||||||
homepage = "https://github.com/firezone/firezone";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
mainProgram = "firezone-gateway";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,281 +0,0 @@
|
||||||
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
|
|
||||||
index 9645ee069..558339b1f 100644
|
|
||||||
--- a/rust/Cargo.lock
|
|
||||||
+++ b/rust/Cargo.lock
|
|
||||||
@@ -951,7 +951,7 @@ dependencies = [
|
|
||||||
"cocoa-foundation 0.1.2",
|
|
||||||
"core-foundation 0.9.4",
|
|
||||||
"core-graphics 0.23.2",
|
|
||||||
- "foreign-types",
|
|
||||||
+ "foreign-types 0.5.0",
|
|
||||||
"libc",
|
|
||||||
"objc",
|
|
||||||
]
|
|
||||||
@@ -967,7 +967,7 @@ dependencies = [
|
|
||||||
"cocoa-foundation 0.2.0",
|
|
||||||
"core-foundation 0.10.0",
|
|
||||||
"core-graphics 0.24.0",
|
|
||||||
- "foreign-types",
|
|
||||||
+ "foreign-types 0.5.0",
|
|
||||||
"libc",
|
|
||||||
"objc",
|
|
||||||
]
|
|
||||||
@@ -1173,7 +1173,7 @@ dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"core-foundation 0.9.4",
|
|
||||||
"core-graphics-types 0.1.3",
|
|
||||||
- "foreign-types",
|
|
||||||
+ "foreign-types 0.5.0",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
@@ -1186,7 +1186,7 @@ dependencies = [
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
"core-foundation 0.10.0",
|
|
||||||
"core-graphics-types 0.2.0",
|
|
||||||
- "foreign-types",
|
|
||||||
+ "foreign-types 0.5.0",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
@@ -1999,6 +1999,7 @@ dependencies = [
|
|
||||||
"firezone-logging",
|
|
||||||
"firezone-telemetry",
|
|
||||||
"futures",
|
|
||||||
+ "hyper-tls",
|
|
||||||
"native-dialog",
|
|
||||||
"nix 0.29.0",
|
|
||||||
"rand 0.8.5",
|
|
||||||
@@ -2281,6 +2282,15 @@ version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "foreign-types"
|
|
||||||
+version = "0.3.2"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
|
||||||
+dependencies = [
|
|
||||||
+ "foreign-types-shared 0.1.1",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.5.0"
|
|
||||||
@@ -2288,7 +2298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-macros",
|
|
||||||
- "foreign-types-shared",
|
|
||||||
+ "foreign-types-shared 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
@@ -2302,6 +2312,12 @@ dependencies = [
|
|
||||||
"syn 2.0.87",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "foreign-types-shared"
|
|
||||||
+version = "0.1.1"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.3.1"
|
|
||||||
@@ -3035,6 +3051,22 @@ dependencies = [
|
|
||||||
"tower-service",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "hyper-tls"
|
|
||||||
+version = "0.6.0"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
|
||||||
+dependencies = [
|
|
||||||
+ "bytes",
|
|
||||||
+ "http-body-util",
|
|
||||||
+ "hyper",
|
|
||||||
+ "hyper-util",
|
|
||||||
+ "native-tls",
|
|
||||||
+ "tokio",
|
|
||||||
+ "tokio-native-tls",
|
|
||||||
+ "tower-service",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "hyper-util"
|
|
||||||
version = "0.1.9"
|
|
||||||
@@ -3723,6 +3755,23 @@ dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "native-tls"
|
|
||||||
+version = "0.2.12"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
|
||||||
+dependencies = [
|
|
||||||
+ "libc",
|
|
||||||
+ "log",
|
|
||||||
+ "openssl",
|
|
||||||
+ "openssl-probe",
|
|
||||||
+ "openssl-sys",
|
|
||||||
+ "schannel",
|
|
||||||
+ "security-framework",
|
|
||||||
+ "security-framework-sys",
|
|
||||||
+ "tempfile",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "ndk"
|
|
||||||
version = "0.9.0"
|
|
||||||
@@ -4286,6 +4335,50 @@ dependencies = [
|
|
||||||
"pathdiff",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "openssl"
|
|
||||||
+version = "0.10.68"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
|
||||||
+dependencies = [
|
|
||||||
+ "bitflags 2.6.0",
|
|
||||||
+ "cfg-if",
|
|
||||||
+ "foreign-types 0.3.2",
|
|
||||||
+ "libc",
|
|
||||||
+ "once_cell",
|
|
||||||
+ "openssl-macros",
|
|
||||||
+ "openssl-sys",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
+[[package]]
|
|
||||||
+name = "openssl-macros"
|
|
||||||
+version = "0.1.1"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|
||||||
+dependencies = [
|
|
||||||
+ "proc-macro2",
|
|
||||||
+ "quote",
|
|
||||||
+ "syn 2.0.87",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
+[[package]]
|
|
||||||
+name = "openssl-probe"
|
|
||||||
+version = "0.1.5"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|
||||||
+
|
|
||||||
+[[package]]
|
|
||||||
+name = "openssl-sys"
|
|
||||||
+version = "0.9.104"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
|
||||||
+dependencies = [
|
|
||||||
+ "cc",
|
|
||||||
+ "libc",
|
|
||||||
+ "pkg-config",
|
|
||||||
+ "vcpkg",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "opentelemetry"
|
|
||||||
version = "0.26.0"
|
|
||||||
@@ -5385,6 +5478,15 @@ dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "schannel"
|
|
||||||
+version = "0.1.27"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
|
|
||||||
+dependencies = [
|
|
||||||
+ "windows-sys 0.59.0",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "schemars"
|
|
||||||
version = "0.8.21"
|
|
||||||
@@ -5474,6 +5576,29 @@ dependencies = [
|
|
||||||
"zbus",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "security-framework"
|
|
||||||
+version = "2.11.1"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
|
||||||
+dependencies = [
|
|
||||||
+ "bitflags 2.6.0",
|
|
||||||
+ "core-foundation 0.9.4",
|
|
||||||
+ "core-foundation-sys",
|
|
||||||
+ "libc",
|
|
||||||
+ "security-framework-sys",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
+[[package]]
|
|
||||||
+name = "security-framework-sys"
|
|
||||||
+version = "2.14.0"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
|
||||||
+dependencies = [
|
|
||||||
+ "core-foundation-sys",
|
|
||||||
+ "libc",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "selectors"
|
|
||||||
version = "0.22.0"
|
|
||||||
@@ -5947,7 +6072,7 @@ dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"cfg_aliases",
|
|
||||||
"core-graphics 0.24.0",
|
|
||||||
- "foreign-types",
|
|
||||||
+ "foreign-types 0.5.0",
|
|
||||||
"js-sys",
|
|
||||||
"log",
|
|
||||||
"objc2",
|
|
||||||
@@ -6786,6 +6911,16 @@ dependencies = [
|
|
||||||
"syn 2.0.87",
|
|
||||||
]
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "tokio-native-tls"
|
|
||||||
+version = "0.3.1"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
|
||||||
+dependencies = [
|
|
||||||
+ "native-tls",
|
|
||||||
+ "tokio",
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-rustls"
|
|
||||||
version = "0.26.0"
|
|
||||||
@@ -7395,6 +7530,12 @@ version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
|
||||||
|
|
||||||
+[[package]]
|
|
||||||
+name = "vcpkg"
|
|
||||||
+version = "0.2.15"
|
|
||||||
+source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
+
|
|
||||||
[[package]]
|
|
||||||
name = "version-compare"
|
|
||||||
version = "0.2.0"
|
|
||||||
diff --git a/rust/gui-client/src-tauri/Cargo.toml b/rust/gui-client/src-tauri/Cargo.toml
|
|
||||||
index 32ca56197..f0475e6bf 100644
|
|
||||||
--- a/rust/gui-client/src-tauri/Cargo.toml
|
|
||||||
+++ b/rust/gui-client/src-tauri/Cargo.toml
|
|
||||||
@@ -25,6 +25,7 @@ firezone-headless-client = { workspace = true }
|
|
||||||
firezone-logging = { workspace = true }
|
|
||||||
firezone-telemetry = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
+hyper-tls = "0.6.0"
|
|
||||||
native-dialog = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
rustls = { workspace = true }
|
|
|
@ -1,153 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
rustPlatform,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nix-update-script,
|
|
||||||
pkg-config,
|
|
||||||
dbus,
|
|
||||||
openssl,
|
|
||||||
zenity,
|
|
||||||
cargo-tauri,
|
|
||||||
gdk-pixbuf,
|
|
||||||
glib,
|
|
||||||
gobject-introspection,
|
|
||||||
gtk3,
|
|
||||||
kdialog,
|
|
||||||
libsoup_3,
|
|
||||||
libayatana-appindicator,
|
|
||||||
webkitgtk_4_1,
|
|
||||||
wrapGAppsHook3,
|
|
||||||
stdenvNoCC,
|
|
||||||
git,
|
|
||||||
pnpm_9,
|
|
||||||
nodejs,
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
version = "1.4.0";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "firezone";
|
|
||||||
repo = "firezone";
|
|
||||||
tag = "gui-client-${version}";
|
|
||||||
hash = "sha256-gwlkHTFVd1gHwOOIar+5+LEP2ovoyEIMmLfPxYb/OCs=";
|
|
||||||
# FIXME: remove once https://github.com/firezone/firezone/pull/7808 is released
|
|
||||||
# FIXME: somehow still required...
|
|
||||||
postFetch = ''
|
|
||||||
${lib.getExe git} -C $out apply ${./0000-add-hyper-tls-dependency.patch}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
frontend = stdenvNoCC.mkDerivation rec {
|
|
||||||
pname = "firezone-gui-client-frontend";
|
|
||||||
inherit version src;
|
|
||||||
|
|
||||||
pnpmDeps = pnpm_9.fetchDeps {
|
|
||||||
inherit pname version;
|
|
||||||
src = "${src}/rust/gui-client";
|
|
||||||
hash = "sha256-Gc+X4mbpHa8b/Ol6Fee7VFpTPG25LksoAEjFww1WH5I=";
|
|
||||||
};
|
|
||||||
pnpmRoot = "rust/gui-client";
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pnpm_9.configHook
|
|
||||||
nodejs
|
|
||||||
];
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
|
|
||||||
cd $pnpmRoot
|
|
||||||
cp node_modules/flowbite/dist/flowbite.min.js src/
|
|
||||||
pnpm tailwindcss -i src/input.css -o src/output.css
|
|
||||||
node --max_old_space_size=1024000 ./node_modules/vite/bin/vite.js build
|
|
||||||
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
cp -r dist $out
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "firezone-gui-client";
|
|
||||||
inherit version src;
|
|
||||||
|
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-eqkYwP14kca7Q/P9wc+CvTBmKETTmbd06EBNx3MKLro=";
|
|
||||||
sourceRoot = "${src.name}/rust";
|
|
||||||
buildAndTestSubdir = "gui-client";
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
cargo-tauri.hook
|
|
||||||
|
|
||||||
pkg-config
|
|
||||||
wrapGAppsHook3
|
|
||||||
];
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
openssl
|
|
||||||
dbus
|
|
||||||
gdk-pixbuf
|
|
||||||
glib
|
|
||||||
gobject-introspection
|
|
||||||
gtk3
|
|
||||||
libsoup_3
|
|
||||||
|
|
||||||
libayatana-appindicator
|
|
||||||
webkitgtk_4_1
|
|
||||||
];
|
|
||||||
|
|
||||||
# Required to remove profiling arguments which conflict with this builder
|
|
||||||
postPatch = ''
|
|
||||||
rm .cargo/config.toml
|
|
||||||
ln -s ${frontend} gui-client/dist
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Required to run tests
|
|
||||||
preCheck = ''
|
|
||||||
export XDG_RUNTIME_DIR=$(mktemp -d)
|
|
||||||
'';
|
|
||||||
|
|
||||||
checkFlags = [
|
|
||||||
# Requires network access
|
|
||||||
"--skip=notifiers"
|
|
||||||
];
|
|
||||||
|
|
||||||
preFixup = ''
|
|
||||||
gappsWrapperArgs+=(
|
|
||||||
# Otherwise blank screen, see https://github.com/tauri-apps/tauri/issues/9304
|
|
||||||
--set WEBKIT_DISABLE_DMABUF_RENDERER 1
|
|
||||||
--prefix PATH ":" ${
|
|
||||||
lib.makeBinPath [
|
|
||||||
zenity
|
|
||||||
kdialog
|
|
||||||
]
|
|
||||||
}
|
|
||||||
--prefix LD_LIBRARY_PATH ":" ${
|
|
||||||
lib.makeLibraryPath [
|
|
||||||
libayatana-appindicator
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru = {
|
|
||||||
inherit frontend;
|
|
||||||
updateScript = nix-update-script { };
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "GUI client for the Firezone zero-trust access platform";
|
|
||||||
homepage = "https://github.com/firezone/firezone";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
mainProgram = "firezone-gui-client";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
rustPlatform,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nix-update-script,
|
|
||||||
}:
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "firezone-headless-client";
|
|
||||||
version = "1.4.0";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "oddlama";
|
|
||||||
repo = "firezone";
|
|
||||||
rev = "feat/configurable-gateway-interface";
|
|
||||||
hash = "sha256-dsGQubRs/ZHdAd6MHpa+3K4vGm4OnCdf1yMlGG1AIJk=";
|
|
||||||
};
|
|
||||||
|
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-odrexu5mBGmvHNF4cUu9PDIEdxZC451lWV7dsLYT/Sg=";
|
|
||||||
sourceRoot = "${src.name}/rust";
|
|
||||||
buildAndTestSubdir = "headless-client";
|
|
||||||
|
|
||||||
# Required to remove profiling arguments which conflict with this builder
|
|
||||||
postPatch = ''
|
|
||||||
rm .cargo/config.toml
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Required to run tests
|
|
||||||
preCheck = ''
|
|
||||||
export XDG_RUNTIME_DIR=$(mktemp -d)
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.updateScript = nix-update-script { };
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "CLI client for the Firezone zero-trust access platform";
|
|
||||||
homepage = "https://github.com/firezone/firezone";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
mainProgram = "firezone-headless-client";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
rustPlatform,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nix-update-script,
|
|
||||||
}:
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "firezone-relay";
|
|
||||||
version = "unstable-2025-01-19";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "firezone";
|
|
||||||
repo = "firezone";
|
|
||||||
rev = "8c9427b7b133e5050be34c2ac0e831c12c08f02c";
|
|
||||||
hash = "sha256-yccplADHRJQQiKrmHcJ5rvouswHrbx4K6ysnIAoZJR0=";
|
|
||||||
};
|
|
||||||
|
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-WpJL5ALFMvyYv3QI5gMazAj6BVr4oyGq+zOo40rxqOE=";
|
|
||||||
sourceRoot = "${src.name}/rust";
|
|
||||||
buildAndTestSubdir = "relay";
|
|
||||||
|
|
||||||
# Required to remove profiling arguments which conflict with this builder
|
|
||||||
postPatch = ''
|
|
||||||
rm .cargo/config.toml
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.updateScript = nix-update-script { };
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "STUN/TURN server for the Firezone zero-trust access platform";
|
|
||||||
homepage = "https://github.com/firezone/firezone";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
mainProgram = "firezone-relay";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
import ../firezone-server-domain/generic.nix {
|
|
||||||
mixReleaseName = "api";
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
diff --git a/apps/domain/lib/domain/config/definitions.ex b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
index 8cd2e8d0f..de55c8e8f 100644
|
|
||||||
--- a/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
+++ b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
@@ -120,6 +120,7 @@ defmodule Domain.Config.Definitions do
|
|
||||||
]},
|
|
||||||
{"Instrumentation",
|
|
||||||
[
|
|
||||||
+ :healthz_port,
|
|
||||||
:instrumentation_client_logs_enabled,
|
|
||||||
:instrumentation_client_logs_bucket,
|
|
||||||
:telemetry_metrics_reporter,
|
|
||||||
@@ -474,6 +475,19 @@ defmodule Domain.Config.Definitions do
|
|
||||||
## Telemetry
|
|
||||||
##############################################
|
|
||||||
|
|
||||||
+ @doc """
|
|
||||||
+ The port for the internal healthz endpoint.
|
|
||||||
+ """
|
|
||||||
+ defconfig(:healthz_port, :integer,
|
|
||||||
+ default: 4000,
|
|
||||||
+ changeset: fn changeset, key ->
|
|
||||||
+ Ecto.Changeset.validate_number(changeset, key,
|
|
||||||
+ greater_than: 0,
|
|
||||||
+ less_than_or_equal_to: 65_535
|
|
||||||
+ )
|
|
||||||
+ end
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
@doc """
|
|
||||||
Enable or disable the Firezone telemetry collection.
|
|
||||||
|
|
||||||
diff --git a/apps/domain/lib/domain/telemetry.ex b/apps/domain/lib/domain/telemetry.ex
|
|
||||||
index af430358d..d154282b4 100644
|
|
||||||
--- a/apps/domain/lib/domain/telemetry.ex
|
|
||||||
+++ b/apps/domain/lib/domain/telemetry.ex
|
|
||||||
@@ -13,7 +13,7 @@ defmodule Domain.Telemetry do
|
|
||||||
|
|
||||||
children = [
|
|
||||||
# We start a /healthz endpoint that is used for liveness probes
|
|
||||||
- {Bandit, plug: Telemetry.HealthzPlug, scheme: :http, port: 4000},
|
|
||||||
+ {Bandit, plug: Telemetry.HealthzPlug, scheme: :http, port: Keyword.get(config, :healthz_port)},
|
|
||||||
|
|
||||||
# Telemetry poller will execute the given period measurements
|
|
||||||
# every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
|
|
||||||
diff --git a/config/runtime.exs b/config/runtime.exs
|
|
||||||
index 7817942fa..c6dfe9c31 100644
|
|
||||||
--- a/config/runtime.exs
|
|
||||||
+++ b/config/runtime.exs
|
|
||||||
@@ -211,7 +211,9 @@ if config_env() == :prod do
|
|
||||||
otlp_endpoint: System.get_env("OTLP_ENDPOINT")
|
|
||||||
end
|
|
||||||
|
|
||||||
- config :domain, Domain.Telemetry, metrics_reporter: compile_config!(:telemetry_metrics_reporter)
|
|
||||||
+ config :domain, Domain.Telemetry,
|
|
||||||
+ healthz_port: compile_config!(:healthz_port),
|
|
||||||
+ metrics_reporter: compile_config!(:telemetry_metrics_reporter)
|
|
||||||
|
|
||||||
if telemetry_metrics_reporter = compile_config!(:telemetry_metrics_reporter) do
|
|
||||||
config :domain, telemetry_metrics_reporter, compile_config!(:telemetry_metrics_reporter_opts)
|
|
|
@ -1,100 +0,0 @@
|
||||||
diff --git a/apps/domain/lib/domain/config.ex b/apps/domain/lib/domain/config.ex
|
|
||||||
index 11fdcc3a1..9254f210d 100644
|
|
||||||
--- a/apps/domain/lib/domain/config.ex
|
|
||||||
+++ b/apps/domain/lib/domain/config.ex
|
|
||||||
@@ -42,6 +42,24 @@ defmodule Domain.Config do
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
+ @doc """
|
|
||||||
+ Similar to `compile_config/2` but returns nil if the configuration is invalid.
|
|
||||||
+
|
|
||||||
+ This function does not resolve values from the database because it's intended use is during
|
|
||||||
+ compilation and before application boot (in `config/runtime.exs`).
|
|
||||||
+
|
|
||||||
+ If you need to resolve values from the database, use `fetch_config/1` or `fetch_config!/1`.
|
|
||||||
+ """
|
|
||||||
+ def compile_config(module \\ Definitions, key, env_config \\ System.get_env()) do
|
|
||||||
+ case Fetcher.fetch_source_and_config(module, key, %{}, env_config) do
|
|
||||||
+ {:ok, _source, value} ->
|
|
||||||
+ value
|
|
||||||
+
|
|
||||||
+ {:error, reason} ->
|
|
||||||
+ nil
|
|
||||||
+ end
|
|
||||||
+ end
|
|
||||||
+
|
|
||||||
def config_changeset(changeset, schema_key, config_key \\ nil) do
|
|
||||||
config_key = config_key || schema_key
|
|
||||||
|
|
||||||
diff --git a/apps/domain/lib/domain/config/definitions.ex b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
index 8cd2e8d0f..f27d67c69 100644
|
|
||||||
--- a/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
+++ b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
@@ -61,6 +61,7 @@ defmodule Domain.Config.Definitions do
|
|
||||||
{"Database",
|
|
||||||
[
|
|
||||||
:database_host,
|
|
||||||
+ :database_socket_dir,
|
|
||||||
:database_port,
|
|
||||||
:database_name,
|
|
||||||
:database_user,
|
|
||||||
@@ -255,6 +256,11 @@ defmodule Domain.Config.Definitions do
|
|
||||||
"""
|
|
||||||
defconfig(:database_host, :string, default: "postgres")
|
|
||||||
|
|
||||||
+ @doc """
|
|
||||||
+ PostgreSQL socket directory (takes precedence over hostname).
|
|
||||||
+ """
|
|
||||||
+ defconfig(:database_socket_dir, :string, default: nil)
|
|
||||||
+
|
|
||||||
@doc """
|
|
||||||
PostgreSQL port.
|
|
||||||
"""
|
|
||||||
diff --git a/config/runtime.exs b/config/runtime.exs
|
|
||||||
index 7817942fa..14cbe182f 100644
|
|
||||||
--- a/config/runtime.exs
|
|
||||||
+++ b/config/runtime.exs
|
|
||||||
@@ -1,22 +1,31 @@
|
|
||||||
import Config
|
|
||||||
|
|
||||||
if config_env() == :prod do
|
|
||||||
- import Domain.Config, only: [compile_config!: 1]
|
|
||||||
+ import Domain.Config, only: [compile_config!: 1, compile_config: 1]
|
|
||||||
|
|
||||||
###############################
|
|
||||||
##### Domain ##################
|
|
||||||
###############################
|
|
||||||
|
|
||||||
- config :domain, Domain.Repo,
|
|
||||||
- database: compile_config!(:database_name),
|
|
||||||
- username: compile_config!(:database_user),
|
|
||||||
- hostname: compile_config!(:database_host),
|
|
||||||
- port: compile_config!(:database_port),
|
|
||||||
- password: compile_config!(:database_password),
|
|
||||||
- pool_size: compile_config!(:database_pool_size),
|
|
||||||
- ssl: compile_config!(:database_ssl_enabled),
|
|
||||||
- ssl_opts: compile_config!(:database_ssl_opts),
|
|
||||||
- parameters: compile_config!(:database_parameters)
|
|
||||||
+ config :domain,
|
|
||||||
+ Domain.Repo,
|
|
||||||
+ [
|
|
||||||
+ {:database, compile_config!(:database_name)},
|
|
||||||
+ {:username, compile_config!(:database_user)},
|
|
||||||
+ {:port, compile_config!(:database_port)},
|
|
||||||
+ {:pool_size, compile_config!(:database_pool_size)},
|
|
||||||
+ {:ssl, compile_config!(:database_ssl_enabled)},
|
|
||||||
+ {:ssl_opts, compile_config!(:database_ssl_opts)},
|
|
||||||
+ {:parameters, compile_config!(:database_parameters)}
|
|
||||||
+ ] ++
|
|
||||||
+ if(compile_config(:database_password),
|
|
||||||
+ do: [{:password, compile_config!(:database_password)}],
|
|
||||||
+ else: []
|
|
||||||
+ ) ++
|
|
||||||
+ if(compile_config(:database_socket_dir),
|
|
||||||
+ do: [{:socket_dir, compile_config!(:database_socket_dir)}],
|
|
||||||
+ else: [{:hostname, compile_config!(:database_host)}]
|
|
||||||
+ )
|
|
||||||
|
|
||||||
config :domain, Domain.Tokens,
|
|
||||||
key_base: compile_config!(:tokens_key_base),
|
|
|
@ -1,94 +0,0 @@
|
||||||
diff --git a/apps/domain/lib/domain/config/definitions.ex b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
index 8cd2e8d0f..2e6ca054b 100644
|
|
||||||
--- a/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
+++ b/apps/domain/lib/domain/config/definitions.ex
|
|
||||||
@@ -584,6 +584,7 @@ defmodule Domain.Config.Definitions do
|
|
||||||
Swoosh.Adapters.Mailgun,
|
|
||||||
Swoosh.Adapters.Mailjet,
|
|
||||||
Swoosh.Adapters.Mandrill,
|
|
||||||
+ Swoosh.Adapters.Mua,
|
|
||||||
Swoosh.Adapters.Postmark,
|
|
||||||
Swoosh.Adapters.ProtonBridge,
|
|
||||||
Swoosh.Adapters.SMTP,
|
|
||||||
diff --git a/apps/web/lib/web/live/sign_up.ex b/apps/web/lib/web/live/sign_up.ex
|
|
||||||
index dfbc94d9b..638e3b373 100644
|
|
||||||
--- a/apps/web/lib/web/live/sign_up.ex
|
|
||||||
+++ b/apps/web/lib/web/live/sign_up.ex
|
|
||||||
@@ -1,5 +1,6 @@
|
|
||||||
defmodule Web.SignUp do
|
|
||||||
use Web, {:live_view, layout: {Web.Layouts, :public}}
|
|
||||||
+ require Logger
|
|
||||||
alias Domain.{Auth, Accounts, Actors, Config}
|
|
||||||
alias Web.Registration
|
|
||||||
|
|
||||||
@@ -358,7 +359,9 @@ defmodule Web.SignUp do
|
|
||||||
|
|
||||||
{:noreply, assign(socket, form: to_form(changeset))}
|
|
||||||
|
|
||||||
- {:error, :send_email, _reason, _effects_so_far} ->
|
|
||||||
+ {:error, :send_email, reason, _effects_so_far} ->
|
|
||||||
+ Logger.warning("Failed to send sign_up email", reason: inspect(reason))
|
|
||||||
+
|
|
||||||
changeset =
|
|
||||||
Ecto.Changeset.add_error(
|
|
||||||
changeset,
|
|
||||||
diff --git a/config/runtime.exs b/config/runtime.exs
|
|
||||||
index 7817942fa..8704ccde5 100644
|
|
||||||
--- a/config/runtime.exs
|
|
||||||
+++ b/config/runtime.exs
|
|
||||||
@@ -228,7 +228,21 @@ if config_env() == :prod do
|
|
||||||
[
|
|
||||||
adapter: compile_config!(:outbound_email_adapter),
|
|
||||||
from_email: compile_config!(:outbound_email_from)
|
|
||||||
- ] ++ compile_config!(:outbound_email_adapter_opts)
|
|
||||||
+ ] ++
|
|
||||||
+ (if System.get_env("OUTBOUND_EMAIL_ADAPTER") == "Elixir.Swoosh.Adapters.Mua" do
|
|
||||||
+ [
|
|
||||||
+ protocol: String.to_atom(System.get_env("OUTBOUND_EMAIL_SMTP_PROTOCOL")),
|
|
||||||
+ relay: System.get_env("OUTBOUND_EMAIL_SMTP_HOST"),
|
|
||||||
+ port: String.to_integer(System.get_env("OUTBOUND_EMAIL_SMTP_PORT")),
|
|
||||||
+ auth: [
|
|
||||||
+ username: System.get_env("OUTBOUND_EMAIL_SMTP_USERNAME"),
|
|
||||||
+ password: System.get_env("OUTBOUND_EMAIL_SMTP_PASSWORD")
|
|
||||||
+ ]
|
|
||||||
+ ]
|
|
||||||
+ else
|
|
||||||
+ []
|
|
||||||
+ end) ++
|
|
||||||
+ compile_config!(:outbound_email_adapter_opts)
|
|
||||||
|
|
||||||
config :workos, WorkOS.Client,
|
|
||||||
api_key: compile_config!(:workos_api_key),
|
|
||||||
diff --git a/mix.exs b/mix.exs
|
|
||||||
index 12782d631..dee1245d2 100644
|
|
||||||
--- a/mix.exs
|
|
||||||
+++ b/mix.exs
|
|
||||||
@@ -47,7 +47,9 @@ defmodule Firezone.MixProject do
|
|
||||||
# Formatter doesn't track dependencies of children applications
|
|
||||||
{:phoenix, "~> 1.7.0"},
|
|
||||||
{:phoenix_live_view, "~> 1.0.0-rc.0"},
|
|
||||||
- {:floki, "~> 0.37.0"}
|
|
||||||
+ {:floki, "~> 0.37.0"},
|
|
||||||
+ {:mua, "~> 0.2.0"},
|
|
||||||
+ {:mail, "~> 0.3.0"}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
diff --git a/mix.lock b/mix.lock
|
|
||||||
index 757829003..47775677d 100644
|
|
||||||
--- a/mix.lock
|
|
||||||
+++ b/mix.lock
|
|
||||||
@@ -50,11 +50,13 @@
|
|
||||||
"junit_formatter": {:hex, :junit_formatter, "3.4.0", "d0e8db6c34dab6d3c4154c3b46b21540db1109ae709d6cf99ba7e7a2ce4b1ac2", [:mix], [], "hexpm", "bb36e2ae83f1ced6ab931c4ce51dd3dbef1ef61bb4932412e173b0cfa259dacd"},
|
|
||||||
"libcluster": {:hex, :libcluster, "3.3.3", "a4f17721a19004cfc4467268e17cff8b1f951befe428975dd4f6f7b84d927fe0", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7c0a2275a0bb83c07acd17dab3c3bfb4897b145106750eeccc62d302e3bdfee5"},
|
|
||||||
"logger_json": {:hex, :logger_json, "6.2.0", "13e2e9f5f7b195865c5c3ef3d296c3ad50e7ecb038d899433702a79e979b91d7", [:mix], [{:ecto, "~> 3.11", [hex: :ecto, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "98366d02bedbb56e41b25a6d248d566d4f4bc224bae2b1e982df00ed04ba9219"},
|
|
||||||
+ "mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"},
|
|
||||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
|
||||||
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
|
||||||
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
|
|
||||||
"mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"},
|
|
||||||
"mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"},
|
|
||||||
+ "mua": {:hex, :mua, "0.2.4", "a9172ab0a1ac8732cf2699d739ceac3febcb9b4ffc540260ad2e32c0b6632af9", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "e7e4dacd5ad65f13e3542772e74a159c00bd2d5579e729e9bb72d2c73a266fb7"},
|
|
||||||
"multipart": {:hex, :multipart, "0.4.0", "634880a2148d4555d050963373d0e3bbb44a55b2badd87fa8623166172e9cda0", [:mix], [{:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "3c5604bc2fb17b3137e5d2abdf5dacc2647e60c5cc6634b102cf1aef75a06f0a"},
|
|
||||||
"nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"},
|
|
||||||
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
|
|
@ -1,135 +0,0 @@
|
||||||
{
|
|
||||||
mixReleaseName, # "domain" "web" or "api"
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
nixosTests,
|
|
||||||
fetchFromGitHub,
|
|
||||||
beamPackages,
|
|
||||||
pnpm_9,
|
|
||||||
nodejs,
|
|
||||||
tailwindcss,
|
|
||||||
esbuild,
|
|
||||||
}:
|
|
||||||
|
|
||||||
beamPackages.mixRelease rec {
|
|
||||||
pname = "firezone-server-${mixReleaseName}";
|
|
||||||
version = "unstable-2025-01-19";
|
|
||||||
|
|
||||||
src = "${
|
|
||||||
fetchFromGitHub {
|
|
||||||
owner = "firezone";
|
|
||||||
repo = "firezone";
|
|
||||||
rev = "8c9427b7b133e5050be34c2ac0e831c12c08f02c";
|
|
||||||
hash = "sha256-yccplADHRJQQiKrmHcJ5rvouswHrbx4K6ysnIAoZJR0=";
|
|
||||||
}
|
|
||||||
}/elixir";
|
|
||||||
patches = [
|
|
||||||
./0000-add-healthz-port.patch
|
|
||||||
./0001-postgres-socket.patch
|
|
||||||
./0002-add-mua.patch
|
|
||||||
];
|
|
||||||
|
|
||||||
pnpmDeps = pnpm_9.fetchDeps {
|
|
||||||
inherit pname version;
|
|
||||||
src = "${src}/apps/web/assets";
|
|
||||||
hash = "sha256-6rhhGv3jQY5MkOMNe1GEtNyrzJYXCSzvo8RLlKelP10=";
|
|
||||||
};
|
|
||||||
pnpmRoot = "apps/web/assets";
|
|
||||||
|
|
||||||
preBuild = ''
|
|
||||||
cat >> config/config.exs <<EOF
|
|
||||||
config :tailwind, path: "${lib.getExe tailwindcss}"
|
|
||||||
config :esbuild, path: "${lib.getExe esbuild}"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat >> config/runtime.exs <<EOF
|
|
||||||
config :tzdata, :data_dir, System.get_env("TZDATA_DIR")
|
|
||||||
EOF
|
|
||||||
'';
|
|
||||||
|
|
||||||
postBuild = ''
|
|
||||||
pushd apps/web
|
|
||||||
# for external task you need a workaround for the no deps check flag
|
|
||||||
# https://github.com/phoenixframework/phoenix/issues/2690
|
|
||||||
mix do deps.loadpaths --no-deps-check, assets.deploy
|
|
||||||
mix do deps.loadpaths --no-deps-check, phx.digest priv/static
|
|
||||||
popd
|
|
||||||
'';
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pnpm_9
|
|
||||||
pnpm_9.configHook
|
|
||||||
nodejs
|
|
||||||
];
|
|
||||||
|
|
||||||
inherit mixReleaseName;
|
|
||||||
|
|
||||||
# https://github.com/elixir-cldr/cldr_numbers/pull/52
|
|
||||||
mixNixDeps = import ./mix.nix {
|
|
||||||
inherit lib beamPackages;
|
|
||||||
overrides =
|
|
||||||
final: prev:
|
|
||||||
(lib.mapAttrs (
|
|
||||||
_: value:
|
|
||||||
value.override {
|
|
||||||
appConfigPath = src + "/config";
|
|
||||||
}
|
|
||||||
) prev)
|
|
||||||
// {
|
|
||||||
ex_cldr_numbers = beamPackages.buildMix rec {
|
|
||||||
name = "ex_cldr_numbers";
|
|
||||||
version = "2.33.4";
|
|
||||||
|
|
||||||
src = beamPackages.fetchHex {
|
|
||||||
pkg = "ex_cldr_numbers";
|
|
||||||
version = "${version}";
|
|
||||||
sha256 = "sha256-0Vt+IX6eYMMo5zBF5R3GfXrF0plyR7gz76ssabLtBvU=";
|
|
||||||
};
|
|
||||||
|
|
||||||
beamDeps = [
|
|
||||||
final.decimal
|
|
||||||
final.digital_token
|
|
||||||
final.ex_cldr
|
|
||||||
final.ex_cldr_currencies
|
|
||||||
final.jason
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# mix2nix does not support git dependencies yet,
|
|
||||||
# so we need to add them manually
|
|
||||||
openid_connect = beamPackages.buildMix {
|
|
||||||
name = "openid_connect";
|
|
||||||
version = "2024-06-15-unstable";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "firezone";
|
|
||||||
repo = "openid_connect";
|
|
||||||
rev = "e4d9dca8ae43c765c00a7d3dfa12d6f24f5b3418";
|
|
||||||
hash = "sha256-LMmG+WWs83Hw/jcrersUMpk2tdXxkOU0CTe7qVbk6GQ=";
|
|
||||||
};
|
|
||||||
beamDeps = [
|
|
||||||
final.jason
|
|
||||||
final.finch
|
|
||||||
final.jose
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
passthru.tests = {
|
|
||||||
inherit (nixosTests) firezone;
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "Backend server for the Firezone zero-trust access platform";
|
|
||||||
homepage = "https://github.com/firezone/firezone";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
oddlama
|
|
||||||
patrickdag
|
|
||||||
];
|
|
||||||
mainProgram = mixReleaseName;
|
|
||||||
platforms = lib.platforms.linux;
|
|
||||||
};
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +0,0 @@
|
||||||
import ./generic.nix {
|
|
||||||
mixReleaseName = "domain";
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
import ../firezone-server-domain/generic.nix {
|
|
||||||
mixReleaseName = "web";
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue