Feature: Key Management Service (KMS)#12711
Conversation
0a283c9 to
5112eea
Compare
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## main #12711 +/- ##
=============================================
- Coverage 18.02% 3.51% -14.51%
=============================================
Files 5968 465 -5503
Lines 537086 40194 -496892
Branches 65961 7572 -58389
=============================================
- Hits 96819 1414 -95405
+ Misses 429347 38590 -390757
+ Partials 10920 190 -10730
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
ceb2913 to
d629f87
Compare
There was a problem hiding this comment.
Pull request overview
This pull request introduces a comprehensive Key Management Service (KMS) framework for CloudStack that provides envelope encryption for volume encryption. KEKs (Key Encryption Keys) stored in PKCS#11-compliant HSMs or the CloudStack database wrap per-volume DEKs (Data Encryption Keys), ensuring key material is never stored in plaintext.
Changes:
- Adds KMS framework with HSM integration for envelope encryption
- Introduces 8 new admin/user APIs for KMS key and HSM profile management
- Creates 6 new database tables for storing KMS metadata
- Adds UI support for KMS key selection in volume and VM deployment workflows
Reviewed changes
Copilot reviewed 123 out of 123 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
framework/kms/ |
Core KMS framework interfaces and exceptions |
plugins/kms/ |
Database and PKCS#11 KMS provider implementations |
engine/schema/ |
Database entities and DAOs for KMS tables |
api/src/main/java/org/apache/cloudstack/api/command/ |
New API commands for KMS operations |
ui/src/views/ |
UI components for KMS key selection |
server/src/main/java/ |
KMS manager implementation and integration |
| Test files | Unit tests for KMS retry logic and key creation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ba00a5d to
943f19a
Compare
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16962 |
8ea09bb to
df2df4b
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 124 out of 124 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeObject.java
Show resolved
Hide resolved
engine/schema/src/main/java/org/apache/cloudstack/kms/dao/KMSWrappedKeyDaoImpl.java
Show resolved
Hide resolved
75519c2 to
1fce0b2
Compare
|
@blueorangutan package |
|
@vishesh92 a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16998 |
|
@blueorangutan package |
|
@vishesh92 a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 17008 |
| entityEventDetails.put(EVENT_HSM_PROFILE_CREATE, HSMProfile.class); | ||
| entityEventDetails.put(EVENT_HSM_PROFILE_UPDATE, HSMProfile.class); | ||
| entityEventDetails.put(EVENT_HSM_PROFILE_DELETE, HSMProfile.class); | ||
|
|
There was a problem hiding this comment.
VOLUME.MIGRATE.TO.KMS event?
| import java.util.List; | ||
|
|
||
| @APICommand(name = "migrateVolumesToKMS", | ||
| description = "Migrates passphrase-based volumes to KMS (admin only)", |
There was a problem hiding this comment.
| description = "Migrates passphrase-based volumes to KMS (admin only)", | |
| description = "Migrates encrypted volumes to KMS", |
not need of admin only, it's authorized, listed as admin's API
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
| description = "the ID of the project to add the HSM profile for") | ||
| private Long projectId; | ||
|
|
||
| @Parameter(name = "system", type = CommandType.BOOLEAN, |
There was a problem hiding this comment.
| @Parameter(name = "system", type = CommandType.BOOLEAN, | |
| @Parameter(name = "ApiConstants.IS_PUBLIC", type = CommandType.BOOLEAN, |
| @Parameter(name = "system", type = CommandType.BOOLEAN, | ||
| description = "whether this is a system HSM profile available to all users globally (root admin only). " | ||
| + "Default is false") | ||
| private Boolean system; |
There was a problem hiding this comment.
| private Boolean system; | |
| private Boolean isPublic; |
| private String encryptionFormat; | ||
|
|
||
| @SerializedName(ApiConstants.KMS_KEY) | ||
| @Param(description = "KMS key id of the volume", since = "4.23.0") |
There was a problem hiding this comment.
| @Param(description = "KMS key id of the volume", since = "4.23.0") | |
| @Param(description = "KMS key of the volume", since = "4.23.0") |
| return setPassphraseForVolumeEncryption(volume, null, null); | ||
| } | ||
|
|
||
| private VolumeVO setPassphraseForVolumeEncryption(VolumeVO volume, KMSKeyVO kmsKey, Long callerAccountId) { |
There was a problem hiding this comment.
| private VolumeVO setPassphraseForVolumeEncryption(VolumeVO volume, KMSKeyVO kmsKey, Long callerAccountId) { | |
| private VolumeVO setKmsKeyForVolumeEncryption(VolumeVO volume, KMSKeyVO kmsKey, Long callerAccountId) { |
change if relavant.
| CONSTRAINT `fk_kms_keys__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE, | ||
| CONSTRAINT `fk_kms_keys__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE, | ||
| CONSTRAINT `fk_kms_keys__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, | ||
| CONSTRAINT `fk_kms_keys__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) |
There was a problem hiding this comment.
| CONSTRAINT `fk_kms_keys__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) | |
| CONSTRAINT `fk_kms_keys__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) ON DELETE CASCADE |
| INDEX `idx_kms_key_status` (`kms_key_id`, `status`, `removed`), | ||
| INDEX `idx_kek_label` (`kek_label`), | ||
| CONSTRAINT `fk_kms_kek_versions__kms_key_id` FOREIGN KEY (`kms_key_id`) REFERENCES `kms_keys`(`id`) ON DELETE CASCADE, | ||
| CONSTRAINT `fk_kms_kek_versions__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) |
There was a problem hiding this comment.
| CONSTRAINT `fk_kms_kek_versions__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) | |
| CONSTRAINT `fk_kms_kek_versions__hsm_profile_id` FOREIGN KEY (`hsm_profile_id`) REFERENCES `kms_hsm_profiles`(`id`) ON DELETE CASCADE |
| public static final String EVENT_KMS_KEY_UPDATE = "KMS.KEY.UPDATE"; | ||
| public static final String EVENT_KMS_KEY_ROTATE = "KMS.KEY.ROTATE"; | ||
| public static final String EVENT_KMS_KEY_DELETE = "KMS.KEY.DELETE"; | ||
| public static final String EVENT_VOLUME_MIGRATE_TO_KMS = "VOLUME.MIGRATE.TO.KMS"; |
There was a problem hiding this comment.
| public static final String EVENT_VOLUME_MIGRATE_TO_KMS = "VOLUME.MIGRATE.TO.KMS"; |
| import javax.inject.Inject; | ||
|
|
||
| @APICommand(name = "rotateKMSKey", | ||
| description = "Rotates KEK by creating new version and scheduling gradual re-encryption", |
There was a problem hiding this comment.
| description = "Rotates KEK by creating new version and scheduling gradual re-encryption", | |
| description = "Rotates KMS key (KEK) by creating new version and scheduling gradual re-encryption", |
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| @APICommand(name = "addHSMProfile", description = "Adds a new HSM profile", responseObject = HSMProfileResponse.class, |
There was a problem hiding this comment.
| @APICommand(name = "addHSMProfile", description = "Adds a new HSM profile", responseObject = HSMProfileResponse.class, | |
| @APICommand(name = "createHSMProfile", description = "Creates a new HSM profile", responseObject = HSMProfileResponse.class, |
| @Param(description = "whether the HSM profile is enabled") | ||
| private Boolean enabled; | ||
|
|
||
| @SerializedName("system") |
There was a problem hiding this comment.
| @SerializedName("system") | |
| @SerializedName(ApiConstants.IS_PUBLIC) |
| return volume; | ||
| } | ||
|
|
||
| if (kmsKey != null) { |
There was a problem hiding this comment.
refactor the kms key to a method
| 'Domain': 'Domain', | ||
| 'Template': 'Template', | ||
| 'KMS': 'KMS', | ||
| 'HSM': 'KMS', |
There was a problem hiding this comment.
| 'HSM': 'KMS', | |
| 'HSM': 'Key Management System', |
| { | ||
| api: 'migrateVolumesToKMS', | ||
| icon: 'swap-outlined', | ||
| docHelp: 'adminguide/storage.html#lifecycle-operations', |
There was a problem hiding this comment.
update the doc links
Key Management Service (KMS) with HSM Integration
Description
Introduces a Key Management Service (KMS) framework for CloudStack that provides envelope encryption for volume encryption. KEKs (Key Encryption Keys) stored in PKCS#11-compliant HSMs or the CloudStack database wrap per-volume DEKs (Data Encryption Keys), ensuring key material is never stored in plaintext.
Design Document: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Key+Management+Service+%28KMS%29+with+HSM+Integration
Docs PR: apache/cloudstack-documentation#634
New APIs
createKMSKeylistKMSKeysupdateKMSKeydeleteKMSKeyrotateKMSKeymigrateVolumesToKMSaddHSMProfilelistHSMProfilesupdateHSMProfiledeleteHSMProfileNew Database Tables
kms_hsm_profiles,kms_hsm_profile_details,kms_keys,kms_kek_versions,kms_wrapped_key,kms_database_kek_objectsModified:
cloud.volumes— addedkms_key_idandkms_wrapped_key_idcolumns.New Global Settings
kms.dek.size.bits256kms.retry.count3kms.retry.delay.ms1000kms.operation.timeout.sec30kms.rewrap.batch.size50kms.rewrap.interval.ms300000UI Changes
How to Test
Tested with: