started soteria homeconfiguration
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
let
|
let
|
||||||
username = "john";
|
username = "john";
|
||||||
hostname = "john-pc-ubuntu";
|
hostname = "john-pc-ubuntu";
|
||||||
testTarget = "fded:fb16:653e:25da:be24:11ff:fea0:753f";
|
# testTarget = "fded:fb16:653e:25da:be24:11ff:fea0:753f";
|
||||||
|
testTarget = "fded:fb16:653e:25da:be24:11ff:fe89:1cc3";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.modules.homeManager."${hostname}" = { pkgs, config, ... }:
|
flake.modules.homeManager."${hostname}" = { pkgs, config, ... }:
|
||||||
@@ -34,28 +35,14 @@ in
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
nixos-rebuild
|
nixos-rebuild
|
||||||
(writeShellScriptBin "test-push" ''
|
(writeShellScriptBin "test-push" ''
|
||||||
nixos-rebuild switch --flake ${flakeDir}#soteria --target-host root@${testTarget}
|
mkdir -p /var/tmp/nix-build
|
||||||
|
chmod 1777 /var/tmp/nix-build
|
||||||
|
nixos-rebuild switch \
|
||||||
|
--flake ${flakeDir}#john-pc-ubuntu \
|
||||||
|
--target-host root@${testTarget}
|
||||||
'')
|
'')
|
||||||
];
|
];
|
||||||
|
|
||||||
mtls = {
|
|
||||||
enable = true;
|
|
||||||
caURL = "https://janus.john-stream.com/";
|
|
||||||
provisioner = "admin";
|
|
||||||
subject = hostname;
|
|
||||||
san = [
|
|
||||||
"${hostname}"
|
|
||||||
"192.168.1.85"
|
|
||||||
"spiffe://john-stream.com/ubuntu"
|
|
||||||
];
|
|
||||||
lifetime = "1h";
|
|
||||||
renew.onCalendar = "*:1/10";
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: Add host-specific settings here:
|
|
||||||
# - sops secret for `restic_password/john_ubuntu`
|
|
||||||
# - zsh RESTIC* session variables
|
|
||||||
|
|
||||||
# TODO: make this more restrictive, rather than allowing all unfree packages
|
# TODO: make this more restrictive, rather than allowing all unfree packages
|
||||||
nixpkgs.config.allowUnfree = true;
|
nixpkgs.config.allowUnfree = true;
|
||||||
nixpkgs.config.permittedInsecurePackages = [ "openssl-1.1.1w" ];
|
nixpkgs.config.permittedInsecurePackages = [ "openssl-1.1.1w" ];
|
||||||
@@ -93,6 +80,19 @@ in
|
|||||||
"/home/john/john-nas"
|
"/home/john/john-nas"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
mtls = {
|
||||||
|
enable = true;
|
||||||
|
caURL = "https://janus.john-stream.com/";
|
||||||
|
provisioner = "admin";
|
||||||
|
subject = hostname;
|
||||||
|
san = [
|
||||||
|
"${hostname}"
|
||||||
|
"192.168.1.85"
|
||||||
|
"spiffe://john-stream.com/ubuntu"
|
||||||
|
];
|
||||||
|
lifetime = "1h";
|
||||||
|
renew.onCalendar = "*:1/10";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
flake.homeConfigurations."${hostname}" = inputs.home-manager.lib.homeManagerConfiguration {
|
flake.homeConfigurations."${hostname}" = inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
|
|||||||
@@ -14,23 +14,51 @@ in
|
|||||||
nixos."${username}"
|
nixos."${username}"
|
||||||
nixos.zsh
|
nixos.zsh
|
||||||
nixos.login-text
|
nixos.login-text
|
||||||
nixos.mtls
|
# nixos.mtls
|
||||||
nixos.restic-server
|
# nixos.restic-server
|
||||||
|
# nixos.restic-envoy
|
||||||
{
|
{
|
||||||
networking.hostName = hostname;
|
networking.hostName = hostname;
|
||||||
|
nix.settings.build-dir = "/var/tmp/nix-build";
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/tmp/nix-build 1777 root root -"
|
||||||
|
];
|
||||||
step-ssh-host = {
|
step-ssh-host = {
|
||||||
hostname = hostname;
|
hostname = hostname;
|
||||||
caURL = caURL;
|
caURL = caURL;
|
||||||
};
|
};
|
||||||
mtls = {
|
# mtls = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
subject = hostname;
|
# subject = hostname;
|
||||||
caURL = caURL;
|
# caURL = caURL;
|
||||||
san = [
|
# san = [
|
||||||
"${hostname}.john-stream.com"
|
# "${hostname}.john-stream.com"
|
||||||
# "192.168.1.244"
|
# # "192.168.1.244"
|
||||||
];
|
# ];
|
||||||
};
|
# };
|
||||||
|
|
||||||
|
# restic.envoy = {
|
||||||
|
# enable = true;
|
||||||
|
# port = 10000;
|
||||||
|
# spiffePrefix = "spiffe://john-stream.com";
|
||||||
|
# upstreamHost = "127.0.0.1";
|
||||||
|
# upstreamPort = 8000;
|
||||||
|
# logLevel = "debug";
|
||||||
|
# policies = {
|
||||||
|
# ubuntu-policy = {
|
||||||
|
# pathPrefix = "/john-ubuntu";
|
||||||
|
# principal = "spiffe://john-stream.com/ubuntu";
|
||||||
|
# };
|
||||||
|
# p14-policy = {
|
||||||
|
# pathPrefix = "/john-p14s";
|
||||||
|
# principal = "spiffe://john-stream.com/john-p14s";
|
||||||
|
# };
|
||||||
|
# gitea-policy = {
|
||||||
|
# pathPrefix = "/gitea";
|
||||||
|
# principal = "spiffe://john-stream.com/gitea";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
home-manager.users."${username}" = {
|
home-manager.users."${username}" = {
|
||||||
imports = with inputs.self.modules.homeManager; [
|
imports = with inputs.self.modules.homeManager; [
|
||||||
@@ -42,4 +70,11 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
flake.homeConfigurations."${hostname}" = inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
|
pkgs = import inputs.nixpkgs { system = "x86_64-linux"; };
|
||||||
|
modules = with inputs.self.modules; [
|
||||||
|
homeManager."${hostname}"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
323
modules/services/restic/envoy.nix
Normal file
323
modules/services/restic/envoy.nix
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
flake.modules.nixos.restic-envoy = { config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.restic.envoy;
|
||||||
|
|
||||||
|
envoyConfig = {
|
||||||
|
static_resources = {
|
||||||
|
listeners = [
|
||||||
|
{
|
||||||
|
name = "listener_0";
|
||||||
|
address.socket_address = {
|
||||||
|
address = cfg.listenAddress;
|
||||||
|
port_value = cfg.port;
|
||||||
|
};
|
||||||
|
filter_chains = [
|
||||||
|
{
|
||||||
|
filter_chain_match.server_names = cfg.serverNames;
|
||||||
|
transport_socket = {
|
||||||
|
name = "envoy.transport_sockets.tls";
|
||||||
|
typed_config = {
|
||||||
|
"@type" = "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext";
|
||||||
|
require_client_certificate = true;
|
||||||
|
common_tls_context = {
|
||||||
|
tls_params.tls_minimum_protocol_version = "TLSv1_3";
|
||||||
|
validation_context = {
|
||||||
|
trusted_ca.filename = cfg.trustedCAPath;
|
||||||
|
match_typed_subject_alt_names = [
|
||||||
|
{
|
||||||
|
san_type = "URI";
|
||||||
|
matcher.prefix = cfg.spiffePrefix;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
tls_certificates = [
|
||||||
|
{
|
||||||
|
certificate_chain.filename = cfg.certificatePath;
|
||||||
|
private_key.filename = cfg.pkcs8PrivateKeyPath;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
filters = [
|
||||||
|
{
|
||||||
|
name = "envoy.filters.network.http_connection_manager";
|
||||||
|
typed_config = {
|
||||||
|
"@type" = "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager";
|
||||||
|
stat_prefix = "ingress_http";
|
||||||
|
use_remote_address = true;
|
||||||
|
http2_protocol_options.max_concurrent_streams = 100;
|
||||||
|
access_log = [
|
||||||
|
{
|
||||||
|
name = "envoy.access_loggers.file";
|
||||||
|
typed_config = {
|
||||||
|
"@type" = "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog";
|
||||||
|
path = cfg.accessLogPath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
route_config = {
|
||||||
|
name = "local_route";
|
||||||
|
virtual_hosts = [
|
||||||
|
{
|
||||||
|
name = "local_service";
|
||||||
|
domains = [ "*" ];
|
||||||
|
routes = [
|
||||||
|
{
|
||||||
|
match.prefix = "/";
|
||||||
|
route.cluster = cfg.clusterName;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
http_filters = [
|
||||||
|
{
|
||||||
|
name = "envoy.filters.http.rbac";
|
||||||
|
typed_config = {
|
||||||
|
"@type" = "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC";
|
||||||
|
rules = {
|
||||||
|
action = "ALLOW";
|
||||||
|
policies = lib.mapAttrs (_: policy: {
|
||||||
|
permissions = [
|
||||||
|
{
|
||||||
|
and_rules.rules = [
|
||||||
|
{
|
||||||
|
header = {
|
||||||
|
name = ":path";
|
||||||
|
string_match.prefix = policy.pathPrefix;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
principals = [
|
||||||
|
{
|
||||||
|
authenticated.principal_name.exact = policy.principal;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}) cfg.policies;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "envoy.filters.http.router";
|
||||||
|
typed_config = {
|
||||||
|
"@type" = "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
clusters = [
|
||||||
|
{
|
||||||
|
name = cfg.clusterName;
|
||||||
|
connect_timeout = cfg.connectTimeout;
|
||||||
|
type = "STRICT_DNS";
|
||||||
|
lb_policy = "ROUND_ROBIN";
|
||||||
|
load_assignment = {
|
||||||
|
cluster_name = cfg.clusterName;
|
||||||
|
endpoints = [
|
||||||
|
{
|
||||||
|
lb_endpoints = [
|
||||||
|
{
|
||||||
|
endpoint.address.socket_address = {
|
||||||
|
address = cfg.upstreamHost;
|
||||||
|
port_value = cfg.upstreamPort;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configFile = (pkgs.formats.json { }).generate "restic-envoy.json" envoyConfig;
|
||||||
|
ensurePkcs8Key = pkgs.writeShellScript "restic-envoy-prepare-key" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
install -d -m 0750 /run/restic-envoy
|
||||||
|
${lib.getExe pkgs.openssl} pkcs8 \
|
||||||
|
-topk8 \
|
||||||
|
-nocrypt \
|
||||||
|
-in ${lib.escapeShellArg cfg.sourcePrivateKeyPath} \
|
||||||
|
-out ${lib.escapeShellArg cfg.pkcs8PrivateKeyPath}
|
||||||
|
chmod 0600 ${lib.escapeShellArg cfg.pkcs8PrivateKeyPath}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.restic.envoy = {
|
||||||
|
enable = lib.mkEnableOption "an Envoy mTLS front-end for restic";
|
||||||
|
|
||||||
|
listenAddress = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "0.0.0.0";
|
||||||
|
description = "Address for Envoy to bind to.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
default = 10000;
|
||||||
|
description = "TCP port for the Envoy listener.";
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Open the configured listener port in the firewall.";
|
||||||
|
};
|
||||||
|
|
||||||
|
serverNames = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "*.john-stream.com" ];
|
||||||
|
description = "Accepted SNI server names for the downstream TLS filter chain.";
|
||||||
|
};
|
||||||
|
|
||||||
|
spiffePrefix = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "spiffe://john-stream.com";
|
||||||
|
description = "Allowed SPIFFE URI prefix for client certificate SAN validation.";
|
||||||
|
};
|
||||||
|
|
||||||
|
trustedCAPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/etc/step/certs/root_ca.crt";
|
||||||
|
description = "Path to the CA certificate used to validate client certificates.";
|
||||||
|
};
|
||||||
|
|
||||||
|
certificatePath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/etc/step/certs/cert.pem";
|
||||||
|
description = "Path to the server certificate presented by Envoy.";
|
||||||
|
};
|
||||||
|
|
||||||
|
sourcePrivateKeyPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/etc/step/certs/key.pem";
|
||||||
|
description = "Path to the source private key that will be converted to PKCS#8 for Envoy.";
|
||||||
|
};
|
||||||
|
|
||||||
|
pkcs8PrivateKeyPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/run/restic-envoy/key_pkcs8.pem";
|
||||||
|
description = "Path to the PKCS#8 private key file consumed by Envoy.";
|
||||||
|
};
|
||||||
|
|
||||||
|
accessLogPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/log/envoy/access.log";
|
||||||
|
description = "Path for the Envoy HTTP access log.";
|
||||||
|
};
|
||||||
|
|
||||||
|
clusterName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "restic";
|
||||||
|
description = "Name of the upstream Envoy cluster.";
|
||||||
|
};
|
||||||
|
|
||||||
|
connectTimeout = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "0.25s";
|
||||||
|
description = "Cluster connect timeout in Envoy duration format.";
|
||||||
|
};
|
||||||
|
|
||||||
|
upstreamHost = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "rest-server";
|
||||||
|
description = "DNS name or IP address for the upstream restic server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
upstreamPort = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
default = 8000;
|
||||||
|
description = "TCP port for the upstream restic server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
logLevel = lib.mkOption {
|
||||||
|
type = lib.types.enum [ "trace" "debug" "info" "warning" "error" "critical" "off" ];
|
||||||
|
default = "info";
|
||||||
|
description = "Envoy application log level.";
|
||||||
|
};
|
||||||
|
|
||||||
|
policies = lib.mkOption {
|
||||||
|
description = "RBAC policy definitions keyed by Envoy policy name.";
|
||||||
|
type = lib.types.attrsOf (lib.types.submodule ({ ... }: {
|
||||||
|
options = {
|
||||||
|
pathPrefix = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Allowed HTTP path prefix for this principal.";
|
||||||
|
};
|
||||||
|
|
||||||
|
principal = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Exact SPIFFE principal required for this path prefix.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
default = {
|
||||||
|
ubuntu-policy = {
|
||||||
|
pathPrefix = "/john-ubuntu";
|
||||||
|
principal = "spiffe://john-stream.com/ubuntu";
|
||||||
|
};
|
||||||
|
p14-policy = {
|
||||||
|
pathPrefix = "/john-p14s";
|
||||||
|
principal = "spiffe://john-stream.com/john-p14s";
|
||||||
|
};
|
||||||
|
gitea-policy = {
|
||||||
|
pathPrefix = "/gitea";
|
||||||
|
principal = "spiffe://john-stream.com/gitea";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.serverNames != [ ];
|
||||||
|
message = "restic.envoy.serverNames must not be empty.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.policies != { };
|
||||||
|
message = "restic.envoy.policies must define at least one RBAC policy.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.port ];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/log/envoy 0750 root root -"
|
||||||
|
"d /run/restic-envoy 0750 root root -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.restic-envoy = {
|
||||||
|
description = "Envoy reverse proxy for the restic server";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
restartIfChanged = true;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
ExecStartPre = ensurePkcs8Key;
|
||||||
|
ExecStart = "${lib.getExe pkgs.envoy} --config-path ${configFile} --log-level ${cfg.logLevel}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "5s";
|
||||||
|
RuntimeDirectory = "restic-envoy";
|
||||||
|
LogsDirectory = "envoy";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user