add README and examples
This commit is contained in:
parent
de367934a7
commit
adc97bd3c5
11 changed files with 146 additions and 80 deletions
101
README.md
101
README.md
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
[age](https://github.com/FiloSottile/age)-encrypted secrets for NixOS.
|
[age](https://github.com/FiloSottile/age)-encrypted secrets for NixOS.
|
||||||
|
|
||||||
# Features
|
It consists of a NixOS module `age`, and a CLI tool called `agenix`
|
||||||
|
used for editing and rekeying the secret files.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
* Secrets are encrypted with SSH keys
|
* Secrets are encrypted with SSH keys
|
||||||
** system public keys via `ssh-keyscan`
|
** system public keys via `ssh-keyscan`
|
||||||
|
@ -10,11 +13,11 @@
|
||||||
* No GPG
|
* No GPG
|
||||||
* Very little code, so it should be easy for you to audit
|
* Very little code, so it should be easy for you to audit
|
||||||
|
|
||||||
# Installation
|
## Installation
|
||||||
|
|
||||||
Choose one of the following methods:
|
Choose one of the following methods:
|
||||||
|
|
||||||
#### [niv](https://github.com/nmattia/niv) (Current recommendation)
|
### [niv](https://github.com/nmattia/niv) (Current recommendation)
|
||||||
|
|
||||||
First add it to niv:
|
First add it to niv:
|
||||||
|
|
||||||
|
@ -22,7 +25,9 @@ First add it to niv:
|
||||||
$ niv add ryantm/agenix
|
$ niv add ryantm/agenix
|
||||||
```
|
```
|
||||||
|
|
||||||
Than add the following to your configuration.nix in the `imports` list:
|
#### Module
|
||||||
|
|
||||||
|
Then add the following to your configuration.nix in the `imports` list:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
|
@ -30,7 +35,7 @@ $ niv add ryantm/agenix
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### nix-channel
|
### nix-channel
|
||||||
|
|
||||||
As root run:
|
As root run:
|
||||||
|
|
||||||
|
@ -47,7 +52,7 @@ $ nix-channel --update
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### fetchTarball
|
### fetchTarball
|
||||||
|
|
||||||
Add the following to your configuration.nix:
|
Add the following to your configuration.nix:
|
||||||
|
|
||||||
|
@ -74,7 +79,9 @@ $ nix-channel --update
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Flakes
|
### Flakes
|
||||||
|
|
||||||
|
#### Module
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
|
@ -96,6 +103,82 @@ $ nix-channel --update
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# Tutorial
|
#### CLI
|
||||||
|
|
||||||
# Threat model
|
You don't need to install it:
|
||||||
|
|
||||||
|
```console
|
||||||
|
nix run github:ryantm/agenix -- --help
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Tutorial
|
||||||
|
|
||||||
|
1. Make a directory to store secrets and a YAML file for configuring encryption.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mkdir secrets
|
||||||
|
$ cd secerts
|
||||||
|
$ touch secrets.yaml
|
||||||
|
```
|
||||||
|
2. Add public keys to `secrets.yaml` file (hint use `ssh-keyscan` or GitHub (for example, https://github.com/ryantm.keys):
|
||||||
|
```yaml
|
||||||
|
public_keys:
|
||||||
|
# users
|
||||||
|
- &user1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH
|
||||||
|
# systems
|
||||||
|
- &system1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
- name: secret1.age
|
||||||
|
public_keys:
|
||||||
|
- *user1
|
||||||
|
- *system1
|
||||||
|
- name: secret2.age
|
||||||
|
public_keys:
|
||||||
|
- *user1
|
||||||
|
```
|
||||||
|
3. Edit secret files (assuming your SSH private key is in ~/.ssh/):
|
||||||
|
```console
|
||||||
|
$ agenix -e secret1.age
|
||||||
|
```
|
||||||
|
4. Add secret to NixOS module config:
|
||||||
|
```nix
|
||||||
|
age.secrets.secret1 = ../secrets/secret1.age;
|
||||||
|
```
|
||||||
|
5. NixOS rebuild or use your deployment too like usual.
|
||||||
|
|
||||||
|
## Rekeying
|
||||||
|
|
||||||
|
If you change the public keys in `secrets.yaml`, you should rekey your
|
||||||
|
secrets:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ agenix --rekey
|
||||||
|
```
|
||||||
|
|
||||||
|
To rekey a secret, you have to be able to decrypt it. Because of
|
||||||
|
randomness in `age`'s encryption algorithms, the files always change
|
||||||
|
when rekeyed, even if the identities do not. This eventually could be
|
||||||
|
improved upon by reading the identities from the age file.
|
||||||
|
|
||||||
|
## Threat model/Warnings
|
||||||
|
|
||||||
|
This library has not be audited by a security professional.
|
||||||
|
|
||||||
|
People unfamiliar with `age` might be surprised that secrets are not
|
||||||
|
authenticated. This means that every attacker that has write access to
|
||||||
|
the repository can modify secrets because public keys are exposed.
|
||||||
|
This seems like not a problem on the first glance because changing the
|
||||||
|
configuration itself could expose secrets easily. However it is easier
|
||||||
|
to review configuration changes rather than random secrets (for
|
||||||
|
example 4096-bit rsa keys). This would be solved by having a message
|
||||||
|
authentication code (MAC) like other implementations like GPG or
|
||||||
|
[sops](https://github.com/Mic92/sops-nix) have, however this was left
|
||||||
|
out for simplicity in `age`.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
This project is based off of
|
||||||
|
[sops-nix](https://github.com/Mic92/sops-nix) created Mic92. Thank you
|
||||||
|
to Mic92 for inspiration and help with making this.
|
||||||
|
|
16
example.yaml
16
example.yaml
|
@ -1,16 +0,0 @@
|
||||||
public_keys:
|
|
||||||
# users
|
|
||||||
- &user1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFx3E0bHOWxRu91+XFzimbVA1mP19c5To/7szED1OUf9 user1@example.com
|
|
||||||
# hosts
|
|
||||||
# get these via ssh-keyscan
|
|
||||||
- &host1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKxk6NtiVv8L8R6/+lHgq4UP8P6JC7a6Wl2klCOOk8GP root@host1
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
- name: secret.age
|
|
||||||
public_keys:
|
|
||||||
- *user1
|
|
||||||
- *host1
|
|
||||||
- name: other.age
|
|
||||||
public_keys:
|
|
||||||
- *user1
|
|
||||||
- *host1
|
|
BIN
example/secret1.age
Normal file
BIN
example/secret1.age
Normal file
Binary file not shown.
5
example/secret2.age
Normal file
5
example/secret2.age
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 V3XmEA OB4+1FbPhQ3r6iGksM7peWX5it8NClpXIq/o5nnP7GA
|
||||||
|
FmHVUj+A5i5+bDFgySQskmlvynnosJiWUTJmBRiNA9I
|
||||||
|
--- tP+3mFVtd7ogVu1Lkboh55zoi5a77Ht08Uc/QuIviv4
|
||||||
|
¤¬Xæ{”ïOŠ£èätMXxÔvÓª(¬IÁmyPÇï¸è+3²S3i
|
14
example/secrets.yaml
Normal file
14
example/secrets.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
public_keys:
|
||||||
|
# users
|
||||||
|
- &user1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH
|
||||||
|
# systems
|
||||||
|
- &system1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
- name: secret1.age
|
||||||
|
public_keys:
|
||||||
|
- *user1
|
||||||
|
- *system1
|
||||||
|
- name: secret2.age
|
||||||
|
public_keys:
|
||||||
|
- *user1
|
7
example_keys/system1
Normal file
7
example_keys/system1
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACDyQ8iK/xUs9XCXXKFuvUfja1s8Biv/t4Caag9bfC9sxAAAAJA3yvCWN8rw
|
||||||
|
lgAAAAtzc2gtZWQyNTUxOQAAACDyQ8iK/xUs9XCXXKFuvUfja1s8Biv/t4Caag9bfC9sxA
|
||||||
|
AAAEA+J2V6AG1NriAIvnNKRauIEh1JE9HSdhvKJ68a5Fm0w/JDyIr/FSz1cJdcoW69R+Nr
|
||||||
|
WzwGK/+3gJpqD1t8L2zEAAAADHJ5YW50bUBob21lMQE=
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
1
example_keys/system1.pub
Normal file
1
example_keys/system1.pub
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE
|
7
example_keys/user1
Normal file
7
example_keys/user1
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACC9InTb4BornFoLqf5j+/M8gtt7hY2KtHr3FnYxkFGgRwAAAJC2JJ8htiSf
|
||||||
|
IQAAAAtzc2gtZWQyNTUxOQAAACC9InTb4BornFoLqf5j+/M8gtt7hY2KtHr3FnYxkFGgRw
|
||||||
|
AAAEDxt5gC/s53IxiKAjfZJVCCcFIsdeERdIgbYhLO719+Kb0idNvgGiucWgup/mP78zyC
|
||||||
|
23uFjYq0evcWdjGQUaBHAAAADHJ5YW50bUBob21lMQE=
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
1
example_keys/user1.pub
Normal file
1
example_keys/user1.pub
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH
|
|
@ -6,16 +6,19 @@ PACKAGE="agenix"
|
||||||
function show_help () {
|
function show_help () {
|
||||||
echo "$PACKAGE - edit and rekey age secret files"
|
echo "$PACKAGE - edit and rekey age secret files"
|
||||||
echo " "
|
echo " "
|
||||||
echo "$PACKAGE -e FILE"
|
echo "$PACKAGE -e FILE [-i PRIVATE_KEY]"
|
||||||
echo "$PACKAGE -r"
|
echo "$PACKAGE -r [-i PRIVATE_KEY]"
|
||||||
echo ' '
|
echo ' '
|
||||||
echo 'options:'
|
echo 'options:'
|
||||||
echo '-h, --help show help'
|
echo '-h, --help show help'
|
||||||
echo '-e, --edit FILE edits FILE using $EDITOR'
|
echo '-e, --edit FILE edits FILE using $EDITOR'
|
||||||
echo '-r, --rekey re-encrypts all secrets with specified recipients'
|
echo '-r, --rekey re-encrypts all secrets with specified recipients'
|
||||||
|
echo '-i, --identity identity to use when decrypting'
|
||||||
echo ' '
|
echo ' '
|
||||||
echo 'FILE an age-encrypted file'
|
echo 'FILE an age-encrypted file'
|
||||||
echo ' '
|
echo ' '
|
||||||
|
echo 'PRIVATE_KEY a path to a private SSH key used to decrypt file'
|
||||||
|
echo ' '
|
||||||
echo 'EDITOR environment variable of editor to use when editing FILE'
|
echo 'EDITOR environment variable of editor to use when editing FILE'
|
||||||
echo ' '
|
echo ' '
|
||||||
echo 'RULES environment variable with path to YAML file specifying recipient public keys.'
|
echo 'RULES environment variable with path to YAML file specifying recipient public keys.'
|
||||||
|
@ -25,6 +28,7 @@ function show_help () {
|
||||||
test $# -eq 0 && (show_help && exit 1)
|
test $# -eq 0 && (show_help && exit 1)
|
||||||
|
|
||||||
REKEY=0
|
REKEY=0
|
||||||
|
DECRYPT=(--decrypt)
|
||||||
|
|
||||||
while test $# -gt 0; do
|
while test $# -gt 0; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -37,7 +41,17 @@ while test $# -gt 0; do
|
||||||
if test $# -gt 0; then
|
if test $# -gt 0; then
|
||||||
export FILE=$1
|
export FILE=$1
|
||||||
else
|
else
|
||||||
echo "no file specified"
|
echo "no FILE specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-i|--identity)
|
||||||
|
shift
|
||||||
|
if test $# -gt 0; then
|
||||||
|
DECRYPT+=(--identity "$1")
|
||||||
|
else
|
||||||
|
echo "no PRIVATE_KEY specified"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
|
@ -81,7 +95,6 @@ function edit {
|
||||||
|
|
||||||
if [ -f "$FILE" ]
|
if [ -f "$FILE" ]
|
||||||
then
|
then
|
||||||
DECRYPT=(--decrypt)
|
|
||||||
while IFS= read -r key
|
while IFS= read -r key
|
||||||
do
|
do
|
||||||
DECRYPT+=(--identity "$key")
|
DECRYPT+=(--identity "$key")
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
#! /usr/bin/env nix-shell
|
|
||||||
#! nix-shell -i bash -p age yq-go moreutils
|
|
||||||
|
|
||||||
while test $# -gt 0; do
|
|
||||||
case "$1" in
|
|
||||||
-h|--help)
|
|
||||||
echo "$package - attempt to capture frames"
|
|
||||||
echo " "
|
|
||||||
echo "$package [options] application [arguments]"
|
|
||||||
echo " "
|
|
||||||
echo "options:"
|
|
||||||
echo "-h, --help show brief help"
|
|
||||||
echo "-a, --action=ACTION specify an action to use"
|
|
||||||
echo "-o, --output-dir=DIR specify a directory to store output in"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-a)
|
|
||||||
shift
|
|
||||||
if test $# -gt 0; then
|
|
||||||
export PROCESS=$1
|
|
||||||
else
|
|
||||||
echo "no process specified"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--action*)
|
|
||||||
export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'`
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-o)
|
|
||||||
shift
|
|
||||||
if test $# -gt 0; then
|
|
||||||
export OUTPUT=$1
|
|
||||||
else
|
|
||||||
echo "no output dir specified"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--output-dir*)
|
|
||||||
export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'`
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
Loading…
Reference in a new issue