系统架构揭秘--构建安全可靠的系统
原文地址:https://google.github.io/building-secure-and-reliable-systems/raw/toc.html
第1章 安全性与可靠性的交集
1.2 设计注意事项
可靠性与安全性的权衡:冗余和事件管理
1.3 机密性,完整性,可用性
传统定义中,安全系统的基本属性包含机密性(confidentiality),完整性(integrity),可用性(availability),CIA 三要素
可用性,既关乎可用性,有关乎安全性。比较经典的 DDoS(distributed denial-of-service)分布式拒绝服务
1.4 共性
可靠性和安全性是系统设计中比较突出的属性,并且很难事后再加固,所以设计之初就需要考虑这两个属性,系统变更的过程中,很容易影响这两点,因此需要整个系统生命周期持续关注和测试它们。
隐形
没有紧急情况下,这两者的隐形意味着可以减少和推迟也不会立刻造成严重后果,一旦失效就会带来很严重的后果。
评估
根据所需要的错误预算(sre google 运维揭秘第三章)来计划工程工作,至少一部分是可以这样做的。攻防演练也可以评估。
简洁性
可以帮助提高评估能力,是最佳方法之一。见第 6 章。
演变
随着业务迭代发展,不可避免让系统变得复杂,从而积累技术债务。微小变更导致重大故障。(debian 和 youtube 的案例)
弹性
系统设计应该包含冗余和不同的故障域,从而通过重新路由请求来限制降低故障的影响。第 8 章深入这点。第 10 章深入探讨 DoS 缓解措施。
每个组件的弹性有上限,可以通过纵深防御和故障域来解决。前者是多种防御机制的集合(冗余也是一种),独立故障域是限制故障的爆炸半径。
划分权限和限制凭证的可用范围来实现不同故障域。
最新特权原则可用缓解内部威胁。
google 是使用多方授权来确保敏感操作由特定员工组审批。
从设计到生产
从代码阶段开始,通过代码审阅来发现潜在问题,甚至公共框架和库来防止。第 12 章深入探讨。
实际部署代码的方法也可以控制安全性和可靠性的风险。第 14 章说明。
调查系统和日志
需要制定计划来检测故障并从故障中恢复。
完善的日志记录是检测和防备故障的基础。第 15 章详述日志。日志越完整详细越好,但是也有注意事项,足够大的规模,大量日志带来很大成本,给分析日志带来困难。youtube 的案例说明日志也会带来可靠性的问题,还有安全问题,日志不应该包含认证凭证和个人身份信息等敏感信息。
危机响应
组织响应非常有挑战性,需要提前制定响应计划。
大的组织,需要 24 小时响应或者跨时区协作。安全事件存在矛盾,多方参与和限制信息传递。
危机期间,需要清晰的指挥链和坚实的检查清单,行动手册和协议。
google 已经转化为事件管理(Incident Management at Google,IMAG)来处理危机响应,并且定期使用灾难恢复测试系统(Disaster Recovery Testing program,DiRT)来模拟各种故障来迫使团队应用这些。第 16,17 章说明。
恢复
快速推送变更是把双刃剑,最终归结为风险评估和业务决策。
第 9 章和第 18 章讨论。
小结
安全性和可靠性,最初很容易成为换取更快速度的代价,事后需要高昂的修复成本,所以需要尽早解决。
组织必须了解安全性和可靠性文化,第 21 章,涉及的角色和责任,见第 20 章。
第2章 攻击者
2.1 攻击者的动机
破坏安全性的首要攻击的是人,因此,可用通过攻击者的视角来考虑目的,让我们更好了解采取主动(系统设计时)和被动的(应急响应时)措施。
2.2 攻击者画像
黑客(hacking)
业务爱好者
技术专家
漏洞研究人员
漏洞奖励计划(vulnerability reward program),也称为漏洞赏金计划(bug bounty program),看 20 章。
黑客活动专家
黑客激进主义(hacktivism)
犯罪分子
通过技术威胁敏感数据而勒索受害者。
也有正常职业工作者处于某些目的而雇佣恶意攻击者。
防御犯罪分子
比如验证码。
自动化和人工智能
未来的一些攻击是可用没有人直接控制下执行的。
第 5 章,自动配置分发和访问证明。
第 14 章,代码自动构建,测试和部署。
第 8 章,DoS 攻击处理。
内部人员
组织的内部人员,内部风险就是这些人构成的威胁。
第 5 章,最小特权技术。
2009-1-31,40min,google 向每个用户每次搜索都显示不详的警告,原因是黑名单 list 被无意添加了"/",匹配了所有网站。
针对内部风险的设计
检测和降低防范内部风险和恶意外部攻击者的两类风险的策略是类似的
- 最小特权原则(第 5 章)
- 零信任(第 3 章)
- 多方授权(第 5 章)
- 业务缘由(第 5 章)
- 审计和检测(第 15 章)
- 可恢复性(第 9 章)
2.3 攻击者方法论
比较典型的几个研究攻击者方法的框架:威胁情报,网络杀伤链和 TTP(攻击者如何工作)
威胁情报
对攻击做详细的描述。
- 书面报告
- 失陷指标(indicator of compromise,IOC)是攻击的有限属性集
- 恶意软件报告
网络杀伤链
cyber kill chain,用这种形式化框架来分析攻击。
TTP
对攻击者的 TTP 进行系统性的分类。
2.4 风险评估注意事项
- 你可能没有意识到你是目标
- 攻击的复杂程度并不能真的帮你成功预测攻击
- 不要低估攻击者
- 归因是很难的
- 攻击者并不总是害怕被抓
第3章 安全代理
3.1 生产环境中的安全代理
零接触生产(Zero Touch Production,ZTP)是 google 的一个项目。要求和生产环境的每个更改都必须自动化,非通过人工进行,由软件预先验证,或者经过审查的 Breakglass 机制触发。
3.2 Google工具代理
第4章 设计中的权衡
4.1 设计目标和要求
特性需求
特性需求,也叫功能需求;关键需求是至关重要的特性需求。
非功能性需求
侧重于系统的通用属性或行为,和安全性和可靠性相关。
功能与涌现特性
可靠性和安全性是系统设计中的涌现特性
案例
google 设计文档模版中可靠性和安全性相关的部分
- 可扩展性
- 冗余和可靠性
- 依赖的注意事项
- 数据的完整性
- SLA 要求
- 安全和隐私考虑
4.2 需求平衡
增强现有系统的可靠性和安全性所需的成本
安全性和可靠性的涌现特性意味着,与之相关的设计通常是最基础的,本质上类似于基础架构体系选型。例如是选用单体架构还是微服务架构。
如果现存系统设计之初没考虑这两点,后期很难加进去。
如果缺乏组件间良好且易于理解的接口定义,同时包含复杂的依赖项,那么它的可用性处于较低的水平,而且容易出现安全问题,即使再多测试和修复也无法改变。
改变现有系统,通常需要很大的时间和成本。而且对于已有系统带来其他缺陷的风险,因此,早期设计系统之初就要考虑安全性和可靠性。
案例
4.3 处理紧张局势和统一目标
案例
统一涌现特性的需求
4.4 初始速度和持续速度
结论:团队文化中尽早嵌入安全性和可靠性是很重要的
小结
安全性和可靠性是整个开发和运营流程中的主要涌现特性。
安全性,可靠性和功能需求之间有诸多权衡,甚至乍一看是互相冲突的。早期避开前两者似乎很提升了效率,但是带来巨大的成本和风险。
第5章 最新特权设计
最小特权设计过程中可能面临权衡和冲突。
人总是会犯错,引用 SRE 的座右铭,“希望不是一种战略”。
5.1 概念和术语
最小特权
拒绝给工具授予绝对权限,尽可能确保用户没有环境特权,如 root 身份登入权限
零信任网络
设计原则从零信任网络开始,不授予用户所在网络位置的任何访问特权,如内网不能比外网 vpn 获得更多访问权限。系统根据用户凭证和设备凭证的组合授权访问权限。
零接触
自动化构建最小特权概念,目标就是零接触界面。第三章有 ZTP 和 ZTN。
5.2 基于风险的访问分类
并非所有数据和操作都是对等的,需要根据影响,安全风险和关键程度对访问进行分类。
5.3 最佳实践
API 功能最小化
Breakglass 机制
紧急情况下打碎玻璃,在非预期情况下恢复服务。
审计
用于检测不正确的授权。
在Google,执行两大类的审计:
- 审计确保遵循最佳实践的做法
- 审计确认安全违规事件
最佳实践类的审核是为了支持可靠性的目标。SRE团队每周团队会议期间审核上周使用Breakglass机制的事件,形成文化压力,要求使用和改进最小化的服务管理类API,而不是使用Breakglass来作为常规工作。
Google通常会将Breakglass事件的审计下饭到团队级别。
在Google,倾向于第二类审计,因为大组织的多方位视角有益于识别外部的安全漏洞。
在Google,使用结构化论证。将结构化数据与审核日志事件关联起来。例如客户支持人员查看客户的付款详细信息或者其他敏感信息时,可以将这些数据与特定的客户咨询单相关联。这样可以确保观察到的数据属于寻求咨询的客户。
测试和最小特权
合理的测试是任何一个设计精良的系统的基础属性。
最小特权,两个维度:
- 针对最小特权的测试,确保仅授予必要资源的访问权限
- 使用最小特权进行测试,确保用于测试的基础设施仅具有所需的访问权限
安全性和可靠性的权衡:测试环境
测试的最佳实践很美好,但是构建适当的测试基础设施的潜在成本很高,但是反过来考虑下没有适当的测试基础设施的成本也很高。所以投入-产出比
分析很重要。
诊断被拒绝的访问
优雅失败和Breakglass机制
5.4 工作案例:配置分发
5.5 认证和授权决策的策略框架
授权控件:有如因素授权MFA,多方授权MPA
随着组织的发展,标准化是必须的。
5.6 高级控制
MPA
让另外一个人参与进来是确保访问决策正确的一种经典方法。
MPA通常用于大范围的访问控制。
3FA
MFA有关键弱点,所有审批的“多方”,都使用集中管理的工作站,一旦一个被攻破,工作站同质化程度高,其他甚至全部工作站被攻破可能越高。
一种选择是要求某些非常危险的操作获得已加固移动平台的授权。
简单起见,只允许RPC来源完全托管桌面工作站,然后需要来自移动平台的三因素授权(3FA)。发现对于移动平台加固用户更能接受。
在google,复用向android手机发送通知的基础设施,用于授权以及向用户报告尝试登入google账户的行为。
临时访问
代理
5.7 权衡和冲突
采用最小特权原则的访问模型肯定会改善组织的安全姿态,但是必须将前面各点概述的优势与实施后的潜在成本相抵消。下面说下成本。
增加了安全的复杂性
对合作商以及公司文化的影响
代码权限放开有风险,但是也有好处。
影响安全性的质量数据和系统
对用户工作效率的影响
对开发复杂性的影响
第6章 面向易理解的设计
第7章 适应变化的设计
唯一不变的就是变化本身。—— 古希腊哲学家赫拉克利特(Heraclitus of Ephesus)
7.1 安全变更的类型
7.2 变更中的设计
7.3 让发布更容易的架构决策
让依赖项保持最新并频繁重建
主要指的是依赖的开源项目,openssl,linux kernel等,大型开源项目有完善的安全漏洞响应和修复计划。
用自动化测试让发布更频繁
大版本拆分成许多小版本,并且实施自动化测试和验证。
使用容器
使用微服务
Google的前端设计(Google Front End,GFE),类似大网关的设计。
7.4 不同的变更:不同的速度与不同的时间线
不是所有变更都会在相同的时间线上或者以相同的速度发生。
Google处理3个变更时间范围:
- 新安全漏洞的短期变更
- 新产品逐步落地的中期变更
- 监管原因是的Google必须建立新系统才能落地的长期变更
短期变更:零日漏洞
案例:破壳漏洞(shellshock)
Google的几点建议:
- 最大限度地标准化软件发布
- 理想情况使用公共的分发标准
- 确保可以为紧急情况下的变更实施加速机制
- 确保有监控来跟踪部署进度,定位未打补丁的系统以确定仍存在的漏洞的位置
- 在响应工作中尽可能早地准备外部沟通
- 提前起草可复用的事件或漏洞响应计划
- 了解哪些系统是非标准的或需要特别关注
中期变更:改善安全态势
案例:使用FIDO安全密钥实现的强制双因素身份认证机制
Google以前使用一次性秘密(OTP),后面调研来双因素身份认证(2FA),最终选择了通用双因素硬件安全令牌(U2F)
长期变更:外部需求
案例:提升https的使用率
7.5 难点:计划调整
可能需要根据外部因素延迟变更
可能需要加快基于公开声明的变更
可能受到的影响不够严重
可能依赖于外部各方
7.6 不断扩大的范围:心脏滴血漏洞
第8章 弹性设计
好的系统设计应该包含弹性规划:系统抵御攻击和承受异常情况
弹性设计与易恢复设计不同,虽然密切相关,后者关注系统损坏后自我修复的能力,前者意味着经得起破坏的系统。弹性系统和恢复性系统都可以更好地从故障中恢复,并且人工干预最小化。
8.1 弹性设计原则
- 将系统设计成每一层都具备弹性的状态
- 确定每项功能的优秀级及其成本
- 按照明确的边界定义划分系统
- 利用部分区域冗余防止局部故障
- 通过尽可能多而安全地自动执行弹性措施,缩短系统的反应时间
- 通过验证系统的弹性属性(包括自动响应和系统的其他弹性属性)来维护系统的有效性
8.2 纵深防御
通过建立多层防御边界来保护系统
特洛伊木马
- 威胁建模和漏洞发现
- 部署
- 执行
- 攻破
Google App Engine分析
- 存在风险的api
- 运行时层
8.3 控制降级
- 通过禁用不常用的功能、最不重要的功能或高成本的服务功能
- 让系统响应措施快速、自动生效
- 了解对公式来说至关重要的系统,以及它们的相对重要性和相互依赖性
安全性和可靠性的权衡:可控降级
区分故障成本
- 确定单个运营环节的总成本
- 确定这些成本发生在运营中的哪个阶段
有了这些信息就可以寻找处可能会推迟高成本操作的变更,直到系统成功恢复
- 计算资源。服务器了解自己的健康状态在下降,可以切换到lame-duck模式,让上游减少或者停止调用
- 用户体验。可以添加离线模式
- 缓解速度。
部署响应机制
建议的连个特定的自动化策略
- 降低负载通过返回错误完成
对客户端的限制是通过将响应延迟到接近截止时间来实现的(有问题的策略)
- 降低负载
- 限流(等待的方式,Google 运维揭秘 21章)
- 自动响应(中央限流server)
负责任的自动化
失效安全(fail-safe)与失效保障(fail-secure)
两者需要权衡
失效安全等于故障时打开,保持运营,默认ACL(Access Control List),allow all
失效保障等于故障时关闭,保持安全,默认ACL,deny all
人类的立足点
允许人为干预到服务降级决策中,需要在系统设计中进行一些预设。
8.4 控制爆炸半径
为了提高安全性的常见方法是对网络进行分段
角色分离
服务账户
位置分离
多机房
统一物理和逻辑架构
信任隔离
基于区域的信任限制
机密性隔离
有了信任隔离的系统,就需要隔离加密密钥
时间分离
基于时间来限制攻击者的能力,定期轮换密钥和凭证
8.5 故障域和冗余
需要平衡的方案
- 将系统分解成独立的故障域
- 将降低单一根源影响到多个故障域的概率作为目标
- 创建可替换故障资源、组间或程序的冗余备份
故障域
控制爆炸半径的一种措施。故障域不是按角色、区域或时间分离,而是通过将系统划分为多个等价但完全独立的副本来实现功能隔离
功能隔离
操作和保持隔离需要持续投入工作。这样做换来的好处是故障域增加了系统的弹性,其他控制爆炸半径的措施无法做到。
数据隔离
建议两种方法来实现数据隔离
组件类型
一个故障域的弹性质量是由它的组件及其依赖项两方面的可靠性综合表现出来的。
大容量组件
大容量的服务
高可用组件
低依赖的组件
控制冗余
故障转移策略
8.6 持续验证(重点看下)
混沌工程可以作为主要手段
验证关键区域
1.注入预期的行为变化
2.将紧急组件作为正常工作的一部分
高可用系统通过镜像进行请求验证,客户端发送两个相同的请求,一个发送到大容量组件,另一个发送到高可用性组件
3.无法镜像请求时就拆分
4.允许超额使用,但防止自满
5.测算密钥轮换周期
验证实践
8.7 实践建议
设计弹性系统不容易。
先按成本排序
- 故障域和控制爆炸半径的成本最低
- 高可用性服务是下一个最具性价比的解决方案
- 对自动化进行投入能实现弹性,考虑部署降低负载和限流功能
- 评估防御DoS攻击的有效性
- 如果你构建的是低依赖性解决方案,请引入一个流程或机制来确保它在一段时间内能保持低依赖性
一些帮助
- 部署故障域和控制爆炸半径将对未来的系统产生持久的影响。隔离技术可以鼓励或强制良好的划分运营故障域。一旦实现到位,它们将不可避免地让实施和部署不必要的耦合或脆弱系统难以实现。
- 定期变更密钥和轮换的技术和演示不仅可以为安全事件做好准备,还可以提供加密的灵活性。例如,可以升级加密原语。
- 部署服务的高可用性实例带来的额外成本相对较低,这提供了一种经济实惠的方式来考察你可以在多大程度上提高服务的可用性。弃用它的成本也很低。
- 降低负载和限流的功能,以及在 8.3 节中涉及的其他方法,可以降低公司需要维护的资源成本。由此产生的用户可见的改进通常适用于最有价值的产品功能。
- 在防御 DoS 攻击时,可控降级至关重要,有助于提高第一反应的速度和效率。
- 低依赖性的解决方案相对比较昂贵,在实践中很少使用。要确定它们是否物有所值,了解一下需要多长时间才能提出业务关键型服务的所有依赖项,这有助于确定这些服务是否物有所值。然后你可以比较一下成本,并得出结论:把时间投入到别处是否更好。
即使弹性设计,也可能在某个时候弹性不足而崩溃,那么在这之后如何恢复受损的系统,将损失的影响降到最低就是面向恢复的设计。
第9章 面向恢复的设计
9.1 恢复的对象
随机错误,意外错误,软件错误和恶意行为
随机错误
硬件故障
意外的位翻转
自然灾害
意外错误
人出于善意的操作而导致的错误
软件错误
开发过程中常见的bug等
恶意行为
9.2 恢复机制的设计原则
面向快捷恢复的设计
xxx
常规发布系统和紧急回滚系统是同一个系统
限制对外部世界观念的依赖
回滚所代表的安全性和可靠性的权衡
使用显式吊销机制
了解精确到字节的预期状态
主机管理
设备固件
Google的包管理系统,不允许单独配置和安装包,不允许只成功一半,都要保证成功,否则回滚。
Spanner是Google的全球分布式数据库,支持外部一致的分布式事务,要求数据中心之间及时保持数据同步,依赖供应商提供的特殊硬件来与外部时间源进行对接。
全局服务
系统最难恢复的区域可能是最高抽象层和基础设施中最持久的部分,如存储,名字服务和身份服务。
持久性数据
没人关心备份,他们只关心恢复
9.3 紧急访问
当无法开展全局范围内的合作时,可以在各个小区域,尝试独立解决问题。
访问控制
通信
通信技术,在线会议等
响应人员的习惯
定期开展紧急访问演习,融入日常习惯中,并且持续验证相关系统的可用性。增强一种确定感,当发生事件时,能保证团队确实拥有相关资质,并且接受必要培训,否则可强制要求演练。
保障相关文档的可用性。
9.4 预期外的收益
面向易恢复设计的机器已经有了安全和自动化的解决方案。