Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.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
Expand Down
4 changes: 2 additions & 2 deletions e2e/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.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=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.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=
Expand Down
49 changes: 43 additions & 6 deletions packages/cmd/kmip.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ Copyright (c) 2023 Infisical Inc.
package cmd

import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"runtime"
"time"

"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/config"
Expand Down Expand Up @@ -128,7 +130,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
Expand All @@ -138,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 == "" {
Expand All @@ -148,9 +155,38 @@ 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.
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")
Expand Down Expand Up @@ -183,7 +219,8 @@ 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

return accessToken, newAwsRefreshAccessTokenFunc(serverName, kmipServerID)
}

// Enrollment token path
Expand All @@ -197,7 +234,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"))
Expand Down Expand Up @@ -228,7 +265,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.
Expand Down
Loading