From 0ab044417eaaf76a25e02d66e36bcba2586f1aba Mon Sep 17 00:00:00 2001 From: chrischristiansen-glitch Date: Wed, 17 Jun 2026 18:39:12 +0200 Subject: [PATCH] fix(opax-mcp): legg til identity token auth i _opax_get/_opax_post mot opax.vauco.no --- opax-mcp/server.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/opax-mcp/server.py b/opax-mcp/server.py index a96a587..10061ba 100644 --- a/opax-mcp/server.py +++ b/opax-mcp/server.py @@ -5,6 +5,8 @@ Auth: Cloud Run IAM (Authorization header) + X-MCP-Secret header for tool-level import os import httpx import base64 +import google.auth +import google.auth.transport.requests from fastapi import FastAPI, HTTPException, Header from pydantic import BaseModel from typing import Optional, Any @@ -27,6 +29,30 @@ def _auth_check(x_mcp_secret: Optional[str]): raise HTTPException(status_code=401, detail="Unauthorized") +def _opax_identity_token() -> str: + """Hent identity token for opax.vauco.no (Cloud Run IAP/IAM).""" + metadata_url = ( + "http://metadata.google.internal/computeMetadata/v1/instance" + f"/service-accounts/default/identity?audience={OPAX_BASE_URL}&format=full" + ) + try: + resp = httpx.get(metadata_url, headers={"Metadata-Flavor": "Google"}, timeout=5) + if resp.status_code == 200 and resp.text.strip(): + return resp.text.strip() + except Exception: + pass + credentials, _ = google.auth.default() + credentials.refresh(google.auth.transport.requests.Request()) + return credentials.token + + +def _opax_headers() -> dict: + return { + "Authorization": f"Bearer {_opax_identity_token()}", + "Content-Type": "application/json", + } + + # --------------------------------------------------------------------------- # Health # --------------------------------------------------------------------------- @@ -70,14 +96,14 @@ async def list_tools(x_mcp_secret: Optional[str] = Header(default=None)): async def _opax_get(path: str) -> Any: async with httpx.AsyncClient(timeout=30) as client: - r = await client.get(f"{OPAX_BASE_URL}{path}") + r = await client.get(f"{OPAX_BASE_URL}{path}", headers=_opax_headers()) r.raise_for_status() return r.json() async def _opax_post(path: str, body: dict) -> Any: async with httpx.AsyncClient(timeout=30) as client: - r = await client.post(f"{OPAX_BASE_URL}{path}", json=body) + r = await client.post(f"{OPAX_BASE_URL}{path}", json=body, headers=_opax_headers()) r.raise_for_status() return r.json() @@ -203,7 +229,7 @@ async def run_emma(p): # Platform tools # --------------------------------------------------------------------------- -async def get_health(p): return await _opax_get("/health") +async def get_health(p): return await _opax_get("/health") async def get_build_status(p): return await _opax_get("/opax/build-status") async def get_state(p): return await _opax_get("/state") async def get_telemetry(p): return await _opax_get("/telemetry/history")