Skip to content

Commit

Permalink
Track encryptionKeyLastRotation and regenerate LTPA config password w…
Browse files Browse the repository at this point in the history
…hen out of sync
  • Loading branch information
kabicin committed Sep 16, 2024
1 parent ce9b00f commit 241b7bb
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
8 changes: 4 additions & 4 deletions internal/controller/assets/create_ltpa_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ LAST_ROTATION=$(curl --cacert ${CACERT} --header "Content-Type: application/json
PASSWORD=$(curl --cacert ${CACERT} --header "Content-Type: application/json" --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${LTPA_SECRET_NAME} | grep -o '"password": "[^"]*' | grep -o '[^"]*$' | base64 -d);

if [ "$ENCRYPTION_KEY_SHARING_ENABLED" == "true" ] && [ $NOT_FOUND_COUNT -eq 0 ]; then
PASSWORD_KEY_LAST_ROTATION=$(curl --cacert ${CACERT} --header "Content-Type: application/json" --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${PASSWORD_KEY_SECRET_NAME} | grep -o '"lastRotation": "[^"]*' | grep -o '[^"]*$' | base64 -d);
PASSWORD_KEY=$(curl --cacert ${CACERT} --header "Content-Type: application/json" --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${PASSWORD_KEY_SECRET_NAME} | grep -o '"passwordEncryptionKey": "[^"]*' | grep -o '[^"]*$' | base64 -d);
ENCODED_PASSWORD=$(securityUtility encode --encoding=${ENCODING_TYPE} --key=${PASSWORD_KEY} ${PASSWORD});
LTPA_ENCODED_PASSWORD="{\"apiVersion\": \"v1\", \"stringData\": {\"lastRotation\": \"$LAST_ROTATION\", \"password\": \"$ENCODED_PASSWORD\"}, \"kind\": \"Secret\",\"metadata\": {\"name\": \"$LTPA_CONFIG_SECRET_NAME\", \"passwordKeyLastRotation\": \"$PASSWORD_KEY_LAST_ROTATION\", \"namespace\": \"$NAMESPACE\",\"labels\": {\"app.kubernetes.io/name\": \"${LTPA_CONFIG_BASE_NAME}\", \"app.kubernetes.io/instance\": \"${LTPA_CONFIG_SECRET_NAME}\", \"$LTPA_LABEL_KEY\": \"$LTPA_LABEL_VALUE\"}},\"type\": \"Opaque\"}";
ENCRYPTION_KEY_LAST_ROTATION=$(curl --cacert ${CACERT} --header "Content-Type: application/json" --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${PASSWORD_KEY_SECRET_NAME} | grep -o '"lastRotation": "[^"]*' | grep -o '[^"]*$' | base64 -d);
ENCRYPTION_KEY=$(curl --cacert ${CACERT} --header "Content-Type: application/json" --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/${NAMESPACE}/secrets/${PASSWORD_KEY_SECRET_NAME} | grep -o '"passwordEncryptionKey": "[^"]*' | grep -o '[^"]*$' | base64 -d);
ENCODED_PASSWORD=$(securityUtility encode --encoding=${ENCODING_TYPE} --key=${ENCRYPTION_KEY} ${PASSWORD});
LTPA_ENCODED_PASSWORD="{\"apiVersion\": \"v1\", \"stringData\": {\"encryptionKeyLastRotation\": \"$ENCRYPTION_KEY_LAST_ROTATION\", \"lastRotation\": \"$LAST_ROTATION\", \"password\": \"$ENCODED_PASSWORD\"}, \"kind\": \"Secret\",\"metadata\": {\"name\": \"$LTPA_CONFIG_SECRET_NAME\", \"passwordKeyLastRotation\": \"$PASSWORD_KEY_LAST_ROTATION\", \"namespace\": \"$NAMESPACE\",\"labels\": {\"app.kubernetes.io/name\": \"${LTPA_CONFIG_BASE_NAME}\", \"app.kubernetes.io/instance\": \"${LTPA_CONFIG_SECRET_NAME}\", \"$LTPA_LABEL_KEY\": \"$LTPA_LABEL_VALUE\"}},\"type\": \"Opaque\"}";
else
SECRET_NAME="${LTPA_SECRET_NAME}-password"
ENCODED_PASSWORD=$(securityUtility encode --encoding=${ENCODING_TYPE} ${PASSWORD});
Expand Down
30 changes: 29 additions & 1 deletion internal/controller/ltpa_keys_sharing.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,8 @@ func (r *ReconcileOpenLiberty) generateLTPAConfig(instance *olv1.OpenLibertyAppl

ltpaConfigSecret := &corev1.Secret{}
ltpaConfigSecretRootName := OperatorShortName + "-managed-ltpa"
if r.isUsingPasswordEncryptionKeySharing(instance, passwordEncryptionMetadata) {
isPasswordEncryptionKeySharing := r.isUsingPasswordEncryptionKeySharing(instance, passwordEncryptionMetadata)
if isPasswordEncryptionKeySharing {
ltpaConfigSecretRootName += "-keyed-password"
ltpaConfigSecret.Name = ltpaConfigSecretRootName + ltpaConfigMetadata.Name
} else {
Expand Down Expand Up @@ -801,6 +802,33 @@ func (r *ReconcileOpenLiberty) generateLTPAConfig(instance *olv1.OpenLibertyAppl
return err
}

// if using encryption key, check if the key has been rotated and requires a regeneration of the LTPA keyed password
if isPasswordEncryptionKeySharing {
internalEncryptionKeySecret, err := r.hasInternalEncryptionKeySecret(instance, passwordEncryptionMetadata)
if err != nil {
return err
}
lastRotation, found := internalEncryptionKeySecret.Data["lastRotation"]
if !found {
// lastRotation field is not present so the Secret was not initialized correctly
err := r.DeleteResource(internalEncryptionKeySecret)
if err != nil {
return err
}
return fmt.Errorf("the internal encryption key secret does not contain field 'lastRotation'")
}

if encryptionKeyLastRotation, found := ltpaConfigSecret.Data["encryptionKeyLastRotation"]; found {
if string(encryptionKeyLastRotation) != string(lastRotation) {
err := r.DeleteResource(ltpaConfigSecret)
if err != nil {
return err
}
return fmt.Errorf("the encryption key has been modified; waiting for a new LTPA password to be generated")
}
}
}

// Create/update the Secret to hold the server.xml that will import the LTPA keys into the Liberty server
// This server.xml will be mounted in /config/configDropins/overrides/ltpaKeysMount.xml
serverXMLMountSecretErr := r.GetClient().Get(context.TODO(), types.NamespacedName{Name: ltpaXMLMountSecret.Name, Namespace: ltpaXMLMountSecret.Namespace}, ltpaXMLMountSecret)
Expand Down

0 comments on commit 241b7bb

Please sign in to comment.