Documentation
¶
Overview ¶
Package authz is Atlas's policy decision point: it decides whether one external Worker action may run, and why (ADR-0475).
It is pure. Set.Evaluate reads its arguments and nothing else — no store, no network, no clock (the instant is in the request) — so a decision is a function of its request and can be explained, tested and simulated as one. Assembling the request from trusted server-side facts is the caller's job (the policy information point), and acting on the answer is the enforcement point's; neither lives here.
It fails closed. The zero Decision is Indeterminate, an evaluation error is Indeterminate, no applicable policy is NotApplicable, and only Decision.Permitted lets an action through.
Index ¶
- Constants
- func Digest(workerType, worker, operation, resource string, params map[string]any) (string, error)
- func IsDelegated(mode string) bool
- type Action
- type Actor
- type Approval
- type Connection
- type Context
- type Decision
- type Document
- type Effect
- type Match
- type ObligationDoc
- type ObligationResult
- type Policy
- type Published
- type Request
- type Resource
- type RuleDoc
- type Set
- type Step
- type Subject
- type Target
Constants ¶
const ( FirstApplicable = "first-applicable" DenyOverrides = "deny-overrides" )
Rule-combining algorithms a policy may declare. There is no default: an algorithm left out is refused, because the two answer the same rules differently.
const ( ObligationApproval = "approval" ObligationFreshAuthentication = "fresh-authentication" )
Obligation types.
const ( ReasonPermit = "PERMIT" ReasonPolicyDeny = "POLICY_DENY" ReasonPolicyIndeterminate = "POLICY_INDETERMINATE" ReasonNoApplicablePolicy = "NO_APPLICABLE_POLICY" ReasonApprovalRequired = "APPROVAL_REQUIRED" ReasonApprovalRejected = "APPROVAL_REJECTED" ReasonApprovalExpired = "APPROVAL_EXPIRED" ReasonReauthRequired = "REAUTHENTICATION_REQUIRED" )
Reason codes the PDP itself produces. Rules add their own.
const ( // ModeService executes as the Worker's own service identity. The Worker // Instance holds that credential, so enforcement is cooperative. ModeService = "service" // ModeDelegatedFixed executes as one connection's external identity, for the // connection's owner. ModeDelegatedFixed = "delegated-fixed" // ModeDelegatedPerJob executes as the executing subject's own connection, // chosen for each job. ModeDelegatedPerJob = "delegated-per-job" )
Identity modes a configured Worker may declare.
const ( ConnectionActive = "active" ConnectionReauthRequired = "reauth_required" ConnectionRevoked = "revoked" )
Connection states.
const ( ApprovalGranted = "granted" ApprovalRejected = "rejected" )
Approval outcomes.
const ( MaxListLen = 256 MaxApprovals = 64 )
MaxListLen bounds every list a request carries, and MaxApprovals the approvals: evaluation time is bounded by its input, because neither FEEL nor temis offers a step budget to bound it otherwise.
Variables ¶
This section is empty.
Functions ¶
func Digest ¶
Digest is the identity of one action: SHA-256 over a canonical JSON of the Worker Type, the Worker, the operation, the canonical resource and every material parameter. An approval is of a digest, so approving one action can never be replayed for another (ADR-0475 §9).
The JSON is canonical because encoding/json writes map keys in sorted order and a value decoded from JSON re-encodes to the same bytes. Only the server computes a digest, over the parameters it resolved itself; a digest a Worker reports is never read.
func IsDelegated ¶
IsDelegated reports whether mode executes as a person through a connection, which is what makes a subject and a connection mandatory.
Types ¶
type Action ¶
type Action struct {
Operation string
// Digest is [Digest] over the Worker Type, the Worker, the operation, the
// resource and every material parameter. Approvals are of a digest.
Digest string
}
Action is the operation and the digest of everything it will do.
type Actor ¶
type Actor struct {
IdentityMode string
Worker string // the configured Worker the compiled task names
WorkerType string
// WorkerInstance is the lease holder's self-asserted label. It is recorded and
// may be matched by nothing that decides — it is not a credential.
WorkerInstance string
// ExecutedAs is the external identity key, or "service:<worker>".
ExecutedAs string
// Connection is the connection a delegated mode uses; nil when there is none.
Connection *Connection
}
Actor is what executes the action: the configured Worker, its identity mode, and the identity it acts as.
type Approval ¶
type Approval struct {
ID string `json:"id"`
Digest string `json:"digest"`
ApproverID string `json:"approverId"`
ApproverGroups []string `json:"approverGroups"` // the approver's groups now, not when they decided
Outcome string `json:"outcome"` // ApprovalGranted or ApprovalRejected
DecidedAt int64 `json:"decidedAt"` // Unix nanoseconds
Revoked bool `json:"revoked"`
}
Approval is one approver's decision about one action digest.
type Connection ¶
type Connection struct {
ID string `json:"id"`
OwnerID string `json:"ownerId"`
Status string `json:"status"`
AllowedWorkers []string `json:"allowedWorkers"`
// LastInteractiveAuth is when its owner last signed in at the provider, Unix
// nanoseconds; 0 when unknown.
LastInteractiveAuth int64 `json:"lastInteractiveAuth"`
}
Connection is the public half of a connection: never its credential.
type Context ¶
type Context struct {
// Time is the evaluation instant, Unix nanoseconds, read by the caller from its
// clock and frozen into the decision's event.
Time int64
ProcessID string // the BPMN process id
ProcessInstanceKey uint64
JobKey uint64
// InitiatedBy is the principal who started the process instance, as the engine
// recorded it at creation; empty when nobody authenticated did.
InitiatedBy string
// Approvals are the approval facts recorded for this instance, with each
// approver's current group membership.
Approvals []Approval
}
Context is when and in which process the action happens.
type Decision ¶
type Decision struct {
Effect Effect
ReasonCode string
// PolicyID and PolicyVersion name the deciding policy: the first Deny under
// deny-overrides, else the first Permit. Empty for a guard's or a default answer.
PolicyID string
PolicyVersion int
// Obligations are those of every contributing Permit, satisfied or not.
Obligations []ObligationResult
// Trace is every policy that was asked and what it said, in evaluation order.
Trace []Step
}
Decision is the PDP's answer, with everything needed to explain it.
type Document ¶
type Document struct {
ID string `json:"id"`
Description string `json:"description,omitempty"`
// Priority orders policies, lowest first. It decides nothing under the fixed
// deny-overrides combination; it decides which policy is reported as deciding
// and the order of the explanation.
Priority int `json:"priority,omitempty"`
Target Target `json:"target,omitempty"`
RuleCombining string `json:"ruleCombining"`
Rules []RuleDoc `json:"rules"`
// DMN is a DMN model whose decisions rules may name. It is compiled once, at
// publication.
DMN string `json:"dmn,omitempty"`
}
Document is a policy as an administrator writes it. It is decoded strictly: a field this build does not know is refused rather than ignored, because an ignored matcher ("subjectGroupAny") is a rule that matches everyone.
func ParseDocument ¶
ParseDocument decodes one policy, refusing unknown fields and trailing content.
type Effect ¶
type Effect uint8
Effect is what a decision, a policy or a rule says.
const ( // Indeterminate is the zero value: something could not be decided — a missing // attribute, a condition that did not evaluate to a boolean, a policy set that // is not there. Never a permit. Indeterminate Effect = iota // Permit lets the action run, once every obligation it carries is satisfied. Permit // Deny refuses it. Deny // NotApplicable means nothing spoke to this request. The enforcement point // treats it as a refusal: Atlas authorizes by default deny. NotApplicable )
func ParseEffect ¶
ParseEffect reads an effect as a policy or a DMN decision writes it. Indeterminate is not something a rule may answer on purpose, so it does not parse.
type Match ¶
type Match struct {
SubjectRolesAny []string `json:"subjectRolesAny,omitempty"`
SubjectGroupsAny []string `json:"subjectGroupsAny,omitempty"`
SubjectIDs []string `json:"subjectIds,omitempty"`
Operations []string `json:"operations,omitempty"`
Workers []string `json:"workers,omitempty"`
IdentityModes []string `json:"identityModes,omitempty"`
ProcessIDs []string `json:"processIds,omitempty"`
// ResourcePrefixes match when the canonical resource id starts with one.
ResourcePrefixes []string `json:"resourcePrefixes,omitempty"`
}
Match is a rule's structured matchers. Every set list must match; a list matches when it contains the request's value (or, for SubjectRolesAny and SubjectGroupsAny, any of the subject's).
type ObligationDoc ¶
type ObligationDoc struct {
ID string `json:"id"`
Type string `json:"type"`
// approval
ApproverGroup string `json:"approverGroup,omitempty"`
Approvals int `json:"approvals,omitempty"`
ValidForSeconds int64 `json:"validForSeconds,omitempty"`
ExcludeRequester bool `json:"excludeRequester,omitempty"`
// fresh-authentication
MaxAgeSeconds int64 `json:"maxAgeSeconds,omitempty"`
}
ObligationDoc is a condition a Permit carries that the server verifies from its own records before the action runs.
type ObligationResult ¶
type ObligationResult struct {
ID string `json:"id"`
Type string `json:"type"`
PolicyID string `json:"policyId"`
PolicyVersion int `json:"policyVersion"`
RuleID string `json:"ruleId,omitempty"`
Satisfied bool `json:"satisfied"`
Reason string `json:"reason,omitempty"` // why it is not satisfied; empty when it is
// ApprovalsUsed are the ids of the approvals that satisfied it, sorted.
ApprovalsUsed []string `json:"approvalsUsed,omitempty"`
// What the approval asks for, so the enforcement point can open a request.
ApproverGroup string `json:"approverGroup,omitempty"`
Approvals int `json:"approvals,omitempty"`
ValidForSeconds int64 `json:"validForSeconds,omitempty"`
ExcludeRequester bool `json:"excludeRequester,omitempty"`
}
ObligationResult is one obligation and whether the request satisfies it. An unmet approval carries what an approval request needs to be opened for it.
Its JSON names are part of the recorded evidence (an authorization's detail), so they are spelled out rather than left to the field names.
type Policy ¶
type Policy struct {
// contains filtered or unexported fields
}
Policy is one published policy compiled for evaluation. It is immutable and safe for concurrent use.
func CompilePolicy ¶
CompilePolicy validates and compiles one policy. Everything that can be checked without a request is checked here — the structure, every FEEL condition, the DMN model — so nothing is parsed or compiled when a decision is asked for (invariant I5). It returns warnings for what is legal but unsafe to rely on.
type Request ¶
Request is everything a decision may depend on. Every field is filled by the server from its own records; nothing in it comes from a BPMN model's claims, a process variable or a Worker Instance's report.
type Resource ¶
Resource is what the action touches, in its canonical spelling ("sharepoint:site=…;list=…;path=…").
type RuleDoc ¶
type RuleDoc struct {
ID string `json:"id"`
// Effect is "Permit" or "Deny". Exactly one of Effect and Decision is set.
Effect string `json:"effect,omitempty"`
// Decision names a decision of the policy's DMN model; its outputs "effect" and
// "reasonCode" are the rule's answer.
Decision string `json:"decision,omitempty"`
ReasonCode string `json:"reasonCode,omitempty"`
When Match `json:"when,omitempty"`
// Condition is a FEEL boolean over subject, actor, action, resource and context.
Condition string `json:"condition,omitempty"`
Obligations []ObligationDoc `json:"obligations,omitempty"`
}
RuleDoc is one rule: a static effect under conditions, or a DMN decision.
type Set ¶
type Set struct {
// contains filtered or unexported fields
}
Set is the compiled, published policy set. It is immutable: publishing builds a new one, and a reader holding the old one keeps deciding with it.
func CompileSet ¶
CompileSet compiles every published policy into one set, ordered by priority and then id so the order of the input never changes an answer.
func (*Set) Evaluate ¶
Evaluate decides one request. A nil set is a set that could not be loaded, and is Indeterminate: "there are no policies" and "the policies are unreadable" must never be confused, because the first denies by default while the second would deny for a reason nobody can fix by writing a policy.
type Step ¶
type Step struct {
PolicyID string
PolicyVersion int
RuleID string // the rule that answered; empty when none did
Effect Effect
Reason string
Note string // why an answer was Indeterminate
}
Step is one policy's answer.
type Subject ¶
type Subject struct {
// ID is the stable principal id ("usr_…"); empty when there is none.
ID string
// Known says ID was found in the user store; Disabled that the account is
// deactivated. Both are read at decision time — current state decides.
Known bool
Disabled bool
// Roles and Groups are the principal's current roles and group ids.
Roles []string
Groups []string
}
Subject is the Atlas principal the action is executed for.
type Target ¶
type Target struct {
WorkerTypes []string `json:"workerTypes,omitempty"`
Workers []string `json:"workers,omitempty"`
Operations []string `json:"operations,omitempty"`
IdentityModes []string `json:"identityModes,omitempty"`
}
Target selects the requests a policy speaks to. Every list that is set must contain the request's value; an empty target applies to every governed action.