堡垒机(Bastion host),又称作跳转机(Jump box),是一台在外部网络为私有网络内的资源提供唯一访问入口的实例。安全合规起见,企业对网络出入口有非常严格的限制和规定。工作负载资源通常情况下不能途径互联网访问。堡垒机作为桥梁较好的解决此问题,即保持工作负载资源相对互联网的安全隔离,又满足开发运维人员受控访问工作负载资源的需求。除便利访问以外,一个成熟堡垒机架构还有如下功能,如记录审计日志,对会话和日志加密,精细化权限管理等。在多账户跨区域的现代化云环境背景下,对堡垒机架构设计又有更高要求和更多挑战。
亚马逊云科技提供诸多堡垒机构建方案,例如 “亚马逊云科技上的 Linux 堡垒机” 解决方案提供 Amazon CloudFormation 模版帮助部署弹性堡垒机于既有或新建 VPC。《通过堡垒机访问实例》一文讨论在单账户着陆区或多账户着陆区访问实例的常见问题和跨操作系统访问方法。《通过会话管理和 EC2 实例连接访问堡垒机》向导展示通过实例连接功能安全访问单账户环境下堡垒机的详细步骤。最近的一篇文章《基于 Amazon EC2 和 Amazon Systems Manager Session Manager 的堡垒机的设计和自动化实现》对堡垒机的优势和功能进行利弊分析和全面总结,并展示数据库联通性概念验证。这些文章都很有启发性,但也有不小的学习曲线和实现难度,特别是考虑到要适应云上多账户环境的情况。
我们以 Cloud Foundations 构建的云上多账户环境为基础,以实际落地为导向,逐步展示如何安全合规的快速构建稳健弹性的堡垒机架构,以实现会话管理和端口转发功能。您可以此为起点,优化构建更贴近您业务需求的堡垒机方案。
整体架构设计
下图展示以 Cloud Foundations 多账户组织结构为基础而构建的弹性堡垒机架构。总体而言:
- 堡垒机实例置于安全账户,由自动扩缩组管理提供峰谷弹性服务和上下班开关机服务;
- 上述堡垒机的安全组、启动模版、自动扩缩组及其策略等堡垒机产品在基础账户预定义;
- Cloud Foundations 基础着陆区配置会话管理首选项:
- 会话通过 SSM 密钥加密发送至同账户 CloudWatch 日志组和 SSM 日志桶;
- 会话空闲时长和会话最长时间;
- 启用非默认用户名登录堡垒机;
- 上述 SSM 客户托管密钥在安全账户集中管理,SSM 日志桶在日志账户集中管理;
- Cloud Foundations 共享网络联通产品在网络账户部署网络资源:
- 创建安全和工作负载 VPC 并共享子网至对应账户;
- 创建终端节点 VPC 使用亚马逊云科技私有网络访问服务(不经互联网关);
部署方法步骤
网络资源定义部署主要步骤为:
- 在基础账户系统应用配置的网络配置文件中定义网络结构 JSON 内容;
- 通过基础账户流水线工厂创建共享网络联通产品,启动产品以生成网络流水线;
- 发布网络流水线一键部署网络相关资源到网络账户、共享子网到成员账户并同步资源标签;
除网络资源外的堡垒机和数据库资源通过 Cloud Foundations 产品工厂定义部署,主要步骤为:
- (堡垒机)通过基础账户产品工厂创建预定义堡垒机产品,启动产品以生成堡垒机流水线;
- (堡垒机)发布堡垒机流水线一键部署堡垒机相关资源,例如安全组、启动模版和自动扩缩组;
- (数据库)在基础账户产品应用配置中定义数据库产品 JSON 内容;
- (数据库)通过基础账户产品工厂创建自定义数据库产品,启动产品以生成数据库流水线;
- (数据库)发布数据库流水线一键部署数据库相关资源,例如安全组、子网组和数据库实例;
主要实现功能
就上述堡垒机架构而言,您可以实现以下主要功能:
- 免 SSH 密钥登录位于安全账户私有子网的堡垒机,通过会话管理器公网地址连接到堡垒机而非通过互联网关直连,主要有三种途径:
- 通过亚马逊云科技命令行工具
- 通过 EC2 控制台
- 通过会话管理控制台;
- 在堡垒机配置数据库端口转发以在云下本地直接登录工作负载账户私有子网内的数据库实例;
网络联通规划
网络结构采用经典共享网络联通方案。借助 Amazon PrivateLink 技术通过亚马逊云科技私有网络访问服务,例如系统管理器,密钥管理,日志等,即不经互联网访问以提高安全性。利用接口终端节点专属 VPC 集中管理接口终端节点以节约成本。使用免费网关终端节点访问 S3。中转网关路由表分别为安全和工作负载账户建表,方便后续网络结构拓展。网络定义内容如下:
定义示例:
{
"vpcs": {
"endpoint": {
"cidr": "10.0.0.0/20",
"interface_endpoints": ["ssm", "ssmmessages", "ec2messages", "kms", "logs"],
"offsets": [[[8,160], [8,161]], [], [[4,2], [4,3]], [], [], []]
},
"security": {
"cidr": "10.0.16.0/20",
"accounts": ["SECURITY_ACCOUNT"],
"gateway_endpoints": ["s3"],
"offsets": [[[8,160], [8,161]], [], [[4,2], [4,3]], [], [], []]
},
"workload": {
"cidr": "10.0.32.0/20",
"accounts": ["WORKLOAD_ACCOUNT"],
"gateway_endpoints": ["s3"],
"offsets": [[[8,160], [8,161]], [], [[4,2], [4,3]], [[4,4], [4,5]], [], []]
}
},
"tgw_cidr": "10.0.0.0/16",
"tgw_route_tables": {
"security": {
"associations": ["security"], "propagations": ["endpoint", "workload"]
},
"workload": {
"associations": ["workload"], "propagations": ["endpoint", "security"]
},
"endpoint": {
"associations": ["endpoint"], "propagations": ["security", "workload"]
}
}
}
网络定义基本结构如总架构图所示。第一个 VPC 为接口终端节点专属 VPC(行 3 – 6),集中统一管理接口终端节点。后两个 VPC 分别共享子网到安全(行 8 – 12)和工作负载账户(行 14 – 18)。联通性方面两两互通(行 23 – 30)。按前述步骤部署网络资源,发布流水线两次并确认网络资源标签同步至成员账户。上述网络结构与之前博客的定义规范略有不同,该网络结构依据 Cloud Foundations 后续优化简化后的规范定义。
产品资源定义
Cloud Foundations 在部署基础着陆区时业已提前部署妥当以下资源:
- 公共云环境资源:安全账户 SSM 客户托管密钥,日志账户 SSM 日志桶并加密;
- 分账户专属资源:SSM 会话管理器首选项,CloudWatch 会话日志组并加密;
- 预定义堡垒机产品:基础账户产品应用配置中预定义堡垒机配置文件,开箱即用;
以下介绍预定义堡垒机产品和完成本文概念验证所需数据库资源。
预定义堡垒机
预定义堡垒机产品主要包含以下资源:
- (IAM) 基于最小授权原则配置适用于堡垒机的实例配置文件及登录堡垒机会话角色。特别通过 SSMSessionRunAs 标签和操作系统用户名交叉验证设置登录用户名;
- (VPC) 堡垒机安全组,允许访问接口终端节点和常见数据库;
- (EC2) 实例启动模版,自动扩缩组及其策略和定时任务。对于无状态堡垒机特别指定使用折扣实例 (Spot Instance) 以降低成本;
定义示例:
[
[
{
"service": "iam",
"accounts": ["SECURITY_ACCOUNT"],
"roles": {
"bastion-linux": { "template": "ssm-ec2" },
"bastion-user": { "template": "ssm-session-user" }
}
},
{
"service": "vpc",
"accounts": ["SECURITY_ACCOUNT"],
"security_groups": {
"bastion-host": {
"out": [
{ "cidr": "*", "protocol": "https" },
{ "cidr": "*", "protocol": "mssql" },
{ "cidr": "*", "protocol": "mysql" },
{ "cidr": "*", "protocol": "postgres" },
{ "cidr": "*", "protocol": "oracle" }
]
}
}
}
],
[
{
"service": "ec2",
"accounts": ["SECURITY_ACCOUNT"],
"templates": {
"bastion-host": {
"ami": "ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64",
"type": "t3.small",
"profile": "bastion-host",
"subnet": "private",
"security_group": "bastion-host",
"spot": true,
"storage": [{ "size": 20 }],
"user_data": ["#!/bin/bash", "useradd --create-home ${param_prefix}"]
}
}
}
],
[
{
"service": "autoscaling",
"accounts": ["SECURITY_ACCOUNT"],
"groups": {
"bastion-host": {
"size": [1, 1, 2],
"subnet": "private",
"template": "bastion-host",
"policy": { "type": "target", "metric": "cpu", "value": 50 },
"schedules": [
{ "size": [1, 1, 2], "cron": "0 8 * * *" },
{ "size": [0, 0, 0], "cron": "0 20 * * *" }
]
}
}
}
]
]
上述定义按依赖关系分三阶段构建自动扩缩组堡垒机:
- 此阶段并行构建无依赖关系的角色(行 4 – 8)和安全组资源(行 12 – 21)。其中角色资源复用标准预定义模版,即简洁又安全;
- 此阶段构建启动模版并配置操作系统登录用户名(行 29 – 40),其中实例配置文件(行 35)和安全组(行 37)引用第一阶段内容,子网引用前述共享至安全账户私有子网;
- 此阶段构建自动扩缩组(行 47 – 57),其中启动模版(行 53)引用第二阶段内容,子网引用前述共享至安全账户私有子网;
您可以根据业务需求微调其中参数,例如实例类型,登录用户名,开关机时间,扩缩触发条件等。
数据库资源
为测试堡垒机端口转发以从本地直连位于云上私有网络网络数据库,定义部署以下数据库资源:
- 数据库基础资源:监控角色,安全组和子网组;
- 数据库实例及其配置;
定义示例:
[
[
{
"service": "iam",
"accounts": ["WORKLOAD_ACCOUNT"],
"roles": { "rds-monitor": { "prebuilt": "rds-monitor" } }
},
{
"service": "vpc",
"accounts": ["WORKLOAD_ACCOUNT"],
"security_groups": {
"rds-mysql": { "in": [{ "protocol": "mysql", "cidr": "10.0.0.0/16" }] }
}
},
{
"service": "rds",
"accounts": ["WORKLOAD_ACCOUNT"],
"subnet_groups": { "db": {} }}
],
[
{
"service": "rds",
"accounts": ["WORKLOAD_ACCOUNT"],
"instances": {
"mysql": {
"type": "db.m5.large",
"engine": { "name": "mysql", "version": "8.0.33" },
"storage": { "size": 20, "max": 100 },
"subnet_group": "db",
"security_group": "rds-mysql",
"options": { "MARIADB_AUDIT_PLUGIN": {} },
"parameters": { "innodb_log_file_size": "536870912" }
}
}
}
]
]
上述定义按依赖关系分二阶段构建自动扩缩组堡垒机:
- 此阶段并行构建无依赖关系的监控角色(行 4 – 6)、数据库安全组(行 9 – 12)和数据库子网组资源(行 16 – 18)。其中数据库子网组引用前述共享至工作负载账户数据库子网;
- 此阶段构建数据库实例(行 22 – 32),其中实子网组(行 29)和安全组(行 30)引用第一阶段内容;
您亦可根据业务需求在上述定义基础上微调其中参数构建其他数据库实例,例如数据库类型及版本,实例类型,卷容量,选项组和参数组等。
预置角色定义模板
前述堡垒机实例配置文件和登录堡垒机角色定义,由于引用预置定义模版故只需一个属性,简洁且便捷。更重要的是,根据最佳实践和安全合规要求预置定义模版,又进一步提高系统整体安全规范程度,互为良性循环。
定义示例:
{
"role": {
"ssm-ec2": {
"trusts": { "default": ["ec2"] },
"managed": {
"default": ["AmazonSSMManagedInstanceCore", "CloudWatchAgentServerPolicy"]
},
"inline": {
"default": [
{ "actions": ["s3:GetEncryptionConfiguration"], "resources": ["*"]},
{ "actions": ["s3:PutObject"], "resources": ["$.s3.ssm/*"]},
{
"actions": ["kms:Decrypt", "kms:GenerateDataKey"],
"resources": ["$.kms.ssm"]
}
]
}
},
"ssm-session-user": {
"trusts": { "default": ["$.account.management", "$.account.security"] },
"inline": {
"default": [{
"actions": ["ssm:StartSession", "ssm:SendCommand"],
"resources": [
"$.arn.ec2:instance/*",
"$.arn.ssm:document/SSM-SessionManagerRunShell",
"arn:$PARTITION:ssm:$REGION::document/AWS-StartPortForwardingSessionToRemoteHost"
],
"conditions": {
"BoolIfExists": { "ssm:SessionDocumentAccessCheck": ["true"] }
}
},
{
"resources": ["*"],
"actions": [
"ssm:DescribeSessions",
"ssm:GetConnectionStatus",
"ssm:DescribeInstanceInformation",
"ssm:DescribeInstanceProperties",
"ec2:DescribeInstances"
]
},
{
"actions": ["ssm:TerminateSession", "ssm:ResumeSession"],
"resources": ["arn:$PARTITION:ssm:*:*:session/${aws:userid}-*"]
},
{ "actions": ["kms:GenerateDataKey"], "resources": ["$.kms.ssm"] }
]},
"tags": { "default": {"SSMSessionRunAs": "$(param_prefix)"} }
}
}
}
以上预定义角色模板定义两个角色:
- 实例配置文件(行 3 – 14),除了系统会话管理所需策略外,允许访问跨账户的 SSM 日志桶(行 11)和 SSM 客户托管密钥(行 13 – 14);
- 会话管理登录堡垒机角色(行 19 – 49),除了会话管理所需权限外,允许访问特定会话文档以在适当位置开启会话(行 23 – 30),允许访问跨账户的 SSM 客户托管密钥(行 47);
功能测试
从命令行登录堡垒机
从命令行登录堡垒机前需设置堡垒机用户临时凭证环境变量,例如:
[ssm-session]
role_arn=arn:aws:iam::SECURITY_ACCOUNT:role/PREFIX-role-bastion-user
credential_source=Environment
role_session_name=iac
然后动态获取堡垒机实例标识:
export INSTANCE_ID=$(aws ec2 describe-instances --output text --no-paginate \
--filters "Name=tag:Name,Values=PREFIX-asg-bastion-linux" \
--query 'Reservations[0].Instances[0].InstanceId' --profile ssm-session)
之后登录:
$ aws ssm start-session --target $INSTANCE_ID \
--document-name SSM-SessionManagerRunShell --profile ssm-session
从控制台登录堡垒机
代入安全账户会话角色后您可以从 EC2 控制台或者会话管理器控制台点击连接按钮登录。
设置端口转发至本地连接云上数据库
通过远程实例端口转发文档转发端口到本地连接云上数据库,在负载账户 RDS 控制台获取数据库实例地址,在密码管理器获取数据库密码,然后通过本地端口 13306 连接云上MySQL 数据库实例。
aws ssm start-session --target $INSTANCE_ID \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"portNumber":["3306"],"localPortNumber":["13306"],"host":["cfsinorg-rds-mysql.****.ap-southeast-1.rds.amazonaws.com"]}' --profile ssm-session
总结
我们介绍了堡垒机的基本概念,并以 Cloud Foundations 构建的云上多账户环境为基础演示如何部署预定义弹性堡垒机产品至安全账户、多渠道登录堡垒机、借助堡垒机转发端口登录云上数据库实例等功能。上述大部分内容和资源都已经由 Cloud Foundations 预置或预定义,简单操作即可开箱即用,构建安全合规的云上环境及访问方法。您可联系亚马逊云科技专家进一步了解,助力您高效开展安全运维云上业务旅程。
本篇作者