EC2实例间SSH连接失败求助(Terraform部署Ansible节点)
问题描述
我通过Terraform在AWS EC2上部署两台实例,分别作为Ansible控制节点和受控节点,需求是自动完成控制节点的Ansible安装、SSH密钥配置,以及将控制节点公钥复制到受控节点的authorized_keys文件中。
部署过程无报错,但尝试通过私有IP从控制节点连接受控节点时,SSH通信被拒绝,错误信息如下:
ssh ubuntu@10.10.0.29 Load key "/home/ubuntu/.ssh/id_rsa": Permission denied ubuntu@10.10.0.29: Permission denied (publickey).
相关配置文件及权限信息如下:
VPC与安全组配置(vpc.tf)
resource "aws_vpc" "vpc_virginia" { cidr_block = var.virginia_cidr tags = { "Name" : "vpc_virginia" } } resource "aws_subnet" "public_subnet" { vpc_id = aws_vpc.vpc_virginia.id cidr_block = var.subnets[0] map_public_ip_on_launch = true tags = { "Name" = "public_subnet" } } resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc_virginia.id tags = { Name = "igw vpc virginia" } } resource "aws_route_table" "public_crt" { vpc_id = aws_vpc.vpc_virginia.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } tags = { Name = "public crt" } } resource "aws_route_table_association" "crta_subnet" { subnet_id = aws_subnet.public_subnet.id route_table_id = aws_route_table.public_crt.id } resource "aws_security_group" "sg_control_node" { name = "public_instance-sg" description = "Allow SSH inbound traffic and all egress traffic" vpc_id = aws_vpc.vpc_virginia.id ingress { description = "SSH over Internet" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = [var.sg_ingress_cidr] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = "control-node_sg" } } resource "aws_security_group" "sg_managed_node" { name = "managed-node-sg" description = "Allow SSH inbound traffic and all HTTP traffic" vpc_id = aws_vpc.vpc_virginia.id ingress { description = "SSH over Internet" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = [var.sg_ingress_cidr] } ingress { description = "HTTP traffic" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = [var.sg_ingress_cidr] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = "managed_node_sg" } }
EC2与密钥复制配置(ec2.tf)
resource "aws_instance" "ec2_control" { ami = "ami-0c7217cdde317cfec" instance_type = "t2.micro" subnet_id = aws_subnet.public_subnet.id key_name = data.aws_key_pair.key.key_name vpc_security_group_ids = [aws_security_group.sg_control_node.id] provisioner "remote-exec" { inline = [ "sudo apt-get update -y", "sudo apt-get install -y software-properties-common", "sudo apt-add-repository --yes --update ppa:ansible/ansible", "sudo apt-get install -y ansible", "sudo adduser ansible --disabled-password --gecos ''", "sudo ssh-keygen -t rsa -b 4096 -f /home/ubuntu/.ssh/id_rsa -N ''", ] connection { type = "ssh" host = self.public_ip user = "ubuntu" private_key = file("keys/mykey.pem") } } tags = { Name = "control_node" } } resource "aws_instance" "ec2_managed" { ami = "ami-0c7217cdde317cfec" instance_type = "t2.micro" subnet_id = aws_subnet.public_subnet.id key_name = data.aws_key_pair.key.key_name vpc_security_group_ids = [aws_security_group.sg_managed_node.id] tags = { Name = "managed_node" } } resource "null_resource" "copy_public_key" { provisioner "local-exec" { command = "scp -o StrictHostKeyChecking=no -i keys/mykey.pem ubuntu@${aws_instance.ec2_control.public_ip}:/home/ubuntu/.ssh/id_rsa.pub public_key.txt" } provisioner "remote-exec" { inline = [ "echo '${file("public_key.txt")}' >> /home/ubuntu/.ssh/authorized_keys" ] connection { type = "ssh" user = "ubuntu" private_key = file("keys/mykey.pem") host = aws_instance.ec2_managed.public_ip } } depends_on = [aws_instance.ec2_control, aws_instance.ec2_managed] }
节点权限信息
控制节点.ssh目录权限
drwx------ 2 ubuntu ubuntu 4096 Feb 9 03:57 . drwxr-x--- 4 ubuntu ubuntu 4096 Feb 9 03:56 .. -rw------- 1 ubuntu ubuntu 387 Feb 9 03:56 authorized_keys -rw------- 1 root root 3389 Feb 9 03:57 id_rsa -rw-r--r-- 1 root root 745 Feb 9 03:57 id_rsa.pub
受控节点.ssh目录权限
drwx------ 2 ubuntu ubuntu 4096 Feb 9 03:56 . drwxr-x--- 4 ubuntu ubuntu 4096 Feb 9 03:57 .. -rw------- 1 ubuntu ubuntu 1133 Feb 9 03:58 authorized_keys
问题根源分析
- SSH密钥权限错误:控制节点上生成的
id_rsa和id_rsa.pub属于root用户,而连接受控节点时使用的是ubuntu用户,ubuntu没有读取root所属密钥文件的权限,导致加载密钥失败。这是因为生成密钥时使用了sudo ssh-keygen,命令以root身份执行,生成的文件归属root。 - 安全组规则限制:受控节点的安全组仅允许来自
var.sg_ingress_cidr的SSH流量,而控制节点通过私有IP发起连接,该IP不在允许范围内,即使密钥正确也会被安全组拦截。
解决方案
1. 修正控制节点密钥归属权限
修改控制节点的remote-exec脚本,去掉sudo执行ssh-keygen,或者生成后修改文件归属:
provisioner "remote-exec" { inline = [ "sudo apt-get update -y", "sudo apt-get install -y software-properties-common", "sudo apt-add-repository --yes --update ppa:ansible/ansible", "sudo apt-get install -y ansible", "sudo adduser ansible --disabled-password --gecos ''", # 去掉sudo,以ubuntu用户身份生成密钥 "ssh-keygen -t rsa -b 4096 -f /home/ubuntu/.ssh/id_rsa -N ''", # 或者保留sudo,添加修改归属的命令 # "sudo ssh-keygen -t rsa -b 4096 -f /home/ubuntu/.ssh/id_rsa -N ''", # "sudo chown ubuntu:ubuntu /home/ubuntu/.ssh/id_rsa /home/ubuntu/.ssh/id_rsa.pub" ] connection { type = "ssh" host = self.public_ip user = "ubuntu" private_key = file("keys/mykey.pem") } }
2. 调整受控节点安全组规则
修改sg_managed_node的SSH ingress规则,允许控制节点所在的VPC CIDR或者控制节点的安全组访问:
resource "aws_security_group" "sg_managed_node" { name = "managed-node-sg" description = "Allow SSH from control node/VPC and all HTTP traffic" vpc_id = aws_vpc.vpc_virginia.id ingress { description = "SSH from control node security group" from_port = 22 to_port = 22 protocol = "tcp" # 允许控制节点安全组的流量 security_groups = [aws_security_group.sg_control_node.id] } ingress { description = "HTTP traffic" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = [var.sg_ingress_cidr] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = "managed_node_sg" } }
3. 优化密钥复制流程(可选)
直接在控制节点使用ssh-copy-id复制公钥到受控节点,避免本地文件中转,更可靠:
resource "null_resource" "copy_public_key" { provisioner "remote-exec" { inline = [ # 先信任受控节点主机密钥,再复制公钥 "ssh-keyscan ${aws_instance.ec2_managed.private_ip} >> /home/ubuntu/.ssh/known_hosts", "ssh-copy-id -i /home/ubuntu/.ssh/id_rsa.pub ubuntu@${aws_instance.ec2_managed.private_ip}" ] connection { type = "ssh" user = "ubuntu" private_key = file("keys/mykey.pem") host = aws_instance.ec2_control.public_ip } } depends_on = [aws_instance.ec2_control, aws_instance.ec2_managed] }
内容的提问来源于stack exchange,提问作者LxX
相关产品推荐
相关产品推荐

