Azure Function Apps Get Secrets
Description:
This is currently how I have my Function Apps getting secrets.
To Resolve:
-
Let’s look at the following functions declared in our standard
shared/helpers.py
found in many of my python Github Repos (for example):1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
def import_creds(): ''' Gets secrets from Azure Keyvault as an application Secret values are stored in the Function App under Configuration Example of how to call from main(): keyvault_creds = import_creds() logging.info(f"client_id: { keyvault_creds['client_id'] }") logging.info(f"client_secret: { keyvault_creds['client_secret'] }") logging.info(f"tenant: { keyvault_creds['tenant'] }") logging.info(f"vault_name: { keyvault_creds['vault_name'] }") ''' try: creds = {} creds["client_id"] = os.environ["client_id"] creds["client_secret"] = os.environ["client_secret"] creds["tenant"] = os.environ["tenant"] creds["vault_name"] = os.environ["vault_name"] except KeyError: logging.error("Unable to get env vars") except Exception as e: logging.error(f"Generic Catch: {str(e)}") return creds def get_oauth(tenant, client_id, client_secret): ''' Gets an Oauth token from Graph API as an application See the scope in the payload where the application is scoped to just Key Vault Example of how to call from main(): token = get_oauth( tenant = keyvault_creds['tenant'], client_id = keyvault_creds['client_id'], client_secret = keyvault_creds['client_secret'] ) ''' url = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" payload = "grant_type=client_credentials"\ f"&client_id={client_id}"\ f"&client_secret={client_secret}"\ "&scope=https%3A%2F%2Fvault.azure.net%2F.default" headers = {'Content-Type': 'application/x-www-form-urlencoded'} response = requests.request("POST", url, headers=headers, data=payload) r = response.json() return r def get_secret(token, vault_name, secret_name): ''' Using an Oauth token, gets the latest version of a secret Example of how to call from main(): secret = get_secret( token = token["access_token"], vault_name = keyvault_creds['vault_name'], secret_name = 'test' ) logging.info(f"Secret value is : {secret['value']}") ''' # Gets the latest version of a secret url = f"https://{vault_name}.vault.azure.net/secrets/{secret_name}?api-version=7.1" # for a specific version of the secret, replace {version} # version = "aadsfasdfasdfasdf" # url = f"https://{vault_name}.vault.azure.net/secrets/test/{version}?api-version=7.1" payload = {} headers = {"Authorization": f"Bearer {token}"} response = requests.request("GET", url, headers=headers, data=payload) r = response.json() return r def get_sn_username(): ''' Using a combination of get_oauth() and get_secret() functions, This will get an oauth token and retrieve the latest version of a secret Example of how to call from main(): sn_username = get_sn_username() logging.info(f"Secret value is : {sn_username}") ''' keyvault_creds = import_creds() token = get_oauth(tenant=keyvault_creds['tenant'], client_id=keyvault_creds['client_id'], client_secret=keyvault_creds['client_secret']) secret = get_secret(token=token["access_token"], vault_name=keyvault_creds['vault_name'], secret_name='ServiceNow-Username') return secret['value']
-
First, notice the
get_sn_username
function which will get the username for an API user for Service Now.- It first creates
keyvault_creds
by querying the Function App’s environmental variables. It is crucial that certain values are set in theConfiguration
blade in Azure for this to work as dicussed in my Function App post - It then calls
get_oauth
which relies on those credentials to be correct to get an Oauth token. - It then passes that token to the Azure Keyvault to get a secret.
- Finally, it returns the plain text version of the secret to whatever calls it.
- It first creates
Comments