2
votes

I've been able to access azure key vault using oauth rest api through my external web app, but for some reason I am unable to retrieve the secrets from the keys. After long hours of researching I've found out that its possible to do this with powershell and c# but have still yet to find any solution with python. Anyone know if its possible with python, or is there a way of emulating what powershell is doing through? Here's the code to retrieve the secret:

def getSecret(vault_name, secret_name, secret_version = ''):
    #Get acess token to azure account
    data = { "grant_type" : "client_credentials", 
            "client_id" : 'appidxx', 
            "client_secret" : 'appsecretxx', 
            "resource" : "https://vault.azure.net"
        }
    headers = { "Content-Type" : "application/x-www-form-urlencoded" }
    r = requests.post("https://login.windows.net/{}/oauth2/token".format('my tenant id'), data=data, headers=headers)
    access_token = r.json()['access_token']
    #Get secret from KeyVault
    headers = {"Authorization":"Bearer {}".format(access_token) }
    r = requests.get('https://{}.vault.azure.net/secrets/{}/{}?api-version=2015-06-01'.format(vault_name, secret_name, secret_version), headers=headers)
    result = r.json()
    if 'value' in result.keys():
        return result["value"]
    else: 
        return 'Secret Not Found'

def searchSecret(secret_name, secret_version = ''):
subscription_id = 'subscription id'    
credentials = ServicePrincipalCredentials(
        client_id= 'appidxx',
        secret= 'appsecretxx',
        tenant= 'tenantidxx'
    )

    kvm_client = KeyVaultManagementClient(credentials,  subscription_id )
    for vault in kvm_client.vaults.list():
        #return when secret found in vault
        secret = getSecret(vault.name, secret_name, secret_version = '')
        if (secret != 'Secret Not Found'):
            return secret
    return 'Secret Not Found'

Also I have registered my app in azure portal and granted permissions to my keys and secrets, however i noticed that when granting access to my app through access policy, the "Authorized application" option is locked and i cannot add my app, which may be the root cause of my issue?? screenshot

2
What is the Http status code return? 401?EagleDev
Side note: you can use https://login.microsoftonline.com instead of https://login.windows.net. Though it won't fix the problem. At a glance I could not see anything really wrong with the code. The authorized application thing in Key Vault is not needed. You granted permissions to the service principal.juunas
Not a direct answer, but why are you using azure-mgmt-keyvault to list the vaults, but direct Rest calls and not azure-keyvault to read the secret?Laurent Mazuel
thuan, im not getting any http error just not getting access to the secrets. juunas oh ok i really thought that could have been the problem. @laurent i didnt think there was a different way of reading the secrets as im quiet new to azure. i thought azure-keyvault only lists the keys, pls is there a better of doing this?flowstack
You should give your service principal(sp) access your key vault permission. Like this imgur.com/a/mrth1Shui shengbao

2 Answers

-1
votes

Firstly, you should give your service principal access your key vault permission. Like this https://imgur.com/a/mrth1.

I test your code by using getSecret('shui','shui02','b89f7498e8c64b6c9365e0eda55b4b5b'), it works for me.

import requests
def getSecret(vault_name, secret_name, secret_version = ''):
    #Get acess token to azure account
    data = { "grant_type" : "client_credentials", 
            "client_id" : '*******', 
            "client_secret" : '*******', 
            "resource" : "https://vault.azure.net"
        }
    headers = { "Content-Type" : "application/x-www-form-urlencoded" }
    r = requests.post("https://login.windows.net/{}/oauth2/token".format('*******'), data=data, headers=headers)
    access_token = r.json()['access_token']
    #Get secret from KeyVault
    headers = {"Authorization":"Bearer {}".format(access_token) }
    r = requests.get('https://{}.vault.azure.net/secrets/{}/{}?api-version=2015-06-01'.format(vault_name, secret_name, secret_version), headers=headers)
    print r
    result = r.json()
    if 'value' in result.keys():
        return result["value"]
    else: 
        return 'Secret Not Found'
getSecret('shui','shui02','b89f7498e8c64b6c9365e0eda55b4b5b')
2
votes

If you want to access secrets more easily using the Azure SDK, there are new packages for working with Key Vault in Python that replace azure-keyvault:

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

Documentation for working with the secrets library can be found on the azure-sdk-for-python GitHub repository, and here's a sample for retrieving secrets as you were doing:

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

credential = DefaultAzureCredential()
subscription_id = "subscription id"

def getSecret(vault_url, secret_name, secret_version=None):
    client = SecretClient(vault_url, credential)
    # list the secrets in the vault
    secret_properties = client.list_properties_of_secrets()
    for secret_property in secret_properties:
        if secret_property.name == secret_name:
            # get secret from Key Vault
            return client.get_secret(secret_name, secret_version)
    return "Secret Not Found"

def searchSecret(secret_name, secret_version=None):
    kvm_client = KeyVaultManagementClient(credential, subscription_id)
    for vault in kvm_client.vaults.list():
        # return when secret found in vault
        secret = getSecret(vault.properties.vault_uri, secret_name, secret_version)
        if secret != "Secret Not Found":
            return secret
    return "Secret Not Found"

You can provide the same credentials that you used for ServicePrincipalCredentials by setting environment variables corresponding to the client_id, secret, and tenant:

export AZURE_CLIENT_ID="appidxx"
export AZURE_CLIENT_SECRET="appsecretxx"
export AZURE_TENANT_ID="tenantidxx"

(I work on the Azure SDK in Python)