1# Guide for migrating to azure-keyvault-keys from azure-keyvault
2
3This guide is intended to assist in the migration to `azure-keyvault-keys` from `azure-keyvault`. It will focus on side-by-side comparisons for similar operations between the two packages.
4
5Familiarity with the `azure-keyvault` package is assumed. For those new to the Key Vault client library for Python, please refer to the [README for `azure-keyvault-keys`](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/keyvault/azure-keyvault-keys/README.md) rather than this guide.
6
7## Table of contents
8
9* [Migration benefits](#migration-benefits)
10* [Important changes](#important-changes)
11    - [Separate packages and clients](#separate-packages-and-clients)
12    - [Client constructors](#client-constructors)
13    - [Async operations](#async-operations)
14    - [Create a key](#create-a-key)
15    - [Retrieve a key](#retrieve-a-key)
16    - [List properties of keys](#list-properties-of-keys)
17    - [Delete a key](#delete-a-key)
18    - [Perform cryptographic operations](#perform-cryptographic-operations)
19* [Additional samples](#additional-samples)
20
21## Migration benefits
22
23A natural question to ask when considering whether or not to adopt a new version or library is what the benefits of doing so would be. As Azure has matured and been embraced by a more diverse group of developers, we have been focused on learning the patterns and practices to best support developer productivity and to understand the gaps that the Python client libraries have.
24
25There were several areas of consistent feedback expressed across the Azure client library ecosystem. One of the most important is that the client libraries for different Azure services have not had a consistent approach to organization, naming, and API structure. Additionally, many developers have felt that the learning curve was difficult, and the APIs did not offer a good, approachable, and consistent onboarding story for those learning Azure or exploring a specific Azure service.
26
27To try and improve the development experience across Azure services, a set of uniform [design guidelines](https://azure.github.io/azure-sdk/python/guidelines/index.html) was created for all languages to drive a consistent experience with established API patterns for all services. A set of [Python-specific guidelines](https://azure.github.io/azure-sdk/python_design.html) was also introduced to ensure that Python clients have a natural and idiomatic feel with respect to the Python ecosystem. Further details are available in the guidelines for those interested.
28
29### Cross Service SDK improvements
30
31The modern Key Vault client library also provides the ability to share in some of the cross-service improvements made to the Azure development experience, such as
32- using the new [`azure-identity`](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md) library to share a single authentication approach between clients
33- a unified logging and diagnostics pipeline offering a common view of the activities across each of the client libraries
34
35## Important changes
36
37### Separate packages and clients
38
39In the interest of simplifying the API `azure-keyvault` and `KeyVaultClient` were split into separate packages and clients:
40
41- [`azure-keyvault-certificates`](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/keyvault/azure-keyvault-certificates/README.md) contains `CertificateClient` for working with certificates.
42- `azure-keyvault-keys` contains `KeyClient` for working with keys and `CryptographyClient` for performing cryptographic operations.
43- [`azure-keyvault-secrets`](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/keyvault/azure-keyvault-secrets/README.md) contains `SecretClient` for working with secrets.
44
45### Client constructors
46
47Across all modern Azure client libraries, clients consistently take an endpoint or connection string along with token credentials. This differs from `KeyVaultClient`, which took an authentication delegate and could be used for multiple Key Vault endpoints.
48
49#### Authenticating
50
51Previously in `azure-keyvault` you could create a `KeyVaultClient` by using `ServicePrincipalCredentials` from `azure.common`:
52
53```python
54from azure.common.credentials import ServicePrincipalCredentials
55from azure.keyvault import KeyVaultClient
56
57credentials = ServicePrincipalCredentials(
58    client_id="client id",
59    secret="client secret",
60    tenant="tenant id"
61)
62
63client = KeyVaultClient(credentials)
64```
65
66Now in `azure-keyvault-keys` you can create a `KeyClient` using any credential from [`azure-identity`](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md). Below is an example using [`DefaultAzureCredential`](https://docs.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python):
67
68```python
69from azure.identity import DefaultAzureCredential
70from azure.keyvault.keys import KeyClient
71
72credential = DefaultAzureCredential()
73
74key_client = KeyClient(vault_url="https://my-key-vault.vault.azure.net/", credential=credential)
75```
76
77You can also create a `CryptographyClient` to perform cryptographic operations (encrypt/decrypt, wrap/unwrap, sign/verify) using a particular key.
78
79```python
80from azure.keyvault.keys.crypto import CryptographyClient
81
82key = key_client.get_key("key-name")
83crypto_client = CryptographyClient(key=key, credential=credential)
84```
85
86### Async operations
87
88The modern `azure-keyvault-keys` library includes a complete async API supported on Python 3.5+. To use it, you must first install an async transport, such as [aiohttp](https://pypi.org/project/aiohttp/). See [azure-core documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md#transport) for more information.
89
90Async operations are available on async clients, which should be closed when they're no longer needed. Each async client is an async context manager and defines an async `close` method. For example:
91
92```python
93from azure.identity.aio import DefaultAzureCredential
94from azure.keyvault.keys.aio import KeyClient
95
96credential = DefaultAzureCredential()
97
98# call close when the client is no longer needed
99client = KeyClient(vault_url="https://my-key-vault.vault.azure.net/", credential=credential)
100...
101await client.close()
102
103# alternatively, use the client as an async context manager
104client = KeyClient(vault_url="https://my-key-vault.vault.azure.net/", credential=credential)
105async with client:
106  ...
107```
108
109### Create a key
110
111In `azure-keyvault` you could create a key by using `KeyVaultClient`'s `create_key` method, which required a vault endpoint, key name, and key type. This method returned a `KeyBundle` containing the key.
112
113```python
114# create an RSA key
115key_bundle = client.create_key(
116    vault_base_url="https://my-key-vault.vault.azure.net/",
117    key_name="key-name",
118    kty="RSA"
119)
120key = key_bundle.key
121
122# create an elliptic curve key
123key_bundle = client.create_key(
124    vault_base_url="https://my-key-vault.vault.azure.net/",
125    key_name="key-name",
126    kty="EC"
127)
128key = key_bundle.key
129```
130
131Now in `azure-keyvault-keys` there are multiple ways to create keys. You can provide a key name and type to the general `create_key` method, or provide just a name to `create_rsa_key` or `create_ec_key`. These methods all return the created key as a `KeyVaultKey`.
132
133```python
134from azure.keyvault.keys import KeyType, KeyCurveName
135
136# create a key with specified type
137key = key_client.create_key(name="key-name", key_type=KeyType.ec)
138print(key.name)
139print(key.key_type)
140
141# create an RSA key
142rsa_key = key_client.create_rsa_key(name="rsa-key-name", size=2048)
143
144# create an elliptic curve key
145ec_key = key_client.create_ec_key(name="ec-key-name", curve=KeyCurveName.p_256)
146```
147
148### Retrieve a key
149
150In `azure-keyvault` you could retrieve a key (in a `KeyBundle`) by using `get_key` and specifying the desired vault endpoint, key name, and key version. You could retrieve the versions of a key with the `get_key_versions` method, which returned an iterator-like object.
151
152```python
153from azure.keyvault import KeyId
154
155key_items = client.get_key_versions(
156    vault_base_url="https://my-key-vault.vault.azure.net/",
157    key_name="key-name"
158)
159
160for key_item in key_items:
161    key_id = KeyId(key_item.kid)
162    key_version = key_id.version
163
164    key_bundle = client.get_key(
165        vault_base_url="https://my-key-vault.vault.azure.net/",
166        key_name="key-name",
167        key_version=key_version
168    )
169    key = key_bundle.key
170```
171
172Now in `azure-keyvault-keys` you can retrieve the latest version of a key (as a `KeyVaultKey`) by using `get_key` and providing a key name.
173
174```python
175key = key_client.get_key(name="key-name")
176
177print(key.name)
178print(key.key_type)
179
180# get the version of the key
181key_version = key.properties.version
182```
183
184### List properties of keys
185
186In `azure-keyvault` you could list the properties of keys in a specified vault with the `get_keys` method. This returned an iterator-like object containing `KeyItem` instances.
187
188```python
189keys = client.get_keys(vault_base_url="https://my-key-vault.vault.azure.net/")
190
191for key in keys:
192    print(key.attributes.created)
193```
194
195Now in `azure-keyvault-keys` you can list the properties of keys in a vault with the `list_properties_of_keys` method. This returns an iterator-like object containing `KeyProperties` instances.
196
197```python
198keys = key_client.list_properties_of_keys()
199
200for key in keys:
201    print(key.name)
202    print(key.created_on)
203```
204
205### Delete a key
206
207In `azure-keyvault` you could delete all versions of a key with the `delete_key` method. This returned information about the deleted key (as a `DeletedKeyBundle`), but you could not poll the deletion operation to know when it completed. This would be valuable information if you intended to permanently delete the deleted key with `purge_deleted_key`.
208
209```python
210deleted_key = client.delete_key(vault_base_url="https://my-key-vault.vault.azure.net/", key_name="key-name")
211
212# this purge would fail if deletion hadn't finished
213client.purge_deleted_key(vault_base_url="https://my-key-vault.vault.azure.net/", key_name="key-name")
214```
215
216Now in `azure-keyvault-keys` you can delete a key with `begin_delete_key`, which returns a long operation poller object that can be used to wait/check on the operation. Calling `result()` on the poller will return information about the deleted key (as a `DeletedKey`) without waiting for the operation to complete, but calling `wait()` will wait for the deletion to complete. Again, `purge_deleted_key` will permanently delete your deleted key and make it unrecoverable.
217
218```python
219deleted_key_poller = key_client.begin_delete_key(name="key-name")
220deleted_key = deleted_key_poller.result()
221
222deleted_key_poller.wait()
223key_client.purge_deleted_key(name="key-name")
224```
225
226### Perform cryptographic operations
227
228In `azure-keyvault` you could perform cryptographic operations with keys by using the `encrypt`/`decrypt`, `wrap_key`/`unwrap_key`, and `sign`/`verify` methods. Each of these methods accepted a vault endpoint, key name, key version, and algorithm along with other parameters.
229
230```python
231from azure.keyvault import KeyId
232
233key_bundle = client.create_key(
234    vault_base_url="https://my-key-vault.vault.azure.net/",
235    key_name="key-name",
236    kty="RSA"
237)
238key = key_bundle.key
239key_id = KeyId(key.kid)
240key_version = key_id.version
241
242plaintext = b"plaintext"
243
244# encrypt data using the key
245operation_result = client.encrypt(
246    vault_base_url="https://my-key-vault.vault.azure.net/",
247    key_name="key-name",
248    key_version=key_version,
249    algorithm="RSA-OAEP-256",
250    value=plaintext
251)
252ciphertext = operation_result.result
253```
254
255Now in `azure-keyvault-keys` you can perform these cryptographic operations by using a `CryptographyClient`. The key used to create the client will be used for these operations. Cryptographic operations are now performed locally by the client when it's intialized with the necessary key material or is able to get that material from Key Vault, and are only performed by the Key Vault service when required key material is unavailable.
256
257```python
258from azure.keyvault.keys.crypto import CryptographyClient, EncryptionAlgorithm
259
260key = key_client.get_key(name="key-name")
261crypto_client = CryptographyClient(key=key, credential=credential)
262
263plaintext = b"plaintext"
264
265# encrypt data using the key
266result = crypto_client.encrypt(algorithm=EncryptionAlgorithm.rsa_oaep_256, plaintext=plaintext)
267ciphertext = result.ciphertext
268```
269
270## Additional samples
271
272* [Key Vault keys samples for Python](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/keyvault/azure-keyvault-keys/samples)
273* [General Key Vault samples for Python](https://docs.microsoft.com/samples/browse/?products=azure-key-vault&languages=python)
274