Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NACL BOX master key support #569

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 76 additions & 23 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"go.mozilla.org/sops/cmd/sops/subcommand/exec"
"go.mozilla.org/sops/cmd/sops/subcommand/groups"
keyservicecmd "go.mozilla.org/sops/cmd/sops/subcommand/keyservice"
"go.mozilla.org/sops/cmd/sops/subcommand/makenaclboxkey"
publishcmd "go.mozilla.org/sops/cmd/sops/subcommand/publish"
"go.mozilla.org/sops/cmd/sops/subcommand/updatekeys"
"go.mozilla.org/sops/config"
Expand All @@ -30,6 +31,7 @@ import (
"go.mozilla.org/sops/keyservice"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/logging"
"go.mozilla.org/sops/naclbox"
"go.mozilla.org/sops/pgp"
"go.mozilla.org/sops/stores/dotenv"
"go.mozilla.org/sops/stores/json"
Expand Down Expand Up @@ -65,8 +67,10 @@ func main() {
app.Authors = []cli.Author{
{Name: "Julien Vehent", Email: "jvehent@mozilla.com"},
{Name: "Adrian Utrilla", Email: "adrianutrilla@gmail.com"},
{Name: "AJ Bahnken", Email: "ajvb@mozilla.com"},
}
app.UsageText = `sops is an editor of encrypted files that supports AWS KMS and PGP
app.UsageText = `sops is an editor of encrypted files that supports AWS & GCP KMS,
Azure Key Vault, Nacl Box and PGP.

To encrypt or decrypt a document with AWS KMS, specify the KMS ARN
in the -k flag or in the SOPS_KMS_ARN environment variable.
Expand All @@ -85,6 +89,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 NACL BOX, specify the base64 encoded public key
in the -n flag, or in the SOPS_NACLBOX_PUBKEYS environment variable.

To encrypt or decrypt using PGP, specify the PGP fingerprint in the
-p flag or in the SOPS_PGP_FP environment variable.

Expand All @@ -106,16 +113,16 @@ func main() {
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "exec-env",
Usage: "execute a command with decrypted values inserted into the environment",
Name: "exec-env",
Usage: "execute a command with decrypted values inserted into the environment",
ArgsUsage: "[file to decrypt] [command to run]",
Flags: append([]cli.Flag{
cli.BoolFlag{
Name: "background",
Name: "background",
Usage: "background the process and don't wait for it to complete",
},
cli.StringFlag{
Name: "user",
Name: "user",
Usage: "the user to run the command as",
},
}, keyserviceFlags...),
Expand All @@ -129,13 +136,12 @@ func main() {

inputStore := inputStore(c, fileName)


svcs := keyservices(c)
opts := decryptOpts{
OutputStore: &dotenv.Store{},
InputStore: inputStore,
InputPath: fileName,
Cipher: aes.NewCipher(),
Cipher: aes.NewCipher(),
KeyServices: svcs,
IgnoreMAC: c.Bool("ignore-mac"),
}
Expand All @@ -146,30 +152,30 @@ func main() {
}

exec.ExecWithEnv(exec.ExecOpts{
Command: command,
Plaintext: output,
Command: command,
Plaintext: output,
Background: c.Bool("background"),
User: c.String("user"),
User: c.String("user"),
})

return nil
},
},
{
Name: "exec-file",
Usage: "execute a command with the decrypted contents as a temporary file",
Name: "exec-file",
Usage: "execute a command with the decrypted contents as a temporary file",
ArgsUsage: "[file to decrypt] [command to run]",
Flags: append([]cli.Flag{
cli.BoolFlag{
Name: "background",
Name: "background",
Usage: "background the process and don't wait for it to complete",
},
cli.BoolFlag{
Name: "no-fifo",
Name: "no-fifo",
Usage: "use a regular file instead of a fifo to temporarily hold the decrypted contents",
},
cli.StringFlag{
Name: "user",
Name: "user",
Usage: "the user to run the command as",
},
}, keyserviceFlags...),
Expand All @@ -189,7 +195,7 @@ func main() {
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
Cipher: aes.NewCipher(),
Cipher: aes.NewCipher(),
KeyServices: svcs,
IgnoreMAC: c.Bool("ignore-mac"),
}
Expand All @@ -200,11 +206,11 @@ func main() {
}

exec.ExecWithFile(exec.ExecOpts{
Command: command,
Plaintext: output,
Command: command,
Plaintext: output,
Background: c.Bool("background"),
Fifo: !c.Bool("no-fifo"),
User: c.String("user"),
Fifo: !c.Bool("no-fifo"),
User: c.String("user"),
})

return nil
Expand Down Expand Up @@ -253,6 +259,19 @@ func main() {
return nil
},
},
{
Name: "makenaclboxkey",
Usage: "Make a NACL BOX key pair",
Action: func(c *cli.Context) error {
err := makenaclboxkey.Run()
if cliErr, ok := err.(*cli.ExitError); ok && cliErr != nil {
return cliErr
} else if err != nil {
return common.NewExitError(err, codes.ErrorGeneric)
}
return nil
},
},
{
Name: "keyservice",
Usage: "start a SOPS key service server",
Expand Down Expand Up @@ -324,6 +343,10 @@ func main() {
Name: "azure-kv",
Usage: "the Azure Key Vault key URL the new group should contain. Can be specified more than once",
},
cli.StringSliceFlag{
Name: "naclbox",
Usage: "the NACL BOX public key 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",
Expand All @@ -342,10 +365,14 @@ func main() {
kmsArns := c.StringSlice("kms")
gcpKmses := c.StringSlice("gcp-kms")
azkvs := c.StringSlice("azure-kv")
naclboxPubKeys := c.StringSlice("naclbox")
var group sops.KeyGroup
for _, fp := range pgpFps {
group = append(group, pgp.NewMasterKeyFromFingerprint(fp))
}
for _, pubkey := range naclboxPubKeys {
group = append(group, naclbox.NewMasterKeyFromPublicKey(pubkey))
}
for _, arn := range kmsArns {
group = append(group, kms.NewMasterKeyFromArn(arn, kms.ParseKMSContext(c.String("encryption-context")), c.String("aws-profile")))
}
Expand Down Expand Up @@ -479,6 +506,11 @@ func main() {
Usage: "comma separated list of PGP fingerprints",
EnvVar: "SOPS_PGP_FP",
},
cli.StringFlag{
Name: "naclbox, n",
Usage: "comma separated list of NACL BOX public keys",
EnvVar: "SOPS_NACLBOX_PUBKEYS",
},
cli.BoolFlag{
Name: "in-place, i",
Usage: "write output back to the same file instead of stdout",
Expand Down Expand Up @@ -531,6 +563,14 @@ func main() {
Name: "rm-pgp",
Usage: "remove the provided comma-separated list of PGP fingerprints from the list of master keys on the given file",
},
cli.StringFlag{
Name: "add-naclbox",
Usage: "add the provided comma-separated list of NACLBOX keys to the list of master keys on the given file",
},
cli.StringFlag{
Name: "rm-naclbox",
Usage: "remove the provided comma-separated list of NACLBOX keys from the list of master keys on the given file",
},
cli.BoolFlag{
Name: "ignore-mac",
Usage: "ignore Message Authentication Code during decryption",
Expand Down Expand Up @@ -588,8 +628,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-azure-kv") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-azure-kv") != "" {
if c.String("add-kms") != "" || c.String("add-pgp") != "" || c.String("add-gcp-kms") != "" || c.String("add-azure-kv") != "" || c.String("add-naclbox") != "" ||
c.String("rm-kms") != "" || c.String("rm-pgp") != "" || c.String("rm-gcp-kms") != "" || c.String("rm-azure-kv") != "" || c.String("rm-naclbox") != "" {
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") {
Expand Down Expand Up @@ -692,6 +732,9 @@ func main() {
for _, k := range pgp.MasterKeysFromFingerprintString(c.String("add-pgp")) {
addMasterKeys = append(addMasterKeys, k)
}
for _, k := range naclbox.MasterKeysFromPublicKeysString(c.String("add-naclbox")) {
addMasterKeys = append(addMasterKeys, k)
}
for _, k := range gcpkms.MasterKeysFromResourceIDString(c.String("add-gcp-kms")) {
addMasterKeys = append(addMasterKeys, k)
}
Expand All @@ -710,6 +753,9 @@ func main() {
for _, k := range pgp.MasterKeysFromFingerprintString(c.String("rm-pgp")) {
rmMasterKeys = append(rmMasterKeys, k)
}
for _, k := range naclbox.MasterKeysFromPublicKeysString(c.String("rm-naclbox")) {
rmMasterKeys = append(rmMasterKeys, k)
}
for _, k := range gcpkms.MasterKeysFromResourceIDString(c.String("rm-gcp-kms")) {
rmMasterKeys = append(rmMasterKeys, k)
}
Expand Down Expand Up @@ -912,6 +958,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
var pgpKeys []keys.MasterKey
var cloudKmsKeys []keys.MasterKey
var azkvKeys []keys.MasterKey
var naclboxKeys []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)
Expand Down Expand Up @@ -940,7 +987,12 @@ 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") == "" {
if c.String("naclbox") != "" {
for _, k := range naclbox.MasterKeysFromPublicKeysString(c.String("naclbox")) {
naclboxKeys = append(naclboxKeys, k)
}
}
if c.String("kms") == "" && c.String("pgp") == "" && c.String("gcp-kms") == "" && c.String("azure-kv") == "" && c.String("naclbox") == "" {
conf, err := loadConfig(c, file, kmsEncryptionContext)
// config file might just not be supplied, without any error
if conf == nil {
Expand All @@ -957,6 +1009,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
group = append(group, cloudKmsKeys...)
group = append(group, azkvKeys...)
group = append(group, pgpKeys...)
group = append(group, naclboxKeys...)
return []sops.KeyGroup{group}, nil
}

Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191107222254-f4817d981bb6 h1:VsmCukA2gDdC3Mu6evOIT0QjLSQWiJIwzv1Bdj4jdzU=
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=
Expand Down
9 changes: 9 additions & 0 deletions keyservice/keyservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/keys"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/naclbox"
"go.mozilla.org/sops/pgp"
)

Expand Down Expand Up @@ -58,6 +59,14 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *naclbox.MasterKey:
return Key{
KeyType: &Key_NaclboxKey{
NaclboxKey: &NaclBoxKey{
Publickey: mk.PublicKey,
},
},
}
default:
panic(fmt.Sprintf("Tried to convert unknown MasterKey type %T to keyservice.Key", mk))
}
Expand Down
Loading