如何将Jenkins的PEM凭证传递给Terraform并等待EC2就绪复制文件
问题背景
基于GitHub托管的Terraform项目可实现在AWS上部署搭载Tomcat的EC2实例,并配置8080端口访问安全策略,当前需要落地两个需求:
- 等待EC2实例完全启动激活后,再执行文件复制操作
- 将index.html、jpg格式示例图片复制到Tomcat的ROOT部署目录
核心卡点为PEM私钥的安全传递:出于安全考虑不将PEM文件直接提交到Git仓库,已将PEM文件存储在Jenkins凭证中,需要明确服务器就绪后执行文件复制的正确实现逻辑,以及将Jenkins存储的PEM凭证安全传递给Terraform的方案。
现有配置片段
Jenkins 配置
environment { AWS_ACCESS_KEY_ID = credentials('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = credentials('AWS_SECRET_ACCESS_KEY') USER_KEYPEM = credentials("AWS_USER_KEY_PEM") }
Terraform 配置
resource "aws_instance" "web1" { ami = "${lookup(var.ami_id, var.region)}" instance_type = "t2.micro" vpc_security_group_ids = ["sg-XXXXXXXXX"] tags = { Name = "myFirstWebServer" } provisioner "remote-exec" { inline = [ "cloud-init status --wait" ] } provisioner "file" { source = "web/index.html" destination = "/path_to_tomcat_root/index.html" } provisioner "file" { source = "web/img.jpg" destination = "/path_to_tomcat_root/img.jpg" } connection { user = "ec2-user" private_key = "?????????" # 待解决:如何从Jenkins凭证传入PEM内容 host = "${aws_instance.web1.public_ip}" } }
实现方案
等待服务器就绪后执行文件复制的配置方法
现有配置中cloud-init status --wait的逻辑方向正确,但需要补充provisioner执行顺序控制和连接重试配置,避免SSH服务未启动、Tomcat目录未初始化时提前执行操作导致报错:
- Terraform会按照代码中定义的顺序从上到下执行provisioner,必须将等待系统就绪的remote-exec块放在所有文件复制provisioner的最前面
- 在connection块中添加超时、重试间隔配置,等待SSH服务正常监听后再建立连接
- 补充Tomcat ROOT目录存在性判断,避免文件复制时目标路径不存在
修正后的核心配置参考:
resource "aws_instance" "web1" { # 省略原有AMI、实例类型、安全组、标签配置 # 最先执行:等待系统和服务初始化完成 provisioner "remote-exec" { inline = [ "cloud-init status --wait", # 轮询等待Tomcat ROOT目录初始化完成 "while [ ! -d /path_to_tomcat_root ]; do sleep 5; done", # 若目录为root权限,可按需添加权限配置,例如:chmod 777 /path_to_tomcat_root ] } # 初始化完成后再执行文件复制 provisioner "file" { source = "web/index.html" destination = "/path_to_tomcat_root/index.html" } provisioner "file" { source = "web/img.jpg" destination = "/path_to_tomcat_root/img.jpg" } connection { user = "ec2-user" private_key = var.aws_private_key host = self.public_ip timeout = "5m" retry_delay = "10s" # 连接失败后10秒重试 } }
Jenkins PEM凭证安全传递给Terraform的方法
全程不要将PEM内容硬编码到代码或提交到Git仓库,通过Terraform敏感变量+Jenkins环境变量的方式传递,避免密钥泄露:
- 在Terraform项目中新建
variables.tf文件,定义接收私钥的敏感变量:
variable "aws_private_key" { description = "EC2实例登录私钥内容" type = string sensitive = true # 标记为敏感值,Terraform执行日志不会输出明文 }
- 修改Jenkins Pipeline配置,利用Terraform的
TF_VAR_前缀环境变量自动传参特性,不需要将PEM写入本地磁盘文件:
Jenkins的
credentials()方法读取密钥类凭证时,会直接将凭证内容赋值给环境变量,全程不需要明文落盘
environment { AWS_ACCESS_KEY_ID = credentials('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = credentials('AWS_SECRET_ACCESS_KEY') USER_KEYPEM = credentials("AWS_USER_KEY_PEM") // Terraform会自动读取TF_VAR_开头的环境变量,匹配同名变量赋值 TF_VAR_aws_private_key = "$USER_KEYPEM" } stages { stage('Deploy') { steps { sh 'terraform init' sh 'terraform apply -auto-approve' } } }
- 配置完成后,Terraform的connection块直接引用
var.aws_private_key即可获取PEM内容,替换原有占位符即可。
注意事项
- 私钥变量标记为敏感类型后,执行过程中不会在Jenkins控制台日志中输出明文,避免日志泄露
- 不需要在Pipeline中额外将PEM内容写入临时文件,减少密钥残留泄露的风险
- 若file provisioner执行时报权限不足错误,在等待就绪的remote-exec块中添加目标目录的权限修改命令,为登录用户分配写入权限即可。
内容的提问来源于stack exchange,提问作者user3442473
相关产品推荐
相关产品推荐

