从Azure函数访问KeyVault机密失败。

huangapple go评论132阅读模式
英文:

accessing keyvault secrets from azure functions fails

问题

由于某些限制,我无法首先在本地测试 Azure 函数,然后再部署它。
因此,我们采用了使用流水线的方法来解决这个问题。
我在 Azure Git 中有一个存储库,在其中有一个文件夹(azure-functions),其中包含 init.py、functions.json 和 requirement.txt。

我使用以下脚本在流水线 yaml 中创建一个新函数。

  1. func init LocalFunctionProj --python
  2. cd LocalFunctionProj
  3. func new --name TimeTrigger --template "Timer trigger" --schedule "0 */5 * * * *"

现在,上述命令创建了一个新的 init.py、functions.json 和 requirement.txt。
我将这些文件的内容从 azure-functions(在我的存储库中)复制到上面创建的文件中。

现在,我有一个 init.py,在其中我尝试访问虚拟关键词值,但最终遇到了模块未找到的错误。

init.py

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. #from azure.keyvault.secrets import SecretClient
  7. #from azure.identity import DefaultAzureCredential
  8. def main(mytimer: func.TimerRequest) -> None:
  9. utc_timestamp = datetime.datetime.utcnow().replace(
  10. tzinfo=datetime.timezone.utc).isoformat()
  11. if mytimer.past_due:
  12. logging.info('The timer is past due!')
  13. KVUri = f"XXXXXX"
  14. credential = az_identity.DefaultAzureCredential()
  15. logging.info('credential info is %s',credential)
  16. #client = SecretClient(vault_url=KVUri, credential=credential)
  17. client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
  18. password = client.get_secret('TestSecret').value
  19. logging.info('Secret value is %s', password)
  20. logging.info('Hello!! Good day!')
  21. logging.info('Python timer trigger function ran at %s', utc_timestamp)

requirement.txt 包含以下条目:

  1. azure-functions
  2. azure-common==1.1.28
  3. azure-core==1.28.0
  4. azure-identity==1.13.0
  5. azure-keyvault-secrets==4.7.0

我使用流水线部署函数,并且部署成功。
时间触发器的响应显示如下:

  1. 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.

  1. func init LocalFunctionProj --python
  2. cd LocalFunctionProj
  3. 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

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. #from azure.keyvault.secrets import SecretClient
  7. #from azure.identity import DefaultAzureCredential
  8. def main(mytimer: func.TimerRequest) -> None:
  9. utc_timestamp = datetime.datetime.utcnow().replace(
  10. tzinfo=datetime.timezone.utc).isoformat()
  11. if mytimer.past_due:
  12. logging.info('The timer is past due!')
  13. KVUri = f"XXXXXX"
  14. credential = az_identity.DefaultAzureCredential()
  15. logging.info('credential info is %s',credential)
  16. #client = SecretClient(vault_url=KVUri, credential=credential)
  17. client = az_identity.SecretClient(vault_url=KVUri, credential=credential)
  18. password = client.get_secret('TestSecret').value
  19. logging.info('Secret value is %s', password)
  20. logging.info('Hello!! Good day!')
  21. logging.info('Python timer trigger function ran at %s', utc_timestamp)

The requirement.txt has the following entries :

  1. azure-functions
  2. azure-common==1.1.28
  3. azure-core==1.28.0
  4. azure-identity==1.13.0
  5. 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:

  1. 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:

  1. azure-functions
  2. azure-common==1.1.28
  3. azure-core==1.28.0
  4. azure-identity==1.13.0
  5. azure-keyvault-secrets==4.7.0
  6. azure-keyvault

As azure identity class does not include SecretClient, It gave an error. I replaced your code -

  1. client = az_identity.SecretClient(vault_url=KVUri, credential=credential)

with the code below and it worked, I also replaced DefaultAzureCredentials with AzureCliCredentials like below:-

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. def main(mytimer: func.TimerRequest) -> None:
  7. utc_timestamp = datetime.datetime.utcnow().replace(
  8. tzinfo=datetime.timezone.utc).isoformat()
  9. if mytimer.past_due:
  10. logging.info('The timer is past due!')
  11. KVUri = f"https://keyvaultvalley.vault.azure.net/"
  12. credential = az_identity.AzureCliCredential()
  13. # Use SecretClient from azure.keyvault.secrets
  14. client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
  15. password = client.get_secret('TestSecret').value
  16. logging.info('Secret value is %s', password)
  17. logging.info('Hello!! Good day!')
  18. logging.info('Python timer trigger function ran at %s', utc_timestamp)

Local:-

从Azure函数访问KeyVault机密失败。

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:-

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. az_identity.ManagedIdentityCredential()
  7. def main(mytimer: func.TimerRequest) -> None:
  8. utc_timestamp = datetime.datetime.utcnow().replace(
  9. tzinfo=datetime.timezone.utc).isoformat()
  10. if mytimer.past_due:
  11. logging.info('The timer is past due!')
  12. KVUri = f"https://keyvaultvalley.vault.azure.net/"
  13. credential = az_identity.ManagedIdentityCredential()
  14. # Use SecretClient from azure.keyvault.secrets
  15. client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
  16. password = client.get_secret('TestSecret').value
  17. logging.info('Secret value is %s', password)
  18. logging.info('Hello!! Good day!')
  19. logging.info('Python timer trigger function ran at %s', utc_timestamp)

Enable System assigned managed identity for your Function app like below:-

从Azure函数访问KeyVault机密失败。

Add Key vault Contributor role to Above Function app managed identity on Key vault and assign access policy to access Secret on Key vault.

从Azure函数访问KeyVault机密失败。

从Azure函数访问KeyVault机密失败。

Now, I uploaded my Function source code file to Azure repository and ran the Pipeline in Devops like below:-

My Azure repository:-

从Azure函数访问KeyVault机密失败。

My function.json:-

  1. {
  2. "scriptFile": "__init__.py",
  3. "bindings": [
  4. {
  5. "name": "mytimer",
  6. "type": "timerTrigger",
  7. "direction": "in",
  8. "schedule": "0 */1 * * * *"
  9. }
  10. ]
  11. }

host.json:-

  1. {
  2. "version": "2.0",
  3. "logging": {
  4. "applicationInsights": {
  5. "samplingSettings": {
  6. "isEnabled": true,
  7. "excludedTypes": "Request"
  8. }
  9. }
  10. },
  11. "extensionBundle": {
  12. "id": "Microsoft.Azure.Functions.ExtensionBundle",
  13. "version": "[3.*, 4.0.0)"
  14. }
  15. }

requirements.txt:-

  1. azure-functions
  2. azure-common==1.1.28
  3. azure-core==1.28.0
  4. azure-identity==1.13.0
  5. azure-keyvault-secrets==4.7.0
  6. azure-keyvault

*Select new Pipeline your Azure repository with functions code and use existing template like below:-

从Azure函数访问KeyVault机密失败。

Select your subscription correctly and your Function app when asked for prompt after selection the option above.

Yaml pipeline script:-

  1. trigger:
  2. - main
  3. variables:
  4. azureSubscription: 'xxxxxxxx4-c61cd03e7111'
  5. functionAppName: 'siliconfunc210'
  6. vmImageName: 'ubuntu-latest'
  7. workingDirectory: '$(System.DefaultWorkingDirectory)/'
  8. stages:
  9. - stage: Build
  10. displayName: Build stage
  11. jobs:
  12. - job: Build
  13. displayName: Build
  14. pool:
  15. vmImage: $(vmImageName)
  16. steps:
  17. - bash: |
  18. if [ -f extensions.csproj ]
  19. then
  20. dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
  21. fi
  22. workingDirectory: $(workingDirectory)
  23. displayName: 'Build extensions'
  24. - task: UsePythonVersion@0
  25. displayName: 'Use Python 3.10'
  26. inputs:
  27. versionSpec: 3.10
  28. - bash: |
  29. pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
  30. workingDirectory: $(workingDirectory)
  31. displayName: &#
  32. <details>
  33. <summary>英文:</summary>
  34. 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.
  35. **My requirements.txt:-**
  36. ```txt
  37. azure-functions
  38. azure-common==1.1.28
  39. azure-core==1.28.0
  40. azure-identity==1.13.0
  41. azure-keyvault-secrets==4.7.0
  42. azure-keyvault

As azure identity class does not include SecretClient, It gave an error. I replaced your code -

  1. client = az_identity.SecretClient(vault_url=KVUri, credential=credential)

with the code below and it worked, I also replaced DefaultAzureCredentials with AzureCliCredentials like below:-

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. def main(mytimer: func.TimerRequest) -&gt; None:
  7. utc_timestamp = datetime.datetime.utcnow().replace(
  8. tzinfo=datetime.timezone.utc).isoformat()
  9. if mytimer.past_due:
  10. logging.info(&#39;The timer is past due!&#39;)
  11. KVUri = f&quot;https://keyvaultvalley.vault.azure.net/&quot;
  12. credential = az_identity.AzureCliCredential()
  13. # Use SecretClient from azure.keyvault.secrets
  14. client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
  15. password = client.get_secret(&#39;TestSecret&#39;).value
  16. logging.info(&#39;Secret value is %s&#39;, password)
  17. logging.info(&#39;Hello!! Good day!&#39;)
  18. logging.info(&#39;Python timer trigger function ran at %s&#39;, utc_timestamp)

Local:-

从Azure函数访问KeyVault机密失败。

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:-

  1. import datetime
  2. import logging
  3. import azure.functions as func
  4. import azure.keyvault.secrets as kv_secrets
  5. import azure.identity as az_identity
  6. az_identity.ManagedIdentityCredential()
  7. def main(mytimer: func.TimerRequest) -&gt; None:
  8. utc_timestamp = datetime.datetime.utcnow().replace(
  9. tzinfo=datetime.timezone.utc).isoformat()
  10. if mytimer.past_due:
  11. logging.info(&#39;The timer is past due!&#39;)
  12. KVUri = f&quot;https://keyvaultvalley.vault.azure.net/&quot;
  13. credential = az_identity.ManagedIdentityCredential()
  14. # Use SecretClient from azure.keyvault.secrets
  15. client = kv_secrets.SecretClient(vault_url=KVUri, credential=credential)
  16. password = client.get_secret(&#39;TestSecret&#39;).value
  17. logging.info(&#39;Secret value is %s&#39;, password)
  18. logging.info(&#39;Hello!! Good day!&#39;)
  19. logging.info(&#39;Python timer trigger function ran at %s&#39;, utc_timestamp)

Enable System assigned managed identity for your Function app like below:-

从Azure函数访问KeyVault机密失败。

Add Key vault Contributor role to Above Function app managed identity on Key vault and assign access policy to access Secret on Key vault.

从Azure函数访问KeyVault机密失败。

从Azure函数访问KeyVault机密失败。

Now, I uploaded my Function source code file to Azure repository and ran the Pipeline in Devops like below:-

My Azure repository:-

从Azure函数访问KeyVault机密失败。

My function.json:-

  1. {
  2. &quot;scriptFile&quot;: &quot;__init__.py&quot;,
  3. &quot;bindings&quot;: [
  4. {
  5. &quot;name&quot;: &quot;mytimer&quot;,
  6. &quot;type&quot;: &quot;timerTrigger&quot;,
  7. &quot;direction&quot;: &quot;in&quot;,
  8. &quot;schedule&quot;: &quot;0 */1 * * * *&quot;
  9. }
  10. ]
  11. }

host.json:-

  1. {
  2. &quot;version&quot;: &quot;2.0&quot;,
  3. &quot;logging&quot;: {
  4. &quot;applicationInsights&quot;: {
  5. &quot;samplingSettings&quot;: {
  6. &quot;isEnabled&quot;: true,
  7. &quot;excludedTypes&quot;: &quot;Request&quot;
  8. }
  9. }
  10. },
  11. &quot;extensionBundle&quot;: {
  12. &quot;id&quot;: &quot;Microsoft.Azure.Functions.ExtensionBundle&quot;,
  13. &quot;version&quot;: &quot;[3.*, 4.0.0)&quot;
  14. }
  15. }

requirements.txt:-

  1. azure-functions
  2. azure-common==1.1.28
  3. azure-core==1.28.0
  4. azure-identity==1.13.0
  5. azure-keyvault-secrets==4.7.0
  6. azure-keyvault

Select new Pipeline your Azure repository with functions code and use existing template like below:-

从Azure函数访问KeyVault机密失败。

Select your subscription correctly and your Function app when asked for prompt after selection the option above.

Yaml pipeline script:-

  1. trigger:
  2. - main
  3. variables:
  4. azureSubscription: &#39;xxxxxxxx4-c61cd03e7111&#39;
  5. functionAppName: &#39;siliconfunc210&#39;
  6. vmImageName: &#39;ubuntu-latest&#39;
  7. workingDirectory: &#39;$(System.DefaultWorkingDirectory)/&#39;
  8. stages:
  9. - stage: Build
  10. displayName: Build stage
  11. jobs:
  12. - job: Build
  13. displayName: Build
  14. pool:
  15. vmImage: $(vmImageName)
  16. steps:
  17. - bash: |
  18. if [ -f extensions.csproj ]
  19. then
  20. dotnet build extensions.csproj --runtime ubuntu.16.04-x64 --output ./bin
  21. fi
  22. workingDirectory: $(workingDirectory)
  23. displayName: &#39;Build extensions&#39;
  24. - task: UsePythonVersion@0
  25. displayName: &#39;Use Python 3.10&#39;
  26. inputs:
  27. versionSpec: 3.10
  28. - bash: |
  29. pip install --target=&quot;./.python_packages/lib/site-packages&quot; -r ./requirements.txt
  30. workingDirectory: $(workingDirectory)
  31. displayName: &#39;Install application dependencies&#39;
  32. - task: ArchiveFiles@2
  33. displayName: &#39;Archive files&#39;
  34. inputs:
  35. rootFolderOrFile: &#39;$(workingDirectory)&#39;
  36. includeRootFolder: false
  37. archiveType: zip
  38. archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
  39. replaceExistingArchive: true
  40. - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
  41. artifact: drop
  42. - stage: Deploy
  43. displayName: Deploy stage
  44. dependsOn: Build
  45. condition: succeeded()
  46. jobs:
  47. - deployment: Deploy
  48. displayName: Deploy
  49. environment: &#39;development&#39;
  50. pool:
  51. vmImage: $(vmImageName)
  52. strategy:
  53. runOnce:
  54. deploy:
  55. steps:
  56. - task: AzureFunctionApp@1
  57. displayName: &#39;Azure functions app deploy&#39;
  58. inputs:
  59. azureSubscription: &#39;$(azureSubscription)&#39;
  60. appType: functionAppLinux
  61. appName: $(functionAppName)
  62. package: &#39;$(Pipeline.Workspace)/drop/$(Build.BuildId).zip&#39;

Devops pipeline ran successfully:-

从Azure函数访问KeyVault机密失败。

Output Azure Function app:-

从Azure函数访问KeyVault机密失败。

huangapple
  • 本文由 发表于 2023年8月10日 15:08:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873358.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定