【问题标题】:Authenticating with Azure Repos git module sources in an Azure Pipelines build在 Azure Pipelines 构建中使用 Azure Repos git 模块源进行身份验证
【发布时间】:2019-03-26 16:26:17
【问题描述】:

我目前正在为 Azure DevOps 创建一个管道,以验证 Terraform 配置并将其应用于不同的订阅。

我的 terraform 配置使用模块,这些模块“托管”在与 terraform 配置相同的 Azure DevOps 项目中的其他存储库中。

可悲的是,当我尝试执行 terraform init 来获取这些模块时,管道任务“挂起”在那里等待凭据输入。

按照Pipeline Documentation on Running Git Commands in a script 中的建议,我尝试使用persistCredentials:true 属性添加checkout 步骤。

从我在任务日志中看到的(见下文),凭据信息是专门添加到当前存储库中的,不能用于其他存储库。

添加persistCredentials:true时执行的命令

2018-10-22T14:06:54.4347764Z ##[command]git config http.https://my-org@dev.azure.com/my-org/my-project/_git/my-repo.extraheader "AUTHORIZATION: bearer ***"

terraform init 任务的输出

2018-10-22T14:09:24.1711473Z terraform init -input=false
2018-10-22T14:09:24.2761016Z Initializing modules...
2018-10-22T14:09:24.2783199Z - module.my-module
2018-10-22T14:09:24.2786455Z   Getting source "git::https://my-org@dev.azure.com/my-org/my-project/_git/my-module-repo?ref=1.0.2"

如何设置 git 凭据以用于其他存储库?

【问题讨论】:

    标签: azure-devops terraform azure-pipelines azure-repos


    【解决方案1】:

    我不认为你可以。通常,您创建另一个构建并链接到该构建中的工件以在当前定义中使用它。这样你就不需要连接到不同的 Git 存储库

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,我最终做的是在 terraform 配置中标记 SYSTEM_ACCESSTOKEN。我在 Azure DevOps 中使用了 Tokenzization 任务,其中 __ 前缀和后缀用于识别并用实际变量替换标记(它是可自定义的,但我发现双下划线最好不要干扰我拥有的任何代码)

      - task: qetza.replacetokens.replacetokens-task.replacetokens@3
          displayName: 'Replace tokens'
          inputs:
            targetFiles: |
             **/*.tfvars
             **/*.tf
            tokenPrefix: '__'
            tokenSuffix: '__'
      

      如果您无法将自定义扩展安装到您的 DevOps 组织,类似 find $(Build.SourcesDirectory)/ -type f -name 'main.tf' -exec sed -i 's~__SYSTEM_ACCESSTOKEN__~$(System.AccessToken)~g' {} \; 的方法也可以使用。

      我的 terraform main.tf 如下所示:

      module "app" {
        source = "git::https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules//azure/app-service?ref=__app-service-module-ver__"
        ....
      }
      

      它并不漂亮,但它完成了工作。模块源(在撰写本文时)不支持来自 terraform 的变量输入。所以我们可以做的是使用 Terrafile,它是一个开源项目,通过在代码旁边保留一个简单的 YAML 文件来帮助跟上您可能使用的模块和同一模块的不同版本。它似乎不再被积极维护,但它只是工作:https://github.com/coretech/terrafile 我的 Terrafile 示例:

      app:
          source:  "https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules"
          version: "feature/handle-twitter"
      app-stable:
          source:  "https://token:__SYSTEM_ACCESSTOKEN__@dev.azure.com/actualOrgName/actualProjectName/_git/TerraformModules"
          version: "1.0.5"
      

      默认情况下,Terrafile 将您的模块下载到 ./vendor 目录,以便您可以将模块源指向以下内容:

      module "app" {
        source = "./vendor/modules/app-stable/azure/app_service"
        ....
      }
      

      现在你只需要弄清楚如何在 Terrafile 所在的目录中执行terrafile 命令。 我的 azure.pipelines.yml 示例:

      - script: curl -L https://github.com/coretech/terrafile/releases/download/v0.6/terrafile_0.6_Linux_x86_64.tar.gz | tar xz -C $(Agent.ToolsDirectory)
        displayName: Install Terrafile
      
      - script: |
          cd $(Build.Repository.LocalPath)
          $(Agent.ToolsDirectory)/terrafile
        displayName: Download required modules
      

      【讨论】:

        【解决方案3】:

        我做了这个

        _ado_token.ps1

        # used in Azure DevOps to allow terrform to auth with Azure DevOps GIT repos
        $tfmodules = Get-ChildItem $PSScriptRoot -Recurse -Filter "*.tf"
        foreach ($tfmodule in $tfmodules) {
            $content = [System.IO.File]::ReadAllText($tfmodule.FullName).Replace("git::https://myorg@","git::https://" + $env:SYSTEM_ACCESSTOKEN +"@")
            [System.IO.File]::WriteAllText($tfmodule.FullName, $content)
        }
        

        azure-pipelines.yml

        - task: PowerShell@2
          env: 
            SYSTEM_ACCESSTOKEN: $(System.AccessToken)
          inputs:
            filePath: '_ado_token.ps1'
            pwsh: true
          displayName: '_ado_token.ps1'
        

        【讨论】:

          【解决方案4】:

          您基本上有两种方法可以做到这一点。

          先决条件

          确保您阅读并根据您的需要应用“在脚本中运行 Git 命令”文档中的 Enable scripts to run Git commands 部分。

          解决方案 #1:在管道运行时动态插入 System.AccessToken(或 PAT,但我不推荐)

          你可以这样做:

          • 在您的代码中插入一个替换标记,例如__SYSTEM_ACCESSTOKEN__(如Nilsas 建议的那样),并使用一些标记替换代码或qetza.replacetokens.replacetokens-task.replacetokens 任务来插入值。此解决方案的缺点是,当您在本地运行 terraform 时,您还必须替换令牌。
          • 使用一些代码将所有git::https://dev.azure.com 文本替换为git::https://YOUR_ACCESS_TOKEN@dev.azure.com

          我通过使用以下 bash 任务脚本来使用第二种方法(它搜索 terragrunt 文件,但您可以适应 terraform 文件而无需太多更改):

          - bash: |
              find $(Build.SourcesDirectory)/ -type f -name 'terragrunt.hcl' -exec sed -i 's~git::https://dev.azure.com~git::https://$(System.AccessToken)@dev.azure.com~g' {} \;
          

          Abu Belai 提供了一个 PowerShell 脚本来做类似的事情。

          但是,如果您的 terraform 模块 git 存储库中的模块在另一个 git 存储库中调用自己的模块,这种类型的解决方案将不起作用,这就是我们的情况。

          解决方案#2:在terraform 模块git repos 的url 的extraheader 中全局添加访问令牌

          这样,由您的代码直接调用或由被调用模块的代码间接调用的所有模块的存储库都将能够使用您的访问令牌。为此,我在您的 terraform/terragrunt 调用之前添加了以下步骤:

          - bash: |
              git config --global http.https://dev.azure.com/<your-org>/<your-first-repo-project>/_git/<your-first-repo>.extraheader "AUTHORIZATION: bearer $(System.AccessToken)"
              git config --global http.https://dev.azure.com/<your-org>/<your-second-repo-project>/_git/<your-second-repo>.extraheader "AUTHORIZATION: bearer $(System.AccessToken)"
          

          您需要为每个调用的git 存储库设置extraheader

          请注意,如果您的管道在同一个工作线程上多次设置extraheader,则您可能需要在调用terraform 后取消设置extraheader。这是因为git 可能会与多个extraheader 声明混淆。您可以通过添加以下步骤来做到这一点:

          - bash: |
              git config --global --unset-all http.https://dev.azure.com/<your-org>/<your-first-repo-project>/_git/<your-first-repo>.extraheader
              git config --global --unset-all http.https://dev.azure.com/<your-org>/<your-second-repo-project>/_git/<your-second-repo>.extraheader 
          

          【讨论】:

          • 请不要遵循解决方案 #2。您会发现您的代理机器以某种方式没有清除它们的额外标头,并且您的管道开始失败并出现 git 错误 128。尝试追踪是一件可怕的事情。
          • 另一方面,解决方案 #1 效果很好。
          • 在将 syste.accesstoken 添加到模块 url 时,我得到“致命:无法读取 'https://***@tfs.company.co.nz' 的密码。有关如何工作的任何建议在那个附近?
          【解决方案5】:

          我通过创建一个运行内联 powershell 脚本的管道模板解决了这个问题。然后,当使用来自不同 Repo 的任何 terraform 模块时,我将模板作为 Pipeline 模板拉入“资源”。 该脚本将对所有 .tf 文件进行递归搜索。然后使用正则表达式更新所有模块源 url。

          我选择了 REGEX 而不是对模块 url 进行标记,因为这将确保可以在开发机器上拉入模块,而无需对源代码进行任何更改。

          parameters:
          - name: terraform_directory
            type: string
          
          steps:
            - task: PowerShell@2
              displayName: Tokenize TF-Module Sources
              env:
                SYSTEM_ACCESSTOKEN: $(System.AccessToken)
              inputs:
                targetType: 'inline'
                
                script: |
                  $regex = "https://*(.+)dev.azure.com"
                  $tokenized_url = "https://token:$($env:SYSTEM_ACCESSTOKEN)@dev.azure.com"
          
                  Write-Host "Recursive Search in ${{ parameters.terraform_directory }}"
                  $tffiles = Get-ChildItem -Path "${{ parameters.terraform_directory }}" -Filter "*main.tf" -Recurse -Force
          
                  Write-Host "Found $($tffiles.Count) files ending with 'main.tf'"
                  if ($tffiles) { Write-Host $tffiles }
          
                  $tffiles | % {
                    Write-Host "Updating file $($_.FullName)"
                    $content = Get-Content $_.FullName
          
                    Write-Host "Replace Strings: $($content | Select-String -Pattern $regex)"
                    
                    $content -replace $regex, $tokenized_url | Set-Content $_.FullName -Force
          
                    Write-Host "Updated content"
                    Write-Host (Get-Content $_.FullName)
                  }
          

          【讨论】:

            猜你喜欢
            • 2022-11-04
            • 2013-03-31
            • 2023-01-19
            • 2021-02-01
            • 2019-07-09
            • 2020-12-17
            • 1970-01-01
            • 1970-01-01
            • 2017-10-30
            相关资源
            最近更新 更多