Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 0 additions & 149 deletions backends/on-machine.nix

This file was deleted.

58 changes: 58 additions & 0 deletions backends/on-machine/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# we use this vars backend as an example backend.
# this generates a script which creates the values at the expected path.
# this script has to be run manually (I guess after updating the system) to generate the required vars.
{
pkgs,
lib,
config,
...
}: let
cfg = config.vars.settings.on-machine;
sortedGenerators =
(lib.toposort (a: b: builtins.elem a.name b.dependencies) (lib.attrValues config.vars.generators))
.result;

promptCmd = {
hidden = "read -sr prompt_value";
line = "read -r prompt_value";
multiline = ''
echo 'press control-d to finish'
prompt_value=$(cat)
'';
};
generate-vars = pkgs.writeShellApplication {
name = "generate-vars";
runtimeInputs = with pkgs; [
coreutils
jq
];
text = ''
_config=${pkgs.writers.writeJSON "generate-vars.json" {
file_location = cfg.fileLocation;
generators = sortedGenerators;
}}

${builtins.readFile ./generate-secrets}
'';
};
in {
options.vars.settings.on-machine = {
enable = lib.mkEnableOption "Enable on-machine vars backend";
fileLocation = lib.mkOption {
type = lib.types.str;
default = "/etc/vars";
};
};
config = lib.mkIf cfg.enable {
vars.settings.fileModule = file: {
path =
if file.config.secret
then "${cfg.fileLocation}/secret/${file.config.generator}/${file.config.name}"
else "${cfg.fileLocation}/public/${file.config.generator}/${file.config.name}";
};
environment.systemPackages = [
generate-vars
];
system.build.generate-vars = generate-vars;
};
}
176 changes: 176 additions & 0 deletions backends/on-machine/generate-secrets
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# -*- mode: shell-script -*-

set -efuo pipefail

function _generators() {
jq --raw-output '.generators | map(.name) | .[]' < "$_config"
}

function _generator_files() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .files | map(.name) | .[]' < "$_config"
}

function _generator_file_get() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .files.[] | select(.name == "'"$2"'") | .'"$3" < "$_config"
}

function _generator_prompts() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .prompts | map(.name) | .[]' < "$_config"
}

function _generator_prompt_get() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .prompts.[] | select(.name == "'"$2"'") | .'"$3" < "$_config"
}

function _generator_dependencies() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .dependencies[]' < "$_config"
}

function _generator_runtime_inputs() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .runtimeInputs[]' < "$_config"
}

function _generator_script() {
jq --raw-output '.generators.[] | select(.name == "'"$1"'") | .script' < "$_config"
}

function _file_location() {
jq --raw-output '.file_location' < "$_config"
}

# make the output directory overridable
OUT_DIR="${OUT_DIR:-$(_file_location)}"

# check if all files are present or all files are missing
# if not, they are in an inconsistent state and we bail out
while read -u 10 -r _generator_name ; do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's with the hard-coded number here? (seeing 2 similar instances below)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah forgot to document, thats to not take over stdin as the code in the while block needs it free.

all_files_missing=true
all_files_present=true
echo "Checking vars for ${_generator_name}..."
while read -r _file_name ; do
_file_generator="$(_generator_file_get "$_generator_name" "$_file_name" "generator")"

if [[ "$(_generator_file_get "$_generator_name" "$_file_name" "secret")" == "true" ]] ; then
OUT_FILE="$OUT_DIR/secret/${_file_generator}/${_file_name}"
else
OUT_FILE="$OUT_DIR/public/${_file_generator}/${_file_name}"
fi

if test -e "$OUT_FILE"; then
all_files_missing=false
else
all_files_present=false
fi
done < <(_generator_files "$_generator_name")

# outputs
out="$(mktemp -d)"
trap 'rm -rf $out' EXIT
export out
mkdir -p "$out"

if [[ "$all_files_missing" == false ]] && [[ "$all_files_present" == false ]] ; then
echo "Inconsistent state for generator: ${_generator_name}"
exit 1
fi
if [[ "$all_files_present" = true ]] ; then
echo "All secrets for ${_generator_name} are present"
elif [[ "$all_files_missing" = true ]] ; then
# prompts
prompts="$(mktemp -d)"
trap 'rm -rf $prompts' EXIT
export prompts
mkdir -p "$prompts"
while read -u 11 -r _prompt_name ; do
_prompt_description="$(_generator_prompt_get "$_generator_name" "$_prompt_name" "description")"
_prompt_type="$(_generator_prompt_get "$_generator_name" "$_prompt_name" "type")"

printf "%s" "$_prompt_description"

case "$_prompt_type" in
hidden)
read -sr prompt_value
;;
line)
read -r prompt_value
;;
multiline)
echo 'press control-d to finish'
prompt_value="$(cat)"
;;
*)
echo "unknown prompt type $_prompt_type"
exit 1
esac

echo -n "$prompt_value" > "$prompts/${_prompt_name}"
done 11< <(_generator_prompts "$_generator_name")

echo "Generating vars for ${_generator_name}"

# dependencies
in=$(mktemp -d)
trap 'rm -rf $in' EXIT
export in
mkdir -p "$in"

while read -r _dependency ; do
mkdir -p "$in/${_dependency}"
while read -r _file_name ; do
if [[ "$(_generator_file_get "$_dependency" "$_file_name" "secret")" == "true" ]] ; then
cp "$OUT_DIR/secret/$_dependency/$_file_name" "$in/$_dependency/$_file_name"
else
cp "$OUT_DIR/public/$_dependency/$_file_name" "$in/$_dependency/$_file_name"
fi
done < <(_generator_files "$_dependency")
done < <(_generator_dependencies "$_generator_name")

# prepare PATH
NEW_PATH=""
while read -r _runtime_input ; do
NEW_PATH="${NEW_PATH:+$NEW_PATH:}$_runtime_input/bin"
done < <(_generator_runtime_inputs "$_generator_name")

# actually run the generator
PATH="$NEW_PATH" "$(command -v bash)" <<<"$(_generator_script "$_generator_name")"

# check if all files got generated
while read -r _file_name ; do
if ! [[ -e "$out/${_file_name}" ]] ; then
echo "generator ${_generator_name} failed to generate ${_file_name}"
exit 1
fi
done < <(_generator_files "$_generator_name")


# move the files to the correct location
while read -r _file_name ; do
if [[ "$(_generator_file_get "$_generator_name" "$_file_name" "secret")" == "true" ]] ; then
OUT_FILE="$OUT_DIR/secret/${_file_generator}/${_file_name}"
else
OUT_FILE="$OUT_DIR/public/${_file_generator}/${_file_name}"
fi

mkdir -p "$(dirname "$OUT_FILE")"
mv "$out/${_file_name}" "$OUT_FILE"
done < <(_generator_files "$_generator_name")

# move the files to the correct location
while read -r _file_name ; do
if [[ "$(_generator_file_get "$_generator_name" "$_file_name" "secret")" == "true" ]] ; then
OUT_FILE="$OUT_DIR/secret/${_file_generator}/${_file_name}"
else
OUT_FILE="$OUT_DIR/public/${_file_generator}/${_file_name}"
fi

_file_owner="$(_generator_file_get "$_generator_name" "$_file_name" "owner")"
_file_group="$(_generator_file_get "$_generator_name" "$_file_name" "group")"
_file_mode="$(_generator_file_get "$_generator_name" "$_file_name" "mode")"

chown "${_file_owner}:${_file_group}" "${OUT_FILE}"
chmod "${_file_mode}" "${OUT_FILE}"
done < <(_generator_files "$_generator_name")

rm -rf "$out"
fi
done 10< <(_generators)
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
forAllSystems = lib.genAttrs supportedSystems;
in {
nixosModules.default = { imports = [ ./options.nix ]; };
nixosModules.backend-on-machine = { imports = [ ./backends/on-machine.nix ]; };
nixosModules.backend-on-machine = { imports = [ ./backends/on-machine ]; };
checks = forAllSystems (system: let
tests = {
testing = inputs.nixpkgs.lib.nixos.runTest {
Expand Down
Loading