Label-scoped access policies that take precedence over resource rules (incident kill switch) #3979
strausmann
started this conversation in
Feature Requests
Replies: 1 comment
|
One addition after thinking through the lifecycle with automatically updated labels (see my comment in #3980): If labels are refreshed by a scanner, a resource can drop out of a policy on its own — for example when a patched image no longer has the CVE label. Whether that should automatically lift the restriction is a security decision, because a wrong or missing label would silently reopen the resource. I'd propose a setting per policy:
Default: sticky. In an incident, I'd rather release patched apps one by one than have a scanner hiccup reopen something. AI disclosure: drafted with the help of an AI assistant (Claude Code); reviewed and edited by me. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
Allow an organization admin to bind an access policy to a label selector instead of to individual resources. All resources whose effective labels match the selector are restricted immediately, with precedence over their own rules, and the restriction is never touched by blueprint sync. Effects: block (
403), maintenance page with a policy-defined message and ETA, or put Pangolin SSO in front for selected users/roles.Motivation
This idea came directly out of PHP2Shell (CVE-2026-109618 / CVE-2026-109619), the PHP remote-code-execution vulnerabilities published in October 2026. I run several PHP applications behind Pangolin, all of them managed through Docker-label blueprints. When the advisory came out, I wanted to take every affected application off the public internet immediately — without stopping the containers and without editing and redeploying each stack while waiting for patched images.
I couldn't do that with Pangolin today:
enabled, the next sync sets it back totruewithin seconds (server/lib/blueprints/publicResources.ts).policyin the blueprint, sync writesresourcePolicyId: null.platform::php".So in the end I had to stop the services themselves or touch every affected stack — slow, error-prone, and exactly when time mattered most. Several open requests point the same way: #1563 (global rules), #2317 (org-level access control), #298 (disable a resource on demand).
Proposed Solution
A label policy binding at organization level:
Name and reason (e.g. "CVE-XXXX-YYYY") — shown in the audit log and optionally on the block/maintenance page.
Selector on effective labels (see Scoped labels (`scope::value`) that survive blueprint sync, plus label inheritance from sites #3978), conditions combined with AND. Each condition has an origin (
resource:,site:or*:for either), a scope, and a value matcher:resource:platform ∈ {php, perl}resource:platform_version = 8.4.*8.4.9 < 8.4.27)resource:platform_version >= 8.4.0 and < 8.4.27resource:platformlegacy*:location = dc-aValues are stored as text, not as references to label rows. If no resource carries a value anymore, the selector keeps it (the UI marks it as "manually entered, currently no match"). An emergency block must not dissolve silently while a container is being rebuilt and briefly has no labels.
Rules: same format and engine as today's resource rules (
ACCEPT/DROP/PASSbyCIDR,IP,COUNTRY,COUNTRY_IS_NOT,ASN,REGION,PATH,METHOD, with priority), plus a default action.Effect when a request is not let through:
403.ACCEPTrule (e.g. your VPN's CIDR) can exempt them.Enabled toggle and optional expiry (auto-disable or reminder).
Evaluation order: matching label policies are evaluated before the resource's own rules, by priority.
DROPtriggers the effect regardless of the resource's rules, auth and SSO settings.PASShands over to the resource's own rules.ACCEPTonly skips this layer — the resource's own auth still applies. A label policy can only restrict access, never weaken a resource's protection. If several policies with different effects match, the strictest wins (block > maintenance > require SSO).Not part of blueprints: label policies are created and changed only via UI/API. Blueprint sync never creates, changes or removes them. The blueprint only provides labels, which the selector uses. That keeps blueprints authoritative for what they define (compatible with Visual indicator and protection of resources created by docker labels #1860) and puts the incident layer on top.
Visibility: a live preview "affects N resources" (recomputed, since labels change), and a banner on each affected resource "restricted by policy X (effect)".
Scope: public resources. Private/site resources are out of scope for a first step.
Performance. Every request to a public HTTP resource already goes through Badger, which calls
POST /badger/verify-session;verifySession.tsalready runscheckRules()per request, backed bylocalCache(resource and rules for 5 s, country/ASN for 5 min). I'd add the label-policy step in the same place, beforecheckRules(), using the same cache pattern (labelPolicies:<resourceId>):ipAllowList), not country, ASN, maintenance page or SSO; Badger calls Pangolin on every request anyway, so there's nothing to gain; and two places evaluating rules would make the feature harder to reason about and test.Alternatives Considered
Additional Context
Questions for the maintainers:
Offer to contribute: I'm willing to implement this myself once the direction, shape and tier are agreed — as a series of small PRs against
dev(data model + API, request-path evaluation, UI, effects), starting with the label-origin change from #3978. If it helps, I'm glad to coordinate in a Discord chat as well.Depends on / related: #3978 (scoped labels, origin, inheritance), #3980 (auto-detection), #1563, #2317, #3497, #298, #2197, #1860.
AI disclosure: this request was drafted with the help of an AI assistant (Claude Code), based on reading the current
devsource; I reviewed and edited it. Any PR would disclose AI use in the PR template as required.All reactions