diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py index c00fd1461b4b..3e072ff03a5f 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/__init__.py @@ -2,6 +2,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------- -from ._client import KeyClient +from .client import KeyClient +from .enums import JsonWebKeyCurveName, JsonWebKeyOperation, JsonWebKeyType -__all__ = ["KeyClient"] +__all__ = ["JsonWebKeyCurveName", "JsonWebKeyOperation", "JsonWebKeyType", "KeyClient"] diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py deleted file mode 100644 index b591ffdcaf0f..000000000000 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_client.py +++ /dev/null @@ -1,718 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ -from datetime import datetime - -try: - from typing import TYPE_CHECKING -except ImportError: - TYPE_CHECKING = False - -if TYPE_CHECKING: - from typing import Any, Dict, Generator, Mapping, Optional - -from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError -from azure.core.tracing.decorator import distributed_trace - -from ._shared import KeyVaultClientBase -from ._models import Key, KeyBase, DeletedKey, KeyOperationResult - - -class KeyClient(KeyVaultClientBase): - """KeyClient is a high-level interface for managing a vault's keys. - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START create_key_client] - :end-before: [END create_key_client] - :language: python - :caption: Creates a new instance of the Key client - :dedent: 4 - """ - - # pylint:disable=protected-access - - @distributed_trace - def create_key( - self, - name, - key_type, - size=None, - key_operations=None, - enabled=None, - expires=None, - not_before=None, - tags=None, - curve=None, - **kwargs - ): - # type: (str, str, Optional[int], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Optional[str], Mapping[str, Any]) -> Key - """Creates a new key, stores it, then returns the key to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. - - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param key_type: The type of key to create. For valid values, see - JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', - 'RSA-HSM', 'oct' - :type key_type: str or ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyType - :param size: The key size in bits. For example: 2048, 3072, or - 4096 for RSA. - :type size: int - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :param curve: Elliptic curve name. If none then defaults to 'P-256'. For valid values, see - JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', - 'P-521', 'SECP256K1' - :type curve: str or ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyCurveName - :returns: The created key - :rtype: ~azure.keyvault.keys._models.Key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START create_key] - :end-before: [END create_key] - :language: python - :caption: Creates a key in the key vault - :dedent: 8 - """ - if enabled is not None or not_before is not None or expires is not None: - attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) - else: - attributes = None - - bundle = self._client.create_key( - self.vault_url, - name, - key_type, - size, - key_attributes=attributes, - key_ops=key_operations, - tags=tags, - curve=curve, - **kwargs - ) - return Key._from_key_bundle(bundle) - - @distributed_trace - def create_rsa_key( - self, - name, - hsm, - size=None, - key_operations=None, - enabled=None, - expires=None, - not_before=None, - tags=None, - **kwargs - ): - # type: (str, bool, Optional[int], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key - """Creates a new RSA type key, stores it, then returns key to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. - - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param hsm: Whether to create as a hardware key (HSM) or software key. - :type hsm: bool - :param size: The key size in bits. For example: 2048, 3072, or - 4096 for RSA. - :type size: int - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The created RSA key - :rtype: ~azure.keyvault.keys._models.Key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START create_rsa_key] - :end-before: [END create_rsa_key] - :language: python - :caption: Creates a RSA key in the key vault - :dedent: 8 - """ - key_type = "RSA-HSM" if hsm else "RSA" - - return self.create_key( - name, - key_type=key_type, - size=size, - key_operations=key_operations, - enabled=enabled, - expires=expires, - not_before=not_before, - tags=tags, - **kwargs - ) - - @distributed_trace - def create_ec_key( - self, - name, - hsm, - curve=None, - key_operations=None, - enabled=None, - expires=None, - not_before=None, - tags=None, - **kwargs - ): - # type: (str, bool, Optional[str], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key - """Creates a new Elliptic curve type key, stores it, then returns key to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. - - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param hsm: Whether to create as a hardware key (HSM) or software key. - :type hsm: bool - :param curve: Elliptic curve name. If none then defaults to 'P-256'. For valid values, see - JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', - 'P-521', 'SECP256K1' - :type curve: str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyCurveName - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The created EC key - :rtype: ~azure.keyvault.keys._models.Key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START create_ec_key] - :end-before: [END create_ec_key] - :language: python - :caption: Creates an EC key in the key vault - :dedent: 8 - """ - - key_type = "EC-HSM" if hsm else "EC" - - return self.create_key( - name, - key_type=key_type, - curve=curve, - key_operations=key_operations, - enabled=enabled, - expires=expires, - not_before=not_before, - tags=tags, - **kwargs - ) - - @distributed_trace - def delete_key(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> DeletedKey - """Deletes a key from the Key Vault. - - The delete key operation cannot be used to remove individual versions - of a key. This operation removes the cryptographic material associated - with the key, which means the key is not usable for Sign/Verify, - Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the - keys/delete permission. - - :param name: The name of the key to delete. - :type name: str - :returns: The deleted key - :rtype: ~azure.keyvault.keys._models.DeletedKey - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START delete_key] - :end-before: [END delete_key] - :language: python - :caption: Deletes a key in the key vault - :dedent: 8 - """ - bundle = self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) - return DeletedKey._from_deleted_key_bundle(bundle) - - @distributed_trace - def get_key(self, name, version=None, **kwargs): - # type: (str, Optional[str], Mapping[str, Any]) -> Key - """Gets the public part of a stored key. - - The get key operation is applicable to all key types. If the requested - key is symmetric, then no key material is released in the response. - This operation requires the keys/get permission. - - :param name: The name of the key to get. - :type name: str - :param version: Retrieves a specific version of a key. If the version is None or an empty string, - the latest version of the key is returned - :type version: str - :returns: Key - :rtype: ~azure.keyvault.keys._models.Key - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START get_key] - :end-before: [END get_key] - :language: python - :caption: Retrieves a key from the key vault - :dedent: 8 - """ - bundle = self._client.get_key( - self.vault_url, name, key_version=version or "", error_map={404: ResourceNotFoundError}, **kwargs - ) - return Key._from_key_bundle(bundle) - - @distributed_trace - def get_deleted_key(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> DeletedKey - """Gets a deleted key from the Key Vault - - The Get Deleted Key operation is applicable for soft-delete enabled - vaults. While the operation can be invoked on any vault, it will return - an error if invoked on a non soft-delete enabled vault. This operation - requires the keys/get permission. - - :param name: The name of the key. - :type name: str - :returns: The deleted key - :rtype: ~azure.keyvault.keys._models.DeletedKey - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START get_deleted_key] - :end-before: [END get_deleted_key] - :language: python - :caption: Retrieves a deleted key from the key vault - :dedent: 8 - """ - bundle = self._client.get_deleted_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) - return DeletedKey._from_deleted_key_bundle(bundle) - - @distributed_trace - def list_deleted_keys(self, **kwargs): - # type: (Mapping[str, Any]) -> Generator[DeletedKey] - """Lists the deleted keys in the Key Vault - - Retrieves a list of the keys in the Key Vault as JSON Web Key - structures that contain the public part of a deleted key. This - operation includes deletion-specific information. The Get Deleted Keys - operation is applicable for vaults enabled for soft-delete. While the - operation can be invoked on any vault, it will return an error if - invoked on a non soft-delete enabled vault. This operation requires the - keys/list permission. - - :returns: An iterator like instance of DeletedKey - :rtype: - Generator[~azure.keyvault.keys._models.DeletedKey] - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START list_deleted_keys] - :end-before: [END list_deleted_keys] - :language: python - :caption: List all the deleted keys in the vault - :dedent: 8 - """ - max_page_size = kwargs.get("max_page_size", None) - return self._client.get_deleted_keys( - self._vault_url, - maxresults=max_page_size, - cls=lambda objs: [DeletedKey._from_deleted_key_item(x) for x in objs], - **kwargs - ) - - @distributed_trace - def list_keys(self, **kwargs): - # type: (Mapping[str, Any]) -> Generator[KeyBase] - """List the keys in the Key Vault - - Retrieves a list of the keys in the Key Vault as JSON Web Key - structures that contain the public part of a stored key. The LIST - operation is applicable to all key types, however only the base key - identifier, attributes, and tags are provided in the response. - Individual versions of a key are not listed in the response. This - operation requires the keys/list permission. - - :returns: An iterator like instance of KeyBase - :rtype: - Generator[~azure.keyvault.keys._models.KeyBase] - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START list_keys] - :end-before: [END list_keys] - :language: python - :caption: List all keys in the vault - :dedent: 8 - """ - max_page_size = kwargs.get("max_page_size", None) - return self._client.get_keys( - self._vault_url, - maxresults=max_page_size, - cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], - **kwargs - ) - - @distributed_trace - def list_key_versions(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> Generator[KeyBase] - """Retrieves a list of individual key versions with the same key name. - - The full key identifier, attributes, and tags are provided in the - response. This operation requires the keys/list permission. - - :param name: The name of the key. - :type name: str - :returns: An iterator like instance of KeyBase - :rtype: - Generator[~azure.keyvault.keys._models.KeyBase] - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START list_key_versions] - :end-before: [END list_key_versions] - :language: python - :caption: List all versions of the specified key - :dedent: 8 - """ - max_page_size = kwargs.get("max_page_size", None) - return self._client.get_key_versions( - self._vault_url, - name, - maxresults=max_page_size, - cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], - **kwargs - ) - - @distributed_trace - def purge_deleted_key(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> None - """Permanently deletes the specified key. - - The Purge Deleted Key operation is applicable for soft-delete enabled - vaults. While the operation can be invoked on any vault, it will return - an error if invoked on a non soft-delete enabled vault. This operation - requires the keys/purge permission. - - :param name: The name of the key - :type name: str - :returns: None - :rtype: None - - Example: - .. code-block:: python - - # if the vault has soft-delete enabled, purge permanently deletes a deleted key - # (with soft-delete disabled, delete itself is permanent) - key_client.purge_deleted_key("key-name") - - """ - self._client.purge_deleted_key(self.vault_url, name, kwargs) - - @distributed_trace - def recover_deleted_key(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> Key - """Recovers the deleted key to its latest version. - - The Recover Deleted Key operation is applicable for deleted keys in - soft-delete enabled vaults. It recovers the deleted key back to its - latest version under /keys. An attempt to recover an non-deleted key - will return an error. Consider this the inverse of the delete operation - on soft-delete enabled vaults. This operation requires the keys/recover - permission. - - :param name: The name of the deleted key. - :type name: str - :returns: The recovered deleted key - :rtype: ~azure.keyvault.keys._models.Key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START recover_deleted_key] - :end-before: [END recover_deleted_key] - :language: python - :caption: Recovers the specified soft-deleted key - :dedent: 8 - """ - bundle = self._client.recover_deleted_key(self.vault_url, name, kwargs) - return Key._from_key_bundle(bundle) - - @distributed_trace - def update_key( - self, name, version=None, key_operations=None, enabled=None, expires=None, not_before=None, tags=None, **kwargs - ): - # type: (str, Optional[str], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key - """The update key operation changes specified attributes of a stored key - and can be applied to any key type and key version stored in Azure Key - Vault. - - In order to perform this operation, the key must already exist in the - Key Vault. Note: The cryptographic material of a key itself cannot be - changed. This operation requires the keys/update permission. - - :param name: The name of key to update. - :type name: str - :param version: The version of the key to update. - :type version: str - :param key_operations: Json web key operations. For more information on - possible key operations, see JsonWebKeyOperation. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The updated key - :rtype: ~azure.keyvault.keys._models.Key - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START update_key] - :end-before: [END update_key] - :language: python - :caption: Updates a key in the key vault - :dedent: 8 - """ - if enabled is not None or not_before is not None or expires is not None: - attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) - else: - attributes = None - bundle = self._client.update_key( - self.vault_url, - name, - key_version=version or "", - key_ops=key_operations, - tags=tags, - key_attributes=attributes, - error_map={404: ResourceNotFoundError}, - **kwargs - ) - return Key._from_key_bundle(bundle) - - @distributed_trace - def backup_key(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> bytes - """Backs up the specified key. - - Requests that a backup of the specified secret be downloaded to the client. - The Key Backup operation exports a key from Azure Key Vault in a - protected form. Note that this operation does NOT return key material - in a form that can be used outside the Azure Key Vault system, the - returned key material is either protected to a Azure Key Vault HSM or - to Azure Key Vault itself. The intent of this operation is to allow a - client to GENERATE a key in one Azure Key Vault instance, BACKUP the - key, and then RESTORE it into another Azure Key Vault instance. The - BACKUP operation may be used to export, in protected form, any key type - from Azure Key Vault. Individual versions of a key cannot be backed up. - BACKUP / RESTORE can be performed within geographical boundaries only; - meaning that a BACKUP from one geographical area cannot be restored to - another geographical area. For example, a backup from the US - geographical area cannot be restored in an EU geographical area. This - operation requires the key/backup permission. - - :param name: The name of the key. - :type name: str - :returns: The raw bytes of the key backup. - :rtype: bytes - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START backup_key] - :end-before: [END backup_key] - :language: python - :caption: Backs up the specified key to the key vault - :dedent: 8 - """ - backup_result = self._client.backup_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) - return backup_result.value - - @distributed_trace - def restore_key(self, backup, **kwargs): - # type: (bytes, Mapping[str, Any]) -> Key - """Restores a backed up key to the Key Vault - - Imports a previously backed up key into Azure Key Vault, restoring the - key, its key identifier, attributes and access control policies. The - RESTORE operation may be used to import a previously backed up key. - Individual versions of a key cannot be restored. The key is restored in - its entirety with the same key name as it had when it was backed up. If - the key name is not available in the target Key Vault, the RESTORE - operation will be rejected. While the key name is retained during - restore, the final key identifier will change if the key is restored to - a different vault. Restore will restore all versions and preserve - version identifiers. The RESTORE operation is subject to security - constraints: The target Key Vault must be owned by the same Microsoft - Azure Subscription as the source Key Vault The user must have RESTORE - permission in the target Key Vault. This operation requires the - keys/restore permission. - - :param backup: The raw bytes of the key backup - :type backup: bytes - :returns: The restored key - :rtype: ~azure.keyvault.keys._models.Key - :raises: ~azure.core.exceptions.ResourceExistsError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys.py - :start-after: [START restore_key] - :end-before: [END restore_key] - :language: python - :caption: Restores a backed up key to the vault - :dedent: 8 - """ - bundle = self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) - return Key._from_key_bundle(bundle) - - @distributed_trace - def import_key(self, name, key, hsm=None, enabled=None, not_before=None, expires=None, tags=None, **kwargs): - # type: (str, List[str], Optional[bool], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key - """Imports an externally created key, stores it, and returns the key to the client. - - The import key operation may be used to import any key type into an - Azure Key Vault. If the named key already exists, Azure Key Vault - creates a new version of the key. This operation requires the - keys/import permission. - - :param name: Name for the imported key. - :type name: str - :param key: The Json web key - :type key: ~azure.security.keyvault.v7_0.models.JsonWebKey - :param hsm: Whether to import as a hardware key (HSM) or software key. - :type hsm: bool - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The imported key - :rtype: ~azure.keyvault.keys._models.Key - - """ - if enabled is not None or not_before is not None or expires is not None: - attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) - else: - attributes = None - bundle = self._client.import_key( - self.vault_url, name, key=key, hsm=hsm, key_attributes=attributes, tags=tags, **kwargs - ) - return Key._from_key_bundle(bundle) - - @distributed_trace - def wrap_key(self, name, algorithm, value, version=None, **kwargs): - # type: (str, str, Optional[str], bytes, Mapping[str, Any]) -> KeyOperationResult - """Wraps a symmetric key using a specified key. - - The WRAP operation supports encryption of a symmetric key using a key - encryption key that has previously been stored in an Azure Key Vault. - The WRAP operation is only strictly necessary for symmetric keys stored - in Azure Key Vault since protection with an asymmetric key can be - performed using the public portion of the key. This operation is - supported for asymmetric keys as a convenience for callers that have a - key-reference but do not have access to the public key material. This - operation requires the keys/wrapKey permission. - - :param name: The name of the key. - :type name: str - :param version: The version of the key. - :type version: str - :param algorithm: algorithm identifier. Possible values include: - 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' - :type algorithm: str or - ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm - :param value: - :type value: bytes - :returns: The wrapped symmetric key. - :rtype: ~azure.keyvault.keys._models.KeyOperationResult - - """ - if version is None: - version = "" - - bundle = self._client.wrap_key( - self.vault_url, name, key_version=version, algorithm=algorithm, value=value, **kwargs - ) - return KeyOperationResult(id=bundle.kid, value=bundle.result) - - @distributed_trace - def unwrap_key(self, name, algorithm, value, version=None, **kwargs): - # type: (str, str, Optional[str], bytes, Mapping[str, Any]) -> KeyOperationResult - """Unwraps a symmetric key using the specified key that was initially used - for wrapping that key. - - The UNWRAP operation supports decryption of a symmetric key using the - target key encryption key. This operation is the reverse of the WRAP - operation. The UNWRAP operation applies to asymmetric and symmetric - keys stored in Azure Key Vault since it uses the private portion of the - key. This operation requires the keys/unwrapKey permission. - - :param name: The name of the key. - :type name: str - :param version: The version of the key. - :type version: str - :param algorithm: algorithm identifier. Possible values include: - 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' - :type algorithm: str or - ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm - :param value: - :type value: bytes - :returns: The unwrapped symmetric key. - :rtype: ~azure.keyvault.keys._models.KeyOperationResult - - """ - if version is None: - version = "" - - bundle = self._client.unwrap_key( - self.vault_url, name, key_version=version, algorithm=algorithm, value=value, **kwargs - ) - return KeyOperationResult(id=bundle.kid, value=bundle.result) diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/version.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_version.py similarity index 100% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/version.py rename to sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_version.py diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/__init__.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/__init__.py index 71cad7e66b18..8eb2ef0f7ef4 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/__init__.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/__init__.py @@ -2,6 +2,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from ._client import KeyClient +from .client import KeyClient __all__ = ["KeyClient"] diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/_client.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py similarity index 50% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/_client.py rename to sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py index 28bccc61f053..390bd77a6602 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/_client.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py @@ -8,57 +8,24 @@ from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async -from azure.keyvault.keys._models import Key, DeletedKey, KeyBase, KeyOperationResult +from azure.keyvault.keys.models import DeletedKey, JsonWebKey, Key, KeyBase, KeyOperationResult from azure.keyvault.keys._shared import AsyncKeyVaultClientBase class KeyClient(AsyncKeyVaultClientBase): - """The KeyClient class defines a high level interface for managing keys in the specified vault. + """A high-level interface for managing a vault's keys. Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START create_key_client] :end-before: [END create_key_client] :language: python - :caption: Creates a new instance of the Key client + :caption: Create a new ``KeyClient`` :dedent: 4 """ # pylint:disable=protected-access - @distributed_trace_async - async def get_key(self, name: str, version: Optional[str] = None, **kwargs: Mapping[str, Any]) -> Key: - """Gets the public part of a stored key. - - The get key operation is applicable to all key types. If the requested - key is symmetric, then no key material is released in the response. - This operation requires the keys/get permission. - - :param name: The name of the key to get. - :type name: str - :param version: Retrieves a specific version of a key. If the version is None or an empty string, - the latest version of the key is returned - :type version: str - :returns: Key - :rtype: ~azure.keyvault.keys._models.Key - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key - - Example: - .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START get_key] - :end-before: [END get_key] - :language: python - :caption: Retrieves a key from the key vault - :dedent: 8 - """ - if version is None: - version = "" - - bundle = await self._client.get_key( - self.vault_url, name, version, error_map={404: ResourceNotFoundError}, **kwargs - ) - return Key._from_key_bundle(bundle) - @distributed_trace_async async def create_key( self, @@ -73,47 +40,30 @@ async def create_key( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> Key: - """Creates a new key, stores it, then returns the key to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. + """Create a key. If ``name`` is already in use, create a new version of the key. Requires the keys/create + permission. - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param key_type: The type of key to create. For valid values, see - JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', - 'RSA-HSM', 'oct' - :param size: The key size in bits. For example: 2048, 3072, or - 4096 for RSA. - :type size: int - :param curve: Elliptic curve name. If none then defaults to 'P-256'. For valid values, see - JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', - 'P-521', 'SECP256K1' - :type curve: str or - :type key_type: str or ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyType - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] + :param str name: The name of the new key. Key Vault will generate the key's version. + :param key_type: The type of key to create + :type key_type: str or ~azure.keyvault.keys.enums.JsonWebKeyType + :param int size: (optional) RSA key size in bits, for example 2048, 3072, or 4096. + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :param curve: (optional) Elliptic curve name. Defaults to the NIST P-256 elliptic curve. + :type curve: ~azure.keyvault.keys.enums.JsonWebKeyCurveName or str :returns: The created key - :rtype: ~azure.keyvault.keys._models.Key + :rtype: ~azure.keyvault.keys.models.Key Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START create_key] :end-before: [END create_key] :language: python - :caption: Creates a key in the key vault + :caption: Create a key :dedent: 8 """ if enabled is not None or not_before is not None or expires is not None: @@ -147,41 +97,27 @@ async def create_rsa_key( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> Key: - """Creates a new RSA type key, stores it, then returns the key to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. - - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param hsm: Whether to import as a hardware key (HSM) or software key. - :type hsm: bool - :param size: The key size in bits. For example: 2048, 3072, or - 4096 for RSA. - :type size: int - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The created RSA key - :rtype: ~azure.keyvault.keys._models.Key + """Create a new RSA key. If ``name`` is already in use, create a new version of the key. Requires the + keys/create permission. + + :param str name: The name for the new key. Key Vault will generate the key's version. + :param bool hsm: Whether to create a hardware key (HSM) or software key + :param int size: (optional) Key size in bits, for example 2048, 3072, or 4096 + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The created key + :rtype: ~azure.keyvault.keys.models.Key Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START create_rsa_key] :end-before: [END create_rsa_key] :language: python - :caption: Creates an RSA key in the key vault + :caption: Create RSA key :dedent: 8 """ key_type = "RSA-HSM" if hsm else "RSA" @@ -211,43 +147,28 @@ async def create_ec_key( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> Key: - """Creates a new Elliptic curve type key, stores it, then returns key attributes to the client. - - The create key operation can be used to create any key type in Azure - Key Vault. If the named key already exists, Azure Key Vault creates a - new version of the key. It requires the keys/create permission. - - :param name: The name for the new key. The system will generate - the version name for the new key. - :type name: str - :param hsm: Whether to import as a hardware key (HSM) or software key. - :type hsm: bool - :param curve: Elliptic curve name. If none then defaults to 'P-256'. For valid values, see - JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', - 'P-521', 'SECP256K1' - :type curve: str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyCurveName - :param key_operations: Supported key operations. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The created EC key - :rtype: ~azure.keyvault.keys._models.Key + """Create a new elliptic curve key. If ``name`` is already in use, create a new version of the key. Requires + the keys/create permission. + + :param str name: The name for the new key. Key Vault will generate the key's version. + :param bool hsm: Whether to create as a hardware key (HSM) or software key. + :param curve: (optional) Elliptic curve name. Defaults to the NIST P-256 elliptic curve. + :type curve: ~azure.keyvault.keys.enums.JsonWebKeyCurveName or str + :param key_operations: (optional) Allowed key operations + :type key_operations: list(~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param datetime.datetime expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The created key + :rtype: ~azure.keyvault.keys.models.Key Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START create_ec_key] :end-before: [END create_ec_key] :language: python - :caption: Creates an EC key in the key vault + :caption: Create an elliptic curve key :dedent: 8 """ key_type = "EC-HSM" if hsm else "EC" @@ -265,92 +186,110 @@ async def create_ec_key( ) @distributed_trace_async - async def update_key( - self, - name: str, - version: Optional[str] = None, - key_operations: Optional[List[str]] = None, - enabled: Optional[bool] = None, - not_before: Optional[datetime] = None, - expires: Optional[datetime] = None, - tags: Optional[Dict[str, str]] = None, - **kwargs: Mapping[str, Any] - ) -> Key: - """The update key operation changes specified attributes of a stored key - and can be applied to any key type and key version stored in Azure Key - Vault. + async def delete_key(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedKey: + """Delete all versions of a key and its cryptographic material. Requires the keys/delete permission. - In order to perform this operation, the key must already exist in the - Key Vault. Note: The cryptographic material of a key itself cannot be - changed. This operation requires the keys/update permission. + :param str name: The name of the key to delete. + :returns: The deleted key + :rtype: ~azure.keyvault.keys.models.DeletedKey + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist - :param name: The name of key to update. - :type name: str - :param version: The version of the key to update. - :type version: str - :param key_operations: Json web key operations. For more information on - possible key operations, see JsonWebKeyOperation. - :type key_operations: list[str or - ~azure.keyvault.keys._generated.v7_0.models.JsonWebKeyOperation] - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] - :returns: The updated key - :rtype: ~azure.security.keyvault.v7_0.models.Key - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key + Example: + .. literalinclude:: ../tests/test_samples_keys_async.py + :start-after: [START delete_key] + :end-before: [END delete_key] + :language: python + :caption: Delete a key + :dedent: 8 + """ + bundle = await self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + return DeletedKey._from_deleted_key_bundle(bundle) + + @distributed_trace_async + async def get_key(self, name: str, version: Optional[str] = None, **kwargs: Mapping[str, Any]) -> Key: + """Get a key's attributes and, if it's an asymmetric key, its public material. Requires the keys/get permission. + + :param str name: The name of the key to get. + :param str version: (optional) A specific version of the key to get. If not specified, gets the latest version + of the key. + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist Example: .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START update_key] - :end-before: [END update_key] + :start-after: [START get_key] + :end-before: [END get_key] :language: python - :caption: Updates a key in the key vault + :caption: Get a key :dedent: 8 """ - if enabled is not None or not_before is not None or expires is not None: - attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) - else: - attributes = None + if version is None: + version = "" - bundle = await self._client.update_key( - self.vault_url, - name, - key_version=version or "", - key_ops=key_operations, - tags=tags, - key_attributes=attributes, - error_map={404: ResourceNotFoundError}, - **kwargs, + bundle = await self._client.get_key( + self.vault_url, name, version, error_map={404: ResourceNotFoundError}, **kwargs ) return Key._from_key_bundle(bundle) + @distributed_trace_async + async def get_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedKey: + """Get a deleted key. This is only possible in a vault with soft-delete enabled. Requires the keys/get + permission. + + :param str name: The name of the key + :returns: The deleted key + :rtype: ~azure.keyvault.keys.models.DeletedKey + + Example: + .. literalinclude:: ../tests/test_samples_keys_async.py + :start-after: [START get_deleted_key] + :end-before: [END get_deleted_key] + :language: python + :caption: Get a deleted key + :dedent: 8 + """ + bundle = await self._client.get_deleted_key( + self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs + ) + return DeletedKey._from_deleted_key_bundle(bundle) + @distributed_trace - def list_keys(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[KeyBase]: - """List keys in the specified vault. + def list_deleted_keys(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[DeletedKey]: + """List all deleted keys, including the public part of each. This is only possible in a vault with soft-delete + enabled. Requires the keys/list permission. + + :returns: An iterator of deleted keys + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.keys.models.DeletedKey] + + Example: + .. literalinclude:: ../tests/test_samples_keys_async.py + :start-after: [START list_deleted_keys] + :end-before: [END list_deleted_keys] + :language: python + :caption: List all the deleted keys + :dedent: 8 + """ + max_results = kwargs.get("max_page_size") + return self._client.get_deleted_keys( + self.vault_url, + maxresults=max_results, + cls=lambda objs: [DeletedKey._from_deleted_key_item(x) for x in objs], + **kwargs + ) - Retrieves a list of the keys in the Key Vault as JSON Web Key - structures that contain the public part of a stored key. The LIST - operation is applicable to all key types, however only the base key - identifier, attributes, and tags are provided in the response. - Individual versions of a key are not listed in the response. This - operation requires the keys/list permission. + @distributed_trace + def list_keys(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[KeyBase]: + """List identifiers, attributes, and tags of all keys in the vault. Requires the keys/list permission. - :returns: An iterator like instance of KeyBase - :rtype: - typing.AsyncIterable[~azure.keyvault.keys._models.KeyBase] + :returns: An iterator of keys without their cryptographic material or version information + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.keys.models.KeyBase] Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START list_keys] :end-before: [END list_keys] :language: python - :caption: List all keys in the vault + :caption: List all keys :dedent: 8 """ max_results = kwargs.get("max_page_size") @@ -363,23 +302,18 @@ def list_keys(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[KeyBase]: @distributed_trace def list_key_versions(self, name: str, **kwargs: Mapping[str, Any]) -> AsyncIterable[KeyBase]: - """Retrieves a list of individual key versions with the same key name. - - The full key identifier, attributes, and tags are provided in the - response. This operation requires the keys/list permission. + """List the identifiers, attributes, and tags of a key's versions. Requires the keys/list permission. - :param name: The name of the key. - :type name: str - :returns: An iterator like instance of KeyBase - :rtype: - typing.AsyncIterable[~azure.keyvault.keys._models.KeyBase] + :param str name: The name of the key + :returns: An iterator of keys without their cryptographic material + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.keys.models.KeyBase] Example: .. literalinclude:: ../tests/test_samples_keys_async.py :start-after: [START list_key_versions] :end-before: [END list_key_versions] :language: python - :caption: List all versions of the specified key + :caption: List all versions of a key :dedent: 8 """ max_results = kwargs.get("max_page_size") @@ -392,222 +326,155 @@ def list_key_versions(self, name: str, **kwargs: Mapping[str, Any]) -> AsyncIter ) @distributed_trace_async - async def backup_key(self, name: str, **kwargs: Mapping[str, Any]) -> bytes: - """Requests a backup of the specified key to the client. - - The Key Backup operation exports a key from Azure Key Vault in a - protected form. Note that this operation does NOT return key material - in a form that can be used outside the Azure Key Vault system, the - returned key material is either protected to a Azure Key Vault HSM or - to Azure Key Vault itself. The intent of this operation is to allow a - client to GENERATE a key in one Azure Key Vault instance, BACKUP the - key, and then RESTORE it into another Azure Key Vault instance. The - BACKUP operation may be used to export, in protected form, any key type - from Azure Key Vault. Individual versions of a key cannot be backed up. - BACKUP / RESTORE can be performed within geographical boundaries only; - meaning that a BACKUP from one geographical area cannot be restored to - another geographical area. For example, a backup from the US - geographical area cannot be restored in an EU geographical area. This - operation requires the key/backup permission. + async def purge_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> None: + """Permanently delete the specified key. This is only possible in vaults with soft-delete enabled. If a vault + does not have soft-delete enabled, :func:`delete_key` is permanent, and this method will return an error. - :param name: The name of the key. - :type name: str - :return: The raw bytes of the key backup. - :rtype: bytes - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key + Requires the keys/purge permission. + + :param str name: The name of the key + :returns: None Example: - .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START backup_key] - :end-before: [END backup_key] - :language: python - :caption: Backs up the specified key to the key vault - :dedent: 8 - """ - backup_result = await self._client.backup_key( - self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs - ) - return backup_result.value + .. code-block:: python - @distributed_trace_async - async def restore_key(self, backup: bytes, **kwargs: Mapping[str, Any]) -> Key: - """Restores a backed up key to a vault. - - Imports a previously backed up key into Azure Key Vault, restoring the - key, its key identifier, attributes and access control policies. The - RESTORE operation may be used to import a previously backed up key. - Individual versions of a key cannot be restored. The key is restored in - its entirety with the same key name as it had when it was backed up. If - the key name is not available in the target Key Vault, the RESTORE - operation will be rejected. While the key name is retained during - restore, the final key identifier will change if the key is restored to - a different vault. Restore will restore all versions and preserve - version identifiers. The RESTORE operation is subject to security - constraints: The target Key Vault must be owned by the same Microsoft - Azure Subscription as the source Key Vault The user must have RESTORE - permission in the target Key Vault. This operation requires the - keys/restore permission. - - :param backup: The raw bytes of the key backup - :type backup: bytes - :returns: The restored key - :rtype: ~azure.keyvault.keys._models.Key - :raises: ~azure.core.exceptions.ResourceExistsError if the client failed to retrieve the key + # if the vault has soft-delete enabled, purge permanently deletes a deleted key + # (with soft-delete disabled, delete_key is permanent) + await key_client.purge_deleted_key("key-name") - Example: - .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START restore_key] - :end-before: [END restore_key] - :language: python - :caption: Restores a backed up key to the vault - :dedent: 8 """ - bundle = await self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) - return Key._from_key_bundle(bundle) + await self._client.purge_deleted_key(self.vault_url, name, **kwargs) @distributed_trace_async - async def delete_key(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedKey: - """Deletes a key from the Key Vault. + async def recover_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> Key: + """Recover a deleted key to its latest version. This is only possible in vaults with soft-delete enabled. If a + vault does not have soft-delete enabled, :func:`delete_key` is permanent, and this method will return an error. + Attempting to recover an non-deleted key will also return an error. - The delete key operation cannot be used to remove individual versions - of a key. This operation removes the cryptographic material associated - with the key, which means the key is not usable for Sign/Verify, - Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the - keys/delete permission. + Requires the keys/recover permission. - :param name: The name of the key to delete. - :type name: str - :returns: The deleted key - :rtype: ~azure.keyvault.keys._models.DeletedKey - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to delete the key + :param str name: The name of the deleted key + :returns: The recovered key + :rtype: ~azure.keyvault.keys.models.Key Example: .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START delete_key] - :end-before: [END delete_key] + :start-after: [START recover_deleted_key] + :end-before: [END recover_deleted_key] :language: python - :caption: Deletes a key in the key vault + :caption: Recover a deleted key :dedent: 8 """ - bundle = await self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) - return DeletedKey._from_deleted_key_bundle(bundle) + bundle = await self._client.recover_deleted_key(self.vault_url, name, **kwargs) + return Key._from_key_bundle(bundle) @distributed_trace_async - async def get_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedKey: - """Gets a deleted key from the Key Vault - - The Get Deleted Key operation is applicable for soft-delete enabled - vaults. While the operation can be invoked on any vault, it will return - an error if invoked on a non soft-delete enabled vault. This operation - requires the keys/get permission. + async def update_key( + self, + name: str, + version: Optional[str] = None, + key_operations: Optional[List[str]] = None, + enabled: Optional[bool] = None, + not_before: Optional[datetime] = None, + expires: Optional[datetime] = None, + tags: Optional[Dict[str, str]] = None, + **kwargs: Mapping[str, Any] + ) -> Key: + """Change attributes of a key. Cannot change a key's cryptographic material. Requires the keys/update + permission. - :param name: The name of the key. - :type name: str - :returns: The deleted key - :rtype: ~azure.keyvault.keys._models.DeletedKey - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the key + :param str name: The name of key to update + :param str version: (optional) The version of the key to update + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param datetime.datetime expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The updated key + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist Example: .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START get_deleted_key] - :end-before: [END get_deleted_key] + :start-after: [START update_key] + :end-before: [END update_key] :language: python - :caption: Retrieves a deleted key from the key vault + :caption: Update a key's attributes :dedent: 8 """ - bundle = await self._client.get_deleted_key( - self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs + if enabled is not None or not_before is not None or expires is not None: + attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) + else: + attributes = None + + bundle = await self._client.update_key( + self.vault_url, + name, + key_version=version or "", + key_ops=key_operations, + tags=tags, + key_attributes=attributes, + error_map={404: ResourceNotFoundError}, + **kwargs, ) - return DeletedKey._from_deleted_key_bundle(bundle) + return Key._from_key_bundle(bundle) - @distributed_trace - def list_deleted_keys(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[DeletedKey]: - """Lists the deleted keys in the specified vault. + @distributed_trace_async + async def backup_key(self, name: str, **kwargs: Mapping[str, Any]) -> bytes: + """Back up a key in a protected form that can't be used outside Azure Key Vault. This is intended to allow + copying a key from one vault to another. Requires the key/backup permission. - Retrieves a list of the keys in the Key Vault as JSON Web Key - structures that contain the public part of a deleted key. This - operation includes deletion-specific information. The Get Deleted Keys - operation is applicable for vaults enabled for soft-delete. While the - operation can be invoked on any vault, it will return an error if - invoked on a non soft-delete enabled vault. This operation requires the - keys/list permission. + Backup / restore cannot be performed across geopolitical boundaries. For example, a backup from a vault in a + USA region cannot be restored to a vault in an EU region. - :returns: An iterator like instance of DeletedKey - :rtype: - typing.AsyncIterable[~azure.keyvault.keys._models.DeletedKey] + :param str name: The name of the key + :returns: The raw bytes of the key backup + :rtype: bytes + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist Example: .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START list_deleted_keys] - :end-before: [END list_deleted_keys] + :start-after: [START backup_key] + :end-before: [END backup_key] :language: python - :caption: List all the deleted keys in the vault + :caption: Get a key backup :dedent: 8 """ - max_results = kwargs.get("max_page_size") - return self._client.get_deleted_keys( - self.vault_url, - maxresults=max_results, - cls=lambda objs: [DeletedKey._from_deleted_key_item(x) for x in objs], - **kwargs + backup_result = await self._client.backup_key( + self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs ) + return backup_result.value @distributed_trace_async - async def purge_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> None: - """Permanently deletes the specified key. - - The Purge Deleted Key operation is applicable for soft-delete enabled - vaults. While the operation can be invoked on any vault, it will return - an error if invoked on a non soft-delete enabled vault. This operation - requires the keys/purge permission. - - :param name: The name of the key - :type name: str - :returns: None - :rtype: None - - Example: - .. code-block:: python - - # if the vault has soft-delete enabled, purge permanently deletes a deleted key - # (with soft-delete disabled, delete itself is permanent) - await key_client.purge_deleted_key("key-name") - - """ - await self._client.purge_deleted_key(self.vault_url, name, **kwargs) - - @distributed_trace_async - async def recover_deleted_key(self, name: str, **kwargs: Mapping[str, Any]) -> Key: - """Recovers the deleted key to its latest version. + async def restore_key(self, backup: bytes, **kwargs: Mapping[str, Any]) -> Key: + """Restore a key backup to the vault. This imports all versions of the key, with its name, attributes, and + access control policies. Requires the keys/restore permission. - The Recover Deleted Key operation is applicable for deleted keys in - soft-delete enabled vaults. It recovers the deleted key back to its - latest version under /keys. An attempt to recover an non-deleted key - will return an error. Consider this the inverse of the delete operation - on soft-delete enabled vaults. This operation requires the keys/recover - permission. + If the backed up key's name is already in use in the target vault, restoring it will fail. Also, the target + vault must be owned by the same Microsoft Azure subscription as the source vault. - :param name: The name of the deleted key. - :type name: str - :returns: The recovered deleted key - :rtype: ~azure.keyvault.keys._models.Key + :param bytes backup: The raw bytes of the key backup + :returns: The restored key + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceExistsError if the backed up key's name is already in use Example: .. literalinclude:: ../tests/test_samples_keys_async.py - :start-after: [START recover_deleted_key] - :end-before: [END recover_deleted_key] + :start-after: [START restore_key] + :end-before: [END restore_key] :language: python - :caption: Recovers the specified soft-deleted key + :caption: Restore a key backup :dedent: 8 """ - bundle = await self._client.recover_deleted_key(self.vault_url, name, **kwargs) + bundle = await self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace_async async def import_key( self, name: str, - key: List[str], + key: JsonWebKey, hsm: Optional[bool] = None, enabled: Optional[bool] = None, not_before: Optional[datetime] = None, @@ -615,30 +482,19 @@ async def import_key( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> Key: - """Imports an externally created key, stores it, and returns the key to the client. - - The import key operation may be used to import any key type into an - Azure Key Vault. If the named key already exists, Azure Key Vault - creates a new version of the key. This operation requires the - keys/import permission. - - :param name: Name for the imported key. - :type name: str - :param key: The Json web key - :type key: ~azure.security.keyvault.v7_0.models.JsonWebKey - :param hsm: Whether to import as a hardware key (HSM) or software key. - :type hsm: bool - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param expires: Expiry date of the key in UTC. - :type expires: datetime.datetime - :param not_before: Not before date of the key in UTC - :type not_before: datetime.datetime - :param tags: Application specific metadata in the form of key-value - pairs. - :type tags: Dict[str, str] + """Import an externally created key. If ``name`` is already in use, import the key as a new version. Requires + the keys/import permission. + + :param str name: Name for the imported key + :param key: The JSON web key to import + :type key: ~azure.keyvault.keys.models.JsonWebKey + :param bool hsm: (optional) Whether to import as a hardware key (HSM) or software key + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The imported key - :rtype: ~azure.keyvault.keys._models.Key + :rtype: ~azure.keyvault.keys.models.Key """ if enabled is not None or not_before is not None or expires is not None: @@ -672,7 +528,7 @@ async def wrap_key( :param algorithm: algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' :type algorithm: str or - ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm + ~azure.keyvault.keys.models.JsonWebKeyEncryptionAlgorithm :param value: :type value: bytes :returns: The wrapped symmetric key. @@ -707,7 +563,7 @@ async def unwrap_key( :param algorithm: algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' :type algorithm: str or - ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm + ~azure.keyvault.keys.models.JsonWebKeyEncryptionAlgorithm :param value: :type value: bytes :returns: The unwrapped symmetric key. diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py new file mode 100644 index 000000000000..dd5854d00533 --- /dev/null +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py @@ -0,0 +1,574 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +from datetime import datetime + +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False + +if TYPE_CHECKING: + # pylint:disable=unused-import + from typing import Any, Dict, Mapping, Optional + from azure.core.paging import ItemPaged + from .models import JsonWebKey + +from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError +from azure.core.tracing.decorator import distributed_trace + +from ._shared import KeyVaultClientBase +from .models import Key, KeyBase, DeletedKey, KeyOperationResult + + +class KeyClient(KeyVaultClientBase): + """A high-level interface for managing a vault's keys. + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START create_key_client] + :end-before: [END create_key_client] + :language: python + :caption: Create a new ``KeyClient`` + :dedent: 4 + """ + + # pylint:disable=protected-access + + @distributed_trace + def create_key( + self, + name, + key_type, + size=None, + key_operations=None, + enabled=None, + expires=None, + not_before=None, + tags=None, + curve=None, + **kwargs + ): + # type: (str, str, Optional[int], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Optional[str], Mapping[str, Any]) -> Key + """Create a key. If ``name`` is already in use, create a new version of the key. Requires the keys/create + permission. + + :param str name: The name of the new key. Key Vault will generate the key's version. + :param key_type: The type of key to create + :type key_type: str or ~azure.keyvault.keys.enums.JsonWebKeyType + :param int size: (optional) RSA key size in bits, for example 2048, 3072, or 4096. + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :param curve: (optional) Elliptic curve name. Defaults to the NIST P-256 elliptic curve. + :type curve: ~azure.keyvault.keys.enums.JsonWebKeyCurveName or str + :returns: The created key + :rtype: ~azure.keyvault.keys.models.Key + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START create_key] + :end-before: [END create_key] + :language: python + :caption: Create a key + :dedent: 8 + """ + if enabled is not None or not_before is not None or expires is not None: + attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) + else: + attributes = None + + bundle = self._client.create_key( + self.vault_url, + name, + key_type, + size, + key_attributes=attributes, + key_ops=key_operations, + tags=tags, + curve=curve, + **kwargs + ) + return Key._from_key_bundle(bundle) + + @distributed_trace + def create_rsa_key( + self, + name, + hsm, + size=None, + key_operations=None, + enabled=None, + expires=None, + not_before=None, + tags=None, + **kwargs + ): + # type: (str, bool, Optional[int], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key + """Create a new RSA key. If ``name`` is already in use, create a new version of the key. Requires the + keys/create permission. + + :param str name: The name for the new key. Key Vault will generate the key's version. + :param bool hsm: Whether to create a hardware key (HSM) or software key + :param int size: (optional) Key size in bits, for example 2048, 3072, or 4096 + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The created key + :rtype: ~azure.keyvault.keys.models.Key + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START create_rsa_key] + :end-before: [END create_rsa_key] + :language: python + :caption: Create RSA key + :dedent: 8 + """ + key_type = "RSA-HSM" if hsm else "RSA" + + return self.create_key( + name, + key_type=key_type, + size=size, + key_operations=key_operations, + enabled=enabled, + expires=expires, + not_before=not_before, + tags=tags, + **kwargs + ) + + @distributed_trace + def create_ec_key( + self, + name, + hsm, + curve=None, + key_operations=None, + enabled=None, + expires=None, + not_before=None, + tags=None, + **kwargs + ): + # type: (str, bool, Optional[str], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key + """Create a new elliptic curve key. If ``name`` is already in use, create a new version of the key. Requires + the keys/create permission. + + :param str name: The name for the new key. Key Vault will generate the key's version. + :param bool hsm: Whether to create as a hardware key (HSM) or software key. + :param curve: (optional) Elliptic curve name. Defaults to the NIST P-256 elliptic curve. + :type curve: ~azure.keyvault.keys.enums.JsonWebKeyCurveName or str + :param key_operations: (optional) Allowed key operations + :type key_operations: list(~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param datetime.datetime expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The created key + :rtype: ~azure.keyvault.keys.models.Key + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START create_ec_key] + :end-before: [END create_ec_key] + :language: python + :caption: Create an elliptic curve key + :dedent: 8 + """ + + key_type = "EC-HSM" if hsm else "EC" + + return self.create_key( + name, + key_type=key_type, + curve=curve, + key_operations=key_operations, + enabled=enabled, + expires=expires, + not_before=not_before, + tags=tags, + **kwargs + ) + + @distributed_trace + def delete_key(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> DeletedKey + """Delete all versions of a key and its cryptographic material. Requires the keys/delete permission. + + :param str name: The name of the key to delete. + :returns: The deleted key + :rtype: ~azure.keyvault.keys.models.DeletedKey + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START delete_key] + :end-before: [END delete_key] + :language: python + :caption: Delete a key + :dedent: 8 + """ + bundle = self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + return DeletedKey._from_deleted_key_bundle(bundle) + + @distributed_trace + def get_key(self, name, version=None, **kwargs): + # type: (str, Optional[str], Mapping[str, Any]) -> Key + """Get a key's attributes and, if it's an asymmetric key, its public material. Requires the keys/get permission. + + :param str name: The name of the key to get. + :param str version: (optional) A specific version of the key to get. If not specified, gets the latest version + of the key. + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START get_key] + :end-before: [END get_key] + :language: python + :caption: Get a key + :dedent: 8 + """ + bundle = self._client.get_key( + self.vault_url, name, key_version=version or "", error_map={404: ResourceNotFoundError}, **kwargs + ) + return Key._from_key_bundle(bundle) + + @distributed_trace + def get_deleted_key(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> DeletedKey + """Get a deleted key. This is only possible in a vault with soft-delete enabled. Requires the keys/get + permission. + + :param str name: The name of the key + :returns: The deleted key + :rtype: ~azure.keyvault.keys.models.DeletedKey + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START get_deleted_key] + :end-before: [END get_deleted_key] + :language: python + :caption: Get a deleted key + :dedent: 8 + """ + # TODO: which exception is raised when soft-delete is not enabled + bundle = self._client.get_deleted_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + return DeletedKey._from_deleted_key_bundle(bundle) + + @distributed_trace + def list_deleted_keys(self, **kwargs): + # type: (Mapping[str, Any]) -> ItemPaged[DeletedKey] + """List all deleted keys, including the public part of each. This is only possible in a vault with soft-delete + enabled. Requires the keys/list permission. + + :returns: An iterator of deleted keys + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.keys.models.DeletedKey] + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START list_deleted_keys] + :end-before: [END list_deleted_keys] + :language: python + :caption: List all the deleted keys + :dedent: 8 + """ + max_page_size = kwargs.get("max_page_size", None) + return self._client.get_deleted_keys( + self._vault_url, + maxresults=max_page_size, + cls=lambda objs: [DeletedKey._from_deleted_key_item(x) for x in objs], + **kwargs + ) + + @distributed_trace + def list_keys(self, **kwargs): + # type: (Mapping[str, Any]) -> ItemPaged[KeyBase] + """List identifiers, attributes, and tags of all keys in the vault. Requires the keys/list permission. + + :returns: An iterator of keys without their cryptographic material or version information + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.keys.models.KeyBase] + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START list_keys] + :end-before: [END list_keys] + :language: python + :caption: List all keys + :dedent: 8 + """ + max_page_size = kwargs.get("max_page_size", None) + return self._client.get_keys( + self._vault_url, + maxresults=max_page_size, + cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], + **kwargs + ) + + @distributed_trace + def list_key_versions(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> ItemPaged[KeyBase] + """List the identifiers, attributes, and tags of a key's versions. Requires the keys/list permission. + + :param str name: The name of the key + :returns: An iterator of keys without their cryptographic material + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.keys.models.KeyBase] + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START list_key_versions] + :end-before: [END list_key_versions] + :language: python + :caption: List all versions of a key + :dedent: 8 + """ + max_page_size = kwargs.get("max_page_size", None) + return self._client.get_key_versions( + self._vault_url, + name, + maxresults=max_page_size, + cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], + **kwargs + ) + + @distributed_trace + def purge_deleted_key(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> None + """Permanently delete the specified key. This is only possible in vaults with soft-delete enabled. If a vault + does not have soft-delete enabled, :func:`delete_key` is permanent, and this method will return an error. + + Requires the keys/purge permission. + + :param str name: The name of the key + :returns: None + + Example: + .. code-block:: python + + # if the vault has soft-delete enabled, purge permanently deletes a deleted key + # (with soft-delete disabled, delete_key is permanent) + key_client.purge_deleted_key("key-name") + + """ + self._client.purge_deleted_key(self.vault_url, name, kwargs) + + @distributed_trace + def recover_deleted_key(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> Key + """Recover a deleted key to its latest version. This is only possible in vaults with soft-delete enabled. If a + vault does not have soft-delete enabled, :func:`delete_key` is permanent, and this method will return an error. + Attempting to recover an non-deleted key will also return an error. + + Requires the keys/recover permission. + + :param str name: The name of the deleted key + :returns: The recovered key + :rtype: ~azure.keyvault.keys.models.Key + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START recover_deleted_key] + :end-before: [END recover_deleted_key] + :language: python + :caption: Recover a deleted key + :dedent: 8 + """ + bundle = self._client.recover_deleted_key(self.vault_url, name, kwargs) + return Key._from_key_bundle(bundle) + + @distributed_trace + def update_key( + self, name, version=None, key_operations=None, enabled=None, expires=None, not_before=None, tags=None, **kwargs + ): + # type: (str, Optional[str], Optional[List[str]], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key + """Change attributes of a key. Cannot change a key's cryptographic material. Requires the keys/update + permission. + + :param str name: The name of key to update + :param str version: (optional) The version of the key to update + :param key_operations: (optional) Allowed key operations + :type key_operations: list(str or ~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bool enabled: (optional) Whether the key is enabled for use + :param datetime.datetime expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The updated key + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START update_key] + :end-before: [END update_key] + :language: python + :caption: Update a key's attributes + :dedent: 8 + """ + if enabled is not None or not_before is not None or expires is not None: + attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) + else: + attributes = None + bundle = self._client.update_key( + self.vault_url, + name, + key_version=version or "", + key_ops=key_operations, + tags=tags, + key_attributes=attributes, + error_map={404: ResourceNotFoundError}, + **kwargs + ) + return Key._from_key_bundle(bundle) + + @distributed_trace + def backup_key(self, name, **kwargs): + # type: (str, Mapping[str, Any]) -> bytes + """Back up a key in a protected form that can't be used outside Azure Key Vault. This is intended to allow + copying a key from one vault to another. Requires the key/backup permission. + + Backup / restore cannot be performed across geopolitical boundaries. For example, a backup from a vault in a + USA region cannot be restored to a vault in an EU region. + + :param str name: The name of the key + :returns: The raw bytes of the key backup + :rtype: bytes + :raises: ~azure.core.exceptions.ResourceNotFoundError if the key doesn't exist + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START backup_key] + :end-before: [END backup_key] + :language: python + :caption: Get a key backup + :dedent: 8 + """ + backup_result = self._client.backup_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + return backup_result.value + + @distributed_trace + def restore_key(self, backup, **kwargs): + # type: (bytes, Mapping[str, Any]) -> Key + """Restore a key backup to the vault. This imports all versions of the key, with its name, attributes, and + access control policies. Requires the keys/restore permission. + + If the backed up key's name is already in use in the target vault, restoring it will fail. Also, the target + vault must be owned by the same Microsoft Azure subscription as the source vault. + + :param bytes backup: The raw bytes of the key backup + :returns: The restored key + :rtype: ~azure.keyvault.keys.models.Key + :raises: ~azure.core.exceptions.ResourceExistsError if the backed up key's name is already in use + + Example: + .. literalinclude:: ../tests/test_samples_keys.py + :start-after: [START restore_key] + :end-before: [END restore_key] + :language: python + :caption: Restore a key backup + :dedent: 8 + """ + bundle = self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) + return Key._from_key_bundle(bundle) + + @distributed_trace + def import_key(self, name, key, hsm=None, enabled=None, not_before=None, expires=None, tags=None, **kwargs): + # type: (str, List[str], Optional[bool], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Key + """Import an externally created key. If ``name`` is already in use, import the key as a new version. Requires + the keys/import permission. + + :param str name: Name for the imported key + :param key: The JSON web key to import + :type key: ~azure.keyvault.keys.models.JsonWebKey + :param bool hsm: (optional) Whether to import as a hardware key (HSM) or software key + :param bool enabled: (optional) Whether the key is enabled for use + :param expires: (optional) Expiry date of the key in UTC + :param datetime.datetime not_before: (optional) Not before date of the key in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :returns: The imported key + :rtype: ~azure.keyvault.keys.models.Key + + """ + if enabled is not None or not_before is not None or expires is not None: + attributes = self._client.models.KeyAttributes(enabled=enabled, not_before=not_before, expires=expires) + else: + attributes = None + bundle = self._client.import_key( + self.vault_url, name, key=key, hsm=hsm, key_attributes=attributes, tags=tags, **kwargs + ) + return Key._from_key_bundle(bundle) + + @distributed_trace + def wrap_key(self, name, algorithm, value, version=None, **kwargs): + # type: (str, str, Optional[str], bytes, Mapping[str, Any]) -> KeyOperationResult + """Wraps a symmetric key using a specified key. + + The WRAP operation supports encryption of a symmetric key using a key + encryption key that has previously been stored in an Azure Key Vault. + The WRAP operation is only strictly necessary for symmetric keys stored + in Azure Key Vault since protection with an asymmetric key can be + performed using the public portion of the key. This operation is + supported for asymmetric keys as a convenience for callers that have a + key-reference but do not have access to the public key material. This + operation requires the keys/wrapKey permission. + + :param str name: The name of the key + :param str version: The version of the key. + :param algorithm: algorithm identifier. Possible values include: + 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' + :type algorithm: str or + ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm + :param value: + :type value: bytes + :returns: The wrapped symmetric key. + :rtype: ~azure.keyvault.keys.models.Key + + """ + if version is None: + version = "" + + bundle = self._client.wrap_key( + self.vault_url, name, key_version=version, algorithm=algorithm, value=value, **kwargs + ) + return KeyOperationResult(id=bundle.kid, value=bundle.result) + + @distributed_trace + def unwrap_key(self, name, algorithm, value, version=None, **kwargs): + # type: (str, str, Optional[str], bytes, Mapping[str, Any]) -> KeyOperationResult + """Unwraps a symmetric key using the specified key that was initially used + for wrapping that key. + + The UNWRAP operation supports decryption of a symmetric key using the + target key encryption key. This operation is the reverse of the WRAP + operation. The UNWRAP operation applies to asymmetric and symmetric + keys stored in Azure Key Vault since it uses the private portion of the + key. This operation requires the keys/unwrapKey permission. + + :param str name: The name of the key + :param str version: The version of the key. + :param algorithm: algorithm identifier. Possible values include: + 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5' + :type algorithm: str or + ~azure.security.keyvault.v7_0.models.JsonWebKeyEncryptionAlgorithm + :param value: + :type value: bytes + :returns: The unwrapped symmetric key. + :rtype: ~azure.keyvault.keys.models.Key + + """ + if version is None: + version = "" + + bundle = self._client.unwrap_key( + self.vault_url, name, key_version=version, algorithm=algorithm, value=value, **kwargs + ) + return KeyOperationResult(id=bundle.kid, value=bundle.result) diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/enums.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/enums.py new file mode 100644 index 000000000000..228e0a6d4095 --- /dev/null +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/enums.py @@ -0,0 +1,35 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +from enum import Enum + + +class JsonWebKeyCurveName(str, Enum): + """Supported elliptic curves""" + + p_256 = "P-256" #: The NIST P-256 elliptic curve, AKA SECG curve SECP256R1. + p_384 = "P-384" #: The NIST P-384 elliptic curve, AKA SECG curve SECP384R1. + p_521 = "P-521" #: The NIST P-521 elliptic curve, AKA SECG curve SECP521R1. + p_256_k = "P-256K" #: The SECG SECP256K1 elliptic curve. + + +class JsonWebKeyOperation(str, Enum): + """Supported key operations""" + + encrypt = "encrypt" + decrypt = "decrypt" + sign = "sign" + verify = "verify" + wrap_key = "wrapKey" + unwrap_key = "unwrapKey" + + +class JsonWebKeyType(str, Enum): + """Supported key types""" + + ec = "EC" #: Elliptic Curve + ec_hsm = "EC-HSM" #: Elliptic Curve with a private key which is not exportable from the HSM + rsa = "RSA" #: RSA (https://tools.ietf.org/html/rfc3447) + rsa_hsm = "RSA-HSM" #: RSA with a private key which is not exportable from the HSM + oct = "oct" #: Octet sequence (used to represent symmetric keys) diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/models.py similarity index 55% rename from sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py rename to sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/models.py index 19ceda29966a..4e1518db97ed 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_models.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/models.py @@ -2,7 +2,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------- -import datetime +from collections import namedtuple try: from typing import TYPE_CHECKING @@ -10,20 +10,66 @@ TYPE_CHECKING = False if TYPE_CHECKING: + # pylint:disable=unused-import + from datetime import datetime from typing import Any, Dict, Generator, Mapping, Optional + from ._shared._generated.v7_0 import models as _models -from collections import namedtuple from ._shared import parse_vault_id -from ._shared._generated.v7_0 import models KeyOperationResult = namedtuple("KeyOperationResult", ["id", "value"]) +class JsonWebKey(object): + """As of http://tools.ietf.org/html/draft-ietf-jose-json-web-key-18. All parameters are optional. + + :param str kid: Key identifier. + :param kty: Key Type (kty), as defined in https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 + :type kty: str or ~azure.keyvault.keys.enums.JsonWebKeyType + :param key_ops: Allowed operations for the key + :type key_ops: list(~azure.keyvault.keys.enums.JsonWebKeyOperation) + :param bytes n: RSA modulus. + :param bytes e: RSA public exponent. + :param bytes d: RSA private exponent, or the D component of an EC private key. + :param bytes dp: RSA private key parameter. + :param bytes dq: RSA private key parameter. + :param bytes qi: RSA private key parameter. + :param bytes p: RSA secret prime. + :param bytes q: RSA secret prime, with p < q. + :param bytes k: Symmetric key. + :param bytes t: HSM Token, used with 'Bring Your Own Key'. + :param crv: Elliptic curve name. + :type crv: str or ~azure.keyvault.keys.enums.JsonWebKeyCurveName + :param bytes x: X component of an EC public key. + :param bytes y: Y component of an EC public key. + """ + + def __init__(self, **kwargs): + # type: (Any) -> None + super(JsonWebKey, self).__init__(**kwargs) + self.kid = kwargs.get("kid", None) + self.kty = kwargs.get("kty", None) + self.key_ops = kwargs.get("key_ops", None) + self.n = kwargs.get("n", None) + self.e = kwargs.get("e", None) + self.d = kwargs.get("d", None) + self.dp = kwargs.get("dp", None) + self.dq = kwargs.get("dq", None) + self.qi = kwargs.get("qi", None) + self.p = kwargs.get("p", None) + self.q = kwargs.get("q", None) + self.k = kwargs.get("k", None) + self.t = kwargs.get("t", None) + self.crv = kwargs.get("crv", None) + self.x = kwargs.get("x", None) + self.y = kwargs.get("y", None) + + class KeyBase(object): """A key's id and attributes.""" def __init__(self, attributes, vault_id, **kwargs): - # type: (models.KeyAttributes, str, Mapping[str, Any]) -> None + # type: (_models.KeyAttributes, str, Mapping[str, Any]) -> None self._attributes = attributes self._id = vault_id self._vault_id = parse_vault_id(vault_id) @@ -32,106 +78,122 @@ def __init__(self, attributes, vault_id, **kwargs): @classmethod def _from_key_bundle(cls, key_bundle): - # type: (models.KeyBundle) -> KeyBase + # type: (_models.KeyBundle) -> KeyBase """Construct a KeyBase from an autorest-generated KeyBundle""" return cls(key_bundle.attributes, key_bundle.key.kid, managed=key_bundle.managed, tags=key_bundle.tags) @classmethod def _from_key_item(cls, key_item): - # type: (models.KeyItem) -> KeyBase + # type: (_models.KeyItem) -> KeyBase """Construct a KeyBase from an autorest-generated KeyItem""" return cls(key_item.attributes, key_item.kid, managed=key_item.managed, tags=key_item.tags) @property def id(self): # type: () -> str - """The key id - :rtype: str""" + """:rtype: str""" return self._id @property def name(self): # type: () -> str - """The name of the key - :rtype: str""" + """:rtype: str""" return self._vault_id.name @property def version(self): # type: () -> str - """The version of the key - :rtype: str""" + """:rtype: str""" return self._vault_id.version @property def enabled(self): # type: () -> bool - """The Key's 'enabled' attribute - :rtype: bool""" + """:rtype: bool""" return self._attributes.enabled @property def not_before(self): # type: () -> datetime - """The Key's not_before date in UTC - :rtype: datetime""" + """ + The key's not-before time, in UTC + + :rtype: datetime.datetime + """ return self._attributes.not_before @property def expires(self): # type: () -> datetime - """The Key's expiry date in UTC - :rtype: datetime""" + """ + When the key will expire, in UTC + + :rtype: datetime.datetime + """ return self._attributes.expires @property def created(self): # type: () -> datetime - """The Key's creation time in UTC - :rtype: datetime""" + """ + When the key was created, in UTC + + :rtype: datetime.datetime + """ return self._attributes.created @property def updated(self): # type: () -> datetime - """The Key's last updated time in UTC - :rtype: datetime""" + """ + When the key was last updated, in UTC + + :rtype: datetime.datetime + """ return self._attributes.updated @property def vault_url(self): # type: () -> str - """The url of the vault containing the key - :rtype: str""" + """ + URL of the vault containing the key + + :rtype: str + """ return self._vault_id.vault_url @property def recovery_level(self): # type: () -> str - """The vault's deletion recovery level for keys - :rtype: str""" + """ + The vault's deletion recovery level for keys + + :rtype: str + """ return self._attributes.recovery_level @property def tags(self): # type: () -> Dict[str, str] - """Application specific metadata in the form of key-value pairs. - :rtype: dict""" + """ + Application specific metadata in the form of key-value pairs + + :rtype: dict + """ return self._tags class Key(KeyBase): - """A key consisting of all KeyBase and key_material information. - """ + """A key's attributes and cryptographic material""" def __init__(self, attributes, vault_id, key_material, **kwargs): - # type: (models.KeyAttributes, str, models.JsonWebKey, Mapping[str, Any]) -> None + # type: (_models.KeyAttributes, str, _models.JsonWebKey, Mapping[str, Any]) -> None super(Key, self).__init__(attributes, vault_id, **kwargs) self._key_material = key_material @classmethod def _from_key_bundle(cls, key_bundle): - # type: (models.KeyBundle) -> Key + # type: (_models.KeyBundle) -> Key """Construct a Key from an autorest-generated KeyBundle""" return cls( attributes=key_bundle.attributes, @@ -143,15 +205,13 @@ def _from_key_bundle(cls, key_bundle): @property def key_material(self): - # type: () -> models.JsonWebKey - """The Json web key""" + # type: () -> _models.JsonWebKey + """The JSON web key""" return self._key_material class DeletedKey(Key): - """A Deleted key consisting of its id, attributes, and tags, as - well as when it will be purged, if soft-delete is enabled for the vault. - """ + """A deleted key's id, attributes, and cryptographic material, as well as when it will be purged""" def __init__( self, @@ -163,7 +223,7 @@ def __init__( scheduled_purge_date=None, **kwargs ): - # type: (models.KeyAttributes, str, models.JsonWebKey, Optional[datetime], Optional[str], Optional[datetime], Mapping[str, Any]) -> None + # type: (_models.KeyAttributes, str, _models.JsonWebKey, Optional[datetime], Optional[str], Optional[datetime], Mapping[str, Any]) -> None super(DeletedKey, self).__init__(attributes, vault_id, key_material, **kwargs) self._deleted_date = deleted_date self._recovery_id = recovery_id @@ -171,7 +231,7 @@ def __init__( @classmethod def _from_deleted_key_bundle(cls, deleted_key_bundle): - # type: (models.DeletedKeyBundle) -> DeletedKey + # type: (_models.DeletedKeyBundle) -> DeletedKey """Construct a DeletedKey from an autorest-generated DeletedKeyBundle""" return cls( attributes=deleted_key_bundle.attributes, @@ -186,7 +246,7 @@ def _from_deleted_key_bundle(cls, deleted_key_bundle): @classmethod def _from_deleted_key_item(cls, deleted_key_item): - # type: (models.DeletedKeyItem) -> DeletedKey + # type: (_models.DeletedKeyItem) -> DeletedKey """Construct a DeletedKey from an autorest-generated DeletedKeyItem""" return cls( attributes=deleted_key_item.attributes, @@ -201,20 +261,29 @@ def _from_deleted_key_item(cls, deleted_key_item): @property def deleted_date(self): # type: () -> datetime - """The time when the key was deleted, in UTC - :rtype: datetime""" + """ + When the key was deleted, in UTC + + :rtype: datetime.datetime + """ return self._deleted_date @property def recovery_id(self): # type: () -> str - """The url of the recovery object, used to identify and recover the deleted key - :rtype: str""" + """ + An identifier used to recover the deleted key + + :rtype: str + """ return self._recovery_id @property def scheduled_purge_date(self): # type: () -> datetime - """The time when the key is scheduled to be purged, in UTC - :rtype: datetime""" + """ + When the key is scheduled to be purged, in UTC + + :rtype: datetime.datetime + """ return self._scheduled_purge_date diff --git a/sdk/keyvault/azure-keyvault-keys/setup.py b/sdk/keyvault/azure-keyvault-keys/setup.py index 7ace5d61bfcd..0ae136fe914d 100644 --- a/sdk/keyvault/azure-keyvault-keys/setup.py +++ b/sdk/keyvault/azure-keyvault-keys/setup.py @@ -36,7 +36,7 @@ pass # Version extraction inspired from 'requests' -with open(os.path.join(PACKAGE_FOLDER_PATH, "version.py"), "r") as fd: +with open(os.path.join(PACKAGE_FOLDER_PATH, "_version.py"), "r") as fd: VERSION = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) if not VERSION: diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py index 44967833f2df..af10d9edd183 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/__init__.py @@ -2,6 +2,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from ._client import SecretClient +from .client import SecretClient __all__ = ["SecretClient"] diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/version.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_version.py similarity index 100% rename from sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/version.py rename to sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_version.py diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/__init__.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/__init__.py index 44967833f2df..af10d9edd183 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/__init__.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/__init__.py @@ -2,6 +2,6 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from ._client import SecretClient +from .client import SecretClient __all__ = ["SecretClient"] diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/_client.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py similarity index 56% rename from sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/_client.py rename to sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py index 9a4a92375ad9..2dbc6944adcc 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/_client.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py @@ -9,19 +9,19 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async -from azure.keyvault.secrets._models import Secret, DeletedSecret, SecretAttributes +from azure.keyvault.secrets.models import Secret, DeletedSecret, SecretAttributes from .._shared import AsyncKeyVaultClientBase class SecretClient(AsyncKeyVaultClientBase): - """SecretClient is a high-level interface for managing a vault's secrets. + """A high-level interface for managing a vault's secrets. Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START create_secret_client] :end-before: [END create_secret_client] :language: python - :caption: Creates a new instance of the Secret client + :caption: Create a new ``SecretClient`` :dedent: 4 """ @@ -29,24 +29,19 @@ class SecretClient(AsyncKeyVaultClientBase): @distributed_trace_async async def get_secret(self, name: str, version: Optional[str] = None, **kwargs: Mapping[str, Any]) -> Secret: - """Get a specified secret from the vault. + """Get a secret. Requires the secrets/get permission. - The GET operation is applicable to any secret stored in Azure Key - Vault. This operation requires the secrets/get permission. - - :param str name: The name of the secret. - :param str version: The version of the secret. If version is None or an empty string, the latest version of - the secret is returned. - :returns: An instance of Secret - :rtype: ~azure.keyvault.secrets._models.Secret - :raises: ~azure.core.exceptions.ResourceNotFoundError if client failed to retrieve the secret + :param str name: The name of the secret + :param str version: (optional) Version of the secret to get. If unspecified, gets the latest version. + :rtype: ~azure.keyvault.secrets.models.Secret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START get_secret] :end-before: [END get_secret] :language: python - :caption: Get secret from the key vault + :caption: Get a secret :dedent: 8 """ bundle = await self._client.get_secret( @@ -66,32 +61,24 @@ async def set_secret( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> Secret: - """Sets a secret in the vault. - - The SET operation adds a secret to the Azure Key Vault. If the named - secret already exists, Azure Key Vault creates a new version of that - secret. This operation requires the secrets/set permission. + """Set a secret value. Create a new secret if ``name`` is not in use. If it is, create a new version of the + secret. :param str name: The name of the secret :param str value: The value of the secret - :param str content_type: Type of the secret value such as a password - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param not_before: Not before date of the secret in UTC - :type not_before: datetime.datetime - :param expires: Expiry date of the secret in UTC. - :type expires: datetime.datetime - :param tags: Application specific metadata in the form of key-value pairs. - :type tags: dict(str, str) - :returns: The created secret - :rtype: ~azure.keyvault.secrets._models.Secret + :param str content_type: (optional) An arbitrary string indicating the type of the secret, e.g. 'password' + :param bool enabled: (optional) Whether the secret is enabled for use + :param datetime.datetime not_before: (optional) Not before date of the secret in UTC + :param datetime.datetime expires: (optional) Expiry date of the secret in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :rtype: ~azure.keyvault.secrets.models.Secret Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START set_secret] :end-before: [END set_secret] :language: python - :caption: Get secret from the key vault + :caption: Set a secret's value :dedent: 8 """ if enabled is not None or not_before is not None or expires is not None: @@ -115,33 +102,26 @@ async def update_secret( tags: Optional[Dict[str, str]] = None, **kwargs: Mapping[str, Any] ) -> SecretAttributes: - """Updates the attributes associated with a specified secret in the key vault. + """Update a secret's attributes, such as its tags or whether it's enabled. Requires the secrets/set permission. - The UPDATE operation changes specified attributes of an existing stored secret. - Attributes that are not specified in the request are left unchanged. The value - of a secret itself cannot be changed. This operation requires the secrets/set permission. + **This method can't change a secret's value.** Use :func:`set_secret` to change values. - :param str name: The name of the secret - :param str version: The version of the secret. - :param str content_type: Type of the secret value such as a password - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param not_before: Not before date of the secret in UTC - :type not_before: datetime.datetime - :param expires: Expiry date of the secret in UTC. - :type expires: datetime.datetime - :param tags: Application specific metadata in the form of key-value pairs. - :type tags: dict(str, str) - :returns: The created secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to retrieve the secret + :param str name: Name of the secret + :param str version: (optional) Version of the secret to update. If unspecified, the latest version is updated. + :param str content_type: (optional) An arbitrary string indicating the type of the secret, e.g. 'password' + :param bool enabled: (optional) Whether the secret is enabled for use + :param datetime.datetime not_before: (optional) Not before date of the secret in UTC + :param datetime.datetime expires: (optional) Expiry date of the secret in UTC. + :param dict(str, str) tags: (optional) Application specific metadata in the form of key-value pairs. + :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START update_secret] :end-before: [END update_secret] :language: python - :caption: Updates the attributes associated with a specified secret in the key vault + :caption: Updates a secret's attributes :dedent: 8 """ if enabled is not None or not_before is not None or expires is not None: @@ -162,23 +142,18 @@ async def update_secret( @distributed_trace def list_secrets(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[SecretAttributes]: - """List secrets in the vault. - - The Get Secrets operation is applicable to the entire vault. However, - only the latest secret identifier and its attributes are provided in the - response. No secret values are returned and individual secret versions are - not listed in the response. This operation requires the secrets/list permission. + """List the latest identifier and attributes of all secrets in the vault, not including their values. Requires + the secrets/list permission. - :returns: An iterator like instance of Secrets - :rtype: - typing.AsyncIterable[~azure.keyvault.secrets._models.SecretAttributes] + :returns: An iterator of secrets + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.secrets.models.SecretAttributes] Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START list_secrets] :end-before: [END list_secrets] :language: python - :caption: Lists all the secrets in the vault + :caption: Lists all secrets :dedent: 8 """ max_results = kwargs.get("max_page_size") @@ -191,23 +166,19 @@ def list_secrets(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[SecretAttri @distributed_trace def list_secret_versions(self, name: str, **kwargs: Mapping[str, Any]) -> AsyncIterable[SecretAttributes]: - """List all versions of the specified secret. - - The full secret identifier and attributes are provided in the response. - No values are returned for the secrets. This operation requires the + """List all versions of a secret, including their identifiers and attributes but not their values. Requires the secrets/list permission. - :param str name: The name of the secret. - :returns: An iterator like instance of SecretAttributes - :rtype: - typing.AsyncIterable[~azure.keyvault.secrets._models.SecretAttributes] + :param str name: Name of the secret + :returns: An iterator of secrets + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.secrets.models.SecretAttributes] Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START list_secret_versions] :end-before: [END list_secret_versions] :language: python - :caption: List all versions of the specified secret + :caption: List all versions of a secret :dedent: 8 """ max_results = kwargs.get("max_page_size") @@ -221,23 +192,19 @@ def list_secret_versions(self, name: str, **kwargs: Mapping[str, Any]) -> AsyncI @distributed_trace_async async def backup_secret(self, name: str, **kwargs: Mapping[str, Any]) -> bytes: - """Backs up the specified secret. - - Requests that a backup of the specified secret be downloaded to the - client. All versions of the secret will be downloaded. This operation - requires the secrets/backup permission. + """Get a backup of all versions of a secret. Requires the secrets/backup permission. - :param str name: The name of the secret. - :returns: The raw bytes of the secret backup. + :param str name: Name of the secret + :returns: The raw bytes of the secret backup :rtype: bytes - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to retrieve the secret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START backup_secret] :end-before: [END backup_secret] :language: python - :caption: Backs up the specified secret + :caption: Back up a secret :dedent: 8 """ backup_result = await self._client.backup_secret( @@ -247,22 +214,19 @@ async def backup_secret(self, name: str, **kwargs: Mapping[str, Any]) -> bytes: @distributed_trace_async async def restore_secret(self, backup: bytes, **kwargs: Mapping[str, Any]) -> SecretAttributes: - """Restores a backed up secret to a vault. - - Restores a backed up secret, and all its versions, to a vault. This - operation requires the secrets/restore permission. + """Restore a backed up secret. Requires the secrets/restore permission. :param bytes backup: The raw bytes of the secret backup :returns: The restored secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes - :raises: ~azure.core.exceptions.ResourceExistsError, if client failed to restore the secret + :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: ~azure.core.exceptions.ResourceExistsError if the secret's name is already in use Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START restore_secret] :end-before: [END restore_secret] :language: python - :caption: Restores a backed up secret to the vault + :caption: Restore a backed up secret :dedent: 8 """ bundle = await self._client.restore_secret( @@ -272,23 +236,18 @@ async def restore_secret(self, backup: bytes, **kwargs: Mapping[str, Any]) -> Se @distributed_trace_async async def delete_secret(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedSecret: - """Deletes a secret from the vault. + """Delete all versions of a secret. Requires the secrets/delete permission. - The DELETE operation applies to any secret stored in Azure Key Vault. - DELETE cannot be applied to an individual version of a secret. This - operation requires the secrets/delete permission. - - :param str name: The name of the secret - :returns: The deleted secret. - :rtype: ~azure.keyvault.secrets._models.DeletedSecret - :raises: ~azure.core.exceptions.ClientRequestError, if client failed to delete the secret + :param str name: Name of the secret + :rtype: ~azure.keyvault.secrets.models.DeletedSecret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START delete_secret] :end-before: [END delete_secret] :language: python - :caption: Deletes a secret + :caption: Delete a secret :dedent: 8 """ bundle = await self._client.delete_secret( @@ -298,22 +257,19 @@ async def delete_secret(self, name: str, **kwargs: Mapping[str, Any]) -> Deleted @distributed_trace_async async def get_deleted_secret(self, name: str, **kwargs: Mapping[str, Any]) -> DeletedSecret: - """Gets the specified deleted secret. - - The Get Deleted Secret operation returns the specified deleted secret - along with its attributes. This operation requires the secrets/get permission. + """Get a deleted secret. This is only possible in vaults with soft-delete enabled. Requires the secrets/get + permission. - :param str name: The name of the secret - :returns: The deleted secret. - :rtype: ~azure.keyvault.secrets._models.DeletedSecret - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to retrieve the secret + :param str name: Name of the secret + :rtype: ~azure.keyvault.secrets.models.DeletedSecret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the deleted secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START get_deleted_secret] :end-before: [END get_deleted_secret] :language: python - :caption: Gets the deleted secret + :caption: Get a deleted secret :dedent: 8 """ bundle = await self._client.get_deleted_secret( @@ -323,22 +279,18 @@ async def get_deleted_secret(self, name: str, **kwargs: Mapping[str, Any]) -> De @distributed_trace def list_deleted_secrets(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[DeletedSecret]: - """Lists deleted secrets of the vault. - - The Get Deleted Secrets operation returns the secrets that have - been deleted for a vault enabled for soft-delete. This - operation requires the secrets/list permission. + """Lists all deleted secrets. This is only possible in vaults with soft-delete enabled. Requires the + secrets/list permission. - :returns: An iterator like instance of DeletedSecrets - :rtype: - typing.AsyncIterable[~azure.keyvault.secrets._models.DeletedSecret] + :returns: An iterator of deleted secrets + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.keyvault.secrets.models.DeletedSecret] Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START list_deleted_secrets] :end-before: [END list_deleted_secrets] :language: python - :caption: Lists the deleted secrets of the vault + :caption: Lists deleted secrets :dedent: 8 """ max_results = kwargs.get("max_page_size") @@ -351,20 +303,19 @@ def list_deleted_secrets(self, **kwargs: Mapping[str, Any]) -> AsyncIterable[Del @distributed_trace_async async def purge_deleted_secret(self, name: str, **kwargs: Mapping[str, Any]) -> None: - """Permanently deletes the specified secret. + """Permanently delete a secret. This is only possible in vaults with soft-delete enabled. If a vault + doesn't have soft-delete enabled, :func:`delete_secret` is permanent, and this method will return an error. - The purge deleted secret operation removes the secret permanently, without the - possibility of recovery. This operation can only be enabled on a soft-delete enabled - vault. This operation requires the secrets/purge permission. + Requires the secrets/purge permission. - :param str name: The name of the secret + :param str name: Name of the secret :returns: None Example: .. code-block:: python # if the vault has soft-delete enabled, purge permanently deletes the secret - # (with soft-delete disabled, delete itself is permanent) + # (with soft-delete disabled, delete_secret is permanent) await secret_client.purge_deleted_secret("secret-name") """ @@ -372,22 +323,19 @@ async def purge_deleted_secret(self, name: str, **kwargs: Mapping[str, Any]) -> @distributed_trace_async async def recover_deleted_secret(self, name: str, **kwargs: Mapping[str, Any]) -> SecretAttributes: - """Recovers the deleted secret to the latest version. + """Recover a deleted secret to its latest version. This is only possible in vaults with soft-delete enabled. + Requires the secrets/recover permission. - Recovers the deleted secret in the specified vault. - This operation can only be performed on a soft-delete enabled - vault. This operation requires the secrets/recover permission. - - :param str name: The name of the secret - :returns: The recovered deleted secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes + :param str name: Name of the secret + :returns: The recovered secret + :rtype: ~azure.keyvault.secrets.models.SecretAttributes Example: .. literalinclude:: ../tests/test_samples_secrets_async.py :start-after: [START recover_deleted_secret] :end-before: [END recover_deleted_secret] :language: python - :caption: Restores a backed up secret to the vault + :caption: Recover a deleted secret :dedent: 8 """ bundle = await self._client.recover_deleted_secret(self.vault_url, name, **kwargs) diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_client.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py similarity index 54% rename from sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_client.py rename to sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py index 40678aabf7d4..1246e49769cb 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_client.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py @@ -10,24 +10,26 @@ TYPE_CHECKING = False if TYPE_CHECKING: - from typing import Any, Dict, Generator, Mapping, Optional + # pylint:disable=unused-import + from typing import Any, Dict, Mapping, Optional + from azure.core.paging import ItemPaged from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from ._shared import KeyVaultClientBase -from ._models import Secret, DeletedSecret, SecretAttributes +from .models import Secret, DeletedSecret, SecretAttributes class SecretClient(KeyVaultClientBase): - """SecretClient is a high-level interface for managing a vault's secrets. + """A high-level interface for managing a vault's secrets. Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START create_secret_client] :end-before: [END create_secret_client] :language: python - :caption: Creates a new instance of the Secret client + :caption: Create a new ``SecretClient`` :dedent: 4 """ @@ -36,24 +38,19 @@ class SecretClient(KeyVaultClientBase): @distributed_trace def get_secret(self, name, version=None, **kwargs): # type: (str, str, Mapping[str, Any]) -> Secret - """Get a specified secret from the vault. + """Get a secret. Requires the secrets/get permission. - The GET operation is applicable to any secret stored in Azure Key - Vault. This operation requires the secrets/get permission. - - :param str name: The name of the secret. - :param str version: The version of the secret. If version is None or the empty string, the latest version of - the secret is returned - :returns: An instance of Secret - :rtype: ~azure.keyvault.secrets._models.Secret - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to retrieve the secret + :param str name: The name of the secret + :param str version: (optional) Version of the secret to get. If unspecified, gets the latest version. + :rtype: ~azure.keyvault.secrets.models.Secret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START get_secret] :end-before: [END get_secret] :language: python - :caption: Get secret from the key vault + :caption: Get a secret :dedent: 8 """ bundle = self._client.get_secret( @@ -66,32 +63,24 @@ def set_secret( self, name, value, content_type=None, enabled=None, not_before=None, expires=None, tags=None, **kwargs ): # type: (str, str, Optional[str], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> Secret - """Sets a secret in the vault. - - The SET operation adds a secret to the Azure Key Vault. If the named - secret already exists, Azure Key Vault creates a new version of that - secret. This operation requires the secrets/set permission. + """Set a secret value. Create a new secret if ``name`` is not in use. If it is, create a new version of the + secret. :param str name: The name of the secret :param str value: The value of the secret - :param str content_type: Type of the secret value such as a password - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param not_before: Not before date of the secret in UTC - :type not_before: datetime.datetime - :param expires: Expiry date of the secret in UTC. - :type expires: datetime.datetime - :param tags: Application specific metadata in the form of key-value pairs. - :type tags: dict(str, str) - :returns: The created secret - :rtype: ~azure.keyvault.secrets._models.Secret + :param str content_type: (optional) An arbitrary string indicating the type of the secret, e.g. 'password' + :param bool enabled: (optional) Whether the secret is enabled for use + :param datetime.datetime not_before: (optional) Not before date of the secret in UTC + :param datetime.datetime expires: (optional) Expiry date of the secret in UTC + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :rtype: ~azure.keyvault.secrets.models.Secret Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START set_secret] :end-before: [END set_secret] :language: python - :caption: Set a secret in the key vault + :caption: Set a secret's value :dedent: 8 """ @@ -109,33 +98,26 @@ def update_secret( self, name, version=None, content_type=None, enabled=None, not_before=None, expires=None, tags=None, **kwargs ): # type: (str, Optional[str], Optional[str], Optional[bool], Optional[datetime], Optional[datetime], Optional[Dict[str, str]], Mapping[str, Any]) -> SecretAttributes - """Updates the attributes associated with a specified secret in the key vault. + """Update a secret's attributes, such as its tags or whether it's enabled. Requires the secrets/set permission. - The UPDATE operation changes specified attributes of an existing stored secret. - Attributes that are not specified in the request are left unchanged. The value - of a secret itself cannot be changed. This operation requires the secrets/set permission. + **This method can't change a secret's value.** Use :func:`set_secret` to change values. - :param str name: The name of the secret - :param str version: The version of the secret. - :param str content_type: Type of the secret value such as a password - :param enabled: Determines whether the object is enabled. - :type enabled: bool - :param not_before: Not before date of the secret in UTC - :type not_before: datetime.datetime - :param expires: Expiry date of the secret in UTC. - :type expires: datetime.datetime - :param tags: Application specific metadata in the form of key-value pairs. - :type tags: dict(str, str) - :returns: The created secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes - :raises: ~azure.core.exceptions.ResourceNotFoundError if the client failed to create the secret + :param str name: Name of the secret + :param str version: (optional) Version of the secret to update. If unspecified, the latest version is updated. + :param str content_type: (optional) An arbitrary string indicating the type of the secret, e.g. 'password' + :param bool enabled: (optional) Whether the secret is enabled for use + :param datetime.datetime not_before: (optional) Not before date of the secret in UTC + :param datetime.datetime expires: (optional) Expiry date of the secret in UTC. + :param dict tags: (optional) Application specific metadata in the form of key-value pairs + :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START update_secret] :end-before: [END update_secret] :language: python - :caption: Updates the attributes associated with a specified secret in the key vault + :caption: Update a secret's attributes :dedent: 8 """ @@ -157,24 +139,19 @@ def update_secret( @distributed_trace def list_secrets(self, **kwargs): - # type: (Mapping[str, Any]) -> Generator[SecretAttributes] - """List secrets in the vault. - - The Get Secrets operation is applicable to the entire vault. However, - only the latest secret identifier and its attributes are provided in the - response. No secret values are returned and individual secret versions are - not listed in the response. This operation requires the secrets/list permission. + # type: (Mapping[str, Any]) -> ItemPaged[SecretAttributes] + """List the latest identifier and attributes of all secrets in the vault, not including their values. Requires + the secrets/list permission. - :returns: An iterator like instance of Secrets - :rtype: - Generator[~azure.keyvault.secrets._models.SecretAttributes] + :returns: An iterator of secrets + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.secrets.models.SecretAttributes] Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START list_secrets] :end-before: [END list_secrets] :language: python - :caption: Lists all the secrets in the vault + :caption: List all secrets :dedent: 8 """ @@ -188,24 +165,20 @@ def list_secrets(self, **kwargs): @distributed_trace def list_secret_versions(self, name, **kwargs): - # type: (str, Mapping[str, Any]) -> Generator[SecretAttributes] - """List all versions of the specified secret. - - The full secret identifier and attributes are provided in the response. - No values are returned for the secrets. This operations requires the + # type: (str, Mapping[str, Any]) -> ItemPaged[SecretAttributes] + """List all versions of a secret, including their identifiers and attributes but not their values. Requires the secrets/list permission. - :param str name: The name of the secret. - :returns: An iterator like instance of Secret - :rtype: - Generator[~azure.keyvault.secrets._models.SecretAttributes] + :param str name: Name of the secret + :returns: An iterator of secrets + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.secrets.models.SecretAttributes] Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START list_secret_versions] :end-before: [END list_secret_versions] :language: python - :caption: List all versions of the specified secret + :caption: List all versions of a secret :dedent: 8 """ @@ -221,23 +194,19 @@ def list_secret_versions(self, name, **kwargs): @distributed_trace def backup_secret(self, name, **kwargs): # type: (str, Mapping[str, Any]) -> bytes - """Backs up the specified secret. - - Requests that a backup of the specified secret be downloaded to the - client. All versions of the secret will be downloaded. This operation - requires the secrets/backup permission. + """Get a backup of all versions of a secret. Requires the secrets/backup permission. - :param str name: The name of the secret. - :returns: The raw bytes of the secret backup. + :param str name: Name of the secret + :returns: The raw bytes of the secret backup :rtype: bytes - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to back up the secret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START backup_secret] :end-before: [END backup_secret] :language: python - :caption: Backs up the specified secret + :caption: Back up a secret :dedent: 8 """ @@ -249,22 +218,19 @@ def backup_secret(self, name, **kwargs): @distributed_trace def restore_secret(self, backup, **kwargs): # type: (bytes, Mapping[str, Any]) -> SecretAttributes - """Restore a backed up secret to the vault. - - Restores a backed up secret, and all its versions, to a vault. This - operation requires the secrets/restore permission. + """Restore a backed up secret. Requires the secrets/restore permission. :param bytes backup: The raw bytes of the secret backup :returns: The restored secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes - :raises: ~azure.core.exceptions.ResourceExistsError, if client failed to restore the secret + :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: ~azure.core.exceptions.ResourceExistsError if the secret's name is already in use Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START restore_secret] :end-before: [END restore_secret] :language: python - :caption: Restores a backed up secret to the vault + :caption: Restore a backed up secret :dedent: 8 """ @@ -274,23 +240,18 @@ def restore_secret(self, backup, **kwargs): @distributed_trace def delete_secret(self, name, **kwargs): # type: (str, Mapping[str, Any]) -> DeletedSecret - """Deletes a secret from the vault. + """Delete all versions of a secret. Requires the secrets/delete permission. - The DELETE operation applies to any secret stored in Azure Key Vault. - DELETE cannot be applied to an individual version of a secret. This - operation requires the secrets/delete permission. - - :param str name: The name of the secret - :return: The deleted secret. - :rtype: ~azure.keyvault.secrets._models.DeletedSecret - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to delete the secret + :param str name: Name of the secret + :rtype: ~azure.keyvault.secrets.models.DeletedSecret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START delete_secret] :end-before: [END delete_secret] :language: python - :caption: Deletes a secret + :caption: Delete a secret :dedent: 8 """ @@ -300,22 +261,19 @@ def delete_secret(self, name, **kwargs): @distributed_trace def get_deleted_secret(self, name, **kwargs): # type: (str, Mapping[str, Any]) -> DeletedSecret - """Gets the specified deleted secret. - - The Get Deleted Secret operation returns the specified deleted secret - along with its attributes. This operation requires the secrets/get permission. + """Get a deleted secret. This is only possible in vaults with soft-delete enabled. Requires the secrets/get + permission. - :param str name: The name of the secret - :return: The deleted secret. - :rtype: ~azure.keyvault.secrets._models.DeletedSecret - :raises: ~azure.core.exceptions.ResourceNotFoundError, if client failed to get the deleted secret + :param str name: Name of the secret + :rtype: ~azure.keyvault.secrets.models.DeletedSecret + :raises: ~azure.core.exceptions.ResourceNotFoundError if the deleted secret doesn't exist Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START get_deleted_secret] :end-before: [END get_deleted_secret] :language: python - :caption: Gets the deleted secret + :caption: Get a deleted secret :dedent: 8 """ @@ -324,23 +282,19 @@ def get_deleted_secret(self, name, **kwargs): @distributed_trace def list_deleted_secrets(self, **kwargs): - # type: (Mapping[str, Any]) -> Generator[DeletedSecret] - """Lists deleted secrets of the vault. - - The Get Deleted Secrets operation returns the secrets that have - been deleted for a vault enabled for soft-delete. This - operation requires the secrets/list permission. + # type: (Mapping[str, Any]) -> ItemPaged[DeletedSecret] + """Lists all deleted secrets. This is only possible in vaults with soft-delete enabled. Requires the + secrets/list permission. - :returns: An iterator like instance of DeletedSecrets - :rtype: - Generator[~azure.keyvault.secrets._models.DeletedSecret] + :returns: An iterator of deleted secrets + :rtype: ~azure.core.paging.ItemPaged[~azure.keyvault.secrets.models.DeletedSecret] Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START list_deleted_secrets] :end-before: [END list_deleted_secrets] :language: python - :caption: Lists the deleted secrets of the vault + :caption: List deleted secrets :dedent: 8 """ @@ -355,21 +309,19 @@ def list_deleted_secrets(self, **kwargs): @distributed_trace def purge_deleted_secret(self, name, **kwargs): # type: (str, Mapping[str, Any]) -> None - """Permanently deletes the specified secret. + """Permanently delete a secret. This is only possible in vaults with soft-delete enabled. If a vault + doesn't have soft-delete enabled, :func:`delete_secret` is permanent, and this method will return an error. - The purge deleted secret operation removes the secret permanently, without the - possibility of recovery. This operation can only be enabled on a soft-delete enabled - vault. This operation requires the secrets/purge permission. + Requires the secrets/purge permission. - :param str name: The name of the secret + :param str name: Name of the secret :returns: None - :raises: ~azure.core.exceptions.HttpResponseError, if client failed to return the purged secret Example: .. code-block:: python # if the vault has soft-delete enabled, purge permanently deletes the secret - # (with soft-delete disabled, delete itself is permanent) + # (with soft-delete disabled, delete_secret is permanent) secret_client.purge_deleted_secret("secret-name") """ @@ -378,23 +330,19 @@ def purge_deleted_secret(self, name, **kwargs): @distributed_trace def recover_deleted_secret(self, name, **kwargs): # type: (str, Mapping[str, Any]) -> SecretAttributes - """Recovers the deleted secret to the latest version. + """Recover a deleted secret to its latest version. This is only possible in vaults with soft-delete enabled. + Requires the secrets/recover permission. - Recovers the deleted secret in the specified vault. - This operation can only be performed on a soft-delete enabled - vault. This operation requires the secrets/recover permission. - - :param str name: The name of the secret - :returns: The recovered deleted secret - :rtype: ~azure.keyvault.secrets._models.SecretAttributes - :raises: ~azure.core.exceptions.HttpResponseError, if client failed to recover the deleted secret + :param str name: Name of the secret + :returns: The recovered secret + :rtype: ~azure.keyvault.secrets.models.SecretAttributes Example: .. literalinclude:: ../tests/test_samples_secrets.py :start-after: [START recover_deleted_secret] :end-before: [END recover_deleted_secret] :language: python - :caption: Restores a backed up secret to the vault + :caption: Recover a deleted secret :dedent: 8 """ diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/models.py similarity index 72% rename from sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py rename to sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/models.py index a8629aeeee28..ee802d052ef7 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_models.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/models.py @@ -2,25 +2,25 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -import datetime - try: from typing import TYPE_CHECKING except ImportError: TYPE_CHECKING = False if TYPE_CHECKING: + # pylint:disable=unused-import + from datetime import datetime from typing import Any, Dict, Mapping, Optional + from ._shared._generated.v7_0 import models as _models from ._shared import parse_vault_id -from ._shared._generated.v7_0 import models class SecretAttributes(object): """A secret's id and attributes.""" def __init__(self, attributes, vault_id, **kwargs): - # type: (models.SecretAttributes, str, Mapping[str, Any]) -> None + # type: (_models.SecretAttributes, str, Mapping[str, Any]) -> None self._attributes = attributes self._id = vault_id self._vault_id = parse_vault_id(vault_id) @@ -31,7 +31,7 @@ def __init__(self, attributes, vault_id, **kwargs): @classmethod def _from_secret_bundle(cls, secret_bundle): - # type: (models.SecretBundle) -> SecretAttributes + # type: (_models.SecretBundle) -> SecretAttributes """Construct a SecretAttributes from an autorest-generated SecretBundle""" return cls( secret_bundle.attributes, @@ -44,7 +44,7 @@ def _from_secret_bundle(cls, secret_bundle): @classmethod def _from_secret_item(cls, secret_item): - # type: (models.SecretItem) -> SecretAttributes + # type: (_models.SecretItem) -> SecretAttributes """Construct a SecretAttributes from an autorest-generated SecretItem""" return cls( secret_item.attributes, @@ -57,98 +57,115 @@ def _from_secret_item(cls, secret_item): @property def content_type(self): # type: () -> str - """Type of the secret value such as a password - :rtype: str""" + """:rtype: str""" return self._content_type @property def id(self): # type: () -> str - """The secret id - :rtype: str""" + """:rtype: str""" return self._id @property def key_id(self): # type: () -> str - """Specifies the corresponding key id backing the KV certificate - :rtype: str""" + """ + If this secret backs a certificate, this property is the identifier of the corresponding key. + + :rtype: str + """ return self._key_id @property def enabled(self): # type: () -> bool - """The Secret's 'enabled' attribute - :rtype: bool""" + """:rtype: bool""" return self._attributes.enabled @property def not_before(self): # type: () -> datetime - """The Secret's not_before date in UTC - :rtype: datetime""" + """ + Not-before time, in UTC + + :rtype: datetime.datetime + """ return self._attributes.not_before @property def expires(self): # type: () -> datetime - """The Secret's expiry date in UTC - :rtype: datetime""" + """ + When the secret expires, in UTC + + :rtype: datetime.datetime + """ return self._attributes.expires @property def created(self): # type: () -> datetime - """The Secret's creation time in UTC - :rtype: datetime""" + """ + When the secret was created, in UTC + + :rtype: datetime.datetime + """ return self._attributes.created @property def updated(self): # type: () -> datetime - """The Secret's last updated time in UTC - :rtype: datetime""" + """ + When the secret was last updated, in UTC + + :rtype: datetime.datetime + """ return self._attributes.updated @property def recovery_level(self): # type: () -> str - """Reflects the deletion recovery level currently in effect for secrets in the current vault - :rtype: str""" + """ + The vault's deletion recovery level for secrets + + :rtype: str + """ return self._attributes.recovery_level @property def vault_url(self): # type: () -> str - """The url of the vault containing the secret - :rtype: str""" + """ + URL of the vault containing the secret + + :rtype: str + """ return self._vault_id.vault_url @property def name(self): # type: () -> str - """The name of the secret - :rtype: str""" + """:rtype: str""" return self._vault_id.name @property def version(self): # type: () -> str - """The version of the secret - :rtype: str""" + """:rtype: str""" return self._vault_id.version @property def tags(self): # type: () -> Dict[str, str] - """Application specific metadata in the form of key-value pairs. + """ + Application specific metadata in the form of key-value pairs + :rtype: dict""" return self._tags class Secret(SecretAttributes): - """A secret consisting of all SecretAttributes and value information. - """ + """All a secret's attributes, and its value.""" def __init__(self, attributes, vault_id, value, **kwargs): super(Secret, self).__init__(attributes, vault_id, **kwargs) @@ -156,7 +173,7 @@ def __init__(self, attributes, vault_id, value, **kwargs): @classmethod def _from_secret_bundle(cls, secret_bundle): - # type: (models.SecretBundle) -> Secret + # type: (_models.SecretBundle) -> Secret """Construct a Secret from an autorest-generated SecretBundle""" return cls( secret_bundle.attributes, @@ -171,18 +188,19 @@ def _from_secret_bundle(cls, secret_bundle): @property def value(self): # type: () -> str - """The secret's value. - :rtype: str""" + """ + The secret value + + :rtype: str + """ return self._value class DeletedSecret(SecretAttributes): - """A Deleted Secret consisting of its id, attributes, and tags, as - well as when it will be purged, if soft-delete is enabled for the vault. - """ + """A deleted secret's attributes, as well as when it will be purged, if soft-delete is enabled for its vault.""" def __init__(self, attributes, vault_id, deleted_date=None, recovery_id=None, scheduled_purge_date=None, **kwargs): - # type: (models.SecretAttributes, str, Optional[datetime], Optional[str], Optional[datetime], Mapping[str, Any]) -> None + # type: (_models.SecretAttributes, str, Optional[datetime], Optional[str], Optional[datetime], Mapping[str, Any]) -> None super(DeletedSecret, self).__init__(attributes, vault_id, **kwargs) self._deleted_date = deleted_date self._recovery_id = recovery_id @@ -190,7 +208,7 @@ def __init__(self, attributes, vault_id, deleted_date=None, recovery_id=None, sc @classmethod def _from_deleted_secret_bundle(cls, deleted_secret_bundle): - # type: (models.DeletedSecretBundle) -> DeletedSecret + # type: (_models.DeletedSecretBundle) -> DeletedSecret """Construct a DeletedSecret from an autorest-generated DeletedSecretBundle""" return cls( deleted_secret_bundle.attributes, @@ -206,7 +224,7 @@ def _from_deleted_secret_bundle(cls, deleted_secret_bundle): @classmethod def _from_deleted_secret_item(cls, deleted_secret_item): - # type: (models.DeletedSecretItem) -> DeletedSecret + # type: (_models.DeletedSecretItem) -> DeletedSecret """Construct a DeletedSecret from an autorest-generated DeletedSecretItem""" return cls( deleted_secret_item.attributes, @@ -222,20 +240,29 @@ def _from_deleted_secret_item(cls, deleted_secret_item): @property def deleted_date(self): # type: () -> datetime - """The time when the secret was deleted, in UTC - :rtype: datetime""" + """ + When the secret was deleted, in UTC + + :rtype: datetime.datetime + """ return self._deleted_date @property def recovery_id(self): # type: () -> str - """The url of the recovery object, used to identify and recover the deleted secret - :rtype: str""" + """ + An identifier used to recover the deleted secret + + :rtype: str + """ return self._recovery_id @property def scheduled_purge_date(self): # type: () -> datetime - """The time when the secret is scheduled to be purged, in UTC - :rtype: datetime""" + """ + When the secret is scheduled to be purged, in UTC + + :rtype: datetime.datetime + """ return self._scheduled_purge_date diff --git a/sdk/keyvault/azure-keyvault-secrets/setup.py b/sdk/keyvault/azure-keyvault-secrets/setup.py index fcec5d8c9ded..7ffb60b443c9 100644 --- a/sdk/keyvault/azure-keyvault-secrets/setup.py +++ b/sdk/keyvault/azure-keyvault-secrets/setup.py @@ -36,7 +36,7 @@ pass # Version extraction inspired from 'requests' -with open(os.path.join(PACKAGE_FOLDER_PATH, "version.py"), "r") as fd: +with open(os.path.join(PACKAGE_FOLDER_PATH, "_version.py"), "r") as fd: VERSION = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) if not VERSION: