Skip to content

Support key rotation for KMIP KMS#1633

Merged
liranmauda merged 1 commit intonoobaa:masterfrom
jackyalbo:jacky-rotate-kmip
Jun 30, 2025
Merged

Support key rotation for KMIP KMS#1633
liranmauda merged 1 commit intonoobaa:masterfrom
jackyalbo:jacky-rotate-kmip

Conversation

@jackyalbo
Copy link
Contributor

@jackyalbo jackyalbo commented Jun 24, 2025

Explain the changes

  1. Due to the removal of NOOBAA_ROOT_SECRET, we have to move KMIP KMS support from a single string to a rotating secret.

Issues: Fixed #xxx / Gap #xxx

  1. Fixed https://issues.redhat.com/browse/DFBUGS-2844

Testing Instructions:

  • Doc added/updated
  • Tests added

Summary by CodeRabbit

  • New Features

    • Enhanced KMIP integration to support key rotation with additional system name and namespace fields.
    • Improved secret handling with dynamic unique identifier keys and updated encoding for KMIP secrets.
  • Tests

    • Added new tests to verify key rotation functionality and related conditions for KMIP integration.

@coderabbitai
Copy link

coderabbitai bot commented Jun 24, 2025

Walkthrough

The KMIP struct in the KMS utility was updated to include three new fields: UID, name, and namespace, with the constructor and Version method adjusted to initialize and use these fields. The Version method now returns a VersionRotatingSecret instead of VersionSingleSecret. Error handling in version secret methods was improved, and secret storage logic was modified to handle the "KMIPSecret" driver differently. Secret storage and retrieval methods were updated to support a new unique identifier key based on secret ID suffixes and to use dynamic cryptographic length calculation. Additionally, new tests were added to validate KMIP key rotation functionality, including operator restart and condition verification, in the test suite.

Changes

File(s) Change Summary
pkg/util/kms/kms_kmip.go, pkg/util/kms/kms_version.go, pkg/util/kms/kms_kmip_storage.go Extended KMIP struct with UID, name, ns; updated constructor and Version method to return VersionRotatingSecret; improved error handling in VersionSingleSecret and VersionRotatingSecret Get methods; modified VersionRotatingSecret Set method for "KMIPSecret" driver; added conditional logic in secret storage methods to handle two unique ID keys and dynamic cryptographic length.
pkg/util/kms/test/kmip/kms_kmip_test.go Added new test context for KMIP key rotation, including operator pod restart and verification of KMS conditions.

Sequence Diagram(s)

sequenceDiagram
    participant TestSuite
    participant NooBaa
    participant Operator
    participant KMIP KMS

    TestSuite->>NooBaa: Create NooBaa with KMIP KMS (rotation enabled)
    NooBaa->>KMIP KMS: Initialize with UID, name, namespace
    TestSuite->>NooBaa: Verify KMS condition type "kmip"
    TestSuite->>Operator: Delete operator pod (simulate restart)
    Operator->>NooBaa: Operator restarts, re-initializes KMS
    NooBaa->>KMIP KMS: Synchronize and rotate key
    TestSuite->>NooBaa: Verify KMS sync and key rotation conditions
    TestSuite->>NooBaa: Delete NooBaa resource
Loading

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6debea2 and ae7408d.

📒 Files selected for processing (4)
  • pkg/util/kms/kms_kmip.go (4 hunks)
  • pkg/util/kms/kms_kmip_storage.go (6 hunks)
  • pkg/util/kms/kms_version.go (4 hunks)
  • pkg/util/kms/test/kmip/kms_kmip_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/util/kms/kms_kmip.go
  • pkg/util/kms/kms_version.go
  • pkg/util/kms/test/kmip/kms_kmip_test.go
  • pkg/util/kms/kms_kmip_storage.go
⏰ Context from checks skipped due to timeout of 90000ms (13)
  • GitHub Check: run-cli-tests
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-azure-vault-test
  • GitHub Check: golangci-lint
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/util/kms/test/kmip/kms_kmip_test.go (1)

123-159: Consider adding validation for actual rotation behavior.

While the test validates that conditions are set correctly, it doesn't verify that actual key rotation occurs. Consider adding validation to ensure that:

  1. The system name and namespace are properly stored in the KMIP struct
  2. Keys are actually rotated according to the schedule
  3. The VersionRotatingSecret is functioning as expected
#!/bin/bash
# Description: Check if there are other key rotation validation patterns in the codebase

# Search for key rotation tests or validation logic
rg -A 10 -B 5 "VersionRotatingSecret|KeyRotate" --type go
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4ce419 and 923a258.

📒 Files selected for processing (2)
  • pkg/util/kms/kms_kmip.go (3 hunks)
  • pkg/util/kms/test/kmip/kms_kmip_test.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (13)
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-admission-test
  • GitHub Check: golangci-lint
  • GitHub Check: run-operator-tests
  • GitHub Check: run-cli-tests
  • GitHub Check: run-hac-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-azure-vault-test
🔇 Additional comments (5)
pkg/util/kms/kms_kmip.go (2)

28-29: LGTM! Fields appropriately added for key rotation support.

The addition of name and ns fields to track the NooBaa system name and namespace is essential for the key rotation functionality. The field names are clear and well-documented.


113-113: Version method correctly updated for key rotation.

The change from VersionSingleSecret to VersionRotatingSecret with the new name and ns fields properly implements the key rotation support as described in the PR objectives.

pkg/util/kms/test/kmip/kms_kmip_test.go (3)

123-128: Well-structured test setup for key rotation validation.

The test configuration properly enables key rotation with EnableKeyRotation = true and sets an appropriate test schedule. The every-minute schedule is suitable for testing purposes.


141-149: Excellent operator restart simulation.

The operator restart simulation by deleting the operator pod is crucial for validating that key rotation functionality persists across operator restarts. This addresses a key reliability concern.


153-155: Key rotation condition validation is essential.

The verification of the ConditionKMSKeyRotate condition after operator restart confirms that the key rotation feature is working correctly. This is a critical test for the new functionality.

@jackyalbo jackyalbo force-pushed the jacky-rotate-kmip branch from 923a258 to a7585d4 Compare June 24, 2025 15:43
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/util/kms/kms_version.go (1)

142-147: Consider architectural alternatives to driver-specific conditional logic.

While this conditional logic successfully enables KMIP key rotation, embedding driver-specific behavior in the generic version handling code introduces coupling that could complicate future maintenance.

Consider these architectural alternatives:

  • Strategy Pattern: Allow drivers to specify their own secret storage strategy
  • Driver Interface Extension: Add a method to the driver interface that determines the storage path
  • Configuration-driven: Move this logic to driver configuration

This approach works for the current requirement but may not scale well if more drivers need special handling.

// Alternative approach - let driver determine storage path
-	var err error
-	if (v.k.driver.Name() == "KMIPSecret") {
-		_, err = v.k.PutSecret(key, toInterfaceMap(s), v.k.driver.SetContext())
-	} else {
-		_, err = v.k.PutSecret(v.BackendSecretName(), toInterfaceMap(s), v.k.driver.SetContext())
-	}
+	secretPath := v.BackendSecretName()
+	if storagePathProvider, ok := v.k.driver.(StoragePathProvider); ok {
+		secretPath = storagePathProvider.GetStoragePath(key)
+	}
+	_, err := v.k.PutSecret(secretPath, toInterfaceMap(s), v.k.driver.SetContext())
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7585d4 and 376b444.

📒 Files selected for processing (1)
  • pkg/util/kms/kms_version.go (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (13)
  • GitHub Check: run-admission-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-hac-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-operator-tests
  • GitHub Check: golangci-lint
🔇 Additional comments (2)
pkg/util/kms/kms_version.go (2)

47-47: LGTM: Enhanced error handling for better K8s compatibility.

The addition of the "does not exist" check alongside "not found" makes the error handling more robust across different Kubernetes error message formats.


110-110: LGTM: Consistent error handling improvement.

Good consistency with the error handling enhancement applied to both VersionSingleSecret and VersionRotatingSecret implementations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 376b444 and 6debea2.

📒 Files selected for processing (4)
  • pkg/util/kms/kms_kmip.go (4 hunks)
  • pkg/util/kms/kms_kmip_storage.go (6 hunks)
  • pkg/util/kms/kms_version.go (4 hunks)
  • pkg/util/kms/test/kmip/kms_kmip_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/util/kms/test/kmip/kms_kmip_test.go
  • pkg/util/kms/kms_kmip.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Neon-White
PR: noobaa/noobaa-operator#1636
File: pkg/backingstore/reconciler.go:718-724
Timestamp: 2025-06-25T15:28:44.044Z
Learning: In pkg/backingstore/reconciler.go, the switch refactor for S3Compatible.SignatureVersion and IBMCos.SignatureVersion maintains the same behavior as the original if-else if logic - when SignatureVersion is empty or unspecified, conn.AuthMethod is left unset. There was no default to V4 in the original code.
pkg/util/kms/kms_version.go (1)
Learnt from: Neon-White
PR: noobaa/noobaa-operator#1636
File: pkg/backingstore/reconciler.go:718-724
Timestamp: 2025-06-25T15:28:44.044Z
Learning: In pkg/backingstore/reconciler.go, the switch refactor for S3Compatible.SignatureVersion and IBMCos.SignatureVersion maintains the same behavior as the original if-else if logic - when SignatureVersion is empty or unspecified, conn.AuthMethod is left unset. There was no default to V4 in the original code.
pkg/util/kms/kms_kmip_storage.go (1)
Learnt from: Neon-White
PR: noobaa/noobaa-operator#1636
File: pkg/backingstore/reconciler.go:718-724
Timestamp: 2025-06-25T15:28:44.044Z
Learning: In pkg/backingstore/reconciler.go, the switch refactor for S3Compatible.SignatureVersion and IBMCos.SignatureVersion maintains the same behavior as the original if-else if logic - when SignatureVersion is empty or unspecified, conn.AuthMethod is left unset. There was no default to V4 in the original code.
🧬 Code Graph Analysis (1)
pkg/util/kms/kms_kmip_storage.go (1)
pkg/util/kms/kms_kmip.go (2)
  • KMIPUniqueID (16-16)
  • NewKMIPUniqueID (17-17)
🪛 golangci-lint (1.64.8)
pkg/util/kms/kms_version.go

124-124: ineffectual assignment to err

(ineffassign)

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-cli-tests
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: golangci-lint
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-kms-tls-token-test
🔇 Additional comments (3)
pkg/util/kms/kms_version.go (1)

49-49: Good improvement to error handling.

The extended error handling to include "does not exist" makes the code more robust against different error message formats.

Also applies to: 112-112

pkg/util/kms/kms_kmip_storage.go (2)

265-274: Well-implemented backward compatibility logic.

The conditional selection between KMIPUniqueID and NewKMIPUniqueID based on the suffix properly supports both single secret (legacy) and rotating secret (new) formats during the transition period.


398-401: Suffix logic consistently applied – no further action needed.

A search for “-root-master-key-backend” shows the same suffix in:

  • pkg/util/kms/kms_version.go (BackendSecretName)
  • pkg/util/kms/kms_kmip_storage.go (DeleteSecret)
  • pkg/util/kms/test/rotate/kms_rotate_test.go

Since the pattern is used uniformly in production code and tests, the conditional cleanup logic is correct and no changes are required. Approving the delete logic as is.

return secrets.NoVersion, err
}

k.secret.StringData[KMIPUniqueID] = registerRespPayload.UniqueIdentifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding minimum key length validation for security.

While the dynamic cryptographic length calculation is more flexible, AES requires specific key lengths (128, 192, or 256 bits). Consider validating that the key length is appropriate for AES encryption.

Add validation before line 358:

// Validate key length for AES
keyLengthBits := len(valueBytes) * 8
if keyLengthBits != 128 && keyLengthBits != 192 && keyLengthBits != 256 {
    return secrets.NoVersion, fmt.Errorf("Invalid AES key length: %d bits. Expected 128, 192, or 256 bits", keyLengthBits)
}
🤖 Prompt for AI Agents
In pkg/util/kms/kms_kmip_storage.go at line 358, add validation before setting
CryptographicLength to ensure the key length in bits is one of the valid AES
lengths: 128, 192, or 256. Calculate keyLengthBits as len(valueBytes) * 8 and
return an error if it does not match these values to enforce proper AES key
length requirements.

Signed-off-by: jackyalbo <jacky.albo@gmail.com>
@jackyalbo jackyalbo force-pushed the jacky-rotate-kmip branch from 6debea2 to ae7408d Compare June 29, 2025 15:36
@liranmauda liranmauda merged commit 975f7ef into noobaa:master Jun 30, 2025
16 checks passed
@tangledbytes
Copy link
Member

I haven't worked with KMS so not sure if I missed anything but looks good in general.

LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants