Skip to content

Commit 43740c0

Browse files
committed
kmsv2: run KDF tests in parallel
This change updates the KDF "feature flag" to be per KMS provider instead of global to the API server. This allows integration tests that use distinct provider names to run in parallel. Locally this change reduced the runtime of test/integration/controlplane/transformation by 3.5 minutes. Signed-off-by: Monis Khan <[email protected]>
1 parent a0db55c commit 43740c0

File tree

4 files changed

+121
-79
lines changed

4 files changed

+121
-79
lines changed

staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,24 +107,35 @@ const (
107107

108108
var codecs serializer.CodecFactory
109109

110-
// this atomic bool allows us to swap enablement of the KMSv2KDF feature in tests
110+
// this map allows us to swap enablement of the KMSv2KDF feature in tests
111111
// as the feature gate is now locked to true starting with v1.29
112112
// Note: it cannot be set by an end user
113-
var kdfDisabled atomic.Bool
113+
// KDF enablement is tracked per KMS provider to allow tests to run in parallel.
114+
var kdfEnabledPerKMS sync.Map // map[string]bool, KMS name -> KDF enabled
114115

115116
// this function should only be called in tests to swap enablement of the KMSv2KDF feature
116-
func SetKDFForTests(b bool) func() {
117-
kdfDisabled.Store(!b)
118-
return func() {
119-
kdfDisabled.Store(false)
117+
// Caller must guarantee that all KMS providers have distinct names across all tests.
118+
func SetKDFForTests(kmsName string, b bool) func() {
119+
if len(kmsName) == 0 { // guarantee that GetKDF("") returns the default value
120+
panic("empty KMS name used in test")
120121
}
122+
if _, loaded := kdfEnabledPerKMS.LoadOrStore(kmsName, b); loaded {
123+
panic("duplicate KMS name used in test")
124+
}
125+
return func() { kdfEnabledPerKMS.Delete(kmsName) }
121126
}
122127

123128
// this function should be used to determine enablement of the KMSv2KDF feature
124129
// instead of getting it from DefaultFeatureGate as the feature gate is now locked
125130
// to true starting with v1.29
126-
func GetKDF() bool {
127-
return !kdfDisabled.Load()
131+
// to allow integration tests to run in parallel, this "feature flag" can be set
132+
// per KMS provider as long as all providers use distinct names.
133+
func GetKDF(kmsName string) bool {
134+
kdfEnabled, ok := kdfEnabledPerKMS.Load(kmsName)
135+
if !ok {
136+
return true // explicit config is missing, but KDF is enabled by default
137+
}
138+
return kdfEnabled.(bool) // this will panic if a non-bool ever gets stored, which should never happen
128139
}
129140

130141
func init() {
@@ -390,7 +401,7 @@ func (h *kmsv2PluginProbe) rotateDEKOnKeyIDChange(ctx context.Context, statusKey
390401
// this gate can only change during tests, but the check is cheap enough to always make
391402
// this allows us to easily exercise both modes without restarting the API server
392403
// TODO integration test that this dynamically takes effect
393-
useSeed := GetKDF()
404+
useSeed := GetKDF(h.name)
394405
stateUseSeed := state.EncryptedObject.EncryptedDEKSourceType == kmstypes.EncryptedDEKSourceType_HKDF_SHA256_XNONCE_AES_GCM_SEED
395406

396407
// state is valid and status keyID is unchanged from when we generated this DEK/seed so there is no need to rotate it

staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,7 +1851,7 @@ func TestComputeEncryptionConfigHash(t *testing.T) {
18511851
}
18521852

18531853
func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) {
1854-
defaultUseSeed := GetKDF()
1854+
defaultUseSeed := GetKDF("")
18551855

18561856
origNowFunc := envelopekmsv2.NowFunc
18571857
now := origNowFunc() // freeze time
@@ -2074,17 +2074,18 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) {
20742074
`encryptKeyIDHash="", stateKeyIDHash="sha256:d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35", expirationTimestamp=` + now.Format(time.RFC3339),
20752075
},
20762076
}
2077-
for _, tt := range tests {
2077+
for i, tt := range tests {
20782078
t.Run(tt.name, func(t *testing.T) {
2079-
defer SetKDFForTests(tt.useSeed)()
2079+
kmsName := fmt.Sprintf("panda-%d", i)
2080+
defer SetKDFForTests(kmsName, tt.useSeed)()
20802081

20812082
var buf bytes.Buffer
20822083
klog.SetOutput(&buf)
20832084

20842085
ctx := testContext(t)
20852086

20862087
h := &kmsv2PluginProbe{
2087-
name: "panda",
2088+
name: kmsName,
20882089
service: tt.service,
20892090
}
20902091
h.state.Store(&tt.state)
@@ -2133,7 +2134,7 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) {
21332134
if _, stateErr := h.getCurrentState(); stateErr == nil || err == nil {
21342135
transformer := envelopekmsv2.NewEnvelopeTransformer(
21352136
&testKMSv2EnvelopeService{err: fmt.Errorf("broken")}, // not called
2136-
"panda",
2137+
kmsName,
21372138
h.getCurrentState,
21382139
"",
21392140
)

0 commit comments

Comments
 (0)