Gary Wright
Gary Wright

Reputation: 33

Interacting with Azure Key Vault using python w/ rest api

I am very interested in using the new service recently released for secret management within Azure. I have found a few example guides walking through how to interact with key vault via powershell cmdlets and c#, however haven't found much at all in regards to getting started with using the rest API.

The thing I am particularly confused with is the handling of oauth2 w/ active directory. I have written a oauth2 application listener, built a web application with an AD instance and can now generate a "access_token". It is very unclear to me how to proceed beyond this though, as I seem to consistently receive a 401 HTTP resp code whenever attempting to use my access_token to perform a key vault API call.

Any guides / tips on using azure key vault with python would be greatly appreciated!

Upvotes: 2

Views: 8416

Answers (5)

mccoyp
mccoyp

Reputation: 307

For working with Key Vault's REST API, there's reference documentation and service documentation that should help.

Using Key Vault with Python is now more easily done with the Azure SDK. There are three Python packages for working with existing vault data, and one for creating/managing vaults:

azure-identity is also the package that should be used with these for authentication.

With the SDK, using an access token to work with an existing vault from an authorized application is as easy as creating a credential and client:

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
client = SecretClient("https://{vault-name}.vault.azure.net", credential)
secret = client.get_secret("secret-name")

(I work on the Azure SDK in Python)

Upvotes: 1

user330612
user330612

Reputation: 2239

I have written a simple python wrapper for the REST APIs for Azure Key Vault. You can check out out here AzureKeyVaultPythonSDK

Crust of the logic is here

class AzureKeyVaultManager(object):

section_name="KeyVaultSection"

# Constructor
def __init__(self, fileName="private.properties"):
    prop_file=os.path.dirname(os.path.realpath(sys.argv[0])) + "/" + fileName
    config = ConfigParser.RawConfigParser()
    config.read(prop_file)
    self.client_id=config.get(self.section_name,'client.id')
    self.client_secret=config.get(self.section_name,'client.secret')
    self.tenant_id=config.get(self.section_name,'tenant.id')
    self.resource=config.get(self.section_name,'resource')
    self.key_vault=config.get(self.section_name,'key.vault')

# Authenticate
def initialize(self):
    if self.client_id and self.client_secret and self.tenant_id and self.resource and self.key_vault:
        print "Got all the properties from file "
        token_url="https://login.windows.net/{0}/oauth2/token".format(self.tenant_id)
        payload = {'client_id':self.client_id, 'client_secret':self.client_secret, 'resource':self.resource, 'grant_type':'client_credentials'}
        response=requests.post(token_url, data=payload).json()
        self.access_token=response['access_token']
    else:
        raise ValueError("Couldn't get the key vault properties from properties file")

# Get secret from a specific keyvault
def getSecretFromKeyVault(self, secretName, keyVault=None):
    if keyVault is None:
        keyVault=self.key_vault

    endpoint = 'https://{0}.vault.azure.net/secrets/{1}?api-version=2015-06-01'.format(keyVault, secretName)
    headers = {"Authorization": 'Bearer ' + self.access_token}
    response = requests.get(endpoint,headers=headers).json()

    if 'value' in response:
        return response['value']
    else:
        raise ValueError("Value not found in response")

Upvotes: 0

James Burke
James Burke

Reputation: 2387

Here are some steps you'll need to do before the following code will work... Hopefully I remembered everything!

  1. You'll need to have an application in AD with at least get access

    note: you need this to get the CLIENT_ID and CLIENT_SECRET anyway then run:

    azure keyvault set-policy --vault-name 'VAULTNAME' --spn CLIENT_ID --perms-to-secrets '["get"]'

  2. You'll also need the id's for your secrets, which you can get with the Azure CLI using:

    azure keyvault secret show [vault] [secret]

    or

    azure keyvault secret show -h # if this is unclear

  3. Copy the key (last argument in the URL)

Then the following code will allow you to query the key vault using oauth2:

import json
import requests

AUTHORITY_HOST = "login.windows.net"
TENANT_ID      = < your tenant id >
CLIENT_ID      = < your client id >
CLIENT_SECRET  = < your client secret >
VAULT          = 'MyVault'

data = { "grant_type" : "client_credentials", 
        "client_id" : CLIENT_ID, 
        "client_secret" : CLIENT_SECRET, 
        "resource" : "https://vault.azure.net"
    }

secrets = [( "i_like_pie", "8a7680a2cf5e4d539494aa0ce265297" )]

headers = { "Content-Type" : "application/x-www-form-urlencoded" }

r = requests.post("https://login.windows.net/{}/oauth2/token".format(TENANT_ID), data=data, headers=headers)
access_token = r.json()['access_token']

for secret, secret_id in secrets.iteritems():

    headers = {"Authorization":"Bearer {}".format(access_token) }
    r = requests.get('https://{}.vault.azure.net/secrets/{}/{}?api-version=2015-06-01'.format(VAULT, secret, secret_id), headers=headers)

    print('##### {} #####'.format(secret))
    print(r.json())
    print('')

Upvotes: 5

fernacolo
fernacolo

Reputation: 7439

When Key Vault returns a 401 response, it includes a www-authenticate header containing authority and resource. You must use both to get a valid bearer token. Then you can redo your request with that token, and if you use the same token on subsequent requests against the same vault, it shouldn't return a 401 until the token expires.

You can know the authority and resource in advance, but it's generally more robust to prepare your code to always handle the 401, specially if you use multiple vaults.

Be sure to only trust on a www-authenticate header of a valid SSL connection, otherwise you might be a victim of spoofing!

Upvotes: 0

Silohoutte
Silohoutte

Reputation: 73

Here are a couple of things that you can check:

  1. When you make the request for the Bearer token, make sure that you include the "resource" header, and that it is set to "https://vault.azure.net". If you don't, you'll get a token, but you won't be able to access any vault data with it.
  2. When you make a call to the vault.azure.net URL, make sure you include the correct "api-version" It can be found in the API documentation. The current value is "2015-02-01-preview".
  3. Of course, check that the Key Vault Access Policy is set correctly for the vault you are trying to access.

Upvotes: 2

Related Questions