Skip to content

Commit dc055b7

Browse files
committed
examples: add flakes-agenix
This also acts as an integration test for age.
1 parent 8aa9e69 commit dc055b7

File tree

6 files changed

+252
-0
lines changed

6 files changed

+252
-0
lines changed

examples/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ By default, [`configuration.nix`](configuration.nix) enables `bitcoind` and `cli
3838
nix-bitcoin configuration to it using [krops](https://github.com/krebs/krops).\
3939
Requires: [Nix](https://nixos.org/nix/), Linux
4040

41+
- [`./flakes-agenix/deploy.sh`](./flakes-agenix/deploy.sh) shows how to deploy a
42+
nix-bitcoin node flake using [agenix](https://github.com/ryantm/agenix) secrets encryption.\
43+
agenix allows repo-defined secrets that can be deployed with any deployment scheme.\
44+
The node is deployed in a container.\
45+
Requires: [Nix](https://nixos.org/), a systemd-based Linux distro and root privileges
46+
4147
- [`./deploy-container-minimal.sh`](deploy-container-minimal.sh) creates a
4248
container defined by [importable-configuration.nix](importable-configuration.nix).\
4349
You can copy and import this file to use nix-bitcoin in an existing NixOS configuration.\
@@ -63,3 +69,5 @@ The commands in `shell.nix` allow you to locally run the node in a VM or contain
6369

6470
Flakes make it easy to include `nix-bitcoin` in an existing NixOS config.
6571
The [flakes example](./flakes/flake.nix) shows how to use `nix-bitcoin` as an input to a system flake.
72+
73+
To use [agenix](https://github.com/ryantm/agenix), which allows committing secrets to the node repo, see [`./flakes-agenix`](./flakes-agenix).

examples/flakes-agenix/deploy.sh

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# Strategy:
5+
# 1. Copy the node flake (./flake.nix) to a temporary dir and create a Git repo.
6+
# 2. Generate age-encrypted secrets by running a package defined by the node flake.
7+
# Commit the secrets.
8+
# 3. Start the node in a container and run test commands.
9+
# The container is destroyed afterwards.
10+
#
11+
# Run this script with arg `-i` or `--interactive` to start an
12+
# interactive shell in the container.
13+
14+
# You can use ./flake.nix as a template for a real deployment.
15+
16+
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
17+
# 0. Prelude
18+
interactive=
19+
case "${1:-}" in
20+
-i|--interactive)
21+
interactive=1
22+
;;
23+
esac
24+
25+
cd "${BASH_SOURCE[0]%/*}"
26+
scriptDir=$PWD
27+
nixBitcoin="$scriptDir/../.."
28+
29+
tmpDir=$(mktemp -d /tmp/nix-bitcoin-agenix.XXX)
30+
trap 'rm -rf $tmpDir' EXIT
31+
32+
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
33+
# 1. Create a flake repo in a tmp dir
34+
rsync -a ./ --exclude deploy.sh ./ "$tmpDir"
35+
36+
cd "$tmpDir"
37+
38+
git init
39+
git add .
40+
git commit -a -m init
41+
42+
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
43+
# 2. Generate age-encrypted secrets
44+
45+
# Use this nix-bitcoin repo as the flake input when generating secrets,
46+
# so that this script can be used for automated testing.
47+
nix run --override-input nix-bitcoin "$nixBitcoin" .#generateAgeSecrets
48+
#
49+
# In a real deployment, you can simply run the following from the deployment repo root:
50+
# nix run .#generateAgeSecrets
51+
#
52+
# or, if you don't define the `generateAgeSecrets` helper package:
53+
# nix run .#nixosConfigurations.demo-node.config.nix-bitcoin.age.generateSecretsScript
54+
#
55+
# Show help
56+
# nix run .#generateAgeSecrets --help
57+
58+
echo
59+
echo "Encrypted secrets:"
60+
ls -al secrets
61+
echo
62+
63+
# Commit age-encrypted secrets
64+
git add ./secrets
65+
git commit -a -m 'add secrets'
66+
67+
# Success!
68+
# This node flake can now be deployed with any deployment method.
69+
70+
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
71+
# 3. Run node in container
72+
73+
if [[ $interactive ]]; then
74+
# Start interactive container shell
75+
runCmd=()
76+
else
77+
runCmd=(
78+
--run c bash -c '
79+
echo
80+
echo "Unencrypted secrets in /run/agenix:"
81+
ls -alH /run/agenix
82+
echo
83+
systemctl status bitcoind
84+
'
85+
)
86+
fi
87+
88+
runContainer=(
89+
nix run --override-input nix-bitcoin "$nixBitcoin" .#container -- "${runCmd[@]}"
90+
)
91+
nix shell --inputs-from "$nixBitcoin" extra-container -c "${runContainer[@]}"
92+
93+
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
94+
# Debug helper: Build flake outputs
95+
# nix build --no-link -L --print-out-paths --override-input nix-bitcoin "$nixBitcoin" .#container
96+
# nix build --no-link -L --print-out-paths --override-input nix-bitcoin "$nixBitcoin" .#generateAgeSecrets

examples/flakes-agenix/flake.lock

+32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/flakes-agenix/flake.nix

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# When using this file as the base for a real deployment,
2+
# make sure to check all lines marked by 'FIXME:'
3+
4+
# This file is used by ./deploy.sh to deploy a container with
5+
# age-encrypted secrets.
6+
7+
{
8+
inputs.nix-bitcoin.url = "github:fort-nix/nix-bitcoin/release";
9+
inputs.agenix.url = "github:ryantm/agenix";
10+
inputs.agenix.inputs.nixpkgs.follows = "nix-bitcoin/nixpkgs";
11+
12+
inputs.flake-utils.follows = "nix-bitcoin/flake-utils";
13+
14+
outputs = { self, nix-bitcoin, agenix, flake-utils }: {
15+
modules = {
16+
demoNode = { config, lib, ... }: {
17+
imports = [
18+
# TODO-EXTERNAL:
19+
# Set this to `agenix.nixosModules.default` when
20+
# https://github.com/ryantm/agenix/pull/126 is merged
21+
agenix.nixosModules.age
22+
nix-bitcoin.nixosModules.default
23+
(nix-bitcoin + "/modules/secrets/age.nix")
24+
];
25+
26+
# Use age-encrypted secrets
27+
nix-bitcoin.age = {
28+
enable = true;
29+
30+
# The local secrets dir and its contents can be created with the
31+
# `generateAgeSecrets` flake package (defined below).
32+
# Use it like so:
33+
# nix run .#generateAgeSecrets
34+
# and commit the newly created ./secrets dir afterwards.
35+
#
36+
# This script must be rerun when adding node services that
37+
# require new secrets.
38+
#
39+
# For a real-life example, see ./deploy.sh
40+
secretsSourceDir = ./secrets;
41+
42+
# FIXME:
43+
# Set this to a public SSH host key of your node (preferably key type `ed25519`).
44+
# You can query host keys with command `ssh-keyscan <node address>`.
45+
# The keys defined here are used to age-encrypt the secrets.
46+
publicKeys = [
47+
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDoAaEMk8jMbg5MnvKDApWC6EpUHRJTzavy/wU2EtgtU"
48+
];
49+
};
50+
51+
# Enable services.
52+
# See ../configuration.nix for all available features.
53+
services.bitcoind.enable = true;
54+
#
55+
# See ../flakes/flake.nix for more settings useful for production nodes.
56+
57+
58+
# WARNING:
59+
# FIXME:
60+
# Remove the following `age.identityPaths` setting in a real deployment.
61+
# This copies a private key to the (publicly readable) Nix store,
62+
# which allows ./deploy.sh to start a age-based container in
63+
# a single deployment step.
64+
#
65+
# In a real deployment, just leave `age.identityPaths` undefined.
66+
# In this case, agenix uses the auto-generated SSH host key.
67+
age.identityPaths = [ ./host-key ];
68+
};
69+
};
70+
71+
nixosConfigurations.demoNode = nix-bitcoin.inputs.nixpkgs.lib.nixosSystem {
72+
system = "x86_64-linux";
73+
modules = [ self.modules.demoNode ];
74+
};
75+
}
76+
// (nix-bitcoin.inputs.nixpkgs.lib.recursiveUpdate
77+
78+
# Allow runnning this node as a container, used by ./deploy.sh
79+
(flake-utils.lib.eachSystem nix-bitcoin.lib.supportedSystems (system: {
80+
packages = {
81+
container = nix-bitcoin.inputs.extra-container.lib.buildContainers {
82+
inherit system;
83+
config.containers.nb-agenix = {
84+
privateNetwork = true;
85+
config.imports = [ self.modules.demoNode ];
86+
};
87+
# Set this when running on a NixOS container host with `system.stateVersion` <22.05
88+
# legacyInstallDirs = true;
89+
};
90+
};
91+
}))
92+
93+
# This allows generating age-encrypted secrets on systems
94+
# that differ from the target node.
95+
# E.g. manage a `x86_64-linux` node from macOS (`aarch64-darwin`)
96+
(flake-utils.lib.eachDefaultSystem (system: {
97+
packages = {
98+
generateAgeSecrets = let
99+
nodeSystem = nix-bitcoin.inputs.nixpkgs.lib.nixosSystem {
100+
inherit system;
101+
modules = [ self.modules.demoNode ];
102+
};
103+
in
104+
nodeSystem.config.nix-bitcoin.age.generateSecretsScript;
105+
};
106+
}))
107+
);
108+
}

examples/flakes-agenix/host-key

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3+
QyNTUxOQAAACA6AGhDJPIzG4OTJ7ygwKVguhKVB0SU82r8v8FNhLYLVAAAAIhEbEOERGxD
4+
hAAAAAtzc2gtZWQyNTUxOQAAACA6AGhDJPIzG4OTJ7ygwKVguhKVB0SU82r8v8FNhLYLVA
5+
AAAECBS5tCD9AcaOcNzPYlreA4BVrsy2f0FaGgEoJfBQzMqzoAaEMk8jMbg5MnvKDApWC6
6+
EpUHRJTzavy/wU2EtgtUAAAABG5vbmUB
7+
-----END OPENSSH PRIVATE KEY-----

test/run-tests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ examples() {
292292
runExample deploy-container-minimal.sh
293293
runExample deploy-qemu-vm.sh
294294
runExample deploy-krops.sh
295+
runExample flakes-agenix/deploy.sh
295296
'
296297
(cd "$scriptDir/../examples" && nix-shell --run "$script")
297298
}

0 commit comments

Comments
 (0)