Documentation
¶
Overview ¶
Package authz is Wardyn's authorization kernel: the one Decision every door refuses with, and the registry of refusal reasons that is the audit contract a SIEM rule is written against. Pure Go — no HTTP, no store — so the same Decision can later cross a wire (schema authz/v1) unchanged.
Index ¶
Constants ¶
const AuditAction = "authz.denied"
AuditAction is the audit action every audited refusal is recorded under.
const Schema = "authz/v1"
Schema names the wire shape of Decision. Changes inside v1 are additive and readers ignore unknown fields; a removal or rename is a new schema.
Variables ¶
This section is empty.
Functions ¶
func Datum ¶
Datum is the data of d's audit row, refused to p over method (empty when no request carried it). A detail never stands in for a reserved key, so it can never forge the reason or a marker. user_view is a marker present only when true (renamed in 0.8 from member_mode); device_channel is a sibling of the ingest marker device_origin, never that key.
Types ¶
type Decision ¶
type Decision struct {
Schema string `json:"schema"`
Effect Effect `json:"effect"`
Status int `json:"status"`
Reason Reason `json:"reason,omitempty"`
// Target is what was refused: a request field (runs.image), a route, or a
// resource id.
Target string `json:"target,omitempty"`
RunID *uuid.UUID `json:"run_id,omitempty"`
// Sentence is the refusal body. Empty means the reason's own sentence.
Sentence string `json:"sentence,omitempty"`
// WireReason overrides the reason an HTTP response carries, when set
// (#656 slice 3's refuse fix). d.Reason itself is never overridden — the
// audit row's own "reason" field (authz.Datum) always uses the TRUE
// cause — this only changes what the CALLER sees. Its one use today is a
// Hidden-effect decision (EffectHidden: "byte-identical to a missing
// row"): the caller must see the SAME reason a truly-missing resource's
// 404 carries, never the internal "not_owner"/"attach_ticket_foreign_run"
// that would tell a prober the resource exists. See Decision.AsIf.
WireReason Reason `json:"wire_reason,omitempty"`
Detail map[string]string `json:"detail,omitempty"`
Obligations []Obligation `json:"obligations,omitempty"`
Trace []Step `json:"trace,omitempty"`
}
Decision is one authorization answer. Every field is data (no funcs), so it serializes as-is.
func Deny ¶
Deny is the refusal of target for reason, answered with sentence. The effect and status come from the registry, never from the door; an unregistered reason still refuses (403) and is caught where it is emitted.
func Drop ¶
Drop is the refusal of the listed entries of target for reason: they are removed and the request proceeds without them.
type Effect ¶
type Effect string
Effect is what a Decision does to the request. Append-only: it is part of the wire contract (testdata/wire.golden).
const ( EffectAllow Effect = "allow" EffectDeny Effect = "deny" // EffectHidden is the 404 twin: byte-identical to a missing row, so a // refusal is never an existence oracle. EffectHidden Effect = "hidden" EffectUnprocessable Effect = "unprocessable" // EffectConflict is a refusal answered 409: the request is well-formed and // the caller could otherwise make it, but their own session state (a // deleted user-view type) conflicts with it. EffectConflict Effect = "conflict" )
type Obligation ¶
type Obligation struct {
Kind ObligationKind `json:"kind"`
Detail string `json:"detail"`
}
Obligation is one thing a Decision does to one part of the request.
type ObligationKind ¶
type ObligationKind string
ObligationKind is what an allow still does to the request. Append-only, like Effect.
const ObligationDrop ObligationKind = "drop"
ObligationDrop removes one entry from the request and lets the rest proceed.
type Origin ¶
type Origin struct {
DeviceID *uuid.UUID `json:"device_id,omitempty"`
Placement string `json:"placement,omitempty"`
}
Origin is where a request reached the deciding control plane from. Zero in 0.8. Only the org sets DeviceID, from the device channel it authenticated — never from anything a laptop asserts.
type Principal ¶
type Principal struct {
Subject string `json:"subject"`
// MemberView: an admin exercising "view as member"; only marks the row,
// the tier the kernel saw is already clamped.
MemberView bool `json:"member_view,omitempty"`
// UserType is the type a member view looks through; read only with MemberView.
UserType string `json:"user_type,omitempty"`
Origin Origin `json:"origin"`
}
Principal is who a decision is about.
type Reason ¶
type Reason string
Reason is a refusal's stable code: the `reason` of its authz.denied row and of its Decision. The set is the registry below and nothing else.
Append-only once 0.8.0 is tagged (testdata/wire.golden): a SIEM rule is written against these strings, so from then on a removal or a rename is a major version.
const ( ReasonAdminSurface Reason = "admin_surface" ReasonSecurityAdminSurface Reason = "security_admin_surface" ReasonNotOwner Reason = "not_owner" ReasonAttachTicketForeignRun Reason = "attach_ticket_foreign_run" ReasonBYOIUser Reason = "byoi_user" ReasonCapabilityAgent Reason = "capability_agent" ReasonCapabilityEgressHost Reason = "capability_egress_host" ReasonCapabilityFeature Reason = "capability_feature" ReasonCapabilityPolicy Reason = "capability_policy" ReasonCapabilitySecret Reason = "capability_secret" ReasonCapabilityWorkspace Reason = "capability_workspace" ReasonCapabilityWorkspaceProvider Reason = "capability_workspace_provider" ReasonCapabilityModelProvider Reason = "capability_model_provider" ReasonGovernanceProfile Reason = "governance_profile" ReasonGrantPairingNotEligible Reason = "grant_pairing_not_eligible" ReasonGroupsSnapshotStale Reason = "groups_snapshot_stale" ReasonHarnessLoginMechanismPrincipal Reason = "harness_login_mechanism_principal" ReasonHarnessLoginNotPerUser Reason = "harness_login_not_per_user" ReasonRunKept Reason = "run_kept" ReasonRunNotFound Reason = "run_not_found" ReasonRunTerminal Reason = "run_terminal" ReasonSecondHumanRequired Reason = "second_human_required" ReasonRunQuota Reason = "run_quota" ReasonUserTypeUnknown Reason = "user_type_unknown" ReasonUserViewTypeDeleted Reason = "user_view_type_deleted" // it — none by that name, off, not serving the agent, none chosen among // several, no usable credential of the caller's for it, or a policy grant // that would set a model credential beside it (#987). ReasonModelProviderUnavailable Reason = "model_provider_unavailable" // ReasonAdminView: an admin in the user view launched a run after the type // the view looks through was deleted. Not audited on its own — the cause // row is ReasonUserViewTypeDeleted, which the launch response answered. ReasonAdminView Reason = "admin_view" // ReasonDelegationScope: a portal's delegated token asked for a route // outside the delegation allow-list (#1142). ReasonDelegationScope Reason = "delegation_scope" )
type Refusal ¶
type Refusal struct {
Effect Effect
// Audit: the refusal writes an authz.denied row. False only for a caller
// who IS authorized and is at a limit — a row per quota hit would make a
// busy user look like an attacker.
Audit bool
// Sentence is the reason's own body, used when the door supplies none;
// set only where every door refusing with the reason says the same thing.
Sentence string
}
Refusal is one reason's registry row.