DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.

DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
This document outlines the design for a comprehensive Key Management Service (KMS) in Apache CloudStack that provides envelope encryption for volume encryption using Hardware Security Modules (HSMs) or a database-backed fallback provider (also used for testing).
...
| What | Source | Used For |
|---|---|---|
| KEK size | keybits parameter in createKMSKey / rotateKMSKey (stored in kms_keys.key_bits) | Size of the Key Encryption Key stored in the HSM or database. Used when creating or rotating a KEK. |
| DEK size | Global config kms.dek.size.bits | Size of the Data Encryption Key generated per volume. Used in generateVolumeKeyWithKek(). |
keybits controls only the KEK size (e.g., 256-bit AES key in the HSM).kms.dek.size.bits controls the DEK size for all new encrypted volumes....
HSM Profile Management (Admin only)
DBEncryptionUtil before storageKMS Key Management
Key Rotation
Transaction.execute() block; orphaned HSM keys are cleaned up on DB failureVolume Encryption Integration
kms.dek.size.bits) and wrap them with the active KEK versionPlugin Architecture
DatabaseKMSProvider: Database-backed KEK storage with AES/GCM/NoPadding encryption via DBEncryptionUtilPKCS11HSMProvider: PKCS#11 HSM integration with per-profile session pooling and AES/CBC/PKCS5Padding wrappingConcurrency & Cluster Safety
ThreadPoolExecutor(core=2, max=100, keepAlive=60s, SynchronousQueue) with daemon threadsGlobalLock("kms.rewrap.worker") prevents duplicate rewrap work across management server nodesScheduledExecutorService (replaces java.util.Timer) for robust periodic rewrap scheduling...
account_id set → visible only to that accountzone_id set, account_id NULL → visible to all accounts in that zonezone_id NULL, account_id NULL, system is_public = TRUE → visible to all accounts in all zones...
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
name | Yes | String | Name of the KMS key |
description | No | String | Description of the KMS key |
purpose | Yes | String | Purpose of the key (volume, tls) |
zoneid | Yes | UUID | Zone ID where the key will be valid |
hsmprofileid | Yes | UUID | HSM profile ID to create the KEK in |
keybits | No | Integer | KEK size in bits (128, 192, 256). Default: 256 |
account | No | String | Account name (admin use) |
domainid | No | UUID | Domain ID (admin use) |
CloudMonkey Example:
cmk createKMSKey \
name="volume-encryption-key" \
description="Production volume encryption" \
purpose="volume" \
keybits=256 \
zoneid=<zone-uuid> \
hsmprofileid=<hsm-profile-uuid>
Lists KMS keys available to the caller.
Parameters:
Lists KMS keys available to the caller.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | No | UUID | List KMS key by UUID |
purpose | No | String | Filter by purpose |
zoneid | No | UUID | Filter by |
| Parameter | Required | Type | Description |
id | No | UUID | List KMS key by UUID |
purpose | No | String | Filter by purpose | zoneid | No | UUID | Filter by
| zone | |||
state | No | String | Filter by state (Enabled, Disabled) |
...
cmk listKMSKeys purpose=volume state=Enabled
Updates KMS key name, description, or state.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | Yes | UUID | KMS key UUID |
name | No | String | New name |
description | No | String | New description |
enabled | No | Boolean | Enable/disable the key |
CloudMonkey Example:
cmk updateKMSKey id=<kms-key-uuid> enabled=false
Deletes a KMS key (Deletes a KMS key (only if not referenced by volumes or wrapped keys).
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | Yes | UUID | KMS key UUID |
CloudMonkey Example:
...
Rotates KEK by creating a new version and scheduling gradual re-encryption of wrapped keys.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | Yes | UUID | KMS key UUID to rotate |
keybits | No | Integer | Key size for new KEK (default: same as current) |
hsmprofileid | No | UUID | Target HSM profile for cross-HSM migration |
CloudMonkey Examples:
# Same-HSM rotation
cmk rotateKMSKey id=<kms-key-uuid>
# Cross-HSM migration
cmk rotateKMSKey id=<kms-key-uuid> hsmprofileid=<target-hsm-profile-uuid>
Migrates passphrase-based volumes to KMS encryption.
Parameters:
Migrates passphrase-based volumes to KMS encryption.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
zoneid | Yes | UUID | Zone ID |
id | Yes | UUID | KMS key ID to migrate volumes to |
account | No | String | Migrate volumes for specific account |
domainid | No | UUID | Domain ID |
CloudMonkey Example:
cmk migrateVolumesToKMS zoneid=<zone-uuid> id=<kms-key-uuid>
Adds a new HSM profile for Adds a new HSM profile for connecting to an HSM device.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
name | Yes | String | HSM profile name |
protocol | No | String | Protocol (PKCS11, KMIP, etc.). Default: pkcs11 |
zoneid | No | UUID | Zone ID (null = global scope) |
domainid | No | UUID | Domain ID |
account | No | String | Account name |
| is_public | No | Boolean | |
| Public profile (globally available, root admin only) | |||
vendorname | No | String | HSM vendor name |
details | No | Map | HSM configuration |
PKCS#11 details keys: library (path to PKCS#11 library), slot (slot number), pin (HSM PIN, encrypted at rest), token_label (token label), minSessions, maxSessions
CloudMonkey Example:
...
| details |
PKCS#11 details keys: library (path to PKCS#11 library), slot (slot number), pin (HSM PIN, encrypted at rest), token_label (token label), minSessions, maxSessions
Lists HSM profiles visible to the caller.
ENC(...))Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | No | UUID | HSM profile ID |
zoneid | No | UUID | Zone ID |
protocol | No | String | Protocol filter |
enabled | No | Boolean | Enabled filter |
CloudMonkey Example:
...
Updates an HSM profile name or enabled state.
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | Yes | UUID | HSM profile UUID |
name | No | String | New name |
enabled | No | Boolean | Enable/disable |
Note: Updating configuration
detailsis not currently supported. To change PKCS#11 parameters (e.g., PIN), delete and re-create the HSM profile.
CloudMonkey Example:
...
| Enable/disable |
Deletes an HSM profile (only if not in use by any KEK versions).
Parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
id | Yes | UUID | HSM profile UUID |
CloudMonkey Example:
...
| Setting Key | Scope | Type | Default | Description |
|---|---|---|---|---|
kms.dek.size.bits | Global | Integer | 256 | Size of DEKs in bits for new volumes (128, 192, 256) |
kms.retry.count | Global | Integer | 3 | Number of retry attempts for transient KMS failures |
kms.retry.delay.ms | Global | Integer | 1000 | Delay in milliseconds between retry attempts |
kms.operation.timeout.sec | Global | Integer | 30 | Per-attempt timeout for KMS operations |
kms.rewrap.batch.size | Global | Integer | 50 | Wrapped keys rewrapped per batch in background job |
kms.rewrap.interval.ms | Global | Long | 300000 | Interval between background rewrap executions (5 min) |
...
Stores HSM profile configurations. Scoped by account_id, domain_id, and zone_id.
| Code Block |
|---|
CREATE TABLE IF NOT EXISTS `cloud`.`kms_hsm_profiles` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `uuid` VARCHAR(40) NOT NULL, `name` VARCHAR(255) NOT NULL, `protocol` VARCHAR(32) NOT NULL COMMENT 'PKCS11, KMIP, AWS_KMS, etc.', `account_id` BIGINT UNSIGNED COMMENT 'null = admin-provided', `domain_id` BIGINT UNSIGNED, `zone_id` BIGINT UNSIGNED COMMENT 'null = global scope', `vendor_name` VARCHAR(64), `enabled` BOOLEAN NOT NULL DEFAULT TRUE, |
...
`is_public` BOOLEAN NOT NULL DEFAULT FALSE, `created` DATETIME NOT NULL, `removed` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `uk_uuid` (`uuid`), UNIQUE KEY `uk_account_name` (`account_id`, `name`, `removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.kms_hsm_profile_detailsKey-value configuration details for HSM profiles. Sensitive values (PIN, password) are encrypted via DBEncryptionUtil.
| Code Block | ||
|---|---|---|
| ||
CREATE TABLE IF NOT EXISTS `cloud`.`kms_hsm_profile_details` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `profile_id` BIGINT UNSIGNED NOT NULL, `name` VARCHAR(255) NOT NULL, |
...
`value` TEXT NOT NULL COMMENT 'encrypted if sensitive', PRIMARY KEY (`id`), UNIQUE KEY `uk_profile_name` (`profile_id`, `name`), CONSTRAINT `fk_kms_hsm_profile_details__profile_id` FOREIGN KEY (`profile_id`) REFERENCES `kms_hsm_profiles`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.kms_keysKMS key (KEK) metadata. Account-scoped, zone-bound.
| Code Block | ||
|---|---|---|
| ||
CREATE TABLE IF NOT EXISTS `cloud`.`kms_keys` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `uuid` VARCHAR(40) NOT NULL, `name` VARCHAR(255) NOT NULL, `description` VARCHAR(1024), `kek_label` VARCHAR(255) NOT NULL, `purpose` VARCHAR(32) NOT NULL COMMENT 'VOLUME_ENCRYPTION, TLS_CERT, CONFIG_SECRET', `account_id` BIGINT UNSIGNED NOT NULL, `domain_id` BIGINT UNSIGNED NOT NULL, `zone_id` BIGINT UNSIGNED NOT NULL, `algorithm` VARCHAR(64) NOT NULL DEFAULT 'AES/GCM/NoPadding', `key_bits` INT NOT NULL DEFAULT 256, `enabled` TINYINT(1) NOT NULL DEFAULT 1, `hsm_profile_id` BIGINT UNSIGNED NOT NULL, `created` DATETIME NOT NULL, `removed` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `uk_uuid` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.kms_kek_versionsKEK versions for gradual key rotation. Only one Active version per KMS key at a time.
| Code Block | ||
|---|---|---|
| ||
CREATE TABLE IF NOT EXISTS `cloud`.`kms_kek_versions` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `uuid` VARCHAR(40) NOT NULL, `kms_key_id` BIGINT UNSIGNED NOT NULL, `version_number` INT NOT NULL, `kek_label` VARCHAR(255) NOT NULL, `status` VARCHAR(32) NOT NULL DEFAULT 'Active' COMMENT 'Active, Previous, Archived', `hsm_profile_id` BIGINT UNSIGNED, `hsm_key_label` VARCHAR(255), `created` DATETIME NOT NULL, `removed` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `uk_uuid` (`uuid`), UNIQUE KEY `uk_kms_key_version` (`kms_key_id`, `version_number`, `removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.kms_wrapped_keyWrapped DEKs. Each volume references one wrapped key.
| Code Block | ||
|---|---|---|
| ||
CREATE TABLE IF NOT EXISTS `cloud`.`kms_wrapped_key` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `uuid` VARCHAR(40) NOT NULL, `kms_key_id` BIGINT UNSIGNED, `kek_version_id` BIGINT UNSIGNED, `zone_id` BIGINT UNSIGNED NOT NULL, `wrapped_blob` VARBINARY(4096) NOT NULL, `created` DATETIME NOT NULL, `removed` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `uk_uuid` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.kms_database_kek_objectsPKCS#11-compatible object storage for the database KMS provider. Key material is encrypted via DBEncryptionUtil (Base64-encoded KEK → DBEncryptionUtil.encrypt() → stored bytes).
| Code Block | ||
|---|---|---|
| ||
CREATE TABLE IF NOT EXISTS `cloud`.`kms_database_kek_objects` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `uuid` VARCHAR(40) NOT NULL, `object_class` VARCHAR(32) NOT NULL DEFAULT 'CKO_SECRET_KEY', `label` VARCHAR(255) NOT NULL, `object_id` VARBINARY(64), `key_type` VARCHAR(32) NOT NULL DEFAULT 'CKK_AES', `key_material` VARBINARY(512) NOT NULL COMMENT 'encrypted KEK material', `is_sensitive` BOOLEAN NOT NULL DEFAULT TRUE, `is_extractable` BOOLEAN NOT NULL DEFAULT FALSE, `purpose` VARCHAR(32) NOT NULL, `key_bits` INT NOT NULL, `algorithm` VARCHAR(64) NOT NULL DEFAULT 'AES/GCM/NoPadding', `created` DATETIME NOT NULL, `removed` DATETIME, PRIMARY KEY (`id`), UNIQUE KEY `uk_uuid` (`uuid`), UNIQUE KEY `uk_label` (`label`, `removed`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
...
cloud.volumesTwo new columns added via schema migration:
| Code Block | ||
|---|---|---|
| ||
-- KMS key reference ALTER TABLE `cloud`.`volumes` ADD COLUMN `kms_key_id` BIGINT UNSIGNED; ALTER TABLE `cloud`.`volumes` ADD CONSTRAINT `fk_volumes__kms_key_id` FOREIGN KEY (`kms_key_id`) REFERENCES `kms_keys`(`id`); -- Wrapped DEK reference ALTER TABLE `cloud`.`volumes` ADD COLUMN `kms_wrapped_key_id` BIGINT UNSIGNED; ALTER TABLE `cloud`.`volumes` ADD CONSTRAINT `fk_volumes__kms_wrapped_key_id` FOREIGN KEY (`kms_wrapped_key_id`) REFERENCES `kms_wrapped_key`(`id`); |
...
A new KMS top-level menu section is added with two sub-sections:
...