1
0
mirror of https://github.com/getsops/sops.git synced 2026-02-05 12:45:21 +01:00

Introduce key service flag optionally prompting users on encryption/decryption (#322)

This commit is contained in:
Adrian Utrilla
2018-04-11 14:46:50 +02:00
committed by GitHub
parent 16950d00d2
commit 37b6fff84d
3 changed files with 79 additions and 16 deletions

View File

@@ -110,11 +110,23 @@ func main() {
Usage: "address to listen on, e.g. '127.0.0.1:5000' or '/tmp/sops.sock'",
Value: "127.0.0.1:5000",
},
cli.BoolFlag{
Name: "prompt",
Usage: "Prompt user to confirm every incoming request",
},
cli.BoolFlag{
Name: "verbose",
Usage: "Enable verbose logging output",
},
},
Action: func(c *cli.Context) error {
if c.Bool("verbose") {
logging.SetLevel(logrus.DebugLevel)
}
return keyservicecmd.Run(keyservicecmd.Opts{
Network: c.String("network"),
Address: c.String("address"),
Prompt: c.Bool("prompt"),
})
},
},
@@ -356,8 +368,6 @@ func main() {
app.Action = func(c *cli.Context) error {
if c.Bool("verbose") {
logging.SetLevel(logrus.DebugLevel)
} else {
logging.SetLevel(logrus.WarnLevel)
}
if c.NArg() < 1 {
return common.NewExitError("Error: no file specified", codes.NoFileSpecified)

View File

@@ -23,6 +23,7 @@ func init() {
type Opts struct {
Network string
Address string
Prompt bool
}
// Run runs a SOPS key service server
@@ -33,7 +34,9 @@ func Run(opts Opts) error {
}
defer lis.Close()
grpcServer := grpc.NewServer()
keyservice.RegisterKeyServiceServer(grpcServer, keyservice.Server{})
keyservice.RegisterKeyServiceServer(grpcServer, keyservice.Server{
Prompt: opts.Prompt,
})
log.Infof("Listening on %s://%s", opts.Network, opts.Address)
// Close socket if we get killed

View File

@@ -1,6 +1,8 @@
package keyservice
import (
"fmt"
"go.mozilla.org/sops/gcpkms"
"go.mozilla.org/sops/kms"
"go.mozilla.org/sops/pgp"
@@ -11,7 +13,10 @@ import (
)
// Server is a key service server that uses SOPS MasterKeys to fulfill requests
type Server struct{}
type Server struct {
// Prompt indicates whether the server should prompt before decrypting or encrypting data
Prompt bool
}
func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error) {
pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint)
@@ -86,36 +91,73 @@ func (ks *Server) decryptWithGcpKms(key *GcpKmsKey, ciphertext []byte) ([]byte,
func (ks Server) Encrypt(ctx context.Context,
req *EncryptRequest) (*EncryptResponse, error) {
key := *req.Key
var response *EncryptResponse
switch k := key.KeyType.(type) {
case *Key_PgpKey:
ciphertext, err := ks.encryptWithPgp(k.PgpKey, req.Plaintext)
if err != nil {
return nil, err
}
return &EncryptResponse{
response = &EncryptResponse{
Ciphertext: ciphertext,
}, nil
}
case *Key_KmsKey:
ciphertext, err := ks.encryptWithKms(k.KmsKey, req.Plaintext)
if err != nil {
return nil, err
}
return &EncryptResponse{
response = &EncryptResponse{
Ciphertext: ciphertext,
}, nil
}
case *Key_GcpKmsKey:
ciphertext, err := ks.encryptWithGcpKms(k.GcpKmsKey, req.Plaintext)
if err != nil {
return nil, err
}
return &EncryptResponse{
response = &EncryptResponse{
Ciphertext: ciphertext,
}, nil
}
case nil:
return nil, status.Errorf(codes.NotFound, "Must provide a key")
default:
return nil, status.Errorf(codes.NotFound, "Unknown key type")
}
if ks.Prompt {
err := ks.prompt(key, "encrypt")
if err != nil {
return nil, err
}
}
return response, nil
}
func keyToString(key Key) string {
switch k := key.KeyType.(type) {
case *Key_PgpKey:
return fmt.Sprintf("PGP key with fingerprint %s", k.PgpKey.Fingerprint)
case *Key_KmsKey:
return fmt.Sprintf("AWS KMS key with ARN %s", k.KmsKey.Arn)
case *Key_GcpKmsKey:
return fmt.Sprintf("GCP KMS key with resource ID %s", k.GcpKmsKey.ResourceId)
default:
return fmt.Sprintf("Unknown key type")
}
}
func (ks Server) prompt(key Key, requestType string) error {
keyString := keyToString(key)
var response string
for response != "y" && response != "n" {
fmt.Printf("\nReceived %s request using %s. Respond to request? (y/n): ", requestType, keyString)
_, err := fmt.Scanln(&response)
if err != nil {
return err
}
}
if response == "n" {
return grpc.Errorf(codes.PermissionDenied, "Request rejected by user")
}
return nil
}
// Decrypt takes a decrypt request and decrypts the provided ciphertext with the provided key, returning the decrypted
@@ -123,34 +165,42 @@ func (ks Server) Encrypt(ctx context.Context,
func (ks Server) Decrypt(ctx context.Context,
req *DecryptRequest) (*DecryptResponse, error) {
key := *req.Key
var response *DecryptResponse
switch k := key.KeyType.(type) {
case *Key_PgpKey:
plaintext, err := ks.decryptWithPgp(k.PgpKey, req.Ciphertext)
if err != nil {
return nil, err
}
return &DecryptResponse{
response = &DecryptResponse{
Plaintext: plaintext,
}, nil
}
case *Key_KmsKey:
plaintext, err := ks.decryptWithKms(k.KmsKey, req.Ciphertext)
if err != nil {
return nil, err
}
return &DecryptResponse{
response = &DecryptResponse{
Plaintext: plaintext,
}, nil
}
case *Key_GcpKmsKey:
plaintext, err := ks.decryptWithGcpKms(k.GcpKmsKey, req.Ciphertext)
if err != nil {
return nil, err
}
return &DecryptResponse{
response = &DecryptResponse{
Plaintext: plaintext,
}, nil
}
case nil:
return nil, grpc.Errorf(codes.NotFound, "Must provide a key")
default:
return nil, grpc.Errorf(codes.NotFound, "Unknown key type")
}
if ks.Prompt {
err := ks.prompt(key, "decrypt")
if err != nil {
return nil, err
}
}
return response, nil
}