1
0
Fork 0
mirror of https://github.com/Mic92/sops-nix.git synced 2025-03-16 05:28:15 +00:00

Replace sops-gpg-hook with sops-import-keys-hook

This commit is contained in:
Jörg Thalheim 2021-07-03 07:36:22 +02:00
parent 7918c59b39
commit 73e19bf11b
No known key found for this signature in database
GPG key ID: B3F5D81B0C6967C4
11 changed files with 246 additions and 19 deletions

View file

@ -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" $ 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 ```yaml
$ export SOPS_PGP_FP=2504791468b153b8a3963cc97ba53d1919c5dfd4 # 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: 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 0fd60c8c3b664aceb1796ce02b318df330331003
``` ```
Also the hex string here is the fingerprint of your server's gpg key that can be exported Also the hex string here is the fingerprint of your server's gpg key that can be exported append to `.sops.yaml`:
append to `SOPS_PGP_FP`:
```console ```yaml
$ export SOPS_PGP_FP=${SOPS_PGP_FP}:2504791468b153b8a3963cc97ba53d1919c5dfd4 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). 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 ### 4. Create a sops file
To create a sops file you need to set export `SOPS_PGP_FP` to include both the fingerprint To create a sops file you need write a `.sops.yaml` as described above and
of your personal gpg key (and your colleagues) and your servers: import your personal gpg key (and your colleagues) and your servers into your
gpg key chain.
```console sops-nix automates importing gpg keys with a hook for nix-shell allowing public
$ export SOPS_PGP_FP="2504791468b153b8a3963cc97ba53d1919c5dfd4,2504791468b153b8a3963cc97ba53d1919c5dfd4" keys to be shared via version control (i.e. git):
```
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:
```nix ```nix
# shell.nix # shell.nix
with import <nixpkgs> {}; with import <nixpkgs> {};
mkShell { mkShell {
# imports all files ending in .asc/.gpg and sets $SOPS_PGP_FP. # imports all files ending in .asc/.gpg
sopsPGPKeyDirs = [ sopsPGPKeyDirs = [
"./keys/hosts" "./keys/hosts"
"./keys/users" "./keys/users"
@ -214,8 +228,23 @@ mkShell {
# "./keys/users/mic92.asc" # "./keys/users/mic92.asc"
# "./keys/hosts/server01.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 = [ nativeBuildInputs = [
(pkgs.callPackage <sops-nix> {}).sops-pgp-hook (pkgs.callPackage <sops-nix> {}).sops-import-keys-hook
]; ];
} }
``` ```

View file

@ -6,7 +6,11 @@
}; };
in rec { in rec {
sops-init-gpg-key = pkgs.callPackage ./pkgs/sops-init-gpg-key {}; 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; inherit sops-install-secrets;
# backwards compatibility # backwards compatibility

View file

@ -16,7 +16,7 @@
let let
localPkgs = import ./default.nix { pkgs = final; }; localPkgs = import ./default.nix { pkgs = final; };
in { 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 # backward compatibility
inherit (prev) ssh-to-pgp; inherit (prev) ssh-to-pgp;
}; };

View file

@ -0,0 +1,8 @@
{ stdenv, makeSetupHook, gnupg, sops, nix }:
(makeSetupHook {
substitutions = {
gpg = "${gnupg}/bin/gpg";
};
deps = [ sops gnupg ];
} ./sops-import-keys-hook.bash)

View 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)
}
}

View 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

View file

@ -0,0 +1,61 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
W1YR5NNzw2GqjhH3nhj/SnUwXg==
=jshU
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -0,0 +1 @@
../../../sops-install-secrets/test-assets/key.asc

Binary file not shown.

View 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
];
}