PhD in Computer science, data scientist at Consid AB.
The following describes how an Azure Function written in Python3 can access secrets stored in an Azure Keyvault using ManagedIdentityCredential.
Microsofts documentation on Azure Functions describes the most important steps.
Login and create app (assumes that storage account already exitst).
az login --use-device-code
az functionapp list \
--resource-group ${RESOURCE_GROUP} \
--subscription ${SUBSCRIPTION}
az config param-persist on
az functionapp create \
-n ${FUNCTION_APP} \
--storage-account ${STORAGE_ACCOUNT_NAME} \
--consumption-plan-location ${LOCATION} \
--runtime python \
--resource-group ${RESOURCE_GROUP}
The most of the following descriptions are adopted from Mark Heath’s blog.
az keyvault create -n ${KEY_VAULT_NAME} --resource-group ${RESOURCE_GROUP}
# Save a secret in the key vault
SECRET_NAME="MySecret"
az keyvault secret set -n ${SECRET_NAME} --vault-name ${KEY_VAULT_NAME} \
--value "Super secret value!"
# View the secret
az keyvault secret show -n ${SECRET_NAME} --vault-name ${KEY_VAULT_NAME}
# Get the principalId from the functionapp
PRINCIPAL_ID=$(az functionapp identity show -n ${FUNCTION_APP} --query principalId)
# Assign a managed identity
az functionapp identity assign --name ${FUNCTION_APP} --resource-group ${RESOURCE_GROUP}
# Grant the Managed Identity Read Access to Key Vault
az keyvault set-policy -n ${KEY_VAULT_NAME} \
--object-id ${PRINCIPAL_ID} \
--resource-group ${RESOURCE_GROUP} \
--secret-permissions get list
The following is an example Python code that can be used to access secrets stored in the Key Vault.
File ${FUNCTION_APP}/requrements.txt
azure-functions==1.6.0
azure-identity==1.5.0
azure-keyvault-secrets==4.2.0
File ${FUNCTION_APP}/read_secrets/function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["get"]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
File ${FUNCTION_APP}/read_secrets/__init__.py
import logging
import azure.functions as func
from azure.identity.aio import ManagedIdentityCredential
from azure.keyvault.secrets.aio import SecretClient
KEY_VAULT = "change me to the right key vault"
KEY_VAULT_URL = f"https://{KEY_VAULT}.vault.azure.net/"
KV_ONE = "name of first secret"
KV_TWO = "name of second secret"
async def read_keys(secrets):
ret = {}
try:
async with SecretClient(
vault_url=KEY_VAULT_URL,
credential=ManagedIdentityCredential(),
logging_enable=True,
) as secret_client:
for secret in secrets:
ret[secret] = (await secret_client.get_secret(secret)).value
except Exception as excep:
logging.error("%s", excep)
finally:
await secret_client.close()
return ret
async def main(req: func.HttpRequest) -> func.HttpResponse:
"""Main function."""
logging.info("Python HTTP trigger function processed a request.")
secrets = await read_keys(
(KV_ONE, KV_TWO)
)
logging.debug("%s", secrets.keys())
return func.HttpResponse(
f'{{"status": "ok", "read secrets": "{secrets.keys()}"}}',
mimetype="application/json",
status_code=200,
)
Don’t forget to publish the updated function.
func azure functionapp publish ${FUNCTION_APP}