英文:
accessing keyvault secrets from azure functions fails
问题
由于某些限制,我无法首先在本地测试 Azure 函数,然后再部署它。
因此,我们采用了使用流水线的方法来解决这个问题。
我在 Azure Git 中有一个存储库,在其中有一个文件夹(azure-functions),其中包含 init.py、functions.json 和 requirement.txt。
我使用以下脚本在流水线 yaml 中创建一个新函数。
func init LocalFunctionProj --python
cd LocalFunctionProj
func new --name TimeTrigger --template "Timer trigger" --schedule "0 */5 * * * *"
现在,上述命令创建了一个新的 init.py、functions.json 和 requirement.txt。
我将这些文件的内容从 azure-functions(在我的存储库中)复制到上面创建的文件中。
现在,我有一个 init.py,在其中我尝试访问虚拟关键词值,但最终遇到了模块未找到的错误。
init.py
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
#from azure.keyvault.secrets import SecretClient
#from azure.identity import DefaultAzureCredential
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"XXXXXX"
credential = az_identity.DefaultAzureCredential()
logging.info('credential info is %s',credential)
#client = SecretClient(vault_url=KVUri, credential=credential)
client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
requirement.txt 包含以下条目:
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
我使用流水线部署函数,并且部署成功。
时间触发器的响应显示如下:
Result: Failure Exception: ModuleNotFoundError: No module named 'azure.keyvault'. Please check the requirements.txt file for the missing module. For more info, please refer the troubleshooting guide: https://aka.ms/functions-modulenotfound Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 380, in _handle__function_load_request func = loader.load_function( File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 48, in call raise extend_exception_message(e, message) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 44, in call return func(*args, **kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/loader.py", line 132, in load_function mod = importlib.import_module(fullmodname) File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "/home/site/wwwroot/TimeTrigger/__init__.py", line 5, in <module> import azure.keyvault.secrets as kv_secrets
英文:
Due to some limitations, I am not able to test the azure function first locally and then deploy it.
So, we have followed the approach of working around, with the use of pipelines.
I have a repository in Azure git, where I have a folder (azure-functions) containing init.py, functions.json and requirement.txt.
I create a new function from the pipeline using the following script inside the pipeline yaml.
func init LocalFunctionProj --python
cd LocalFunctionProj
func new --name TimeTrigger --template "Timer trigger" --schedule "0 */5 * * * *"
Now the above command creates a new init.py , functions.json and the requirement.txt.
I copy the contents of the files from azure-functions(in my repo) to these files created above.
Now, I have the init.py where I try to access the dummy keyvault value, but end up facing with the module not found error.
init.py
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
#from azure.keyvault.secrets import SecretClient
#from azure.identity import DefaultAzureCredential
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"XXXXXX"
credential = az_identity.DefaultAzureCredential()
logging.info('credential info is %s',credential)
#client = SecretClient(vault_url=KVUri, credential=credential)
client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
The requirement.txt has the following entries :
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
I deploy the function using the pipeline itself, and it is successful.
The time triggered response shows the following:
Result: Failure Exception: ModuleNotFoundError: No module named 'azure.keyvault'. Please check the requirements.txt file for the missing module. For more info, please refer the troubleshooting guide: https://aka.ms/functions-modulenotfound Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 380, in _handle__function_load_request func = loader.load_function( File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 48, in call raise extend_exception_message(e, message) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 44, in call return func(*args, **kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/loader.py", line 132, in load_function mod = importlib.import_module(fullmodname) File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "/home/site/wwwroot/TimeTrigger/__init__.py", line 5, in <module> import azure.keyvault.secrets as kv_secrets
答案1
得分: 1
I tried running pip install -r requirements.txt
and then ran func host start
and the Function ran but it gave an error in your init.py code.
My requirements.txt:
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
azure-keyvault
As azure identity class does not include SecretClient, It gave an error. I replaced your code -
client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
with the code below and it worked, I also replaced DefaultAzureCredentials
with AzureCliCredentials
like below:-
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"https://keyvaultvalley.vault.azure.net/"
credential = az_identity.AzureCliCredential()
# Use SecretClient from azure.keyvault.secrets
client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
Local:-
But AzureCliCredentials won't work in Azure Functions Deployment via Devops as Function app cannot authenticate with your Azure account and key vault via CLI as the interactive authentication is not supported in Function app. One option is to create Azure Service principal and assign it a role to Key vault and deploy the code in function app another way is to authenticate the existing code with ManagedIdentityCredentials with Function app.
init.py with ManagedIdentityCredentials:-
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
az_identity.ManagedIdentityCredential()
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"https://keyvaultvalley.vault.azure.net/"
credential = az_identity.ManagedIdentityCredential()
# Use SecretClient from azure.keyvault.secrets
client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
Enable System assigned managed identity for your Function app
like below:-
Add Key vault Contributor role to Above Function app managed identity
on Key vault and assign access policy to access Secret on Key vault.
Now, I uploaded my Function source code file to Azure repository and ran the Pipeline in Devops like below:-
My Azure repository:-
My function.json:-
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */1 * * * *"
}
]
}
host.json:-
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}
requirements.txt:-
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
azure-keyvault
*Select new Pipeline your Azure repository with functions code and use existing template like below:-
Select your subscription correctly and your Function app when asked for prompt after selection the option above.
Yaml pipeline script:-
trigger:
- main
variables:
azureSubscription: 'xxxxxxxx4-c61cd03e7111'
functionAppName: 'siliconfunc210'
vmImageName: 'ubuntu-latest'
workingDirectory: '$(System.DefaultWorkingDirectory)/'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
fi
workingDirectory: $(workingDirectory)
displayName: 'Build extensions'
- task: UsePythonVersion@0
displayName: 'Use Python 3.10'
inputs:
versionSpec: 3.10
- bash: |
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
workingDirectory: $(workingDirectory)
displayName: &#
<details>
<summary>英文:</summary>
I tried running `pip install -r requirements.txt` and then ran `func host start` and the Function ran but it gave an error in your init.py code.
**My requirements.txt:-**
```txt
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
azure-keyvault
As azure identity class does not include SecretClient, It gave an error. I replaced your code -
client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
with the code below and it worked, I also replaced DefaultAzureCredentials
with AzureCliCredentials
like below:-
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"https://keyvaultvalley.vault.azure.net/"
credential = az_identity.AzureCliCredential()
# Use SecretClient from azure.keyvault.secrets
client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
Local:-
But AzureCliCredentials won't work in Azure Functions Deployment via Devops as Function app cannot authenticate with your Azure account and key vault via CLI as the interactive authentication is not supported in Function app. One option is to create Azure Service principal and assign it a role to Key vault and deploy the code in function app another way is to authenticate the existing code with ManagedIdentityCredentials with Function app.
init.py with ManagedIdentityCredentials:-
import datetime
import logging
import azure.functions as func
import azure.keyvault.secrets as kv_secrets
import azure.identity as az_identity
az_identity.ManagedIdentityCredential()
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
KVUri = f"https://keyvaultvalley.vault.azure.net/"
credential = az_identity.ManagedIdentityCredential()
# Use SecretClient from azure.keyvault.secrets
client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
password = client.get_secret('TestSecret').value
logging.info('Secret value is %s', password)
logging.info('Hello!! Good day!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
Enable System assigned managed identity for your Function app
like below:-
Add Key vault Contributor role to Above Function app managed identity
on Key vault and assign access policy to access Secret on Key vault.
Now, I uploaded my Function source code file to Azure repository and ran the Pipeline in Devops like below:-
My Azure repository:-
My function.json:-
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */1 * * * *"
}
]
}
host.json:-
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}
requirements.txt:-
azure-functions
azure-common==1.1.28
azure-core==1.28.0
azure-identity==1.13.0
azure-keyvault-secrets==4.7.0
azure-keyvault
Select new Pipeline your Azure repository with functions code and use existing template like below:-
Select your subscription correctly and your Function app when asked for prompt after selection the option above.
Yaml pipeline script:-
trigger:
- main
variables:
azureSubscription: 'xxxxxxxx4-c61cd03e7111'
functionAppName: 'siliconfunc210'
vmImageName: 'ubuntu-latest'
workingDirectory: '$(System.DefaultWorkingDirectory)/'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
fi
workingDirectory: $(workingDirectory)
displayName: 'Build extensions'
- task: UsePythonVersion@0
displayName: 'Use Python 3.10'
inputs:
versionSpec: 3.10
- bash: |
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
workingDirectory: $(workingDirectory)
displayName: 'Install application dependencies'
- task: ArchiveFiles@2
displayName: 'Archive files'
inputs:
rootFolderOrFile: '$(workingDirectory)'
includeRootFolder: false
archiveType: zip
archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
replaceExistingArchive: true
- publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
artifact: drop
- stage: Deploy
displayName: Deploy stage
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
displayName: Deploy
environment: 'development'
pool:
vmImage: $(vmImageName)
strategy:
runOnce:
deploy:
steps:
- task: AzureFunctionApp@1
displayName: 'Azure functions app deploy'
inputs:
azureSubscription: '$(azureSubscription)'
appType: functionAppLinux
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
Devops pipeline ran successfully:-
Output Azure Function app:-
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论