Skip to content

Commit

Permalink
Simplify handling of encryption config (what to encrypt, key groups, …
Browse files Browse the repository at this point in the history
…Shamir threshold, etc.).

Signed-off-by: Felix Fontein <[email protected]>
  • Loading branch information
felixfontein committed Dec 29, 2023
1 parent cc0477c commit c5c5980
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 113 deletions.
19 changes: 2 additions & 17 deletions cmd/sops/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,7 @@ type editOpts struct {

type editExampleOpts struct {
editOpts
UnencryptedSuffix string
EncryptedSuffix string
UnencryptedRegex string
EncryptedRegex string
MACOnlyEncrypted bool
KeyGroups []sops.KeyGroup
GroupThreshold int
encryptConfig
}

type runEditorUntilOkOpts struct {
Expand All @@ -61,16 +55,7 @@ func editExample(opts editExampleOpts) ([]byte, error) {
}
tree := sops.Tree{
Branches: branches,
Metadata: sops.Metadata{
KeyGroups: opts.KeyGroups,
UnencryptedSuffix: opts.UnencryptedSuffix,
EncryptedSuffix: opts.EncryptedSuffix,
UnencryptedRegex: opts.UnencryptedRegex,
EncryptedRegex: opts.EncryptedRegex,
MACOnlyEncrypted: opts.MACOnlyEncrypted,
Version: version.Version,
ShamirThreshold: opts.GroupThreshold,
},
Metadata: metadataFromEncryptionConfig(opts.encryptConfig),
FilePath: path,
}

Expand Down
40 changes: 24 additions & 16 deletions cmd/sops/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ import (
"github.com/mitchellh/go-wordwrap"
)

type encryptOpts struct {
Cipher sops.Cipher
InputStore sops.Store
OutputStore sops.Store
InputPath string
KeyServices []keyservice.KeyServiceClient
type encryptConfig struct {
UnencryptedSuffix string
EncryptedSuffix string
UnencryptedRegex string
Expand All @@ -28,6 +23,15 @@ type encryptOpts struct {
GroupThreshold int
}

type encryptOpts struct {
Cipher sops.Cipher
InputStore sops.Store
OutputStore sops.Store
InputPath string
KeyServices []keyservice.KeyServiceClient
encryptConfig
}

type fileAlreadyEncryptedError struct{}

func (err *fileAlreadyEncryptedError) Error() string {
Expand Down Expand Up @@ -55,6 +59,19 @@ func ensureNoMetadata(opts encryptOpts, branch sops.TreeBranch) error {
return nil
}

func metadataFromEncryptionConfig(config encryptConfig) sops.Metadata {
return sops.Metadata{
KeyGroups: config.KeyGroups,
UnencryptedSuffix: config.UnencryptedSuffix,
EncryptedSuffix: config.EncryptedSuffix,
UnencryptedRegex: config.UnencryptedRegex,
EncryptedRegex: config.EncryptedRegex,
MACOnlyEncrypted: config.MACOnlyEncrypted,
Version: version.Version,
ShamirThreshold: config.GroupThreshold,
}
}

func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
// Load the file
fileBytes, err := os.ReadFile(opts.InputPath)
Expand All @@ -77,16 +94,7 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
}
tree := sops.Tree{
Branches: branches,
Metadata: sops.Metadata{
KeyGroups: opts.KeyGroups,
UnencryptedSuffix: opts.UnencryptedSuffix,
EncryptedSuffix: opts.EncryptedSuffix,
UnencryptedRegex: opts.UnencryptedRegex,
EncryptedRegex: opts.EncryptedRegex,
MACOnlyEncrypted: opts.MACOnlyEncrypted,
Version: version.Version,
ShamirThreshold: opts.GroupThreshold,
},
Metadata: metadataFromEncryptionConfig(opts.encryptConfig),
FilePath: path,
}
dataKey, errs := tree.GenerateDataKeyWithKeyServices(opts.KeyServices)
Expand Down
177 changes: 97 additions & 80 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,56 +834,11 @@ func main() {
fileNameOverride = fileName
}

unencryptedSuffix := c.String("unencrypted-suffix")
encryptedSuffix := c.String("encrypted-suffix")
encryptedRegex := c.String("encrypted-regex")
unencryptedRegex := c.String("unencrypted-regex")
macOnlyEncrypted := c.Bool("mac-only-encrypted")
conf, err := loadConfig(c, fileNameOverride, nil)
// Load configuration here for backwards compatibility (error out in case of bad config files)
_, err = loadConfig(c, fileNameOverride, nil)
if err != nil {
return toExitError(err)
}
if conf != nil {
// command line options have precedence
if unencryptedSuffix == "" {
unencryptedSuffix = conf.UnencryptedSuffix
}
if encryptedSuffix == "" {
encryptedSuffix = conf.EncryptedSuffix
}
if encryptedRegex == "" {
encryptedRegex = conf.EncryptedRegex
}
if unencryptedRegex == "" {
unencryptedRegex = conf.UnencryptedRegex
}
if !macOnlyEncrypted {
macOnlyEncrypted = conf.MACOnlyEncrypted
}
}

cryptRuleCount := 0
if unencryptedSuffix != "" {
cryptRuleCount++
}
if encryptedSuffix != "" {
cryptRuleCount++
}
if encryptedRegex != "" {
cryptRuleCount++
}
if unencryptedRegex != "" {
cryptRuleCount++
}

if cryptRuleCount > 1 {
return common.NewExitError("Error: cannot use more than one of encrypted_suffix, unencrypted_suffix, encrypted_regex or unencrypted_regex in the same file", codes.ErrorConflictingParameters)
}

// only supply the default UnencryptedSuffix when EncryptedSuffix and EncryptedRegex are not provided
if cryptRuleCount == 0 {
unencryptedSuffix = sops.DefaultUnencryptedSuffix
}

inputStore := inputStore(c, fileNameOverride)
outputStore := outputStore(c, fileNameOverride)
Expand All @@ -895,30 +850,24 @@ func main() {
}
var output []byte
if c.Bool("encrypt") {
var groups []sops.KeyGroup
groups, err = keyGroups(c, fileNameOverride)
if err != nil {
return toExitError(err)
}
var threshold int
threshold, err = shamirThreshold(c, fileNameOverride)
encConfig, err := getEncryptConfig(c, fileNameOverride)
if err != nil {
return toExitError(err)
}
output, err = encrypt(encryptOpts{
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
Cipher: aes.NewCipher(),
UnencryptedSuffix: unencryptedSuffix,
EncryptedSuffix: encryptedSuffix,
UnencryptedRegex: unencryptedRegex,
EncryptedRegex: encryptedRegex,
MACOnlyEncrypted: macOnlyEncrypted,
KeyServices: svcs,
KeyGroups: groups,
GroupThreshold: threshold,
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
Cipher: aes.NewCipher(),
KeyServices: svcs,
encryptConfig: encConfig,
})
// While this check is also done below, the `err` in this scope shadows
// the `err` in the outer scope. **Only** do this in case --decrypt,
// --rotate-, and --set are not specified, though, to keep old behavior.
if err != nil && !c.Bool("decrypt") && !c.Bool("rotate") && c.String("set") == "" {
return toExitError(err)
}
}

if c.Bool("decrypt") {
Expand Down Expand Up @@ -1060,26 +1009,19 @@ func main() {
output, err = edit(opts)
} else {
// File doesn't exist, edit the example file instead
var groups []sops.KeyGroup
groups, err = keyGroups(c, fileNameOverride)
encConfig, err := getEncryptConfig(c, fileNameOverride)
if err != nil {
return toExitError(err)
}
var threshold int
threshold, err = shamirThreshold(c, fileNameOverride)
output, err = editExample(editExampleOpts{
editOpts: opts,
encryptConfig: encConfig,
})
// While this check is also done below, the `err` in this scope shadows
// the `err` in the outer scope
if err != nil {
return toExitError(err)
}
output, err = editExample(editExampleOpts{
editOpts: opts,
UnencryptedSuffix: unencryptedSuffix,
EncryptedSuffix: encryptedSuffix,
UnencryptedRegex: unencryptedRegex,
EncryptedRegex: encryptedRegex,
MACOnlyEncrypted: macOnlyEncrypted,
KeyGroups: groups,
GroupThreshold: threshold,
})
}
}

Expand Down Expand Up @@ -1121,6 +1063,81 @@ func main() {
}
}

func getEncryptConfig(c *cli.Context, fileName string) (encryptConfig, error) {
unencryptedSuffix := c.String("unencrypted-suffix")
encryptedSuffix := c.String("encrypted-suffix")
encryptedRegex := c.String("encrypted-regex")
unencryptedRegex := c.String("unencrypted-regex")
macOnlyEncrypted := c.Bool("mac-only-encrypted")
conf, err := loadConfig(c, fileName, nil)
if err != nil {
return encryptConfig{}, toExitError(err)
}
if conf != nil {
// command line options have precedence
if unencryptedSuffix == "" {
unencryptedSuffix = conf.UnencryptedSuffix
}
if encryptedSuffix == "" {
encryptedSuffix = conf.EncryptedSuffix
}
if encryptedRegex == "" {
encryptedRegex = conf.EncryptedRegex
}
if unencryptedRegex == "" {
unencryptedRegex = conf.UnencryptedRegex
}
if !macOnlyEncrypted {
macOnlyEncrypted = conf.MACOnlyEncrypted
}
}

cryptRuleCount := 0
if unencryptedSuffix != "" {
cryptRuleCount++
}
if encryptedSuffix != "" {
cryptRuleCount++
}
if encryptedRegex != "" {
cryptRuleCount++
}
if unencryptedRegex != "" {
cryptRuleCount++
}

if cryptRuleCount > 1 {
return encryptConfig{}, common.NewExitError("Error: cannot use more than one of encrypted_suffix, unencrypted_suffix, encrypted_regex, or unencrypted_regex in the same file", codes.ErrorConflictingParameters)
}

// only supply the default UnencryptedSuffix when EncryptedSuffix, EncryptedRegex, and others are not provided
if cryptRuleCount == 0 {
unencryptedSuffix = sops.DefaultUnencryptedSuffix
}

var groups []sops.KeyGroup
groups, err = keyGroups(c, fileName)
if err != nil {
return encryptConfig{}, err
}

var threshold int
threshold, err = shamirThreshold(c, fileName)
if err != nil {
return encryptConfig{}, err
}

return encryptConfig{
UnencryptedSuffix: unencryptedSuffix,
EncryptedSuffix: encryptedSuffix,
UnencryptedRegex: unencryptedRegex,
EncryptedRegex: encryptedRegex,
MACOnlyEncrypted: macOnlyEncrypted,
KeyGroups: groups,
GroupThreshold: threshold,
}, nil
}

func toExitError(err error) error {
if cliErr, ok := err.(*cli.ExitError); ok && cliErr != nil {
return cliErr
Expand Down

0 comments on commit c5c5980

Please sign in to comment.