Skip to content

separate MCP ingress without basic auth to enable its own bearer auth - #81

Merged
vitek-rostislav merged 1 commit into
mainfrom
rv/mcp-http-auth
Jul 20, 2026
Merged

separate MCP ingress without basic auth to enable its own bearer auth#81
vitek-rostislav merged 1 commit into
mainfrom
rv/mcp-http-auth

Conversation

@vitek-rostislav

@vitek-rostislav vitek-rostislav commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Non-production domains (and any production domain in FORCE_HTTP_AUTH_IN_PRODUCTION) are protected by nginx HTTP basic auth on the main ingress. Basic auth and the MCP Bearer token both use the single Authorization header, so while basic auth is enabled the Bearer token never reaches the application and external MCP clients (e.g. Claude Code) can't authenticate.

This publishes the MCP paths through a second eshop-mcp ingress without basic auth, so they stay reachable. These paths remain protected by the application itself (Bearer token on /_mcp) or are public by the OAuth specification:

  • /_mcp and /mcp/oauth (Prefix)
  • /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource (ImplementationSpecific, since ingress-nginx >= 1.12 rejects dots in Exact/Prefix paths by default)

Behavior

  • The MCP ingress is rendered for the first domain only, always on root-level paths (a path-based first domain does not shift them).
  • It is rendered regardless of HTTP basic auth, so the MCP paths are always served separately from the main ingress and the routing does not differ between environments.
  • It can be disabled completely with the new MCP_INGRESS_ENABLED=0 environment variable (default: 1, documented in README).
  • It is rendered from the new kubernetes/ingress/.ingress-mcp.yaml template, which can be overridden in orchestration/kubernetes/ingress/ as usual.
  • The TLS certificate managed by the main ingress is reused via the shared TLS secret (cert-manager annotation dropped) to avoid issuing a duplicate certificate.
  • Server-scoped nginx settings of the main ingress (e.g. the Cloudflare real_ip_header server-snippet) apply to the MCP locations automatically, because ingress-nginx merges all ingresses of the same hostname into a single server block — the MCP ingress intentionally does not repeat them.

Refactoring of deploy/parts/domains.sh

Ingress generation is split into two phases so a second ingress type can be rendered from the same data instead of copying configuration from an already generated ingress:

  1. prepare_domain_data builds a DOMAIN_DATA_<index> associative array per domain (hostname, redirect counterpart, URL path, TLS secret name, HTTP auth flag, whitelist IPs, Cloudflare flag),
  2. render_ingress copies a template, applies the shared data (name, hostname, TLS) and delegates template-specific behavior to a configure function (configure_default_ingress for the main ingress; the MCP template needs none).

Whitelist IP merging was simplified into a single normalization step (whitespace stripped, duplicated/leading/trailing commas collapsed).

Tests & docs

  • New test scenario development-with-cloudflare covering the Cloudflare + MCP combination (the MCP ingress must stay free of basic auth, IP whitelisting and the Cloudflare server-snippet).
  • Expected outputs of the existing scenarios extended with the generated eshop-mcp ingress.
  • Upgrade notes added to UPGRADE.md (v5.1.0 → v5.2.0) — note that the MCP paths are no longer covered by HTTP basic auth on non-production environments.

Comment thread deploy/parts/domains.sh Outdated
@vitek-rostislav
vitek-rostislav merged commit 561a8a3 into main Jul 20, 2026
1 check passed
@vitek-rostislav
vitek-rostislav deleted the rv/mcp-http-auth branch July 20, 2026 13:02
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.

3 participants