Skip to content

Commit 32381d8

Browse files
committed
test/kms: add InvalidImageVaultEncryptionProvider for degradation tests
The invalid image uses a properly formatted OCI reference with sha256 digest that passes API validation but points to a non-existent image, causing ImagePullBackOff and operator degradation.
1 parent 9e7a937 commit 32381d8

3 files changed

Lines changed: 85 additions & 30 deletions

File tree

test/library/encryption/helpers.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,35 @@ func setUpTearDown(namespace string) func(testing.TB, bool) {
346346
}
347347
}
348348
}
349+
350+
// WaitForPodImagePullBackOff polls pods in the given namespace until at least one pod
351+
// has an init container or container stuck in ImagePullBackOff. This is useful for
352+
// detecting that an invalid KMS plugin image is causing static pod failure.
353+
func WaitForPodImagePullBackOff(ctx context.Context, t testing.TB, kubeClient kubernetes.Interface, namespace, labelSelector string, timeout time.Duration) {
354+
t.Helper()
355+
t.Logf("Waiting up to %s for a pod in %s (selector=%s) to enter ImagePullBackOff", timeout, namespace, labelSelector)
356+
err := wait.PollUntilContextTimeout(ctx, waitPollInterval, timeout, true, func(ctx context.Context) (bool, error) {
357+
pods, err := kubeClient.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector})
358+
if err != nil {
359+
t.Logf("Error listing pods: %v", err)
360+
return false, nil
361+
}
362+
for _, pod := range pods.Items {
363+
for _, cs := range pod.Status.InitContainerStatuses {
364+
if cs.State.Waiting != nil && (cs.State.Waiting.Reason == "ImagePullBackOff" || cs.State.Waiting.Reason == "ErrImagePull") {
365+
t.Logf("Pod %s init container %s is in %s", pod.Name, cs.Name, cs.State.Waiting.Reason)
366+
return true, nil
367+
}
368+
}
369+
for _, cs := range pod.Status.ContainerStatuses {
370+
if cs.State.Waiting != nil && (cs.State.Waiting.Reason == "ImagePullBackOff" || cs.State.Waiting.Reason == "ErrImagePull") {
371+
t.Logf("Pod %s container %s is in %s", pod.Name, cs.Name, cs.State.Waiting.Reason)
372+
return true, nil
373+
}
374+
}
375+
}
376+
return false, nil
377+
})
378+
require.NoError(t, err, "timed out waiting for pod to enter ImagePullBackOff in namespace %s", namespace)
379+
}
380+

test/library/encryption/kms/vault.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ const (
3333
defaultVaultTransitKey = "kms-key"
3434
defaultAppRoleTargetNamespace = "openshift-config"
3535
vaultCommandTimeout = 30 * time.Second
36+
37+
// InvalidVaultKMSPluginImage is an OCI image reference that passes API validation
38+
// (correct format, sha256 digest, sufficient length) but does not exist in any registry.
39+
// Use this to test degradation when the KMS plugin image cannot be pulled.
40+
InvalidVaultKMSPluginImage = "quay.io/openshifttest/mock-kms-plugin-nonexistent@sha256:0000000000000000000000000000000000000000000000000000000000000000"
3641
)
3742

3843
// DefaultVaultEncryptionProvider is a ready-to-use Vault KMS EncryptionProvider for e2e tests.
@@ -47,6 +52,35 @@ var DefaultFakeVaultEncryptionProvider = library.EncryptionProvider{
4752
Setup: ensureDefaultVaultAppRoleSecret,
4853
}
4954

55+
// InvalidImageVaultEncryptionProvider is a Vault KMS EncryptionProvider with a
56+
// non-existent plugin image. Use this for testing degradation when the image cannot be pulled.
57+
var InvalidImageVaultEncryptionProvider = library.EncryptionProvider{
58+
APIServerEncryption: InvalidImageVaultKMSPluginConfig,
59+
Setup: ensureDefaultVaultAppRoleSecret,
60+
}
61+
62+
// InvalidImageVaultKMSPluginConfig is identical to DefaultVaultKMSPluginConfig
63+
// but uses a non-existent image that will fail to pull.
64+
var InvalidImageVaultKMSPluginConfig = configv1.APIServerEncryption{
65+
Type: configv1.EncryptionTypeKMS,
66+
KMS: configv1.KMSPluginConfig{
67+
Type: configv1.VaultKMSProvider,
68+
Vault: configv1.VaultKMSPluginConfig{
69+
KMSPluginImage: InvalidVaultKMSPluginImage,
70+
VaultAddress: defaultVaultAddress,
71+
VaultNamespace: defaultVaultEnterpriseNS,
72+
TransitMount: defaultVaultTransitMount,
73+
TransitKey: defaultVaultTransitKey,
74+
Authentication: configv1.VaultAuthentication{
75+
Type: configv1.VaultAuthenticationTypeAppRole,
76+
AppRole: configv1.VaultAppRoleAuthentication{
77+
Secret: configv1.VaultSecretReference{Name: defaultVaultAppRoleSecretName},
78+
},
79+
},
80+
},
81+
},
82+
}
83+
5084
// DefaultVaultKMSPluginConfig is the standard Vault KMS encryption config
5185
// used by CI e2e tests.
5286
var DefaultVaultKMSPluginConfig = configv1.APIServerEncryption{

test/library/encryption/scenarios.go

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,14 @@ func TestEncryptionRotation(ctx context.Context, t testing.TB, scenario Rotation
279279
}
280280

281281
// InvalidImageRecoveryScenario tests that an invalid KMS plugin image causes
282-
// the cluster to degrade and that correcting the image restores normal operation.
282+
// the operator to degrade (even when switching to aescbc) and that providing
283+
// a valid KMS image restores normal operation.
283284
//
284-
// Arda's scenario:
285-
// 1. Enable KMS with invalid image
286-
// 2. Attempt to switch to aescbc (cluster should be stuck on KMS)
287-
// 3. See degraded
288-
// 4. Update with KMS with valid image
289-
// 5. See everything works
285+
// Flow:
286+
// 1. Enable KMS with invalid (non-existent) plugin image
287+
// 2. Switch to aescbc — cluster should remain stuck on KMS (rollout blocked)
288+
// 3. Operator reports degraded (stuck NodeInstaller, ImagePullBackOff, etc.)
289+
// 4. Fix by applying KMS with valid image and wait for full encryption migration
290290
type InvalidImageRecoveryScenario struct {
291291
BasicScenario
292292
// InvalidImageProvider is the KMS EncryptionProvider configured with an invalid
@@ -297,19 +297,15 @@ type InvalidImageRecoveryScenario struct {
297297
ValidImageProvider EncryptionProvider
298298
// WaitForDegraded should block until the operator reports a degraded condition.
299299
WaitForDegraded func(ctx context.Context, t testing.TB)
300-
// WaitForRecovery should block until the operator reports a healthy condition
301-
// and encryption is fully operational.
302-
WaitForRecovery func(ctx context.Context, t testing.TB)
303300
}
304301

305302
// TestEncryptionInvalidImageRecovery tests that:
306-
// 1. Enabling KMS with an invalid plugin image causes degradation
307-
// 2. The cluster remains stuck and cannot migrate to another mode (e.g. aescbc)
308-
// 3. Fixing the KMS config with a valid image restores the cluster
303+
// 1. Enabling KMS with an invalid plugin image causes the operator to degrade
304+
// 2. Switching to aescbc does NOT recover (cluster is stuck on the failed KMS rollout)
305+
// 3. Providing a valid KMS image restores the cluster (uses SetAndWaitForEncryptionType)
309306
func TestEncryptionInvalidImageRecovery(ctx context.Context, t testing.TB, scenario InvalidImageRecoveryScenario) {
310307
e := NewE(t, PrintEventsOnFailure(scenario.OperatorNamespace))
311308
require.NotNil(t, scenario.WaitForDegraded, "WaitForDegraded must not be nil")
312-
require.NotNil(t, scenario.WaitForRecovery, "WaitForRecovery must not be nil")
313309
require.Equal(t, configv1.EncryptionTypeKMS, scenario.InvalidImageProvider.Type, "InvalidImageProvider must be KMS type")
314310
require.Equal(t, configv1.EncryptionTypeKMS, scenario.ValidImageProvider.Type, "ValidImageProvider must be KMS type")
315311

@@ -326,32 +322,25 @@ func TestEncryptionInvalidImageRecovery(ctx context.Context, t testing.TB, scena
326322
_, err = cs.ApiServerConfig.Update(ctx, apiServer, metav1.UpdateOptions{})
327323
require.NoError(t, err)
328324

329-
// step 2: attempt to switch to aescbc — cluster should remain stuck on KMS
325+
// step 2: attempt to switch to aescbc — the cluster should remain stuck on KMS
326+
// because the static pod rollout with the invalid image is blocking progress
330327
t.Log("Attempting to switch to aescbc (cluster should remain stuck on KMS)")
331328
apiServer, err = cs.ApiServerConfig.Get(ctx, "cluster", metav1.GetOptions{})
332329
require.NoError(t, err)
333330
apiServer.Spec.Encryption = configv1.APIServerEncryption{Type: configv1.EncryptionTypeAESCBC}
334331
_, err = cs.ApiServerConfig.Update(ctx, apiServer, metav1.UpdateOptions{})
335332
require.NoError(t, err)
336333

337-
// step 3: wait for degraded
334+
// step 3: wait for degraded — the operator is stuck because the invalid KMS image
335+
// prevents the NodeInstaller from completing the rollout
338336
t.Log("Waiting for operator to report degraded status")
339337
scenario.WaitForDegraded(ctx, e)
340338

341-
// step 4: fix the config with valid KMS image
342-
t.Log("Updating KMS encryption with valid plugin image to recover")
343-
if scenario.ValidImageProvider.Setup != nil {
344-
scenario.ValidImageProvider.Setup(ctx, e)
345-
}
346-
apiServer, err = cs.ApiServerConfig.Get(ctx, "cluster", metav1.GetOptions{})
347-
require.NoError(t, err)
348-
apiServer.Spec.Encryption = scenario.ValidImageProvider.APIServerEncryption
349-
_, err = cs.ApiServerConfig.Update(ctx, apiServer, metav1.UpdateOptions{})
350-
require.NoError(t, err)
351-
352-
// step 5: wait for recovery — everything should work
353-
t.Log("Waiting for operator to recover with valid KMS image")
354-
scenario.WaitForRecovery(ctx, e)
339+
// step 4: fix by applying KMS with valid image and wait for full recovery
340+
// (uses SetAndWaitForEncryptionType which waits for encryption key migration,
341+
// same as the standard encryption on/off and migration tests)
342+
t.Log("Recovering: applying KMS with valid plugin image and waiting for full migration")
343+
SetAndWaitForEncryptionType(ctx, e, scenario.ValidImageProvider, scenario.TargetGRs, scenario.Namespace, scenario.LabelSelector)
355344

356345
t.Log("Invalid image recovery test passed")
357346
}

0 commit comments

Comments
 (0)