Skip to content

Commit 62c2795

Browse files
authored
[Key Vault] Implement secure key release (Azure#20048)
1 parent c80ba86 commit 62c2795

20 files changed

+1671
-57
lines changed

sdk/keyvault/azure-keyvault-keys/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
## 4.5.0b2 (Unreleased)
44

55
### Features Added
6+
- Added support for secure key release from a Managed HSM
7+
([#19588](https://github.com/Azure/azure-sdk-for-python/issues/19588))
8+
- Added `release_key` method to `KeyClient` for releasing the private component of a key
9+
- Added `exportable` and `release_policy` keyword-only arguments to key creation and import
10+
methods
11+
- Added `KeyExportEncryptionAlgorithm` enum for specifying an encryption algorithm to be used
12+
in key release
613

714
### Breaking Changes
815
> These changes do not impact the API of stable versions such as 4.4.0.

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22
# Copyright (c) Microsoft Corporation.
33
# Licensed under the MIT License.
44
# -------------------------------------
5-
from ._enums import KeyCurveName, KeyOperation, KeyType
5+
from ._enums import KeyCurveName, KeyExportEncryptionAlgorithm, KeyOperation, KeyType
66
from ._shared.client_base import ApiVersion
7-
from ._models import DeletedKey, JsonWebKey, KeyProperties, KeyVaultKey, KeyVaultKeyIdentifier, RandomBytes
7+
from ._models import (
8+
DeletedKey,
9+
JsonWebKey,
10+
KeyProperties,
11+
KeyReleasePolicy,
12+
KeyVaultKey,
13+
KeyVaultKeyIdentifier,
14+
RandomBytes,
15+
ReleaseKeyResult,
16+
)
817
from ._client import KeyClient
918

1019
__all__ = [
@@ -14,11 +23,14 @@
1423
"KeyVaultKey",
1524
"KeyVaultKeyIdentifier",
1625
"KeyCurveName",
26+
"KeyExportEncryptionAlgorithm",
1727
"KeyOperation",
1828
"KeyType",
1929
"DeletedKey",
2030
"KeyProperties",
31+
"KeyReleasePolicy",
2132
"RandomBytes",
33+
"ReleaseKeyResult",
2234
]
2335

2436
from ._version import VERSION

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py

Lines changed: 101 additions & 14 deletions
Large diffs are not rendered by default.

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_enums.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
# Copyright (c) Microsoft Corporation.
33
# Licensed under the MIT License.
44
# ------------------------------------
5+
# pylint:skip-file (avoids crash due to six.with_metaclass https://github.com/PyCQA/astroid/issues/713)
56
from enum import Enum
7+
from six import with_metaclass
68

9+
from azure.core import CaseInsensitiveEnumMeta
710

8-
class KeyCurveName(str, Enum):
11+
12+
class KeyCurveName(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)):
913
"""Supported elliptic curves"""
1014

1115
p_256 = "P-256" #: The NIST P-256 elliptic curve, AKA SECG curve SECP256R1.
@@ -14,7 +18,15 @@ class KeyCurveName(str, Enum):
1418
p_256_k = "P-256K" #: The SECG SECP256K1 elliptic curve.
1519

1620

17-
class KeyOperation(str, Enum):
21+
class KeyExportEncryptionAlgorithm(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)):
22+
"""Supported algorithms for protecting exported key material"""
23+
24+
CKM_RSA_AES_KEY_WRAP = "CKM_RSA_AES_KEY_WRAP"
25+
RSA_AES_KEY_WRAP_256 = "RSA_AES_KEY_WRAP_256"
26+
RSA_AES_KEY_WRAP_384 = "RSA_AES_KEY_WRAP_384"
27+
28+
29+
class KeyOperation(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)):
1830
"""Supported key operations"""
1931

2032
encrypt = "encrypt"
@@ -24,9 +36,10 @@ class KeyOperation(str, Enum):
2436
verify = "verify"
2537
wrap_key = "wrapKey"
2638
unwrap_key = "unwrapKey"
39+
export = "export"
2740

2841

29-
class KeyType(str, Enum):
42+
class KeyType(with_metaclass(CaseInsensitiveEnumMeta, str, Enum)):
3043
"""Supported key types"""
3144

3245
ec = "EC" #: Elliptic Curve

sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def __init__(self, key_id, attributes=None, **kwargs):
7171
self._vault_id = KeyVaultKeyIdentifier(key_id)
7272
self._managed = kwargs.get("managed", None)
7373
self._tags = kwargs.get("tags", None)
74+
self._release_policy = kwargs.pop("release_policy", None)
7475

7576
def __repr__(self):
7677
# type () -> str
@@ -80,8 +81,19 @@ def __repr__(self):
8081
def _from_key_bundle(cls, key_bundle):
8182
# type: (_models.KeyBundle) -> KeyProperties
8283
"""Construct a KeyProperties from an autorest-generated KeyBundle"""
84+
# release_policy was added in 7.3-preview
85+
release_policy = None
86+
if hasattr(key_bundle, "release_policy") and key_bundle.release_policy is not None:
87+
release_policy = KeyReleasePolicy(
88+
data=key_bundle.release_policy.data, content_type=key_bundle.release_policy.content_type
89+
)
90+
8391
return cls(
84-
key_bundle.key.kid, attributes=key_bundle.attributes, managed=key_bundle.managed, tags=key_bundle.tags
92+
key_bundle.key.kid,
93+
attributes=key_bundle.attributes,
94+
managed=key_bundle.managed,
95+
tags=key_bundle.tags,
96+
release_policy=release_policy,
8597
)
8698

8799
@classmethod
@@ -179,8 +191,8 @@ def recoverable_days(self):
179191
:rtype: int
180192
"""
181193
# recoverable_days was added in 7.1-preview
182-
if self._attributes and hasattr(self._attributes, "recoverable_days"):
183-
return self._attributes.recoverable_days
194+
if self._attributes:
195+
return getattr(self._attributes, "recoverable_days", None)
184196
return None
185197

186198
@property
@@ -210,6 +222,55 @@ def managed(self):
210222
"""
211223
return self._managed
212224

225+
@property
226+
def exportable(self):
227+
# type: () -> Optional[bool]
228+
"""Whether the private key can be exported
229+
230+
:rtype: bool
231+
"""
232+
# exportable was added in 7.3-preview
233+
if self._attributes:
234+
return getattr(self._attributes, "exportable", None)
235+
return None
236+
237+
@property
238+
def release_policy(self):
239+
# type: () -> Optional[KeyReleasePolicy]
240+
"""The :class:`~azure.keyvault.keys.KeyReleasePolicy` specifying the rules under which the key can be exported.
241+
242+
:rtype: ~azure.keyvault.keys.KeyReleasePolicy
243+
"""
244+
return self._release_policy
245+
246+
247+
class KeyReleasePolicy(object):
248+
"""The policy rules under which a key can be exported.
249+
250+
:param data: Blob encoding the policy rules under which the key can be released.
251+
:type data: bytes
252+
253+
:keyword content_type: Content type and version of the release policy. Defaults to "application/json; charset=utf-8"
254+
if omitted.
255+
:paramtype content_type: str
256+
"""
257+
258+
def __init__(self, data, **kwargs):
259+
# type: (bytes, **Any) -> None
260+
self.data = data
261+
self.content_type = kwargs.get("content_type", None)
262+
263+
264+
class ReleaseKeyResult(object):
265+
"""The result of a key release operation.
266+
267+
:ivar str value: A signed token containing the released key.
268+
"""
269+
270+
def __init__(self, value):
271+
# type: (str) -> None
272+
self.value = value
273+
213274

214275
class KeyVaultKey(object):
215276
"""A key's attributes and cryptographic material.

0 commit comments

Comments
 (0)