一款用 Ruby 编写的多线程 AWS 安全清单收集工具。
该工具旨在高效收集大量 AWS 资源属性与元数据。它目标是收集与 AWS 环境安全配置及状态相关的几乎所有内容。
现有工具(例如 AWS Config)虽然能执行某些资源收集,但在覆盖范围和特异性上不足以准确衡量安全状态(例如详细的资源属性数据、完整解析的策略文档以及嵌套的资源关系)。
AWS Recon 通过利用自动重试(无论是网络可靠性问题还是 API 限流)、自动分页处理大型响应(每次 API 调用超过 100 个资源)以及多线程并行请求来加速收集,从而处理大型账户的收集工作。
** 使用并不表示认可
AWS Recon 需要一个具有 ReadOnlyAccess 权限的 AWS 账户角色或凭证。完整的 AdministratorAccess 权限过高,但也可以使用。SecurityAudit 策略不足,因为它缺少对许多服务的访问权限。
使用 Docker 19.x 或更高版本运行预构建的镜像,无需安装任何东西。
如果您已安装 Ruby(2.6.x 或 2.7.x),则可能需要安装 Ruby gem。
AWS Recon 可以通过 Docker 容器本地运行,也可以通过安装 Ruby gem 运行。
要通过 Docker 容器运行,请将必要的 AWS 凭证传递给 Docker run 命令。例如:
$ docker run -t --rm \
-e AWS_REGION \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN \
-v $(pwd)/output.json:/recon/output.json \
darkbitio/aws_recon:latest \
aws_recon -v -s EC2 -r global,us-east-1,us-east-2
要在本地运行,首先安装 gem:
$ gem install aws_recon
Fetching aws_recon-0.5.17.gem
Fetching aws-sdk-3.0.1.gem
Fetching parallel-1.20.1.gem
...
Successfully installed aws-sdk-3.0.1
Successfully installed parallel-1.20.1
Successfully installed aws_recon-0.5.17
或者使用 bundle 将其添加到 Gemfile:
$ bundle add aws_recon
Fetching gem metadata from https://rubygems.org/
Resolving dependencies...
...
Using aws-sdk 3.0.1
Using parallel-1.20.1
Using aws_recon 0.5.17
AWS Recon 将利用运行环境当前可用的任何 AWS 凭证(参见 要求)。如果您要从多个账户收集数据,可能需要使用类似 aws-vault 的工具来管理不同的凭证。
$ aws-vault exec profile -- aws_recon
普通的环境变量也可以正常工作。
$ AWS_PROFILE=<profile> aws_recon
从 Docker 容器使用 aws-vault 管理的凭证运行(输出到标准输出):
$ aws-vault exec <vault_profile> -- docker run -t --rm \
-e AWS_REGION \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN \
darkbitio/aws_recon:latest \
aws_recon -j -s EC2 -r global,us-east-1,us-east-2
从 Docker 容器使用 aws-vault 管理的凭证并将输出写入文件,您需要满足几个要求。首先,Docker 需要能够绑定挂载您指定的路径(或其父路径)。其次,您需要创建一个空文件来保存输出(例如 output.json)。这是因为在运行时只有该文件被挂载到 Docker 容器中。例如:
创建一个空文件。
$ touch output.json
运行 aws_recon 容器,指定输出文件。
$ aws-vault exec <vault_profile> -- docker run -t --rm \
-e AWS_REGION \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN \
-v $(pwd)/output.json:/recon/output.json \
darkbitio/aws_recon:latest \
aws_recon -s EC2 -v -r global,us-east-1,us-east-2
您可能希望最初使用 -v 或 --verbose 标志来查看收集运行时的状态和活动。
在详细模式下,控制台输出将显示:
<thread>.<region>.<service>.<operation>
t 前缀表示特定请求正在哪个线程下运行。Region、service 和 operation 指示当前正在进行的请求操作及其位置。
$ aws_recon -v
t0.global.EC2.describe_account_attributes
t2.global.S3.list_buckets
t3.global.Support.describe_trusted_advisor_checks
t2.global.S3.list_buckets.acl
t5.ap-southeast-1.WorkSpaces.describe_workspaces
t6.ap-northeast-1.Lightsail.get_instances
...
t2.us-west-2.WorkSpaces.describe_workspaces
t1.us-east-2.Lightsail.get_instances
t4.ap-southeast-1.Firehose.list_delivery_streams
t7.ap-southeast-1.Lightsail.get_instances
t0.ap-south-1.Lightsail.get_instances
t1.us-east-2.Lightsail.get_load_balancers
t7.ap-southeast-2.WorkSpaces.describe_workspaces
t2.eu-west-3.SageMaker.list_notebook_instances
t3.eu-west-2.SageMaker.list_notebook_instances
Finished in 46 seconds. Saving resources to output.json.
# 收集 S3 和 EC2 全局资源,以及 us-east-1 和 us-east-2
$ AWS_PROFILE=<profile> aws_recon -s S3,EC2 -r global,us-east-1,us-east-2
# 收集 S3 和 EC2 全局资源,以及 us-east-1 和 us-east-2
$ AWS_PROFILE=<profile> aws_recon --services S3,EC2 --regions global,us-east-1,us-east-2
# 将输出保存到 S3 存储桶
$ AWS_PROFILE=<profile> aws_recon \
--services S3,EC2 \
--regions global,us-east-1,us-east-2 \
--verbose \
--s3-bucket my-recon-bucket
# 将输出保存到 S3 存储桶,并指定非 us-east-1 的主区域
$ AWS_PROFILE=<profile> aws_recon \
--services S3,EC2 \
--regions global,us-east-1,us-east-2 \
--verbose \
--s3-bucket my-recon-bucket:us-west-2
示例 OpenCSPM 格式(NDJSON)输出。
$ AWS_PROFILE=<profile> aws_recon -l \
-s S3,EC2 \
-r global,us-east-1,us-east-2 \
-f custom
或
$ AWS_PROFILE=<profile> aws_recon -j \
-s S3,EC2 \
-r global,us-east-1,us-east-2 \
-f custom > output.json
大多数情况下,与权限相关的 API 异常会被静默忽略。这些错误通常由以下原因引起:
在 verbose 模式下,您会在输出中看到异常日志:
t2.us-east-1.EC2.describe_subnets.0
t4.us-east-1.SSM.describe_instance_information.0
t6.us-east-1.SecurityHub.InvalidAccessException <-----
t2.us-east-1.EC2.describe_addresses.0
t4.us-east-1.SSM.describe_parameters.0
t1.us-east-1.GuardDuty.list_detectors.0
使用 -q 命令行选项可以重新抛出这些异常,从而更容易排查访问问题。
Traceback (most recent call last):
arn:aws:sts::1234567890:assumed-role/role/my-audit-role is not authorized to perform:
codepipeline:GetPipeline on resource: arn:aws:codepipeline:us-west-2:1234567890:pipeline
(Aws::CodePipeline::Errors::AccessDeniedException)
堆栈跟踪的最后一行显示了触发异常的准确 API 操作。如果您无法解决必要的访问问题,应使用 -x 或 --not-services 排除这些服务,或者省略 -q 选项以便收集可以继续。
AWS Recon 使用多线程来克服向全球各地端点执行大量 API 调用时面临的 I/O 挑战。
对于全局服务(如 IAM、Shield 和 Support),请求不会多线程处理。S3 模块是多线程的,因为每个存储桶需要多次额外的调用来收集完整的元数据。
对于区域服务,每个区域的服务都会生成一个线程(不超过线程数限制)。默认情况下,最多使用 8 个线程。如果您的账户资源分布在多个区域,可以通过 -t X 增加线程数(其中 X 是线程数)来提升速度。
在新/空账户中,AWS Recon 至少会进行约 2,000 次 API 调用,以便查询所有 20 个标准(非 GovCloud、非中国)区域中支持的服务。在大型账户中,如果启用的线程数超过默认值(8),很可能遇到 API 速率限制(限流)。
Recon 会自动退避并尊重 API 响应中的重试限制。如果您在收集过程中观察到长时间停顿,很可能就是这个原因。使用 -d 或 --debug 选项重新收集以观察线路跟踪,查看是否被限流。如果您经常被限流,请考虑减少线程数或向 AWS 申请提高速率限制。
大多数用户会希望将收集范围限制在相关的服务和区域内。不进行任何排除运行将尝试收集账户中所有已启用区域的所有资源。
$ aws_recon -h
AWS Recon - AWS Inventory Collector (0.5.17)
Usage: aws_recon [options]
-r, --regions [REGIONS] 要扫描的区域,以逗号分隔(默认:全部)
-n, --not-regions [REGIONS] 要跳过的区域,以逗号分隔(默认:无)
-s, --services [SERVICES] 要扫描的服务,以逗号分隔(默认:全部)
-x, --not-services [SERVICES] 要跳过的服务,以逗号分隔(默认:无)
-c, --config [CONFIG] 指定服务和区域的配置文件(例如 config.yaml)
-b, --s3-bucket [BUCKET:REGION] 将输出文件写入 S3 存储桶(默认:'')
-o, --output [OUTPUT] 指定输出文件(默认:output.json)
-f, --format [FORMAT] 指定输出格式(默认:aws)
-t, --threads [THREADS] 指定最大线程数(默认:8,最大:128)
-l, --json-lines 输出 NDJSON/JSONL 格式(默认:false)
-u, --user-data 收集 EC2 实例用户数据(默认:false)
-z, --skip-slow 跳过慢速操作(默认:false)
-g, --skip-credential-report 跳过生成 IAM 凭据报告(默认:false)
-j, --stream-output 将 JSON lines 流式输出到 stdout(默认:false)
-v, --verbose 输出客户端进度和当前操作
-q, --quit-on-exception 遇到 API 错误时停止收集(默认:false)
-d, --debug 输出调试信息及线路跟踪
-h, --help 打印此帮助信息
输出始终是某种形式的 JSON——JSON lines 或纯 JSON。输出写入文件(默认),或写入标准输出(使用 -j)。
当写入 S3 存储桶时,JSON 输出会自动使用 gzip 压缩。
如果您已启用手动启用的区域:
并且您使用 STS 代入角色到账户,您需要在代入角色来源的账户中启用 v2 STS 令牌,才能对上述区域运行 AWS Recon。
版本 1 令牌仅在默认可用的 AWS 区域中有效。这些令牌在手动启用的区域(如亚太(香港))中无效。版本 2 令牌在所有区域均有效。但版本 2 令牌更长,可能会影响临时存储令牌的系统。
如果您使用静态访问密钥/密钥,则可以不受 STS 令牌版本影响地从这些区域进行收集。
以下列出了当前每个服务的“覆盖范围”。尚未覆盖的服务将陆续添加。欢迎提交 PR。:)
AWS Recon 旨在收集所有与确定 AWS 账户安全状态相关的资源和元数据。但它并不实际检查资源的安全状态——那是其他工具的工作,它们将 AWS Recon 的输出作为输入。
AWS Recon 的主要动机之一是构建一个易于维护和扩展的工具。如果您认为某个特定服务的覆盖范围可以改进,我们欢迎为此提交 PR。任何对 Ruby 有一定熟悉程度的人都可以模仿现有收集器使用的模式来查询特定服务,并将结果添加到资源收集中。
克隆此仓库:
$ git clone [email protected]:darkbitio/aws-recon.git
$ cd aws-recon
如果使用 RVM,请创建一个粘性 gemset:
$ rvm use 2.7.2@aws_recon_dev --create --ruby-version
运行 bin/setup 安装依赖。然后运行 rake test 执行测试。您也可以运行 bin/console 进入交互式提示进行实验。
要将此 gem 安装到本地机器,运行 bundle exec rake install。要发布新版本,请更新 version.rb 中的版本号,然后运行 bundle exec rake release,这将为该版本创建 git 标签,推送 git 提交和标签,并将 .gem 文件推送到 rubygems.org。
AWS Recon 的灵感来源于以下工具的作者和团队所做的出色工作: