This commit is contained in:
Jimmy Cuadra 2020-07-04 10:47:06 -07:00
Родитель 334be56818
Коммит e8d00046e1
9 изменённых файлов: 1198 добавлений и 456 удалений

183
age/keysource.go Normal file
Просмотреть файл

@ -0,0 +1,183 @@
package age
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"
"filippo.io/age"
)
// MasterKey is an age key used to encrypt and decrypt sops' data key.
type MasterKey struct {
Identity string // a Bech32-encoded private key
Recipient string // a Bech32-encoded public key
EncryptedKey string // a sops data key encrypted with age
parsedIdentity *age.X25519Identity // a parsed age private key
parsedRecipient *age.X25519Recipient // a parsed age public key
}
// Encrypt takes a sops data key, encrypts it with age and stores the result in the EncryptedKey field.
func (key *MasterKey) Encrypt(datakey []byte) error {
buffer := &bytes.Buffer{}
if key.parsedRecipient == nil {
parsedRecipient, err := age.ParseX25519Recipient(key.Recipient)
if err != nil {
return fmt.Errorf("failed to parse input as Bech32-encoded age public key: %v", err)
}
key.parsedRecipient = parsedRecipient
}
w, err := age.Encrypt(buffer, key.parsedRecipient)
if err != nil {
return fmt.Errorf("failed to open file for encrypting sops data key with age: %v", err)
}
if _, err := w.Write(datakey); err != nil {
return fmt.Errorf("failed to encrypt sops data key with age: %v", err)
}
if err := w.Close(); err != nil {
return fmt.Errorf("failed to close file for encrypting sops data key with age: %v", err)
}
key.EncryptedKey = buffer.String()
return nil
}
// EncryptIfNeeded encrypts the provided sops' data key and encrypts it if it hasn't been encrypted yet.
func (key *MasterKey) EncryptIfNeeded(datakey []byte) error {
if key.EncryptedKey == "" {
return key.Encrypt(datakey)
}
return nil
}
// EncryptedDataKey returns the encrypted data key this master key holds.
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
// SetEncryptedDataKey sets the encrypted data key for this master key.
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}
// Decrypt decrypts the EncryptedKey field with the age identity and returns the result.
func (key *MasterKey) Decrypt() ([]byte, error) {
path := fmt.Sprintf("%s/.sops/age/%s.key", os.Getenv("HOME"), key.Recipient)
_, err := os.Stat(path)
if os.IsNotExist(err) {
return nil, fmt.Errorf("no private key found at %s", path)
}
file, err := os.Open(path)
defer file.Close()
scanner := bufio.NewScanner(file)
var privateKey string
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "AGE-SECRET-KEY") {
privateKey = line
break
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error scanning lines in age private key file: %v", err)
}
if privateKey == "" {
return nil, fmt.Errorf("no age private key found in file at: %v", path)
}
parsedIdentity, err := age.ParseX25519Identity(string(privateKey))
if err != nil {
return nil, fmt.Errorf("failed to parse private key as age X25519Identity at %s: %v", path, err)
}
buffer := &bytes.Buffer{}
reader := bytes.NewReader([]byte(key.EncryptedKey))
r, err := age.Decrypt(reader, parsedIdentity)
if err != nil {
return nil, fmt.Errorf("failed to open encrypted data key: %v", err)
}
if _, err := io.Copy(buffer, r); err != nil {
return nil, fmt.Errorf("failed to read encrypted data key: %v", err)
}
return buffer.Bytes(), nil
}
// NeedsRotation returns whether the data key needs to be rotated or not.
func (key *MasterKey) NeedsRotation() bool {
return false
}
// ToString converts the key to a string representation.
func (key *MasterKey) ToString() string {
return key.Recipient
}
// ToMap converts the MasterKey to a map for serialization purposes.
func (key *MasterKey) ToMap() map[string]interface{} {
out := make(map[string]interface{})
out["recipient"] = key.Recipient
out["enc"] = key.EncryptedKey
return out
}
// MasterKeysFromRecipients takes a comma-separated list of Bech32-encoded public keys and returns a
// slice of new MasterKeys.
func MasterKeysFromRecipients(commaSeparatedRecipients string) ([]*MasterKey, error) {
recipients := strings.Split(commaSeparatedRecipients, ",")
var keys []*MasterKey
for _, recipient := range recipients {
key, err := MasterKeyFromRecipient(recipient)
if err != nil {
return nil, err
}
keys = append(keys, key)
}
return keys, nil
}
// MasterKeyFromRecipient takes a Bech32-encoded public key and returns a new MasterKey.
func MasterKeyFromRecipient(recipient string) (*MasterKey, error) {
parsedRecipient, err := age.ParseX25519Recipient(recipient)
if err != nil {
return nil, err
}
return &MasterKey{
Recipient: recipient,
parsedRecipient: parsedRecipient,
}, nil
}

Просмотреть файл

@ -16,6 +16,7 @@ import (
"github.com/sirupsen/logrus"
"go.mozilla.org/sops/v3"
"go.mozilla.org/sops/v3/aes"
"go.mozilla.org/sops/v3/age"
_ "go.mozilla.org/sops/v3/audit"
"go.mozilla.org/sops/v3/azkv"
"go.mozilla.org/sops/v3/cmd/sops/codes"
@ -61,7 +62,7 @@ func main() {
},
}
app.Name = "sops"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Azure Key Vault and GPG support"
app.Usage = "sops - encrypted file editor with AWS KMS, GCP KMS, Azure Key Vault, age, and GPG support"
app.ArgsUsage = "sops [options] file"
app.Version = version.Version
app.Authors = []cli.Author{
@ -96,6 +97,9 @@ func main() {
https://docs.microsoft.com/en-us/go/azure/azure-sdk-go-authorization#use-environment-based-authentication.
The user/sp needs the key/encrypt and key/decrypt permissions)
To encrypt or decrypt using age, specify the recipient in the -a flag, or
in the SOPS_AGE_RECIPIENTS environment variable.
To encrypt or decrypt using PGP, specify the PGP fingerprint in the
-p flag or in the SOPS_PGP_FP environment variable.
@ -377,6 +381,10 @@ func main() {
Name: "hc-vault-transit",
Usage: "the full vault path to the key used to encrypt/decrypt. Make you choose and configure a key with encrption/decryption enabled (e.g. 'https://vault.example.org:8200/v1/transit/keys/dev'). Can be specified more than once",
},
cli.StringSliceFlag{
Name: "age",
Usage: "the age recipient the new group should contain. Can be specified more than once",
},
cli.BoolFlag{
Name: "in-place, i",
Usage: "write output back to the same file instead of stdout",
@ -396,6 +404,7 @@ func main() {
gcpKmses := c.StringSlice("gcp-kms")
vaultURIs := c.StringSlice("hc-vault-transit")
azkvs := c.StringSlice("azure-kv")
ageRecipients := c.StringSlice("age")
var group sops.KeyGroup
for _, fp := range pgpFps {
group = append(group, pgp.NewMasterKeyFromFingerprint(fp))
@ -422,6 +431,14 @@ func main() {
}
group = append(group, k)
}
for _, recipient := range ageRecipients {
k, err := age.MasterKeyFromRecipient(recipient)
if err != nil {
log.WithError(err).Error("Failed to add key")
continue
}
group = append(group, k)
}
return groups.Add(groups.AddOpts{
InputPath: c.String("file"),
InPlace: c.Bool("in-place"),
@ -552,6 +569,11 @@ func main() {
Usage: "comma separated list of PGP fingerprints",
EnvVar: "SOPS_PGP_FP",
},
cli.StringFlag{
Name: "age, a",
Usage: "comma separated list of age recipients",
EnvVar: "SOPS_AGE_RECIPIENTS",
},
cli.BoolFlag{
Name: "in-place, i",
Usage: "write output back to the same file instead of stdout",
@ -604,6 +626,14 @@ func main() {
Name: "rm-hc-vault-transit",
Usage: "remove the provided comma-separated list of Vault's URI key from the list of master keys on the given file ( eg. https://vault.example.org:8200/v1/transit/keys/dev)",
},
cli.StringFlag{
Name: "add-age",
Usage: "add the provided comma-separated list of age recipients fingerprints to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-age",
Usage: "remove the provided comma-separated list of age recipients from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-pgp",
Usage: "add the provided comma-separated list of PGP fingerprints to the list of master keys on the given file",
@ -673,8 +703,8 @@ func main() {
return toExitError(err)
}
if _, err := os.Stat(fileName); os.IsNotExist(err) {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-hc-vault-transit") != "" || c.String("add-azure-kv") != "" || c.String("add-age") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-hc-vault-transit") != "" || c.String("rm-azure-kv") != "" || c.String("rm-age") != "" {
return common.NewExitError("Error: cannot add or remove keys on non-existent files, use `--kms` and `--pgp` instead.", codes.CannotChangeKeysFromNonExistentFile)
}
if c.Bool("encrypt") || c.Bool("decrypt") || c.Bool("rotate") {
@ -802,6 +832,13 @@ func main() {
for _, k := range hcVaultKeys {
addMasterKeys = append(addMasterKeys, k)
}
ageKeys, err := age.MasterKeysFromRecipients(c.String("add-age"))
if err != nil {
return err
}
for _, k := range ageKeys {
addMasterKeys = append(addMasterKeys, k)
}
var rmMasterKeys []keys.MasterKey
for _, k := range kms.MasterKeysFromArnString(c.String("rm-kms"), kmsEncryptionContext, c.String("aws-profile")) {
@ -827,6 +864,13 @@ func main() {
for _, k := range hcVaultKeys {
rmMasterKeys = append(rmMasterKeys, k)
}
ageKeys, err = age.MasterKeysFromRecipients(c.String("rm-age"))
if err != nil {
return err
}
for _, k := range ageKeys {
rmMasterKeys = append(rmMasterKeys, k)
}
output, err = rotate(rotateOpts{
OutputStore: outputStore,
@ -1023,6 +1067,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
var cloudKmsKeys []keys.MasterKey
var azkvKeys []keys.MasterKey
var hcVaultMkKeys []keys.MasterKey
var ageMasterKeys []keys.MasterKey
kmsEncryptionContext := kms.ParseKMSContext(c.String("encryption-context"))
if c.String("encryption-context") != "" && kmsEncryptionContext == nil {
return nil, common.NewExitError("Invalid KMS encryption context format", codes.ErrorInvalidKMSEncryptionContextFormat)
@ -1060,7 +1105,16 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
pgpKeys = append(pgpKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" {
if c.String("age") != "" {
ageKeys, err := age.MasterKeysFromRecipients(c.String("age"))
if err != nil {
return nil, err
}
for _, k := range ageKeys {
ageMasterKeys = append(ageMasterKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" && c.String("hc-vault-transit") == "" && c.String("age") == "" {
conf, err := loadConfig(c, file, kmsEncryptionContext)
// config file might just not be supplied, without any error
if conf == nil {
@ -1078,6 +1132,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
group = append(group, azkvKeys...)
group = append(group, pgpKeys...)
group = append(group, hcVaultMkKeys...)
group = append(group, ageMasterKeys...)
log.Debugf("Master keys available: %+v", group)
return []sops.KeyGroup{group}, nil
}

10
go.mod
Просмотреть файл

@ -4,6 +4,7 @@ go 1.13
require (
cloud.google.com/go v0.43.0
filippo.io/age v1.0.0-beta4
github.com/Azure/azure-sdk-for-go v31.2.0+incompatible
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Azure/go-autorest/autorest v0.9.0
@ -19,8 +20,8 @@ require (
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/fatih/color v1.7.0
github.com/golang/protobuf v1.3.2
github.com/google/go-cmp v0.3.0
github.com/golang/protobuf v1.4.1
github.com/google/go-cmp v0.5.0
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/goware/prefixer v0.0.0-20160118172347-395022866408
@ -40,11 +41,12 @@ require (
github.com/stretchr/testify v1.5.1
github.com/vektra/mockery v1.1.2 // indirect
go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
google.golang.org/api v0.7.0
google.golang.org/grpc v1.22.1
google.golang.org/grpc v1.27.0
google.golang.org/protobuf v1.25.0
gopkg.in/ini.v1 v1.44.0
gopkg.in/urfave/cli.v1 v1.20.0
gotest.tools v2.2.0+incompatible // indirect

42
go.sum
Просмотреть файл

@ -5,6 +5,8 @@ cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w=
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc=
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
filippo.io/age v1.0.0-beta4 h1:czSjaSa0owsI5gw/cE9yI/mfTiuhgYjozHI96v0PVJo=
filippo.io/age v1.0.0-beta4/go.mod h1:TOa3exZvzRCLfjmbJGsqwSQ0HtWjJfTTCQnQsNCC4E0=
github.com/Azure/azure-sdk-for-go v31.2.0+incompatible h1:kZFnTLmdQYNGfakatSivKHUfUnDZhqNdchHD4oIhp5k=
github.com/Azure/azure-sdk-for-go v31.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
@ -60,6 +62,7 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -77,6 +80,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@ -99,6 +104,13 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@ -107,6 +119,10 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -224,6 +240,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -233,6 +250,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@ -247,6 +266,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/vektra/mockery v1.1.2 h1:uc0Yn67rJpjt8U/mAZimdCKn9AeA97BOkjpmtBSlfP4=
@ -267,6 +287,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49N
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@ -370,6 +392,9 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 h1:Ygq9/SRJX9+dU0WCIICM8RkWvDw03lvB77hrhJnpxfU=
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -377,14 +402,26 @@ google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -398,6 +435,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

Просмотреть файл

@ -7,6 +7,7 @@ package keyservice
import (
"fmt"
"go.mozilla.org/sops/v3/age"
"go.mozilla.org/sops/v3/azkv"
"go.mozilla.org/sops/v3/gcpkms"
"go.mozilla.org/sops/v3/hcvault"
@ -69,6 +70,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *age.MasterKey:
return Key{
KeyType: &Key_AgeKey{
AgeKey: &AgeKey{
Recipient: mk.Recipient,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -7,6 +7,7 @@ message Key {
GcpKmsKey gcp_kms_key = 3;
AzureKeyVaultKey azure_keyvault_key = 4;
VaultKey vault_key = 5;
AgeKey age_key = 6;
}
}
@ -37,6 +38,10 @@ message AzureKeyVaultKey {
string version = 3;
}
message AgeKey {
string recipient = 1;
}
message EncryptRequest {
Key key = 1;
bytes plaintext = 2;

Просмотреть файл

@ -3,6 +3,7 @@ package keyservice
import (
"fmt"
"go.mozilla.org/sops/v3/age"
"go.mozilla.org/sops/v3/azkv"
"go.mozilla.org/sops/v3/gcpkms"
"go.mozilla.org/sops/v3/hcvault"
@ -75,6 +76,20 @@ func (ks *Server) encryptWithVault(key *VaultKey, plaintext []byte) ([]byte, err
return []byte(vaultKey.EncryptedKey), nil
}
func (ks *Server) encryptWithAge(key *AgeKey, plaintext []byte) ([]byte, error) {
ageKey := age.MasterKey{
Recipient: key.Recipient,
}
err := ageKey.Encrypt(plaintext)
if err != nil {
return nil, err
}
return []byte(ageKey.EncryptedKey), nil
}
func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error) {
pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint)
pgpKey.EncryptedKey = string(ciphertext)
@ -120,6 +135,15 @@ func (ks *Server) decryptWithVault(key *VaultKey, ciphertext []byte) ([]byte, er
return []byte(plaintext), err
}
func (ks *Server) decryptWithAge(key *AgeKey, ciphertext []byte) ([]byte, error) {
ageKey := age.MasterKey{
Recipient: key.Recipient,
}
ageKey.EncryptedKey = string(ciphertext)
plaintext, err := ageKey.Decrypt()
return []byte(plaintext), err
}
// Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted
// result
func (ks Server) Encrypt(ctx context.Context,
@ -167,6 +191,14 @@ func (ks Server) Encrypt(ctx context.Context,
response = &EncryptResponse{
Ciphertext: ciphertext,
}
case *Key_AgeKey:
ciphertext, err := ks.encryptWithAge(k.AgeKey, req.Plaintext)
if err != nil {
return nil, err
}
response = &EncryptResponse{
Ciphertext: ciphertext,
}
case nil:
return nil, status.Errorf(codes.NotFound, "Must provide a key")
default:
@ -261,6 +293,14 @@ func (ks Server) Decrypt(ctx context.Context,
response = &DecryptResponse{
Plaintext: plaintext,
}
case *Key_AgeKey:
plaintext, err := ks.decryptWithAge(k.AgeKey, req.Ciphertext)
if err != nil {
return nil, err
}
response = &DecryptResponse{
Plaintext: plaintext,
}
case nil:
return nil, grpc.Errorf(codes.NotFound, "Must provide a key")
default:

Просмотреть файл

@ -15,6 +15,7 @@ import (
"fmt"
"go.mozilla.org/sops/v3"
"go.mozilla.org/sops/v3/age"
"go.mozilla.org/sops/v3/azkv"
"go.mozilla.org/sops/v3/gcpkms"
"go.mozilla.org/sops/v3/hcvault"
@ -42,6 +43,7 @@ type Metadata struct {
GCPKMSKeys []gcpkmskey `yaml:"gcp_kms" json:"gcp_kms"`
AzureKeyVaultKeys []azkvkey `yaml:"azure_kv" json:"azure_kv"`
VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"`
AgeKeys []agekey `yaml:"age" json:"age"`
LastModified string `yaml:"lastmodified" json:"lastmodified"`
MessageAuthenticationCode string `yaml:"mac" json:"mac"`
PGPKeys []pgpkey `yaml:"pgp" json:"pgp"`
@ -58,6 +60,7 @@ type keygroup struct {
GCPKMSKeys []gcpkmskey `yaml:"gcp_kms,omitempty" json:"gcp_kms,omitempty"`
AzureKeyVaultKeys []azkvkey `yaml:"azure_kv,omitempty" json:"azure_kv,omitempty"`
VaultKeys []vaultkey `yaml:"hc_vault" json:"hc_vault"`
AgeKeys []agekey `yaml:"age" json:"age"`
}
type pgpkey struct {
@ -97,6 +100,11 @@ type azkvkey struct {
EncryptedDataKey string `yaml:"enc" json:"enc"`
}
type agekey struct {
Recipient string `yaml:"recipient" json:"recipient"`
EncryptedDataKey string `yaml:"enc" json:"enc"`
}
// MetadataFromInternal converts an internal SOPS metadata representation to a representation appropriate for storage
func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
var m Metadata
@ -115,6 +123,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
m.GCPKMSKeys = gcpkmsKeysFromGroup(group)
m.VaultKeys = vaultKeysFromGroup(group)
m.AzureKeyVaultKeys = azkvKeysFromGroup(group)
m.AgeKeys = ageKeysFromGroup(group)
} else {
for _, group := range sopsMetadata.KeyGroups {
m.KeyGroups = append(m.KeyGroups, keygroup{
@ -123,6 +132,7 @@ func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
GCPKMSKeys: gcpkmsKeysFromGroup(group),
VaultKeys: vaultKeysFromGroup(group),
AzureKeyVaultKeys: azkvKeysFromGroup(group),
AgeKeys: ageKeysFromGroup(group),
})
}
}
@ -206,6 +216,19 @@ func azkvKeysFromGroup(group sops.KeyGroup) (keys []azkvkey) {
return
}
func ageKeysFromGroup(group sops.KeyGroup) (keys []agekey) {
for _, key := range group {
switch key := key.(type) {
case *age.MasterKey:
keys = append(keys, agekey{
Recipient: key.Recipient,
EncryptedDataKey: key.EncryptedKey,
})
}
}
return
}
// ToInternal converts a storage-appropriate Metadata struct to a SOPS internal representation
func (m *Metadata) ToInternal() (sops.Metadata, error) {
lastModified, err := time.Parse(time.RFC3339, m.LastModified)
@ -251,7 +274,7 @@ func (m *Metadata) ToInternal() (sops.Metadata, error) {
}, nil
}
func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, azkvKeys []azkvkey, vaultKeys []vaultkey) (sops.KeyGroup, error) {
func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmskey, azkvKeys []azkvkey, vaultKeys []vaultkey, ageKeys []agekey) (sops.KeyGroup, error) {
var internalGroup sops.KeyGroup
for _, kmsKey := range kmsKeys {
k, err := kmsKey.toInternal()
@ -288,13 +311,20 @@ func internalGroupFrom(kmsKeys []kmskey, pgpKeys []pgpkey, gcpKmsKeys []gcpkmske
}
internalGroup = append(internalGroup, k)
}
for _, ageKey := range ageKeys {
k, err := ageKey.toInternal()
if err != nil {
return nil, err
}
internalGroup = append(internalGroup, k)
}
return internalGroup, nil
}
func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) {
var internalGroups []sops.KeyGroup
if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 {
internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys, m.VaultKeys)
if len(m.PGPKeys) > 0 || len(m.KMSKeys) > 0 || len(m.GCPKMSKeys) > 0 || len(m.AzureKeyVaultKeys) > 0 || len(m.VaultKeys) > 0 || len(m.AgeKeys) > 0 {
internalGroup, err := internalGroupFrom(m.KMSKeys, m.PGPKeys, m.GCPKMSKeys, m.AzureKeyVaultKeys, m.VaultKeys, m.AgeKeys)
if err != nil {
return nil, err
}
@ -302,7 +332,7 @@ func (m *Metadata) internalKeygroups() ([]sops.KeyGroup, error) {
return internalGroups, nil
} else if len(m.KeyGroups) > 0 {
for _, group := range m.KeyGroups {
internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.AzureKeyVaultKeys, group.VaultKeys)
internalGroup, err := internalGroupFrom(group.KMSKeys, group.PGPKeys, group.GCPKMSKeys, group.AzureKeyVaultKeys, group.VaultKeys, group.AgeKeys)
if err != nil {
return nil, err
}
@ -381,6 +411,13 @@ func (pgpKey *pgpkey) toInternal() (*pgp.MasterKey, error) {
}, nil
}
func (ageKey *agekey) toInternal() (*age.MasterKey, error) {
return &age.MasterKey{
EncryptedKey: ageKey.EncryptedDataKey,
Recipient: ageKey.Recipient,
}, nil
}
// ExampleComplexTree is an example sops.Tree object exhibiting complex relationships
var ExampleComplexTree = sops.Tree{
Branches: sops.TreeBranches{