Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions sdk/keyvault/azure-keyvault-keys/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Release History

## 4.12.0b2 (Unreleased)
## 4.12.0b2 (2026-05-29)

### Features Added

### Breaking Changes

### Bugs Fixed

### Other Changes
- Added the `ExternalKey` model and the new `KeyClient.create_external_key` method
for registering a Key Vault key whose material is held in an external HSM [#47200](https://github.com/Azure/azure-sdk-for-python/pull/47200).
- Added the `KeyProperties.external_key` read-only property.

## 4.12.0b1 (2026-05-26)

Expand Down
24 changes: 24 additions & 0 deletions sdk/keyvault/azure-keyvault-keys/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ This section contains code snippets covering common tasks:
* [Update an existing key](#update-an-existing-key)
* [Delete a key](#delete-a-key)
* [Configure automatic key rotation](#configure-automatic-key-rotation)
* [Register external keys](#register-external-keys-managed-hsm-only)
* [List keys](#list-keys)
* [Perform cryptographic operations](#cryptographic-operations)
* [Async API](#async-api)
Expand Down Expand Up @@ -204,6 +205,29 @@ print(f"Rotated the key on-demand; new version is {rotated_key.properties.versio

<!-- END SNIPPET -->

### Register external keys (Managed HSM only)
[create_external_key](https://aka.ms/azsdk/python/keyvault-keys/docs#azure.keyvault.keys.KeyClient.create_external_key)
registers an external key with a Managed HSM that is configured to use External Key Management (EKM). The external HSM
owns the key material; the Managed HSM stores only a reference to the key.

> **NOTE:** External keys are only supported on Managed HSM, not regular Key Vault. The Managed HSM must be configured
> with an external HSM source.

```python
from azure.identity import DefaultAzureCredential
from azure.keyvault.keys import ExternalKey, KeyClient

credential = DefaultAzureCredential()

key_client = KeyClient(vault_url="https://my-managed-hsm.managedhsm.azure.net/", credential=credential)

external_key = ExternalKey(id="external-key-reference-id")
key = key_client.create_external_key("external-key-name", external_key=external_key)

print(key.name)
print(key.properties.external_key.id)
```

### List keys
[list_properties_of_keys](https://aka.ms/azsdk/python/keyvault-keys/docs#azure.keyvault.keys.KeyClient.list_properties_of_keys)
lists the properties of all of the keys in the client's vault.
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/azure-keyvault-keys/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/keyvault/azure-keyvault-keys",
"Tag": "python/keyvault/azure-keyvault-keys_e47dc10e22"
"Tag": "python/keyvault/azure-keyvault-keys_652b9e1d39"
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ._shared.client_base import ApiVersion
from ._models import (
DeletedKey,
ExternalKey,
JsonWebKey,
KeyAttestation,
KeyProperties,
Expand All @@ -27,6 +28,7 @@
__all__ = [
"ApiVersion",
"KeyClient",
"ExternalKey",
"JsonWebKey",
"KeyAttestation",
"KeyVaultKey",
Expand Down
85 changes: 82 additions & 3 deletions sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@
from ._models import JsonWebKey, KeyRotationLifetimeAction
from ._shared import KeyVaultClientBase
from ._shared._polling import DeleteRecoverPollingMethod, KeyVaultOperationPoller
from ._models import DeletedKey, KeyVaultKey, KeyProperties, KeyReleasePolicy, KeyRotationPolicy, ReleaseKeyResult
from ._models import (
DeletedKey,
ExternalKey,
KeyVaultKey,
KeyProperties,
KeyReleasePolicy,
KeyRotationPolicy,
ReleaseKeyResult,
)


def _get_key_id(vault_url, key_name, version=None):
Expand Down Expand Up @@ -57,6 +65,7 @@ def _get_attributes(
not_before: Optional[datetime],
expires_on: Optional[datetime],
exportable: Optional[bool] = None,
external_key: Optional[ExternalKey] = None,
) -> Optional[KeyAttributes]:
"""Return a KeyAttributes object if non-None attributes are provided, or None otherwise.

Expand All @@ -68,13 +77,25 @@ def _get_attributes(
:type expires_on: ~datetime.datetime or None
:param exportable: Whether the private key can be exported.
:type exportable: bool or None
:param external_key: A reference to an external key, when registering an external key.
:type external_key: ~azure.keyvault.keys.ExternalKey or None

:returns: An autorest-generated model of the key's attributes.
:rtype: KeyAttributes
"""
if enabled is not None or not_before is not None or expires_on is not None or exportable is not None:
if (
enabled is not None
or not_before is not None
or expires_on is not None
or exportable is not None
or external_key is not None
):
return self._models.KeyAttributes(
enabled=enabled, not_before=not_before, expires=expires_on, exportable=exportable
enabled=enabled,
not_before=not_before,
expires=expires_on,
exportable=exportable,
external_key=external_key._to_generated() if external_key is not None else None,
)
return None

Expand Down Expand Up @@ -398,6 +419,64 @@ def create_oct_key(
**kwargs,
)

@distributed_trace
def create_external_key(
self,
name: str,
external_key: ExternalKey,
*,
enabled: Optional[bool] = None,
tags: Optional[Dict[str, str]] = None,
not_before: Optional[datetime] = None,
expires_on: Optional[datetime] = None,
release_policy: Optional[KeyReleasePolicy] = None,
**kwargs: Any,
) -> KeyVaultKey:
"""Register a Managed HSM key that points at material managed by an external HSM.

Requires the keys/create permission. Only available with API version
``2026-01-01-preview`` and newer, and only supported on Managed HSM.

:param str name: The name for the new key.
:param external_key: A reference identifying the external key material.
:type external_key: ~azure.keyvault.keys.ExternalKey

:keyword enabled: Whether the key is enabled for use.
:paramtype enabled: bool or None
:keyword tags: Application specific metadata in the form of key-value pairs.
:paramtype tags: dict[str, str] or None
:keyword not_before: Not before date of the key in UTC.
:paramtype not_before: ~datetime.datetime or None
:keyword expires_on: Expiry date of the key in UTC.
:paramtype expires_on: ~datetime.datetime or None
:keyword release_policy: The policy rules under which the key can be exported.
:paramtype release_policy: ~azure.keyvault.keys.KeyReleasePolicy or None

:returns: The created key.
:rtype: ~azure.keyvault.keys.KeyVaultKey

:raises ~azure.core.exceptions.HttpResponseError:
"""
attributes = self._get_attributes(
enabled=enabled, not_before=not_before, expires_on=expires_on, external_key=external_key
)

policy = release_policy
if policy is not None:
policy = self._models.KeyReleasePolicy(
encoded_policy=policy.encoded_policy, content_type=policy.content_type, immutable=policy.immutable
)
# External keys are mutually exclusive with `kty`. The generated overload requires `kty`,
# but the runtime constructor accepts arbitrary kwargs.
parameters = self._models.KeyCreateParameters( # type: ignore[call-overload]
key_attributes=attributes,
tags=tags,
release_policy=policy,
)

bundle = self._client.create_key(key_name=name, parameters=parameters, **kwargs)
return KeyVaultKey._from_key_bundle(bundle)

@distributed_trace
def begin_delete_key( # pylint:disable=bad-option-value,delete-operation-wrong-return-type
self, name: str, **kwargs: Any
Expand Down
Loading
Loading