Question and Suitable Scenarios
A platform team wants rules such as “databases cannot be public,” “only signed images may run,” and “a role can read only its own tenant” to become testable, reviewable, and automatically enforced. The interviewer asks you to explain Policy as Code and draw the boundary between policy decisions and business execution.
Assume requests arrive from an API, CI/CD, or an infrastructure change; policy input is structured JSON; and policies need versions, rollback, and auditability. The question is about the boundary and reasoning, not a commitment to OPA, Rego, or one vendor.
What the Interviewer Is Evaluating
- Whether you separate policy definition, decision computation, and enforcement responsibilities.
- Whether you know a policy engine can return structured results rather than only a boolean.
- Whether you handle policy and input-version consistency, timeouts, caching, and default deny.
- Whether you treat policy code as software that needs review, tests, release, and audit, not as copied configuration.
A weak answer says “use OPA for authorization.” A strong answer puts a Policy Enforcement Point at the request boundary, keeps the Policy Decision Point focused on computation, and makes each decision explainable, replayable, and traceable.
Questions to Clarify Before Answering
- Is the decision for runtime access or pre-deployment compliance? Runtime decisions emphasize latency and availability; deployment checks emphasize feedback and blocking.
- Who supplies identity, tenant, resource labels, and environment state, and can those fields be trusted? Missing input must not silently become allow.
- On failure, should the system default deny, degrade to allow, or request human approval? The answer depends on action impact and availability goals.
- Can policy publication be independent of the application release? Independent releases require version binding, compatibility checks, and fast rollback.
- What must an audit record contain? If input includes personal or secret data, logs need redaction before storage or upload.
30-Second Answer Framework
“Policy as Code puts executable rules into version control, review, and testing. A request reaches a PEP, which collects and normalizes subject, action, resource, and context, then calls a PDP with the normalized input and policy version. The PDP returns a structured decision such as allow, deny, reasons, and obligations; the PEP actually blocks or continues the action. I would use default deny, bounded and versioned caching, and redacted decision logs. Before release I would run replay and canary checks, and make emergency exceptions time-bound, approved, and auditable.”
Step-by-Step Deep Answer
1. Define the policy object and boundary
Translate a natural-language rule into subject, action, resource, conditions, and outcome. “A service must not expose an unencrypted public port” can mean: the subject is a deployment pipeline, the action is create service, the resource is service configuration, the conditions are port and network attributes, and the outcome is deny with a remediation message.
The PDP reads normalized input and policy and returns allow, deny, warn, or richer structured data. The PEP sits at an API, admission controller, CI job, or service-call boundary and turns the result into block, continue, mutate, or human escalation.
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’s documentation explicitly separates decision-making from enforcement, and AWS guidance describes PDPs with PEPs on APIs. That boundary lets one rule set serve multiple entry points without pretending that the policy engine performs the business transaction.
2. Normalize input and handle missing fields
Raw formats differ by entry point: CI may provide a YAML plan, an API an HTTP request, and a service call an object. The PEP or an authorization layer should convert them to a stable internal shape and attach source, timestamp, and data-version metadata.
When tenant, owner, or environment state is missing, default deny is safer than guessing. The policy should distinguish explicit deny from “cannot decide,” allowing the PEP to request approval or retry; undefined must not be treated as 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. Treat policy as testable software
Policy files belong in Git and should pass syntax checks, unit tests, adversarial cases, and code review. Tests must cover allow and neighboring-tenant, missing-field, expired-identity, conflicting-rule, and default paths.
package invoices
default allow := false
allow if {
input.action == "read"
input.subject.tenant == input.resource.tenant
"reader" in input.subject.roles
}Fix the policy version and data snapshot in tests. If a rule depends on a live directory or network call, define timeout and staleness limits before deciding whether local caching is acceptable.
4. Design publication, caching, and rollback
Policy release needs a version, compatibility checks, and rollback like a service release. A PDP can run as a local sidecar, a library, or a centralized service: local execution reduces network latency, while centralization simplifies management. The choice depends on update speed, failure radius, and consistency requirements.
Cache only decisions with an explicit lifetime, binding subject, resource, policy version, and authorization-data version. Permission revocation, tenant migration, and high-risk actions should not use a long cache that cannot be invalidated quickly. When the PDP times out, the PEP chooses deny, approval, or a narrow pre-approved path according to action risk.
5. Record explainable, redacted decisions
Each decision needs at least policy version, input summary, result, reasons, decision ID, and PEP identity for incident replay. Inputs may contain usernames, tokens, or secrets, so the logging layer must remove or mask sensitive fields before upload.
An allow can also carry obligations, such as writing an audit event, limiting fields, or requiring step-up confirmation. The PDP returns the obligation; the PEP executes it and denies or escalates if it cannot.
High-Quality Sample Answer
I would define Policy as Code as expressing security, compliance, and operational constraints as versioned, testable, machine-readable rules. A request reaches a PEP, which authenticates the subject and normalizes subject, action, resource, and context before sending them with a policy version to a PDP. The PDP computes a decision and returns allow, deny, reasons, obligations, and a decision ID. The PEP, not the PDP, blocks the request, continues the business action, or starts human approval.
I would version policy and input data, review policies in Git, and test them with replayable snapshots. Runtime behavior defaults to deny, and caches are bound to policy and authorization-data versions; revocations invalidate high-risk decisions quickly. A PDP outage should not automatically become allow, so I would choose the failure mode by action risk. Finally, I would write redacted decision logs for audit and rollback. The same rules can then serve API, CI, and infrastructure entry points while each entry point retains enforcement responsibility.
Common Mistakes
- Mistake → Let the PDP update a database or deploy infrastructure → Why it fails → Decision and side effects become inseparable and hard to retry or audit → Fix → Return a decision and obligations from the PDP; let the PEP or business service perform effects.
- Mistake → Default to allow when the PDP times out → Why it fails → A network fault becomes a permission bypass → Fix → Choose deny, approval, or a short pre-approved path by action risk.
- Mistake → Log only allow or deny → Why it fails → Nobody can explain which rule and input produced the result → Fix → Record policy version, reasons, decision ID, and a redacted input summary.
- Mistake → Treat a policy cache as permanent truth → Why it fails → Revocations and tenant changes cannot take effect promptly → Fix → Bind versions and expiry, and invalidate on critical events.
Follow-Up Questions and Responses
If the centralized PDP is unavailable, must every read fail?
Classify the action first. Permission changes, transfers, and cross-tenant reads should default deny; a low-risk read may use a short-lived, version-bound local decision, with the cache use recorded and audited after recovery. Availability is not a universal reason to allow.
What if the policy and identity directory update at the same time?
Carry policy and identity-data versions in the decision, and have the PEP check a version or lease before enforcement. Revocation events invalidate caches; if the version cannot be confirmed, deny or re-evaluate. Test concurrent updates and delayed messages so an old decision cannot be written back.
If one rule allows and another denies, which wins?
Define precedence explicitly; never depend on file order. Use default deny with explicit deny precedence, or aggregate rules into a decision with reasons and risk. Conflicts need tests and a release gate so different entry points cannot interpret them differently.
How do you support emergency allow without destroying auditability?
Model it as a temporary policy or obligation with approver, scope, reason, start time, and expiry. The PEP records every use, automatic expiry revokes it, and replay distinguishes the exception from normal rules. Never bypass policy versions by editing a database manually.