Files
charts/clustertool/pkg/sops/wrapper.go
2024-10-17 12:56:56 +02:00

158 lines
3.6 KiB
Go

package sops
import (
"errors"
"fmt"
"github.com/getsops/sops/v3"
"github.com/getsops/sops/v3/aes"
"github.com/getsops/sops/v3/age"
"github.com/getsops/sops/v3/cmd/sops/common"
"github.com/getsops/sops/v3/cmd/sops/formats"
"github.com/getsops/sops/v3/config"
"github.com/getsops/sops/v3/decrypt"
"github.com/getsops/sops/v3/keys"
"github.com/getsops/sops/v3/keyservice"
"github.com/getsops/sops/v3/version"
"github.com/truecharts/public/clustertool/pkg/helper"
)
var encrConfig *EncryptionConfig
const ageKeyFilePath = "./age.agekey"
func EncryptWithAgeKey(body []byte, regex string, format string) ([]byte, error) {
// Create a cypher instance
cypher := NewCypher()
sopsConfig, err := LoadSopsConfig()
if err != nil {
return nil, err
}
var groups []sops.KeyGroup
var ageKeys []string
// Iterate over each creation rule and find matching files
for _, rule := range sopsConfig.CreationRules {
if err != nil {
return nil, fmt.Errorf("invalid path regex in .sops.yaml: %v", err)
}
ageKeys = append(ageKeys, rule.Age)
}
for _, ageKey := range helper.UniqueNonEmptyElementsOf(ageKeys) {
var keyGroup sops.KeyGroup
keyGroup = append(keyGroup, NewMasterKey(ageKey))
groups = append(groups, keyGroup)
}
// Encrypt the data using the sops key
encryptedData, err := cypher.Encrypt(body, EncryptionConfig{
Keys: groups,
UnencryptedSuffix: "",
EncryptedSuffix: "",
UnencryptedRegex: "",
EncryptedRegex: regex,
ShamirThreshold: 3,
Format: format,
})
if err != nil {
return nil, fmt.Errorf("error encrypting data: %v", err)
}
return encryptedData, nil
}
/// Custom keygroup
func NewMasterKey(pubkey string) (result keys.MasterKey) {
result, err := age.MasterKeyFromRecipient(pubkey)
if err != nil {
}
return result
}
/// IMPORTED
const (
formatYaml = "yaml"
formatJson = "json"
)
type Cypher interface {
Decrypt(content []byte, config string) ([]byte, error)
Encrypt(data []byte, config EncryptionConfig) ([]byte, error)
}
type cypher struct{}
func NewCypher() Cypher {
return &cypher{}
}
func (c *cypher) Decrypt(content []byte, format string) ([]byte, error) {
return decrypt.Data(content, format)
}
type EncryptionConfig struct {
Format string
Keys []sops.KeyGroup
UnencryptedSuffix string
EncryptedSuffix string
UnencryptedRegex string
EncryptedRegex string
ShamirThreshold int
}
func (m *cypher) Encrypt(content []byte, encrConfig EncryptionConfig) (result []byte, err error) {
var store common.Store
switch encrConfig.Format {
case formatYaml:
store = common.StoreForFormat(formats.Yaml, config.NewStoresConfig())
default:
store = common.StoreForFormat(formats.Json, config.NewStoresConfig())
}
branches, err := store.LoadPlainFile(content)
if err != nil {
return
}
tree := sops.Tree{
Branches: branches,
Metadata: sops.Metadata{
KeyGroups: encrConfig.Keys,
UnencryptedSuffix: encrConfig.UnencryptedSuffix,
EncryptedSuffix: encrConfig.EncryptedSuffix,
UnencryptedRegex: encrConfig.UnencryptedRegex,
EncryptedRegex: encrConfig.EncryptedRegex,
Version: version.Version,
ShamirThreshold: encrConfig.ShamirThreshold,
},
}
dataKey, errs := tree.GenerateDataKeyWithKeyServices(
[]keyservice.KeyServiceClient{keyservice.NewLocalClient()},
)
if len(errs) > 0 {
return nil, errors.New(fmt.Sprint("Could not generate data key:", errs))
}
encryptTreeOpts := common.EncryptTreeOpts{
DataKey: dataKey,
Tree: &tree,
Cipher: aes.NewCipher(),
}
err = common.EncryptTree(encryptTreeOpts)
if err != nil {
return nil, err
}
return store.EmitEncryptedFile(tree)
}