简体   繁体   English

脚本如何访问服务连接? (Azure Devops 管道)

[英]How can a script access Service Connections? (Azure Devops Pipelines)

According to https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints there's a rich array of Service Connection types.根据https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints有丰富的服务连接类型。 I can easily manage a set of service connections at the project level and set permissions to limit which users are able to view/edit them -- this is all good.我可以轻松地在项目级别管理一组服务连接并设置权限以限制哪些用户能够查看/编辑它们——这一切都很好。

But I can't figure out how to access a Service Connection with a script step in my build pipeline.但我不知道如何在构建管道中使用脚本步骤访问服务连接。 For example, let's say I have a Service Connection representing credentials for an Azure Service Principal.例如,假设我有一个代表 Azure 服务主体凭据的服务连接。 I'd like to access those credentials in a script step.我想在脚本步骤中访问这些凭据。

How can I write a script step that makes use of them?如何编写使用它们的脚本步骤?

Because a Service Connection involves data shaped specifically to the connected service (the Generic Service Connection being the exception that proves the rule...), you won't be able to make use of strongly typed properties in your Bash task.因为服务连接涉及专门为连接的服务塑造的数据( 通用服务连接是证明规则的例外......),所以您将无法在 Bash 任务中使用强类型属性。 Instead, you may want to examine environment variables and process the service connection data manually.相反,您可能希望检查环境变量并手动处理服务连接数据。

Based on a survey of some of the tasks in the Azure DevOps repos, it appears that service connections and their data are populated as environment variables on the agent running the build task.根据对 Azure DevOps 存储库中某些任务的调查,服务连接及其数据似乎作为运行构建任务的代理上的环境变量填充。 The service connections are retrieved via a method that runs a given name string through the following regex before retrieving the resultant environment key's value:在检索结果环境键的值之前,通过以下正则表达式运行给定name字符串的方法检索服务连接:

process.env[name.replace(/\\./g, '_').toUpperCase()];

The retrieval of various Service Endpoint data is wrapped in the vsts-task-lib/task module , allowing consuming tasks to write code like so:各种 Service Endpoint 数据的检索被封装在vsts-task-lib/task 模块中,允许消费任务编写如下代码:

taskLib.getEndpointAuthorization('SYSTEMVSSCONNECTION', false);

taskLib.getEndpointDataParameter('MYSERVICECONNECTION', 'SOME_PARAMETER_NAME', false);

taskLib.getEndpointUrl('MYSERVICECONNECTION', false) // <-- last param indicates required or not

Therefore, if you wanted to access service connections in a bash script without any additional customization, I would recommend that you:因此,如果您想在 bash 脚本中访问服务连接而不进行任何额外的自定义,我建议您:

a) Validate the availability of service connection information in the build script task by iterating and writing environment variables, setting the system.debug environment variable. a) 通过迭代写入环境变量,设置system.debug环境变量,验证构建脚本任务中服务连接信息的可用性。 There's some indication that build tasks aren't "seeded" with connections they aren't requesting specifically, so you may need to create a custom build task which has as one of its' inputs the service connection name you want to use有一些迹象表明构建任务没有“播种”它们没有专门请求的连接,因此您可能需要创建一个自定义构建任务,该任务将您要使用的服务连接名称作为其输入之一

b) read the desired values from variables as outlined above in your bash script. b) 从上面概述的 bash 脚本中的变量中读取所需的值。 Service connection variable names may be computed similarly to this :服务连接变量名可以类似地计算到这个

   var dataParam = getVariable('ENDPOINT_DATA_' + id + '_' + key.toUpperCase());  

You may need to iterate against this to determine the data schema/structure.您可能需要对此进行迭代以确定数据模式/结构。

I've been wondering about this too.我也一直在想这个问题。 The solution I've settled on is to use the ' Azure CLI ' task rather than the basic 'Script' (or 'Bash') task.我确定的解决方案是使用“ Azure CLI ”任务而不是基本的“脚本”(或“Bash”)任务。 This is ostensibly for running Az CLI commands, but there's nothing to stop you running only standard Bash scripts (or PSCore if that's your thing).这表面上是为了运行 Az CLI 命令,但没有什么可以阻止您只运行标准的 Bash 脚本(或者 PSCore,如果那是你的事)。

If you examine the environment variables present when you run this task, you'll see a bunch of information about the Service Connection in variables prefixed with 'ENDPOINT_DATA_'.如果您检查运行此任务时存在的环境变量,您将在以“ENDPOINT_DATA_”为前缀的变量中看到一堆有关服务连接的信息。 This tallies up with what Josh E was saying.这与 Josh E 所说的相符。 It includes Azure Subscription ID, name, Service Principle Object ID, etc.它包括 Azure 订阅 ID、名称、服务原则对象 ID 等。

Optionally you can enable the Service Principle details to be added to the environment too.您也可以选择将服务原则详细信息添加到环境中。 This will then include SPN key, TenantID, etc. as secret environment variables.然后,这将包括 SPN 密钥、TenantID 等作为秘密环境变量。

Here's what the tasks look like:以下是任务的样子:

- task: AzureCLI@2
  displayName: 'Azure CLI'
  inputs:
    scriptType: bash
    scriptLocation: inlineScript
    azureSubscription: '<Service Connection Name>'
    inlineScript: |
      env | sort

- task: AzureCLI@2
  displayName: 'Azure CLI, with SPN info'
  inputs:
    scriptType: bash
    scriptLocation: inlineScript
    azureSubscription: '<Service Connection Name>'
    addSpnToEnvironment: true
    inlineScript: |
      env | sort

Of course this is all only applicable to Azure Cloud Service Connections.当然,这一切只适用于 Azure 云服务连接。 There might be similar techniques you could use for other Service Connections, but I haven't investigated them.可能有类似的技术可以用于其他服务连接,但我还没有研究它们。

I found that if I use the Kubectl task with the command to login right before I run my bash Task, I do not need to authenticate or use a hostname.我发现,如果我在运行 bash 任务之前使用 Kubectl 任务和命令登录,则不需要进行身份验证或使用主机名。

KUBERNETESNODE and SERVICEPROTOCOL are Pipeline variables that I set a priori. KUBERNETESNODE 和 SERVICEPROTOCOL 是我先验设置的管道变量。

      - task: Kubernetes@1
        displayName: 'Kubernetes Login'
        # This is needed to run kubectl command from bash.
        inputs:
          connectionType: 'Kubernetes Service Connection'
          kubernetesServiceEndpoint: '<Service Connection Name>'
          command: 'login'

      - task: Bash@3
        displayName: 'Run Component Test'        
        inputs:
          targetType: 'inline'
          script: |
            #Get the Node Port
            nodePort=`kubectl get --namespace $(Build.BuildId) svc <service name> -o=jsonpath='{.spec.ports[0].nodePort}'`
            #Run Newman test
            newman run postman/Service.postman_collection.json --global-var host=$KUBERNETESNODE --global-var protocol=$SERVICEPROTOCOL --global-var port=$nodePort -r junit

I am using the same service connection in my scripts/tools as for the ARM deployments.我在脚本/工具中使用与 ARM 部署相同的服务连接。

In order to export the variables, I created the following template.为了导出变量,我创建了以下模板。

parameters:
- name: azureSubscription
  type: string
- name: exportAsOutput
  type: boolean
  default: false
  
steps:  
- task: AzureCLI@2
  name: exported_azure_credentials
  displayName: 'Export Azure Credentials'
  inputs:
    azureSubscription: '${{ parameters.azureSubscription }}'
    scriptType: pscore
    scriptLocation: inlineScript
    addSpnToEnvironment: true
    ${{ if eq(parameters.exportAsOutput, true) }}:
      inlineScript: |
        Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId"
        Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID;isOutput=true]$env:tenantId"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID;isOutput=true]$env:servicePrincipalId"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET]$env:servicePrincipalKey"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET;isOutput=true]$env:servicePrincipalKey"
    ${{ if eq(parameters.exportAsOutput, false) }}:
      inlineScript: |
        Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId"
        Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_SECRET]$env:servicePrincipalKey"

DevOps is really clever about secrets, so they do not show up in the pipeline logs. DevOps 在处理机密方面非常聪明,因此它们不会出现在管道日志中。

If you need to use the service connection to get authorized to different services/resources, you can also get the required tokens with the service connection and pass them to scripts that can't use the service connection directly, like:如果您需要使用服务连接来获得对不同服务/资源的授权,您还可以通过服务连接获取所需的令牌,并将它们传递给无法直接使用服务连接的脚本,例如:

- task: AzurePowerShell@5
  inputs:
    azureSubscription: 'AzureServiceConnection'
    ScriptType: 'InlineScript'
    Inline: |
      $token = Get-AzAccessToken 
      echo "##vso[task.setvariable variable=accesstoken;]$($token.Token)"
    azurePowerShellVersion: 'LatestVersion'
  
- script: 'echo This is the token: $(accesstoken)'

As others have stated, there isn't a great built-in way to access Service Connections with a script.正如其他人所说,没有一种很好的内置方式来使用脚本访问服务连接。 As I do not like the workaround of exposing credentials via long-lived environment variables (for security and laziness purposes), I wrote an extension that allows you to utilize a Generic Service Connection with a custom script: https://marketplace.visualstudio.com/items?itemName=cloudpup.authenticated-scripts由于我不喜欢通过长期存在的环境变量(出于安全和懒惰目的)公开凭据的解决方法,我编写了一个扩展程序,允许您使用带有自定义脚本的通用服务连接: https://marketplace.visualstudio。 com/items?itemName=cloudpup.authenticated-scripts

It does this by exposing the service connection as environment variables that only last for the lifetime of the single script task:它通过将服务连接公开为仅在单个脚本任务的生命周期内持续的环境变量来实现:

Service Connection Variable服务连接变量 Environment Variable环境变量
url网址 AS_SC_URL AS_SC_URL
username用户名 AS_SC_USERNAME AS_SC_USERNAME
password密码 AS_SC_PASSWORD AS_SC_PASSWORD

显示作为环境变量公开的服务连接的屏幕截图

Example例子

The tasks included in this extension allow you to write succinct pipelines like the following:此扩展中包含的任务允许您编写如下简洁的管道:

steps:
- task: AuthenticatedPowerShell@1  
  inputs:
    serviceConnection: 'Testing Authenticated Shell'
    targetType: inline
    script: 'Write-Host "url: $env:AS_SC_URL | username: $env:AS_SC_USERNAME | password: $env:AS_SC_PASSWORD"'

Yes this can be achieved, I use this method all of the time, you first need a task which will output the credentials into environment variables, you then create your own variables from the environment variables the task outputs, I usually use AzureCLI:是的,这可以实现,我一直使用这种方法,您首先需要一个将凭据输出到环境变量中的任务,然后从任务输出的环境变量中创建自己的变量,我通常使用 AzureCLI:

# Set Variables.
- task: AzureCLI@2
  name: setVariables
  displayName: Set Output Variables
  continueOnError: false
  inputs:
    azureSubscription: nameOfAzureServiceConnection
    scriptType: ps
    scriptLocation: inlineScript
    addSpnToEnvironment: true # this must be set to true
    inlineScript: |
      Write-Host "##vso[task.setvariable variable=azureClientId;isOutput=true]$($env:servicePrincipalId)"
      Write-Host "##vso[task.setvariable variable=azureClientSecret;isOutput=true]$($env:servicePrincipalKey)"
      Write-Host "##vso[task.setvariable variable=azureTenantId;isOutput=true]$($env:tenantId)"

Then you can use these new variables you have set in a step below, make sure you call the variables with the task name, so $(taskName.variableName), the below example uses the new variables to set environment variables in a later PowerShell task for Terraform to use for authentication:然后您可以使用您在下面的步骤中设置的这些新变量,确保您使用任务名称调用变量,因此 $(taskName.variableName),下面的示例使用新变量在稍后的 PowerShell 任务中设置环境变量Terraform 用于身份验证:

- PowerShell: |
     terraform plan -input=false -out=tfplan
 displayName: 'Terraform Plan'
 env:
   ARM_CLIENT_ID: $(setVariables.azureClientId)
   ARM_CLIENT_SECRET: $(setVariables.azureClientSecret)
   ARM_TENANT_ID: $(setVariables.azureTenantId)

ref: https://jimferrari.com/2021/11/15/access-azure-service-connection-via-script/参考: https ://jimferrari.com/2021/11/15/access-azure-service-connection-via-script/

是的,这可以实现,我使用与DELUXEnized相同的方法并且运行良好,该方法在此处更详细地显示: https : //jimferrari.com/2021/11/15/access-azure-service-connection-via- 脚本/

According to https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints there's a rich array of Service Connection types.根据https://docs.microsoft.com/zh-cn/azure/devops/pipelines/library/service-endpoints ,服务连接类型丰富。 I can easily manage a set of service connections at the project level and set permissions to limit which users are able to view/edit them -- this is all good.我可以在项目级别轻松管理一组服务连接,并设置权限以限制哪些用户可以查看/编辑它们-一切都很好。

But I can't figure out how to access a Service Connection with a script step in my build pipeline.但是我无法弄清楚如何在构建管道中使用脚本步骤访问服务连接。 For example, let's say I have a Service Connection representing credentials for an Azure Service Principal.例如,假设我有一个服务连接,代表一个Azure服务主体的凭据。 I'd like to access those credentials in a script step.我想在脚本步骤中访问这些凭据。

How can I write a script step that makes use of them?如何编写一个使用它们的脚本步骤?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 azure - how to integrate azure advanced App Service Authentication / Authorization to access azure devops API (tasks, pipelines) - azure - how to integrate azure advanced App Service Authentication / Authorization to access azure devops API (tasks, pipelines) Azure Devops 无法禁用“新服务连接体验” - Azure Devops can't disable "New service connections experience" 针对 azure devops 服务连接授权管道 - authorising pipelines against azure devops service connection 更新 Azure Devops 管道服务连接 - Update Azure Devops pipelines service connection 如何从 Azure devops 导出管道列表? - How can I export a list of pipelines from Azure devops? Azure DevOps 授予对管道的存储库访问权限 - Azure DevOps grant repository access to pipelines Azure Devops - 使用脚本访问 Pull Request 中构建验证管道的数量 - Azure Devops - use a script to access the number of build validation pipelines in a Pull Request Azure DevOps 流水线能否按特定顺序运行? - Can Azure DevOps pipelines be run in a specific order? 如何通过 Azure DevOps 管道为 Azure Service Fabric 应用程序设置环境变量 - How to set Environment Variable for Azure Service Fabric application through Azure DevOps pipelines 如何将 Azure DevOps 服务器存储库与 Azure DevOps 服务管道集成 - How to integrate Azure DevOps Servers repositories with Azure DevOps Services Pipelines
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM