安全事件分级与响应
| 等级 | 示例 | 响应时限 | 处置方式 |
|---|---|---|---|
| P1 严重 | 凭证泄露、勒索软件、数据外泄 | 15 分钟 | 立即隔离、吊销凭证、启动应急流程 |
| P2 高 | 特权账号异常登录、安全组开放高危端口 | 1 小时 | 确认合法性、必要时阻断并通知 |
| P3 中 | 高危漏洞、加密配置缺失、异常 API 调用 | 1 个工作日 | 评估影响、安排修复窗口 |
| P4 低 | 配置偏离基线、低危漏洞 | 1 周 | 纳入例行整改批次 |
托管安全运营包含什么
- GuardDuty、Security Hub、Inspector、Macie 的统一接入与调优(降噪很关键)
- 7×24 告警值守,P1/P2 事件电话触达
- 漏洞按资产重要性排优先级,跟踪修复闭环
- 月度安全态势报告:新增风险、修复进度、趋势对比
- 季度权限审阅:清理僵尸账号、过宽权限、闲置 Access Key
- 年度红蓝对抗演练与应急流程验证
凭证泄露自动响应
"""GuardDuty 检测到凭证异常使用时的自动响应。
处置顺序很重要:
1. 先给凭证附加拒绝一切的策略(立即止血,比删除快且可回溯)
2. 快照当前会话信息用于取证
3. 通知安全团队与凭证所属人
4. 不自动删除任何东西——取证需要现场
"""
from __future__ import annotations
import json
import os
from datetime import datetime, timezone
import boto3
iam = boto3.client("iam")
sts = boto3.client("sts")
sns = boto3.client("sns")
ddb = boto3.resource("dynamodb")
QUARANTINE_POLICY_ARN = os.environ["QUARANTINE_POLICY_ARN"]
ALERT_TOPIC_ARN = os.environ["ALERT_TOPIC_ARN"]
FORENSICS_TABLE = os.environ["FORENSICS_TABLE"]
HIGH_SEVERITY = 7.0
def quarantine_user(user_name: str) -> dict:
"""附加拒绝策略并禁用所有 Access Key。"""
actions = []
iam.attach_user_policy(UserName=user_name, PolicyArn=QUARANTINE_POLICY_ARN)
actions.append("attached-quarantine-policy")
keys = iam.list_access_keys(UserName=user_name)["AccessKeyMetadata"]
for key in keys:
if key["Status"] == "Active":
iam.update_access_key(
UserName=user_name,
AccessKeyId=key["AccessKeyId"],
Status="Inactive",
)
actions.append(f"deactivated-key-{key['AccessKeyId'][-4:]}")
return {"user": user_name, "actions": actions}
def quarantine_role(role_name: str) -> dict:
"""角色无法禁用,改为收紧信任策略并附加拒绝策略。"""
iam.attach_role_policy(RoleName=role_name, PolicyArn=QUARANTINE_POLICY_ARN)
return {"role": role_name, "actions": ["attached-quarantine-policy"]}
def record_forensics(finding: dict, response: dict) -> None:
ddb.Table(FORENSICS_TABLE).put_item(Item={
"finding_id": finding["id"],
"detected_at": finding.get("updatedAt","),
"responded_at": datetime.now(timezone.utc).isoformat(),
"severity": str(finding.get("severity",")),
"type": finding.get("type","),
"account": finding.get("accountId","),
"region": finding.get("region","),
"raw_finding": json.dumps(finding, default=str)[:380000],
"response": json.dumps(response),
})
def lambda_handler(event, context): # noqa: ARG001
finding = event["detail"]
severity = float(finding.get("severity", 0))
ftype = finding.get("type",")
if severity < HIGH_SEVERITY or "Credential" not in ftype:
return {"action": "logged-only", "severity": severity}
resource = finding.get("resource", {})
access_key_detail = resource.get("accessKeyDetails", {})
principal_type = access_key_detail.get("userType",")
principal_name = access_key_detail.get("userName",")
response: dict = {"principal": principal_name, "type": principal_type}
try:
if principal_type == "IAMUser":
response.update(quarantine_user(principal_name))
elif principal_type == "AssumedRole":
role = principal_name.split("/")[0] if "/" in principal_name else principal_name
response.update(quarantine_role(role))
else:
response["actions"] = ["manual-review-required"]
except iam.exceptions.NoSuchEntityException:
response["actions"] = ["principal-not-found"]
record_forensics(finding, response)
sns.publish(
TopicArn=ALERT_TOPIC_ARN,
Subject=f"[P1] 凭证异常已自动隔离:{principal_name}",
Message=json.dumps({
"finding_type": ftype,
"severity": severity,
"account": finding.get("accountId"),
"region": finding.get("region"),
"principal": principal_name,
"actions_taken": response.get("actions", []),
"next_steps": [
"确认该凭证的合法用途与最近使用记录",
"检查该凭证在事发期间的全部 API 调用",
"确认无横向移动后,轮换凭证并解除隔离",
],
}, ensure_ascii=False, indent=2),
)
return response
隔离而不是删除,是为了保留取证现场。删掉用户以后,CloudTrail 里的调用记录就很难关联分析了。