Skip to content

Conversation

@ehsandeep
Copy link
Member

@ehsandeep ehsandeep commented Oct 13, 2025

  • Support service account impersonation with configurable token lifetime
  • Add authentication via ADC, static keys, or separate source credentials
  • Include comprehensive documentation and examples
  • Maintain full backward compatibility with existing configurations

Closes #707

Summary by CodeRabbit

  • New Features

    • Support for GCP short-lived credentials with configurable token lifetimes and multiple authentication flows (developer, CI/CD, GKE, migration).
  • Documentation

    • Expanded GCP provider guide with authentication modes, required roles, examples, org-level discovery.
    • Added dedicated GCP short-lived credentials guide with configs, examples, troubleshooting, and migration advice.
  • Tests

    • Unit tests for duration parsing, token lifetime validation, and config validation.
  • Chores

    • .gitignore updated to track cloudlist and ignore test results and sensitive credential files.

- Support service account impersonation with configurable token lifetime
- Add authentication via ADC, static keys, or separate source credentials
- Include comprehensive documentation and examples
- Maintain full backward compatibility with existing configurations
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds GCP short-lived credential support via the IAM Service Account Credentials API, configurable token lifetime and source credential options, documentation and .gitignore updates, unit tests, and provider integration wiring to use short-lived or standard token sources.

Changes

Cohort / File(s) Summary
Ignore rules
.gitignore
Stop ignoring cloudlist (-cloudlist+cloudlist); add ignore patterns for \.claude/settings.local.json, TEST_RESULTS.md, test-*.yaml, *-sa.json, and *.key.json.
Docs: GCP auth & setup
PROVIDERS.md, docs/GCP_SHORT_LIVED_CREDENTIALS.md
Add Authentication Modes section describing Traditional Static Credentials and Short‑lived Credentials; document config fields (use_short_lived_credentials, service_account_email, source_credentials, token_lifetime, gcp_service_account_key), examples (developer, CI/CD, GKE, migration), required IAM roles/APIs, org-level Asset API notes, troubleshooting, and references.
Auth: short-lived tokens
pkg/providers/gcp/auth.go
Rename auth plugin constant to gcp-cloudlist; add shortLivedTokenSource (implements oauth2.TokenSource), parseDuration, validateShortLivedConfig; add registerWithOptions(ctx, serviceAccountKey, useShortLived, targetServiceAccount, sourceCredentialsPath, tokenLifetime) (option.ClientOption, error) to build either short‑lived or standard token sources, pre‑validate token generation, and improve error handling.
Auth tests
pkg/providers/gcp/auth_test.go
New tests for parseDuration, token lifetime validation, validateShortLivedConfig, and token lifetime defaults using table-driven tests and testify/assert.
Provider integration
pkg/providers/gcp/gcp.go
Read use_short_lived_credentials, service_account_email, source_credentials, token_lifetime from options; call registerWithOptions when short‑lived is enabled and propagate resulting TokenSource/ClientOption to GCP client creation for both individual and organization providers; add option import and validation logic.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as CLI User
  participant CL as cloudlist (GCP provider)
  participant Auth as registerWithOptions
  participant IAM as GCP IAM Credentials API
  participant GCP as GCP Services

  User->>CL: Run discovery with GCP options
  CL->>Auth: Request credential setup (use_short_lived? yes/no)
  alt use_short_lived = true
    Auth->>IAM: generateAccessToken(target SA, lifetime)
    IAM-->>Auth: access token + expiry
    Auth-->>CL: TokenSource (short-lived)
  else
    Auth-->>CL: Standard credential TokenSource / ClientOption
  end
  loop discovery
    CL->>GCP: API call with bearer token
    alt token expired
      CL->>Auth: refresh token
      Auth->>IAM: generateAccessToken(...)
      IAM-->>Auth: new token
      Auth-->>CL: Token
    end
  end
  CL-->>User: Discovered resources
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A hop, a skip, a token anew—
I mint short lives in clouds of blue.
No keys to hide, no rusty ring,
I trade old secrets for a fleeting spring.
Fresh tokens bloom, then softly go—🐇🔐

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The inclusion of unrelated .gitignore modifications such as new ignore patterns for test and credential files falls outside the objectives of adding GCP short-lived credentials and is not referenced in the linked issue requirements. Please separate the .gitignore updates into a distinct housekeeping pull request or document their necessity in this PR description to keep the scope focused on GCP short-lived credentials support.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change by indicating the addition of GCP short-lived credentials support, matching the core functionality introduced in the pull request.
Linked Issues Check ✅ Passed The changes implement all requirements from issue #707 by supporting multiple source credential types including ADC, static keys, and workload identity, providing configurable token lifetimes with validation, enabling service account impersonation, adding in-memory token refresh support, preserving backward compatibility, delivering clear error messages for permission issues, and including comprehensive documentation and migration examples.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-gcp-short-lived-credentials

Comment @coderabbitai help to get the list of available commands and usage tips.

@ehsandeep ehsandeep self-assigned this Oct 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (17)
.gitignore (1)

6-13: Clarify intent of ignoring cloudlist and tighten secret patterns

  • The line "cloudlist" will ignore any top-level file/dir named cloudlist (often the built binary). If the intent is to ignore only the binary at repo root, prefer anchoring: "/cloudlist".
  • Consider adding patterns for other common GCP key names to avoid accidental commits, e.g., "application_default_credentials.json" and "*-adc.json".
- cloudlist
+ /cloudlist
+ application_default_credentials.json
+ *-adc.json
pkg/providers/gcp/auth_test.go (1)

80-135: Test name vs. behavior mismatch; consider renaming or exercising actual validation

This test is named for ValidateLifetime but only checks parsed duration range. Either:

  • rename to reflect behavior (e.g., TestTokenLifetimeRange), or
  • add a small validation helper in prod code (e.g., validateTokenLifetime(string) error) and invoke it here.
docs/GCP_SHORT_LIVED_CREDENTIALS.md (3)

60-85: CI example: add explicit note that source_credentials is a filesystem path

Small clarity tweak: explicitly state source_credentials expects a path to a JSON key file readable by the process; ADC will be used if omitted.


167-176: Parameter table is clear; consider noting accepted formats next to token_lifetime

Add “Supports seconds and Go duration (e.g., 3600s, 1h, 1h30m)” directly in the Description to reduce back-and-forth.


193-205: Troubleshooting impersonation: include serviceAccount member example for CI

Add explicit example member for service accounts: serviceAccount:MINIMAL_SA@PROJECT.iam.gserviceaccount.com, to mirror the user:… example.

PROVIDERS.md (4)

50-64: Nice addition explaining modes; consider heading levels instead of bold to satisfy markdownlint

Convert bold section titles to proper headings (e.g., “#### Traditional Authentication”, “#### Short‑lived Credentials”) to address MD036.

-**A. Traditional Authentication (Static Credentials)**
+#### A. Traditional Authentication (Static Credentials)
...
-**B. Short-lived Credentials (Recommended for Enhanced Security)**
+#### B. Short-lived Credentials (Recommended for Enhanced Security)

Based on static analysis hints


68-133: Options 1–5: same heading nit and minor consistency

  • Use heading syntax for “Option N” lines (MD036).
  • Keep parameter names consistent with code: service_account_email, source_credentials, token_lifetime (already correct).

Based on static analysis hints


150-155: Parameter doc is clear; add explicit range/format to token_lifetime here too

Mirror the range (1s–43200s) and format info inline.


208-214: Convert bare URLs in “References” to markdown links (MD034)

Replace bare links with text to satisfy markdownlint.

Based on static analysis hints

pkg/providers/gcp/gcp.go (5)

231-253: Short‑lived config parsing duplicated in org/individual paths; centralize and pre‑validate

  • Factor parsing/validation of use_short_lived_credentials, service_account_email, source_credentials, token_lifetime into a helper to avoid duplication and drift.
  • Optionally pre‑validate token_lifetime format here to fail fast before calling registerWithOptions.

254-269: Prefer context with timeout for token generation

registerWithOptions likely calls IAM Credentials API. Wrap with context.WithTimeout to avoid indefinite hangs.

- creds, err = registerWithOptions(
-   context.Background(),
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+ creds, err = registerWithOptions(
-   context.Background(),
+   ctx,

326-340: Project listing: warn on pagination/list errors

You wrap creation error, but if Pages returns an error, you propagate it; good. Consider emitting a warning before returning to aid diagnosis.


532-569: Duplicate short‑lived parsing in org provider—apply the same helper

Same recommendation as individual provider to reduce duplication and keep validation consistent.


555-569: Add timeout to org provider registerWithOptions call too

Same context.WithTimeout recommendation as above.

pkg/providers/gcp/auth.go (3)

80-94: Prefer structured googleapi error handling; also fix permission name

Use googleapi.Error instead of string contains, and correct permission to iam.serviceAccounts.getAccessToken.

+   // imports:
+   // "errors"
+   // "google.golang.org/api/googleapi"
@@
- if err != nil {
-   // Provide helpful error messages for common issues
-   errMsg := err.Error()
-   if strings.Contains(errMsg, "403") {
-     return nil, errkit.Wrap(err, "permission denied: ensure source credentials have 'roles/iam.serviceAccountTokenCreator' or 'iam.serviceAccounts.generateAccessToken' permission on target service account")
-   }
-   if strings.Contains(errMsg, "404") {
-     return nil, errkit.Wrap(err, "service account not found: verify the service_account_email is correct")
-   }
-   if strings.Contains(errMsg, "PERMISSION_DENIED") || strings.Contains(errMsg, "IAM_PERMISSION_DENIED") {
-     return nil, errkit.Wrap(err, "IAM Service Account Credentials API may not be enabled or accessible")
-   }
-   return nil, errkit.Wrap(err, "failed to generate access token")
- }
+ if err != nil {
+   var gerr *googleapi.Error
+   if errors.As(err, &gerr) {
+     switch gerr.Code {
+     case 403:
+       return nil, errkit.Wrap(err, "permission denied: ensure source credentials have 'roles/iam.serviceAccountTokenCreator' (permission 'iam.serviceAccounts.getAccessToken') on the target service account")
+     case 404:
+       return nil, errkit.Wrap(err, "service account not found: verify the service_account_email is correct")
+     }
+   }
+   // Fallback on text signals for non-HTTP code cases
+   if strings.Contains(err.Error(), "PERMISSION_DENIED") || strings.Contains(err.Error(), "IAM_PERMISSION_DENIED") {
+     return nil, errkit.Wrap(err, "IAM Service Account Credentials API may not be enabled or accessible")
+   }
+   return nil, errkit.Wrap(err, "failed to generate access token")
+ }

Add imports at the top:

 import (
   "context"
   "fmt"
   "net/http"
+  "errors"
   "os"
   "strconv"
   "strings"
   "time"
@@
   "golang.org/x/oauth2/google"
   "google.golang.org/api/iamcredentials/v1"
+  "google.golang.org/api/googleapi"
   "google.golang.org/api/option"
   "k8s.io/client-go/rest"
 )

43-49: Parse lifetime once at construction to avoid repeated parsing and reduce runtime errors

Store a parsed time.Duration in the token source. This also surfaces bad input earlier.

 type shortLivedTokenSource struct {
   ctx                  context.Context
   sourceCredentials    *google.Credentials
   targetServiceAccount string
-  lifetime             string
+  lifetimeDur          time.Duration
 }
@@
- // Parse lifetime duration
- lifetimeDuration, err := parseDuration(s.lifetime)
- if err != nil {
-   return nil, errkit.Wrap(err, "invalid token lifetime")
- }
+ // lifetime already parsed at construction as s.lifetimeDur
@@
 req := &iamcredentials.GenerateAccessTokenRequest{
   Scope:    []string{scope},
-  Lifetime: fmt.Sprintf("%ds", int(lifetimeDuration.Seconds())),
+  Lifetime: fmt.Sprintf("%ds", int(s.lifetimeDur.Seconds())),
 }
@@
- gologger.Debug().Msgf("Generating short-lived token for service account: %s (lifetime: %s)", s.targetServiceAccount, s.lifetime)
+ gologger.Debug().Msgf("Generating short-lived token for service account: %s (lifetime: %s)", s.targetServiceAccount, s.lifetimeDur)

And initialize it in registerWithOptions:

- shortLivedSource := &shortLivedTokenSource{
-   ctx:                  ctx,
-   sourceCredentials:    sourceCreds,
-   targetServiceAccount: targetServiceAccount,
-   lifetime:             tokenLifetime,
- }
+ lifetimeDur, err := parseDuration(tokenLifetime)
+ if err != nil {
+   return nil, errkit.Wrap(err, "invalid token lifetime")
+ }
+ shortLivedSource := &shortLivedTokenSource{
+   ctx:                  ctx,
+   sourceCredentials:    sourceCreds,
+   targetServiceAccount: targetServiceAccount,
+   lifetimeDur:          lifetimeDur,
+ }

Also applies to: 53-64, 184-191, 77-77, 74-75


184-201: Optional: use impersonate package to simplify IAM token minting

google.golang.org/api/impersonate provides a first‑party TokenSource with built‑in caching and bounds checking. It reduces maintenance and uses the IAM Credentials API under the hood.

Example:

import "google.golang.org/api/impersonate"

ts, err := impersonate.CredentialsTokenSource(
  ctx,
  impersonate.CredentialsConfig{
    TargetPrincipal: targetServiceAccount,
    Scopes:          []string{scope},
    // Lifetime defaults to 1h; optional: Lifetime: time.Minute * 55,
  },
  option.WithCredentials(sourceCreds),
)
if err != nil {
  return nil, errkit.Wrap(err, "create impersonated token source")
}
finalTokenSource = oauth2.ReuseTokenSource(nil, ts)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e4fc52 and f8a3776.

⛔ Files ignored due to path filters (1)
  • examples/gcp-short-lived-credentials.yaml is excluded by !**/*.yaml
📒 Files selected for processing (6)
  • .gitignore (1 hunks)
  • PROVIDERS.md (4 hunks)
  • docs/GCP_SHORT_LIVED_CREDENTIALS.md (1 hunks)
  • pkg/providers/gcp/auth.go (2 hunks)
  • pkg/providers/gcp/auth_test.go (1 hunks)
  • pkg/providers/gcp/gcp.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/providers/gcp/auth.go (1)
pkg/providers/gcp/gcp.go (1)
  • New (184-202)
pkg/providers/gcp/gcp.go (2)
pkg/providers/k8s/kubernetes.go (1)
  • New (33-89)
pkg/providers/aws/aws.go (1)
  • New (125-214)
🪛 markdownlint-cli2 (0.18.1)
PROVIDERS.md

54-54: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


58-58: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


68-68: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


91-91: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


102-102: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


113-113: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


123-123: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


209-209: Bare URL used

(MD034, no-bare-urls)


210-210: Bare URL used

(MD034, no-bare-urls)


211-211: Bare URL used

(MD034, no-bare-urls)


212-212: Bare URL used

(MD034, no-bare-urls)


213-213: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: release-test
  • GitHub Check: Analyze (go)
  • GitHub Check: Test Builds (1.22.x, ubuntu-latest)
  • GitHub Check: Test Builds (1.22.x, windows-latest)
  • GitHub Check: Test Builds (1.22.x, macOS-latest)
  • GitHub Check: Lint Test
🔇 Additional comments (8)
pkg/providers/gcp/auth_test.go (2)

10-78: Good coverage for duration parsing formats and edge cases


179-185: Default lifetime assertion looks good

pkg/providers/gcp/gcp.go (5)

21-21: Import of option is appropriate for credential wiring


580-625: Extended metadata wiring looks good; errors are downgraded to warnings

LGTM; good resilience by continuing when specific APIs aren’t permitted.


783-830: Provider.Verify logic is pragmatic and safe

Checks minimal API availability across services; returns useful errors. LGTM.


832-859: OrgProvider.Verify via Asset API is sound

Single-page probe with informative error context. LGTM.


184-202: registerWithOptions correctly falls back to ADC when no service account key is provided

pkg/providers/gcp/auth.go (1)

112-129: Duration parser is clear and robust

Covers both “Ns” and Go duration formats. LGTM.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
pkg/providers/gcp/auth.go (1)

232-238: Handle "already registered" errors gracefully.

RegisterAuthProviderPlugin returns an error if the plugin is already registered. If registerWithOptions is called multiple times (e.g., when creating multiple GCP provider instances), subsequent calls will fail. The previous review suggested checking for "already registered" errors, but this wasn't fully implemented.

Apply this diff to handle duplicate registration gracefully:

-	err = rest.RegisterAuthProviderPlugin(googleAuthPlugin,
+	err := rest.RegisterAuthProviderPlugin(googleAuthPlugin,
 		func(clusterAddress string, config map[string]string, persister rest.AuthProviderConfigPersister) (rest.AuthProvider, error) {
 			return &googleAuthProvider{tokenSource: finalTokenSource}, nil
 		})
-	if err != nil {
-		return nil, errkit.Wrap(err, "failed to register GKE auth provider plugin")
-	}
+	if err != nil && !strings.Contains(strings.ToLower(err.Error()), "already registered") {
+		return nil, errkit.Wrap(err, "failed to register GKE auth provider plugin")
+	}
🧹 Nitpick comments (1)
pkg/providers/gcp/auth.go (1)

81-94: Error string matching is fragile but acceptable.

The error handling checks for substring patterns like "403", "404", "PERMISSION_DENIED" to provide helpful user-facing messages. While this approach is common for external APIs without structured error types, it can break if GCP changes their error message format. Consider using type assertions or checking for specific error types if the GCP SDK provides them. However, the current implementation provides good user experience with actionable error messages.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af7fff3 and dc82a5e.

📒 Files selected for processing (2)
  • pkg/providers/gcp/auth.go (2 hunks)
  • pkg/providers/gcp/auth_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/providers/gcp/auth_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/providers/gcp/auth.go (1)
pkg/providers/gcp/gcp.go (1)
  • New (184-202)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Builds (1.22.x, windows-latest)
  • GitHub Check: Test Builds (1.22.x, ubuntu-latest)
  • GitHub Check: Test Builds (1.22.x, macOS-latest)
  • GitHub Check: Lint Test
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
pkg/providers/gcp/auth.go (1)

209-214: Verify context lifetime for token refresh scenarios.

The context passed to registerWithOptions is stored in shortLivedTokenSource and reused for all token refresh operations. If this context is canceled (e.g., a short-lived request context), subsequent token refreshes will fail, even during long-running operations.

Ensure the context passed to this function has an appropriate lifetime that covers the intended duration of token usage. For long-running services, consider using context.Background() or a context with a lifetime matching the service's operation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pkg/providers/gcp/auth.go (2)

82-94: Consider more robust error detection for IAM API failures.

The current error handling uses case-sensitive string matching (strings.Contains) to detect specific error conditions. This approach is fragile and may miss error variations or changes in API error messages.

Consider these improvements:

  1. Check for HTTP status codes if available from the API error:
if apiErr, ok := err.(*googleapi.Error); ok {
  switch apiErr.Code {
  case 403:
    return nil, errkit.Wrap(err, "permission denied: ensure source credentials have 'roles/iam.serviceAccountTokenCreator' or 'iam.serviceAccounts.generateAccessToken' permission on target service account")
  case 404:
    return nil, errkit.Wrap(err, "service account not found: verify the service_account_email is correct")
  }
}
  1. If using string matching, use case-insensitive checks:
-if strings.Contains(errMsg, "403") {
+if strings.Contains(strings.ToLower(errMsg), "403") || strings.Contains(strings.ToLower(errMsg), "permission denied") {

This makes error detection more reliable and maintainable.


154-156: Consider extracting the default token lifetime as a constant.

The default value "3600s" is hardcoded in the function signature. For better maintainability and clarity, consider defining it as a package-level constant.

Apply this diff:

+const (
+	googleAuthPlugin = "gcp-cloudlist"
+	scope            = "https://www.googleapis.com/auth/cloud-platform"
+	defaultTokenLifetime = "3600s"
+)
 func register(ctx context.Context, serviceAccountKey []byte) (option.ClientOption, error) {
-	return registerWithOptions(ctx, serviceAccountKey, false, "", "", "3600s")
+	return registerWithOptions(ctx, serviceAccountKey, false, "", "", defaultTokenLifetime)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc82a5e and c8281dc.

📒 Files selected for processing (1)
  • pkg/providers/gcp/auth.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/providers/gcp/auth.go (1)
pkg/providers/gcp/gcp.go (1)
  • New (184-202)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Lint Test
  • GitHub Check: Test Builds (1.22.x, ubuntu-latest)
  • GitHub Check: Test Builds (1.22.x, windows-latest)
  • GitHub Check: Test Builds (1.22.x, macOS-latest)
  • GitHub Check: release-test
  • GitHub Check: Analyze (go)
🔇 Additional comments (7)
pkg/providers/gcp/auth.go (7)

1-24: LGTM! Import additions and plugin name fix look good.

The new imports support the short-lived credentials functionality, and the plugin name change to gcp-cloudlist resolves the previous collision with client-go's built-in GCP auth provider.


112-129: LGTM! Duration parsing implementation is clean and flexible.

The function correctly handles both seconds format ("3600s") and standard Go duration format ("1h", "30m"), with clear error messages.


131-152: LGTM! Configuration validation is thorough.

The validation logic correctly enforces requirements for short-lived credentials and provides clear error messages when configuration is invalid.


158-201: LGTM! Credential source selection logic is well-structured.

The three-tier credential source precedence (explicit path → service account key → ADC) is implemented correctly with appropriate logging and error handling for each path. The fallback to ADC aligns with GCP best practices.


203-229: LGTM! Short-lived token source configuration is robust.

The implementation correctly:

  • Wraps the short-lived source with ReuseTokenSource for automatic caching/refresh
  • Tests token generation immediately to catch errors early
  • Provides clear logging for both configuration modes

231-243: LGTM! Plugin registration error handling is correct.

The error handling now properly checks for the "was registered twice" error message and wraps other errors appropriately. The debug logging for duplicate registrations is helpful for troubleshooting.


245-252: No changes required – both branches return option.ClientOption
All GCP client constructors accept option.ClientOption, so both WithTokenSource and WithCredentials work as expected.

Copy link
Member

@tarunKoyalwar tarunKoyalwar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm !

@ehsandeep ehsandeep merged commit 1f16c70 into dev Oct 14, 2025
7 checks passed
@ehsandeep ehsandeep deleted the feat-gcp-short-lived-credentials branch October 14, 2025 18:33
visnetodev pushed a commit to visnetotest/cloudlist that referenced this pull request Dec 7, 2025
* feat: add GCP short-lived credentials support

- Support service account impersonation with configurable token lifetime
- Add authentication via ADC, static keys, or separate source credentials
- Include comprehensive documentation and examples
- Maintain full backward compatibility with existing configurations

* Limit GCP short-lived token lifetime to 1 hour max

* Add validation for short-lived GCP credentials config

* Update auth.go
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.

Add Support for GCP Short-lived Credentials via Service Account Credentials API

3 participants