aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/apps/postgresql/default.nix31
-rw-r--r--modules/apps/postgresql/server.nix169
-rw-r--r--modules/deployment/default.nix2
-rw-r--r--modules/deployment/keyrings.nix155
-rw-r--r--modules/system/nixos.nix4
-rw-r--r--modules/system/users.nix2
6 files changed, 323 insertions, 40 deletions
diff --git a/modules/apps/postgresql/default.nix b/modules/apps/postgresql/default.nix
index e7eecaa..9ac2a27 100644
--- a/modules/apps/postgresql/default.nix
+++ b/modules/apps/postgresql/default.nix
@@ -68,21 +68,46 @@ let
concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${show n v}") (explicit opts.server))
);
- preStart = ''
+
+ # FIXME: There is a bash builtin "csv", but it fails on a complicated,
+ # FIXME: but still valid string like '/tmp, "/xx, yy", "/foo"'.
+ # FIXME: Ref. https://www.postgresql.org/docs/current/runtime-config-connection.html
+ # XXX: order of options is important for postgres.
+ main-pre = pkgs.writeBashScriptBin "pgsql-${name}-pre" ''
+ set -euo pipefail
+
mkdir -v -p '${data_directory}'
chown -R '${user}:${user}' '${data_directory}'
chmod -R u=rwX,g=,o= '${data_directory}'
+
+ mkdirs() {
+ for d in "$@"; do
+ case $d in
+ @*)
+ ;;
+ *)
+ mkdir -p -v "$d"
+ chmod -c a=rwxt "$d"
+ ;;
+ esac
+ done
+ }
+ export -f mkdirs
+
+ ${pkgs.csvtool}/bin/csvtool call mkdirs <(${opts.package}/bin/postgres -C unix_socket_directories --config-file='${conf}')
'';
main = pkgs.writeBashScriptBin "pgsql-${name}" ''
set -euo pipefail
+
if [ ! -f '${data_directory}/PG_VERSION' ]; then
${initdb} '${data_directory}'
rm -f '${data_directory}/'*hba.conf
rm -f '${data_directory}/'*ident.conf
rm -f '${data_directory}/postgresql.conf'
fi
- exec '${opts.package}/bin/postgres' -c 'config_file=${conf}'
+
+ exec ${opts.package}/bin/postgres --config-file='${conf}'
'';
psql = "${opts.package}/bin/psql -v ON_ERROR_STOP=1 -p${toString port} -U postgres";
@@ -114,8 +139,8 @@ let
wantedBy = [ "multi-user.target" ];
wants = [ "keys.target" ];
after = [ "keys.target" "network.target" "local-fs.target" ];
- inherit preStart;
serviceConfig = {
+ ExecStartPre = "${main-pre}/bin/pgsql-${name}-pre";
ExecStart = "${main}/bin/pgsql-${name}";
KillMode = "mixed";
KillSignal = "SIGINT";
diff --git a/modules/apps/postgresql/server.nix b/modules/apps/postgresql/server.nix
index c24494c..baafb35 100644
--- a/modules/apps/postgresql/server.nix
+++ b/modules/apps/postgresql/server.nix
@@ -19,12 +19,12 @@ let
in {
options = {
- DateStyle = optional str;
- IntervalStyle = optional (enum [ "sql_standard" "postgres_verbose" "iso_8601" ]);
- TimeZone = optional str;
+ allow_alter_system = optional bool;
application_name = optional str;
+ archive_cleanup_command = optional path;
archive_command = optional path;
- archive_mode = optional bool;
+ archive_library = optional path;
+ archive_mode = optional (enum [ "always" "on" "off" ]);
archive_timeout = optional int;
array_nulls = optional bool;
authentication_timeout = optional int;
@@ -37,58 +37,93 @@ in {
autovacuum_naptime = optional int;
autovacuum_vacuum_cost_delay = optional int;
autovacuum_vacuum_cost_limit = optional int;
+ autovacuum_vacuum_insert_scale_factor = optional float;
+ autovacuum_vacuum_insert_threshold = optional int;
+ autovacuum_vacuum_max_threshold = optional int;
autovacuum_vacuum_scale_factor = optional float;
autovacuum_vacuum_threshold = optional int;
autovacuum_work_mem = optional int;
+ autovacuum_worker_slots = optional int;
+ backend_flush_after = optional int;
backslash_quote = optional (enum [ "on" "off" "safe_encoding" ]);
bgwriter_delay = optional int;
+ bgwriter_flush_after = optional int;
bgwriter_lru_maxpages = optional int;
bgwriter_lru_multiplier = optional int;
+ bonjour = optional bool;
+ bonjour_name = optional str;
bytea_output = optional (enum [ "hex" "escape" ]);
check_function_bodies = optional bool;
checkpoint_completion_target = optional float;
+ checkpoint_flush_after = optional int;
checkpoint_segments = optional int;
checkpoint_timeout = optional int;
checkpoint_warning = optional int;
+ client_connection_check_interval = optional int;
client_encoding = optional str;
- client_min_messages = optional (enum [ "DEBUG5" "DEBUG4" "DEBUG3" "DEBUG2" "DEBUG1" "LOG" "NOTICE" "WARNING" "ERROR" "FATAL" "PANIC" ]);
+ client_min_messages = optional (enum [ "DEBUG5" "DEBUG4" "DEBUG3" "DEBUG2" "DEBUG1" "LOG" "NOTICE" "WARNING" "ERROR" ]);
+ cluster_name = optional str;
commit_delay = optional int;
commit_siblings = optional int;
+ commit_timestamp_buffers = optional int;
+ compute_query_id = optional (enum [ "off" "on" "auto" "regress" ]);
constraint_exclusion = optional (enum [ "on" "partition" "off" ]);
cpu_index_tuple_cost = optional float;
cpu_operator_cost = optional float;
cpu_tuple_cost = optional float;
cursor_tuple_fraction = optional float;
data_directory = mandatory path;
+ data_sync_retry = optional bool;
+ DateStyle = optional str;
deadlock_timeout = optional int;
debug_pretty_print = optional bool;
debug_print_parse = optional bool;
debug_print_plan = optional bool;
debug_print_rewritten = optional bool;
default_statistics_target = optional int;
+ default_table_access_method = optional str;
default_tablespace = optional str;
default_text_search_config = optional str;
+ default_toast_compression = optional (enum [ "pglz" "lz4" ]);
default_transaction_deferrable = optional bool;
default_transaction_isolation = optional (enum [ "read uncommitted" "read committed" "repeatable read" "serializable" ]);
default_transaction_read_only = optional bool;
default_with_oids = optional bool;
- dynamic_shared_memory_type = optional (enum [ "posix" "sysv" "mmap" "none" ]);
+ dynamic_library_path = optional str;
+ dynamic_shared_memory_type = optional (enum [ "posix" "sysv" "mmap" ]);
effective_cache_size = optional int;
effective_io_concurrency = optional int;
+ enable_async_append = optional bool;
enable_bitmapscan = optional bool;
+ enable_distinct_reordering = optional bool;
+ enable_gathermerge = optional bool;
+ enable_group_by_reordering = optional bool;
enable_hashagg = optional bool;
enable_hashjoin = optional bool;
+ enable_incremental_sort = optional bool;
enable_indexonlyscan = optional bool;
enable_indexscan = optional bool;
enable_material = optional bool;
+ enable_memoize = optional bool;
enable_mergejoin = optional bool;
enable_nestloop = optional bool;
+ enable_parallel_append = optional bool;
+ enable_parallel_hash = optional bool;
+ enable_partition_pruning = optional bool;
+ enable_partitionwise_aggregate = optional bool;
+ enable_partitionwise_join = optional bool;
+ enable_presorted_aggregate = optional bool;
+ enable_self_join_elimination = optional bool;
enable_seqscan = optional bool;
enable_sort = optional bool;
enable_tidscan = optional bool;
escape_string_warning = optional bool;
+ event_source = optional str;
exit_on_error = optional bool;
+ extension_control_path = optional str;
extra_float_digits = optional int;
+ file_copy_method = optional (enum [ "COPY" "CLONE" ]);
+ file_extend_method = optional (enum [ "posix_fallocate" "write_zeros" ]);
from_collapse_limit = optional int;
fsync = optional bool;
full_page_writes = optional bool;
@@ -99,117 +134,233 @@ in {
geqo_seed = optional float;
geqo_selection_bias = optional float;
geqo_threshold = optional int;
+ gin_fuzzy_search_limit = optional int;
+ gss_accept_delegation = optional bool;
+ hash_mem_multiplier = optional float;
hba_file = default "" lines;
hot_standby = optional bool;
hot_standby_feedback = optional bool;
+ huge_page_size = optional int;
huge_pages = optional (enum [ "on" "off" "try" ]);
+ icu_validation_level = optional (enum [ "DISABLED" "DEBUG5" "DEBUG4" "DEBUG3" "DEBUG2" "DEBUG1" "LOG" "INFO" "NOTICE" "WARNING" "ERROR" ]);
ident_file = default "" lines;
+ idle_replication_slot_timeout = optional int;
+ IntervalStyle = optional (enum [ "sql_standard" "postgres" "postgres_verbose" "iso_8601" ]);
+ io_combine_limit = optional int;
+ io_max_combine_limit = optional int;
+ io_max_concurrency = optional int;
+ io_method = optional (enum [ "worker" "io_uring" "sync" ]);
+ io_workers = optional int;
+ jit = optional bool;
+ jit_above_cost = optional float;
+ jit_inline_above_cost = optional float;
+ jit_optimize_above_cost = optional float;
+ jit_provider = optional str;
join_collapse_limit = optional int;
+ krb_caseins_users = optional bool;
+ krb_server_keyfile = optional path;
lc_messages = optional str;
lc_monetary = optional str;
lc_numeric = optional str;
lc_time = optional str;
listen_addresses = optional (either (listOf str) str);
lo_compat_privileges = optional bool;
+ local_preload_libraries = optional (either (listOf str) str);
lock_timeout = optional int;
log_autovacuum_min_duration = optional int;
log_checkpoints = optional bool;
- log_connections = optional bool;
- log_destination = optional (enum [ "stderr" "csvlog" "syslog" ]);
+ log_connections = let x = enum [ "receipt" "authentication" "authorization" "setup_durations" "all"]; in optional (either (listOf x) x);
+ log_destination = let x = enum [ "stderr" "csvlog" "syslog" "jsonlog" ]; in optional (either (listOf x) x);
log_directory = optional path;
log_disconnections = optional bool;
log_duration = optional bool;
log_error_verbosity = optional (enum [ "TERSE" "DEFAULT" "VERBOSE" ]);
log_executor_stats = optional bool;
+ log_file_mode = optional int;
log_filename = optional str;
log_hostname = optional bool;
log_line_prefix = optional str;
+ log_lock_failures = optional bool;
log_lock_waits = optional bool;
+ log_min_duration_sample = optional int;
log_min_duration_statement = optional int;
log_min_error_statement = optional (enum [ "DEBUG5" "DEBUG4" "DEBUG3" "DEBUG2" "DEBUG1" "LOG" "NOTICE" "WARNING" "ERROR" "FATAL" "PANIC" ]);
log_min_messages = optional (enum [ "DEBUG5" "DEBUG4" "DEBUG3" "DEBUG2" "DEBUG1" "LOG" "NOTICE" "WARNING" "ERROR" "FATAL" "PANIC" ]);
+ log_parameter_max_length = optional int;
+ log_parameter_max_length_on_error = optional int;
log_parser_stats = optional bool;
log_planner_stats = optional bool;
+ log_recovery_conflict_waits = optional bool;
+ log_replication_commands = optional bool;
log_rotation_age = optional int;
log_rotation_size = optional int;
+ log_startup_progress_interval = optional int;
log_statement = optional (enum [ "none" "ddl" "mod" "all" ]);
+ log_statement_sample_rate = optional float;
log_statement_stats = optional bool;
log_temp_files = optional int;
log_timezone = optional str;
+ log_transaction_sample_rate = optional float;
log_truncate_on_rotation = optional bool;
logging_collector = optional bool;
+ logical_decoding_work_mem = optional int;
+ maintenance_io_concurrency = optional int;
maintenance_work_mem = optional int;
+ max_active_replication_origins = optional int;
max_connections = optional int;
max_files_per_process = optional int;
max_locks_per_transaction = optional int;
+ max_logical_replication_workers = optional int;
+ max_notify_queue_pages = optional int;
+ max_parallel_apply_workers_per_subscription = optional int;
+ max_parallel_maintenance_workers = optional int;
+ max_parallel_workers = optional int;
+ max_parallel_workers_per_gather = optional int;
+ max_pred_locks_per_page = optional int;
+ max_pred_locks_per_relation = optional int;
max_pred_locks_per_transaction = optional int;
max_prepared_transactions = optional int;
max_replication_slots = optional int;
+ max_slot_wal_keep_size = optional int;
max_stack_depth = optional int;
max_standby_archive_delay = optional int;
max_standby_streaming_delay = optional int;
+ max_sync_workers_per_subscription = optional int;
max_wal_senders = optional int;
+ max_wal_size = optional int;
max_worker_processes = optional int;
+ min_dynamic_shared_memory = optional int;
+ min_parallel_index_scan_size = optional int;
+ min_parallel_table_scan_size = optional int;
+ min_wal_size = optional int;
+ multixact_member_buffers = optional int;
+ multixact_offset_buffers = optional int;
+ notify_buffers = optional int;
+ oauth_validator_libraries = optional str;
+ parallel_leader_participation = optional bool;
+ parallel_setup_cost = optional float;
+ parallel_tuple_cost = optional float;
password_encryption = optional (enum [ "md5" "scram-sha-256" ]);
+ plan_cache_mode = optional (enum [ "auto" "force_custom_plan" "force_generic_plan" ]);
port = default 5432 int;
+ primary_conninfo = optional str;
+ primary_slot_name = optional str;
quote_all_identifiers = optional bool;
random_page_cost = optional float;
+ recovery_end_command = optional path;
+ recovery_init_sync_method = optional (enum ["fsync" "syncfs"]);
+ recovery_min_apply_delay = optional int;
+ recovery_prefetch = optional (enum [ "on" "try" "off" ]);
+ recovery_target = optional str;
+ recovery_target_action = optional (enum ["pause" "promote" "shutdown"]);
+ recovery_target_inclusive = optional bool;
+ recovery_target_lsn = optional str;
+ recovery_target_name = optional str;
+ recovery_target_time = optional str;
+ recovery_target_timeline = optional str;
+ recovery_target_xid = optional str;
+ recursive_worktable_factor = optional float;
+ reserved_connections = optional int;
restart_after_crash = optional bool;
+ restore_command = optional path;
+ row_security = optional bool;
+ scram_iterations = optional int;
search_path = optional (either (listOf str) str);
seq_page_cost = optional float;
+ serializable_buffers = optional int;
+ session_preload_libraries = optional (either (listOf str) str);
session_replication_role = optional (enum [ "origin" "replica" "local" ]);
shared_buffers = optional int;
+ shared_memory_type = optional (enum [ "sysv" "mmap" ]);
+ shared_preload_libraries = optional (either (listOf str) str);
sql_inheritance = optional bool;
ssl = optional bool;
ssl_ca_file = optional path;
ssl_cert_file = optional path;
ssl_ciphers = optional str;
+ ssl_crl_dir = optional path;
ssl_crl_file = optional path;
+ ssl_dh_params_file = optional str;
ssl_ecdh_curve = optional str;
+ ssl_groups = optional str;
ssl_key_file = optional path;
+ ssl_max_protocol_version = optional (enum [ "TLSv1" "TLSv1.1" "TLSv1.2" "TLSv1.3" ]);
+ ssl_min_protocol_version = optional (enum [ "TLSv1" "TLSv1.1" "TLSv1.2" "TLSv1.3" ]);
ssl_prefer_server_ciphers = optional bool;
ssl_renegotiation_limit = optional int;
+ ssl_tls13_ciphers = optional str;
standard_conforming_strings = optional bool;
statement_timeout = optional int;
+ stats_fetch_consistency = optional (enum [ "none" "cache" "snapshot" ]);
stats_temp_directory = optional path;
+ subtransaction_buffers = optional int;
+ summarize_wal = optional bool;
superuser_reserved_connections = optional int;
+ sync_replication_slots = optional bool;
synchronize_seqscans = optional bool;
- synchronous_commit = optional (enum [ "on" "remote_write" "local" "off" ]);
+ synchronized_standby_slots = optional (either (listOf str) str);
+ synchronous_commit = optional (enum [ "on" "remote_write" "remote_apply" "local" "off" ]);
synchronous_standby_names = optional (either (listOf str) str);
+ syslog_facility = optional (enum [ "LOCAL0" "LOCAL1" "LOCAL2" "LOCAL3" "LOCAL4" "LOCAL5" "LOCAL6" "LOCAL7" ]);
syslog_ident = optional str;
+ syslog_sequence_numbers = optional bool;
+ syslog_split_messages = optional bool;
tcp_keepalives_count = optional int;
tcp_keepalives_idle = optional int;
tcp_keepalives_interval = optional int;
+ tcp_user_timeout = optional int;
temp_buffers = optional int;
temp_file_limit = optional int;
temp_tablespaces = optional str;
+ TimeZone = optional str;
timezone_abbreviations = optional str;
track_activities = optional bool;
track_activity_query_size = optional int;
+ track_commit_timestamp = optional bool;
+ track_cost_delay_timing = optional bool;
track_counts = optional bool;
track_functions = optional (enum [ "none" "pl" "all" ]);
track_io_timing = optional bool;
+ track_wal_io_timing = optional bool;
+ transaction_buffers = optional int;
transform_null_equals = optional bool;
+ unix_socket_group = optional str;
+ unix_socket_permissions = optional int;
update_process_title = optional bool;
+ vacuum_buffer_usage_limit = optional int;
vacuum_cost_delay = optional int;
vacuum_cost_limit = optional int;
vacuum_cost_page_dirty = optional int;
vacuum_cost_page_hit = optional int;
vacuum_cost_page_miss = optional int;
vacuum_defer_cleanup_age = optional int;
+ vacuum_failsafe_age = optional int;
vacuum_freeze_min_age = optional int;
vacuum_freeze_table_age = optional int;
+ vacuum_max_eager_freeze_failure_rate = optional float;
+ vacuum_multixact_failsafe_age = optional int;
vacuum_multixact_freeze_min_age = optional int;
vacuum_multixact_freeze_table_age = optional int;
+ vacuum_truncate = optional bool;
wal_buffers = optional int;
+ wal_compression = optional (enum [ "pglz" "lz4" "zstd" "off" ]);
+ wal_decode_buffer_size = optional int;
+ wal_init_zero = optional bool;
wal_keep_segments = optional int;
+ wal_keep_size = optional int;
wal_level = optional (enum [ "minimal" "replica" "logical" ]);
wal_log_hints = optional bool;
+ wal_receiver_create_temp_slot = optional bool;
wal_receiver_status_interval = optional int;
wal_receiver_timeout = optional int;
+ wal_recycle = optional bool;
+ wal_retrieve_retry_interval = optional int;
wal_sender_timeout = optional int;
+ wal_skip_threshold = optional int;
+ wal_summary_keep_time = optional int;
wal_sync_method = optional (enum [ "open_datasync" "fdatasync" "fsync" "fsync_writethrough" "open_sync" ]);
wal_writer_delay = optional int;
+ wal_writer_flush_after = optional int;
work_mem = optional int;
xmlbinary = optional (enum [ "base64" "hex" ]);
xmloption = optional (enum [ "DOCUMENT" "CONTENT" ]);
diff --git a/modules/deployment/default.nix b/modules/deployment/default.nix
index 240d970..9ef03e8 100644
--- a/modules/deployment/default.nix
+++ b/modules/deployment/default.nix
@@ -1,4 +1,4 @@
-{lib, ... }:
+{ lib, ... }:
let
all = lib.filterAttrs
diff --git a/modules/deployment/keyrings.nix b/modules/deployment/keyrings.nix
index 23a96d0..14c228a 100644
--- a/modules/deployment/keyrings.nix
+++ b/modules/deployment/keyrings.nix
@@ -1,47 +1,48 @@
-{ config, lib, ... }:
-
+{ config, lib, pkgs, ... }:
+
let
inherit (builtins)
- attrNames baseNameOf head match pathExists readFile ;
+ attrNames baseNameOf head map match
+ ;
inherit (lib)
- filter foldl genAttrs hasPrefix mapAttrsToList mkOption
- optionalAttrs unique ;
+ filter flip foldl genAttrs hasPrefix mapAttrs' mapAttrsToList mkOption
+ nameValuePair optionalAttrs unique
+ ;
inherit (lib.types)
- attrsOf listOf nullOr path ;
+ attrsOf either externalPath int listOf nullOr package path str submodule
+ ;
- allusers = config.users.users;
cfg = config.nixsap.deployment;
- # XXX If the file is encrypted:
- # error: the contents of the file ‘...’ cannot be represented as a Nix string
- read = key:
+ emptyKey = pkgs.writeText "empty" "";
+ getKeySource = key:
let
m = match "^(.+)@[^@]+$" key;
s = if m != null then head m else key;
in if cfg.secrets != null
- then readFile (cfg.secrets + "/${s}")
- else "";
+ then cfg.secrets + "/${s}"
+ else emptyKey;
in {
options.nixsap.deployment = {
secrets = mkOption {
description = ''
- Directory with the secrets on the deploy machine. If not specified,
- each key will be an empty file.
+ Directory with the secrets on the build machine. If not specified,
+ each key in the keyrings will be an empty file.
'';
- type = nullOr path;
+ type = nullOr externalPath;
default = null;
example = "<secrets>";
};
keyStore = mkOption {
description = ''
- Directory with the keys on the target machine. NixOps uses /run/keys,
- and this is default. If you use another deployment tool, you would
- like to set it to something else.
+ Directory with the keys on the target machine.
+ This directory will be created, its permissions changed to
+ ``0750`` and ownership to ``root:keys``.
'';
- type = path;
+ type = externalPath;
default = "/run/keys";
example = "/root/keys";
};
@@ -62,21 +63,121 @@ in {
pgbackup = [ "/run/keys/s3cmd.cfg@pgbackup" ];
};
};
+
+ keys = mkOption {
+ default = {};
+ description = ''
+ The set of keys to be deployed to the machine. Each attribute maps
+ a key name to a file that can be accessed as ``keyStore``/``name``.
+ A key is a file which cannot be in Nix store for security reasons,
+ e. g. it contains a password, a SSH private key, etc.
+ Each key also gets a systemd service ``<name>-key.service``
+ which is active while the key is present and inactive while the key
+ is absent.
+ '';
+
+ type = attrsOf (submodule ({name, config, ...}: {
+ options = {
+ source = mkOption {
+ description = ''
+ Local file contaning the key. The contents of this file will put on the machine
+ in a file maching the key's name.
+ '';
+ type = path;
+ };
+ uid = mkOption {
+ default = 0;
+ type = int;
+ description = ''
+ The user id that will be set for the key file.
+ '';
+ };
+ gid = mkOption {
+ default = 0;
+ type = int;
+ description = ''
+ The group id that will be set for the key file.
+ '';
+ };
+ mode = mkOption {
+ default = 400;
+ example = "0640";
+ type = int;
+ description = ''
+ The access mode that will be set for the key file.
+ Should be in a numeric form accepted by ``chmod(1)``.
+ '';
+ };
+ };
+ }));
+ };
+
+ send-keys-sftp = mkOption {
+ type = package;
+ description = ''
+ Derive this file with `nix-build '<nixpkgs/nixos>' -A config.nixsap.deployment.send-keys-sftp ... --no-out-link`
+ and feed it to the ``sftp(1)`` to upload the secrets (the keys) to the machine.
+ '';
+ readOnly = true;
+ default =
+ let
+ key-store-dir = pkgs.runCommand "key-store-dir" {} "mkdir -p $out/'${cfg.keyStore}'";
+ key-cmds = lib.concatStringsSep "\n" (flip mapAttrsToList cfg.keys (name: key: ''
+ put '${key.source}' '${name}.tmp'
+ chmod ${toString key.mode} '${name}.tmp'
+ chown ${toString key.uid} '${name}.tmp'
+ chgrp ${toString key.gid} '${name}.tmp'
+ rename '${name}.tmp' '${name}'
+ ''));
+ in pkgs.writeText "send-keys-sftp" (
+ if cfg.keys != {} then ''
+ cd /
+ lcd '${key-store-dir}'
+ put -pR *
+
+ chown ${toString config.users.users.root.uid} '${cfg.keyStore}'
+ chgrp ${toString config.users.groups.keys.gid} '${cfg.keyStore}'
+ chmod 0750 '${cfg.keyStore}'
+
+ cd '${cfg.keyStore}'
+
+ ${key-cmds}
+ bye
+ '' else ''
+ bye
+ ''
+ );
+ };
};
config = {
- users.users = genAttrs (attrNames cfg.keyrings) (
- name: optionalAttrs (name != "root") { extraGroups = [ "keys" ]; }
- );
-
- deployment.keys = foldl (a: b: a//b) {} (
- mapAttrsToList (name: keys:
+ nixsap.deployment.keys = foldl (a: b: a//b) {} (
+ mapAttrsToList (user: keys:
let realkeys = unique (filter (n: n != null && hasPrefix cfg.keyStore n) keys);
in genAttrs (map baseNameOf realkeys)
- (key: { text = read key;
- user = toString allusers.${name}.uid;
+ (key: { source = getKeySource key;
+ uid = config.users.users.${user}.uid;
})
) cfg.keyrings
);
+
+ users.users = genAttrs (attrNames cfg.keyrings) (
+ user: optionalAttrs (user != "root") { extraGroups = [ "keys" ]; }
+ );
+
+ systemd.services =
+ flip mapAttrs' cfg.keys (name: key:
+ nameValuePair "${name}-key" {
+ enable = true;
+ serviceConfig = {
+ TimeoutStartSec = "infinity";
+ Restart = "always";
+ RestartSec = "100ms";
+ ExecStartPre = "${pkgs.wait4file} '${cfg.keyStore}/${name}'";
+ ExecStart = "${pkgs.hangonfile} '${cfg.keyStore}/${name}'";
+ };
+ }
+ );
+
};
}
diff --git a/modules/system/nixos.nix b/modules/system/nixos.nix
new file mode 100644
index 0000000..a02acd6
--- /dev/null
+++ b/modules/system/nixos.nix
@@ -0,0 +1,4 @@
+{ config, lib, ...}:
+{
+ system.stateVersion = lib.mkDefault config.system.nixos.release;
+}
diff --git a/modules/system/users.nix b/modules/system/users.nix
index 022a7e7..b348942 100644
--- a/modules/system/users.nix
+++ b/modules/system/users.nix
@@ -36,6 +36,7 @@ let
mkDaemonUser = name:
{
isNormalUser = false;
+ isSystemUser = true;
uid = uid name;
group = name;
};
@@ -43,6 +44,7 @@ let
mkNormalUser = name:
{
isNormalUser = true;
+ isSystemUser = false;
uid = uid name;
};