Skip to content

feat(console): let a deployment name extra sandbox entitlements hosts - #1551

Open
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/allow-control-plane-through-proxy
Open

feat(console): let a deployment name extra sandbox entitlements hosts#1551
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/allow-control-plane-through-proxy

Conversation

@0xAlcibiades

@0xAlcibiades 0xAlcibiades commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Closes #1558.

Part of #1486 — the auth half, direction 2 of the three that issue's thread lists.

The bind

upstream_deny_cidrs blocks the cluster service range by design, so sandboxes
cannot reach arbitrary in-cluster services. That also blocks the Console, and it
cannot be relaxed without opening everything else.

Fronting the Console on an address outside the range gets past the network
block, and then 403s. sandbox_entitlements_hosts is:

def self.sandbox_entitlements_hosts
  [ Principal.host_from_url(ENV["CENTAUR_CONSOLE_URL"]) ]
end

One host, from the Console's own env, with no config, admin API or DB row
overriding it. So the injection rule only ever matches the in-cluster address —
the one the sandbox cannot use. Reaching the Console needs a host outside the
range; getting a credential needs the host inside it.
As shipped those are
mutually exclusive, which is why this is not solvable in a deployment's own
values.

Change

CENTAUR_CONSOLE_ENTITLEMENTS_HOSTS (chart:
console.entitlementsHosts) names additional hosts for the same credential.

  • Adds rather than replaces. The in-cluster address keeps working, including
    for the sync path that already uses it.
  • Accepts a URL or a bare host, because the value is in practice copied from
    whatever CENTAUR_CONSOLE_URL is set to, and a URL silently producing a
    non-matching rule is the failure this is meant to remove.
  • Normalized through the existing Principal.normalize_hosts, so matching
    does not hinge on case, whitespace or a trailing dot, and a host that
    duplicates the default collapses.

Unset, nothing changes.

Why this direction

The issue lists three shapes. Exempting the control plane from the forwarded
deny is the narrowest, but the deny is enforced by the proxy binary rather than
by this repo, so it is not a change that can be made here. Exposing
console.extraEnv is the broadest and least targeted. This one is the smallest
change inside centaur that actually unblocks the pair.

It is the auth half only. A deployment still has to front the Console on a
reachable address; this makes that address work instead of 403ing.

Testing

Four new model tests: the default is the console URL alone; a configured host
adds to it rather than replacing it; a URL and a bare host are both accepted;
and values are normalized and de-duplicated.

I could not run them. The console suite needs bundle install and a
prepared database, and this machine has Ruby 2.6 against a Gemfile.lock wanting
bundler 4.0.10, so neither bin/rails test nor bin/rubocop would start. Both
files pass ruby -c, and filter_map/index_with are already used elsewhere
in this app, but the tests themselves rest on CI. Flagging that rather than
implying otherwise.

helm lint passes, the values schema stays valid, and helm template renders
CENTAUR_CONSOLE_ENTITLEMENTS_HOSTS only when the value is set.

sandbox_entitlements_hosts is the Console's own CENTAUR_CONSOLE_URL and
nothing else, so the proxy injects the sandbox entitlements credential for
exactly one host: the in-cluster address.

That is unreachable for a deployment whose sandboxes are denied the cluster
service range -- which the proxy's own upstream_deny_cidrs exists to do, so
sandboxes cannot reach arbitrary in-cluster services. Such a deployment has to
front the Console on another address, and then the request arrives with no
credential and is refused, because no injection rule matches the host it
actually used. Reaching the Console needs a host outside the range; getting a
credential needs the host to be inside it. The two are mutually exclusive as
shipped, and the deny list cannot be relaxed without opening every in-cluster
service to every sandbox.

CENTAUR_CONSOLE_ENTITLEMENTS_HOSTS names additional hosts for the same
credential. It adds to the default rather than replacing it, so the in-cluster
address keeps working for the sync path that already uses it, and it accepts a
URL or a bare host because the value is usually copied from whatever
CENTAUR_CONSOLE_URL is set to. Hosts are normalized and de-duplicated through
the existing helper, so rule matching does not hinge on case or a trailing
dot.
The schema entry landed as a member of the allowedHosts object instead of a
sibling of it, so console.entitlementsHosts -- the value the template actually
reads -- was not what the schema validated, and allowedHosts grew a spurious
array member of its own.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sandbox_entitlements_hosts is hardcoded to CENTAUR_CONSOLE_URL, so no reachable Console host can be entitled

1 participant