如果你的团队正在为SOC 2 Type II审核做准备,那么这本手册正是为你准备的。它详细列出了审计人员实际会检查的90天时间安排、14项关键控制措施以及证据收集所需的相关基础设施。
虽然大家都会公布这些控制措施的具体清单,但却没有人会提供那份按周划分的工作计划表——而这份计划表正是确保一切顺利进行所必需的。
这里提供了详细的90天时间安排,其中也提到了那些可能会使整个流程延长60天的错误因素,以及如何避免这些错误。
目录
你将学到什么
读完这本手册后,你将会了解:
-
如何正确确定SOC2审核的范围——这个决定将影响后续的所有工作
-
在观察期第一天就必须激活的14项控制措施
-
如何构建能够自动运行的证据收集系统
-
如何选择审计师并进行准备情况评估
-
观察期内会发生哪些事情,以及如何在不影响时间安排的情况下弥补不足之处
现在让我们开始吧。
先决条件
在开始学习之前,你需要具备以下条件:
知识要求:
-
对AWS服务有基本了解(如EC2、RDS、S3、IAM、VPC等)
-
熟悉Terraform或其他代码化基础设施管理工具
-
能够熟练阅读GitHub Actions中的YAML工作流脚本
-
对SOC2的基本概念有所了解;如果完全是初次接触,建议先阅读AICPA关于SOC2的概述
工具与访问权限:
-
拥有具有管理员权限的AWS账户
-
拥有具备管理员权限的GitHub组织账号
-
已安装Terraform(版本1.0或更高版本)
-
Python 3.8或更高版本(用于运行证据收集相关脚本)
预计耗时: 从开始到结束总共需要90天。在最初的六周里,相关工程师每周需要投入大约8到12小时的工作;而在后续的观察期内,这一时间会减少到每周2到4小时。
第1至2周:确定SOC2范围的边界——哪些内容应包含在内,哪些应排除在外
大多数团队常犯的错误
大多数团队将SOC2的范围定得过于宽泛。他们会将所有的AWS账户、所有服务以及所有环境都纳入其中。这种做法是错误的,原因如下:
如果范围过广,那就意味着需要实施更多的控制措施,需要收集更多的证据,同时审计人员也需要检查更多的系统。
任何位于你设定的边界范围内的系统,都必须满足全部14项控制要求。如果将开发沙箱也包含在内,那么你的工程师们使用的实验环境就必须启用GuardDuty、进行CloudTrail日志记录,并且部署过程也要受到保护。对于那些对客户没有任何风险的系统来说,这样做无疑会增加大量的工作量,还会耗费数月的时间来收集证据。
正确界定SOC2的范围意味着,你只需要将那些存储、处理或传输客户数据的系统纳入其中,并证明其他所有系统都无法接触到这些数据。
错误的范围设定(过于宽泛):
整个AWS组织
├── 生产环境(属于范围)
├── 测试环境(属于范围)
├── 开发环境(属于范围)
├── 沙箱环境(属于范围)
└── CI/CD流程(属于范围)
正确的范围设定(界定得当):
SOC2边界
├── 生产环境AWS账户(属于范围)
├── 生产环境EKS集群(属于范围)
├── 生产环境RDS数据库(属于范围)
└── 其他所有内容(不属于范围——通过网络隔离来确保这一点)
正确界定范围的原因是,它只将那些真正负责处理客户数据的系统纳入保护范围。而边界之外的所有系统,都是通过技术手段被彻底隔离开来的,因此这些系统无法接触到边界内的任何数据。
确定范围边界的框架
对于你的基础设施中的每一个系统,都要问自己以下四个问题:
| 问题 | 如果是 | 如果不是 |
|---|---|---|
| 这个系统是否存储、处理或传输客户数据? | ✅ 属于范围 | ❌ 不属于范围 |
| 这个系统是否会影响到面向客户的服务的可用性? | ✅ 属于范围 | ❌ 不属于范围 |
| 这个系统是否能够访问生产环境的凭证信息? | ✅ 属于范围 | ❌ 不属于范围 |
| 如果这个系统遭到攻击,是否会导致客户数据泄露? | ✅ 属于范围 | ❌ 不属于范围 |
只要有一个问题的答案是“是”,那么这个系统就应该被纳入你的SOC2保护范围之内。
网络隔离——证明你的边界设定有效的技术手段
网络隔离是指将基础设施划分为相互独立的区域,这样一来,一个区域内的系统就无法与另一个区域的系统进行通信,除非你明确允许它们之间进行交互。
在SOC2的框架下,这种技术控制措施能够证明那些不在评估范围内的系统确实无法访问处于评估范围内的系统——这不仅仅是通过政策规定来实现的,而是通过基础设施层面的限制来保障的。
如果没有实施网络隔离,SOC2审核人员就无法确认你的安全边界是否真实有效。如果你的沙箱环境中的开发人员能够访问生产环境中的数据库,那么无论你的架构图上如何标注,这个沙箱环境实际上都属于评估范围之内。
以下是使用Terraform在生产环境与非生产环境之间实现网络隔离的示例代码。网络访问控制列表会阻止所有来自私有IP地址范围(10.0.0.0/8)的入站流量进入生产环境的VPC;而`aws_vpc_peering_connection`注释则明确表示了不建立环境间互连的决策:
# 该账户没有与非生产环境建立VPC互连。
# 正正是因为没有这种互连,才实现了网络隔离。
# 在未经SOC2审核之前,请勿为该账户添加任何互连连接。
resource "aws_network_acl" "deny_non_production" {
vpc_id = aws_vpc.production.id
# 阻止所有来自非生产环境IP地址范围的入站流量
ingress {
rule_no = 100
action = "deny"
from_port = 0
to_port = 0
protocol = "-1"
cidr_block = "10.0.0.0/8"
}
# 允许来自互联网的合法HTTPS流量进入生产环境
ingress {
rule_no = 200
action = "allow"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_block = "0.0.0.0/0"
}
# 允许所有出站流量(根据你的架构需求进行适当调整)
egress {
rule_no = 100
action = "allow"
from_port = 0
to_port = 0
protocol = "-1"
cidr_block = "0.0.0.0/0"
}
tags = {
Name = "production-nacl"
Environment = "production"
Purpose = "SOC2网络隔离"
}
}
在应用了Terraform配置后,可以使用以下命令来验证网络隔离措施是否有效:
# 确认生产环境与非生产环境之间不存在VPC互连连接
aws ec2 describe-vpc-peering-connections \
--filters Name=status-code,Values=active \
--query 'VpcPeeringConnections[*].{ID:VpcPeeringConnectionId,Requester:RequesterVpcInfo.VpcId,Accepter:AccepterVpcInfo.VpcId}' \
--output table
交付物:你的SOC2安全边界图
在第1到第2周结束时,你需要一份安全边界图——这份可视化文档应清楚地显示所有处于评估范围内的系统、所有不在评估范围内的系统,以及它们之间的隔离措施。
这份边界图应该包含以下内容:

请在图中标注所有的AWS服务、所有数据流的方向箭头,以及各个分段的标签。这份图表将成为证明您合规情况的主要依据,审计人员通常会首先要求查看这份图表。
第3至6周:在观察期第一天就必须启用的14项控制措施
这14项控制措施必须在观察期开始的第一天就立即实施,并且要持续收集相关证据。如果您其中任何一项措施延迟实施,那么针对该措施的观察期限将会从实际实施之日起重新计算,而不会从审计期第一天开始算起。
可以把观察期想象成一台监控摄像头,它正在记录您的基础设施运行情况。审计人员之后会查看这些录像。如果在某个特定事件发生时摄像头没有处于开启状态,那么这个事件就无法被记录下来——相应地,SOC2标准中针对这一事件的控制措施也会被视为未得到执行。
控制措施1:多因素认证的强制实施(CC6.6)
多因素认证要求用户使用两种独立的因素来验证自己的身份:一种是他们知道的信息(例如密码),另一种是他们拥有的设备或工具(例如手机或硬件钥匙)。如果没有多因素认证机制,即使密码被盗取,攻击者也同样能够访问您的生产系统。
SOC2标准中的CC6.6要求只有经过授权的用户才能访问系统。多因素认证正是使“授权”这一概念具有实际意义的技术手段。如果没有这一机制,任何密码泄露事件都可能导致生产系统被非法访问。
要实施多因素认证,您可以使用与您的身份提供商(如Okta、Google Workspace或Azure AD)连接的AWS IAM Identity Center。多因素认证会在身份提供商层面得到强制执行——任何未启用该功能的用户都无法进行身份验证,无论他们试图访问的是哪种AWS服务。
# IAM Identity Center的配置设置:多因素认证在身份提供商层面被强制实施。
# 没有任何IAM用户能够直接通过控制台或CLI访问系统。
# 所有访问请求都必须通过SSO会话来完成(默认会话有效期为8小时)。
resource "aws_ssoadmin_instance_access_control_attributes" "mfa" {
instance_arn = tolist(data.aws_ssoadmininstances.this.arns)[0]
attribute {
key = "email"
value {
source = ["$${path:email}"]
}
}
}
您可以通过以下命令验证是否有IAM用户保留了直接访问控制台的权限(这种权限会绕过多因素认证机制):
# 如果有用户具有直接访问控制台的权限,请立即进行调查
aws iam list-users \
--query 'Users[?PasswordLastUsed!=`null`].[UserName,PasswordLastUsed]' \
--output table
控制措施2:代码化基础设施管理(CC8.1)
代码化基础设施管理意味着需要通过版本控制的代码文件(如Terraform、Pulumi或AWS CDK)来定义您的云基础设施,而不是通过AWS控制台手动创建资源。任何对基础设施的修改都应通过拉取请求的形式提出,由同事进行审核,然后通过自动化流程来最终应用这些更改。
SOC2 CC8.1要求对生产环境中的所有变更进行记录、审核并获得批准。通过手动方式在控制台进行的更改不会留下任何审计痕迹;如果工程师直接在AWS控制台中创建安全组,而没有使用Terraform这一工具,那么这样的变更就无法被SOC2审计人员发现。而IaC技术则能够确保所有的变更都可以被审查,并且其操作过程也可以被追踪记录下来。
现在让我们看看如何在这里实现基础设施即代码的理念。这个GitHub Actions工作流程仅会在主分支上应用Terraform,而且前提是相关的拉取请求已经过审核并获得批准。该工作流程会为每一次基础设施变更创建一份不可更改的记录:
# .github/workflows/terraform-apply.yml
name: 应用Terraform配置(生产环境)
on:
push:
branches: [main]
paths: ['terraform/**']
permissions:
id-token: write # AWS OIDC认证所必需
contents: read
jobs:
apply:
name: 应用基础设施变更
runs-on: ubuntu-latest
environment: production # 生产环境中的操作需要人工批准
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 配置AWS凭证(使用OIDC,不使用长期有效的密钥)
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS ACCOUNT_ID }}:role/terraform-apply
aws-region: us-east-1
- name: 安装Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: "1.6.0"
- name: 制定Terraform配置方案
run: |
terraform init
terraform plan -out=tfplan -input=false
- name: 应用Terraform配置
run: terraform apply -input=false tfplan
这种做法所能提供的SOC2证据是:每次基础设施变更都会生成一份GitHub Actions运行日志,其中会显示是谁触发了这次变更、变更是在何时进行的,以及具体发生了哪些变化。
控制措施3:启用CloudTrail(符合CC7.1要求)
AWS CloudTrail是一项能够记录您在AWS账户中执行的每一条API调用的服务——它会记录调用者是谁、调用时间是什么、是从哪个IP地址进行的调用,以及调用是否成功。可以将它看作是您AWS环境中发生的一切事件的完整审计日志。
SOC2的CC7.1要求对安全事件进行监控。CloudTrail就是这一监控机制的基础所在;如果没有它,就无法检测到未经授权的访问行为、无法调查相关事件,也无法向审核人员证明您的控制措施确实按照预期的方式在运行。如果审核人员无法查看AWS的历史API调用记录,就无法确认在审查期间您的访问控制措施是否得到了有效执行。
要实施这一要求,您需要启用多区域的CloudTrail功能,这样就能捕获所有AWS区域中的活动信息,包括像IAM这样的全局服务的相关数据。您还可以将日志发送到启用了对象锁功能的S3存储桶中(证据收集部分中的控制措施3已经介绍了这一点),这样一来,这些日志就无法被修改或删除:
# 启用CloudTrail功能,并配置日志文件验证及多区域覆盖
aws cloudtrail create-trail \
--name production-audit-trail \
--s3-bucket-name your-cloudtrail-logs-bucket \
--is-multi-region-trail \
--enable-log-file-validation \
--include-global-service-events
# 启动日志记录功能
aws cloudtrail start-logging --name production-audit-trail
# 确认日志记录功能是否已启动并正在正常运行
aws cloudtrail get-trail-status --name production-audit-trail \
--query '{IsLogging:IsLogging,LatestDeliveryTime:LatestDeliveryTime}'
控制项4:启用GuardDuty(符合CC7.2标准)
AWS GuardDuty是一种威胁检测服务,它能分析您的CloudTrail日志、VPC流量日志以及DNS日志。该服务利用机器学习技术来识别可疑行为——例如某个EC2实例与已知的恶意软件服务器进行通信、某个IAM用户从异常国家登录,或者那些表明凭证被盗用的异常API调用模式。
SOC2 CC7.2标准要求使用检测工具来发现潜在的安全事件。GuardDuty正是这种监控工具,它能在异常情况发生时立即通知您,而不仅仅是在事情发生后才告知您。如果没有GuardDuty,您很可能要等到损失已经造成之后才会发现安全问题。
以下是具体的实施步骤:
# 启用GuardDuty——对于活跃的威胁,检测结果会每15分钟发布一次
aws guardduty create-detector \
--enable \
--finding-publishing-frequency FIFTEEN_MINUTES
# 验证GuardDuty是否处于激活状态
aws guardduty list-detectors --query 'DetectorIds' --output table
您还可以设置一个EventBridge规则,以便将GuardDuty发出的严重性为“CRITICAL”或“HIGH”的检测结果立即发送到您的事件响应渠道。如果某个检测结果在90天内未被审核,那么它就符合SOC2的标准要求。
控制项5:VPC流量日志(符合CC6.1标准)
VPC流量日志会记录通过您的虚拟私有云传输的IP流量信息——包括所有被允许或被拒绝的连接请求,以及相关的源IP地址、目的IP地址、端口、协议类型等信息。这些日志提供了CloudTrail所无法提供的网络层审计追踪功能。
SOC2 CC6.1标准要求对网络访问进行控制并进行监控。通过VPC流量日志,您可以验证自己的网络隔离措施是否有效(被拒绝的连接会在日志中明确显示为“rejected”),发现服务之间的异常通信行为,并在网络层层面调查安全事件。
# 为VPC流量日志创建一个IAM角色,以便将其数据传输到CloudWatch
aws iam create-role \
--role-name vpc-flow-logs-role \
--assume-role-policy-document '{
"Version":"2012-10-17",
"Statement[]{
"Effect":"Allow",
"Principal":{"Service":"vpc-flow-logs.amazonaws.com"},
"Action":"sts:AssumeRole"
}]
}'
# 为所有类型的流量启用VPC流量日志记录功能
aws ec2 create-flow-logs \
--resource-ids vpc-YOUR_PRODUCTION_VPC_ID \
--resource-type VPC \
--traffic-type ALL \
--log-group-name /aws/vpc/flow-logs/production \
--deliver-log-permission-arn arn:aws:iam::YOUR_ACCOUNT_ID:role/vpc-flow-logs-role
# 验证流量日志是否处于激活状态
aws ec2 describe-flow-logs \
--filter Name=resource-id,Values=vpc-YOUR_PRODUCTION_VPC_ID \
--query 'FlowLogs[*].{Status:FlowLogStatus,LogGroup:LogGroupName}'
控制项6:Secrets Manager(符合CC6.7标准)
秘密管理是指将凭证信息(如数据库密码、API密钥、证书以及其他敏感配置值)存储在专门的、具有访问控制功能的系统中(例如AWS Secrets Manager或HashiCorp Vault),而不是将其保存在`.env`文件中、放在GitHub仓库中,或者直接硬编码到应用程序代码中。
SOC2 CC6.7要求保护敏感的系统组件,防止未经授权的访问。存储在提交到仓库的.env文件中的机密信息,对于所有拥有仓库访问权限的开发人员、所有的CI/CD工具以及所有曾经克隆过该仓库的工程师来说都是可访问的——包括那些后来已经离开公司的员工。
Secrets Manager提供了集中式的存储机制、访问日志记录功能、自动加密周期更新功能,同时还支持细粒度的IAM权限控制,因此只有特定的服务才能获取特定的机密信息。
让我们来看看具体的实现方法——如何存储和更新这些机密信息:
# 存储数据库凭据,并设置自动每90天更新一次
aws secretsmanager create-secret \
--name production/postgresql/credentials \
--description "用于生产环境的PostgreSQL数据库凭据,每90天更新一次" \
--secret-string '{
"username": "app_user",
"password": "REPLACE_WITH_STRONG_PASSWORD",
"host": "your-rds-endpoint.us-east-1.rds.amazonaws.com",
"port": 5432,
"dbname": "production"
}'
# 启用自动每90天更新机制
aws secretsmanager rotate-secret \
--secret-id production/postgresql/credentials \
--rotation-rules AutomaticallyAfterDays=90
你的应用程序在运行时是如何获取这些机密信息的(切勿将凭据硬编码在代码中):
# 正确的做法:在运行时从Secrets Manager中获取机密信息
import boto3
import json
def get_db_credentials():
client = boto3.client('secretsmanager', region_name='us-east-1')
response = client.get_secret_value(SecretId='production/postgresql/credentials')
return json.loads(response['SecretString'])
# 错误的做法:将机密信息硬编码在应用程序代码或.env文件中
DB_PASSWORD = "my_database_password_123" # 这种做法是绝对不可取的
CloudTrail中的访问日志会记录每次获取机密信息的具体时间、使用的IAM角色等信息。这些日志就是证明你的机密信息访问行为受到控制且可被审计的证据。
控制措施7:EBS加密(CC6.1要求)
EBS(弹性块存储)加密功能可以确保连接到你的EC2实例并用于RDS数据库的持久性磁盘在静止状态下会被使用AES-256算法进行加密。如果AWS的员工或攻击者获得了对这些存储硬件的物理访问权限,没有加密密钥的话,这些数据将无法被读取。
SOC2 CC6.1要求保护信息资产,防止未经授权的访问。静态数据加密这一控制措施可以在存储设备发生物理损坏或磁盘被错误地移除时保护数据安全。在全账户范围内启用这一功能后,所有新的EBS卷都会自动被加密,包括用于RDS数据库的存储空间、EKS节点上的卷以及EC2实例的根卷。
# 为该区域内的所有新创建的EBS卷默认启用加密功能
aws ec2 enable-ebs-encryption-by-default
# 验证加密功能是否已经启用
aws ec2 get-ebs-encryption-by-default \
--query 'EbsEncryptionByDefault'
# 预期输出:true
# 检查现有的EBS卷——如果发现有卷的加密状态为false,就需要进行迁移操作
aws ec2 describe-volumes \
--query 'Volumes[?Encrypted==`false`].[VolumeId,Size,VolumeType]' \
--output table
所有现有的未加密卷都必须先创建快照,然后再用新生成的加密卷替换原有的未加密卷。具体操作流程为:首先对未加密卷创建快照,然后根据该快照创建一个新的加密卷,并将其替换到实例中。
控制项8:S3块级公共访问限制(CC6.1)
Amazon S3存储桶可以配置为允许公众访问,这意味着互联网上的任何用户都可以在无需认证的情况下读取这些存储桶中的内容。但“块级公共访问限制”是一项在账户级别和存储桶级别设置的机制,它可以确保无论存储桶本身的配置如何,都不会被设置为公开访问状态。
配置错误的S3存储桶是导致云环境中数据泄露的最常见原因之一。在账户层面实施块级公共访问限制意味着,即使开发人员设置了错误的存储桶策略,他们也不会不小心暴露包含客户数据的存储桶。这种设置其实是一种安全防护机制,而不仅仅是一项政策规定。
# 在AWS账户层面设置块级公共访问限制——适用于所有存储桶
aws s3control put-public-access-block \
--account-id YOUR_ACCOUNT_ID \
--public-access-block-configuration \
BlockPublicAcls=true,\
IgnorePublicAcls=true,\
BlockPublicPolicy=true,\
RestrictPublicBuckets=true
# 验证账户层面的设置是否已生效
aws s3control get-public-access-block \
--account-id YOUR ACCOUNT_ID
# 检查是否有任何存储桶被设置为公开访问状态(应该为零)
aws s3api list-buckets --query 'Buckets[*].Name' --output text | \
tr '\t' '\n' | while read bucket; do
result=\((aws s3api get-public-access-block --bucket "\)bucket" 2>/dev/null)
if echo "$result" | grep -q '"BlockPublicAcls": false'; then
echo "警告:$bucket的块级公共访问限制功能未完全生效"
fi
done
控制项9:分支保护机制(CC8.1)
分支保护是GitHub提供的一项设置,它能够防止工程师在没有经过其他团队成员审核和批准的情况下,直接将代码推送到主分支中。此外,在任何代码被合并之前,还需要确保你的持续集成/部署流程能够通过相应的检查。
SOC2标准中的CC8.1要求实施变更管理机制,即所有对生产环境的修改都必须被记录、审核并得到批准。如果没有分支保护机制,工程师就可以直接将代码推送到主分支,而这样的操作会通过你的持续集成/部署流程直接部署到生产环境中,从而导致没有审核过程且无法追踪修改痕迹。分支保护机制实际上就是对你变更管理政策的技术性执行保障。
大多数团队都会忽略这一关键设置:必须启用“禁止绕过上述设置”的选项。如果不启用这个选项,管理员就可以绕过分支保护机制,而SOC2审计人员会将这一点视为安全漏洞,因为这意味着你的变更管理措施可以被规避。
# .github/settings.yml文件——通过代码配置分支保护机制
# 需要安装GitHub App来应用这些设置:https://github.com/apps/settings
branches:
- name: main
protection:
required_pull_request_reviews:
required_approving_review_count: 1
dismiss_stale_reviews: true
require_code_owner_reviews: false
required_status_checks:
strict: true
contexts:
- "CI / test"
- "Security / trivy-scan"
enforce_admins: true # 管理员无法绕过此设置——这一点非常重要
restrictions: null # 除了上述限制外,不添加其他推送限制
allow_force_pushes: false
allow_deletions: false
以下是验证分支保护机制是否得到有效执行、以及管理员是否无法绕过该机制的方法:
# 用于获取包括管理员是否被允许绕过保护规则在内的所有信息
curl -H "Authorization: token YOUR_GITHUB_TOKEN" \
https://api.github.com/repos/YOUR_ORG/YOUR_REPO/branches/main/protection \
| jq '{enforce_admins: .enforce_admins.enabled, required_reviews: .required_pull_request_reviews.required_approving_review_count}'
控制项10:容器镜像扫描(CC7.4)
容器镜像扫描会在部署之前分析你的Docker镜像,以检测其中包含的操作系统包及应用程序依赖项中是否存在已知的安全漏洞。
Trivy是一款开源工具,它能够检查基础镜像(如Ubuntu、Alpine等)、所有已安装的操作系统包,以及特定语言相关的依赖项(如npm、pip、Go模块),并对比这些组件是否与国家漏洞数据库中的信息一致。
SOC2标准要求必须对漏洞进行监控和识别。你部署的每一个容器都包含带有操作系统包的基础镜像,而这些包经常会被发现存在安全漏洞。如果一个严重的漏洞在生产环境中未被修复长达90天,那么这就会被视为违反SOC2标准。通过在持续集成流程中自动执行扫描,可以确保每个镜像在部署之前都经过严格检查。
# .github/workflows/security-scan.yml
name: 安全扫描
on: [push, pull_request]
jobs:
trivy-scan:
name: 容器漏洞扫描
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 构建容器镜像
run: docker build -t app:${{ github.sha }} .
- name: 扫描镜像以检测漏洞
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1 # 如果发现严重或高风险的漏洞,则终止整个流程
- name: 将扫描结果上传到GitHub的安全页面
uses: github/codeql-action/upload-sarif@v2
if: always() # 即使扫描发现了问题,也必须上传结果
with:
sarif_file: trivy-results.sarif
该扫描工具会检查以下内容:
-
基础镜像中的操作系统包是否存在安全漏洞(例如,你的Ubuntu基础镜像中可能存在的OpenSSL漏洞)
-
应用程序依赖项的脆弱版本(比如你的应用程序所使用的npm包中是否存在已知的可远程代码执行漏洞)
-
Dockerfile本身是否存在配置错误(例如以root用户身份运行程序,或使用了
latest标签等)
扫描结果会显示在你仓库的GitHub安全页面上,这样你就可以查看每次扫描的历史记录——这些记录就是你满足SOC2标准所需的证据。
控制项11:事件响应计划(CC9.2)
事件响应计划是一份经过测试的书面流程,它明确规定了在发生安全事件时,你的团队应该采取哪些行动——从收到警报开始,到通知客户,再到事后的总结分析,整个过程都有详细的安排。
SOC2 CC9.2要求你必须建立一套书面的安全事件应对流程,并且对该流程进行过测试。审计人员会要求你提供这份书面操作手册,以及证明在观察期内曾经进行过桌面演练(即模拟安全事件处理流程的练习)的相关证据。
你的事件响应操作手册必须包括以下内容:
-
严重等级划分:明确P1级(生产系统瘫痪、客户数据面临风险)、P2级(服务性能下降、存在潜在风险)以及P3级(小问题、对客户没有影响)的定义,并规定针对每种等级应采取的响应措施及相应的服务水平协议。
-
升级处理流程:明确在每个严重等级下应该联系哪些具体人员,同时提供他们的联系方式。不能只是笼统地写“值班工程师”——必须指定具体的名字,并且要准备备用联系人,以防第一联系人10分钟内没有回应。
-
事件发生后的15分钟内应采取的措施:明确此时需要立即执行的具体步骤,包括隔离受影响的系统、评估事故影响范围、通知相关负责部门以及开始记录事件处理过程。
-
沟通模板:预先准备好的Slack消息模板、用于联系客户的电子邮件模板,以及符合监管要求的通知模板(例如GDPR要求在72小时内通知相关方,HIPAA则要求在60天内通知)。
-
事件事后分析:制定无责追究的事后分析流程,使用5问法进行根本原因分析,并建立行动项跟踪机制。
在观察期内至少进行一次桌面演练:召集你的工程团队,花45分钟时间模拟一个真实的场景(例如“有人将AWS访问密钥泄露到了公开的GitHub仓库中”),然后一起按照操作手册来处理这个场景。要将会议日期、参与人员、模拟的场景、发现的问题以及采取的补救措施都记录下来。这份文档就是你的证明。
控制项12:访问权限审核(CC6.3)
访问权限审核是指每季度对那些在你的生产系统中拥有访问权限的人员进行审查——这些系统包括AWS账户、GitHub仓库、生产数据库,以及所有会处理客户数据的SaaS工具。你需要确认名单上的每个人仍然在公司工作,并且确实还需要他们当前的角色所赋予的访问权限。
SOC2 CC6.3要求:当某人不再需要某些访问权限时,必须立即撤销这些权限。那些仍然可以访问生产环境AWS账户的前员工,实际上构成了严重的安全风险,这也是SOC2审核中肯定会发现的问题。
在我进行过的每一次访问权限审核中,至少都有3到5名前员工或承包商仍然拥有他们本不应拥有的活跃访问权限。
季度访问权限审核的检查清单如下:
# 1. IAM用户——列出所有用户的登录日期
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content \
| base64 --decode | cut -d',' -f1,5 | column -t -s ,
# 2. IAM角色——找出90天以上未被使用的角色
aws iam get-account-authorization-details \
--query 'RoleDetailList[*].{Role:RoleName,LastUsed:RoleLastUsed.LastUsedDate}' \
--output table
# 3. 确认AWS SSO用户列表与当前员工名单一致
aws identitystore list-users \
--identity-store-id YOUR_IDENTITY_STORE_ID \
--query 'Users[*].{Name:DisplayName,Email:Emails[0].Value}' \
--output table
将检测结果与你们人力资源系统中现有的员工名单进行对照。记录下所有发生的变更——无论是访问权限的取消、权限的降低,还是账户的禁用。这些被记录下来的变更就是证明此次审查是真正得到了认真执行的,而不仅仅是一种走形式的操作。
控制项13:备份验证(CC9.5)
备份验证实际上是指将备份数据恢复到生产环境中,以确认这些备份数据确实可以有效使用——而不仅仅是确认备份文件是否已经生成。如果一个备份从未被测试过,那么从灾难恢复的角度来看,这个备份就毫无意义。
SOC2标准中的CC9.5要求必须对灾难恢复流程进行测试。如果你的生产数据库发生了损坏,而在事件发生时你才发现自动生成的RDS快照无法被恢复,那么这就既属于灾难恢复方面的失败,也符合SOC2标准的检测要求。
如何测试你的RDS备份:
# 第一步:找到最新的生产环境快照
aws rds describe-db-snapshots \
--db-instance-identifier your-production-db \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime)[-1].DBSnapshotIdentifier' \
--output text
# 第二步:将快照恢复到测试环境中
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier backup-verification-test \
--db-snAPSHOT-identifier YOUR_SNAPSHOT_ID \
--db-instance-class db.t3.medium \
--no-publicly-accessible \
--tags Key=Purpose,Value=backup-verification; Key=Environment,Value=test
# 第三步:等待恢复完成(通常需要5到15分钟)
aws rds wait db-instance-available \
--db-instance-identifier backup-verification-test
# 第四步:连接测试环境并验证数据完整性
# 在恢复后的环境中运行以下命令进行检查
psql -h RESTORED_INSTANCE_ENDPOINT -U your_user -d your_database \
-c "SELECT COUNT(*) FROM users; SELECT MAX(created_at) FROM orders;"
# 第五步:记录测试结果,并删除测试用实例
aws rds delete-db-instance \
--db-instance-identifier backup-verification-test \
--skip-final-snapshot
请记录下测试的日期、使用的快照、恢复完成的时间、数据验证的结果,以及进行测试的人员。至少每季度需要执行一次这样的测试。这些记录就是你满足SOC2标准CC9.5要求的证据。
控制项14:变更管理日志(CC8.1)
变更管理日志是对生产环境中发生的每一项变更进行记录的文件,其中会明确说明哪些内容发生了变化、谁批准了这些变更,以及这些变更是在什么时候应用的。
SOC2标准中的CC8.1要求对生产环境中的所有变更都必须经过授权并留下书面记录。如果你已经实施了IaC和GitOps机制,那么你就已经拥有了两份关于变更历史的记录,这两份记录共同满足了这一控制要求。
GitHub的Pull Request历史记录能够详细记录每一项代码或基础设施方面的变更:是谁提出了这个变更请求,谁对它进行了审核并给予了批准,CI测试的状态如何,以及最终这些变更是什么时候被合并到代码中的。这些记录就是你用于管理应用程序和基础设施变更的依据。
ArgoCD同步历史记录会详细记载每一次对Kubernetes集群的部署操作:哪些应用程序被进行了同步、这些操作是基于哪个Git提交指令进行的、具体发生在什么时间,以及同步是否成功。
若需将ArgoCD的同步历史记录导出作为证据,可以按照以下步骤操作:
# 将ArgoCD的应用程序同步历史记录导出为JSON格式的证据文件
argocd app history YOUR_APP_NAME --output json > argocd-sync-history-$(date +%Y%m).json
# 将生成的文件上传到SOC2证据存储桶中
aws s3 cp argocd-sync-history-$(date +%Y%m).json \
s3://your-soc2-evidence-bucket/change-management/$(date +%Y/%m)/
# 每条部署记录中会包含以下信息:
# - 应用程序名称、部署使用的版本号(Git提交哈希值)
# - 部署操作的时间戳
# - 是由用户手动执行同步操作,还是自动完成的
# - 同步操作的成败状态
结合GitHub的Pull Request历史记录与ArgoCD的同步历史记录,审计人员就能获得在观察期内对生产环境所进行的每一项更改的完整、且不可被篡改的记录。
第7至10周:证据收集基础设施
对于SOC2审核而言,证据就是决定审核结果成败的关键因素。
你可能会想知道:究竟什么是证据呢?在SOC2的框架下,证据是指能够证明在观察期内的某个特定时间点,某项控制措施确实得到了正确执行的文档。政策文件规定了你应该做什么,而证据则能证明你确实按照这些规定行事了——而且这种行为是持续性的,而不仅仅是在审计前的那一周。
举个例子来说:
-
对于多因素身份验证这一控制措施而言,证据就是在观察期内某个特定日期拍摄的IAM Identity Center的多因素身份验证设置截图,再加上一份显示没有任何IAM用户拥有访问控制台权限的报告。
-
对于GuardDuty这一控制措施来说,证据就是GuardDuty控制台的截图,其中会显示出当前处于激活状态的检测工具,同时还需要你记录下在观察期间针对这些检测结果所采取的应对措施。
-
对于访问权限审查这一控制措施而言,证据就是已经填写完成的访问权限审查文档,其中会明确记载审查的日期、参与人员的姓名以及具体的权限变更内容。
面临的挑战在于,如何在3到12个月的时间里持续收集这些证据,而不会花费大量的人力进行手动操作。解决方案就是使用自动化的数据收集基础设施。
证据存储桶——用于存放审计证据的防篡改存储空间
证据存储桶实际上是一个启用了Object Lock功能的S3存储桶,并且Object Lock被设置在了GOVERNANCE模式下。这种设置可以确保在您指定的保留期内(在本例中为365天),任何对象都无法被删除或修改。这意味着,一旦有证据文件被上传到这个存储桶中,即使拥有管理员权限的用户也无法更改这些文件的内容——除非他们明确地绕过Object Lock的限制,而这样的操作本身也会留下审计痕迹。
正是这种防篡改的特性,让审计人员能够确信这些证据文件是在规定时间之前创建的,而且在后续也没有被任何人修改过。
# terraform/soc2-evidence-bucket.tf
resource "aws_s3_bucket" "soc2_evidence" {
bucket = "\({var.company_name}-soc2-evidence-\){var.environment}"
}
# 阻止所有公共访问该证据存储桶
resource "aws_s3_bucket_public_access_block" "soc2_evidence" {
bucket = aws_s3_bucket.soc2_evidence.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# 启用版本控制功能,这样覆盖操作会生成新版本而非替换原有文件
resource "aws_s3_bucket_versioning" "soc2_evidence" {
bucket = aws_s3_bucket.soc2_evidence.id
versioning_configuration {
status = "Enabled"
}
}
# 启用对象锁机制,在“GOVERNANCE”模式下,对象在365天内无法被删除
resource "aws_s3_bucket_object_lockConfiguration" "soc2_evidence" {
bucket = aws_s3_bucket.soc2_evidence.id
rule {
default_retention {
mode = "GOVERNANCE"
days = 365
}
}
}
# 对所有静态证据数据进行加密
resource "aws_s3_bucket_server_side_encryption_configuration" "soc2_evidence" {
bucket = aws_s3_bucket.soc2_evidence.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
每日证据收集器Lambda函数
这个Lambda函数每天会自动运行,并将每个关键控制项的状态导出到证据存储桶中,生成带有时间戳的JSON文件。在3到12个月的观察期内,该函数会每天记录一次,以证明这些控制项处于激活状态且正常运行。
该函数会自动检查七项控制项:CloudTrail的状态、GuardDuty的状态、VPC流量日志、S3的公共访问限制设置、EBS的数据加密情况、多因素认证的合规性以及GuardDuty发现的异常数量。每天的数据都会被上传,并且会启用对象锁机制,因此这些数据无法被修改。
# lambda/evidence-collector/handler.py
import boto3
import json
from datetime import datetime, timedelta, timezone
def lambda_handler(event, context):
"""
日常SOC2证据收集器。
每天在00:00 UTC通过EventBridge调度程序运行。
将控制项的状态导出到启用对象锁的S3证据存储桶中。
"""
evidence = {
'collection_timestamp': datetime.now(timezone.utc).isoformat(),
'collection_date': datetime.now(timezone.utc).strftime('%Y-%m-%d'),
'account_id': boto3.client('sts').get_caller_identity()['Account'],
'controls': {}
}
# 控制项3:CloudTrail的状态
cloudtrail = boto3.client('cloudtrail')
trails = cloudtrail.describe_trails(includeShadowTrails=False)['trailList']
multi_region_trails = [t for t in trails if t.get('IsMultiRegionTrail')]
evidence['controls']['cloudtrail'] = {
'status': 'PASS' if multi_region_trails else 'FAIL',
'detail': f"{len(multi_region_trails)}个多区域跟踪机制处于激活状态",
'trails': [t['Name'] for t in multi_region_trails]
}
# 控制项4:GuardDuty的状态
guardduty = boto3.client('guardduty')
detectors = guardduty.list_detectors=['DetectorIds']
unresolved_critical = 0
for detector_id in detectors:
findings = guardduty.list_findings(
DetectorId=detector_id,
FindingCriteria={
'Criterion': {
'severity': {'Gte': 7}, # 仅检查高严重性和关键性异常
'service.archived': {'Eq': ['false']}
}
}
)
unresolved_critical += len(findings['FindingIds'])
evidence['controls']['guardduty'] = {
'status': 'PASS' if detectors else 'FAIL',
'detail': f"{len(detectors)}个检测机制处于激活状态,{unresolved_critical}个高严重性/关键性异常尚未得到解决",
'unresolved_high_critical': unresolved_CRITICAL
}
# 控制项5:VPC流量日志
ec2 = boto3.client('ec2')
flow_logs = ec2.describe_flowLogs(
Filters=[{'Name': 'resource-type', 'Values': ['VPC']},
{'Name': 'flow-log-status', 'Values': ['ACTIVE']}]
)['FlowLogs']
evidence['controls']['vpc_flow_logs'] = {
'status': 'PASS' if flow_logs else 'FAIL',
'detail': f"{len(flow_logs)}条VPC流量日志处于激活状态",
'active_flow_logs': lenFLOW Logs)
}
# 控制项7:EBS是否默认启用了数据加密
ebs_encryption = ec2.get_ebs_encryption_by_default['EbsEncryptionByDefault']
evidence['controls']['ebs_encryption_by_default'] = {
'status': 'PASS' if ebs_encryption else 'FAIL',
'detail': 'EBS是否默认启用了数据加密'
}
# 控制项8:S3的公共访问限制设置(账户级别)
s3control = boto3.client('s3control')
account_id = boto3.client('sts').get_caller_identity['Account']
try:
pab = s3control.get_public_access_block(AccountId=account_id)'PublicAccessBlockConfiguration'
allblocked = all([pab['BlockPublicAcls'], pab['IgnorePublicAcls'],
pab['BlockPublicPolicy', pab['RestrictPublicBuckets']))
evidence['controls']['s3_block_public_access'] = {
'status': 'PASS' if all_blocked else 'FAIL',
'detail': '所有四项S3公共访问限制设置都已启用' if allblocked else '至少有一项设置未启用',
'configuration': pab
}
except Exception as e:
evidence['controls']['s3_block_public_access'] = {'status': 'FAIL', 'detail': str(e)}
# 将收集到的证据数据上传到S3存储桶,并启用对象锁机制
s3 = boto3.client('s3')
evidence_key = f"daily/{evidence['collection_date']}/control-status.json"
lock_until = datetime.now(timezone.utc) + timedelta(days=365)
s3.put_object(
Bucket='YOUR_EVIDENCE_BUCKET_NAME',
Key=evidence_key,
Body=json.dumps(evidence, indent=2),
ContentType='application/json',
ObjectLockMode='GOVERNANCE',
ObjectLockRetainUntilDate=lock_until
)
# 如果有任何控制项未通过检查,就发送警报
failed-controls = [k for k, v in evidence['controls'].items() if v['status'] == 'FAIL']
if failed_controls:
sns = boto3.client('sns')
sns.publish(
TopicArn='YOUR_ALERT_TOPIC_ARN',
Subject=f'SOC2控制项检查失败 — {evidence["collection_date"]}',
Message=f'以下控制项未通过每日检查:\n\n{json.dumps(failed-controls, indent=2)}'
)
return {
'statusCode': 200,
'controls_checked': len(evidence['controls')),
'controls_failed': len(failed_controls),
'evidence_location': f"s3://YOUR_EVIDENCE_BUCKET_NAME/{evidence_key}"
}
GitHub Actions证据收集工作流程
该工作流程每天都会运行,用于收集那些无法通过AWS API自动获取的证据信息——例如GitHub层面的控制措施状态、最近的拉取请求活动情况以及持续集成管道的运行结果。这些数据会被以JSON文件的形式导出到同一个证据存储桶中。
# .github/workflows/soc2-evidence.yml
name: SOC2证据收集
on:
schedule:
- cron: '0 1 * * *' # 每天UTC时间01:00执行(在Lambda函数于00:00运行之后)
workflow_dispatch: # 根据需要允许手动触发该工作流程
permissions:
contents: read
jobs:
collect-github-evidence:
name: 收集GitHub相关的控制措施证据
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 配置AWS身份凭证
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS ACCOUNT_ID }}:role/evidence-collector
aws-region: us-east-1
- name: 获取主分支的保护状态信息
run: |
DATE=$(date +%Y-%m-%d)
mkdir -p evidence/github
# 获取主分支的保护规则信息
curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/branches/main/protection" \
| jq '{
date: "'$DATE'",
enforce_admins: .enforce_admins.enabled,
required_reviews: .required_pull_request_reviews.required_approving_review_count,
required_status_checks: .required_statuschecks.contexts,
allow_force_pushes: .allow-force-pushes.enabled
}' > evidence/github/branch-protection-$DATE.json
echo "已收集到主分支的保护状态证据"
cat evidence.github/branch-protection-$DATE.json
- name: 将证据文件上传至S3存储桶
run: |
DATE=$(date +%Y-%m-%d)
aws s3 sync evidence/ \
s3://\({{ secrets.SOC2_EVIDENCE_BUCKET }}/daily/\)DATE/github/ \
--no-progress
echo "证据文件已上传至:s3://\({{ secrets.SOC2_EVIDENCE_bucket }}/daily/\)DATE.github/"
第11至14周:审计师选聘与准备情况评估
如何选择SOC2审计师
挑选合适的审计师对于大多数团队来说,其重要性往往被低估。SOC2审计通常由注册会计师事务所负责执行——具体而言,是由那些拥有颁发SOC报告资质的机构来承担这项工作。选择一家具有处理类似规模云原生SaaS企业经验的专业机构至关重要;而如果选错了机构,他们可能会将适用于大型企业的审计框架套用到处于初创阶段的中小企业身上,从而得出与实际情况不符的审计结果。
以下是挑选审计师时需要关注的重点以及需要注意的事项:
经验比品牌更重要
确认审计机构是否熟悉你所使用的合规性检测工具
了解Type II审计的实际费用
如何进行准备性评估(模拟审计)
准备性评估就是在进行正式审计之前,自行进行的模拟测试。在聘请审计机构之前的2到4周内进行这项评估,目的是在审计机构发现问题之前先找出并弥补这些漏洞。因为如果在模拟审计中发现漏洞,你只需要花费一周的时间来整改;而如果在正式审计中发现这些问题,那么你可能会收到一份有保留意见的审计报告,并需要重新进行审计。
你可以自己来进行准备性评估,也可以聘请咨询机构来协助完成这项工作。聘请咨询机构会更有帮助,因为独立的第三方审核人员能够发现那些你自己可能忽视的问题。
操作流程:
-
步骤1:逐一检查以下清单中的各项控制措施,尝试收集审计人员会要求提供的证据。
-
步骤2:对于那些无法提供清晰、带有时间戳的证据的控制措施,说明其中存在漏洞,并将其记录下来。
-
步骤3:根据漏洞的类型对它们进行优先级排序。对于“证据缺失”的情况,需要改进证据收集机制;而对于“控制措施未得到实施”的情况,则需要进行相应的系统配置调整。
-
步骤4:在聘请真正的审计人员之前,务必弥补所有存在的漏洞。
控制措施
所需证据
>
验证方法
>
已完成吗?
MFA已启用
IAM凭证报告 + SSO MFA政策截图
aws iam get-credential-report
⬜
CloudTrail处于激活状态
追踪日志的状态 + S3存储确认信息
aws cloudtrail get-trail-status
⬜
GuardDuty已启用
检测器列表 + 发现问题的审核记录
aws guardduty list-detectors
⬜
VPC流量日志
激活的流量日志列表 + 样本日志条目
aws ec2 describe-flow-logs
⬜
Secrets Manager中的秘密信息
秘密信息列表 + 密码轮换策略确认
aws secretsmanager list-secrets
⬜
EBS默认采用加密功能
账户级别的加密设置
aws ec2 get-ebs-encryption-by-default
⬜
S3禁止公共访问
账户级别的公共访问配置设置
aws s3control get-public-access-block
⬜
分支保护机制(禁止管理员绕过规则)
GitHub分支保护功能的API响应结果
GitHub API或设置界面
⬜
CI流程中的Trivy扫描功能
GitHub Actions运行历史记录,其中包含扫描结果
GitHub Actions日志
⬜
事件响应操作手册
>
书面版操作手册 + 包含日期的桌面演练记录
文件审核
⬜
访问权限审查
包含具体修改内容的季度审查文档
文件审核
⬜
备份测试
RDS恢复日志 + 数据验证结果
文件审核
⬜
变更管理记录
GitHub Pull Request历史记录 + ArgoCD同步记录
GitHub与ArgoCD系统
⬜
大多数团队都会忽略的一点:使用自己保存的证据来验证各项控制措施是否已经得到正确实施。请从每日自动导出的数据中随机选取某一天的证据,确认这些证据是否完整、带有时间戳,并且能够准确反映当天该控制措施的实际状态。
<如果12月14日的证据文件显示GuardDuty处于“启用”状态,但实际上那天GuardDuty是被禁用的,那么审计人员会在AWS账户记录中发现这一矛盾之处——而这种发现显然属于严重的违规行为。>
第15至18周:观察期
审计师如何检查您的控制措施
SOC2审计师并不会亲自前往您的办公室,也不会在您的AWS控制台中实时监控您的基础设施。整个审计过程都是通过远程方式进行,且完全基于文档审查。
具体操作流程如下:
首先,审计师会列出一份证据收集清单——对于II型审计而言,这份清单通常包含80到150项内容。您需要将这些证据上传到一个共享门户中(这个平台由审计师提供,通常是安全的文档共享系统)。审计师会审核这些证据,提出进一步的问题,并找出那些证据缺失或控制措施未按描述运行的情况。
对于像CloudTrail和GuardDuty这样的自动化控制措施,其证据就是您每天生成的Lambda脚本输出结果。审计师会在观察期内随机抽查这些每日快照,以确认这些控制措施始终处于激活状态。
而对于访问审核和备份测试等手动控制措施,其证据就是您在执行这些操作时产生的相关文档。
实际意义在于:审计师是信任您提供的这些证据的。因此,您用于存储这些证据的 bucket是否启用了对象锁定功能就非常重要了。这一功能能够向审计师证明:这些证据确实是在声称的生成时间生成的,并且自那时起没有被修改过。
观察期内审计师会审查哪些内容
审核内容
审核频率
审核目的
CloudTrail日志
每月进行随机检查
检查是否存在绕过基础设施即代码管理的手动操作,以及日志传输是否存在问题
GuardDuty检测结果
每季度审核汇总报告
那些在您规定的SLA时间内尚未得到处理的严重或危急问题
访问审核完成情况
每个季度都会进行核实
检查是否有未完成的审核任务,或者尽管员工发生了变动,但相关审核内容却没有任何变化
事件响应测试结果
每年进行一次核查
在观察期内是否进行了任何桌面演练
证据收集情况
确认证据收集是否持续进行
检查每日生成的日志是否存在缺失,或者某些特定日期的证据是否未被提交
变更管理记录
抽查相关的拉取请求和同步历史记录
检查是否有未经审核或没有关联拉取请求的部署操作
什么情况会导致审计结果出现异常
SOC2审计结果是指审计师根据审查情况得出的结论,说明在观察期内某项控制措施并未有效运行。这些审计结果的范围很广,从一些不影响整体审计意见的轻微问题,到那些会导致审计报告被评为“有保留意见”的严重缺陷,都属于其中。
了解哪些因素会引发审计问题的发现,以及哪些情况会导致观察期重新开始,对于管理审计时间线而言至关重要。
控制措施缺失是指在观察期内未实施必要的控制措施,或者这些措施被暂时禁用。例如,如果在第二个月发现某个IAM用户在前三周内没有使用多因素认证机制,就必须记录相应的补救措施,并证明这一缺陷已经得到解决。
是否需要重新开始观察期,取决于这种缺失持续了多长时间,以及审计师如何评估相关风险——但通常来说,如果缺失时间少于30天,并且能够立即采取补救措施并完成记录,那么观察期就不会重新开始。
证据收集不足
则是更为严重的问题。如果用于收集日常数据的Lambda工具连续两周无法正常工作,导致没有生成任何证据记录,那么在这段时间内,就没有任何文件可以证明你的控制措施正在有效运行。审计师自然也无法验证那些缺乏证据支持的控件。
当出现证据收集不足的情况时,几乎总是需要延长观察期,因为对于那些没有被记录下来的时间段,根本无法事后生成相应的证据。
流程执行失误
是指某些手动控制的操作没有按照规定的流程进行。最常见的例子就是忽略了访问权限审查环节。与控制措施缺失类似,只要这些失误能够及时被记录下来,并且有明确的补救措施,通常也不需要重新开始观察期。
未修补的关键安全漏洞
属于特殊情况。如果Trivy检测到生产环境中存在关键安全漏洞,而该漏洞在规定的补救时限内仍未得到修复(对于关键漏洞,这个时限通常是30天;对于高风险漏洞,则是90天),那么审计师就会在报告中将这一情况记录下来。
如何在不重新开始观察期的情况下弥补缺陷
当你在观察期内发现某些缺陷时,可以按照以下步骤进行处理:
对于控制措施缺失的情况:
1. 立即采取补救措施,不要拖延;
2. 记录具体的补救过程:包括截图、拉取请求的链接,或者包含时间戳的CLI命令执行结果;
3. 在审计日志中明确记录缺陷存在的时间段:“控制措施缺失期间:2024-03-10至2024-03-14(共4天)。根本原因:[X]。补救措施:[Y]。在缺陷存在期间,没有客户数据被访问。”
4. 主动通知审计师——他们迟早会发现这些问题,主动披露总比事后解释要好;
5>如果缺陷存在的时间很短,并且已经立即得到了补救,那么观察期就不会重新开始。
对于证据收集不足的情况:
1. 立即修复证据收集相关系统;
2>需要明白的是,对于缺陷存在的那段时间段,是无法事后生成证据的;
3>受影响的控制措施的观察期实际上是从恢复证据收集工作的那一天开始重新计算的;
4>如果缺陷出现在观察期的早期阶段,或许可以与审计师协商延长观察期,而无需重新开始整个观察流程。
专业提示:设置一个CloudWatch警报,当Lambda未能按时将证据文件上传到S3时,该警报就会触发。这样一来,每天缺失的证据文件就能在24小时内被发现,而不会在审计审查过程中被遗漏。
90天SOC2时间线概览
周数
重点任务
关键成果
。
常见错误
1–2周
范围界定
绘制边界图、使用Terraform进行网络分割配置
错误地将开发环境和测试环境也纳入审计范围
3–6周
控制措施实施
落实14项控制措施并开始收集相关证据
在观察期开始后才开始执行这些控制措施
7–10周
证据收集
创建S3存储桶用于存放证据文件、使用Lambda脚本进行每日数据采集、配置GitHub Actions工作流程
采用手动方式收集证据,容易导致数据遗漏
11–14周
准备阶段
进行模拟审计、弥补存在的缺陷、选定审计机构
忽略模拟审计环节
15–18周
观察期
每日收集证据文件、定期进行审查、测试事件响应机制
往往在审计期间才发现证据收集中存在的漏洞
下一步该做什么?
从第1周开始行动。明确SOC2的审计范围,针对基础设施中的每个系统应用四问框架进行评估,使用Excalidraw工具绘制边界图,并详细记录网络分割控制措施的相关信息。
接下来,按顺序实施这14项控制措施,优先处理MFA和CloudTrail这两项在审计中经常被遗漏的控制措施。
在观察期开始之前,先建立完善的证据收集机制。自动化的Lambda脚本和GitHub Actions工作流程对于确保审计顺利进行至关重要,否则审核过程可能会延长60天。
需要记住的一点是:SOC2评估中,控制措施占20%,证据收集占30%,而持续运营则占据50%。因此要尽早开始准备,尽可能实现自动化操作,在正式审计之前先进行一次模拟审计。
参考资源
本指南中引用了以下资源:
-
AICPA SOC2概述 — 美国注册会计师协会发布的官方SOC2文档,其中包含了信任服务标准的相关内容
-
Vanta — 一款合规自动化平台,可连接AWS和GitHub系统,实现证据收集自动化并跟踪控制措施的执行状态
-
Drata — 另一款具备类似功能的合规自动化平台
-
-
Excalidraw — 一款免费的开源绘图工具,可用于绘制SOC2边界图
-
-
-
Ayobami Adejumo 是一位资深平台工程师兼FinOps领域的专家。他主要从事SOC2合规性相关技术的研究,同时也会探讨Kubernetes平台的成本优化方案以及平台工程的相关议题。
操作流程:
-
步骤1:逐一检查以下清单中的各项控制措施,尝试收集审计人员会要求提供的证据。
-
步骤2:对于那些无法提供清晰、带有时间戳的证据的控制措施,说明其中存在漏洞,并将其记录下来。
-
步骤3:根据漏洞的类型对它们进行优先级排序。对于“证据缺失”的情况,需要改进证据收集机制;而对于“控制措施未得到实施”的情况,则需要进行相应的系统配置调整。
-
步骤4:在聘请真正的审计人员之前,务必弥补所有存在的漏洞。
| 控制措施 | 所需证据 | 验证方法 | 已完成吗? |
|---|---|---|---|
| MFA已启用 | IAM凭证报告 + SSO MFA政策截图 | aws iam get-credential-report |
⬜ |
| CloudTrail处于激活状态 | 追踪日志的状态 + S3存储确认信息 | aws cloudtrail get-trail-status |
⬜ |
| GuardDuty已启用 | 检测器列表 + 发现问题的审核记录 | aws guardduty list-detectors |
⬜ |
| VPC流量日志 | 激活的流量日志列表 + 样本日志条目 | aws ec2 describe-flow-logs |
⬜ |
| Secrets Manager中的秘密信息 | 秘密信息列表 + 密码轮换策略确认 | aws secretsmanager list-secrets |
⬜ |
| EBS默认采用加密功能 | 账户级别的加密设置 | aws ec2 get-ebs-encryption-by-default |
⬜ |
| S3禁止公共访问 | 账户级别的公共访问配置设置 | aws s3control get-public-access-block |
⬜ |
| 分支保护机制(禁止管理员绕过规则) | GitHub分支保护功能的API响应结果 | GitHub API或设置界面 | ⬜ |
| CI流程中的Trivy扫描功能 | GitHub Actions运行历史记录,其中包含扫描结果 | GitHub Actions日志 | ⬜ |
| 事件响应操作手册 | 书面版操作手册 + 包含日期的桌面演练记录 | 文件审核 | ⬜ |
| 访问权限审查 | 包含具体修改内容的季度审查文档 | 文件审核 | ⬜ |
| 备份测试 | RDS恢复日志 + 数据验证结果 | 文件审核 | ⬜ |
| 变更管理记录 | GitHub Pull Request历史记录 + ArgoCD同步记录 | GitHub与ArgoCD系统 | ⬜ |
大多数团队都会忽略的一点:使用自己保存的证据来验证各项控制措施是否已经得到正确实施。请从每日自动导出的数据中随机选取某一天的证据,确认这些证据是否完整、带有时间戳,并且能够准确反映当天该控制措施的实际状态。
<如果12月14日的证据文件显示GuardDuty处于“启用”状态,但实际上那天GuardDuty是被禁用的,那么审计人员会在AWS账户记录中发现这一矛盾之处——而这种发现显然属于严重的违规行为。>
第15至18周:观察期
审计师如何检查您的控制措施
SOC2审计师并不会亲自前往您的办公室,也不会在您的AWS控制台中实时监控您的基础设施。整个审计过程都是通过远程方式进行,且完全基于文档审查。
具体操作流程如下:
首先,审计师会列出一份证据收集清单——对于II型审计而言,这份清单通常包含80到150项内容。您需要将这些证据上传到一个共享门户中(这个平台由审计师提供,通常是安全的文档共享系统)。审计师会审核这些证据,提出进一步的问题,并找出那些证据缺失或控制措施未按描述运行的情况。
对于像CloudTrail和GuardDuty这样的自动化控制措施,其证据就是您每天生成的Lambda脚本输出结果。审计师会在观察期内随机抽查这些每日快照,以确认这些控制措施始终处于激活状态。
而对于访问审核和备份测试等手动控制措施,其证据就是您在执行这些操作时产生的相关文档。
实际意义在于:审计师是信任您提供的这些证据的。因此,您用于存储这些证据的 bucket是否启用了对象锁定功能就非常重要了。这一功能能够向审计师证明:这些证据确实是在声称的生成时间生成的,并且自那时起没有被修改过。
观察期内审计师会审查哪些内容
| 审核内容 | 审核频率 | 审核目的 |
|---|---|---|
| CloudTrail日志 | 每月进行随机检查 | 检查是否存在绕过基础设施即代码管理的手动操作,以及日志传输是否存在问题 |
| GuardDuty检测结果 | 每季度审核汇总报告 | 那些在您规定的SLA时间内尚未得到处理的严重或危急问题 |
| 访问审核完成情况 | 每个季度都会进行核实 | 检查是否有未完成的审核任务,或者尽管员工发生了变动,但相关审核内容却没有任何变化 |
| 事件响应测试结果 | 每年进行一次核查 | 在观察期内是否进行了任何桌面演练 |
| 证据收集情况 | 确认证据收集是否持续进行 | 检查每日生成的日志是否存在缺失,或者某些特定日期的证据是否未被提交 |
| 变更管理记录 | 抽查相关的拉取请求和同步历史记录 | 检查是否有未经审核或没有关联拉取请求的部署操作 |
什么情况会导致审计结果出现异常
SOC2审计结果是指审计师根据审查情况得出的结论,说明在观察期内某项控制措施并未有效运行。这些审计结果的范围很广,从一些不影响整体审计意见的轻微问题,到那些会导致审计报告被评为“有保留意见”的严重缺陷,都属于其中。
了解哪些因素会引发审计问题的发现,以及哪些情况会导致观察期重新开始,对于管理审计时间线而言至关重要。
控制措施缺失是指在观察期内未实施必要的控制措施,或者这些措施被暂时禁用。例如,如果在第二个月发现某个IAM用户在前三周内没有使用多因素认证机制,就必须记录相应的补救措施,并证明这一缺陷已经得到解决。
是否需要重新开始观察期,取决于这种缺失持续了多长时间,以及审计师如何评估相关风险——但通常来说,如果缺失时间少于30天,并且能够立即采取补救措施并完成记录,那么观察期就不会重新开始。
证据收集不足
则是更为严重的问题。如果用于收集日常数据的Lambda工具连续两周无法正常工作,导致没有生成任何证据记录,那么在这段时间内,就没有任何文件可以证明你的控制措施正在有效运行。审计师自然也无法验证那些缺乏证据支持的控件。
当出现证据收集不足的情况时,几乎总是需要延长观察期,因为对于那些没有被记录下来的时间段,根本无法事后生成相应的证据。
流程执行失误
是指某些手动控制的操作没有按照规定的流程进行。最常见的例子就是忽略了访问权限审查环节。与控制措施缺失类似,只要这些失误能够及时被记录下来,并且有明确的补救措施,通常也不需要重新开始观察期。
未修补的关键安全漏洞
属于特殊情况。如果Trivy检测到生产环境中存在关键安全漏洞,而该漏洞在规定的补救时限内仍未得到修复(对于关键漏洞,这个时限通常是30天;对于高风险漏洞,则是90天),那么审计师就会在报告中将这一情况记录下来。
如何在不重新开始观察期的情况下弥补缺陷
当你在观察期内发现某些缺陷时,可以按照以下步骤进行处理:
对于控制措施缺失的情况:
1. 立即采取补救措施,不要拖延;
2. 记录具体的补救过程:包括截图、拉取请求的链接,或者包含时间戳的CLI命令执行结果;
3. 在审计日志中明确记录缺陷存在的时间段:“控制措施缺失期间:2024-03-10至2024-03-14(共4天)。根本原因:[X]。补救措施:[Y]。在缺陷存在期间,没有客户数据被访问。”
4. 主动通知审计师——他们迟早会发现这些问题,主动披露总比事后解释要好;
5>如果缺陷存在的时间很短,并且已经立即得到了补救,那么观察期就不会重新开始。
对于证据收集不足的情况:
1. 立即修复证据收集相关系统;
2>需要明白的是,对于缺陷存在的那段时间段,是无法事后生成证据的;
3>受影响的控制措施的观察期实际上是从恢复证据收集工作的那一天开始重新计算的;
4>如果缺陷出现在观察期的早期阶段,或许可以与审计师协商延长观察期,而无需重新开始整个观察流程。
专业提示:设置一个CloudWatch警报,当Lambda未能按时将证据文件上传到S3时,该警报就会触发。这样一来,每天缺失的证据文件就能在24小时内被发现,而不会在审计审查过程中被遗漏。
90天SOC2时间线概览
| 周数 | 重点任务 | 关键成果 | 常见错误 |
|---|---|---|---|
| 1–2周 | 范围界定 | 绘制边界图、使用Terraform进行网络分割配置 | 错误地将开发环境和测试环境也纳入审计范围 |
| 3–6周 | 控制措施实施 | 落实14项控制措施并开始收集相关证据 | 在观察期开始后才开始执行这些控制措施 |
| 7–10周 | 证据收集 | 创建S3存储桶用于存放证据文件、使用Lambda脚本进行每日数据采集、配置GitHub Actions工作流程 | 采用手动方式收集证据,容易导致数据遗漏 |
| 11–14周 | 准备阶段 | 进行模拟审计、弥补存在的缺陷、选定审计机构 | 忽略模拟审计环节 |
| 15–18周 | 观察期 | 每日收集证据文件、定期进行审查、测试事件响应机制 | 往往在审计期间才发现证据收集中存在的漏洞 |
下一步该做什么?
从第1周开始行动。明确SOC2的审计范围,针对基础设施中的每个系统应用四问框架进行评估,使用Excalidraw工具绘制边界图,并详细记录网络分割控制措施的相关信息。
接下来,按顺序实施这14项控制措施,优先处理MFA和CloudTrail这两项在审计中经常被遗漏的控制措施。
在观察期开始之前,先建立完善的证据收集机制。自动化的Lambda脚本和GitHub Actions工作流程对于确保审计顺利进行至关重要,否则审核过程可能会延长60天。
需要记住的一点是:SOC2评估中,控制措施占20%,证据收集占30%,而持续运营则占据50%。因此要尽早开始准备,尽可能实现自动化操作,在正式审计之前先进行一次模拟审计。
参考资源
本指南中引用了以下资源:
-
AICPA SOC2概述 — 美国注册会计师协会发布的官方SOC2文档,其中包含了信任服务标准的相关内容
-
Vanta — 一款合规自动化平台,可连接AWS和GitHub系统,实现证据收集自动化并跟踪控制措施的执行状态
-
Drata — 另一款具备类似功能的合规自动化平台
-
Excalidraw — 一款免费的开源绘图工具,可用于绘制SOC2边界图
Ayobami Adejumo 是一位资深平台工程师兼FinOps领域的专家。他主要从事SOC2合规性相关技术的研究,同时也会探讨Kubernetes平台的成本优化方案以及平台工程的相关议题。