我一直在阅读的所有内容都说我应该使用TF_VAR_方法将我的客户端秘密传递给Terraform,但我一直得到这个错误:
Error: No value for required variable
on variables.tf line 1:
1: variable "clientid" {
The root module input variable "clientid" is not set, and has no default
value. Use a -var or -var-file command line argument to provide a value for
this variable.
请注意,如果我将值直接传递给-var标志,它会正常工作。所以,这个问题是关于如何使用TF_VAR_方法,而不是如何登录。
Jenkinsfile
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent { label 'docker-agent' }
environment {
AZURE_SUBSCRIPTION_ID='<......>'
AZURE_TENANT_ID='<.......>'
CONTAINER_REGISTRY='containerregistry'
RESOURCE_GROUP='crrg'
REPO="sftp01"
IMAGE_NAME="sftptest"
TAG="0.01"
}
stages {
stage('build') {
steps {
//sh 'docker build -t containerregistry.azurecr.io/sftp01/sftptest:0.01 -f Dockerfile .'
//sh 'echo built'
withCredentials([usernamePassword(credentialsId: 'containerregistryCreds', passwordVariable: 'AZURE_CLIENT_SECRET', usernameVariable: 'AZURE_CLIENT_ID')]) {
sh 'export TF_VAR_clientid=$AZURE_CLIENT_ID'
sh 'export TF_VAR_clientsecret=$AZURE_CLIENT_SECRET'
sh 'export TF_VAR_subscriptionid=$AZURE_SUBSCRIPTION_ID'
sh 'export TF_VAR_tenantid=$AZURE_TENANT_ID'
//sh 'az login --service-principal -u $AZURE_CLIENT_ID -p $AZURE_CLIENT_SECRET -t $AZURE_TENANT_ID'
//sh 'az account set -s $AZURE_SUBSCRIPTION_ID'
//sh 'az acr login --name $CONTAINER_REGISTRY --resource-group $RESOURCE_GROUP'
//sh 'az acr build --image $REPO/$IMAGE_NAME:$TAG --registry $CONTAINER_REGISTRY --file Dockerfile . '
sh 'terraform init'
sh 'terraform fmt'
sh 'terraform validate'
sh 'terraform apply -auto-approve -no-color'
//If I pass the variables this way, it works fine.
//sh 'terraform apply -auto-approve -no-color -var clientid=$AZURE_CLIENT_ID -var clientsecret=$AZURE_CLIENT_SECRET -var subscriptionid=$AZURE_SUBSCRIPTION_ID -var tenantid=$AZURE_TENANT_ID'
sh 'terraform show'
sh 'terraform state list'
}
}
}
}
}
main.tf
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.2"
}
}
}
provider "azurerm" {
client_id = var.clientid
client_secret = var.clientsecret
subscription_id = var.subscriptionid
tenant_id = var.tenantid
features {}
}
resource "azurerm_resource_group" "resourceNameTFscopeOnly" {
name = "myTFResourceGroup"
location = "westus2"
}
variables.tf
variable "clientid" {
description = "Azure Client ID"
type = string
sensitive = true
}
variable "clientsecret" {
description = "Azure Client Service Principal Secret"
type = string
sensitive = true
}
variable "subscriptionid" {
description = "Azure Subscription ID"
type = string
sensitive = true
}
variable "tenantid" {
description = "Azure Tenant ID"
type = string
sensitive = true
}
variable "testpassword" {
description = "For testing (not relevant to question)"
type = string
sensitive = true
}
我做错了什么?
Jenkins Pipeline中的withCredentials
块已经将您的变量导出到其作用域内的环境中。您可以额外地修改env
对象以获得额外的环境变量,并从env
对象访问当前的环境变量(例如您在environment
指令中分配的那些)。这就是terrform在没有变量值时出错的原因:它们都没有在环境中正确设置。
// assign password and username environment variables within block arguments
withCredentials([usernamePassword(credentialsId: 'containerregistryCreds', passwordVariable: 'TF_VAR_clientsecret', usernameVariable: 'TF_VAR_clientid')]) {
script {
// re-assign other environment variables from environment directive to env object within block scope
env.TF_VAR_subscriptionid = env.AZURE_SUBSCRIPTION_ID
env.TF_VAR_tenantid = env.AZURE_TENANT_ID
...
}
}
这就是我最后所做的。感谢Matt回答了这个核心问题。此外,为了保持tenantId和subscriptionId不受源代码控制,我将它们放在Jenkins:
中它们自己的usernamePassword凭据中。//Jenkinsfile (Declarative Pipeline)
pipeline {
agent { label 'docker-agent' }
environment {
//TF_LOG='DEBUG'
TF_LOG_PATH='/home/jenkins/terraform-debug.log'
CONTAINER_REGISTRY='ArcticaCR'
RESOURCE_GROUP='crrg'
REPO="sftp01"
IMAGE_NAME="sftptest"
TAG="0.01"
}
stages {
stage('build') {
steps {
withCredentials([
usernamePassword(credentialsId: 'sftpServicePrincipalCreds', passwordVariable: 'TF_VAR_clientsecret', usernameVariable: 'TF_VAR_clientid'),
usernamePassword(credentialsId: 'AzureTenantSubscription', passwordVariable: 'TF_VAR_tenantid', usernameVariable: 'TF_VAR_subscriptionid'),
usernamePassword(credentialsId: 'passwordtestCreds', passwordVariable: 'TEST_PASSWORD', usernameVariable: 'TEST_USERNAME')
]) {
sh 'az login --service-principal -u $TF_VAR_clientid -p $TF_VAR_clientsecret -t $TF_VAR_tenantid'
sh 'az account set -s $TF_VAR_subscriptionid'
sh 'az acr login --name $CONTAINER_REGISTRY --resource-group $RESOURCE_GROUP'
sh 'az acr build --image $REPO/$IMAGE_NAME:$TAG --registry $CONTAINER_REGISTRY --file Dockerfile . '
sh 'az logout'
sh 'terraform init'
sh 'terraform fmt'
sh 'terraform validate'
sh 'terraform apply -auto-approve -no-color -var testpassword=$TEST_PASSWORD'
sh 'terraform show'
sh 'terraform state list'
}
}
}
}
}
因此,正如在另一个答案中已经说明的那样,您在一个sh
步骤中导出变量,但在另一个sh
步骤中运行Terraform命令。导出的值不能跨步骤保存,因为这些步骤是独立的Bash进程。但是您可以在一步中运行它:
sh """
export TF_VAR_...=...
terraform ...
"""
我认为env.TF_VAR_... = ...
的解决方案仍然更好。