题干与适用场景
平台团队希望把“禁止公开数据库”“只允许签名镜像”“某角色只能访问自己的租户”等规则从文档变成可测试、可审查、可自动执行的策略。面试官要求你解释 Policy as Code,并画出策略决策与业务执行的边界。
默认假设:请求来自 API、CI/CD 或基础设施变更;策略输入是结构化 JSON;策略需要版本、回滚和审计。题目讨论的是通用边界,不绑定 OPA、Rego 或某一家公司的实现。
面试官考察点
- 是否能把策略定义、决策计算和强制执行拆成清晰的职责。
- 是否知道策略引擎可以返回结构化结果,而不只是布尔值。
- 是否能处理策略与输入数据的版本一致性、超时、缓存和默认拒绝。
- 是否能把策略代码纳入代码评审、测试、发布和审计,而不是把它当成配置文件复制。
普通回答只说“用 OPA 做鉴权”。强回答会说明 PEP 在请求边界阻断动作,PDP 只负责计算决定,并且每个决定都能解释、回放和追踪。
回答前需要澄清的问题
- 决定的是运行时访问,还是部署前合规检查?运行时更关注延迟和可用性,部署前更关注反馈和阻断。
- 策略输入由谁提供,身份、租户、资源标签和环境状态是否可信?输入不完整时不能默默放行。
- 失败时默认拒绝、降级放行还是进入人工审批?这取决于动作的破坏性和业务可用性目标。
- 是否允许策略发布与业务代码独立上线?独立发布需要版本绑定、兼容检查和快速回滚。
- 审计需要看到哪些字段?若输入含个人或秘密数据,日志必须脱敏后再保存。
30 秒回答框架
“Policy as Code 把可执行规则放进版本控制、评审和测试流程。请求先由 PEP 收集并规范化主体、动作、资源和环境,再调用 PDP 计算结构化决定,例如允许、拒绝、原因和策略版本。PEP 负责真正阻断或继续执行,不能把 PDP 的返回当成自动完成了安全控制。我会给决定绑定策略和输入版本,采用默认拒绝、受控缓存和超时策略,并记录可脱敏的决定日志。发布前做回放和金丝雀,紧急放行也要有期限、审批和审计。”
分步骤深入解答
1. 先定义策略对象和决策边界
把自然语言规则拆成主体、动作、资源、条件和结果。例如“服务不得公开暴露未加密端口”可以表达为:主体是部署流水线,动作是创建服务,资源是服务配置,条件是端口与网络属性,结果是拒绝并附带修复消息。
PDP 读取规范化输入和策略,返回 allow、deny、warn 或更丰富的结构化数据。PEP 位于 API、Admission Controller、CI job 或服务调用边界,负责把决定落实为阻断、继续、修改或人工升级。
caller -> PEP: subject, action, resource, context
PEP -> PDP: normalized input + policy version
PDP -> PEP: decision, reasons, obligations, decision_id
PEP -> target: enforce decision or stop request
PEP -> audit: redacted decision recordOPA 官方文档明确强调决策与执行解耦,AWS 的设计指南也把 PDP 与 API 上的 PEP 分开。这个边界让同一套规则可用于多个入口,但不会误以为策略引擎能替业务完成事务。
2. 规范化输入并处理缺失字段
不同入口的原始输入格式不同:CI 可能给 YAML 计划,API 给 HTTP 请求,服务间调用给对象。PEP 或授权中间层应先转换成稳定的内部结构,并标记来源、时间和数据版本。
缺少租户、资源所有者或环境状态时,默认拒绝比猜测安全。策略要区分“明确拒绝”和“无法判断”,让 PEP 决定是否人工审批或稍后重试;不能把 undefined 当成 allow。
{
"subject": {"id": "u-17", "tenant": "t-3", "roles": ["reader"]},
"action": "read",
"resource": {"type": "invoice", "id": "inv-9", "tenant": "t-3"},
"context": {"environment": "prod", "authn_level": "mfa"},
"policy_version": "2026-06-18.4"
}3. 让策略成为可测试的软件
策略文件进入 Git,经过语法检查、单元测试、对抗样例和代码评审。测试不仅验证 allow,还要验证相邻租户、缺失字段、过期身份、冲突规则和默认路径。
package invoices
default allow := false
allow if {
input.action == "read"
input.subject.tenant == input.resource.tenant
"reader" in input.subject.roles
}测试输入应固定策略版本和数据快照。若规则依赖实时目录或网络调用,先定义超时和陈旧数据上限,再决定是否允许本地缓存。
4. 设计发布、缓存和回滚
策略发布要像服务发布一样有版本号、兼容检查和回滚。PDP 可以本地 sidecar、库或集中服务部署:本地模式降低网络延迟,集中模式便于统一管理;选择取决于策略更新速度、故障半径和一致性要求。
缓存只能缓存有明确生存期的决定,并绑定主体、资源、策略版本和输入数据版本。权限撤销、租户迁移或高风险动作不应使用无法及时失效的长缓存。PDP 超时后,PEP 应按动作风险选择拒绝、人工审批或有限的预先批准路径。
5. 记录可解释且可脱敏的决定
每次决定至少需要策略版本、输入摘要、结果、原因、决定 ID 和 PEP 标识,才能在事故后回放。输入可能含用户名、令牌或秘密,日志系统应在上传前删除或掩码敏感字段。
“允许”也可以带义务,例如必须写审计事件、限制字段或要求二次确认。PDP 返回义务,PEP 负责执行并在无法执行时拒绝或升级。
高质量示范回答
我会把 Policy as Code 定义为:把安全、合规和运行约束写成可版本化、可测试的机器可读规则。请求先到 PEP,由它验证身份、组装并规范化主体、动作、资源和上下文,再把输入和策略版本交给 PDP。PDP 只计算决定,返回 allow、deny、原因、义务和决定 ID;PEP 才负责阻断请求、继续业务或发起人工审批。
我会为策略和输入绑定版本,策略进入 Git、评审、单元测试和回放流程。运行时优先默认拒绝,缓存绑定策略版本和授权数据版本;撤销权限等高风险变化要快速失效。PDP 不可用时不能一概降级放行,我会按动作风险分别处理。最后记录经过脱敏的决定日志,支持审计和回滚。这样同一规则能复用在 API、CI 和基础设施入口,同时保留每个入口的执行责任。
常见错误
- 错误表现 → 让 PDP 直接修改数据库或执行部署 → 失败原因 → 决策与副作用混在一起,难以重试和审计 → 修正方法 → PDP 返回决定与义务,PEP 或业务服务执行副作用。
- 错误表现 → PDP 超时就默认放行 → 失败原因 → 网络故障变成权限绕过 → 修正方法 → 按动作风险采用拒绝、人工审批或短期预批准。
- 错误表现 → 只记录 allow/deny → 失败原因 → 无法解释哪条规则和哪份输入导致结果 → 修正方法 → 记录策略版本、原因、决定 ID 与脱敏输入摘要。
- 错误表现 → 把策略缓存当成永久真相 → 失败原因 → 撤销或租户变更无法及时生效 → 修正方法 → 绑定数据版本和失效时间,关键事件主动清缓存。
追问及应对
如果 PDP 集中服务不可用,所有读取请求都要失败吗?
先按风险分级。修改权限、转账、跨租户读取等高风险动作默认拒绝;低风险只读动作可以使用短期、版本绑定的本地决定,但必须记录使用了缓存,并在恢复后补审计。不能把“可用性”作为所有资源的统一放行理由。
如果策略和身份目录同时更新,怎样避免旧决定覆盖新权限?
让决定携带策略版本与身份数据版本,PEP 在执行前检查版本或租约。撤销事件触发缓存失效;无法确认版本时走拒绝或重新评估。测试中加入并发更新和延迟消息,验证旧决定不会被重新写回。
如果两条规则一条 allow、一条 deny,谁优先?
优先级必须显式定义,不能依赖文件顺序。可以采用默认拒绝、显式 deny 优先,或将规则合并为带原因和风险等级的决定。规则冲突应有测试用例和发布阻断,避免不同入口解释不一致。
如何支持紧急放行而不破坏审计?
把紧急放行建模为有审批人、范围、原因、开始和过期时间的临时策略或义务;PEP 在每次使用时记录它。到期自动撤销,回放工具能区分正常规则和紧急例外,不能通过手工改数据库绕过策略版本。