Allow GCP KMS keys to use a custom cryptoKey version#515
Conversation
Until now, every GCP KMS operation hardcoded cryptoKey version "1". This matches Canton-generated keys (Canton always creates a new cryptoKey rather than adding a version to an existing one), but it prevents using cryptoKeys whose key material was imported into GCP KMS, since each import creates a new cryptoKey version and the version that holds the imported material is typically not "1" -- and can be relevant even for asymmetric keys. Add a new optional `key-version-overrides` field to `KmsConfig.Gcp`, mapping a cryptoKey id to the cryptoKey version Canton should use for that key. Keys not listed continue to default to "1", so existing configurations are unchanged. The lookup happens at every call site that previously used the hardcoded version, via a single `cryptoKeyVersionName` helper. Symmetric encrypt/decrypt paths are unchanged: GCP picks the primary version on encrypt and recovers it from the ciphertext on decrypt, so no per-key version is needed there. Includes documentation for the new field in the GCP KMS config reference and the external-key-storage how-to, plus an UNRELEASED.md entry.
|
✅ All required contributors have signed the CLA for this PR. Thank you! |
|
I have hereby read the Digital Asset CLA and agree to its terms |
|
recheck |
|
Hello @same-id , sorry for the delay in replying. I was wondering whether we could instead use Do you think this would work? Do you see any use case where choosing the latest version might be incorrect? This way, we could avoid the extra configuration, which can be hard to keep track of and set correctly. What do you think? |
|
I initially wanted to do that - the API calls themselves are cheap and only done at startup I guess, to resolve the key itself. But even so, I thought that maybe a user might want to do key migration and during the key migration the user will want access to both key versions at the same time. Not 100% sure about that use case. Generally in hindsight I am guessing the correct way of passing the KMS key inside would be like in terraform packages where you give the entry resource as a url: gcpkms://......./keyRing/....../key/....../keyVersions/ But seems like Canton already is not working this way and constructs the url itself at each point from the url parts. I would assume a I don't mind for either way - any thoughts? |
|
I wonder if we could do the following: On the register keys command, we could either:
This would require a regex check on the GCP KMS ID to determine whether it is a full Terraform identifier or a regular KMS ID. That way, we could keep the static config and the |
Would option 2 still require setting all that: type = gcp Which are a part of the terraform key-id anyway? We can also just support For option 1 just need to make sure we have the KMS client threaded to all the functions that need it Whatever you prefer. |
|
In my opinion, since we don’t yet have a use case for selecting a key version other than the latest one, I would only implement option 1 for now. We can always revisit this later if we do end up needing to select a version that is not the latest one. |
|
I opened a different PR - so it would be easier to compare the change size. Notice that now we need some new permissions and we change the default behavior. |
Summary
Until now, every GCP KMS operation hardcoded cryptoKey version
"1". That matches Canton-generated keys (Canton always creates a new cryptoKey rather than adding a version to an existing one), but it prevents using cryptoKeys whose key material was imported into GCP KMS — each import creates a new cryptoKey version, and the version holding the imported material is typically not"1". This is relevant even for asymmetric keys.This PR adds a new optional
key-version-overridesfield toKmsConfig.Gcp, mapping a cryptoKey id to the cryptoKey version Canton should use for that key. Keys not listed in the map continue to default to version"1", so existing configurations are unchanged.All
CryptoKeyVersionName.of(...)call sites now go through a singlecryptoKeyVersionNamehelper that reads the version viaconfig.keyVersionOverrides.getOrElse(keyId.unwrap, "1").Symmetric encrypt/decrypt paths are unchanged: GCP picks the primary version on encrypt and recovers it from the ciphertext on decrypt, so no per-key version is needed there.
Documentation: adds the new field to
kms_gcp_config.rst, links to it from the external-key-storage how-to, and adds anUNRELEASED.mdminor-improvement entry.