停止在 AWS 中使用 SSH!原因如下!DevSecOps 视角

我们要解决什么问题?欢迎来到雲闪世界
我见过多少次安全组从 10.0.0.0/8 或更糟的 0.0.0.0/0 开放端口 22?太多次了!但为什么,为什么在有更好的替代方案的情况下,我们在 2024 年仍在使用 SSH?作为一名安全专家,我经常被要求说服人们“一种更好的工作方式”。我经常失败。人们喜欢快速简便的工作方式 (我不怪他们!)。但在安全事故数量不断上升的时代,我们必须找到一种更好的工作方式,一种在设计上就内置安全性的方式。
此外,如果您在 YouTube 上观看技术视频,您经常会看到面向公众的 EC2 实例,SSH 向“我的 IP”开放。我不会责怪内容创建者这样做,毕竟,他们只是想向人们展示如何执行特定任务。然而,许多开发人员认为这是唯一的工作方式,因此当安全专家告诉他们需要更改连接到 EC2 的方式时,他们通常会遭到抵制。
那么,如何在没有密钥对、没有公共 IP 地址、没有配置不当的安全组的情况下提供对 EC2 实例的安全访问,同时受益于增强的日志记录和安全性?!
答案是系统管理器和会话管理器。


什么是系统管理器 (SSM)?

我们要解决什么问题?
我见过多少次安全组从 10.0.0.0/8 或更糟的 0.0.0.0/0 开放端口 22?太多次了!但为什么,为什么在有更好的替代方案的情况下,我们在 2024 年仍在使用 SSH?作为一名安全专家,我经常被要求说服人们“一种更好的工作方式”。我经常失败。人们喜欢快速简便的工作方式 (我不怪他们!)。但在安全事故数量不断上升的时代,我们必须找到一种更好的工作方式,一种在设计上就内置安全性的方式。
此外,如果您在 YouTube 上观看技术视频,您经常会看到面向公众的 EC2 实例,SSH 向“我的 IP”开放。我不会责怪内容创建者这样做,毕竟,他们只是想向人们展示如何执行特定任务。然而,许多开发人员认为这是唯一的工作方式,因此当安全专家告诉他们需要更改连接到 EC2 的方式时,他们通常会遭到抵制。
那么,如何在没有密钥对、没有公共 IP 地址、没有配置不当的安全组的情况下提供对 EC2 实例的安全访问,同时受益于增强的日志记录和安全性?!
答案是系统管理器和会话管理器。

什么是系统管理器 (SSM)?

AWS Systems Manager 是您的 AWS 应用程序和资源的运营中心,也是混合和多云环境的安全端到端管理解决方案,可实现大规模安全运营。
Systems Manager 提供的一些服务包括:

  • 补丁管理
  • 软件分发
  • EC2 清单
  • 配置管理
  • 会话管理器

什么是会话管理器?
您可以使用交互式一键式基于浏览器的 shell 或 AWS 命令​​行界面 (AWS CLI) 连接到 AWS EC2 实例。会话管理器提供安全且可审计的节点管理,无需打开入站端口、维护堡垒主机或管理 SSH 密钥。会话管理器还允许您遵守公司政策,这些政策要求对托管节点进行受控访问、严格的安全实践以及包含节点访问详细信息的完全可审计日志,同时为最终用户提供对托管节点的简单一键式跨平台访问。


为什么使用会话管理器而不是 SSH?

  • 使用 IAM 策略对托管节点进行集中访问控制
  • 安全组中无需开放入站端口 22 或 3389 (Windows)
  • 无需管理堡垒主机或 SSH 密钥
  • 记录和审核会话活动。

日志记录功能分为两个级别,首先,所有会话都记录到 AWS CloudTrail,使活动审计与其他 AWS 服务和事件类型保持一致。这确保了会话处于活动状态时执行的活动不可否认。
其次,按键操作可以捕获到集中式日志记录设施,例如 CloudWatch 或 Amazon S3。这意味着,如果您有特定的监管要求,需要通过终端记录在 EC2 实例上执行的所有操作,您可以这样做。这对安全运营团队在进行事件调查时也非常有益,因为他们可以根据已知的可疑活动(例如特权升级)建立警报。

解决方案架构概述
为多帐户环境进行设计并不简单,尤其是当您涉及加密密钥时,但是可以通过在帐户配置过程中自动执行下面概述的配置来减轻复杂性。下面的设计应该有助于阐明我们如何解决 SSH 挑战,而不会给开发人员或平台工程师增加障碍。

多账户环境中会话管理器日志的高级设计多账户环境中会话管理器日志的高级设计

日志账户(S3 和 CloudWatch)
日志账户位于安全组织单位 (OU) 中。S3 存储桶和 CloudWatch 日志组在此账户中配置,并使用 KMS 密钥加密。
VPC 端点 (VPCe)
在 Workloads OU 中的每个 AWS 账户中,配置 VPC 端点以将流量保持在 AWS 云内部。这样就可以通过 VPCe 访问 S3 存储桶和 CloudWatch Log 组,而无需传出到 Internet。
EC2 实例
EC2 实例配置了自定义实例配置文件,具有将日志发送到 CloudWatch 和 S3 的权限,确保它们有权使用 KMS 密钥进行加密。此外,AWS 还提供了管理 IAM 策略,使 Systems Manager 能够运行;这也附加到实例配置文件中。
系统管理器和会话管理器
会话管理器首选项是存储上述配置的地方,确保使用相同的 S3 存储桶或 CloudWatch 组。
将日志导入 SIEM(可选)
安全信息和事件管理系统将从多个来源捕获日志,以进行分析并对潜在恶意活动发出警报。与在 CloudWatch 中配置警报相比,安全分析师在 SIEM 中配置规则可能更容易。这也意味着您可以快速使 CloudWatch 日志过期以节省成本,因为无论如何日志都会被提取到外部系统中。
会话记录的先决条件

  • 使用安装了 SSM 代理的 Amazon 系统映像 (AMI)(Amazon Linux 2023 默认安装了它)。
  • 按照AWS 的指南配置系统管理器(某些设置在我的 terraform 配置中)。
  • 确保已配置 ec2messages、ssm、ssmmessages、kms、logs 和 s3 的 VPC 端点。我还发现还需要 S3 的网关端点。

设置和使用会话管理器日志
Terraform 配置
下面是我用来配置此演示的核心方面的 Terraform。
ec2.tf — 配置 EC2 实例和相关设置
这将在您的 VPC 中创建 EC2,并创建一个允许所有 IP 地址出站的安全组。请注意,没有入站端口 22。还有一个 IAM 策略,用于向 CloudWatch、S3 和 KMS 提供权限;这确保我们可以发送日志并使用正确的加密密钥。
接下来,这将创建角色,附加我们的 IAM 策略以及所需的 AmazonSSMManagedInstanceCore 策略。(这是一个 AWS 托管策略,是 SSM 服务与 EC2 实例上的 SSM 代理通信所必需的)。
最后,将创建一个实例配置文件,并使用从 IAM 角色获取的权限将其附加到 EC2。

# Creates EC2 instance
resource "aws_instance" "ssm_recording_example" {
  ami                    = data.aws_ami.amazon_linux_2023.id
  instance_type          = "t2.micro"
  iam_instance_profile   = aws_iam_instance_profile.ec2_ssm_instance_profile.name
  subnet_id              = data.aws_subnet.subnet.id
  vpc_security_group_ids = ["${aws_security_group.session_manager_security_group.id}"]
  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required" # This enforces the use of IMDSv2
    http_put_response_hop_limit = 1
  }
  tags = {
    Name        = "Session Manager Demo"
    Environment = "Development"
    Owner       = "Medium Article"
  }
}
# Creates Security Group
resource "aws_security_group" "session_manager_security_group" {
  name        = "Session Manager Security Group"
  description = "Session Manager Security Group"
  vpc_id      = data.aws_vpc.main.id
  tags = {
    Name : "Session Manager Security Group"
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
# Creates EC2 IAM Policy
resource "aws_iam_policy" "session_manager_recording_policy" {
  name        = "SSM-SessionManager-S3-KMS-Logging"
  description = "Policy for SSM Session Manager logging to S3 with KMS encryption"
  policy      = <<EOF
  {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PutObjectsBucket",
      "Action": [
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Effect": "Allow",
      "Resource": "${aws_s3_bucket.log_bucket.arn}/*"
    },
    {
      "Sid": "ListBucketAndEncryptionConfig",
      "Action": [
        "s3:GetEncryptionConfiguration"
      ],
      "Effect": "Allow",
      "Resource": "${aws_s3_bucket.log_bucket.arn}"
    },
    {
      "Sid": "S3KMSSessionManagerKMS",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey*"
      ],
      "Resource": [
        "${aws_kms_key.log_key.arn}"
      ]
    },
        {
            "Sid": "cloudwatch",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*"
        }
  ]
}
EOF
}
# Creates IAM role
resource "aws_iam_role" "ec2_ssm_role" {
  name = "ec2_ssm_role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
  managed_policy_arns = ["${aws_iam_policy.session_manager_recording_policy.arn}", "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
}
# Creates instance profile
resource "aws_iam_instance_profile" "ec2_ssm_instance_profile" {
  name = "ec2_ssm_instance_profile"
  role = aws_iam_role.ec2_ssm_role.name
}

s3.tf - 存储桶配置

在这里创建存储桶、启用版本控制(推荐)、定义 KMS 密钥以及存储桶策略。为 S3、KMS 和 EC2 定义资源和身份策略似乎很复杂,但请记住,这是一个多帐户配置,因此需要多做一些工作才能获得正确的权限。

resource "aws_s3_bucket" "log_bucket" {"aws_s3_bucket" "log_bucket" {
  bucket = var.bucket_name
}

resource "aws_s3_bucket_versioning" "log_bucket_versioning" {
  bucket = aws_s3_bucket.log_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}
resource "aws_s3_bucket_server_side_encryption_configuration" "log_bucket_encryption" {
  bucket = aws_s3_bucket.log_bucket.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.log_key.arn
    }
    bucket_key_enabled = true
  }
}
resource "aws_s3_bucket_policy" "log_bucket_policy" {
  bucket = aws_s3_bucket.log_bucket.id
  policy = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetEncryptionConfiguration",
            "Resource": "${aws_s3_bucket.log_bucket.arn}",
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalOrgID": "${var.organization_id}"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "${aws_s3_bucket.log_bucket.arn}/*",
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalOrgID": "${var.organization_id}"
                }
            }
        }
    ]
}
POLICY
}


cloudwatch.tf — 日志组
这将创建一个日志组并使用 KMS 密钥进行加密。(在生产环境中,最好为 CloudWatch 和 S3 使用专用的 KMS 密钥。

resource "aws_cloudwatch_log_group" "session_manager_logs_group" {"aws_cloudwatch_log_group" "session_manager_logs_group" {
  name              = "session_manager_logs"
  kms_key_id        = aws_kms_key.log_key.arn
  log_group_class   = "STANDARD"
  retention_in_days = 30
  tags = {
    Environment = "Sandbox"
  }
}

data.tf — 填充输入以供稍后使用
这是我们指定 VPC 的标签名称的地方,因此我们可以使用 terraform 查询 AWS API 并检索其属性,即 VPC ID。如果您知道 VPC ID,则不需要此数据源,只需将 VPC ID 引用为变量,或者如果它作为资源存在于您的 terraform 配置中,请从那里引用它。(子网 ID 类似)
最后,我们查询最新的 AMI,如果您使用的是 Amazon Linux 2023 映像,这将很有用。我们输出 AMI ID 以供稍后使用。

data "aws_vpc" "main" {"aws_vpc" "main" {
  filter {
    name   = "tag:Name"
    values = ["INSERT VPC NAME"]
  }
}

data "aws_subnet" "subnet" {
  filter {
    name   = "tag:Name"
    values = ["INSERT SUBNET NAME"]
  }
}

data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-kernel-5.10-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
}

output "ami_id" {
  value = data.aws_ami.amazon_linux_2023.id
}


变量
这里的变量是存储桶的名称、组织 ID、帐户 ID 和区域。您的 Terraform 中可能不需要其中的部分或全部,具体取决于您的 Terraform 状态中已有的内容。同样,您可以选择使用其他方法来输入这些值,以使代码更具可重用性,例如 CI 管道变量。

variable "bucket_name" {"bucket_name" {
  type    = string
  default = "medium-session-manager-article"
}

variable "organization_id" {
  type    = string
  default = "INSERT ORG ID"
}

variable "account_id" {
  type    = string
  default = "INSERT ACCOUNT ID"
}

variable "region" {
  type    = string
  default = "eu-west-1"
}


请注意,在撰写本文时,AWS Terraform 提供程序中没有用于会话管理器首选项的原生 Terraform 资源。但是,如果您想自动执行此过程,可以使用自定义模块,可在此处找到。在接下来的几个步骤中,我将改为显示来自 AWS 控制台的屏幕截图。

  1. 访问 AWS 中的 Systems Manager 服务,在 Node Management 下,您将找到 Session Manager。单击Preferences,然后单击 Edit

2. 在常规首选项中,您可以指定多个选项,包括(如果愿意,您可以将这些选项保留为默认选项):

  • 会话超时
  • 最大会话时长——您可以选择在 SSM 中恢复会话,因此这需要与您的团队讨论
  • 使用 KMS 代替 TLS
  • 为 Linux EC2 实例指定运行方式 — 如果您拥有具有特定用户的自定义 AMI,则这可能会很有用。

3. 日志选项——重要!
这是我们指定日志发送目的地的地方。我们可以指定 CloudWatch、S3 或两者。

4. 我们可以在这里指定几个选项,在本例中我们保留默认设置。选择要将日志发送到的 CloudWatch 日志组,然后单击“保存”。

5. 如果需要,我们还可以将日志发送到 S3;如果您有日志保留要求并且希望将 CloudWatch 成本降至最低,这可能会很有用。
选择要将日志发送到的存储桶,并指定选项前缀。我建议使用AccountID/session-logs/前缀,这样您就可以轻松识别日志来自哪个 AWS 帐户。提醒一下,没有用于此目的的 Terraform 资源,因此您需要手动完成此部分或作为帐户销售流程的一部分。

CloudWatch 中的示例日志
下面是我在 EC2 实例中输入一些命令的示例。

以下是 CloudWatch 中的相应活动。

值得注意的是,会话记录在 AWS CloudTrail 中,提供审计功能,以实现问责和不可否认性。
会话管理器如何通过将活动记录到 CloudWatch 和 S3 来增强安全态势
通过捕获 EC2 实例的按键,它将帮助安全团队提高检测和响应能力,因为他们可以为输入特定命令(例如提升到 root 权限)的情况建立规则。此外,通过将日志发送到 SIEM,可以使用威胁情报(包括入侵指标 (IOC))来丰富日志,这可能会揭示试图连接到可疑域(命令和控制流量)的行为,无论是窃取数据还是用作加密挖掘队列的一部分。
该解决方案的第二个好处是它增加了一层审计和合规性,使安全团队能够记录已发生的变更。这允许外部审计员批准有足够的控制措施来检测未经授权的活动。此外,由于 SSM 使用 IAM 权限授予对 Session Manager 的访问权限,因此如果通过公司安全策略限制控制台访问,它可以用作预防性控制。应该注意的是,还有其他解决方案可以提供更复杂的特权访问,其中之一就是Teleport
需要注意的是,如果 EC2 以其他方式受到攻击(例如导致远程执行命令的 RCE 攻击),会话管理器将不会捕获日志,因此始终有必要实施多种安全控制措施来检测和应对威胁。示例包括将 Linux 操作系统日志从 EC2 实例集中到 CloudWatch 和部署端点传感器(如eBPF)
最后的想法
AWS 一直在努力寻找更安全的方式来提供对其服务的访问,但让大家接受这些新的工作方式往往是一个挑战。人们已经习惯了自己的工作方式,很难改变他们的工作方式;通过终端或使用堡垒进行连接是一种便捷的做法,这种做法已经存在了 25 年多。
虽然有一些像 Teleport 这样的第三方供应商做得很好,但有时使用原生 AWS 工具更容易,使用 Wiz 之类的工具集中审核配置并将其注销到 CloudWatch 或 S3 之类的一致存储解决方案。
我可能应该在本文开头就说明一个免责声明;这假设您的环境中已经存在高水平的一致性和护栏;如果您允许开发人员在没有正确 IAM 角色的情况下启动 EC2 实例,SSM 根本无法工作。因此,您需要有权限边界或服务控制策略等控制措施来强制遵守上述护栏。您甚至可以强制实施基础设施即代码扫描,以防止在没有此解决方案运行所需的先决条件的情况下部署配置。

感谢关注雲闪世界。(Aws解决方案架构师vs开发人员&GCP解决方案架构师vs开发人员)

  • 32
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值