Documentation
¶
Overview ¶
Package policy decides whether a live resource query is permitted by the cluster owner's agent configuration.
This is a second gate, independent of Kubernetes RBAC. RBAC answers "may this ServiceAccount read the resource"; this answers "did the cluster owner agree that the Kubexa platform may read it". Both must say yes.
Index ¶
- func MatchesName(name string, patterns []string) bool
- type Decision
- type Policy
- func (p *Policy) AllowsAnyGet(group, version, resource string) bool
- func (p *Policy) AllowsAnyList(group, version, resource string) bool
- func (p *Policy) Decide(ref Ref, verb Verb, namespace, name string) Decision
- func (p *Policy) UnredactedWildcardRuleIDs() []string
- func (p *Policy) WildcardRuleIDs() []string
- type Ref
- type Verb
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MatchesName ¶
MatchesName reports whether an object name satisfies the name patterns a Decision carried out. The executor calls it once per LIST row, because a LIST carries no name at decision time.
It is a package function over patterns rather than a Policy method taking a namespace, and that is the whole point. A method would walk the rule list a second time, and when the namespace it received differed from the one Decide was evaluated against it could select a MORE PERMISSIVE rule than the one that authorized the query -- admitting a row a direct get is denied. Passing the authorizing rule's patterns through the Decision makes one rule selection per query, so there is no second selection to diverge.
Types ¶
type Decision ¶
type Decision struct {
Allowed bool
// RedactSecrets tells the executor whether to strip Secret values.
RedactSecrets bool
// LabelSelector and FieldSelector come from the matching rule and are
// ANDed with whatever the request carried.
LabelSelector string
FieldSelector string
// NamePatterns are the authorizing rule's name patterns. The executor
// filters LIST rows against these via MatchesName, so row filtering uses
// the same rule that permitted the query -- see MatchesName's comment for
// why re-consulting the policy per row would be a data-exposure bug.
NamePatterns []string
// WildcardRule reports that the authorizing rule was a wildcard
// (resources: ["*"]) rather than one naming this resource. It changes
// nothing about what is permitted; it tells the caller that ref.Resource
// was chosen by the requester, not by the owner's config, so anything
// keyed on it must stay bounded. The executor uses it to decide whether
// the resource is safe to use as a Prometheus label -- see metrics.go.
WildcardRule bool
// Reason explains a denial in terms the operator can act on. Empty when
// allowed.
Reason string
}
Decision is the outcome of evaluating one query against the policy.
type Policy ¶
type Policy struct {
// contains filtered or unexported fields
}
Policy is an immutable, compiled rule set. It is built once at startup and never mutated: the agent has no config hot-reload, and a policy that can change at runtime is a policy nobody can reason about.
func Compile ¶
Compile builds a Policy from the agent's root configuration, resolving the inheritance from collect.state described in pkg/config/query.go.
func (*Policy) AllowsAnyGet ¶
AllowsAnyGet reports whether any rule grants get on this resource, in any namespace. See AllowsAnyList for why this is coarser than Decide.
func (*Policy) AllowsAnyList ¶
AllowsAnyList reports whether any rule grants list on this resource, in any namespace. It answers the catalog's question -- "could a query for this type ever succeed" -- and is deliberately coarser than Decide: a per-GVR boolean cannot express a namespace-scoped policy, so Decide stays authoritative at request time.
A wildcard rule changes this coarseness's scale, not its shape: even a namespace-scoped wildcard answers true for every GVR the capability reporter discovers, so the published catalogue reads as "policy allows this" cluster-wide, while Decide still refuses every namespace but the one the rule names.
func (*Policy) Decide ¶
Decide evaluates one query.
Rules are evaluated in configuration order and the FIRST match decides the whole outcome. Because no rule can deny, first-match-wins gives the same allow/deny answer as treating the rules as additive; the ordering exists so that when two rules match, it is unambiguous whose selectors apply.
name is empty for a LIST. A name pattern therefore cannot deny a LIST here; the executor applies it to the returned rows instead.
func (*Policy) UnredactedWildcardRuleIDs ¶ added in v0.6.0
UnredactedWildcardRuleIDs names the wildcard rules whose grant includes readable Secret values -- the exact condition the startup warning in cmd/agent fires on, expressed here so it can be tested.
A wildcard rule covers secrets like everything else; with redact_secrets off, their values leave the cluster. Either half alone is a deliberate choice an operator may well have made, so nothing is reported unless both hold. Redaction on returns nothing: the wildcard is then no wider than the operator asked for.
func (*Policy) WildcardRuleIDs ¶ added in v0.6.0
WildcardRuleIDs names the compiled rules that permit every resource.
It exists for one caller: the startup warning in cmd/agent. A wildcard rule covers secrets like everything else, and paired with unredacted Secret values that is the widest read policy this agent can hold -- not something an operator should first learn from a screen. A disabled policy permits nothing, so it reports nothing.