From db72447450c39fb3e3dd5b7700de7d600927656d Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Mon, 29 Jun 2026 17:34:46 +1000 Subject: [PATCH 1/3] Make Google Cloud OIDC service account token lifetime configurable Reads Octopus.Action variable {account}.OpenIdConnect.TokenLifetimeSeconds (default 3600, clamped 600-43200) instead of the hardcoded 3600 when building the gcloud create-cred-config call. --- .../GoogleCloudAccountExtensions.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs index d56f64a418..66e166e9cb 100644 --- a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs +++ b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs @@ -244,6 +244,17 @@ bool TryAuthenticateWithOidc(string accountVariable, string jwtToken, string? im return false; } + const int defaultTokenLifetimeSeconds = 3600; + const int minTokenLifetimeSeconds = 600; + const int maxTokenLifetimeSeconds = 43200; + var tokenLifetimeSeconds = variables.GetInt32($"{accountVariable}.OpenIdConnect.TokenLifetimeSeconds") ?? defaultTokenLifetimeSeconds; + if (tokenLifetimeSeconds < minTokenLifetimeSeconds || tokenLifetimeSeconds > maxTokenLifetimeSeconds) + { + var clamped = Math.Max(minTokenLifetimeSeconds, Math.Min(maxTokenLifetimeSeconds, tokenLifetimeSeconds)); + log.Warn($"Google Cloud OIDC token lifetime of {tokenLifetimeSeconds} seconds is outside the allowed range of {minTokenLifetimeSeconds}-{maxTokenLifetimeSeconds} seconds; using {clamped} seconds instead."); + tokenLifetimeSeconds = clamped; + } + File.WriteAllText(jwtFilePath, jwtToken); if (audience.Contains("iam.googleapis.com/")) @@ -256,7 +267,7 @@ bool TryAuthenticateWithOidc(string accountVariable, string jwtToken, string? im "create-cred-config", audience, $"--service-account={impersonationEmails}", - "--service-account-token-lifetime-seconds=3600", + $"--service-account-token-lifetime-seconds={tokenLifetimeSeconds}", "--subject-token-type=urn:ietf:params:oauth:token-type:jwt", "--credential-source-type=text", $"--credential-source-file={jwtFilePath.EnsureDoubleQuoteIfContainsSpaces()}", From eb0a55bcb1713ae15cd4f47937073920f45d84ed Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Mon, 29 Jun 2026 17:45:08 +1000 Subject: [PATCH 2/3] Warn when Google Cloud OIDC token lifetime is not a valid integer --- .../GoogleCloudAccountExtensions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs index 66e166e9cb..a15f9d21c0 100644 --- a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs +++ b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs @@ -247,7 +247,10 @@ bool TryAuthenticateWithOidc(string accountVariable, string jwtToken, string? im const int defaultTokenLifetimeSeconds = 3600; const int minTokenLifetimeSeconds = 600; const int maxTokenLifetimeSeconds = 43200; + var rawTokenLifetime = variables.Get($"{accountVariable}.OpenIdConnect.TokenLifetimeSeconds"); var tokenLifetimeSeconds = variables.GetInt32($"{accountVariable}.OpenIdConnect.TokenLifetimeSeconds") ?? defaultTokenLifetimeSeconds; + if (!string.IsNullOrEmpty(rawTokenLifetime) && !int.TryParse(rawTokenLifetime, out _)) + log.Warn($"Google Cloud OIDC token lifetime value '{rawTokenLifetime}' is not a valid integer; using {defaultTokenLifetimeSeconds} seconds instead."); if (tokenLifetimeSeconds < minTokenLifetimeSeconds || tokenLifetimeSeconds > maxTokenLifetimeSeconds) { var clamped = Math.Max(minTokenLifetimeSeconds, Math.Min(maxTokenLifetimeSeconds, tokenLifetimeSeconds)); From 05ffaef272dc8e6c4cbd29d562c7d124629fdbb9 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Wed, 1 Jul 2026 07:21:15 +1000 Subject: [PATCH 3/3] Remove token lifetime clamp; range is validated server-side on the account --- .../GoogleCloudAccountExtensions.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs index a15f9d21c0..a65106ec78 100644 --- a/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs +++ b/source/Calamari.GoogleCloudAccounts/GoogleCloudAccountExtensions.cs @@ -245,18 +245,7 @@ bool TryAuthenticateWithOidc(string accountVariable, string jwtToken, string? im } const int defaultTokenLifetimeSeconds = 3600; - const int minTokenLifetimeSeconds = 600; - const int maxTokenLifetimeSeconds = 43200; - var rawTokenLifetime = variables.Get($"{accountVariable}.OpenIdConnect.TokenLifetimeSeconds"); var tokenLifetimeSeconds = variables.GetInt32($"{accountVariable}.OpenIdConnect.TokenLifetimeSeconds") ?? defaultTokenLifetimeSeconds; - if (!string.IsNullOrEmpty(rawTokenLifetime) && !int.TryParse(rawTokenLifetime, out _)) - log.Warn($"Google Cloud OIDC token lifetime value '{rawTokenLifetime}' is not a valid integer; using {defaultTokenLifetimeSeconds} seconds instead."); - if (tokenLifetimeSeconds < minTokenLifetimeSeconds || tokenLifetimeSeconds > maxTokenLifetimeSeconds) - { - var clamped = Math.Max(minTokenLifetimeSeconds, Math.Min(maxTokenLifetimeSeconds, tokenLifetimeSeconds)); - log.Warn($"Google Cloud OIDC token lifetime of {tokenLifetimeSeconds} seconds is outside the allowed range of {minTokenLifetimeSeconds}-{maxTokenLifetimeSeconds} seconds; using {clamped} seconds instead."); - tokenLifetimeSeconds = clamped; - } File.WriteAllText(jwtFilePath, jwtToken);