mirror of
https://github.com/Mic92/sops-nix.git
synced 2024-12-14 11:57:52 +00:00
Replace sops-gpg-hook with sops-import-keys-hook
This commit is contained in:
parent
7918c59b39
commit
73e19bf11b
11 changed files with 246 additions and 19 deletions
63
README.md
63
README.md
|
@ -144,10 +144,20 @@ $ ssh-keygen -p -N "" -f /tmp/id_rsa
|
|||
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i /tmp/id_rsa | gpg --import --quiet"
|
||||
```
|
||||
|
||||
The hex string printed here is your GPG fingerprint that can be exported to `SOPS_PGP_FP`.
|
||||
The hex string printed here is your GPG fingerprint that can written to your [`.sops.yaml`](https://github.com/mozilla/sops#using-sops-yaml-conf-to-select-kms-pgp-for-new-files) in the root of your configuration directory or repository.
|
||||
|
||||
```console
|
||||
$ export SOPS_PGP_FP=2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```yaml
|
||||
# This example uses yaml anchors which allows to name keys
|
||||
# and re-use for multiple keys in a flexible way.
|
||||
# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
|
||||
# for a more complex example
|
||||
keys:
|
||||
- &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
creation_rules:
|
||||
- path_regex: secrets/[^/]+\.yaml$
|
||||
key_groups:
|
||||
- pgp:
|
||||
- *admin
|
||||
```
|
||||
|
||||
If you have generated a GnuPG key directly you can get your fingerprint like this:
|
||||
|
@ -179,32 +189,36 @@ $ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -o serv
|
|||
0fd60c8c3b664aceb1796ce02b318df330331003
|
||||
```
|
||||
|
||||
Also the hex string here is the fingerprint of your server's gpg key that can be exported
|
||||
append to `SOPS_PGP_FP`:
|
||||
Also the hex string here is the fingerprint of your server's gpg key that can be exported append to `.sops.yaml`:
|
||||
|
||||
```console
|
||||
$ export SOPS_PGP_FP=${SOPS_PGP_FP}:2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```yaml
|
||||
keys:
|
||||
- &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
- &server 0fd60c8c3b664aceb1796ce02b318df330331003
|
||||
creation_rules:
|
||||
- path_regex: secrets/[^/]+\.yaml$
|
||||
key_groups:
|
||||
- pgp:
|
||||
- *admin
|
||||
- *server
|
||||
```
|
||||
|
||||
If you prefer having a separate GnuPG key, see [Use with GnuPG instead of ssh keys](#use-with-gnupg-instead-of-ssh-keys).
|
||||
|
||||
### 4. Create a sops file
|
||||
|
||||
To create a sops file you need to set export `SOPS_PGP_FP` to include both the fingerprint
|
||||
of your personal gpg key (and your colleagues) and your servers:
|
||||
To create a sops file you need write a `.sops.yaml` as described above and
|
||||
import your personal gpg key (and your colleagues) and your servers into your
|
||||
gpg key chain.
|
||||
|
||||
```console
|
||||
$ export SOPS_PGP_FP="2504791468b153b8a3963cc97ba53d1919c5dfd4,2504791468b153b8a3963cc97ba53d1919c5dfd4"
|
||||
```
|
||||
|
||||
sops-nix automates that with a hook for nix-shell and also takes care of importing all keys, allowing
|
||||
public keys to be stored in git:
|
||||
sops-nix automates importing gpg keys with a hook for nix-shell allowing public
|
||||
keys to be shared via version control (i.e. git):
|
||||
|
||||
```nix
|
||||
# shell.nix
|
||||
with import <nixpkgs> {};
|
||||
mkShell {
|
||||
# imports all files ending in .asc/.gpg and sets $SOPS_PGP_FP.
|
||||
# imports all files ending in .asc/.gpg
|
||||
sopsPGPKeyDirs = [
|
||||
"./keys/hosts"
|
||||
"./keys/users"
|
||||
|
@ -214,8 +228,23 @@ mkShell {
|
|||
# "./keys/users/mic92.asc"
|
||||
# "./keys/hosts/server01.asc"
|
||||
#];
|
||||
|
||||
# This hook can also import gpg keys into its own seperate
|
||||
# gpg keyring instead of using the default one. This allows
|
||||
# to isolate otherwise unrelated server keys from the user gpg keychain.
|
||||
# By uncommenting the following lines, it will set GNUPGHOME
|
||||
# to .git/gnupg.
|
||||
# Storing it inside .git prevents accedentially commiting private keys.
|
||||
# After setting this option you will also need to import your own
|
||||
# private key into keyring, i.e. using a a command like this
|
||||
# (replacing 0000000000000000000000000000000000000000 with your fingerprint)
|
||||
# $ (unset GNUPGHOME; gpg --armor --export-secret-key 0000000000000000000000000000000000000000) | gpg --import
|
||||
#sopsCreateGPGHome = true;
|
||||
# To use a different directory for gpg dirs set sopsGPGHome
|
||||
#sopsGPGHome = "${toString ./.}/../gnupg";
|
||||
|
||||
nativeBuildInputs = [
|
||||
(pkgs.callPackage <sops-nix> {}).sops-pgp-hook
|
||||
(pkgs.callPackage <sops-nix> {}).sops-import-keys-hook
|
||||
];
|
||||
}
|
||||
```
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
};
|
||||
in rec {
|
||||
sops-init-gpg-key = pkgs.callPackage ./pkgs/sops-init-gpg-key {};
|
||||
sops-pgp-hook = pkgs.callPackage ./pkgs/sops-pgp-hook { };
|
||||
sops-pgp-hook = pkgs.lib.warn ''
|
||||
sops-pgp-hook is deprecated, use sops-import-keys-hook instead.
|
||||
Also see https://github.com/Mic92/sops-nix/issues/98
|
||||
'' pkgs.callPackage ./pkgs/sops-pgp-hook { };
|
||||
sops-import-keys-hook = pkgs.callPackage ./pkgs/sops-import-keys-hook { };
|
||||
inherit sops-install-secrets;
|
||||
|
||||
# backwards compatibility
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
let
|
||||
localPkgs = import ./default.nix { pkgs = final; };
|
||||
in {
|
||||
inherit (localPkgs) sops-install-secrets sops-init-gpg-key sops-pgp-hook;
|
||||
inherit (localPkgs) sops-install-secrets sops-init-gpg-key sops-pgp-hook sops-import-keys-hook;
|
||||
# backward compatibility
|
||||
inherit (prev) ssh-to-pgp;
|
||||
};
|
||||
|
|
8
pkgs/sops-import-keys-hook/default.nix
Normal file
8
pkgs/sops-import-keys-hook/default.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ stdenv, makeSetupHook, gnupg, sops, nix }:
|
||||
|
||||
(makeSetupHook {
|
||||
substitutions = {
|
||||
gpg = "${gnupg}/bin/gpg";
|
||||
};
|
||||
deps = [ sops gnupg ];
|
||||
} ./sops-import-keys-hook.bash)
|
76
pkgs/sops-import-keys-hook/hook_test.go
Normal file
76
pkgs/sops-import-keys-hook/hook_test.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ok fails the test if an err is not nil.
|
||||
func ok(tb testing.TB, err error) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellHook(t *testing.T) {
|
||||
assets := os.Getenv("TEST_ASSETS")
|
||||
if assets == "" {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
assets = path.Join(path.Dir(filename), "test-assets")
|
||||
}
|
||||
tempdir, err := ioutil.TempDir("", "testdir")
|
||||
ok(t, err)
|
||||
cmd := exec.Command("cp", "-vra", assets+"/.", tempdir)
|
||||
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
ok(t, cmd.Run())
|
||||
|
||||
defer os.RemoveAll(tempdir)
|
||||
|
||||
cmd = exec.Command("nix-shell", path.Join(assets, "shell.nix"), "--run", "gpg --list-keys")
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
cmd.Dir = tempdir
|
||||
fmt.Println(tempdir)
|
||||
err = cmd.Run()
|
||||
stdout := stdoutBuf.String()
|
||||
stderr := stderrBuf.String()
|
||||
fmt.Printf("$ %s\nstdout: \n%s\nstderr: \n%s\n", strings.Join(cmd.Args, " "), stdout, stderr)
|
||||
ok(t, err)
|
||||
|
||||
expectedKeys := []string{
|
||||
"C6DA56E69A7C756564A8AFEB4A6B05B714D13EFD",
|
||||
"4EC40F8E04A945339F7F7C0032C5225271038E3F",
|
||||
"7FB89715AADA920D65D25E63F9BA9DEBD03F57C0",
|
||||
"E3B7464FBE89F5378ED4BC60FC925B42FC8B773D",
|
||||
}
|
||||
for _, key := range expectedKeys {
|
||||
if !strings.Contains(stdout, key) {
|
||||
t.Fatalf("'%v' not in '%v'", key, stdout)
|
||||
}
|
||||
}
|
||||
|
||||
// it should ignore subkeys from ./keys/key-with-subkeys.asc
|
||||
subkey := "94F174F588090494E73D0835A79B1680BC4D9A54"
|
||||
if strings.Contains(stdout, subkey) {
|
||||
t.Fatalf("subkey found in %s", stdout)
|
||||
}
|
||||
|
||||
expectedStderr := "./non-existing-key.gpg does not exists"
|
||||
if !strings.Contains(stderr, expectedStderr) {
|
||||
t.Fatalf("'%v' not in '%v'", expectedStderr, stdout)
|
||||
}
|
||||
|
||||
}
|
33
pkgs/sops-import-keys-hook/sops-import-keys-hook.bash
Normal file
33
pkgs/sops-import-keys-hook/sops-import-keys-hook.bash
Normal file
|
@ -0,0 +1,33 @@
|
|||
_sopsAddKey() {
|
||||
@gpg@ --quiet --import "$key"
|
||||
local fpr
|
||||
# only add the first fingerprint, this way we ignore subkeys
|
||||
fpr=$(@gpg@ --with-fingerprint --with-colons --show-key "$key" \
|
||||
| awk -F: '$1 == "fpr" { print $10; exit }')
|
||||
}
|
||||
|
||||
sopsImportKeysHook() {
|
||||
local key dir
|
||||
if [ -n "${sopsCreateGPGHome}" ]; then
|
||||
export GNUPGHOME=${sopsGPGHome:-$(pwd)/.git/gnupg}
|
||||
mkdir -m 700 -p $GNUPGHOME
|
||||
fi
|
||||
for key in ${sopsPGPKeys-}; do
|
||||
if [[ -f "$key" ]]; then
|
||||
_sopsAddKey "$key"
|
||||
else
|
||||
echo "$key does not exists" >&2
|
||||
fi
|
||||
done
|
||||
for dir in ${sopsPGPKeyDirs-}; do
|
||||
while IFS= read -r -d '' key; do
|
||||
_sopsAddKey "$key"
|
||||
done < <(find -L "$dir" -type f \( -name '*.gpg' -o -name '*.asc' \) -print0)
|
||||
done
|
||||
}
|
||||
|
||||
if [ -z "${shellHook-}" ]; then
|
||||
shellHook=sopsImportKeysHook
|
||||
else
|
||||
shellHook="sopsImportKeysHook;${shellHook}"
|
||||
fi
|
BIN
pkgs/sops-import-keys-hook/test-assets/existing-key.gpg
Normal file
BIN
pkgs/sops-import-keys-hook/test-assets/existing-key.gpg
Normal file
Binary file not shown.
|
@ -0,0 +1,61 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
W1YR5NNzw2GqjhH3nhj/SnUwXg==
|
||||
=jshU
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
1
pkgs/sops-import-keys-hook/test-assets/keys/key.asc
Symbolic link
1
pkgs/sops-import-keys-hook/test-assets/keys/key.asc
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../sops-install-secrets/test-assets/key.asc
|
BIN
pkgs/sops-import-keys-hook/test-assets/keys/key.gpg
Normal file
BIN
pkgs/sops-import-keys-hook/test-assets/keys/key.gpg
Normal file
Binary file not shown.
15
pkgs/sops-import-keys-hook/test-assets/shell.nix
Normal file
15
pkgs/sops-import-keys-hook/test-assets/shell.nix
Normal file
|
@ -0,0 +1,15 @@
|
|||
# shell.nix
|
||||
with import <nixpkgs> {};
|
||||
mkShell {
|
||||
sopsPGPKeyDirs = [
|
||||
"./keys"
|
||||
];
|
||||
sopsPGPKeys = [
|
||||
"./existing-key.gpg"
|
||||
"./non-existing-key.gpg"
|
||||
];
|
||||
sopsCreateGPGHome = "1";
|
||||
nativeBuildInputs = [
|
||||
(pkgs.callPackage ../../.. {}).sops-import-keys-hook
|
||||
];
|
||||
}
|
Loading…
Reference in a new issue