difftreelog
doc: tried to improve docs, realised I'm still too lazy for that
in: trunk
5 files changed
docs/secrets.adocdiffbeforeafterbothno changes
lib/default.nixdiffbeforeafterboth33 inherit (options) mkHostsOption;33 inherit (options) mkHostsOption;343435 modules = {35 modules = {36 # mkDefault = mkOverride 100036 /**37 # For places, where fleet knows better than nixpkgs defaults.37 Use in places, where fleet might know better than nixpkgs defaults to38 */38 mkFleetDefault = mkOverride 999;39 mkFleetDefault = mkOverride 999;40 /**39 # Some generators use mkDefault, but optionDefault is set by nixpkgs.41 Some generators use mkDefault, but optionDefault is set by nixpkgs.42 */40 mkFleetGeneratorDefault = mkOverride 1001;43 mkFleetGeneratorDefault = mkOverride 1001;41 };44 };424543 inherit (modules) mkFleetDefault mkFleetGeneratorDefault;46 inherit (modules) mkFleetDefault mkFleetGeneratorDefault;444745 secrets = {48 secrets = {49 /**50 Generate a random secret password, 32 ascii characters by default5152 Options:53 size: generated password length in ascii characters (bytes).54 noSymbols: by default, character set includes various special characters ($ , ! + * : ~), and might55 not be accepted in some contexts, this option switches charset to just [A-Za-z0-9].5657 Output:58 Resulting secret has only part: secret, which contains encrypted password.59 */46 mkPassword = {size ? 32}: {60 mkPassword = {size ? 32}: {47 coreutils,61 coreutils,48 mkSecretGenerator,62 mkSecretGenerator,54 '';68 '';55 };69 };567071 /**72 Generate a random ed25519 keypair7374 Options:75 noEmbedPublic: By default, secret key also embeds public key in itself ("extended" format, 64 bytes)76 When noEmbedPublis is enabled - only the private scalar is included.77 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".7879 Output:80 Resulting secret has two parts: public and secret, where the secret part is encrypted.8182 This secret format is used by e.g Garage S3 server83 */57 mkEd25519 = {84 mkEd25519 = {58 noEmbedPublic ? false,85 noEmbedPublic ? false,59 encoding ? null,86 encoding ? null,67 '';94 '';68 };95 };699697 /**98 Generate a random x25519 keypair99100 Options:101 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".102103 Output:104 Resulting secret has two parts: public and secret, where the secret part is encrypted.105106 This secret format is used by e.g Wireguard VPN for peers (base64-encoded)107 */70 mkX25519 = {encoding ? null}: {mkSecretGenerator}:108 mkX25519 = {encoding ? null}: {mkSecretGenerator}:71 mkSecretGenerator {109 mkSecretGenerator {72 script = ''110 script = ''76 '';114 '';77 };115 };78116117 /**118 Generate a random RSA keypair119120 Options:121 size: RSA key size, 4096 by default122123 Output:124 Resulting secret has two parts: public and secret, where the secret part is encrypted.125 Both parts are PEM encoded.126 */79 mkRsa = {size ? 4096}: {127 mkRsa = {size ? 4096}: {80 openssl,128 openssl,81 mkSecretGenerator,129 mkSecretGenerator,92 '';140 '';93 };141 };94142143 /**144 Generate a random byte sequence145146 Options:147 size: generated password length in bytes, 32 by default.148 encoding: how the generated bytes should be encoded, "raw" (default), "hex" or "base64"149 noNuls: prevent output byte sequence from containing internal \0, useful for some C applications150 that can't handle their strings properly.151152 Output:153 Resulting secret has only part: secret, which contains encrypted bytes.154155 Might be used for e.g. Wireguard VPN PSK keys (base64-encoded)156 */95 mkBytes = {157 mkBytes = {96 count ? 32,158 count ? 32,97 encoding,159 encoding,104 ${optionalString noNuls "--no-nuls"}166 ${optionalString noNuls "--no-nuls"}105 '';167 '';106 };168 };169 /**170 Shorthand for `mkBytes`, which defaults to "hex" encoding171 */107 mkHexBytes = {count ? 32}:172 mkHexBytes = {count ? 32}:108 mkBytes {173 mkBytes {109 inherit count;174 inherit count;110 encoding = "hex";175 encoding = "hex";111 };176 };177 /**178 Shorthand for `mkBytes`, which defaults to "base64" encoding179 */112 mkBase64Bytes = {count ? 32}:180 mkBase64Bytes = {count ? 32}:113 mkBytes {181 mkBytes {114 inherit count;182 inherit count;126 plaintextPrefix = "<PLAINTEXT>";194 plaintextPrefix = "<PLAINTEXT>";127 plaintextNewlinePrefix = "<PLAINTEXT-NL>";195 plaintextNewlinePrefix = "<PLAINTEXT-NL>";128 in {196 in {197 /**198 Decode public secret part into string199 */129 decodeRawSecret = raw:200 decodeRawSecret = raw:130 if hasPrefix plaintextPrefix raw201 if hasPrefix plaintextPrefix raw131 then removePrefix plaintextPrefix raw202 then removePrefix plaintextPrefix rawmodules/hosts.nixdiffbeforeafterboth11 inherit (lib.attrsets) mapAttrsToList mapAttrs;11 inherit (lib.attrsets) mapAttrsToList mapAttrs;12 inherit (lib.lists) flatten groupBy;12 inherit (lib.lists) flatten groupBy;13in {13in {14 # Fleet Meta Configuration Module1514 options = {16 options = {15 data = mkOption {17 data = mkOption {18 version = mkOption {20 version = mkOption {19 type = str;21 type = str;20 internal = true;22 internal = true;23 description = "Internal version identifier for saved fleet state";21 };24 };2522 gcRootPrefix = mkOption {26 gcRootPrefix = mkOption {23 type = str;27 type = str;24 internal = true;28 internal = true;29 description = "Prefix for fleet-generated gc garbage collection roots";25 };30 };3126 hosts = mkOption {32 hosts = mkOption {27 type = attrsOf (submodule {33 type = attrsOf (submodule {28 options.encryptionKey = mkOption {34 options.encryptionKey = mkOption {29 type = str;35 type = str;30 description = "Rage SSH encryption key for secrets.";36 description = "Rage SSH encryption key for host-bound secrets";31 };37 };32 });38 });33 };39 };34 };40 };35 };41 };36 description = ''42 description = ''37 Configuration provided from outside.43 Persistent configuration data for fleet management.38 Usually used to persist fleet data between runs.44 Typically used to maintain state between fleet configuration runs.39 '';45 '';40 };46 };4741 taggedWith = mkOption {48 taggedWith = mkOption {42 type = attrsOf (listOf str);49 type = attrsOf (listOf str);43 internal = true;50 internal = true;51 description = "Mapping of hosts grouped by tags, used by fleet CLI";44 };52 };5345 hosts = mkOption {54 hosts = mkOption {46 type = mkHostsType ({config, ...}: {55 type = mkHostsType ({config, ...}: {47 options = {56 options = {48 system = mkOption {57 system = mkOption {49 description = "Type of the system.";58 description = "System architecture and platform identifier";50 type = str;59 type = str;51 example = "x86_64-linux";60 example = "x86_64-linux";52 };61 };6253 tags = mkOption {63 tags = mkOption {54 description = "Host tag. In CLI, you can refer to all hosts having this tag using @tag syntax.";64 description = ''65 Tags for host classification.66 Used for host selection via @tag syntax in CLI tools.67 '';55 type = listOf str;68 type = listOf str;56 };69 };7071 # Network configuration details57 network = mkOption {72 network = mkOption {58 type = submodule {73 type = submodule {59 options = {74 options = {60 internalIps = mkOption {75 internalIps = mkOption {61 description = "Internal ips";76 description = "List of internal IP addresses for the host";62 type = listOf str;77 type = listOf str;63 default = [];78 default = [];64 };79 };8065 externalIps = mkOption {81 externalIps = mkOption {66 description = "External ips";82 description = "List of external IP addresses for the host";67 type = listOf str;83 type = listOf str;68 default = [];84 default = [];69 };85 };70 };86 };71 };87 };72 description = "Network definition of host";73 };88 };74 };89 };75 config = {90 config = {91 # Default hostname generation76 nixos.networking.hostName = mkFleetGeneratorDefault config._module.args.name;92 nixos.networking.hostName = mkFleetGeneratorDefault config._module.args.name;93 # Default 'all' tag for every host77 tags = ["all"];94 tags = ["all"];78 };95 };79 _file = ./meta.nix;96 _file = ./meta.nix;80 });97 });81 default = {};98 default = {};82 description = "Configurations of individual hosts";83 };99 };84 };100 };101102 # Generate a mapping of hosts indexed by their tags85 config.taggedWith = let103 config.taggedWith = let104 # Flatten host tags into a list of {hostname, tag} pairs86 hostTagList = flatten (mapAttrsToList (hostname: host: map (tag: {inherit hostname tag;}) host.tags) config.hosts);105 hostTagList = flatten (mapAttrsToList (hostname: host: map (tag: {inherit hostname tag;}) host.tags) config.hosts);106 # Group hostnames by their tags87 grouped = mapAttrs (_: hosts: lib.map (pair: pair.hostname) hosts) (groupBy (elem: elem.tag) hostTagList);107 grouped = mapAttrs (_: hosts: lib.map (pair: pair.hostname) hosts) (groupBy (elem: elem.tag) hostTagList);88 in108 in89 grouped;109 grouped;110111 # Source file reference90 _file = ./meta.nix;112 _file = ./meta.nix;91}113}92114modules/secrets-data.nixdiffbeforeafterboth15 options = {15 options = {16 raw = mkOption {16 raw = mkOption {17 type = nullOr str;17 type = nullOr str;18 description = "Encrypted + encoded secret data";18 description = "Raw secret data in unspecified encoded and optionally encrypted format.";19 default = null;19 default = null;20 };20 };21 };21 };26 options = {26 options = {27 createdAt = mkOption {27 createdAt = mkOption {28 type = str;28 type = str;29 description = "When this secret was (re)generated";29 description = "Timestamp of secret generation/last rotation.";30 default = null;30 default = null;31 };31 };32 expiresAt = mkOption {32 expiresAt = mkOption {33 type = nullOr str;33 type = nullOr str;34 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";34 description = "Expiration timestamp triggering mandatory secret rotation.";35 default = null;35 default = null;36 };36 };373738 owners = mkOption {38 owners = mkOption {39 type = listOf str;39 type = listOf str;40 description = ''40 description = ''41 For which owners this secret is currently encrypted,41 List of hosts currently authorized to decrypt this shared secret.42 if not matches expectedOwners - then this secret is considered outdated, and4243 should be regenerated/reencrypted.43 If owners differ from expected owners, the secret is considered outdated4444 and requires regeneration or re-encryption.45 Imported from fleet.nix46 '';45 '';47 default = [];46 default = [];48 };47 };49 generationData = mkOption {48 generationData = mkOption {50 type = unspecified;49 type = unspecified;51 description = "Data that is embedded into secret part";50 description = "Contextual metadata associated with secret part.";52 default = null;51 default = null;53 };52 };54 };53 };60 options = {59 options = {61 createdAt = mkOption {60 createdAt = mkOption {62 type = str;61 type = str;63 description = "When this secret was (re)generated";62 description = "Timestamp of secret generation/last rotation.";64 default = null;63 default = null;65 };64 };66 expiresAt = mkOption {65 expiresAt = mkOption {67 type = nullOr str;66 type = nullOr str;68 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";67 description = "Expiration timestamp triggering mandatory secret rotation.";69 default = null;68 default = null;70 };69 };71 shared = mkOption {70 shared = mkOption {72 type = bool;71 type = bool;73 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";72 description = "Indicates if secret is a shared secret, so other hosts might have the same piece of secret data.";74 default = false;73 default = false;75 };74 };76 generationData = mkOption {75 generationData = mkOption {77 type = unspecified;76 type = unspecified;78 description = "Data that is embedded into secret part";77 description = "Contextual metadata associated with secret part.";79 default = null;78 default = null;80 };79 };81 };80 };87 sharedSecrets = mkOption {86 sharedSecrets = mkOption {88 type = attrsOf (submodule sharedSecretData);87 type = attrsOf (submodule sharedSecretData);89 default = {};88 default = {};90 description = "Stored shared secret data.";89 description = "Shared secret data.";91 };90 };92 hostSecrets = mkOption {91 hostSecrets = mkOption {93 type = attrsOf (attrsOf (submodule hostSecretData));92 type = attrsOf (attrsOf (submodule hostSecretData));94 default = {};93 default = {};95 description = "Host secrets.";94 description = "Host-specific secrets.";96 internal = true;95 internal = true;97 };96 };98 };97 };modules/secrets.nixdiffbeforeafterboth4 ...4 ...5}: let5}: let6 inherit (lib.options) mkOption literalExpression;6 inherit (lib.options) mkOption literalExpression;7 inherit (lib.types) unspecified nullOr listOf str bool attrsOf submodule;7 inherit (lib.types) unspecified nullOr listOf str bool attrsOf submodule functionTo package;8 inherit (lib.strings) concatStringsSep;8 inherit (lib.strings) concatStringsSep;9 inherit (lib.attrsets) mapAttrs;9 inherit (lib.attrsets) mapAttrs;101011 sharedSecret = {config, ...}: {11 sharedSecret = {config, ...}: {12 options = {12 options = {13 expectedOwners = mkOption {13 expectedOwners = mkOption {14 type = nullOr (listOf str);14 type = nullOr (listOf str);15 description = ''15 description = ''16 List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)16 Specifies the list of hosts authorized to decrypt and access this shared secret.171718 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners18 When null, secret ownership is managed manually via fleet.nix and CLI.19 Decrypted secrets will be stored at /run/secrets/$\{name} on authorized hosts.19 '';20 '';20 default = null;21 default = null;21 };22 };22 # TODO: Aren't those options may be just desugared to data/expectedData?23 regenerateOnOwnerAdded = mkOption {23 regenerateOnOwnerAdded = mkOption {24 type = bool;24 type = bool;25 description = ''25 description = ''26 Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.26 Controls whether the secret must be regenerated when new owners are added.272728 You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.28 Set to true when the secret contains owner-specific references (e.g., X.509 Subject Alternative Names).29 When true, adding a new owner will trigger secret regeneration instead of simple re-encryption.29 '';30 '';30 };31 };31 regenerateOnOwnerRemoved = mkOption {32 regenerateOnOwnerRemoved = mkOption {32 default = config.regenerateOnOwnerAdded;33 default = config.regenerateOnOwnerAdded;33 defaultText = literalExpression "regenerateOnOwnerAdded";34 defaultText = literalExpression "regenerateOnOwnerAdded";34 type = bool;35 type = bool;35 description = ''36 description = ''36 Should this secret be removed on owner removal, or it may be just reencrypted37 Determines secret behavior when owners are removed from the configuration.373838 Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.39 Typically mirrors regenerateOnOwnerAdded. Override cautiously.39 Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked40 Set to false if host permissions are revoked through alternative mechanisms like firewall rules.40 in some other way than by this secret ownership, I.e by firewall/etc.41 '';41 '';42 };42 };43 generator = mkOption {43 generator = mkOption {44 type = nullOr unspecified;44 type = nullOr (functionTo package);45 description = "Derivation to evaluate for secret generation";45 description = ''46 Function evaluating to nix derivation responsible for (re)generating the secret's content.4748 An input to this function - `pkgs` of a generator host with implementation-defined representation of extra encryption data,49 use `mkSecretGenerator` helpers to implement own generators.50 '';46 default = null;51 default = null;47 };52 };48 expectedGenerationData = mkOption {53 expectedGenerationData = mkOption {49 type = unspecified;54 type = unspecified;50 description = "Data that gets embedded into secret part";55 description = "Contextual metadata embedded within the secret part value";51 default = null;56 default = null;52 };57 };53 };58 };57 sharedSecrets = mkOption {62 sharedSecrets = mkOption {58 type = attrsOf (submodule sharedSecret);63 type = attrsOf (submodule sharedSecret);59 default = {};64 default = {};60 description = "Shared secrets";65 description = "Collection of secrets shared across multiple hosts with configurable ownership";61 };66 };62 };67 };63 config = {68 config = {