Skip to content

Commit b1d99e6

Browse files
authored
feat(auth): support Kubernetes inline credentials (#67)
* test(auth): add tests for prepare_credentials_for_adc() * feat(auth): support inline credentials for ADC * test: add tests to check for info leakage * fix: credential leak via Slack notification
1 parent cbd2e4c commit b1d99e6

File tree

4 files changed

+368
-15
lines changed

4 files changed

+368
-15
lines changed

src/models/rewards_eligibility_oracle.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ def main(run_date_override: date = None):
3333
"""
3434
Main entry point for the Rewards Eligibility Oracle.
3535
This function:
36-
1. Sets up Google credentials (if not already set up by scheduler)
37-
2. Fetches and processes indexer eligibility data
38-
3. Submits eligible indexers to the blockchain
39-
4. Sends Slack notifications about the run status
36+
1. Fetches and processes indexer eligibility data
37+
2. Submits eligible indexers to the blockchain
38+
3. Sends Slack notifications about the run status
4039
4140
Args:
4241
run_date_override: If provided, use this date for the run instead of today.

src/models/scheduler.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ def initialize(self):
159159
try:
160160
validate_all_required_env_vars()
161161

162+
# Prepare credentials using inline JSON or file paths
163+
credential_manager.prepare_credentials_for_adc()
164+
162165
# Validate credentials early (Fail Fast)
163166
try:
164167
credential_manager.get_google_credentials()

src/utils/configuration.py

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,10 @@ def get_google_credentials(self) -> google.auth.credentials.Credentials:
367367
return credentials
368368

369369
except Exception as e:
370-
error_msg = f"Failed to load Google Cloud credentials: {e}"
371-
logger.error(error_msg)
370+
error_msg = (
371+
"Failed to load Google Cloud credentials. Check GOOGLE_APPLICATION_CREDENTIALS configuration."
372+
)
373+
logger.error(f"{error_msg} Error details: {type(e).__name__}")
372374
raise ValueError(error_msg)
373375

374376

@@ -407,8 +409,14 @@ def _parse_and_validate_credentials_json(self, creds_env: str) -> dict:
407409

408410
return creds_data
409411

410-
except Exception as e:
411-
raise ValueError(f"Invalid credentials JSON: {e}") from e
412+
except json.JSONDecodeError:
413+
raise ValueError("Invalid credentials JSON format. Expected valid JSON string.")
414+
except ValueError:
415+
# Re-raise our own validation errors with their specific messages
416+
raise
417+
except Exception:
418+
# Catch-all for unexpected errors - don't leak credential data
419+
raise ValueError("Invalid or incomplete credentials. Check credentials structure.")
412420

413421

414422
def _setup_user_credentials_from_dict(self, creds_data: dict) -> None:
@@ -444,8 +452,70 @@ def _setup_service_account_credentials_from_dict(self, creds_data: dict) -> None
444452
logger.info("Successfully loaded service account credentials from environment variable")
445453

446454
# If the credentials creation fails, raise an error
447-
except Exception as e:
448-
raise ValueError(f"Invalid service account credentials: {e}") from e
455+
except Exception:
456+
raise ValueError(
457+
"Invalid service account credentials. Check private_key, client_email, and project_id fields."
458+
)
459+
460+
461+
def prepare_credentials_for_adc(self) -> None:
462+
"""
463+
Prepare Google credentials for Application Default Credentials (ADC).
464+
465+
Supports both inline JSON and file paths:
466+
- Inline JSON: Writes temp file and updates env var
467+
- File path: Validates existence, logs warning if not found
468+
469+
This enables google.auth.default() to work with both credential sources while
470+
maintaining official API usage.
471+
472+
Raises:
473+
ValueError: If inline JSON is invalid or incomplete
474+
"""
475+
creds_env = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
476+
477+
# If not set, log warning and return
478+
if not creds_env:
479+
logger.warning("GOOGLE_APPLICATION_CREDENTIALS not set. Will fall back to ADC.")
480+
return
481+
482+
# Inline JSON pattern
483+
if creds_env.strip().startswith("{"):
484+
creds_data = None
485+
try:
486+
# Validate JSON structure
487+
creds_data = self._parse_and_validate_credentials_json(creds_env)
488+
489+
# Write to temp file
490+
temp_path = Path("/tmp/gcp-credentials.json")
491+
with open(temp_path, "w", encoding="utf-8") as f:
492+
json.dump(creds_data, f)
493+
494+
# Set restrictive permissions
495+
temp_path.chmod(0o600)
496+
497+
# Update env var
498+
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = str(temp_path)
499+
500+
logger.info("Prepared inline JSON credentials for ADC")
501+
502+
except ValueError:
503+
# Re-raise our own validation errors
504+
raise
505+
506+
except Exception:
507+
# Catch unexpected errors without leaking credential data
508+
raise ValueError("Failed to prepare inline credentials. Check JSON format and structure.")
509+
510+
finally:
511+
# Clear data from memory
512+
if creds_data:
513+
creds_data.clear()
514+
515+
# File path pattern
516+
elif not Path(creds_env).exists():
517+
logger.warning(f"Credentials file not found: {creds_env}")
518+
logger.warning("Will attempt to use gcloud CLI or other ADC sources")
449519

450520

451521
def setup_google_credentials(self) -> None:
@@ -477,8 +547,12 @@ def setup_google_credentials(self) -> None:
477547
self._setup_service_account_credentials_from_dict(creds_data.copy())
478548

479549
# If the credentials parsing fails, raise an error
480-
except Exception as e:
481-
raise ValueError(f"Error processing inline credentials: {e}") from e
550+
except ValueError:
551+
# Re-raise our own validation errors
552+
raise
553+
except Exception:
554+
# Catch unexpected errors without leaking credential data
555+
raise ValueError("Error processing inline credentials. Check format and required fields.")
482556

483557
# Clear the credentials from memory
484558
finally:

0 commit comments

Comments
 (0)