Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
28344fd
PoC(keystore::plugin): Proof of Concept start
Dexmachi Jun 4, 2026
15cb869
lint
Dexmachi Jun 4, 2026
b3a4d5b
better handling
Dexmachi Jun 5, 2026
35c8b51
fix order
Dexmachi Jun 5, 2026
60ba87e
fix order
Dexmachi Jun 5, 2026
c0b5eab
Merge branch 'main' into feat/plugs
Dexmachi Jun 5, 2026
063c855
feat(keystore): add granular timeouts
Dexmachi Jun 5, 2026
007e708
feat?(keystore): instanceId
Dexmachi Jun 5, 2026
5e7c0b6
fix(keystore::plugin): not having a lsp cause of formating is weird
Dexmachi Jun 5, 2026
0318a6f
fix(plugin): Now uses binaryName instead of default
Dexmachi Jun 5, 2026
2e6a6c6
fix(test::plugin): localization
Dexmachi Jun 5, 2026
762e42e
add(metadata): plugins in the metadata
Dexmachi Jun 5, 2026
08da841
feat(plugin): add initial keyservice support
Dexmachi Jun 5, 2026
38edd4b
feat(plugin-interface): add validation and sanity checks
Dexmachi Jun 7, 2026
7a8b7ed
feat(plugin_tests): add more coverage
Dexmachi Jun 7, 2026
0822c51
fix(plugin-interface): make tests pass
Dexmachi Jun 7, 2026
53eaebb
lint(stores/server): replace spaces with tabs
Dexmachi Jun 7, 2026
fbda3a9
fix(plugin-interface): inconsistency
Dexmachi Jun 7, 2026
65a27ff
test(plugin): add concurrency test
Dexmachi Jun 7, 2026
73172ea
Merge branch 'main' into feat/plugs
Dexmachi Jun 15, 2026
8e3c9ec
Merge branch 'main' into feat/plugs
Dexmachi Jun 30, 2026
dac5906
Merge branch 'main' into feat/plugs
Dexmachi Jul 4, 2026
32acad7
Merge branch 'main' into feat/plugs
Dexmachi Jul 13, 2026
be0147d
Merge branch 'main' into feat/plugs
Dexmachi Aug 28, 2026
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
27 changes: 27 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/getsops/sops/v3/hcvault"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/plugin"
"github.com/getsops/sops/v3/publish"
"go.yaml.in/yaml/v3"
)
Expand Down Expand Up @@ -129,6 +130,13 @@ type configFile struct {
Stores StoresConfig `yaml:"stores"`
}

type pluginKey struct {
Timeout string `yaml:"timeout,omitempty"`
BinaryName string `yaml:"binary_name"`
InstanceID string `yaml:"instance_id,omitempty"`
Config map[string]any `yaml:"config"`
}

type keyGroup struct {
Merge []keyGroup `yaml:"merge"`
KMS []kmsKey `yaml:"kms"`
Expand All @@ -138,6 +146,7 @@ type keyGroup struct {
Vault []string `yaml:"hc_vault"`
Age []string `yaml:"age"`
PGP []string `yaml:"pgp"`
Plugin []pluginKey `yaml:"plugins"`
}

type gcpKmsKey struct {
Expand Down Expand Up @@ -177,6 +186,7 @@ type destinationRule struct {

type creationRule struct {
PathRegex string `yaml:"path_regex"`
Timeout string `yaml:"timeout,omitempty"`
KMS interface{} `yaml:"kms"` // string or []string
AwsProfile string `yaml:"aws_profile"`
Age interface{} `yaml:"age"` // string or []string
Expand All @@ -187,6 +197,7 @@ type creationRule struct {
VaultURI interface{} `yaml:"hc_vault_transit_uri"` // string or []string
KeyGroups []keyGroup `yaml:"key_groups"`
ShamirThreshold int `yaml:"shamir_threshold"`
Plugin []pluginKey `yaml:"plugins"`
UnencryptedSuffix string `yaml:"unencrypted_suffix"`
EncryptedSuffix string `yaml:"encrypted_suffix"`
UnencryptedRegex string `yaml:"unencrypted_regex"`
Expand Down Expand Up @@ -357,6 +368,14 @@ func extractMasterKeys(group keyGroup) (sops.KeyGroup, error) {
return nil, err
}
}


for _, p := range group.Plugin {
resolvedTimeout := p.Timeout
mKey := plugin.NewMasterKey(p.BinaryName, p.Config, resolvedTimeout, p.InstanceID)
keyGroup = append(keyGroup, mKey)
}

return deduplicateKeygroup(keyGroup), nil
}

Expand Down Expand Up @@ -445,6 +464,14 @@ func getKeyGroupsFromCreationRule(cRule *creationRule, kmsEncryptionContext map[
for _, k := range vaultKeys {
keyGroup = append(keyGroup, k)
}
for _, p := range cRule.Plugin {
resolvedTimeout := p.Timeout
if resolvedTimeout == "" {
resolvedTimeout = cRule.Timeout
}
mKey := plugin.NewMasterKey(p.BinaryName, p.Config, resolvedTimeout, p.InstanceID)
keyGroup = append(keyGroup, mKey)
}
groups = append(groups, keyGroup)
}
return groups, nil
Expand Down
14 changes: 14 additions & 0 deletions keyservice/keyservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ master keys.
package keyservice

import (
"encoding/json"
"fmt"

"github.com/getsops/sops/v3/age"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/getsops/sops/v3/keys"
"github.com/getsops/sops/v3/kms"
"github.com/getsops/sops/v3/pgp"
"github.com/getsops/sops/v3/plugin"
)

// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers
Expand Down Expand Up @@ -46,6 +48,18 @@ func KeyFromMasterKey(mk keys.MasterKey) Key {
},
},
}
case *plugin.MasterKey:
configBytes, _ := json.Marshal(mk.PluginConfig)
return Key{
KeyType: &Key_PluginKey{
PluginKey: &PluginKey{
BinaryName: mk.BinaryName,
InstanceId: mk.InstanceID,
Config: string(configBytes),
Timeout: mk.Timeout,
},
},
}
case *kms.MasterKey:
ctx := make(map[string]string)
for k, v := range mk.EncryptionContext {
Expand Down
Loading