fix: add authentication for Cloud Run service calls
Cloud Run services are deployed with --no-allow-unauthenticated, requiring an ID token in the Authorization header. - Add _get_cloud_run_id_token() helper using google-auth library - Update whisper_transcribe.py to include Bearer token in Cloud Run calls - Update video_renderer.py to include Bearer token in FFmpeg Cloud Run calls The ID token is fetched using the service account credentials (GOOGLE_APPLICATION_CREDENTIALS) and targets the Cloud Run service URL. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
77dc58b124
commit
7d2366d0f4
2 changed files with 57 additions and 5 deletions
|
|
@ -14,8 +14,11 @@ from pathlib import Path
|
|||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
import google.auth.transport.requests
|
||||
import httpx
|
||||
from google.auth import default
|
||||
from google.cloud import storage
|
||||
from google.oauth2 import id_token
|
||||
|
||||
from ..core.config import settings
|
||||
from ..core.logging import get_logger
|
||||
|
|
@ -24,6 +27,19 @@ from ..schemas.accessible_video import AccessibleVideoMethod, GeminiAccessibleVi
|
|||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def _get_cloud_run_id_token(audience: str) -> str:
|
||||
"""
|
||||
Get an ID token for authenticating to Cloud Run services.
|
||||
|
||||
Uses the service account credentials to generate an ID token
|
||||
that Cloud Run will accept for authentication.
|
||||
"""
|
||||
credentials, _ = default()
|
||||
request = google.auth.transport.requests.Request()
|
||||
token = id_token.fetch_id_token(request, audience)
|
||||
return token
|
||||
|
||||
|
||||
class FFmpegExecutionError(Exception):
|
||||
"""Raised when an FFmpeg/FFprobe command fails."""
|
||||
pass
|
||||
|
|
@ -153,9 +169,13 @@ class VideoRendererService:
|
|||
Probe result with duration and stream info
|
||||
"""
|
||||
client = self._get_http_client()
|
||||
service_url = settings.ffmpeg_service_url.rstrip("/")
|
||||
auth_token = _get_cloud_run_id_token(service_url)
|
||||
|
||||
response = client.post(
|
||||
f"{settings.ffmpeg_service_url}/probe",
|
||||
json={"source_gcs_uri": gcs_uri}
|
||||
f"{service_url}/probe",
|
||||
json={"source_gcs_uri": gcs_uri},
|
||||
headers={"Authorization": f"Bearer {auth_token}"}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
|
@ -178,10 +198,14 @@ class VideoRendererService:
|
|||
Response JSON
|
||||
"""
|
||||
client = self._get_http_client()
|
||||
service_url = settings.ffmpeg_service_url.rstrip("/")
|
||||
auth_token = _get_cloud_run_id_token(service_url)
|
||||
|
||||
try:
|
||||
response = client.post(
|
||||
f"{settings.ffmpeg_service_url}{endpoint}",
|
||||
json=payload
|
||||
f"{service_url}{endpoint}",
|
||||
json=payload,
|
||||
headers={"Authorization": f"Bearer {auth_token}"}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@
|
|||
import os
|
||||
import uuid
|
||||
|
||||
import google.auth.transport.requests
|
||||
import httpx
|
||||
from google.auth import default
|
||||
from google.cloud import storage
|
||||
from google.oauth2 import id_token
|
||||
|
||||
from ..core.config import settings
|
||||
from ..core.logging import get_logger
|
||||
|
|
@ -14,6 +17,25 @@ from . import celery_app
|
|||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def _get_cloud_run_id_token(audience: str) -> str:
|
||||
"""
|
||||
Get an ID token for authenticating to Cloud Run services.
|
||||
|
||||
Uses the service account credentials to generate an ID token
|
||||
that Cloud Run will accept for authentication.
|
||||
"""
|
||||
# Get credentials from the environment (GOOGLE_APPLICATION_CREDENTIALS)
|
||||
credentials, _ = default()
|
||||
|
||||
# Create a request object for token refresh
|
||||
request = google.auth.transport.requests.Request()
|
||||
|
||||
# Fetch an ID token for the target audience (the Cloud Run service URL)
|
||||
token = id_token.fetch_id_token(request, audience)
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def _upload_audio_to_gcs_temp(audio_path: str, job_id: str) -> str:
|
||||
"""Upload local audio file to GCS temporary location and return GCS URI."""
|
||||
# Generate unique temp path
|
||||
|
|
@ -70,11 +92,17 @@ def _transcribe_via_cloud_run(job_id: str, audio_path: str) -> dict:
|
|||
|
||||
logger.info(f"Calling Whisper Cloud Run service: {endpoint}")
|
||||
|
||||
# Get ID token for Cloud Run authentication
|
||||
id_token = _get_cloud_run_id_token(service_url)
|
||||
|
||||
with httpx.Client(timeout=300.0) as client:
|
||||
response = client.post(
|
||||
endpoint,
|
||||
json={"gcs_uri": gcs_uri},
|
||||
headers={"Content-Type": "application/json"}
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {id_token}"
|
||||
}
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue