Skip to content

Commit 4583549

Browse files
committed
Track ltpa keys last rotation and delete LTPA password when out of sync
1 parent 241b7bb commit 4583549

File tree

2 files changed

+64
-49
lines changed

2 files changed

+64
-49
lines changed

Diff for: internal/controller/ltpa_keys_sharing.go

+62-47
Original file line numberDiff line numberDiff line change
@@ -179,28 +179,29 @@ func hasLTPAConfigResourceSuffixesEnv(instance *olv1.OpenLibertyApplication) (st
179179
}
180180

181181
// Create or use an existing LTPA Secret identified by LTPA metadata for the OpenLibertyApplication instance
182-
func (r *ReconcileOpenLiberty) reconcileLTPAKeys(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata) (string, string, error) {
182+
func (r *ReconcileOpenLiberty) reconcileLTPAKeys(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata) (string, string, string, error) {
183183
var err error
184184
ltpaSecretName := ""
185+
ltpaKeysLastRotation := ""
185186
if r.isLTPAKeySharingEnabled(instance) {
186-
ltpaSecretName, err = r.generateLTPAKeys(instance, ltpaKeysMetadata)
187+
ltpaSecretName, ltpaKeysLastRotation, err = r.generateLTPAKeys(instance, ltpaKeysMetadata)
187188
if err != nil {
188-
return "Failed to generate the shared LTPA keys Secret", ltpaSecretName, err
189+
return "Failed to generate the shared LTPA keys Secret", ltpaSecretName, ltpaKeysLastRotation, err
189190
}
190191
} else {
191192
err := r.RemoveLeaderTrackerReference(instance, LTPA_RESOURCE_SHARING_FILE_NAME)
192193
if err != nil {
193-
return "Failed to remove leader tracking reference to the LTPA keys", ltpaSecretName, err
194+
return "Failed to remove leader tracking reference to the LTPA keys", ltpaSecretName, ltpaKeysLastRotation, err
194195
}
195196
}
196-
return "", ltpaSecretName, nil
197+
return "", ltpaSecretName, ltpaKeysLastRotation, nil
197198
}
198199

199200
// Create or use an existing LTPA Secret identified by LTPA metadata for the OpenLibertyApplication instance
200-
func (r *ReconcileOpenLiberty) reconcileLTPAConfig(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata, ltpaConfigMetadata *lutils.LTPAMetadata, passwordEncryptionMetadata *lutils.PasswordEncryptionMetadata) (string, error) {
201+
func (r *ReconcileOpenLiberty) reconcileLTPAConfig(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata, ltpaConfigMetadata *lutils.LTPAMetadata, passwordEncryptionMetadata *lutils.PasswordEncryptionMetadata, ltpaKeysLastRotation string) (string, error) {
201202
var err error
202203
if r.isLTPAKeySharingEnabled(instance) {
203-
err = r.generateLTPAConfig(instance, ltpaKeysMetadata, ltpaConfigMetadata, passwordEncryptionMetadata)
204+
err = r.generateLTPAConfig(instance, ltpaKeysMetadata, ltpaConfigMetadata, passwordEncryptionMetadata, ltpaKeysLastRotation)
204205
if err != nil {
205206
return "Failed to generate the shared LTPA keys Secret", err
206207
}
@@ -247,7 +248,7 @@ func (r *ReconcileOpenLiberty) restartLTPAKeysGeneration(instance *olv1.OpenLibe
247248
}
248249

249250
// Generates the LTPA keys file and returns the name of the Secret storing its metadata
250-
func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplication, ltpaMetadata *lutils.LTPAMetadata) (string, error) {
251+
func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplication, ltpaMetadata *lutils.LTPAMetadata) (string, string, error) {
251252
// Initialize LTPA resources
252253
passwordEncryptionMetadata := &lutils.PasswordEncryptionMetadata{Name: ""}
253254

@@ -330,11 +331,11 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
330331
if err != nil && kerrors.IsNotFound(err) {
331332
leaderName, thisInstanceIsLeader, _, err := r.reconcileLeader(instance, ltpaMetadata, LTPA_RESOURCE_SHARING_FILE_NAME, true)
332333
if err != nil {
333-
return "", err
334+
return "", "", err
334335
}
335336
// If this instance is not the leader, exit the reconcile loop
336337
if !thisInstanceIsLeader {
337-
return "", fmt.Errorf("Waiting for OpenLibertyApplication instance '" + leaderName + "' to generate the shared LTPA keys file for the namespace '" + instance.Namespace + "'.")
338+
return "", "", fmt.Errorf("Waiting for OpenLibertyApplication instance '" + leaderName + "' to generate the shared LTPA keys file for the namespace '" + instance.Namespace + "'.")
338339
}
339340

340341
err = r.GetClient().Get(context.TODO(), types.NamespacedName{Name: ltpaJobRequest.Name, Namespace: ltpaJobRequest.Namespace}, ltpaJobRequest)
@@ -344,47 +345,47 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
344345
// Clear all LTPA-related resources from a prior reconcile
345346
err = r.DeleteResource(ltpaXMLSecret)
346347
if err != nil {
347-
return "", err
348+
return "", "", err
348349
}
349350
err = r.DeleteResource(ltpaXMLMountSecret)
350351
if err != nil {
351-
return "", err
352+
return "", "", err
352353
}
353354
err = r.DeleteResource(ltpaKeysCreationScriptConfigMap)
354355
if err != nil {
355-
return "", err
356+
return "", "", err
356357
}
357358
err = r.GetClient().Delete(context.TODO(), generateLTPAKeysJob, &client.DeleteOptions{PropagationPolicy: &deletePropagationBackground})
358359
if err != nil && !kerrors.IsNotFound(err) {
359-
return "", err
360+
return "", "", err
360361
}
361362
err := r.CreateOrUpdate(ltpaJobRequest, nil, func() error {
362363
return nil
363364
})
364365
if err != nil {
365-
return "", fmt.Errorf("Failed to create ConfigMap " + ltpaJobRequest.Name)
366+
return "", "", fmt.Errorf("Failed to create ConfigMap " + ltpaJobRequest.Name)
366367
}
367368
} else {
368-
return "", fmt.Errorf("Failed to get ConfigMap " + ltpaJobRequest.Name)
369+
return "", "", fmt.Errorf("Failed to get ConfigMap " + ltpaJobRequest.Name)
369370
}
370371
} else {
371372
// Create the ServiceAccount
372373
if err := r.CreateOrUpdate(ltpaServiceAccount, nil, func() error {
373374
return nil
374375
}); err != nil && !kerrors.IsNotFound(err) {
375-
return "", fmt.Errorf("Failed to create ServiceAccount " + ltpaServiceAccount.Name)
376+
return "", "", fmt.Errorf("Failed to create ServiceAccount " + ltpaServiceAccount.Name)
376377
}
377378

378379
// Create the Role/RoleBinding
379380
if err := r.CreateOrUpdate(ltpaRole, nil, func() error {
380381
return nil
381382
}); err != nil && !kerrors.IsNotFound(err) {
382-
return "", fmt.Errorf("Failed to create Role " + ltpaRole.Name)
383+
return "", "", fmt.Errorf("Failed to create Role " + ltpaRole.Name)
383384
}
384385
if err := r.CreateOrUpdate(ltpaRoleBinding, nil, func() error {
385386
return nil
386387
}); err != nil && !kerrors.IsNotFound(err) {
387-
return "", fmt.Errorf("Failed to create RoleBinding " + ltpaRoleBinding.Name)
388+
return "", "", fmt.Errorf("Failed to create RoleBinding " + ltpaRoleBinding.Name)
388389
}
389390

390391
// Create a ConfigMap to store the internal/controller/assets/create_ltpa_keys.sh script
@@ -393,7 +394,7 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
393394
ltpaKeysCreationScriptConfigMap.Data = make(map[string]string)
394395
script, err := os.ReadFile("internal/controller/assets/" + lutils.LTPAKeysCreationScriptFileName)
395396
if err != nil {
396-
return "", err
397+
return "", "", err
397398
}
398399
ltpaKeysCreationScriptConfigMap.Data[lutils.LTPAKeysCreationScriptFileName] = string(script)
399400
// prevent script from being modified
@@ -410,22 +411,22 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
410411
// Compare the bundle script against the ltpaKeysCreationScriptConfigMap's saved script
411412
script, err := os.ReadFile("internal/controller/assets/" + lutils.LTPAKeysCreationScriptFileName)
412413
if err != nil {
413-
return "", err
414+
return "", "", err
414415
}
415416
savedScript, found := ltpaKeysCreationScriptConfigMap.Data[lutils.LTPAKeysCreationScriptFileName]
416417
// Delete ltpaKeysCreationScriptConfigMap if it is missing the data key
417418
if !found {
418419
if err := r.DeleteResource(ltpaKeysCreationScriptConfigMap); err != nil {
419-
return "", err
420+
return "", "", err
420421
}
421-
return "", fmt.Errorf("the LTPA Keys Creation ConfigMap is missing key " + lutils.LTPAKeysCreationScriptFileName)
422+
return "", "", fmt.Errorf("the LTPA Keys Creation ConfigMap is missing key " + lutils.LTPAKeysCreationScriptFileName)
422423
}
423424
// Delete ltpaKeysCreationScriptConfigMap if the file contents do not match
424425
if string(script) != savedScript {
425426
if err := r.DeleteResource(ltpaKeysCreationScriptConfigMap); err != nil {
426-
return "", err
427+
return "", "", err
427428
}
428-
return "", fmt.Errorf("the LTPA Keys Creation ConfigMap key '" + lutils.LTPAKeysCreationScriptFileName + "' is out of sync")
429+
return "", "", fmt.Errorf("the LTPA Keys Creation ConfigMap key '" + lutils.LTPAKeysCreationScriptFileName + "' is out of sync")
429430
}
430431
// Run the Kubernetes Job to generate the shared ltpa.keys file and LTPA Secret
431432
err = r.GetClient().Get(context.TODO(), types.NamespacedName{Name: generateLTPAKeysJob.Name, Namespace: generateLTPAKeysJob.Namespace}, generateLTPAKeysJob)
@@ -446,7 +447,7 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
446447
return nil
447448
})
448449
if err != nil {
449-
return "", fmt.Errorf("Failed to create Job %s: %s"+generateLTPAKeysJob.Name, err)
450+
return "", "", fmt.Errorf("Failed to create Job %s: %s"+generateLTPAKeysJob.Name, err)
450451
}
451452
} else if err == nil {
452453
// If the LTPA Secret is not yet created (LTPA Job has not successfully completed)
@@ -455,61 +456,61 @@ func (r *ReconcileOpenLiberty) generateLTPAKeys(instance *olv1.OpenLibertyApplic
455456
// Delete the Job request to restart the entire LTPA generation process (i.e. reloading the script, ltpa.xml, and Job)
456457
err = r.DeleteResource(ltpaJobRequest)
457458
if err != nil {
458-
return ltpaSecret.Name, err
459+
return ltpaSecret.Name, "", err
459460
}
460461
}
461462
} else {
462-
return "", fmt.Errorf("Failed to get Job " + generateLTPAKeysJob.Name)
463+
return "", "", fmt.Errorf("Failed to get Job " + generateLTPAKeysJob.Name)
463464
}
464465
}
465466
}
466467

467468
// Reconcile the Job
468469
err = r.GetClient().Get(context.TODO(), types.NamespacedName{Name: generateLTPAKeysJob.Name, Namespace: generateLTPAKeysJob.Namespace}, generateLTPAKeysJob)
469470
if err != nil && kerrors.IsNotFound(err) {
470-
return "", fmt.Errorf("Waiting for the LTPA key to be generated by Job '" + generateLTPAKeysJob.Name + "'.")
471+
return "", "", fmt.Errorf("Waiting for the LTPA key to be generated by Job '" + generateLTPAKeysJob.Name + "'.")
471472
} else if err != nil {
472-
return "", fmt.Errorf("Failed to get Job " + generateLTPAKeysJob.Name)
473+
return "", "", fmt.Errorf("Failed to get Job " + generateLTPAKeysJob.Name)
473474
}
474475
if len(generateLTPAKeysJob.Status.Conditions) > 0 && generateLTPAKeysJob.Status.Conditions[0].Type == v1.JobFailed {
475-
return "", fmt.Errorf("Job " + generateLTPAKeysJob.Name + " has failed. Manually clean up hung resources by setting .spec.manageLTPA to false in the " + leaderName + " instance.")
476+
return "", "", fmt.Errorf("Job " + generateLTPAKeysJob.Name + " has failed. Manually clean up hung resources by setting .spec.manageLTPA to false in the " + leaderName + " instance.")
476477
}
477-
return "", fmt.Errorf("Waiting for the LTPA key to be generated by Job '" + generateLTPAKeysJob.Name + "'.")
478+
return "", "", fmt.Errorf("Waiting for the LTPA key to be generated by Job '" + generateLTPAKeysJob.Name + "'.")
478479
} else if err != nil {
479-
return "", err
480-
} else {
481-
_, thisInstanceIsLeader, _, err := r.reconcileLeader(instance, ltpaMetadata, LTPA_RESOURCE_SHARING_FILE_NAME, true)
482-
if err != nil {
483-
return "", err
484-
}
485-
if !thisInstanceIsLeader {
486-
return ltpaSecret.Name, nil
487-
}
480+
return "", "", err
481+
}
482+
_, thisInstanceIsLeader, _, err := r.reconcileLeader(instance, ltpaMetadata, LTPA_RESOURCE_SHARING_FILE_NAME, true)
483+
if err != nil {
484+
return "", "", err
485+
}
486+
lastRotation := string(ltpaSecret.Data["lastRotation"])
487+
if !thisInstanceIsLeader {
488+
return ltpaSecret.Name, lastRotation, nil
488489
}
489490

490491
// The LTPA Secret is created (in other words, the LTPA Job has completed) so delete the Job request
491492
err = r.DeleteResource(ltpaJobRequest)
492493
if err != nil {
493-
return ltpaSecret.Name, err
494+
return ltpaSecret.Name, lastRotation, err
494495
}
495496
// The LTPA Secret is created so delete the ServiceAccount, Role and RoleBinding
496497
err = r.DeleteResource(ltpaServiceAccount)
497498
if err != nil {
498-
return ltpaSecret.Name, err
499+
return ltpaSecret.Name, lastRotation, err
499500
}
500501
err = r.DeleteResource(ltpaRole)
501502
if err != nil {
502-
return ltpaSecret.Name, err
503+
return ltpaSecret.Name, lastRotation, err
503504
}
504505
err = r.DeleteResource(ltpaRoleBinding)
505506
if err != nil {
506-
return ltpaSecret.Name, err
507+
return ltpaSecret.Name, lastRotation, err
507508
}
508-
return ltpaSecret.Name, nil
509+
return ltpaSecret.Name, lastRotation, nil
509510
}
510511

511512
// Generates the LTPA keys file and returns the name of the Secret storing its metadata
512-
func (r *ReconcileOpenLiberty) generateLTPAConfig(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata, ltpaConfigMetadata *lutils.LTPAMetadata, passwordEncryptionMetadata *lutils.PasswordEncryptionMetadata) error {
513+
func (r *ReconcileOpenLiberty) generateLTPAConfig(instance *olv1.OpenLibertyApplication, ltpaKeysMetadata *lutils.LTPAMetadata, ltpaConfigMetadata *lutils.LTPAMetadata, passwordEncryptionMetadata *lutils.PasswordEncryptionMetadata, ltpaKeysLastRotation string) error {
513514
ltpaXMLSecret := &corev1.Secret{}
514515
ltpaXMLSecretRootName := OperatorShortName + lutils.LTPAServerXMLSuffix
515516
ltpaXMLSecret.Name = ltpaXMLSecretRootName + ltpaConfigMetadata.Name
@@ -802,6 +803,20 @@ func (r *ReconcileOpenLiberty) generateLTPAConfig(instance *olv1.OpenLibertyAppl
802803
return err
803804
}
804805

806+
// if the LTPA password is outdated from the LTPA Secret, delete the LTPA password
807+
lastRotation, found := ltpaConfigSecret.Data["lastRotation"]
808+
if !found || string(lastRotation) != string(ltpaKeysLastRotation) {
809+
// lastRotation field is not present so the Secret was not initialized correctly
810+
err := r.DeleteResource(ltpaConfigSecret)
811+
if err != nil {
812+
return err
813+
}
814+
if !found {
815+
return fmt.Errorf("the LTPA password does not contain field 'lastRotation'")
816+
}
817+
return fmt.Errorf("the LTPA password is out of sync with the generated LTPA Secret; waiting for a new LTPA password to be generated")
818+
}
819+
805820
// if using encryption key, check if the key has been rotated and requires a regeneration of the LTPA keyed password
806821
if isPasswordEncryptionKeySharing {
807822
internalEncryptionKeySecret, err := r.hasInternalEncryptionKeySecret(instance, passwordEncryptionMetadata)

Diff for: internal/controller/openlibertyapplication_controller.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -460,14 +460,14 @@ func (r *ReconcileOpenLiberty) Reconcile(ctx context.Context, request ctrl.Reque
460460
}
461461

462462
// Create and manage the shared LTPA keys Secret if the feature is enabled
463-
message, ltpaSecretName, err := r.reconcileLTPAKeys(instance, ltpaKeysMetadata)
463+
message, ltpaSecretName, ltpaKeysLastRotation, err := r.reconcileLTPAKeys(instance, ltpaKeysMetadata)
464464
if err != nil {
465465
reqLogger.Error(err, message)
466466
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
467467
}
468468

469469
// Using the LTPA keys and config metadata, create and manage the shared LTPA Liberty server XML if the feature is enabled
470-
message, err = r.reconcileLTPAConfig(instance, ltpaKeysMetadata, ltpaConfigMetadata, passwordEncryptionMetadata)
470+
message, err = r.reconcileLTPAConfig(instance, ltpaKeysMetadata, ltpaConfigMetadata, passwordEncryptionMetadata, ltpaKeysLastRotation)
471471
if err != nil {
472472
reqLogger.Error(err, message)
473473
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)

0 commit comments

Comments
 (0)