GitHub Action中Terraform OIDC认证初始化ARM配置错误求助
错误信息
Initializing the backend...
╷
│ Error: Error building ARM Config: Authenticating using the Azure CLI is only supported as a User (not a Service Principal).
│
│ To authenticate to Azure using a Service Principal, you can use the separate 'Authenticate using a Service Principal'
│ auth method - instructions for which can be found here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret
│
│ Alternatively you can authenticate using the Azure CLI by using a User Account.
现有配置
工作流.yml文件
name: 'Create Infra with Terraform' on: push: branches: [ main ] paths: .github/workflows/main.yml pull_request: branches: none # [ main ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: permissions: id-token: write contents: read env: STORAGE_ACCOUNT_NAME: terraformstate01923777 RESOURCE_GROUP_NAME: rg-terraform-state CONTAINER_NAME: tfstate BLOB_NAME: terraform.tfstate WORKING_DIRECTORY: . jobs: scan-terraform-config: runs-on: ubuntu-latest name: Scan Terraform with Checov steps: - name: Checkout repo uses: actions/checkout@master - name: Run Checkov Scan id: checkov uses: bridgecrewio/checkov-action@master with: directory: . soft_fail: true # optional: do not return an error code if there are failed checks # check: CKV_AWS_1 # optional: run only a specific check_id. can be comma separated list # skip_check: CKV_AWS_2 # optional: skip a specific check_id. can be comma separated list # quiet: true # optional: display only failed checks # framework: terraform # optional: run only on a specific infrastructure {cloudformation,terraform,kubernetes,all} # output_format: sarif # optional: the output format, one of: cli, json, junitxml, github_failed_only, or sarif. Default: sarif # download_external_modules: true # optional: download external terraform modules from public git repositories and terraform registry # log_level: DEBUG # optional: set log level. Default WARNING # config_file: path/this_file # baseline: cloudformation/.checkov.baseline # optional: Path to a generated baseline file. Will only report results not in the baseline. # container_user: 1000 # optional: Define what UID and / or what GID to run the container under to prevent permission issues deploy-azure-infra-terraform: name: Deploy to Azure with Terraform runs-on: ubuntu-latest # environment: production needs: [scan-terraform-config] # Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest defaults: run: shell: bash working-directory: . steps: # Checkout the repository to the GitHub Actions runner - name: Checkout uses: actions/checkout@v4 - name: Login to Azure with OIDC uses: Azure/login@v2.3.0 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Create Terraform backend state storage uses: Azure/cli@v2.1.0 with: inlineScript: | az version # Create resource group az group create --name $RESOURCE_GROUP_NAME --location westeurope # Create storage account with open access az storage account create --name $STORAGE_ACCOUNT_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --sku Standard_LRS \ --encryption-services blob \ --default-action "Allow" # Create blob container with authentication mode az storage container create --name $CONTAINER_NAME \ --account-name $STORAGE_ACCOUNT_NAME \ --auth-mode login # Install the latest version of Terraform CLI - name: Install Terraform uses: hashicorp/setup-terraform@v1 with: terraform_version: 1.1.7 - name: Terraform Init id: init env: ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} ARM_USE_OIDC: true ARM_USE_CLI: false run: | # Initialize Terraform with backend configuration terraform init \ -backend-config="resource_group_name=$RESOURCE_GROUP_NAME" \ -backend-config="storage_account_name=$STORAGE_ACCOUNT_NAME" \ -backend-config="container_name=$CONTAINER_NAME" \ -backend-config="key=$BLOB_NAME" \ -backend-config="use_azuread_auth=true" # Checks that all Terraform configuration files adhere to a canonical format - name: Terraform Format id: format run: terraform fmt -check continue-on-error: true - name: Terraform Plan id: plan env: ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} ARM_USE_OIDC: true ARM_USE_CLI: false if: github.event_name == 'pull_request' # 'push' # run: | terraform plan -no-color - name: Add Terraform Plan Comment id: comment uses: actions/github-script@v6 if: github.event_name == 'pull_request' # 'push' env: PLAN: "terraform\n${{ steps.plan.outputs.stdout }}" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const output = `#### Terraform Format and Style 🖌\`${{ steps.format.outcome }}\` #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` <details><summary>Show Plan</summary> \`\`\`${process.env.PLAN}\`\`\` </details> *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ env.WORKING_DIRECTORY }}\`, Workflow: \`${{ github.workflow }}\`*`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output }) # On push to main, build or change infrastructure according to Terraform configuration files - name: Terraform Apply if: github.ref == 'refs/heads/main' && github.event_name == 'push' env: ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} ARM_USE_OIDC: true ARM_USE_CLI: false run: terraform apply -auto-approve
main.tf文件
terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0" } } required_version = ">= 1.0.0" # Backend configuration will be provided via command line backend "azurerm" {} } provider "azurerm" { features {} use_cli = false use_oidc = true } resource "azurerm_resource_group" "example" { name = "example-resources" location = "West Europe" }
解决方案
错误根源是Terraform的azurerm后端默认尝试使用Azure CLI认证,但当前会话是通过服务主体(OIDC登录)创建的,不符合CLI认证的用户账户要求。需要明确告诉后端使用OIDC认证并禁用CLI认证:
修改Terraform Init命令,添加后端配置参数
在terraform init的命令中加入-backend-config="use_cli=false",确保后端明确禁用CLI认证:terraform init \ -backend-config="resource_group_name=$RESOURCE_GROUP_NAME" \ -backend-config="storage_account_name=$STORAGE_ACCOUNT_NAME" \ -backend-config="container_name=$CONTAINER_NAME" \ -backend-config="key=$BLOB_NAME" \ -backend-config="use_azuread_auth=true" \ -backend-config="use_cli=false"验证环境变量传递
确保ARM_USE_OIDC=true和ARM_USE_CLI=false环境变量在Init步骤正确生效,这些变量会被azurerm后端读取,优先使用OIDC认证方式。版本兼容性检查
当前使用的Terraform 1.1.7和azurerm provider 3.x版本组合支持OIDC后端认证,但建议确认两者版本匹配:- Terraform 1.1+支持OIDC环境变量传递
- azurerm provider 3.0+支持OIDC认证
确认服务主体权限
确保用于OIDC登录的服务主体拥有目标存储账户的Storage Blob Data Contributor权限,避免后续权限问题(虽然当前错误是认证方式问题,但权限配置是后续必要步骤)。
内容的提问来源于stack exchange,提问作者shameera2008

