Terraform中如何将AWS EC2实例SSH签名存入AWS Secrets Manager?
解决Terraform中堡垒机SSH known_hosts存入AWS Secrets Manager的问题
问题场景
使用Terraform 1.4创建EC2堡垒机实例,需生成该实例的SSH known_hosts条目并存入AWS Secrets Manager,供后续CI/CD通过堡垒机隧道执行kubectl(避免K8s API服务器暴露)。因无法使用sshclient Provider,采用local-exec调用ssh-keyscan工具,但将结果存入本地文件后,Terraform计划阶段会提前加载该文件(此时local-exec尚未执行),导致执行中断。
最优解决方案:直接在Provisioner中完成扫描与Secret写入
跳过本地文件存储步骤,直接在terraform_data的local-exec中完成ssh-keyscan扫描,并通过AWS CLI将结果打包为JSON后写入Secrets Manager,彻底避免计划阶段的文件加载冲突。
完整代码示例
resource "aws_instance" "bastion" { key_name = "key_name" instance_type = "t2.micro" ami = "ami-..." subnet_id = "subnet-..." vpc_security_group_ids = ["sg-..."] # 必须放行22端口,确保ssh-keyscan可连接 } resource "aws_secretsmanager_secret" "bastion" { name = "bastion" } resource "terraform_data" "ssh_keyscan_store_secret" { input = [aws_instance.bastion.id, aws_secretsmanager_secret.bastion.arn] provisioner "local-exec" { interpreter = ["bash", "-c"] command = <<EOF # 重试获取known_hosts,避免实例刚启动SSHD未就绪 KNOWN_HOSTS="" for i in {1..10}; do KNOWN_HOSTS=$(ssh-keyscan -t rsa ${aws_instance.bastion.public_dns} 2>/dev/null) if [ -n "$KNOWN_HOSTS" ]; then break fi sleep 5 done if [ -z "$KNOWN_HOSTS" ]; then echo "Failed to retrieve SSH known_hosts after 10 attempts" >&2 exit 1 fi # 构造JSON格式的Secret内容 SECRET_JSON=$(jq -n \ --arg public_dns "${aws_instance.bastion.public_dns}" \ --arg ssh_known_hosts "$KNOWN_HOSTS" \ '{public_dns: $public_dns, ssh_known_hosts: $ssh_known_hosts}') # 写入AWS Secrets Manager aws secretsmanager put-secret-value \ --secret-id ${aws_secretsmanager_secret.bastion.arn} \ --secret-string "$SECRET_JSON" EOF } }
关键说明
- 避免本地文件依赖:直接在
local-exec中完成扫描和Secret写入,跳过中间文件,彻底解决计划阶段加载文件的问题。 - 重试机制:添加10次循环重试,每次间隔5秒,确保实例的SSHD服务完全启动后再执行扫描,避免因实例未就绪导致的扫描失败。
- 环境依赖:执行Terraform的环境需安装
jq(用于构造JSON)和AWS CLI,且AWS CLI需具备secretsmanager:PutSecretValue权限。 - 权限与网络:确保堡垒机安全组放行22端口,且执行环境可访问堡垒机的公网DNS。
内容的提问来源于stack exchange,提问作者Oliver
相关产品推荐
相关产品推荐

