From f53d5f32d56314175fd95ef9fc95c3fd5cf5a092 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Wed, 5 Aug 2026 14:30:05 -0400 Subject: [PATCH 01/13] feat: wire KMIP server certificate auto-renewal token refresh Bumps infisical-kmip to the auto-renewal version (pseudo-version off the feature branch; swap for the release tag once it lands). enrollKmipServer now also returns a refresh function passed to the server as RefreshAccessToken: AWS enrollment re-authenticates via STS and persists the new token, token enrollment has no refresh since enrollment tokens are single-use. --- go.mod | 2 +- go.sum | 4 ++-- packages/cmd/kmip.go | 34 ++++++++++++++++++++++++++++------ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index bc4dc53d..dd126b84 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/uuid v1.6.0 github.com/h2non/filetype v1.1.3 github.com/infisical/go-sdk v0.7.0 - github.com/infisical/infisical-kmip v0.3.19 + github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 github.com/jackc/pgx/v5 v5.9.2 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/masterzen/winrm v0.0.0-20260407182533-5570be7f80cf diff --git a/go.sum b/go.sum index 3ba40cf0..e7cf0001 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.19 h1:JDndxhM9+GoHTqSOX47H3KIxIuDmrEHsq17wvhw3RL8= -github.com/infisical/infisical-kmip v0.3.19/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 h1:6//zuxPFhsx8EE3y5E/ooS9KigSsvTIbk2jf91BTNtw= +github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= diff --git a/packages/cmd/kmip.go b/packages/cmd/kmip.go index 49d33051..a4ab969e 100644 --- a/packages/cmd/kmip.go +++ b/packages/cmd/kmip.go @@ -4,6 +4,7 @@ Copyright (c) 2023 Infisical Inc. package cmd import ( + "context" "errors" "fmt" "os" @@ -128,7 +129,7 @@ func startKmipServer(cmd *cobra.Command, args []string) { isResourceAuth := enrollMethod == localkmip.EnrollMethodToken || enrollMethod == localkmip.EnrollMethodAws if isResourceAuth { - serverConfig.AccessToken = enrollKmipServer(cmd, enrollMethod, serverName) + serverConfig.AccessToken, serverConfig.RefreshAccessToken = enrollKmipServer(cmd, enrollMethod, serverName) } else { // No enroll method given: reuse the stored enrollment access token unless explicit identity // credentials were passed. This keeps a manual restart of an enrolled server from silently @@ -149,8 +150,10 @@ func startKmipServer(cmd *cobra.Command, args []string) { } // enrollKmipServer obtains a KMIP server access token via token or AWS enrollment, -// persisting the relevant state under the KMIP server's config file. -func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) string { +// persisting the relevant state under the KMIP server's config file. For AWS enrollment it +// also returns a refresh function so the server can re-authenticate when its access token +// expires before its certificate does; token enrollment is single-use, so no refresh exists. +func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) (string, func() (string, error)) { httpClient, err := util.GetRestyClientWithCustomHeaders() if err != nil { util.HandleError(err, "unable to create HTTP client") @@ -183,7 +186,26 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) strin } log.Info().Msgf("KMIP server authenticated via AWS Auth. State saved to %s", localkmip.GetConfPathDisplay(serverName)) - return accessToken + + refreshAccessToken := func() (string, error) { + refreshClient, err := util.GetRestyClientWithCustomHeaders() + if err != nil { + return "", fmt.Errorf("unable to create HTTP client: %w", err) + } + + newToken, err := localkmip.LoginKmipServerWithAws(context.Background(), refreshClient, kmipServerID) + if err != nil { + return "", fmt.Errorf("AWS Auth re-login failed: %w", err) + } + + if err := localkmip.SaveAccessToken(serverName, newToken); err != nil { + log.Warn().Msgf("failed to persist refreshed KMIP access token: %v", err) + } + + return newToken, nil + } + + return accessToken, refreshAccessToken } // Enrollment token path @@ -197,7 +219,7 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) strin storedAccessToken, err := localkmip.LoadStoredAccessToken(serverName) if err == nil && storedAccessToken != "" { log.Info().Msg("Reusing stored KMIP server access token.") - return storedAccessToken + return storedAccessToken, nil } if enrollToken == "" { util.HandleError(errors.New("--token is required when --enroll-method=token and no access token is stored")) @@ -228,7 +250,7 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) strin } log.Info().Msgf("KMIP server enrolled successfully. Access token saved to %s", localkmip.GetConfPathDisplay(serverName)) - return enrollResp.AccessToken + return enrollResp.AccessToken, nil } // resolveKmipIdentityCredentials parses the legacy machine-identity credentials. From 0dea9a714a75435fd31ab7773b496df7c286a938 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Wed, 5 Aug 2026 15:01:22 -0400 Subject: [PATCH 02/13] chore: tidy e2e module for infisical-kmip bump --- e2e/go.mod | 2 +- e2e/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/go.mod b/e2e/go.mod index 81c1389c..739fd67f 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -168,7 +168,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/indece-official/go-ebcdic v1.2.0 // indirect github.com/infisical/go-sdk v0.7.0 // indirect - github.com/infisical/infisical-kmip v0.3.19 // indirect + github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index 04c3e52c..1c5a774a 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -591,8 +591,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.19 h1:JDndxhM9+GoHTqSOX47H3KIxIuDmrEHsq17wvhw3RL8= -github.com/infisical/infisical-kmip v0.3.19/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 h1:6//zuxPFhsx8EE3y5E/ooS9KigSsvTIbk2jf91BTNtw= +github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= From 878168b82ef2f660433596d86a568b787f16e675 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Wed, 5 Aug 2026 15:08:37 -0400 Subject: [PATCH 03/13] chore: bump infisical-kmip to key/cert pair validation fix --- e2e/go.mod | 2 +- e2e/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e/go.mod b/e2e/go.mod index 739fd67f..ae6394a6 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -168,7 +168,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/indece-official/go-ebcdic v1.2.0 // indirect github.com/infisical/go-sdk v0.7.0 // indirect - github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 // indirect + github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index 1c5a774a..ae60d68f 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -591,8 +591,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 h1:6//zuxPFhsx8EE3y5E/ooS9KigSsvTIbk2jf91BTNtw= -github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 h1:4rwG5XE+IFUOXsfiBx6UW7dVgJeWM/RxQNgh4gd1kwg= +github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/go.mod b/go.mod index dd126b84..028b2339 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/uuid v1.6.0 github.com/h2non/filetype v1.1.3 github.com/infisical/go-sdk v0.7.0 - github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 + github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 github.com/jackc/pgx/v5 v5.9.2 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/masterzen/winrm v0.0.0-20260407182533-5570be7f80cf diff --git a/go.sum b/go.sum index e7cf0001..a44cc7e3 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14 h1:6//zuxPFhsx8EE3y5E/ooS9KigSsvTIbk2jf91BTNtw= -github.com/infisical/infisical-kmip v0.3.20-0.20260805182853-a96df71b6d14/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 h1:4rwG5XE+IFUOXsfiBx6UW7dVgJeWM/RxQNgh4gd1kwg= +github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= From 8759a781b1f78ab4dbdb74e29d42a49bbeb1ee28 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 7 Aug 2026 14:43:22 -0400 Subject: [PATCH 04/13] chore: bump infisical-kmip past isRenewal flag removal --- e2e/go.mod | 2 +- e2e/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e/go.mod b/e2e/go.mod index ae6394a6..aa539ef1 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -168,7 +168,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/indece-official/go-ebcdic v1.2.0 // indirect github.com/infisical/go-sdk v0.7.0 // indirect - github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 // indirect + github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index ae60d68f..b79855c8 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -591,8 +591,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 h1:4rwG5XE+IFUOXsfiBx6UW7dVgJeWM/RxQNgh4gd1kwg= -github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b h1:T/lEyqFeZz0T4B6tomhlgjmJ1+ffuF2irFRtjOEC5Gw= +github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/go.mod b/go.mod index 028b2339..a38b2ddb 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/uuid v1.6.0 github.com/h2non/filetype v1.1.3 github.com/infisical/go-sdk v0.7.0 - github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 + github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b github.com/jackc/pgx/v5 v5.9.2 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/masterzen/winrm v0.0.0-20260407182533-5570be7f80cf diff --git a/go.sum b/go.sum index a44cc7e3..f97ca450 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3 h1:4rwG5XE+IFUOXsfiBx6UW7dVgJeWM/RxQNgh4gd1kwg= -github.com/infisical/infisical-kmip v0.3.20-0.20260805190802-0b7dadb616b3/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b h1:T/lEyqFeZz0T4B6tomhlgjmJ1+ffuF2irFRtjOEC5Gw= +github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= From d0384f34dc96f8c09505d27ef12e1c71417a8235 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 7 Aug 2026 14:55:57 -0400 Subject: [PATCH 05/13] fix: bound AWS token refresh with timeouts and wire it on flagless restarts The refresh closure's HTTP client and STS login now have deadlines so a hung API call cannot stall certificate renewal. A flagless restart of an AWS-enrolled server (stored-token path) now detects the persisted server ID and wires the same refresh function, so it can still recover from a rejected token. --- packages/cmd/kmip.go | 53 ++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/packages/cmd/kmip.go b/packages/cmd/kmip.go index a4ab969e..d64d21d6 100644 --- a/packages/cmd/kmip.go +++ b/packages/cmd/kmip.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "runtime" + "time" "github.com/Infisical/infisical-merge/packages/api" "github.com/Infisical/infisical-merge/packages/config" @@ -139,6 +140,11 @@ func startKmipServer(cmd *cobra.Command, args []string) { if storedToken, _ := localkmip.LoadStoredAccessToken(serverName); storedToken != "" { log.Info().Msg("Using stored KMIP server access token") serverConfig.AccessToken = storedToken + // Only AWS enrollment persists a server ID, so its presence means this server can + // re-authenticate via STS when the stored token is rejected mid-run. + if storedServerID, _ := localkmip.LoadStoredServerID(serverName); storedServerID != "" { + serverConfig.RefreshAccessToken = newAwsRefreshAccessTokenFunc(serverName, storedServerID) + } } } if serverConfig.AccessToken == "" { @@ -149,6 +155,33 @@ func startKmipServer(cmd *cobra.Command, args []string) { kmip.StartServer(serverConfig) } +// newAwsRefreshAccessTokenFunc returns a function that re-authenticates the KMIP server via +// AWS STS and persists the new access token, used by the renewal loop when the current token +// is rejected. Bounded timeouts so a hung API call cannot stall renewal indefinitely. +func newAwsRefreshAccessTokenFunc(serverName, kmipServerID string) func() (string, error) { + return func() (string, error) { + refreshClient, err := util.GetRestyClientWithCustomHeaders() + if err != nil { + return "", fmt.Errorf("unable to create HTTP client: %w", err) + } + refreshClient.SetTimeout(30 * time.Second) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + newToken, err := localkmip.LoginKmipServerWithAws(ctx, refreshClient, kmipServerID) + if err != nil { + return "", fmt.Errorf("AWS Auth re-login failed: %w", err) + } + + if err := localkmip.SaveAccessToken(serverName, newToken); err != nil { + log.Warn().Msgf("failed to persist refreshed KMIP access token: %v", err) + } + + return newToken, nil + } +} + // enrollKmipServer obtains a KMIP server access token via token or AWS enrollment, // persisting the relevant state under the KMIP server's config file. For AWS enrollment it // also returns a refresh function so the server can re-authenticate when its access token @@ -187,25 +220,7 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) (stri log.Info().Msgf("KMIP server authenticated via AWS Auth. State saved to %s", localkmip.GetConfPathDisplay(serverName)) - refreshAccessToken := func() (string, error) { - refreshClient, err := util.GetRestyClientWithCustomHeaders() - if err != nil { - return "", fmt.Errorf("unable to create HTTP client: %w", err) - } - - newToken, err := localkmip.LoginKmipServerWithAws(context.Background(), refreshClient, kmipServerID) - if err != nil { - return "", fmt.Errorf("AWS Auth re-login failed: %w", err) - } - - if err := localkmip.SaveAccessToken(serverName, newToken); err != nil { - log.Warn().Msgf("failed to persist refreshed KMIP access token: %v", err) - } - - return newToken, nil - } - - return accessToken, refreshAccessToken + return accessToken, newAwsRefreshAccessTokenFunc(serverName, kmipServerID) } // Enrollment token path From e00f8650ec59eb33d2df128ac8de994696904637 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 7 Aug 2026 21:40:52 -0400 Subject: [PATCH 06/13] chore: bump infisical-kmip for renewal loop review fixes --- e2e/go.mod | 2 +- e2e/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e/go.mod b/e2e/go.mod index aa539ef1..826cb969 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -168,7 +168,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/indece-official/go-ebcdic v1.2.0 // indirect github.com/infisical/go-sdk v0.7.0 // indirect - github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b // indirect + github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index b79855c8..50710085 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -591,8 +591,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b h1:T/lEyqFeZz0T4B6tomhlgjmJ1+ffuF2irFRtjOEC5Gw= -github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 h1:p145uaPRke7N1kP5lMcO/XX/OOosHhQ2JS3095aQVhM= +github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/go.mod b/go.mod index a38b2ddb..b1c046b6 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/uuid v1.6.0 github.com/h2non/filetype v1.1.3 github.com/infisical/go-sdk v0.7.0 - github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b + github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 github.com/jackc/pgx/v5 v5.9.2 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/masterzen/winrm v0.0.0-20260407182533-5570be7f80cf diff --git a/go.sum b/go.sum index f97ca450..be0e57ea 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b h1:T/lEyqFeZz0T4B6tomhlgjmJ1+ffuF2irFRtjOEC5Gw= -github.com/infisical/infisical-kmip v0.3.20-0.20260807184232-e21f475ca02b/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 h1:p145uaPRke7N1kP5lMcO/XX/OOosHhQ2JS3095aQVhM= +github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= From 2ca90213bab8a2455ad90de0f88c0fe6e181b655 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 14 Aug 2026 09:12:21 +0100 Subject: [PATCH 07/13] fix(kmip): decide STS refresh from the recorded enroll method LoadStoredServerID falls back to INFISICAL_KMIP_SERVER_ID, so a token-enrolled server whose environment carries that variable was wired for an STS refresh it cannot perform. A rejected token then surfaced as an AWS failure rather than telling the operator to re-enroll. Record the enroll method at enrollment and decide from that. Both reads behind the decision are conf-file only, since the environment says what this run was handed rather than how the server enrolled. Servers enrolled before the method was recorded have a conf-file server ID and no method, so that combination still counts as AWS-enrolled and keeps its refresh. Without that they would silently lose mid-run re-authentication. --- packages/cmd/kmip.go | 16 ++++++--- packages/kmip/enroll.go | 32 +++++++++++++++++ packages/kmip/enroll_test.go | 67 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 packages/kmip/enroll_test.go diff --git a/packages/cmd/kmip.go b/packages/cmd/kmip.go index d64d21d6..0394b48a 100644 --- a/packages/cmd/kmip.go +++ b/packages/cmd/kmip.go @@ -140,10 +140,12 @@ func startKmipServer(cmd *cobra.Command, args []string) { if storedToken, _ := localkmip.LoadStoredAccessToken(serverName); storedToken != "" { log.Info().Msg("Using stored KMIP server access token") serverConfig.AccessToken = storedToken - // Only AWS enrollment persists a server ID, so its presence means this server can - // re-authenticate via STS when the stored token is rejected mid-run. - if storedServerID, _ := localkmip.LoadStoredServerID(serverName); storedServerID != "" { - serverConfig.RefreshAccessToken = newAwsRefreshAccessTokenFunc(serverName, storedServerID) + // Keyed off the recorded enroll method rather than the server ID: LoadStoredServerID + // falls back to INFISICAL_KMIP_SERVER_ID, so a token-enrolled server with that + // variable set would be wired for STS refresh it cannot perform, and a rejected + // token would surface as an AWS failure instead of "re-enroll this server". + if serverID, canRefresh := localkmip.ResolveAwsRefreshServerID(serverName); canRefresh { + serverConfig.RefreshAccessToken = newAwsRefreshAccessTokenFunc(serverName, serverID) } } } @@ -214,6 +216,9 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) (stri if err := localkmip.SaveServerID(serverName, kmipServerID); err != nil { util.HandleError(err, "failed to save KMIP server id to config") } + if err := localkmip.SaveEnrollMethod(serverName, localkmip.EnrollMethodAws); err != nil { + util.HandleError(err, "failed to save KMIP enroll method to config") + } if err := localkmip.SaveDomain(serverName, config.INFISICAL_URL); err != nil { util.HandleError(err, "failed to save domain to config") } @@ -257,6 +262,9 @@ func enrollKmipServer(cmd *cobra.Command, enrollMethod, serverName string) (stri if err := localkmip.SaveAccessToken(serverName, enrollResp.AccessToken); err != nil { util.HandleError(err, "failed to save KMIP server access token") } + if err := localkmip.SaveEnrollMethod(serverName, localkmip.EnrollMethodToken); err != nil { + util.HandleError(err, "failed to save KMIP enroll method to config") + } if err := localkmip.SaveEnrollmentToken(serverName, enrollToken); err != nil { util.HandleError(err, "failed to save enrollment token to config") } diff --git a/packages/kmip/enroll.go b/packages/kmip/enroll.go index f37318c3..eca45b48 100644 --- a/packages/kmip/enroll.go +++ b/packages/kmip/enroll.go @@ -131,6 +131,38 @@ func SaveServerID(name, kmipServerID string) error { return saveConfKey(name, INFISICAL_KMIP_SERVER_ID_KEY, kmipServerID) } +// Deliberately conf-file only, unlike the loaders above. The env var is how an operator asks for a +// method on this run; the conf file records how the server actually enrolled, which is what tells +// us whether it can re-authenticate on its own. +func LoadStoredEnrollMethod(name string) (string, error) { + return loadConfKey(name, INFISICAL_KMIP_ENROLL_METHOD_KEY) +} + +func SaveEnrollMethod(name, method string) error { + return saveConfKey(name, INFISICAL_KMIP_ENROLL_METHOD_KEY, method) +} + +// Conf-file only, for deciding what a server is rather than what this run asked for. Servers +// enrolled before the method was recorded have a server ID here and nothing else, which is what +// identifies them as AWS-enrolled. +func LoadPersistedServerID(name string) (string, error) { + return loadConfKey(name, INFISICAL_KMIP_SERVER_ID_KEY) +} + +// Reports the server ID to re-authenticate with when a stored access token is rejected mid-run, +// and whether STS refresh applies at all. Both reads ignore the environment: INFISICAL_KMIP_SERVER_ID +// says what this run was handed, not how the server enrolled, so honouring it here would wire a +// token-enrolled server for a refresh it cannot perform and turn a rejected token into an AWS error. +// A server enrolled before the method was recorded is identified by a conf-file server ID alone. +func ResolveAwsRefreshServerID(name string) (string, bool) { + method, _ := LoadStoredEnrollMethod(name) + serverID, _ := LoadPersistedServerID(name) + if serverID == "" { + return "", false + } + return serverID, method == EnrollMethodAws || method == "" +} + func GetConfPathDisplay(name string) string { path, err := kmipConfPath(name) if err != nil { diff --git a/packages/kmip/enroll_test.go b/packages/kmip/enroll_test.go new file mode 100644 index 00000000..e24d4fe7 --- /dev/null +++ b/packages/kmip/enroll_test.go @@ -0,0 +1,67 @@ +package kmip + +import "os" +import "testing" + +func cleanup(t *testing.T, name string) { + t.Helper() + if p, err := kmipConfPath(name); err == nil { + _ = os.Remove(p) + } +} + +func TestAwsRefreshOnlyForAwsEnrolledServers(t *testing.T) { + // The review finding: token-enrolled, but the environment carries a server ID. + t.Run("token enrolled with env server id", func(t *testing.T) { + name := "probe-token" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, EnrollMethodToken); err != nil { + t.Fatal(err) + } + t.Setenv(INFISICAL_KMIP_SERVER_ID_KEY, "srv-from-environment") + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("token-enrolled server must not be wired for STS refresh") + } + }) + + t.Run("aws enrolled", func(t *testing.T) { + name := "probe-aws" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, EnrollMethodAws); err != nil { + t.Fatal(err) + } + if err := SaveServerID(name, "srv-real"); err != nil { + t.Fatal(err) + } + id, aws := ResolveAwsRefreshServerID(name) + if !aws || id != "srv-real" { + t.Fatalf("aws-enrolled server should refresh via STS, got id=%q aws=%v", id, aws) + } + }) + + // Enrolled before the method was recorded: must keep working. + t.Run("legacy aws enrolled without a recorded method", func(t *testing.T) { + name := "probe-legacy" + defer cleanup(t, name) + if err := SaveServerID(name, "srv-legacy"); err != nil { + t.Fatal(err) + } + id, aws := ResolveAwsRefreshServerID(name) + if !aws || id != "srv-legacy" { + t.Fatalf("legacy aws server should still refresh, got id=%q aws=%v", id, aws) + } + }) + + // A legacy token-enrolled server has no server ID in the conf file, only the env var. + t.Run("legacy token enrolled with env server id", func(t *testing.T) { + name := "probe-legacy-token" + defer cleanup(t, name) + if err := SaveEnrollmentToken(name, "tok"); err != nil { + t.Fatal(err) + } + t.Setenv(INFISICAL_KMIP_SERVER_ID_KEY, "srv-from-environment") + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("env var must not make a legacy token-enrolled server look aws-enrolled") + } + }) +} From 37f3588a7c13edfa944adf28de52c8370d93f340 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 14 Aug 2026 09:24:13 +0100 Subject: [PATCH 08/13] test(kmip): cover the STS refresh decision edge cases Adds the cases the fix has to get right beyond the reported one: never enrolled, an aws method with no server id to refresh with, a stale server id left behind by re-enrolling from aws to token, an environment server id that differs from the recorded one, an unrecognised method, and re-enrollment replacing the recorded method. --- packages/kmip/enroll_test.go | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/packages/kmip/enroll_test.go b/packages/kmip/enroll_test.go index e24d4fe7..c7dbcb7f 100644 --- a/packages/kmip/enroll_test.go +++ b/packages/kmip/enroll_test.go @@ -65,3 +65,89 @@ func TestAwsRefreshOnlyForAwsEnrolledServers(t *testing.T) { } }) } + +func TestResolveAwsRefreshServerIDEdgeCases(t *testing.T) { + t.Run("never enrolled", func(t *testing.T) { + name := "probe-absent" + defer cleanup(t, name) + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("a server with no config must not refresh") + } + }) + + t.Run("aws method recorded but no server id", func(t *testing.T) { + name := "probe-aws-no-id" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, EnrollMethodAws); err != nil { + t.Fatal(err) + } + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("there is nothing to re-authenticate with without a server id") + } + }) + + // Re-enrolled from aws to token: the old server ID is still in the conf file. + t.Run("stale server id from a previous aws enrollment", func(t *testing.T) { + name := "probe-reenrolled" + defer cleanup(t, name) + if err := SaveServerID(name, "srv-old-aws"); err != nil { + t.Fatal(err) + } + if err := SaveEnrollMethod(name, EnrollMethodToken); err != nil { + t.Fatal(err) + } + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("a token re-enrollment must not keep refreshing via the old aws server id") + } + }) + + t.Run("env server id differs from the recorded one", func(t *testing.T) { + name := "probe-env-differs" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, EnrollMethodAws); err != nil { + t.Fatal(err) + } + if err := SaveServerID(name, "srv-recorded"); err != nil { + t.Fatal(err) + } + t.Setenv(INFISICAL_KMIP_SERVER_ID_KEY, "srv-from-environment") + id, aws := ResolveAwsRefreshServerID(name) + if !aws || id != "srv-recorded" { + t.Fatalf("must re-authenticate as the recorded server, got id=%q aws=%v", id, aws) + } + }) + + t.Run("unrecognised method", func(t *testing.T) { + name := "probe-unknown" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, "kubernetes"); err != nil { + t.Fatal(err) + } + if err := SaveServerID(name, "srv-x"); err != nil { + t.Fatal(err) + } + if _, aws := ResolveAwsRefreshServerID(name); aws { + t.Fatal("only aws enrollment refreshes via STS") + } + }) + + t.Run("method is overwritten on re-enrollment", func(t *testing.T) { + name := "probe-overwrite" + defer cleanup(t, name) + if err := SaveEnrollMethod(name, EnrollMethodToken); err != nil { + t.Fatal(err) + } + if err := SaveEnrollMethod(name, EnrollMethodAws); err != nil { + t.Fatal(err) + } + if err := SaveServerID(name, "srv-now-aws"); err != nil { + t.Fatal(err) + } + if got, _ := LoadStoredEnrollMethod(name); got != EnrollMethodAws { + t.Fatalf("re-enrollment should replace the method, got %q", got) + } + if id, aws := ResolveAwsRefreshServerID(name); !aws || id != "srv-now-aws" { + t.Fatalf("expected refresh as srv-now-aws, got id=%q aws=%v", id, aws) + } + }) +} From 20ba9b6f3da21829aaaaa7d563f67d6335dce314 Mon Sep 17 00:00:00 2001 From: bernie-g Date: Fri, 14 Aug 2026 10:01:27 +0100 Subject: [PATCH 09/13] chore(kmip): trim comments to the non-obvious parts Drops narration that restated the code: the decision block at the call site, now covered by the named function, a duplicated note on the loader beside it, and test comments the subtest names already say. --- packages/cmd/kmip.go | 4 ---- packages/kmip/enroll.go | 15 ++++----------- packages/kmip/enroll_test.go | 4 ---- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/cmd/kmip.go b/packages/cmd/kmip.go index 0394b48a..51664d07 100644 --- a/packages/cmd/kmip.go +++ b/packages/cmd/kmip.go @@ -140,10 +140,6 @@ func startKmipServer(cmd *cobra.Command, args []string) { if storedToken, _ := localkmip.LoadStoredAccessToken(serverName); storedToken != "" { log.Info().Msg("Using stored KMIP server access token") serverConfig.AccessToken = storedToken - // Keyed off the recorded enroll method rather than the server ID: LoadStoredServerID - // falls back to INFISICAL_KMIP_SERVER_ID, so a token-enrolled server with that - // variable set would be wired for STS refresh it cannot perform, and a rejected - // token would surface as an AWS failure instead of "re-enroll this server". if serverID, canRefresh := localkmip.ResolveAwsRefreshServerID(serverName); canRefresh { serverConfig.RefreshAccessToken = newAwsRefreshAccessTokenFunc(serverName, serverID) } diff --git a/packages/kmip/enroll.go b/packages/kmip/enroll.go index eca45b48..ee752ad5 100644 --- a/packages/kmip/enroll.go +++ b/packages/kmip/enroll.go @@ -131,9 +131,7 @@ func SaveServerID(name, kmipServerID string) error { return saveConfKey(name, INFISICAL_KMIP_SERVER_ID_KEY, kmipServerID) } -// Deliberately conf-file only, unlike the loaders above. The env var is how an operator asks for a -// method on this run; the conf file records how the server actually enrolled, which is what tells -// us whether it can re-authenticate on its own. +// Conf-file only: the env var says what this run asked for, not how the server enrolled. func LoadStoredEnrollMethod(name string) (string, error) { return loadConfKey(name, INFISICAL_KMIP_ENROLL_METHOD_KEY) } @@ -142,18 +140,13 @@ func SaveEnrollMethod(name, method string) error { return saveConfKey(name, INFISICAL_KMIP_ENROLL_METHOD_KEY, method) } -// Conf-file only, for deciding what a server is rather than what this run asked for. Servers -// enrolled before the method was recorded have a server ID here and nothing else, which is what -// identifies them as AWS-enrolled. func LoadPersistedServerID(name string) (string, error) { return loadConfKey(name, INFISICAL_KMIP_SERVER_ID_KEY) } -// Reports the server ID to re-authenticate with when a stored access token is rejected mid-run, -// and whether STS refresh applies at all. Both reads ignore the environment: INFISICAL_KMIP_SERVER_ID -// says what this run was handed, not how the server enrolled, so honouring it here would wire a -// token-enrolled server for a refresh it cannot perform and turn a rejected token into an AWS error. -// A server enrolled before the method was recorded is identified by a conf-file server ID alone. +// Ignores the environment throughout: honouring INFISICAL_KMIP_SERVER_ID here would wire a +// token-enrolled server for an STS refresh it cannot perform. A missing method means the server +// enrolled before it was recorded, where a conf-file server ID identifies AWS enrollment. func ResolveAwsRefreshServerID(name string) (string, bool) { method, _ := LoadStoredEnrollMethod(name) serverID, _ := LoadPersistedServerID(name) diff --git a/packages/kmip/enroll_test.go b/packages/kmip/enroll_test.go index c7dbcb7f..2af9abcb 100644 --- a/packages/kmip/enroll_test.go +++ b/packages/kmip/enroll_test.go @@ -11,7 +11,6 @@ func cleanup(t *testing.T, name string) { } func TestAwsRefreshOnlyForAwsEnrolledServers(t *testing.T) { - // The review finding: token-enrolled, but the environment carries a server ID. t.Run("token enrolled with env server id", func(t *testing.T) { name := "probe-token" defer cleanup(t, name) @@ -39,7 +38,6 @@ func TestAwsRefreshOnlyForAwsEnrolledServers(t *testing.T) { } }) - // Enrolled before the method was recorded: must keep working. t.Run("legacy aws enrolled without a recorded method", func(t *testing.T) { name := "probe-legacy" defer cleanup(t, name) @@ -52,7 +50,6 @@ func TestAwsRefreshOnlyForAwsEnrolledServers(t *testing.T) { } }) - // A legacy token-enrolled server has no server ID in the conf file, only the env var. t.Run("legacy token enrolled with env server id", func(t *testing.T) { name := "probe-legacy-token" defer cleanup(t, name) @@ -86,7 +83,6 @@ func TestResolveAwsRefreshServerIDEdgeCases(t *testing.T) { } }) - // Re-enrolled from aws to token: the old server ID is still in the conf file. t.Run("stale server id from a previous aws enrollment", func(t *testing.T) { name := "probe-reenrolled" defer cleanup(t, name) From a91c1a77a0d3a5d20bb3507affd5dcbfa4865f52 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Mon, 17 Aug 2026 18:34:46 +0800 Subject: [PATCH 10/13] misc: added ignore --- .github/workflows/govulncheck.yml | 40 ++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml index 7d56b139..51fda665 100644 --- a/.github/workflows/govulncheck.yml +++ b/.github/workflows/govulncheck.yml @@ -29,17 +29,39 @@ jobs: # Fails on ANY vulnerable module version (deps + stdlib for the CI toolchain), # regardless of reachability — matches external (Trivy-style) scanners. # - # ALLOWLIST holds advisories we knowingly accept: each must have no fixed - # version available AND not be present in our build graph (unreachable). - # Everything else — including any future fixable advisory — still fails. + # DEP_ALLOWLIST holds dependency advisories we knowingly accept: each must + # have no fixed version available AND not be present in our build graph + # (unreachable). Everything else still fails. # - GO-2026-5932: golang.org/x/crypto/openpgp is unmaintained (Fixed in: N/A). # We do not import openpgp anywhere; verify with: # go list -deps ./... | grep openpgp # (expect no output) + # + # STDLIB_ALLOWLIST holds standard-library advisories whose only remedy is a + # toolchain bump. Every workflow here — including the release build — pins + # 1.25.12, so moving off it is its own change and is deliberately deferred. + # Listing the IDs rather than skipping stdlib wholesale keeps the gate + # honest: a newly published stdlib advisory still fails until someone + # decides to accept or fix it. - name: Run govulncheck (module versions) env: CGO_ENABLED: "0" run: | - ALLOWLIST="GO-2026-5932" + DEP_ALLOWLIST="GO-2026-5932" + + # Fixed in stdlib@go1.25.13, except GO-2026-5942 (stdlib@go1.26.6). + # Delete these once the pinned toolchain covers them. + STDLIB_ALLOWLIST=" + GO-2026-5026 + GO-2026-5942 + GO-2026-5972 + GO-2026-6088 + GO-2026-6089 + GO-2026-6090 + GO-2026-6091 + GO-2026-6218 + " + + ALLOWLIST="$DEP_ALLOWLIST $STDLIB_ALLOWLIST" # Human-readable report (informational; govulncheck exits 3 when it # finds anything, so don't let that fail the step on its own). @@ -48,15 +70,21 @@ jobs: # Machine-readable gate: fail only on advisories not in the allowlist. govulncheck -scan module -format json > govulncheck.json || true findings="$(jq -r 'select(.finding != null) | .finding.osv' govulncheck.json | sort -u)" + allowed="$(tr ' ' '\n' <<< "$ALLOWLIST" | grep -v '^$' | sort -u)" unexpected="" for id in $findings; do - if ! grep -qxF "$id" <<< "$(tr ' ' '\n' <<< "$ALLOWLIST")"; then + if ! grep -qxF "$id" <<< "$allowed"; then unexpected="$unexpected $id" fi done - echo "=== Allowlisted (no fix available, not in build graph): $ALLOWLIST ===" + echo "=== Allowlisted: $(tr '\n' ' ' <<< "$allowed")===" + + stale="$(comm -23 <(echo "$allowed") <(echo "$findings"))" + if [ -n "$stale" ]; then + echo "::warning::Allowlist entries no longer reported, drop them: $(tr '\n' ' ' <<< "$stale")" + fi if [ -n "${unexpected// /}" ]; then echo "::error::Non-allowlisted vulnerabilities found:$unexpected" From 39a6035dd58b3ccea31cf0ac74ac976e7661dc6e Mon Sep 17 00:00:00 2001 From: bernie-g Date: Mon, 17 Aug 2026 07:23:31 -0400 Subject: [PATCH 11/13] chore: retrigger checks From 83663e6e94a57bac31005155b4e28110eb2aa98e Mon Sep 17 00:00:00 2001 From: bernie-g Date: Mon, 17 Aug 2026 13:24:42 -0400 Subject: [PATCH 12/13] chore: pin infisical-kmip to the released v0.3.20 --- e2e/go.mod | 2 +- e2e/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e/go.mod b/e2e/go.mod index 826cb969..ed358a56 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -168,7 +168,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/indece-official/go-ebcdic v1.2.0 // indirect github.com/infisical/go-sdk v0.7.0 // indirect - github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 // indirect + github.com/infisical/infisical-kmip v0.3.20 // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index 50710085..e873f8fb 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -591,8 +591,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 h1:p145uaPRke7N1kP5lMcO/XX/OOosHhQ2JS3095aQVhM= -github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20 h1:FAc/SK90qgSyQg24+gpkudmGmGT5+75/1o3EcsEewtQ= +github.com/infisical/infisical-kmip v0.3.20/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/go.mod b/go.mod index b1c046b6..e5acef0f 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/uuid v1.6.0 github.com/h2non/filetype v1.1.3 github.com/infisical/go-sdk v0.7.0 - github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 + github.com/infisical/infisical-kmip v0.3.20 github.com/jackc/pgx/v5 v5.9.2 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/masterzen/winrm v0.0.0-20260407182533-5570be7f80cf diff --git a/go.sum b/go.sum index be0e57ea..993a0108 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/indece-official/go-ebcdic v1.2.0 h1:nKCubkNoXrGvBp3MSYuplOQnhANCDEY51 github.com/indece-official/go-ebcdic v1.2.0/go.mod h1:RBddVJt0Ks0eDLRG5dhPwBDRiTNA7n+yv0dVFpSs46Q= github.com/infisical/go-sdk v0.7.0 h1:x9/1PczL+ioVD1jCp4LHQzPpBawatbmkjAC0S1OAtUA= github.com/infisical/go-sdk v0.7.0/go.mod h1:yEfXF+3YDDXiJ9zzJUSzW6me6XXPPEDK52fSU6JfpCA= -github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78 h1:p145uaPRke7N1kP5lMcO/XX/OOosHhQ2JS3095aQVhM= -github.com/infisical/infisical-kmip v0.3.20-0.20260808014015-39f64ec76f78/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= +github.com/infisical/infisical-kmip v0.3.20 h1:FAc/SK90qgSyQg24+gpkudmGmGT5+75/1o3EcsEewtQ= +github.com/infisical/infisical-kmip v0.3.20/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= From f506ec1cdd35de3f419fac82a0c1b61c0c34feaf Mon Sep 17 00:00:00 2001 From: bernie-g Date: Mon, 17 Aug 2026 13:33:16 -0400 Subject: [PATCH 13/13] chore: retrigger checks