Skip to content

Commit 093c7b0

Browse files
ravwojdylaclaude
andcommitted
[iris] Make IAP validation optional for initial testing
Add REQUIRE_IAP env var (default: false). When disabled, the proxy forwards all requests without IAP JWT validation and deploys with --allow-unauthenticated. Set REQUIRE_IAP=true and switch to --no-allow-unauthenticated once the LB + IAP stack is configured. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1dbaca4 commit 093c7b0

2 files changed

Lines changed: 18 additions & 22 deletions

File tree

infra/iris-iap-proxy/deploy.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,11 @@ gcloud run deploy "${SERVICE}" \
133133
--region="${REGION}" \
134134
--source=. \
135135
--service-account="${SA_EMAIL}" \
136-
--no-allow-unauthenticated \
136+
--allow-unauthenticated \
137137
--network="${VPC_NETWORK}" \
138138
--subnet="${VPC_SUBNET}" \
139139
--vpc-egress=private-ranges-only \
140-
--set-env-vars="GCP_PROJECT=${PROJECT},CONTROLLER_ZONE=us-central1-a,CONTROLLER_LABEL=iris-marin-controller,CONTROLLER_PORT=10000,PROXY_TOKEN_SECRET=iris-iap-proxy-token" \
140+
--set-env-vars="GCP_PROJECT=${PROJECT},CONTROLLER_ZONE=us-central1-a,CONTROLLER_LABEL=iris-marin-controller,CONTROLLER_PORT=10000,PROXY_TOKEN_SECRET=iris-iap-proxy-token,REQUIRE_IAP=false" \
141141
--timeout=300 \
142142
--memory=512Mi \
143143
--cpu=1 \

infra/iris-iap-proxy/main.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
# Copyright The Marin Authors
22
# SPDX-License-Identifier: Apache-2.0
33

4-
"""GAE reverse proxy for the Iris controller, protected by GCP IAP.
4+
"""Cloud Run reverse proxy for the Iris controller.
55
66
All requests are forwarded to the controller VM discovered via GCE labels.
7-
IAP handles authentication at the Google infrastructure layer; this app
8-
re-validates the IAP JWT for defense-in-depth and extracts the caller's
9-
email for audit logging.
10-
11-
CLI / programmatic callers send:
12-
- ``Authorization: Bearer <iap-oidc-token>`` (consumed by IAP)
13-
- ``X-Iris-Token: <controller-jwt>`` (forwarded as Authorization to controller)
14-
15-
Browser callers authenticate via IAP's OAuth flow; their controller session
16-
cookie (``iris_session``) is forwarded transparently.
7+
When IAP is enabled, the proxy validates the ``X-Goog-IAP-JWT-Assertion``
8+
header for defense-in-depth. When ``REQUIRE_IAP=false`` (the default),
9+
IAP validation is skipped and all requests are forwarded without auth —
10+
useful for initial testing before the LB + IAP stack is configured.
1711
"""
1812

1913
import logging
@@ -27,10 +21,11 @@
2721
from starlette.routing import Route
2822

2923
from discovery import get_controller_url
30-
from iap import IapValidationError, validate_iap_jwt
3124

3225
logger = logging.getLogger(__name__)
3326

27+
REQUIRE_IAP = os.environ.get("REQUIRE_IAP", "false").lower() in ("true", "1", "yes")
28+
3429
_IRIS_TOKEN_HEADER = "x-iris-token"
3530

3631
# Headers that should not be forwarded to the controller.
@@ -126,15 +121,16 @@ def _build_upstream_headers(request: Request, iap_email: str | None) -> dict[str
126121

127122
async def _proxy(request: Request) -> Response:
128123
"""Forward any request to the controller."""
129-
# Validate IAP JWT (defense-in-depth).
130124
iap_email: str | None = None
131-
try:
132-
iap_email = validate_iap_jwt(dict(request.headers))
133-
except IapValidationError as exc:
134-
logger.warning("IAP validation failed: %s", exc)
135-
# In production IAP is enforced at the infra layer, so this should
136-
# not happen. Return 401 rather than silently forwarding.
137-
return JSONResponse({"error": str(exc)}, status_code=401)
125+
126+
if REQUIRE_IAP:
127+
from iap import IapValidationError, validate_iap_jwt
128+
129+
try:
130+
iap_email = validate_iap_jwt(dict(request.headers))
131+
except IapValidationError as exc:
132+
logger.warning("IAP validation failed: %s", exc)
133+
return JSONResponse({"error": str(exc)}, status_code=401)
138134

139135
client = await _get_client()
140136
path = request.url.path

0 commit comments

Comments
 (0)