Check! Azure SDK for Python で Azure Key Vault をつかうには！（認証まわり対策）

こんばんは！ @dz_ こと大平かづみです。

Prologue - はじめに
====
Azure SDK for Python を使って、Azure Key Vault の利用を試みたところ、RBAC (Role Based Access Control ) の認証で苦戦したので、腹いせにその状況と対処をしたためます。

RBAC認証とSDK用 auth ファイルについて
----

Azure の認証情報について検討していたところ、以下の形式で json ファイルで扱えることがわかりました。

- [azure.common package — Azure SDK for Python 2.0.0 documentation](http://azure-sdk-for-python.readthedocs.io/en/latest/ref/azure.common.html?highlight=credential#azure.common.client_factory.get_client_from_auth_file)

たとえば、新しく RBAC の認証を発行し、その情報を上記の JSON 形式で出力するには、下記の [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli "Install the Azure CLI 2.0 | Microsoft Docs") のコマンドを利用できます。

```bash:CLIでRBACによる認証情報を発行（SDK用JSON出力オプション）
$ az login
$ az ad sp create-for-rbac --sdk-auth > auth-sample.json
```

```json:SDK用JSONのサンプル（上記ドキュメントから引用）
{
    "clientId": "ad735158-65ca-11e7-ba4d-ecb1d756380e",
    "clientSecret": "b70bb224-65ca-11e7-810c-ecb1d756380e",
    "subscriptionId": "bfc42d3a-65ca-11e7-95cf-ecb1d756380e",
    "tenantId": "c81da1d8-65ca-11e7-b1d1-ecb1d756380e",
    "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
    "resourceManagerEndpointUrl": "https://management.azure.com/",
    "activeDirectoryGraphResourceId": "https://graph.windows.net/",
    "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
    "galleryEndpointUrl": "https://gallery.azure.com/",
    "managementEndpointUrl": "https://management.core.windows.net/"
}
```

SDK で認証情報を扱うには
----

また、環境変数 `AZURE_AUTH_LOCATION` に、このJOSNファイルのパスを設定しておけば、SDKが自動で読み込んでくれるとのこと。

そして、上記のリンク先にあるように、ほとんどの場合は `azure.common.client_factory.get_client_from_auth_file` を利用して、簡単にクライアントを生成してくれます。

Azure SDK for Python で Azure Key Vault を利用するには
====

`KeyVaultClient` では、 `get_client_from_auth_file` が使えないよう…
----
しかぁし！

Azure Key Vault のクライアント `KeyVaultClient` も、上記の方法で簡単に生成できると思い、やってみたところ… できない(´･ω･`)

```bash:azure-keyvaultのバージョン
$ pip show azure-keyvault
Name: azure-keyvault
Version: 0.3.5
...
```


```python:KeyVaultClientではだめだった例
from azure.common.client_factory import get_client_from_auth_file
from azure.keyvault import KeyVaultClient
client = get_client_from_auth_file(KeyVaultClient)
```

```python:KeyVaultClientではだめだったときのエラー
Traceback (most recent call last):
  File "sample.py", line 26, in <module>
    client = get_client_from_auth_file(KeyVaultClient)
  File "/usr/local/lib/python2.7/dist-packages/azure/common/client_factory.py", line 192, in get_client_fr
om_auth_file
    return get_client_from_json_dict(client_class, config_dict, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/azure/common/client_factory.py", line 132, in get_client_fr
om_json_dict
    return _instantiate_client(client_class, **parameters)
  File "/usr/local/lib/python2.7/dist-packages/azure/common/client_factory.py", line 31, in _instantiate_c
lient
    return client_class(**kwargs)
TypeError: __init__() got an unexpected keyword argument 'base_url'
```

`KeyVaultClient` の生成はこちらの方法で！
----

SDKのソースコードともにらめっこして、最終的にたどり着いたこちらの資料、この方法で行けましたー！いえーい！ヾ(o´∀｀o)ﾉ

- [Azure Key Vault libraries for Python | Microsoft Docs](https://docs.microsoft.com/en-us/python/api/overview/azure/key-vault?view=azure-python)

せっかくなので、上記を参考に `AZURE_AUTH_LOCATION` のパスを利用するサンプルコードを書いてみました。

```python:sample.py
#!/usr/bin/env python

import json
import os

from azure.keyvault import KeyVaultClient, KeyVaultAuthentication
from azure.common.credentials import ServicePrincipalCredentials

def auth_callback(server, resource, scope):
    with open(os.environ.get('AZURE_AUTH_LOCATION')) as auth_file:
        auth = json.load(auth_file)

    credentials = ServicePrincipalCredentials(
        client_id=auth['clientId'],
        secret=auth['clientSecret'],
        tenant=auth['tenantId'],
        resource=resource
    )
    token = credentials.token
    return token['token_type'], token['access_token']

# クライアントを取得する
client = KeyVaultClient(KeyVaultAuthentication(auth_callback))

# シークレットを取得する
vault_base_url = 'https://<Key Vault の名前>.vault.azure.net/'
secret_name = '<シークレットの名前>'
secret_version = '' # バージョンを指定しない場合

secret = client.get_secret(vault_base_url, secret_name, secret_version)
```

シークレットの取得に関しては、下記のドキュメント参考にしました。

- [Example - KeyVault — Azure SDK for Python 2.0.0 documentation](http://azure-sdk-for-python.readthedocs.io/en/latest/sample_azure-keyvault.html#example)

これですすめるー！いえーい！ヾ(o´∀｀o)ﾉ

Epilogue - おわりに
====
ということで、だいぶん翻弄されましたが、SDKがオープンソースでソースコード読めば解けることとか、わかった時のうれしさとか、これだからエンジニアはやめられません  	(oゝω･o)ﾉ))