diff --git a/docs/configuration.md b/docs/configuration.md index 55b67bba83..82edb51418 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -129,12 +129,12 @@ db: ### Key Access Server (KAS) -| Field | Description | Default | -| ------------------ | ------------------------------------------------------------------------------- | ------- | -| `enabled` | Enable the Key Access Server | `true` | -| `keyring.*.kid` | Which key id this is binding | | -| `keyring.*.alg` | (Optional) Associated algorithm. (Allows reusing KID with different algorithms) | | -| `keyring.*.legacy` | When loading a TDF with no key identifier, this key may be used. | `false` | +| Field | Description | Default | +| ------------------ | ------------------------------------------------------------------------------- | -------- | +| `enabled` | Enable the Key Access Server | `true` | +| `keyring.*.kid` | Which key id this is binding | | +| `keyring.*.alg` | (Optional) Associated algorithm. (Allows reusing KID with different algorithms) | | +| `keyring.*.legacy` | Indicates this may be used for TDFs with no key ID; default if all unspecified. | inferred | Example: @@ -179,4 +179,4 @@ services: | `clientsecret` | Client Credentials Secret | | | `tokenendpoint` | OAuth 2 Token Endpoint (Will be removed at a later time) | | | `rego.path` | Path to rego policy file | Leverages embedded rego policy | -| `rego.query` | Rego query to execute in policy | `data.opentdf.entitlements.attributes` | \ No newline at end of file +| `rego.query` | Rego query to execute in policy | `data.opentdf.entitlements.attributes` | diff --git a/service/kas/kas.go b/service/kas/kas.go index 05dd2a8bb4..76deb2d903 100644 --- a/service/kas/kas.go +++ b/service/kas/kas.go @@ -60,6 +60,8 @@ func NewRegistration() serviceregistry.Registration { } deprecatedOrDefault(kasCfg.ECCertID, security.AlgorithmECP256R1) deprecatedOrDefault(kasCfg.RSACertID, security.AlgorithmRSA2048) + default: + kasCfg.Keyring = append(kasCfg.Keyring, inferLegacyKeys(kasCfg.Keyring)...) } p := access.Provider{ @@ -86,3 +88,19 @@ func NewRegistration() serviceregistry.Registration { }, } } + +// If there exists *any* legacy keys, returns empty list. +// Otherwise, create a copy with legacy=true for all values +func inferLegacyKeys(keys []access.CurrentKeyFor) []access.CurrentKeyFor { + for _, k := range keys { + if k.Legacy { + return nil + } + } + l := make([]access.CurrentKeyFor, len(keys)) + for i, k := range keys { + l[i] = k + l[i].Legacy = true + } + return l +} diff --git a/service/kas/kidless_test.go b/service/kas/kidless_test.go new file mode 100644 index 0000000000..02d0275576 --- /dev/null +++ b/service/kas/kidless_test.go @@ -0,0 +1,58 @@ +package kas + +import ( + "testing" + + "github.com/opentdf/platform/service/internal/security" + "github.com/opentdf/platform/service/kas/access" + "github.com/stretchr/testify/assert" +) + +func TestInferLegacyKeys_empty(t *testing.T) { + assert.Empty(t, inferLegacyKeys(nil)) +} + +func TestInferLegacyKeys_singles(t *testing.T) { + one := []access.CurrentKeyFor{ + { + Algorithm: security.AlgorithmRSA2048, + KID: "rsa", + }, + } + + oneLegacy := []access.CurrentKeyFor{ + { + Algorithm: security.AlgorithmRSA2048, + KID: "rsa", + Legacy: true, + }, + } + + assert.Equal(t, oneLegacy, inferLegacyKeys(one)) + assert.False(t, one[0].Legacy) + assert.True(t, oneLegacy[0].Legacy) +} + +func TestInferLegacyKeys_Mixed(t *testing.T) { + in := []access.CurrentKeyFor{ + { + Algorithm: security.AlgorithmRSA2048, + KID: "a", + }, + { + Algorithm: security.AlgorithmECP256R1, + KID: "b", + }, + { + Algorithm: security.AlgorithmECP256R1, + KID: "c", + Legacy: true, + }, + { + Algorithm: security.AlgorithmECP256R1, + KID: "d", + }, + } + + assert.Empty(t, inferLegacyKeys(in)) +}