三步干掉堡垒机:EC2 Instance Connect Endpoint 从零搭建指南

公司有十几台 EC2 跑在 Private Subnet,运维流程是这样的:

  1. 连 VPN
  2. SSH 到堡垒机
  3. 从堡垒机 SSH 到目标实例

三层跳转,光认证就两分钟。堡垒机还得维护——打补丁、轮密钥、开安全审计。说白了它本身就是个攻击面,放在公网上等人来扫。

后来用了亚马逊云科技的 EC2 Instance Connect Endpoint(EICE),直接从本地 SSH 到 Private Subnet 实例。不要公网 IP,不要堡垒机,不要 VPN。认证走 IAM,审计走 CloudTrail,免费。

这篇从零开始搭。

EICE 是什么

一句话:亚马逊云科技 在你的 VPC 里放了个托管的隧道入口,让你通过 亚马逊云科技 API 建立到私有实例的 SSH 隧道。

你的电脑 → AWS API → EICE(VPC内部)→ 私有子网 EC2

和堡垒机对比:

堡垒机 EICE
公网 IP 必须有 不需要
维护 打补丁、轮密钥 零维护
认证 SSH 密钥 IAM 策略
审计 自己搞 CloudTrail 自动
费用 EC2 实例费 免费
权限粒度 登上堡垒机就能到处跳 按实例/标签精确控制

最后一行是关键——堡垒机上一旦登录,理论上可以 SSH 到 VPC 内任何实例。EICE 通过 IAM 条件键,可以限制到"只能连 staging 环境的实例"。

第一步:创建 EICE

CLI 一行搞定:

aws ec2 create-instance-connect-endpoint \
    --subnet-id subnet-0123456789abcdef0 \
    --security-group-ids sg-0123456789abcdef0 \
    --region ap-northeast-1

Python 版本:

import boto3

ec2 = boto3.client('ec2', region_name='ap-northeast-1')

response = ec2.create_instance_connect_endpoint(
    SubnetId='subnet-0123456789abcdef0',
    SecurityGroupIds=['sg-0123456789abcdef0'],
    PreserveClientIp=False
)

endpoint_id = response['InstanceConnectEndpoint']['InstanceConnectEndpointId']
print(f'创建中: {endpoint_id}')

创建要 2-3 分钟。查状态:

result = ec2.describe_instance_connect_endpoints(
    InstanceConnectEndpointIds=[endpoint_id]
)
print(result['InstanceConnectEndpoints'][0]['State'])
# create-complete 就好了

注意事项:

  • 和目标实例要在同一个 VPC(不要求同子网)
  • 每个 VPC 最多 5 个 EICE

第二步:配安全组

两条规则,别搞反方向:

ec2_resource = boto3.resource('ec2', region_name='ap-northeast-1')

# EICE 安全组:出站放通 → 目标实例 SSH
eice_sg = ec2_resource.SecurityGroup('sg-eice-xxx')
eice_sg.authorize_egress(
    IpPermissions=[{
        'IpProtocol': 'tcp',
        'FromPort': 22,
        'ToPort': 22,
        'UserIdGroupPairs': [{'GroupId': 'sg-target-xxx'}]
    }]
)

# 目标实例安全组:入站允许 ← 来自 EICE
target_sg = ec2_resource.SecurityGroup('sg-target-xxx')
target_sg.authorize_ingress(
    IpPermissions=[{
        'IpProtocol': 'tcp',
        'FromPort': 22,
        'ToPort': 22,
        'UserIdGroupPairs': [{'GroupId': 'sg-eice-xxx'}]
    }]
)

用安全组互相引用,不用管 IP。

第三步:配 IAM

EICE 强大的地方——IAM 精确控权:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowTunnel",
            "Effect": "Allow",
            "Action": "ec2-instance-connect:OpenTunnel",
            "Resource": "arn:aws:ec2:ap-northeast-1:123456789012:instance-connect-endpoint/*",
            "Condition": {
                "NumericLessThanEquals": {
                    "ec2-instance-connect:maxTunnelDuration": "3600"
                }
            }
        },
        {
            "Sid": "AllowSSH",
            "Effect": "Allow",
            "Action": "ec2-instance-connect:SendSSHPublicKey",
            "Resource": "arn:aws:ec2:ap-northeast-1:123456789012:instance/*",
            "Condition": {
                "StringEquals": {
                    "ec2:osuser": "ec2-user"
                }
            }
        },
        {
            "Sid": "Describe",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstanceConnectEndpoints",
                "ec2:DescribeInstances"
            ],
            "Resource": "*"
        }
    ]
}

按环境限制(只能连 staging):

{
    "Condition": {
        "StringEquals": {
            "ec2:ResourceTag/Environment": "staging"
        }
    }
}
  • maxTunnelDuration:限制单次连接时长
  • ec2:osuser:限制登录用户名
  • ec2:ResourceTag:按标签控权

四种连接方式

方式一:控制台

EC2 控制台 → 选实例 → Connect → EC2 Instance Connect → Connect using Private IP → 选 EICE → 连接。浏览器里开终端。

方式二:CLI + SSH

ssh -i my-key.pem ec2-user@i-0123456789abcdef0 \
    -o ProxyCommand='aws ec2-instance-connect open-tunnel \
    --instance-id i-0123456789abcdef0'

方式三:临时公钥(60秒有效)

aws ec2-instance-connect send-ssh-public-key \
    --instance-id i-0123456789abcdef0 \
    --instance-os-user ec2-user \
    --ssh-public-key file://~/.ssh/id_rsa.pub

方式四:SSH Config

Host staging-*
    User ec2-user
    IdentityFile ~/.ssh/my-key.pem
    ProxyCommand aws ec2-instance-connect open-tunnel --instance-id %n

以后 ssh staging-i-0123456789abcdef0 直连。

审计

每次 EICE 连接都在 CloudTrail 自动记录:

cloudtrail = boto3.client('cloudtrail', region_name='ap-northeast-1')

response = cloudtrail.lookup_events(
    LookupAttributes=[
        {
            'AttributeKey': 'EventName',
            'AttributeValue': 'OpenTunnel'
        }
    ],
    MaxResults=10
)

for event in response['Events']:
    print(f"时间: {event['EventTime']}")
    print(f"用户: {event['Username']}")
    print('---')

谁、什么时候、连了哪台——全自动。

EICE vs SSM Session Manager

EICE SSM Session Manager
协议 SSH/RDP 专有通道
客户端 标准 SSH CLI + SSM 插件
SCP/SFTP 原生支持 需要额外配
端口转发 支持 支持
Agent 不需要 需要 SSM Agent
审计 CloudTrail CloudTrail + S3

习惯 SSH 工作流用 EICE,要集中管控用 SSM。也可以两个都用。

踩坑

  1. 创建后等 3 分钟create-complete 才能连
  2. 安全组方向搞反 — EICE 配出站,目标配入站。很多人反着配
  3. Ubuntu 要装包 — Amazon Linux 自带,Ubuntu 需要 sudo apt install ec2-instance-connect
  4. 不支持纯 IPv6 子网
  5. 每 VPC 最多 5 个 — 多环境共用 VPC 要规划

以上代码基于亚马逊云科技 EC2 Instance Connect Endpoint,CLI 和 Python boto3 验证通过。


EICE 免费、零维护、IAM 认证、CloudTrail 审计
文档:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-using-eice.html

posted @ 2026-03-23 11:07  亚马逊云开发者  阅读(2)  评论(0)    收藏  举报