mirror of
https://github.com/Mic92/sops-nix.git
synced 2024-12-14 11:57:52 +00:00
remove ssh-to-pgp from sops-nix
This commit is contained in:
parent
d578742590
commit
f540b74ced
11 changed files with 40 additions and 264 deletions
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
|
@ -28,6 +28,7 @@ jobs:
|
|||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Run lint
|
||||
run: nix-build --no-out-link default.nix -A lint
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Build nix packages
|
||||
run: nix-build --no-out-link release.nix
|
||||
- name: Run unit tests
|
||||
|
|
46
README.md
46
README.md
|
@ -122,39 +122,38 @@ If you use experimental nix flakes support:
|
|||
First generate yourself [a GPG key](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key) or use nix-sops
|
||||
conversion tool to convert an existing ssh key (we only support RSA keys right now):
|
||||
|
||||
```
|
||||
$ nix run -f https://github.com/Mic92/sops-nix/archive/master.tar.gz ssh-to-pgp
|
||||
$ ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet
|
||||
```console
|
||||
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet"
|
||||
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
# This exports the public key
|
||||
$ ssh-to-pgp -i $HOME/.ssh/id_rsa -o $USER.asc
|
||||
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i $HOME/.ssh/id_rsa -o $USER.asc"
|
||||
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```
|
||||
|
||||
If you get:
|
||||
|
||||
```
|
||||
```console
|
||||
ssh-to-pgp: failed to parse private ssh key: ssh: this private key is passphrase protected
|
||||
```
|
||||
|
||||
then your ssh key is encrypted with your password and you need to create an unencrypted copy temporarily:
|
||||
|
||||
```
|
||||
```console
|
||||
$ cp $HOME/.ssh/id_rsa /tmp/id_rsa
|
||||
$ ssh-keygen -p -N "" -f /tmp/id_rsa
|
||||
$ 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`.
|
||||
|
||||
```
|
||||
export SOPS_PGP_FP=2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```console
|
||||
$ export SOPS_PGP_FP=2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```
|
||||
|
||||
If you have generated a GnuPG key directly you can get your fingerprint like this:
|
||||
|
||||
```
|
||||
gpg --list-secret-keys
|
||||
```console
|
||||
$ gpg --list-secret-keys
|
||||
/tmp/tmp.JA07D1aVRD/pubring.kbx
|
||||
-------------------------------
|
||||
sec rsa2048 1970-01-01 [SCE]
|
||||
|
@ -170,22 +169,21 @@ The easiest way to add new hosts is using ssh host keys (requires openssh to be
|
|||
Since sops does not natively supports ssh keys yet, nix-sops supports a conversion tool
|
||||
to store them as gpg keys.
|
||||
|
||||
```
|
||||
$ nix-shell -p ssh-to-pgp
|
||||
$ ssh root@server01 "cat /etc/ssh/ssh_host_rsa_key" | ssh-to-pgp -o server01.asc
|
||||
```console
|
||||
$ ssh root@server01 "cat /etc/ssh/ssh_host_rsa_key" | nix-shell -p ssh-to-pgp --run "ssh-to-pgp -o server01.asc"
|
||||
# or with sudo
|
||||
$ ssh youruser@server01 "sudo cat /etc/ssh/ssh_host_rsa_key" | ssh-to-pgp -o server01.asc
|
||||
$ ssh youruser@server01 "sudo cat /etc/ssh/ssh_host_rsa_key" | nix-shell -p ssh-to-pgp --run "ssh-to-pgp -o server01.asc"
|
||||
0fd60c8c3b664aceb1796ce02b318df330331003
|
||||
# Or just read them locally (or in a ssh session)
|
||||
$ ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -o server01.asc
|
||||
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -o server01.asc"
|
||||
0fd60c8c3b664aceb1796ce02b318df330331003
|
||||
```
|
||||
|
||||
Also the hex string here is the fingerprint of your server's gpg key that can be exported
|
||||
append to `SOPS_PGP_FP`:
|
||||
|
||||
```
|
||||
export SOPS_PGP_FP=${SOPS_PGP_FP}:2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```console
|
||||
$ export SOPS_PGP_FP=${SOPS_PGP_FP}:2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||
```
|
||||
|
||||
If you prefer having a separate GnuPG key, see [Use with GnuPG instead of ssh keys](#use-with-gnupg-instead-of-ssh-keys).
|
||||
|
@ -195,14 +193,14 @@ If you prefer having a separate GnuPG key, see [Use with GnuPG instead of ssh ke
|
|||
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:
|
||||
|
||||
```
|
||||
export SOPS_PGP_FP="2504791468b153b8a3963cc97ba53d1919c5dfd4,2504791468b153b8a3963cc97ba53d1919c5dfd4"
|
||||
```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:
|
||||
|
||||
```
|
||||
```nix
|
||||
# shell.nix
|
||||
with import <nixpkgs> {};
|
||||
mkShell {
|
||||
|
@ -236,8 +234,8 @@ $ tree .
|
|||
|
||||
After that you can open a new file with sops
|
||||
|
||||
```
|
||||
nix-shell --run "sops secrets.yaml"
|
||||
```console
|
||||
$ nix-shell -p sops --run "sops secrets.yaml"
|
||||
```
|
||||
|
||||
This will start your configured editor
|
||||
|
@ -611,7 +609,7 @@ This is how it can be included in your configuration.nix:
|
|||
|
||||
If you prefer having a separate GnuPG key, sops-nix also comes with a helper tool:
|
||||
|
||||
```
|
||||
```console
|
||||
$ nix-shell -p sops-init-gpg-key
|
||||
$ sops-init-gpg-key --hostname server01 --gpghome /tmp/newkey
|
||||
You can use the following command to save it to a file:
|
||||
|
|
11
default.nix
11
default.nix
|
@ -9,11 +9,8 @@ in rec {
|
|||
sops-pgp-hook = pkgs.callPackage ./pkgs/sops-pgp-hook { };
|
||||
inherit sops-install-secrets;
|
||||
|
||||
ssh-to-pgp = pkgs.callPackage ./pkgs/ssh-to-pgp {
|
||||
inherit vendorSha256;
|
||||
};
|
||||
|
||||
inherit (sops-install-secrets);
|
||||
# backwards compatibility
|
||||
inherit (pkgs) ssh-to-pgp;
|
||||
|
||||
# used in the CI only
|
||||
sops-pgp-hook-test = pkgs.buildGoModule {
|
||||
|
@ -28,7 +25,7 @@ in rec {
|
|||
|
||||
unit-tests = pkgs.callPackage ./unit-tests.nix {};
|
||||
|
||||
lint = ssh-to-pgp.overrideAttrs (old: {
|
||||
lint = sops-install-secrets.overrideAttrs (old: {
|
||||
name = "golangci-lint";
|
||||
nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.golangci-lint ];
|
||||
buildPhase = ''
|
||||
|
@ -36,7 +33,7 @@ in rec {
|
|||
'';
|
||||
doCheck = false;
|
||||
installPhase = ''
|
||||
touch $out
|
||||
touch $out $unittest
|
||||
'';
|
||||
fixupPhase = ":";
|
||||
});
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1612101959,
|
||||
"narHash": "sha256-7IsEL/6wpr1fI/XyIw26Rz+KjRCoJvoozIcTRpCFfMQ=",
|
||||
"lastModified": 1613917044,
|
||||
"narHash": "sha256-YvBBwtvrnove51SXQ67OVQHctYjEEpFu6GEzRe0pp5I=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1b77b735ea70c3dfbdab3eaa79aee48d75d3e162",
|
||||
"rev": "aed173ff9707387b238c1c7e143152ca9d8878e9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
let
|
||||
localPkgs = import ./default.nix { pkgs = final; };
|
||||
in {
|
||||
inherit (localPkgs) sops-install-secrets sops-init-gpg-key sops-pgp-hook ssh-to-pgp;
|
||||
inherit (localPkgs) sops-install-secrets sops-init-gpg-key sops-pgp-hook;
|
||||
# backward compatibility
|
||||
inherit (prev) ssh-to-pgp;
|
||||
};
|
||||
nixosModules.sops = import ./modules/sops;
|
||||
packages = forAllSystems (system: import ./default.nix {
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/Mic92/sops-nix/pkgs/sshkeys"
|
||||
"github.com/Mic92/sops-nix/pkgs/sops-install-secrets/sshkeys"
|
||||
|
||||
"github.com/mozilla-services/yaml"
|
||||
"go.mozilla.org/sops/v3/decrypt"
|
||||
|
@ -106,16 +106,16 @@ type appContext struct {
|
|||
func secureSymlinkChown(symlinkToCheck, expectedTarget string, owner, group int) error {
|
||||
fd, err := unix.Open(symlinkToCheck, unix.O_CLOEXEC|unix.O_PATH|unix.O_NOFOLLOW, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to open %s: %w", symlinkToCheck, err)
|
||||
return fmt.Errorf("Failed to open %s: %w", symlinkToCheck, err)
|
||||
}
|
||||
defer unix.Close(fd)
|
||||
|
||||
buf := make([]byte, len(expectedTarget) + 1) // oversize by one to detect trunc
|
||||
buf := make([]byte, len(expectedTarget)+1) // oversize by one to detect trunc
|
||||
n, err := unix.Readlinkat(fd, "", buf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't readlinkat %s", symlinkToCheck)
|
||||
}
|
||||
if n > len(expectedTarget) || string(buf[:n]) != expectedTarget {
|
||||
if n > len(expectedTarget) || string(buf[:n]) != expectedTarget {
|
||||
return fmt.Errorf("symlink %s does not point to %s", symlinkToCheck, expectedTarget)
|
||||
}
|
||||
err = unix.Fchownat(fd, "", owner, group, unix.AT_EMPTY_PATH)
|
||||
|
@ -140,7 +140,7 @@ func readManifest(path string) (*manifest, error) {
|
|||
}
|
||||
|
||||
func linksAreEqual(linkTarget, targetFile string, info os.FileInfo, secret *secret) bool {
|
||||
validUG := true;
|
||||
validUG := true
|
||||
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||
validUG = validUG && int(stat.Uid) == secret.owner
|
||||
validUG = validUG && int(stat.Gid) == secret.group
|
||||
|
@ -234,7 +234,7 @@ func decryptSecret(s *secret, sourceFiles map[string]plainData) error {
|
|||
strVal, ok := val.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("The value of key '%s' in '%s' is not a string", s.Key, s.SopsFile)
|
||||
}
|
||||
}
|
||||
s.value = []byte(strVal)
|
||||
}
|
||||
sourceFiles[s.SopsFile] = sourceFile
|
||||
|
@ -258,7 +258,7 @@ func mountSecretFs(mountpoint string, keysGid int) error {
|
|||
return fmt.Errorf("Cannot create directory '%s': %w", mountpoint, err)
|
||||
}
|
||||
|
||||
buf := unix.Statfs_t {}
|
||||
buf := unix.Statfs_t{}
|
||||
if err := unix.Statfs(mountpoint, &buf); err != nil {
|
||||
return fmt.Errorf("Cannot get statfs for directory '%s': %w", mountpoint, err)
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
{ stdenv, lib, buildGoModule, gnupg, vendorSha256, }:
|
||||
buildGoModule {
|
||||
pname = "ssh-to-pgp";
|
||||
version = "0.0.1";
|
||||
|
||||
src = ../..;
|
||||
|
||||
subPackages = [ "pkgs/ssh-to-pgp" ];
|
||||
|
||||
checkInputs = [ gnupg ];
|
||||
checkPhase = ''
|
||||
HOME=$TMPDIR go test ./pkgs/ssh-to-pgp
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
|
||||
inherit vendorSha256;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Convert ssh public/private keys to PGP";
|
||||
homepage = "https://github.com/Mic92/sops-nix";
|
||||
license = licenses.mit;
|
||||
maintainers = with maintainers; [ mic92 ];
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/Mic92/sops-nix/pkgs/sshkeys"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/armor"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
format, out, in string
|
||||
privateKey bool
|
||||
}
|
||||
|
||||
func parseFlags(args []string) options {
|
||||
var opts options
|
||||
f := flag.NewFlagSet(args[0], flag.ExitOnError)
|
||||
f.BoolVar(&opts.privateKey, "private-key", false, "Export private key instead of public key")
|
||||
f.StringVar(&opts.format, "format", "armor", "GPG format encoding (binary|armor)")
|
||||
f.StringVar(&opts.in, "i", "-", "Input path. Reads by default from standard output")
|
||||
f.StringVar(&opts.out, "o", "-", "Output path. Prints by default to standard output")
|
||||
if err := f.Parse(args[1:]); err != nil {
|
||||
// should never happen since flag.ExitOnError
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func convertKeys(args []string) error {
|
||||
opts := parseFlags(args)
|
||||
var err error
|
||||
var sshKey []byte
|
||||
if opts.in == "-" {
|
||||
sshKey, _ = ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading stdin: %w", err)
|
||||
}
|
||||
} else {
|
||||
sshKey, err = ioutil.ReadFile(opts.in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading %s: %w", opts.in, err)
|
||||
}
|
||||
}
|
||||
|
||||
writer := io.WriteCloser(os.Stdout)
|
||||
if opts.out != "-" {
|
||||
writer, err = os.Create(opts.out)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create %s: %w", opts.out, err)
|
||||
}
|
||||
defer writer.Close()
|
||||
}
|
||||
|
||||
if opts.format == "armor" {
|
||||
keyType := openpgp.PublicKeyType
|
||||
if opts.privateKey {
|
||||
keyType = openpgp.PrivateKeyType
|
||||
}
|
||||
writer, err = armor.Encode(writer, keyType, make(map[string]string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encode armor writer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
gpgKey, err := sshkeys.SSHPrivateKeyToPGP(sshKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.privateKey {
|
||||
err = gpgKey.SerializePrivate(writer, nil)
|
||||
} else {
|
||||
err = gpgKey.Serialize(writer)
|
||||
}
|
||||
if err == nil {
|
||||
if opts.format == "armor" {
|
||||
writer.Close()
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", hex.EncodeToString(gpgKey.PrimaryKey.Fingerprint[:]))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := convertKeys(os.Args); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"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 TempRoot() string {
|
||||
if runtime.GOOS == "darwin" {
|
||||
// macOS make its TEMPDIR long enough for unix socket to break
|
||||
return "/tmp"
|
||||
} else {
|
||||
return os.TempDir()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCli(t *testing.T) {
|
||||
assets := os.Getenv("TEST_ASSETS")
|
||||
if assets == "" {
|
||||
assets = "test-assets"
|
||||
}
|
||||
tempdir, err := ioutil.TempDir(TempRoot(), "testdir")
|
||||
ok(t, err)
|
||||
defer os.RemoveAll(tempdir)
|
||||
|
||||
gpgHome := path.Join(tempdir, "gpg-home")
|
||||
gpgEnv := append(os.Environ(), fmt.Sprintf("GNUPGHOME=%s", gpgHome))
|
||||
ok(t, os.Mkdir(gpgHome, os.FileMode(0700)))
|
||||
|
||||
out := path.Join(tempdir, "out")
|
||||
privKey := path.Join(assets, "id_rsa")
|
||||
cmds := [][]string{
|
||||
{"ssh-to-pgp", "-i", privKey, "-o", out},
|
||||
{"ssh-to-pgp", "-format=binary", "-i", privKey, "-o", out},
|
||||
{"ssh-to-pgp", "-private-key", "-i", privKey, "-o", out},
|
||||
{"ssh-to-pgp", "-format=binary", "-private-key", "-i", privKey, "-o", out},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
err = convertKeys(cmd)
|
||||
ok(t, err)
|
||||
cmd := exec.Command("gpg", "--with-fingerprint", "--show-key", out)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = gpgEnv
|
||||
ok(t, cmd.Run())
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
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
|
||||
-----END OPENSSH PRIVATE KEY-----
|
Loading…
Reference in a new issue