From 400157a468da8a10bbc2e3a075cd453996d7ae5f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 3 Jun 2025 21:34:24 +0400 Subject: [PATCH 01/14] feat(cli): gateway auth methods --- cli/go.mod | 4 +- cli/go.sum | 2 + cli/packages/cmd/gateway.go | 135 +++++++++++++++++++++++++++++--- cli/packages/cmd/kmip.go | 4 +- cli/packages/cmd/login.go | 135 ++++++++------------------------ cli/packages/gateway/gateway.go | 4 + cli/packages/util/auth.go | 122 +++++++++++++++++++++++++++++ cli/packages/util/constants.go | 5 +- cli/packages/util/helper.go | 9 ++- 9 files changed, 298 insertions(+), 122 deletions(-) diff --git a/cli/go.mod b/cli/go.mod index 229e37137..1b44d9c9d 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -2,6 +2,8 @@ module github.com/Infisical/infisical-merge go 1.23.0 +replace github.com/infisical/go-sdk => ../../go-sdk + toolchain go1.23.5 require ( @@ -14,7 +16,7 @@ require ( github.com/fatih/semgroup v1.2.0 github.com/gitleaks/go-gitdiff v0.9.1 github.com/h2non/filetype v1.1.3 - github.com/infisical/go-sdk v0.5.92 + github.com/infisical/go-sdk v0.5.94 github.com/infisical/infisical-kmip v0.3.5 github.com/mattn/go-isatty v0.0.20 github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a diff --git a/cli/go.sum b/cli/go.sum index d253c70d5..957fedb05 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -294,6 +294,8 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/infisical/go-sdk v0.5.92 h1:PoCnVndrd6Dbkipuxl9fFiwlD5vCKsabtQo09mo8lUE= github.com/infisical/go-sdk v0.5.92/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= +github.com/infisical/go-sdk v0.5.94 h1:wKBj+KpJEe+ZzOJ7koXQZDR0dLL9bt0Kqgf/1q+7tG4= +github.com/infisical/go-sdk v0.5.94/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= github.com/infisical/infisical-kmip v0.3.5 h1:QM3s0e18B+mYv3a9HQNjNAlbwZJBzXq5BAJM2scIeiE= github.com/infisical/infisical-kmip v0.3.5/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= diff --git a/cli/packages/cmd/gateway.go b/cli/packages/cmd/gateway.go index 51565b6fd..3e6e268d9 100644 --- a/cli/packages/cmd/gateway.go +++ b/cli/packages/cmd/gateway.go @@ -7,16 +7,79 @@ import ( "os/exec" "os/signal" "runtime" + "sync/atomic" "syscall" "time" + "github.com/Infisical/infisical-merge/packages/api" + "github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/gateway" "github.com/Infisical/infisical-merge/packages/util" + infisicalSdk "github.com/infisical/go-sdk" + "github.com/pkg/errors" "github.com/posthog/posthog-go" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) +func getInfisicalSdkInstance(cmd *cobra.Command) (infisicalSdk.InfisicalClientInterface, context.CancelFunc, error) { + + ctx, cancel := context.WithCancel(cmd.Context()) + infisicalClient := infisicalSdk.NewInfisicalClient(ctx, infisicalSdk.Config{ + SiteUrl: config.INFISICAL_URL, + UserAgent: api.USER_AGENT, + }) + + token, err := util.GetInfisicalToken(cmd) + if err != nil { + cancel() + return nil, nil, err + } + + fmt.Printf("token: %+v\n", token) + + // if the --token param is set, we use it directly for authentication + if token != nil { + infisicalClient.Auth().SetAccessToken(token.Token) + fmt.Printf("token from client: %+v\n", infisicalClient.Auth().GetAccessToken()) + return infisicalClient, cancel, nil + } + + // if the --token param is not set, we use the auth-method flag to determine the authentication method, and perform the appropriate login flow based on that + authMethod, err := cmd.Flags().GetString("auth-method") + if err != nil { + cancel() + return nil, nil, err + } + + authMethodValid, strategy := util.IsAuthMethodValid(authMethod, false) + if !authMethodValid { + util.PrintErrorMessageAndExit(fmt.Sprintf("Invalid login method: %s", authMethod)) + } + + sdkAuthenticator := util.NewSdkAuthenticator(infisicalClient, cmd) + + authStrategies := map[util.AuthStrategyType]func() (credential infisicalSdk.MachineIdentityCredential, e error){ + util.AuthStrategy.UNIVERSAL_AUTH: sdkAuthenticator.HandleUniversalAuthLogin, + util.AuthStrategy.KUBERNETES_AUTH: sdkAuthenticator.HandleKubernetesAuthLogin, + util.AuthStrategy.AZURE_AUTH: sdkAuthenticator.HandleAzureAuthLogin, + util.AuthStrategy.GCP_ID_TOKEN_AUTH: sdkAuthenticator.HandleGcpIdTokenAuthLogin, + util.AuthStrategy.GCP_IAM_AUTH: sdkAuthenticator.HandleGcpIamAuthLogin, + util.AuthStrategy.AWS_IAM_AUTH: sdkAuthenticator.HandleAwsIamAuthLogin, + util.AuthStrategy.OIDC_AUTH: sdkAuthenticator.HandleOidcAuthLogin, + util.AuthStrategy.JWT_AUTH: sdkAuthenticator.HandleJwtAuthLogin, + } + + _, err = authStrategies[strategy]() + + if err != nil { + cancel() + return nil, nil, err + } + + return infisicalClient, cancel, nil +} + var gatewayCmd = &cobra.Command{ Use: "gateway", Short: "Run the Infisical gateway or manage its systemd service", @@ -26,13 +89,18 @@ var gatewayCmd = &cobra.Command{ DisableFlagsInUseLine: true, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - token, err := util.GetInfisicalToken(cmd) - if err != nil { - util.HandleError(err, "Unable to parse token flag") - } - if token == nil { - util.HandleError(fmt.Errorf("Token not found")) + infisicalClient, cancelSdk, err := getInfisicalSdkInstance(cmd) + if err != nil { + util.HandleError(err, "unable to get infisical client") + } + defer cancelSdk() + + var accessToken atomic.Value + accessToken.Store(infisicalClient.Auth().GetAccessToken()) + + if accessToken.Load().(string) == "" { + util.HandleError(errors.New("no access token found")) } Telemetry.CaptureEvent("cli-command:gateway", posthog.NewProperties().Set("version", util.CLI_VERSION)) @@ -41,13 +109,14 @@ var gatewayCmd = &cobra.Command{ signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) sigStopCh := make(chan bool, 1) - ctx, cancel := context.WithCancel(cmd.Context()) - defer cancel() + ctx, cancelCmd := context.WithCancel(cmd.Context()) + defer cancelCmd() go func() { <-sigCh close(sigStopCh) - cancel() + cancelCmd() + cancelSdk() // If we get a second signal, force exit <-sigCh @@ -55,6 +124,34 @@ var gatewayCmd = &cobra.Command{ os.Exit(1) }() + var gatewayInstance *gateway.Gateway + + // Token refresh goroutine - runs every 10 seconds + go func() { + tokenRefreshTicker := time.NewTicker(10 * time.Second) + defer tokenRefreshTicker.Stop() + + for { + select { + case <-tokenRefreshTicker.C: + if ctx.Err() != nil { + return + } + + newToken := infisicalClient.Auth().GetAccessToken() + if newToken != "" && newToken != accessToken.Load().(string) { + accessToken.Store(newToken) + if gatewayInstance != nil { + gatewayInstance.UpdateIdentityAccessToken(newToken) + } + } + + case <-ctx.Done(): + return + } + } + }() + // Main gateway retry loop with proper context handling retryTicker := time.NewTicker(5 * time.Second) defer retryTicker.Stop() @@ -64,7 +161,7 @@ var gatewayCmd = &cobra.Command{ log.Info().Msg("Shutting down gateway") return } - gatewayInstance, err := gateway.NewGateway(token.Token) + gatewayInstance, err := gateway.NewGateway(accessToken.Load().(string)) if err != nil { util.HandleError(err) } @@ -126,7 +223,7 @@ var gatewayInstallCmd = &cobra.Command{ } if token == nil { - util.HandleError(fmt.Errorf("Token not found")) + util.HandleError(errors.New("Token not found")) } domain, err := cmd.Flags().GetString("domain") @@ -183,7 +280,7 @@ var gatewayRelayCmd = &cobra.Command{ } if relayConfigFilePath == "" { - util.HandleError(fmt.Errorf("Missing config file")) + util.HandleError(errors.New("Missing config file")) } gatewayRelay, err := gateway.NewGatewayRelay(relayConfigFilePath) @@ -198,7 +295,19 @@ var gatewayRelayCmd = &cobra.Command{ } func init() { - gatewayCmd.Flags().String("token", "", "Connect with Infisical using machine identity access token") + gatewayCmd.Flags().String("token", "", "connect with Infisical using machine identity access token. if not provided, you must set the auth-method flag") + + gatewayCmd.Flags().String("auth-method", "", "login method [universal-auth, kubernetes, azure, gcp-id-token, gcp-iam, aws-iam, oidc-auth]. if not provided, you must set the token flag") + + gatewayCmd.Flags().String("client-id", "", "client id for universal auth") + gatewayCmd.Flags().String("client-secret", "", "client secret for universal auth") + + gatewayCmd.Flags().String("machine-identity-id", "", "machine identity id for kubernetes, azure, gcp-id-token, gcp-iam, and aws-iam auth methods") + gatewayCmd.Flags().String("service-account-token-path", "", "service account token path for kubernetes auth") + gatewayCmd.Flags().String("service-account-key-file-path", "", "service account key file path for GCP IAM auth") + + gatewayCmd.Flags().String("jwt", "", "JWT for jwt-based auth methods [oidc-auth, jwt-auth]") + gatewayInstallCmd.Flags().String("token", "", "Connect with Infisical using machine identity access token") gatewayInstallCmd.Flags().String("domain", "", "Domain of your self-hosted Infisical instance") diff --git a/cli/packages/cmd/kmip.go b/cli/packages/cmd/kmip.go index b0c397895..91335d122 100644 --- a/cli/packages/cmd/kmip.go +++ b/cli/packages/cmd/kmip.go @@ -49,13 +49,13 @@ func startKmipServer(cmd *cobra.Command, args []string) { var identityClientSecret string if strategy == util.AuthStrategy.UNIVERSAL_AUTH { - identityClientId, err = util.GetCmdFlagOrEnv(cmd, "identity-client-id", util.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) + identityClientId, err = util.GetCmdFlagOrEnv(cmd, "identity-client-id", []string{util.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME}) if err != nil { util.HandleError(err, "Unable to parse identity client ID") } - identityClientSecret, err = util.GetCmdFlagOrEnv(cmd, "identity-client-secret", util.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) + identityClientSecret, err = util.GetCmdFlagOrEnv(cmd, "identity-client-secret", []string{util.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME}) if err != nil { util.HandleError(err, "Unable to parse identity client secret") } diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index b0ce7564b..ef549aabe 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -49,97 +49,6 @@ type params struct { keyLength uint32 } -func handleUniversalAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - clientId, err := util.GetCmdFlagOrEnv(cmd, "client-id", util.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME) - - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - clientSecret, err := util.GetCmdFlagOrEnv(cmd, "client-secret", util.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().UniversalAuthLogin(clientId, clientSecret) -} - -func handleKubernetesAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - serviceAccountTokenPath, err := util.GetCmdFlagOrEnv(cmd, "service-account-token-path", util.INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().KubernetesAuthLogin(identityId, serviceAccountTokenPath) -} - -func handleAzureAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().AzureAuthLogin(identityId, "") -} - -func handleGcpIdTokenAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().GcpIdTokenAuthLogin(identityId) -} - -func handleGcpIamAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - serviceAccountKeyFilePath, err := util.GetCmdFlagOrEnv(cmd, "service-account-key-file-path", util.INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().GcpIamAuthLogin(identityId, serviceAccountKeyFilePath) -} - -func handleAwsIamAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().AwsIamAuthLogin(identityId) -} - -func handleOidcAuthLogin(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error) { - - identityId, err := util.GetCmdFlagOrEnv(cmd, "machine-identity-id", util.INFISICAL_MACHINE_IDENTITY_ID_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - jwt, err := util.GetCmdFlagOrEnv(cmd, "oidc-jwt", util.INFISICAL_OIDC_AUTH_JWT_NAME) - if err != nil { - return infisicalSdk.MachineIdentityCredential{}, err - } - - return infisicalClient.Auth().OidcAuthLogin(identityId, jwt) -} - func formatAuthMethod(authMethod string) string { return strings.ReplaceAll(authMethod, "-", " ") } @@ -154,8 +63,22 @@ var loginCmd = &cobra.Command{ Use: "login", Short: "Login into your Infisical account", DisableFlagsInUseLine: true, - Run: func(cmd *cobra.Command, args []string) { + PreRunE: func(cmd *cobra.Command, args []string) error { + // daniel: oidc-jwt is deprecated in favor of `jwt`. we backfill the `jwt` flag with the value of `oidc-jwt` if it's set. + if cmd.Flags().Changed("oidc-jwt") && !cmd.Flags().Changed("jwt") { + oidcJWT, err := cmd.Flags().GetString("oidc-jwt") + if err != nil { + return err + } + err = cmd.Flags().Set("jwt", oidcJWT) + if err != nil { + return err + } + } + return nil + }, + Run: func(cmd *cobra.Command, args []string) { presetDomain := config.INFISICAL_URL clearSelfHostedDomains, err := cmd.Flags().GetBool("clear-domains") @@ -310,17 +233,19 @@ var loginCmd = &cobra.Command{ Telemetry.CaptureEvent("cli-command:login", posthog.NewProperties().Set("infisical-backend", config.INFISICAL_URL).Set("version", util.CLI_VERSION)) } else { - authStrategies := map[util.AuthStrategyType]func(cmd *cobra.Command, infisicalClient infisicalSdk.InfisicalClientInterface) (credential infisicalSdk.MachineIdentityCredential, e error){ - util.AuthStrategy.UNIVERSAL_AUTH: handleUniversalAuthLogin, - util.AuthStrategy.KUBERNETES_AUTH: handleKubernetesAuthLogin, - util.AuthStrategy.AZURE_AUTH: handleAzureAuthLogin, - util.AuthStrategy.GCP_ID_TOKEN_AUTH: handleGcpIdTokenAuthLogin, - util.AuthStrategy.GCP_IAM_AUTH: handleGcpIamAuthLogin, - util.AuthStrategy.AWS_IAM_AUTH: handleAwsIamAuthLogin, - util.AuthStrategy.OIDC_AUTH: handleOidcAuthLogin, + sdkAuthenticator := util.NewSdkAuthenticator(infisicalClient, cmd) + + authStrategies := map[util.AuthStrategyType]func() (credential infisicalSdk.MachineIdentityCredential, e error){ + util.AuthStrategy.UNIVERSAL_AUTH: sdkAuthenticator.HandleUniversalAuthLogin, + util.AuthStrategy.KUBERNETES_AUTH: sdkAuthenticator.HandleKubernetesAuthLogin, + util.AuthStrategy.AZURE_AUTH: sdkAuthenticator.HandleAzureAuthLogin, + util.AuthStrategy.GCP_ID_TOKEN_AUTH: sdkAuthenticator.HandleGcpIdTokenAuthLogin, + util.AuthStrategy.GCP_IAM_AUTH: sdkAuthenticator.HandleGcpIamAuthLogin, + util.AuthStrategy.AWS_IAM_AUTH: sdkAuthenticator.HandleAwsIamAuthLogin, + util.AuthStrategy.OIDC_AUTH: sdkAuthenticator.HandleOidcAuthLogin, } - credential, err := authStrategies[strategy](cmd, infisicalClient) + credential, err := authStrategies[strategy]() if err != nil { euErrorMessage := "" @@ -518,14 +443,18 @@ func init() { rootCmd.AddCommand(loginCmd) loginCmd.Flags().Bool("clear-domains", false, "clear all self-hosting domains from the config file") loginCmd.Flags().BoolP("interactive", "i", false, "login via the command line") - loginCmd.Flags().String("method", "user", "login method [user, universal-auth]") loginCmd.Flags().Bool("plain", false, "only output the token without any formatting") + loginCmd.Flags().String("method", "user", "login method [user, universal-auth, kubernetes, azure, gcp-id-token, gcp-iam, aws-iam, oidc-auth]") loginCmd.Flags().String("client-id", "", "client id for universal auth") loginCmd.Flags().String("client-secret", "", "client secret for universal auth") loginCmd.Flags().String("machine-identity-id", "", "machine identity id for kubernetes, azure, gcp-id-token, gcp-iam, and aws-iam auth methods") loginCmd.Flags().String("service-account-token-path", "", "service account token path for kubernetes auth") loginCmd.Flags().String("service-account-key-file-path", "", "service account key file path for GCP IAM auth") - loginCmd.Flags().String("oidc-jwt", "", "JWT for OIDC authentication") + loginCmd.Flags().String("jwt", "", "jwt for jwt-based auth methods [oidc-auth, jwt-auth]") + loginCmd.Flags().String("oidc-jwt", "", "JWT for OIDC authentication. Deprecated, use --jwt instead") + + loginCmd.Flags().MarkDeprecated("oidc-jwt", "use --jwt instead") + } func DomainOverridePrompt() (bool, error) { diff --git a/cli/packages/gateway/gateway.go b/cli/packages/gateway/gateway.go index d0a25ca9c..eb0c72d5d 100644 --- a/cli/packages/gateway/gateway.go +++ b/cli/packages/gateway/gateway.go @@ -54,6 +54,10 @@ func NewGateway(identityToken string) (Gateway, error) { }, nil } +func (g *Gateway) UpdateIdentityAccessToken(accessToken string) { + g.httpClient.SetAuthToken(accessToken) +} + func (g *Gateway) ConnectWithRelay() error { relayDetails, err := api.CallRegisterGatewayIdentityV1(g.httpClient) if err != nil { diff --git a/cli/packages/util/auth.go b/cli/packages/util/auth.go index b54bde45b..eaf7cecc1 100644 --- a/cli/packages/util/auth.go +++ b/cli/packages/util/auth.go @@ -5,7 +5,9 @@ import ( "os" "os/exec" + infisicalSdk "github.com/infisical/go-sdk" "github.com/rs/zerolog/log" + "github.com/spf13/cobra" ) type AuthStrategyType string @@ -18,6 +20,7 @@ var AuthStrategy = struct { GCP_IAM_AUTH AuthStrategyType AWS_IAM_AUTH AuthStrategyType OIDC_AUTH AuthStrategyType + JWT_AUTH AuthStrategyType }{ UNIVERSAL_AUTH: "universal-auth", KUBERNETES_AUTH: "kubernetes", @@ -26,6 +29,7 @@ var AuthStrategy = struct { GCP_IAM_AUTH: "gcp-iam", AWS_IAM_AUTH: "aws-iam", OIDC_AUTH: "oidc-auth", + JWT_AUTH: "jwt-auth", } var AVAILABLE_AUTH_STRATEGIES = []AuthStrategyType{ @@ -36,6 +40,7 @@ var AVAILABLE_AUTH_STRATEGIES = []AuthStrategyType{ AuthStrategy.GCP_IAM_AUTH, AuthStrategy.AWS_IAM_AUTH, AuthStrategy.OIDC_AUTH, + AuthStrategy.JWT_AUTH, } func IsAuthMethodValid(authMethod string, allowUserAuth bool) (isValid bool, strategy AuthStrategyType) { @@ -84,3 +89,120 @@ func EstablishUserLoginSession() LoggedInUserDetails { return loggedInUserDetails } + +type SdkAuthenticator struct { + infisicalClient infisicalSdk.InfisicalClientInterface + cmd *cobra.Command +} + +func NewSdkAuthenticator(infisicalClient infisicalSdk.InfisicalClientInterface, cmd *cobra.Command) *SdkAuthenticator { + return &SdkAuthenticator{ + infisicalClient: infisicalClient, + cmd: cmd, + } +} +func (a *SdkAuthenticator) HandleUniversalAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + clientId, err := GetCmdFlagOrEnv(a.cmd, "client-id", []string{INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME}) + + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + clientSecret, err := GetCmdFlagOrEnv(a.cmd, "client-secret", []string{INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().UniversalAuthLogin(clientId, clientSecret) +} + +func (a *SdkAuthenticator) HandleJwtAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + jwt, err := GetCmdFlagOrEnv(a.cmd, "jwt", []string{INFISICAL_JWT_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().JwtAuthLogin(identityId, jwt) +} + +func (a *SdkAuthenticator) HandleKubernetesAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + serviceAccountTokenPath, err := GetCmdFlagOrEnv(a.cmd, "service-account-token-path", []string{INFISICAL_KUBERNETES_SERVICE_ACCOUNT_TOKEN_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().KubernetesAuthLogin(identityId, serviceAccountTokenPath) +} + +func (a *SdkAuthenticator) HandleAzureAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().AzureAuthLogin(identityId, "") +} + +func (a *SdkAuthenticator) HandleGcpIdTokenAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().GcpIdTokenAuthLogin(identityId) +} + +func (a *SdkAuthenticator) HandleGcpIamAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + serviceAccountKeyFilePath, err := GetCmdFlagOrEnv(a.cmd, "service-account-key-file-path", []string{INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().GcpIamAuthLogin(identityId, serviceAccountKeyFilePath) +} + +func (a *SdkAuthenticator) HandleAwsIamAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().AwsIamAuthLogin(identityId) +} + +func (a *SdkAuthenticator) HandleOidcAuthLogin() (credential infisicalSdk.MachineIdentityCredential, e error) { + + identityId, err := GetCmdFlagOrEnv(a.cmd, "machine-identity-id", []string{INFISICAL_MACHINE_IDENTITY_ID_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + jwt, err := GetCmdFlagOrEnv(a.cmd, "jwt", []string{INFISICAL_JWT_NAME, INFISICAL_OIDC_AUTH_JWT_NAME}) + if err != nil { + return infisicalSdk.MachineIdentityCredential{}, err + } + + return a.infisicalClient.Auth().OidcAuthLogin(identityId, jwt) +} diff --git a/cli/packages/util/constants.go b/cli/packages/util/constants.go index 8b4c586e6..68fda6d50 100644 --- a/cli/packages/util/constants.go +++ b/cli/packages/util/constants.go @@ -24,7 +24,10 @@ const ( INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH_NAME = "INFISICAL_GCP_IAM_SERVICE_ACCOUNT_KEY_FILE_PATH" // OIDC Auth - INFISICAL_OIDC_AUTH_JWT_NAME = "INFISICAL_OIDC_AUTH_JWT" + INFISICAL_OIDC_AUTH_JWT_NAME = "INFISICAL_OIDC_AUTH_JWT" // deprecated in favor of INFISICAL_JWT + + // JWT AUTH + INFISICAL_JWT_NAME = "INFISICAL_JWT" // Generic env variable used for auth methods that require a machine identity ID INFISICAL_MACHINE_IDENTITY_ID_NAME = "INFISICAL_MACHINE_IDENTITY_ID" diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index 153a5a281..ceb0792f1 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -292,13 +292,18 @@ func GetEnvVarOrFileContent(envName string, filePath string) (string, error) { return fileContent, nil } -func GetCmdFlagOrEnv(cmd *cobra.Command, flag, envName string) (string, error) { +func GetCmdFlagOrEnv(cmd *cobra.Command, flag string, envNames []string) (string, error) { value, flagsErr := cmd.Flags().GetString(flag) if flagsErr != nil { return "", flagsErr } if value == "" { - value = os.Getenv(envName) + for _, env := range envNames { + value = os.Getenv(env) + if value != "" { + break + } + } } if value == "" { return "", fmt.Errorf("please provide %s flag", flag) From 6ae7b5e996cc1b7b74e4094a0076041bca7d9570 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 3 Jun 2025 22:24:27 +0400 Subject: [PATCH 02/14] cleanup --- cli/go.mod | 4 +--- cli/go.sum | 2 ++ cli/packages/cmd/gateway.go | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cli/go.mod b/cli/go.mod index 1b44d9c9d..fc7322f61 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -2,8 +2,6 @@ module github.com/Infisical/infisical-merge go 1.23.0 -replace github.com/infisical/go-sdk => ../../go-sdk - toolchain go1.23.5 require ( @@ -16,7 +14,7 @@ require ( github.com/fatih/semgroup v1.2.0 github.com/gitleaks/go-gitdiff v0.9.1 github.com/h2non/filetype v1.1.3 - github.com/infisical/go-sdk v0.5.94 + github.com/infisical/go-sdk v0.5.95 github.com/infisical/infisical-kmip v0.3.5 github.com/mattn/go-isatty v0.0.20 github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a diff --git a/cli/go.sum b/cli/go.sum index 957fedb05..aa8dc1f61 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -296,6 +296,8 @@ github.com/infisical/go-sdk v0.5.92 h1:PoCnVndrd6Dbkipuxl9fFiwlD5vCKsabtQo09mo8l github.com/infisical/go-sdk v0.5.92/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= github.com/infisical/go-sdk v0.5.94 h1:wKBj+KpJEe+ZzOJ7koXQZDR0dLL9bt0Kqgf/1q+7tG4= github.com/infisical/go-sdk v0.5.94/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= +github.com/infisical/go-sdk v0.5.95 h1:so0YwPofbT7j6Ao8Xcxee/o3ia33meuEVDU2vWr9yfs= +github.com/infisical/go-sdk v0.5.95/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= github.com/infisical/infisical-kmip v0.3.5 h1:QM3s0e18B+mYv3a9HQNjNAlbwZJBzXq5BAJM2scIeiE= github.com/infisical/infisical-kmip v0.3.5/go.mod h1:bO1M4YtKyutNg1bREPmlyZspC5duSR7hyQ3lPmLzrIs= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= diff --git a/cli/packages/cmd/gateway.go b/cli/packages/cmd/gateway.go index 3e6e268d9..90710154e 100644 --- a/cli/packages/cmd/gateway.go +++ b/cli/packages/cmd/gateway.go @@ -36,12 +36,9 @@ func getInfisicalSdkInstance(cmd *cobra.Command) (infisicalSdk.InfisicalClientIn return nil, nil, err } - fmt.Printf("token: %+v\n", token) - // if the --token param is set, we use it directly for authentication if token != nil { infisicalClient.Auth().SetAccessToken(token.Token) - fmt.Printf("token from client: %+v\n", infisicalClient.Auth().GetAccessToken()) return infisicalClient, cancel, nil } From 07902f7db9281607b53d25b509b9f966e9de6416 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 04:42:15 +0400 Subject: [PATCH 03/14] feat(identities/kubernetes-auth): use gateway as token reviewer --- ...entity-kubernetes-auth-gateway-reviewer.ts | 23 ++ .../db/schemas/identity-kubernetes-auths.ts | 1 + .../ee/services/audit-log/audit-log-types.ts | 3 + .../dynamic-secret/providers/kubernetes.ts | 3 +- .../dynamic-secret/providers/sql-database.ts | 3 +- backend/src/lib/api-docs/constants.ts | 4 + backend/src/lib/gateway/index.ts | 63 +++++- .../v1/identity-kubernetes-auth-router.ts | 58 ++++- .../identity-kubernetes-auth-service.ts | 187 +++++++++++++--- .../identity-kubernetes-auth-types.ts | 7 + cli/packages/gateway/connection.go | 164 ++++++++++++++ .../src/hooks/api/identities/mutations.tsx | 12 +- frontend/src/hooks/api/identities/types.ts | 8 + .../IdentityKubernetesAuthForm.tsx | 205 ++++++++++++------ 14 files changed, 615 insertions(+), 126 deletions(-) create mode 100644 backend/src/db/migrations/20250604174128_identity-kubernetes-auth-gateway-reviewer.ts diff --git a/backend/src/db/migrations/20250604174128_identity-kubernetes-auth-gateway-reviewer.ts b/backend/src/db/migrations/20250604174128_identity-kubernetes-auth-gateway-reviewer.ts new file mode 100644 index 000000000..da5493153 --- /dev/null +++ b/backend/src/db/migrations/20250604174128_identity-kubernetes-auth-gateway-reviewer.ts @@ -0,0 +1,23 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasTokenReviewModeColumn = await knex.schema.hasColumn(TableName.IdentityKubernetesAuth, "tokenReviewMode"); + + if (!hasTokenReviewModeColumn) { + await knex.schema.alterTable(TableName.IdentityKubernetesAuth, (table) => { + table.string("tokenReviewMode").notNullable().defaultTo("api"); + }); + } +} + +export async function down(knex: Knex): Promise { + const hasTokenReviewModeColumn = await knex.schema.hasColumn(TableName.IdentityKubernetesAuth, "tokenReviewMode"); + + if (hasTokenReviewModeColumn) { + await knex.schema.alterTable(TableName.IdentityKubernetesAuth, (table) => { + table.dropColumn("tokenReviewMode"); + }); + } +} diff --git a/backend/src/db/schemas/identity-kubernetes-auths.ts b/backend/src/db/schemas/identity-kubernetes-auths.ts index 00d1fd771..880928247 100644 --- a/backend/src/db/schemas/identity-kubernetes-auths.ts +++ b/backend/src/db/schemas/identity-kubernetes-auths.ts @@ -31,6 +31,7 @@ export const IdentityKubernetesAuthsSchema = z.object({ encryptedKubernetesTokenReviewerJwt: zodBuffer.nullable().optional(), encryptedKubernetesCaCertificate: zodBuffer.nullable().optional(), gatewayId: z.string().uuid().nullable().optional(), + tokenReviewMode: z.string().default("api"), accessTokenPeriod: z.coerce.number().default(0) }); diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index bd500b377..2d6bc7c06 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -23,6 +23,7 @@ import { ActorType } from "@app/services/auth/auth-type"; import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types"; import { CaStatus } from "@app/services/certificate-authority/certificate-authority-enums"; import { TIdentityTrustedIp } from "@app/services/identity/identity-types"; +import { IdentityKubernetesAuthTokenReviewMode } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-types"; import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-auth-types"; import { PkiItemType } from "@app/services/pki-collection/pki-collection-types"; import { SecretSync, SecretSyncImportBehavior } from "@app/services/secret-sync/secret-sync-enums"; @@ -853,6 +854,7 @@ interface AddIdentityKubernetesAuthEvent { metadata: { identityId: string; kubernetesHost: string; + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces: string; allowedNames: string; accessTokenTTL: number; @@ -874,6 +876,7 @@ interface UpdateIdentityKubernetesAuthEvent { metadata: { identityId: string; kubernetesHost?: string; + tokenReviewMode?: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces?: string; allowedNames?: string; accessTokenTTL?: number; diff --git a/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts b/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts index 8a54ba089..eeea7e4be 100644 --- a/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts +++ b/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts @@ -2,7 +2,7 @@ import axios from "axios"; import https from "https"; import { InternalServerError } from "@app/lib/errors"; -import { withGatewayProxy } from "@app/lib/gateway"; +import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; import { TKubernetesTokenRequest } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-types"; @@ -43,6 +43,7 @@ export const KubernetesProvider = ({ gatewayService }: TKubernetesProviderDTO): return res; }, { + protocol: ProxyProtocol.Tcp, targetHost: inputs.targetHost, targetPort: inputs.targetPort, relayHost, diff --git a/backend/src/ee/services/dynamic-secret/providers/sql-database.ts b/backend/src/ee/services/dynamic-secret/providers/sql-database.ts index ce16a1237..f5299687b 100644 --- a/backend/src/ee/services/dynamic-secret/providers/sql-database.ts +++ b/backend/src/ee/services/dynamic-secret/providers/sql-database.ts @@ -3,7 +3,7 @@ import handlebars from "handlebars"; import knex from "knex"; import { z } from "zod"; -import { withGatewayProxy } from "@app/lib/gateway"; +import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; @@ -185,6 +185,7 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO) await gatewayCallback("localhost", port); }, { + protocol: ProxyProtocol.Tcp, targetHost: providerInputs.host, targetPort: providerInputs.port, relayHost, diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 5dcc812ad..8467f7fe6 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -393,6 +393,8 @@ export const KUBERNETES_AUTH = { caCert: "The PEM-encoded CA cert for the Kubernetes API server.", tokenReviewerJwt: "Optional JWT token for accessing Kubernetes TokenReview API. If provided, this long-lived token will be used to validate service account tokens during authentication. If omitted, the client's own JWT will be used instead, which requires the client to have the system:auth-delegator ClusterRole binding.", + tokenReviewMode: + "The mode to use for token review. Must be one of: 'api', 'gateway'. If gateway is selected, the gateway must be deployed in Kubernetes, and the gateway must have the system:auth-delegator ClusterRole binding.", allowedNamespaces: "The comma-separated list of trusted namespaces that service accounts must belong to authenticate with Infisical.", allowedNames: "The comma-separated list of trusted service account names that can authenticate with Infisical.", @@ -410,6 +412,8 @@ export const KUBERNETES_AUTH = { caCert: "The new PEM-encoded CA cert for the Kubernetes API server.", tokenReviewerJwt: "Optional JWT token for accessing Kubernetes TokenReview API. If provided, this long-lived token will be used to validate service account tokens during authentication. If omitted, the client's own JWT will be used instead, which requires the client to have the system:auth-delegator ClusterRole binding.", + tokenReviewMode: + "The mode to use for token review. Must be one of: 'api', 'gateway'. If gateway is selected, the gateway must be deployed in Kubernetes, and the gateway must have the system:auth-delegator ClusterRole binding.", allowedNamespaces: "The new comma-separated list of trusted namespaces that service accounts must belong to authenticate with Infisical.", allowedNames: "The new comma-separated list of trusted service account names that can authenticate with Infisical.", diff --git a/backend/src/lib/gateway/index.ts b/backend/src/lib/gateway/index.ts index 4d6401eac..9ec6a471e 100644 --- a/backend/src/lib/gateway/index.ts +++ b/backend/src/lib/gateway/index.ts @@ -4,6 +4,7 @@ import net from "node:net"; import quicDefault, * as quicModule from "@infisical/quic"; import axios from "axios"; +import https from "https"; import { BadRequestError } from "../errors"; import { logger } from "../logger"; @@ -148,6 +149,11 @@ interface TProxyServer { getProxyError: () => string; } +export enum ProxyProtocol { + Http = "http", + Tcp = "tcp" +} + const setupProxyServer = async ({ targetPort, targetHost, @@ -155,7 +161,9 @@ const setupProxyServer = async ({ relayHost, relayPort, identityId, - orgId + orgId, + protocol = ProxyProtocol.Tcp, + httpsAgent }: { targetHost: string; targetPort: number; @@ -164,6 +172,8 @@ const setupProxyServer = async ({ tlsOptions: TTlsOption; identityId: string; orgId: string; + protocol?: ProxyProtocol; + httpsAgent?: https.Agent; }): Promise => { const quicClient = await createQuicConnection(relayHost, relayPort, tlsOptions, identityId, orgId).catch((err) => { throw new BadRequestError({ @@ -184,9 +194,42 @@ const setupProxyServer = async ({ clientConn.setNoDelay(true); const stream = quicClient.connection.newStream("bidi"); - // Send FORWARD-TCP command + const forwardWriter = stream.writable.getWriter(); - await forwardWriter.write(Buffer.from(`FORWARD-TCP ${targetHost}:${targetPort}\n`)); + let command: string; + + if (protocol === ProxyProtocol.Http) { + const targetUrl = `${targetHost}:${targetPort}`; // note(daniel): targetHost MUST include the scheme (https|http) + command = `FORWARD-HTTP ${targetUrl}`; + logger.debug(`Using HTTP proxy mode: ${command.trim()}`); + + // extract ca certificate from httpsAgent if present + if (httpsAgent && targetHost.startsWith("https://")) { + const agentOptions = httpsAgent.options; + if (agentOptions && agentOptions.ca) { + const caCert = Array.isArray(agentOptions.ca) ? agentOptions.ca.join("\n") : agentOptions.ca; + const caB64 = Buffer.from(caCert as string).toString("base64"); + command += ` ca=${caB64}`; + + const rejectUnauthorized = agentOptions.rejectUnauthorized !== false; + command += ` verify=${rejectUnauthorized}`; + + logger.debug(`Using HTTP proxy mode [command=${command.trim()}]`); + } + } + + command += "\n"; + } else if (protocol === ProxyProtocol.Tcp) { + // For TCP mode, send FORWARD-TCP with host:port + command = `FORWARD-TCP ${targetHost}:${targetPort}\n`; + logger.debug(`Using TCP proxy mode: ${command.trim()}`); + } else { + throw new BadRequestError({ + message: `Invalid protocol: ${protocol as string}` + }); + } + + await forwardWriter.write(Buffer.from(command)); forwardWriter.releaseLock(); // Set up bidirectional copy @@ -320,7 +363,7 @@ const setupProxyServer = async ({ return; } - logger.info("Gateway proxy started"); + logger.info(`Gateway proxy started on port ${address.port} (${protocol} mode)`); resolve({ server, port: address.port, @@ -351,13 +394,15 @@ interface ProxyOptions { tlsOptions: TTlsOption; identityId: string; orgId: string; + protocol: ProxyProtocol; + httpsAgent?: https.Agent; } export const withGatewayProxy = async ( - callback: (port: number) => Promise, + callback: (port: number, httpsAgent?: https.Agent) => Promise, options: ProxyOptions ): Promise => { - const { relayHost, relayPort, targetHost, targetPort, tlsOptions, identityId, orgId } = options; + const { relayHost, relayPort, targetHost, targetPort, tlsOptions, identityId, orgId, protocol, httpsAgent } = options; // Setup the proxy server const { port, cleanup, getProxyError } = await setupProxyServer({ @@ -367,12 +412,14 @@ export const withGatewayProxy = async ( relayHost, tlsOptions, identityId, - orgId + orgId, + protocol, + httpsAgent }); try { // Execute the callback with the allocated port - return await callback(port); + return await callback(port, httpsAgent); } catch (err) { const proxyErrorMessage = getProxyError(); if (proxyErrorMessage) { diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index d9ef62087..3e244717d 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -8,6 +8,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; import { TIdentityTrustedIp } from "@app/services/identity/identity-types"; +import { IdentityKubernetesAuthTokenReviewMode } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-types"; import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns"; const IdentityKubernetesAuthResponseSchema = IdentityKubernetesAuthsSchema.pick({ @@ -18,6 +19,7 @@ const IdentityKubernetesAuthResponseSchema = IdentityKubernetesAuthsSchema.pick( accessTokenTrustedIps: true, createdAt: true, updatedAt: true, + tokenReviewMode: true, identityId: true, kubernetesHost: true, allowedNamespaces: true, @@ -124,6 +126,10 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide ), caCert: z.string().trim().default("").describe(KUBERNETES_AUTH.ATTACH.caCert), tokenReviewerJwt: z.string().trim().optional().describe(KUBERNETES_AUTH.ATTACH.tokenReviewerJwt), + tokenReviewMode: z + .nativeEnum(IdentityKubernetesAuthTokenReviewMode) + .default(IdentityKubernetesAuthTokenReviewMode.Api) + .describe(KUBERNETES_AUTH.ATTACH.tokenReviewMode), allowedNamespaces: z.string().describe(KUBERNETES_AUTH.ATTACH.allowedNamespaces), // TODO: validation allowedNames: z.string().describe(KUBERNETES_AUTH.ATTACH.allowedNames), allowedAudience: z.string().describe(KUBERNETES_AUTH.ATTACH.allowedAudience), @@ -157,10 +163,22 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide .default(0) .describe(KUBERNETES_AUTH.ATTACH.accessTokenNumUsesLimit) }) - .refine( - (val) => val.accessTokenTTL <= val.accessTokenMaxTTL, - "Access Token TTL cannot be greater than Access Token Max TTL." - ), + .superRefine((data, ctx) => { + if (data.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway && !data.gatewayId) { + ctx.addIssue({ + path: ["gatewayId"], + code: z.ZodIssueCode.custom, + message: "When token review mode is set to Gateway, a gateway must be selected" + }); + } + if (data.accessTokenTTL > data.accessTokenMaxTTL) { + ctx.addIssue({ + path: ["accessTokenTTL"], + code: z.ZodIssueCode.custom, + message: "Access Token TTL cannot be greater than Access Token Max TTL." + }); + } + }), response: { 200: z.object({ identityKubernetesAuth: IdentityKubernetesAuthResponseSchema @@ -186,6 +204,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide metadata: { identityId: identityKubernetesAuth.identityId, kubernetesHost: identityKubernetesAuth.kubernetesHost, + tokenReviewMode: identityKubernetesAuth.tokenReviewMode, allowedNamespaces: identityKubernetesAuth.allowedNamespaces, allowedNames: identityKubernetesAuth.allowedNames, accessTokenTTL: identityKubernetesAuth.accessTokenTTL, @@ -247,6 +266,10 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide ), caCert: z.string().trim().optional().describe(KUBERNETES_AUTH.UPDATE.caCert), tokenReviewerJwt: z.string().trim().nullable().optional().describe(KUBERNETES_AUTH.UPDATE.tokenReviewerJwt), + tokenReviewMode: z + .nativeEnum(IdentityKubernetesAuthTokenReviewMode) + .optional() + .describe(KUBERNETES_AUTH.UPDATE.tokenReviewMode), allowedNamespaces: z.string().optional().describe(KUBERNETES_AUTH.UPDATE.allowedNamespaces), // TODO: validation allowedNames: z.string().optional().describe(KUBERNETES_AUTH.UPDATE.allowedNames), allowedAudience: z.string().optional().describe(KUBERNETES_AUTH.UPDATE.allowedAudience), @@ -280,10 +303,27 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide .optional() .describe(KUBERNETES_AUTH.UPDATE.accessTokenMaxTTL) }) - .refine( - (val) => (val.accessTokenMaxTTL && val.accessTokenTTL ? val.accessTokenTTL <= val.accessTokenMaxTTL : true), - "Access Token TTL cannot be greater than Access Token Max TTL." - ), + .superRefine((data, ctx) => { + if ( + data.tokenReviewMode && + data.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway && + !data.gatewayId && + data.tokenReviewMode !== undefined + ) { + ctx.addIssue({ + path: ["gatewayId"], + code: z.ZodIssueCode.custom, + message: "When token review mode is set to Gateway, a gateway must be selected" + }); + } + if (data.accessTokenMaxTTL && data.accessTokenTTL ? data.accessTokenTTL <= data.accessTokenMaxTTL : true) { + ctx.addIssue({ + path: ["accessTokenTTL"], + code: z.ZodIssueCode.custom, + message: "Access Token TTL cannot be greater than Access Token Max TTL." + }); + } + }), response: { 200: z.object({ identityKubernetesAuth: IdentityKubernetesAuthResponseSchema @@ -308,6 +348,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide metadata: { identityId: identityKubernetesAuth.identityId, kubernetesHost: identityKubernetesAuth.kubernetesHost, + tokenReviewMode: identityKubernetesAuth.tokenReviewMode, + tokenReviewerJwt: identityKubernetesAuth.tokenReviewerJwt, allowedNamespaces: identityKubernetesAuth.allowedNamespaces, allowedNames: identityKubernetesAuth.allowedNames, accessTokenTTL: identityKubernetesAuth.accessTokenTTL, diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 3314d8cab..bb24ddf62 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -20,8 +20,9 @@ import { import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors"; -import { withGatewayProxy } from "@app/lib/gateway"; +import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; +import { logger } from "@app/lib/logger"; import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityOrgDALFactory } from "../identity/identity-org-dal"; @@ -33,6 +34,7 @@ import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/su import { TIdentityKubernetesAuthDALFactory } from "./identity-kubernetes-auth-dal"; import { extractK8sUsername } from "./identity-kubernetes-auth-fns"; import { + IdentityKubernetesAuthTokenReviewMode, TAttachKubernetesAuthDTO, TCreateTokenReviewResponse, TGetKubernetesAuthDTO, @@ -72,19 +74,25 @@ export const identityKubernetesAuthServiceFactory = ({ gatewayId: string; targetHost: string; targetPort: number; + caCert?: string; + reviewTokenThroughGateway: boolean; }, - gatewayCallback: (host: string, port: number) => Promise + gatewayCallback: (host: string, port: number, httpsAgent?: https.Agent) => Promise ): Promise => { const relayDetails = await gatewayService.fnGetGatewayClientTlsByGatewayId(inputs.gatewayId); const [relayHost, relayPort] = relayDetails.relayAddress.split(":"); const callbackResult = await withGatewayProxy( - async (port) => { - // Needs to be https protocol or the kubernetes API server will fail with "Client sent an HTTP request to an HTTPS server" - const res = await gatewayCallback("https://localhost", port); + async (port, httpsAgent) => { + const res = await gatewayCallback( + inputs.reviewTokenThroughGateway ? "http://localhost" : "https://localhost", + port, + httpsAgent + ); return res; }, { + protocol: inputs.reviewTokenThroughGateway ? ProxyProtocol.Http : ProxyProtocol.Tcp, targetHost: inputs.targetHost, targetPort: inputs.targetPort, relayHost, @@ -95,7 +103,12 @@ export const identityKubernetesAuthServiceFactory = ({ ca: relayDetails.certChain, cert: relayDetails.certificate, key: relayDetails.privateKey.toString() - } + }, + // we always pass this, because its needed for both tcp and http protocol + httpsAgent: new https.Agent({ + ca: inputs.caCert, + rejectUnauthorized: !!inputs.caCert + }) } ); @@ -129,17 +142,30 @@ export const identityKubernetesAuthServiceFactory = ({ caCert = decryptor({ cipherTextBlob: identityKubernetesAuth.encryptedKubernetesCaCertificate }).toString(); } - let tokenReviewerJwt = ""; - if (identityKubernetesAuth.encryptedKubernetesTokenReviewerJwt) { - tokenReviewerJwt = decryptor({ - cipherTextBlob: identityKubernetesAuth.encryptedKubernetesTokenReviewerJwt - }).toString(); - } else { - // if no token reviewer is provided means the incoming token has to act as reviewer - tokenReviewerJwt = serviceAccountJwt; - } + const tokenReviewCallbackRaw = async (host: string = identityKubernetesAuth.kubernetesHost, port?: number) => { + logger.info({ host, port }, "tokenReviewCallbackRaw: Processing kubernetes token review using raw API"); + let tokenReviewerJwt = ""; + if (identityKubernetesAuth.encryptedKubernetesTokenReviewerJwt) { + tokenReviewerJwt = decryptor({ + cipherTextBlob: identityKubernetesAuth.encryptedKubernetesTokenReviewerJwt + }).toString(); + } else { + // if no token reviewer is provided means the incoming token has to act as reviewer + tokenReviewerJwt = serviceAccountJwt; + } + + let servername = identityKubernetesAuth.kubernetesHost; + if (servername.startsWith("https://") || servername.startsWith("http://")) { + servername = new RE2("^https?:\\/\\/").replace(servername, ""); + } + // get the last colon index, if it has a port, remove it, including the colon + const lastColonIndex = servername.lastIndexOf(":"); + if (lastColonIndex !== -1) { + servername = servername.substring(0, lastColonIndex); + } + + console.log("servername", servername); - const tokenReviewCallback = async (host: string = identityKubernetesAuth.kubernetesHost, port?: number) => { const baseUrl = port ? `${host}:${port}` : host; const res = await axios @@ -160,10 +186,10 @@ export const identityKubernetesAuthServiceFactory = ({ }, signal: AbortSignal.timeout(10000), timeout: 10000, - // if ca cert, rejectUnauthorized: true httpsAgent: new https.Agent({ ca: caCert, - rejectUnauthorized: !!caCert + rejectUnauthorized: Boolean(caCert), + servername }) } ) @@ -186,24 +212,115 @@ export const identityKubernetesAuthServiceFactory = ({ return res.data; }; - let { kubernetesHost } = identityKubernetesAuth; + const tokenReviewCallbackThroughGateway = async ( + host: string = identityKubernetesAuth.kubernetesHost, + port?: number, + httpsAgent?: https.Agent + ) => { + logger.info( + { + host, + port + }, + "tokenReviewCallbackThroughGateway: Processing kubernetes token review using gateway" + ); - if (kubernetesHost.startsWith("https://") || kubernetesHost.startsWith("http://")) { - kubernetesHost = new RE2("^https?:\\/\\/").replace(kubernetesHost, ""); + const baseUrl = port ? `${host}:${port}` : host; + + const res = await axios + .post( + `${baseUrl}/apis/authentication.k8s.io/v1/tokenreviews`, + { + apiVersion: "authentication.k8s.io/v1", + kind: "TokenReview", + spec: { + token: serviceAccountJwt, + ...(identityKubernetesAuth.allowedAudience ? { audiences: [identityKubernetesAuth.allowedAudience] } : {}) + } + }, + { + headers: { + "Content-Type": "application/json", + "x-infisical-action": "inject-k8s-sa-auth-token" + }, + signal: AbortSignal.timeout(10000), + timeout: 10000, + ...(httpsAgent ? { httpsAgent } : {}) + } + ) + .catch((err) => { + if (err instanceof AxiosError) { + if (err.response) { + const { message } = err?.response?.data as unknown as { message?: string }; + + if (message) { + throw new UnauthorizedError({ + message, + name: "KubernetesTokenReviewRequestError" + }); + } + } + } + throw err; + }); + + return res.data; + }; + + let data: TCreateTokenReviewResponse | undefined; + + if (identityKubernetesAuth.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway) { + const { kubernetesHost } = identityKubernetesAuth; + const lastColonIndex = kubernetesHost.lastIndexOf(":"); + const k8sHost = kubernetesHost.substring(0, lastColonIndex); + const k8sPort = kubernetesHost.substring(lastColonIndex + 1); + + if (!identityKubernetesAuth.gatewayId) { + throw new BadRequestError({ + message: "Gateway ID is required when token review mode is set to Gateway" + }); + } + + data = await $gatewayProxyWrapper( + { + gatewayId: identityKubernetesAuth.gatewayId, + targetHost: k8sHost, // note(daniel): must include the protocol (https|http) + targetPort: k8sPort ? Number(k8sPort) : 443, + caCert, + reviewTokenThroughGateway: true + }, + tokenReviewCallbackThroughGateway + ); + } else if (identityKubernetesAuth.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Api) { + let { kubernetesHost } = identityKubernetesAuth; + if (kubernetesHost.startsWith("https://") || kubernetesHost.startsWith("http://")) { + kubernetesHost = new RE2("^https?:\\/\\/").replace(kubernetesHost, ""); + } + + const [k8sHost, k8sPort] = kubernetesHost.split(":"); + + data = identityKubernetesAuth.gatewayId + ? await $gatewayProxyWrapper( + { + gatewayId: identityKubernetesAuth.gatewayId, + targetHost: k8sHost, + targetPort: k8sPort ? Number(k8sPort) : 443, + reviewTokenThroughGateway: false + }, + tokenReviewCallbackRaw + ) + : await tokenReviewCallbackRaw(); + } else { + throw new BadRequestError({ + message: `Invalid token review mode: ${identityKubernetesAuth.tokenReviewMode}` + }); } - const [k8sHost, k8sPort] = kubernetesHost.split(":"); - - const data = identityKubernetesAuth.gatewayId - ? await $gatewayProxyWrapper( - { - gatewayId: identityKubernetesAuth.gatewayId, - targetHost: k8sHost, - targetPort: k8sPort ? Number(k8sPort) : 443 - }, - tokenReviewCallback - ) - : await tokenReviewCallback(); + if (!data) { + throw new BadRequestError({ + message: "Failed to review token" + }); + } if ("error" in data.status) throw new UnauthorizedError({ message: data.status.error, name: "KubernetesTokenReviewError" }); @@ -298,6 +415,7 @@ export const identityKubernetesAuthServiceFactory = ({ kubernetesHost, caCert, tokenReviewerJwt, + tokenReviewMode, allowedNamespaces, allowedNames, allowedAudience, @@ -384,6 +502,7 @@ export const identityKubernetesAuthServiceFactory = ({ { identityId: identityMembershipOrg.identityId, kubernetesHost, + tokenReviewMode, allowedNamespaces, allowedNames, allowedAudience, @@ -410,6 +529,7 @@ export const identityKubernetesAuthServiceFactory = ({ kubernetesHost, caCert, tokenReviewerJwt, + tokenReviewMode, allowedNamespaces, allowedNames, allowedAudience, @@ -492,6 +612,7 @@ export const identityKubernetesAuthServiceFactory = ({ const updateQuery: TIdentityKubernetesAuthsUpdate = { kubernetesHost, + tokenReviewMode, allowedNamespaces, allowedNames, allowedAudience, diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts index 12edd266f..03dd7fd77 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts @@ -5,11 +5,17 @@ export type TLoginKubernetesAuthDTO = { jwt: string; }; +export enum IdentityKubernetesAuthTokenReviewMode { + Api = "api", + Gateway = "gateway" +} + export type TAttachKubernetesAuthDTO = { identityId: string; kubernetesHost: string; caCert: string; tokenReviewerJwt?: string; + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces: string; allowedNames: string; allowedAudience: string; @@ -26,6 +32,7 @@ export type TUpdateKubernetesAuthDTO = { kubernetesHost?: string; caCert?: string; tokenReviewerJwt?: string | null; + tokenReviewMode?: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces?: string; allowedNames?: string; allowedAudience?: string; diff --git a/cli/packages/gateway/connection.go b/cli/packages/gateway/connection.go index 58a0503ff..78f614f62 100644 --- a/cli/packages/gateway/connection.go +++ b/cli/packages/gateway/connection.go @@ -4,11 +4,18 @@ import ( "bufio" "bytes" "context" + "crypto/tls" + "crypto/x509" + "encoding/base64" "errors" + "fmt" "io" "net" + "net/http" + "os" "strings" "sync" + "time" "github.com/quic-go/quic-go" "github.com/rs/zerolog/log" @@ -89,6 +96,34 @@ func handleStream(stream quic.Stream, quicConn quic.Connection) { CopyDataFromQuicToTcp(stream, destTarget) log.Info().Msgf("Ending secure transmission between %s->%s", quicConn.LocalAddr().String(), destTarget.LocalAddr().String()) return + + case "FORWARD-HTTP": + argParts := bytes.Split(args, []byte(" ")) + if len(argParts) == 0 { + log.Error().Msg("FORWARD-HTTP requires target URL") + return + } + + targetURL := string(argParts[0]) + + // Parse optional parameters + var caCertB64, verifyParam string + for _, part := range argParts[1:] { + partStr := string(part) + if strings.HasPrefix(partStr, "ca=") { + caCertB64 = strings.TrimPrefix(partStr, "ca=") + } else if strings.HasPrefix(partStr, "verify=") { + verifyParam = strings.TrimPrefix(partStr, "verify=") + } + } + + log.Info().Msgf("Starting HTTP proxy to: %s", targetURL) + + if err := handleHTTPProxy(stream, reader, targetURL, caCertB64, verifyParam); err != nil { + log.Error().Msgf("HTTP proxy error: %v", err) + } + return + case "PING": if _, err := stream.Write([]byte("PONG\n")); err != nil { log.Error().Msgf("Error writing PONG response: %v", err) @@ -100,6 +135,135 @@ func handleStream(stream quic.Stream, quicConn quic.Connection) { } } } +func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string, caCertB64 string, verifyParam string) error { + transport := &http.Transport{ + DisableKeepAlives: false, + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + } + + if strings.HasPrefix(targetURL, "https://") { + tlsConfig := &tls.Config{} + + if caCertB64 != "" { + caCert, err := base64.StdEncoding.DecodeString(caCertB64) + if err == nil { + caCertPool := x509.NewCertPool() + if caCertPool.AppendCertsFromPEM(caCert) { + tlsConfig.RootCAs = caCertPool + log.Info().Msg("Using provided CA certificate from gateway client") + } else { + log.Error().Msg("Failed to parse provided CA certificate") + } + } else { + log.Error().Msgf("Failed to decode CA certificate: %v", err) + } + } + + // set certificate verification based on what the gateway client sent + if verifyParam != "" { + tlsConfig.InsecureSkipVerify = verifyParam == "false" + log.Info().Msgf("TLS verification set to: %s", verifyParam) + } + + transport.TLSClientConfig = tlsConfig + } + + // read and parse the http request from the stream + req, err := http.ReadRequest(reader) + if err != nil { + return fmt.Errorf("failed to read HTTP request: %v", err) + } + + actionHeader := req.Header.Get("x-infisical-action") + if actionHeader != "" { + + if actionHeader == "inject-k8s-sa-auth-token" { + token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") + + if err != nil { + stream.Write([]byte(buildHttpInternalServerError("failed to read k8s sa auth token"))) + return fmt.Errorf("failed to read k8s sa auth token: %v", err) + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(token))) + log.Info().Msgf("Injected gateway k8s SA auth token in request to %s", targetURL) + } + + req.Header.Del("x-infisical-action") + } + + var targetFullURL string + if strings.HasPrefix(targetURL, "http://") || strings.HasPrefix(targetURL, "https://") { + baseURL := strings.TrimSuffix(targetURL, "/") + targetFullURL = baseURL + req.URL.Path + if req.URL.RawQuery != "" { + targetFullURL += "?" + req.URL.RawQuery + } + } else { + baseURL := strings.TrimSuffix("http://"+targetURL, "/") + targetFullURL = baseURL + req.URL.Path + if req.URL.RawQuery != "" { + targetFullURL += "?" + req.URL.RawQuery + } + } + + // create the request to the target + proxyReq, err := http.NewRequest(req.Method, targetFullURL, req.Body) + if err != nil { + return fmt.Errorf("failed to create proxy request: %v", err) + } + + // copy headers + for name, values := range req.Header { + for _, value := range values { + proxyReq.Header.Add(name, value) + } + } + + log.Info().Msgf("Proxying %s %s to %s", req.Method, req.URL.Path, targetFullURL) + + client := &http.Client{ + Transport: transport, + Timeout: 30 * time.Second, + } + + // make the request to the target + resp, err := client.Do(proxyReq) + if err != nil { + stream.Write([]byte(buildHttpInternalServerError(fmt.Sprintf("failed to reach target due to networking error: %s", err.Error())))) + return fmt.Errorf("failed to reach target due to networking error: %v", err) + } + defer resp.Body.Close() + + // write response to stream + statusLine := fmt.Sprintf("HTTP/1.1 %d %s\r\n", resp.StatusCode, resp.Status[4:]) + if _, err := stream.Write([]byte(statusLine)); err != nil { + return err + } + + // write headers again + for name, values := range resp.Header { + for _, value := range values { + headerLine := fmt.Sprintf("%s: %s\r\n", name, value) + if _, err := stream.Write([]byte(headerLine)); err != nil { + return err + } + } + } + + // write empty line to end headers + if _, err := stream.Write([]byte("\r\n")); err != nil { + return err + } + + _, err = io.Copy(stream, resp.Body) + return err +} + +func buildHttpInternalServerError(message string) string { + return fmt.Sprintf("HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\n\r\n{\"message\": \"gateway: %s\"}", message) +} type CloseWrite interface { CloseWrite() error diff --git a/frontend/src/hooks/api/identities/mutations.tsx b/frontend/src/hooks/api/identities/mutations.tsx index c08081f11..a7bd88ce9 100644 --- a/frontend/src/hooks/api/identities/mutations.tsx +++ b/frontend/src/hooks/api/identities/mutations.tsx @@ -843,7 +843,8 @@ export const useAddIdentityKubernetesAuth = () => { accessTokenMaxTTL, accessTokenNumUsesLimit, accessTokenTrustedIps, - gatewayId + gatewayId, + tokenReviewMode }) => { const { data: { identityKubernetesAuth } @@ -860,7 +861,8 @@ export const useAddIdentityKubernetesAuth = () => { accessTokenMaxTTL, accessTokenNumUsesLimit, accessTokenTrustedIps, - gatewayId + gatewayId, + tokenReviewMode } ); @@ -950,7 +952,8 @@ export const useUpdateIdentityKubernetesAuth = () => { accessTokenMaxTTL, accessTokenNumUsesLimit, accessTokenTrustedIps, - gatewayId + gatewayId, + tokenReviewMode }) => { const { data: { identityKubernetesAuth } @@ -967,7 +970,8 @@ export const useUpdateIdentityKubernetesAuth = () => { accessTokenMaxTTL, accessTokenNumUsesLimit, accessTokenTrustedIps, - gatewayId + gatewayId, + tokenReviewMode } ); diff --git a/frontend/src/hooks/api/identities/types.ts b/frontend/src/hooks/api/identities/types.ts index c26466213..f5e0f1065 100644 --- a/frontend/src/hooks/api/identities/types.ts +++ b/frontend/src/hooks/api/identities/types.ts @@ -379,10 +379,16 @@ export type DeleteIdentityAzureAuthDTO = { identityId: string; }; +export enum IdentityKubernetesAuthTokenReviewMode { + Api = "api", + Gateway = "gateway" +} + export type IdentityKubernetesAuth = { identityId: string; kubernetesHost: string; tokenReviewerJwt: string; + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces: string; allowedNames: string; allowedAudience: string; @@ -399,6 +405,7 @@ export type AddIdentityKubernetesAuthDTO = { identityId: string; kubernetesHost: string; tokenReviewerJwt?: string; + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces: string; allowedNames: string; allowedAudience: string; @@ -417,6 +424,7 @@ export type UpdateIdentityKubernetesAuthDTO = { identityId: string; kubernetesHost?: string; tokenReviewerJwt?: string | null; + tokenReviewMode?: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces?: string; allowedNames?: string; allowedAudience?: string; diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx index 369977a04..1b55bc60e 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx @@ -33,13 +33,19 @@ import { useGetIdentityKubernetesAuth, useUpdateIdentityKubernetesAuth } from "@app/hooks/api"; -import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; +import { + IdentityKubernetesAuthTokenReviewMode, + IdentityTrustedIp +} from "@app/hooks/api/identities/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { IdentityFormTab } from "./types"; const schema = z .object({ + tokenReviewMode: z + .nativeEnum(IdentityKubernetesAuthTokenReviewMode) + .default(IdentityKubernetesAuthTokenReviewMode.Api), kubernetesHost: z.string().min(1), tokenReviewerJwt: z.string().optional(), gatewayId: z.string().optional().nullable(), @@ -62,7 +68,15 @@ const schema = z ) .min(1) }) - .required(); + .superRefine((data, ctx) => { + if (data.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway && !data.gatewayId) { + ctx.addIssue({ + path: ["gatewayId"], + code: z.ZodIssueCode.custom, + message: "When token review mode is set to Gateway, a gateway must be selected" + }); + } + }); export type FormData = z.infer; @@ -100,11 +114,14 @@ export const IdentityKubernetesAuthForm = ({ control, handleSubmit, reset, + watch, + setValue, formState: { isSubmitting } } = useForm({ resolver: zodResolver(schema), defaultValues: { + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode.Api, kubernetesHost: "", tokenReviewerJwt: "", allowedNames: "", @@ -128,6 +145,7 @@ export const IdentityKubernetesAuthForm = ({ useEffect(() => { if (data) { reset({ + tokenReviewMode: data.tokenReviewMode, kubernetesHost: data.kubernetesHost, tokenReviewerJwt: data.tokenReviewerJwt, allowedNames: data.allowedNames, @@ -148,6 +166,7 @@ export const IdentityKubernetesAuthForm = ({ }); } else { reset({ + tokenReviewMode: IdentityKubernetesAuthTokenReviewMode.Api, kubernetesHost: "", tokenReviewerJwt: "", allowedNames: "", @@ -173,6 +192,7 @@ export const IdentityKubernetesAuthForm = ({ accessTokenMaxTTL, accessTokenNumUsesLimit, gatewayId, + tokenReviewMode, accessTokenTrustedIps }: FormData) => { try { @@ -189,6 +209,7 @@ export const IdentityKubernetesAuthForm = ({ caCert, identityId, gatewayId: gatewayId || null, + tokenReviewMode, accessTokenTTL: Number(accessTokenTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit), @@ -205,6 +226,7 @@ export const IdentityKubernetesAuthForm = ({ allowedAudience: allowedAudience || "", gatewayId: gatewayId || null, caCert: caCert || "", + tokenReviewMode, accessTokenTTL: Number(accessTokenTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit), @@ -228,6 +250,8 @@ export const IdentityKubernetesAuthForm = ({ } }; + const tokenReviewMode = watch("tokenReviewMode"); + return (
{ @@ -235,6 +259,7 @@ export const IdentityKubernetesAuthForm = ({ [ "kubernetesHost", "tokenReviewerJwt", + "tokenReviewMode", "gatewayId", "accessTokenTTL", "accessTokenMaxTTL", @@ -269,21 +294,114 @@ export const IdentityKubernetesAuthForm = ({ )} /> - ( - +
+ - - - )} - /> + {(isAllowed) => ( + ( + + +
+ +
+
+
+ )} + /> + )} +
+
+ + ( + + + + )} + /> + + + {tokenReviewMode === "api" && ( + ( + + + + )} + /> + )} - - {(isAllowed) => ( - ( - - -
- -
-
-
- )} - /> - )} -
- Date: Thu, 5 Jun 2025 04:45:57 +0400 Subject: [PATCH 04/14] cleanup --- backend/src/db/schemas/identity-kubernetes-auths.ts | 5 +++-- .../identity-kubernetes-auth-service.ts | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/src/db/schemas/identity-kubernetes-auths.ts b/backend/src/db/schemas/identity-kubernetes-auths.ts index 880928247..251ae685e 100644 --- a/backend/src/db/schemas/identity-kubernetes-auths.ts +++ b/backend/src/db/schemas/identity-kubernetes-auths.ts @@ -31,8 +31,9 @@ export const IdentityKubernetesAuthsSchema = z.object({ encryptedKubernetesTokenReviewerJwt: zodBuffer.nullable().optional(), encryptedKubernetesCaCertificate: zodBuffer.nullable().optional(), gatewayId: z.string().uuid().nullable().optional(), - tokenReviewMode: z.string().default("api"), - accessTokenPeriod: z.coerce.number().default(0) + accessTokenPeriod: z.coerce.number().default(0), + useGatewayAsReviewer: z.boolean().default(false), + tokenReviewMode: z.string().default("api") }); export type TIdentityKubernetesAuths = z.infer; diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index bb24ddf62..59c062686 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -164,8 +164,6 @@ export const identityKubernetesAuthServiceFactory = ({ servername = servername.substring(0, lastColonIndex); } - console.log("servername", servername); - const baseUrl = port ? `${host}:${port}` : host; const res = await axios From f2a55da9b62afb6def5d9893512bb8a6e8c8dbe5 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 04:49:50 +0400 Subject: [PATCH 05/14] Update .infisicalignore --- .infisicalignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.infisicalignore b/.infisicalignore index 02cdd4f0e..7c203945f 100644 --- a/.infisicalignore +++ b/.infisicalignore @@ -40,3 +40,4 @@ cli/detect/config/gitleaks.toml:gcp-api-key:578 cli/detect/config/gitleaks.toml:gcp-api-key:579 cli/detect/config/gitleaks.toml:gcp-api-key:581 cli/detect/config/gitleaks.toml:gcp-api-key:582 +backend/src/services/smtp/smtp-service.ts:generic-api-key:79 From c34a139b198d34ff7758aaf3b969c9fbf2f403ef Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 05:02:58 +0400 Subject: [PATCH 06/14] cleanup --- backend/src/db/schemas/identity-kubernetes-auths.ts | 1 - backend/src/ee/services/dynamic-secret/providers/vertica.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/db/schemas/identity-kubernetes-auths.ts b/backend/src/db/schemas/identity-kubernetes-auths.ts index 251ae685e..8a351014a 100644 --- a/backend/src/db/schemas/identity-kubernetes-auths.ts +++ b/backend/src/db/schemas/identity-kubernetes-auths.ts @@ -32,7 +32,6 @@ export const IdentityKubernetesAuthsSchema = z.object({ encryptedKubernetesCaCertificate: zodBuffer.nullable().optional(), gatewayId: z.string().uuid().nullable().optional(), accessTokenPeriod: z.coerce.number().default(0), - useGatewayAsReviewer: z.boolean().default(false), tokenReviewMode: z.string().default("api") }); diff --git a/backend/src/ee/services/dynamic-secret/providers/vertica.ts b/backend/src/ee/services/dynamic-secret/providers/vertica.ts index 9e283ab41..046b73017 100644 --- a/backend/src/ee/services/dynamic-secret/providers/vertica.ts +++ b/backend/src/ee/services/dynamic-secret/providers/vertica.ts @@ -4,7 +4,7 @@ import knex, { Knex } from "knex"; import { z } from "zod"; import { BadRequestError } from "@app/lib/errors"; -import { withGatewayProxy } from "@app/lib/gateway"; +import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; @@ -196,6 +196,7 @@ export const VerticaProvider = ({ gatewayService }: TVerticaProviderDTO): TDynam await gatewayCallback("localhost", port); }, { + protocol: ProxyProtocol.Tcp, targetHost: providerInputs.host, targetPort: providerInputs.port, relayHost, From a4c21d85aca21f5b94d50015df90e6cfb813b330 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 05:07:58 +0400 Subject: [PATCH 07/14] Update identity-kubernetes-auth-router.ts --- backend/src/server/routes/v1/identity-kubernetes-auth-router.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index 3e244717d..724880638 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -349,7 +349,6 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide identityId: identityKubernetesAuth.identityId, kubernetesHost: identityKubernetesAuth.kubernetesHost, tokenReviewMode: identityKubernetesAuth.tokenReviewMode, - tokenReviewerJwt: identityKubernetesAuth.tokenReviewerJwt, allowedNamespaces: identityKubernetesAuth.allowedNamespaces, allowedNames: identityKubernetesAuth.allowedNames, accessTokenTTL: identityKubernetesAuth.accessTokenTTL, From caa129b5653819b79d149e27ce72c7577d96d06c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 05:23:30 +0400 Subject: [PATCH 08/14] requested changes --- .../src/server/routes/v1/identity-kubernetes-auth-router.ts | 5 ++--- .../identity-kubernetes-auth-service.ts | 6 +++++- cli/packages/util/helper.go | 2 +- .../IdentitySection/IdentityKubernetesAuthForm.tsx | 1 - 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index 724880638..743c5b321 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -307,8 +307,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide if ( data.tokenReviewMode && data.tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Gateway && - !data.gatewayId && - data.tokenReviewMode !== undefined + !data.gatewayId ) { ctx.addIssue({ path: ["gatewayId"], @@ -316,7 +315,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide message: "When token review mode is set to Gateway, a gateway must be selected" }); } - if (data.accessTokenMaxTTL && data.accessTokenTTL ? data.accessTokenTTL <= data.accessTokenMaxTTL : true) { + if (data.accessTokenMaxTTL && data.accessTokenTTL ? data.accessTokenTTL > data.accessTokenMaxTTL : false) { ctx.addIssue({ path: ["accessTokenTTL"], code: z.ZodIssueCode.custom, diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 59c062686..4eb45ba14 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -249,7 +249,11 @@ export const identityKubernetesAuthServiceFactory = ({ .catch((err) => { if (err instanceof AxiosError) { if (err.response) { - const { message } = err?.response?.data as unknown as { message?: string }; + let { message } = err?.response?.data as unknown as { message?: string }; + + if (!message && typeof err.response.data === "string") { + message = err.response.data; + } if (message) { throw new UnauthorizedError({ diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index ceb0792f1..fc3f994a7 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -299,7 +299,7 @@ func GetCmdFlagOrEnv(cmd *cobra.Command, flag string, envNames []string) (string } if value == "" { for _, env := range envNames { - value = os.Getenv(env) + value = strings.TrimSpace(os.Getenv(env)) if value != "" { break } diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx index 1b55bc60e..e43c94a7e 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx @@ -322,7 +322,6 @@ export const IdentityKubernetesAuthForm = ({ isDisabled={!isAllowed} value={value as string} onValueChange={(v) => { - console.log("v", v); if (v !== "") { onChange(v); } From c425c039394f146a8e9b14162918f62ab9879aa3 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 17:44:41 +0400 Subject: [PATCH 09/14] cleanup --- backend/src/ee/services/audit-log/audit-log-types.ts | 3 --- .../src/server/routes/v1/identity-kubernetes-auth-router.ts | 2 -- 2 files changed, 5 deletions(-) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 808a13f68..cfc01741f 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -35,7 +35,6 @@ import { ActorType } from "@app/services/auth/auth-type"; import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types"; import { CaStatus } from "@app/services/certificate-authority/certificate-authority-enums"; import { TIdentityTrustedIp } from "@app/services/identity/identity-types"; -import { IdentityKubernetesAuthTokenReviewMode } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-types"; import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-auth-types"; import { PkiItemType } from "@app/services/pki-collection/pki-collection-types"; import { SecretSync, SecretSyncImportBehavior } from "@app/services/secret-sync/secret-sync-enums"; @@ -880,7 +879,6 @@ interface AddIdentityKubernetesAuthEvent { metadata: { identityId: string; kubernetesHost: string; - tokenReviewMode: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces: string; allowedNames: string; accessTokenTTL: number; @@ -902,7 +900,6 @@ interface UpdateIdentityKubernetesAuthEvent { metadata: { identityId: string; kubernetesHost?: string; - tokenReviewMode?: IdentityKubernetesAuthTokenReviewMode; allowedNamespaces?: string; allowedNames?: string; accessTokenTTL?: number; diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index 743c5b321..5eb0c6990 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -204,7 +204,6 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide metadata: { identityId: identityKubernetesAuth.identityId, kubernetesHost: identityKubernetesAuth.kubernetesHost, - tokenReviewMode: identityKubernetesAuth.tokenReviewMode, allowedNamespaces: identityKubernetesAuth.allowedNamespaces, allowedNames: identityKubernetesAuth.allowedNames, accessTokenTTL: identityKubernetesAuth.accessTokenTTL, @@ -347,7 +346,6 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide metadata: { identityId: identityKubernetesAuth.identityId, kubernetesHost: identityKubernetesAuth.kubernetesHost, - tokenReviewMode: identityKubernetesAuth.tokenReviewMode, allowedNamespaces: identityKubernetesAuth.allowedNamespaces, allowedNames: identityKubernetesAuth.allowedNames, accessTokenTTL: identityKubernetesAuth.accessTokenTTL, From 594445814a7b34a04d2d072d8e56c24551a78f57 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 18:40:34 +0400 Subject: [PATCH 10/14] docs(identity/kubernetes-auth): added docs for gateway as reviewer --- .../platform/identities/kubernetes-auth.mdx | 111 +++++++++++++----- ...es-kubernetes-auth-gateway-as-reviewer.png | Bin 0 -> 242582 bytes 2 files changed, 81 insertions(+), 30 deletions(-) create mode 100644 docs/images/platform/identities/identities-kubernetes-auth-gateway-as-reviewer.png diff --git a/docs/documentation/platform/identities/kubernetes-auth.mdx b/docs/documentation/platform/identities/kubernetes-auth.mdx index 9daff1e81..e357ba75e 100644 --- a/docs/documentation/platform/identities/kubernetes-auth.mdx +++ b/docs/documentation/platform/identities/kubernetes-auth.mdx @@ -52,10 +52,11 @@ Infisical is able to authenticate and interact with the TokenReview API by using In the following steps, we explore how to create and use identities for your applications in Kubernetes to access the Infisical API using the Kubernetes Auth authentication method. + + - - + **When to use this option**: Choose this approach when you want centralized authentication management. Only one service account needs special permissions, and your application service accounts remain unchanged. @@ -126,41 +127,91 @@ In the following steps, we explore how to create and use identities for your app ``` Keep this JWT token handy as you will need it for the **Token Reviewer JWT** field when configuring the Kubernetes Auth authentication method for the identity in step 2. + - - + + + **When to use this option**: Choose this approach to eliminate long-lived tokens. This option simplifies Infisical configuration but requires each application service account to have elevated permissions. + - - **When to use this option**: Choose this approach to eliminate long-lived tokens. This option simplifies Infisical configuration but requires each application service account to have elevated permissions. - + The self-validation method eliminates the need for a separate long-lived reviewer JWT by using the same token for both authentication and validation. Instead of creating a dedicated reviewer service account, you'll grant the necessary permissions to each application service account. - The self-validation method eliminates the need for a separate long-lived reviewer JWT by using the same token for both authentication and validation. Instead of creating a dedicated reviewer service account, you'll grant the necessary permissions to each application service account. + For each service account that needs to authenticate with Infisical, add the `system:auth-delegator` role: - For each service account that needs to authenticate with Infisical, add the `system:auth-delegator` role: + ```yaml client-role-binding.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: infisical-client-binding-[your-app-name] + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator + subjects: + - kind: ServiceAccount + name: [your-app-service-account] + namespace: [your-app-namespace] + ``` - ```yaml client-role-binding.yaml - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: infisical-client-binding-[your-app-name] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator - subjects: - - kind: ServiceAccount - name: [your-app-service-account] - namespace: [your-app-namespace] - ``` + ``` + kubectl apply -f client-role-binding.yaml + ``` - ``` - kubectl apply -f client-role-binding.yaml - ``` + When configuring Kubernetes Auth in Infisical, leave the **Token Reviewer JWT** field empty. Infisical will use the client's own token for validation. + + + + **When to use this option**: Choose this approach when you have a gateway deployed in your Kubernetes Cluster and wish to eliminate long-lived tokens. This approach simplifies Infisical Kubernetes Auth configuration, and only one service account will need to have the elevated `system:auth-delegator` ClusterRole binding. + - When configuring Kubernetes Auth in Infisical, leave the **Token Reviewer JWT** field empty. Infisical will use the client's own token for validation. - - - + + **Note:** Gateway is a paid feature. - **Infisical Cloud users:** Gateway is + available under the **Enterprise Tier**. - **Self-Hosted Infisical:** Please + contact [sales@infisical.com](mailto:sales@infisical.com) to purchase an + enterprise license. + + + + + To deploy a gateway in your Kubernetes cluster, follow our [Gateway deployment guide using helm](/documentation/platform/gateways/overview). + + + + To grant the gateway the `system:auth-delegator` ClusterRole binding, you can use the following command: + + ```yaml gateway-role-binding.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: infisical-token-reviewer-role-binding + namespace: default # Replace with your namespace if not default + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator + subjects: + - kind: ServiceAccount + name: infisical-gateway # The name of the gateway service account + namespace: default # Replace with your namespace if not default + ``` + + ```bash + kubectl apply -f gateway-role-binding.yaml + ``` + + + The gateway service account name is `infisical-gateway` by default if deployed using Helm. + + + + + To configure your Kubernetes Auth method to use the gateway as the token reviewer, set the `Review Method` to "Gateway as Reviewer", and select the gateway you want to use as the token reviewer. + + ![identities organization create kubernetes auth method](/images/platform/identities/identities-kubernetes-auth-gateway-as-reviewer.png) + + + + To create an identity, head to your Organization Settings > Access Control > Identities and press **Create identity**. diff --git a/docs/images/platform/identities/identities-kubernetes-auth-gateway-as-reviewer.png b/docs/images/platform/identities/identities-kubernetes-auth-gateway-as-reviewer.png new file mode 100644 index 0000000000000000000000000000000000000000..30ac12545f42e2528cb0dba7d69bc3c2fd2a0413 GIT binary patch literal 242582 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�xWP*$b2(Ct@gi`XYs(#A&oSr)Sg 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%0A4#NVCWww)NT-~%qvwIfdgvM&mNueC5 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

#>r}XoVBM8_R{7DmEa|A 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 Date: Thu, 5 Jun 2025 18:40:54 +0400 Subject: [PATCH 11/14] cleanup and minor requested changes --- .../dynamic-secret/providers/kubernetes.ts | 4 +- .../dynamic-secret/providers/sql-database.ts | 4 +- .../dynamic-secret/providers/vertica.ts | 4 +- backend/src/lib/gateway/gateway.ts | 411 ++++++++++++++++ backend/src/lib/gateway/index.ts | 441 +----------------- backend/src/lib/gateway/types.ts | 42 ++ .../identity-kubernetes-auth-service.ts | 6 +- 7 files changed, 464 insertions(+), 448 deletions(-) create mode 100644 backend/src/lib/gateway/gateway.ts create mode 100644 backend/src/lib/gateway/types.ts diff --git a/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts b/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts index eeea7e4be..130e0fa92 100644 --- a/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts +++ b/backend/src/ee/services/dynamic-secret/providers/kubernetes.ts @@ -2,7 +2,7 @@ import axios from "axios"; import https from "https"; import { InternalServerError } from "@app/lib/errors"; -import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; +import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; import { TKubernetesTokenRequest } from "@app/services/identity-kubernetes-auth/identity-kubernetes-auth-types"; @@ -43,7 +43,7 @@ export const KubernetesProvider = ({ gatewayService }: TKubernetesProviderDTO): return res; }, { - protocol: ProxyProtocol.Tcp, + protocol: GatewayProxyProtocol.Tcp, targetHost: inputs.targetHost, targetPort: inputs.targetPort, relayHost, diff --git a/backend/src/ee/services/dynamic-secret/providers/sql-database.ts b/backend/src/ee/services/dynamic-secret/providers/sql-database.ts index f5299687b..39f8dd6de 100644 --- a/backend/src/ee/services/dynamic-secret/providers/sql-database.ts +++ b/backend/src/ee/services/dynamic-secret/providers/sql-database.ts @@ -3,7 +3,7 @@ import handlebars from "handlebars"; import knex from "knex"; import { z } from "zod"; -import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; +import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; @@ -185,7 +185,7 @@ export const SqlDatabaseProvider = ({ gatewayService }: TSqlDatabaseProviderDTO) await gatewayCallback("localhost", port); }, { - protocol: ProxyProtocol.Tcp, + protocol: GatewayProxyProtocol.Tcp, targetHost: providerInputs.host, targetPort: providerInputs.port, relayHost, diff --git a/backend/src/ee/services/dynamic-secret/providers/vertica.ts b/backend/src/ee/services/dynamic-secret/providers/vertica.ts index 046b73017..e361ab329 100644 --- a/backend/src/ee/services/dynamic-secret/providers/vertica.ts +++ b/backend/src/ee/services/dynamic-secret/providers/vertica.ts @@ -4,7 +4,7 @@ import knex, { Knex } from "knex"; import { z } from "zod"; import { BadRequestError } from "@app/lib/errors"; -import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; +import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars"; @@ -196,7 +196,7 @@ export const VerticaProvider = ({ gatewayService }: TVerticaProviderDTO): TDynam await gatewayCallback("localhost", port); }, { - protocol: ProxyProtocol.Tcp, + protocol: GatewayProxyProtocol.Tcp, targetHost: providerInputs.host, targetPort: providerInputs.port, relayHost, diff --git a/backend/src/lib/gateway/gateway.ts b/backend/src/lib/gateway/gateway.ts new file mode 100644 index 000000000..179c29fc8 --- /dev/null +++ b/backend/src/lib/gateway/gateway.ts @@ -0,0 +1,411 @@ +/* eslint-disable no-await-in-loop */ +import crypto from "node:crypto"; +import net from "node:net"; + +import quicDefault, * as quicModule from "@infisical/quic"; +import axios from "axios"; +import https from "https"; + +import { BadRequestError } from "../errors"; +import { logger } from "../logger"; +import { + GatewayProxyProtocol, + IGatewayProxyOptions, + IGatewayProxyServer, + TGatewayTlsOptions, + TPingGatewayAndVerifyDTO +} from "./types"; + +const DEFAULT_MAX_RETRIES = 3; +const DEFAULT_RETRY_DELAY = 1000; // 1 second + +const quic = quicDefault || quicModule; + +const parseSubjectDetails = (data: string) => { + const values: Record = {}; + data.split("\n").forEach((el) => { + const [key, value] = el.split("="); + values[key.trim()] = value.trim(); + }); + return values; +}; + +const createQuicConnection = async ( + relayHost: string, + relayPort: number, + tlsOptions: TGatewayTlsOptions, + identityId: string, + orgId: string +) => { + const client = await quic.QUICClient.createQUICClient({ + host: relayHost, + port: relayPort, + config: { + ca: tlsOptions.ca, + cert: tlsOptions.cert, + key: tlsOptions.key, + applicationProtos: ["infisical-gateway"], + verifyPeer: true, + verifyCallback: async (certs) => { + if (!certs || certs.length === 0) return quic.native.CryptoError.CertificateRequired; + const serverCertificate = new crypto.X509Certificate(Buffer.from(certs[0])); + const caCertificate = new crypto.X509Certificate(tlsOptions.ca); + const isValidServerCertificate = serverCertificate.verify(caCertificate.publicKey); + if (!isValidServerCertificate) return quic.native.CryptoError.BadCertificate; + + const subjectDetails = parseSubjectDetails(serverCertificate.subject); + if (subjectDetails.OU !== "Gateway" || subjectDetails.CN !== identityId || subjectDetails.O !== orgId) { + return quic.native.CryptoError.CertificateUnknown; + } + + if (new Date() > new Date(serverCertificate.validTo) || new Date() < new Date(serverCertificate.validFrom)) { + return quic.native.CryptoError.CertificateExpired; + } + + const formatedRelayHost = + process.env.NODE_ENV === "development" ? relayHost.replace("host.docker.internal", "127.0.0.1") : relayHost; + if (!serverCertificate.checkIP(formatedRelayHost)) return quic.native.CryptoError.BadCertificate; + }, + maxIdleTimeout: 90000, + keepAliveIntervalTime: 30000 + }, + crypto: { + ops: { + randomBytes: async (data) => { + crypto.getRandomValues(new Uint8Array(data)); + } + } + } + }); + return client; +}; + +export const pingGatewayAndVerify = async ({ + relayHost, + relayPort, + tlsOptions, + maxRetries = DEFAULT_MAX_RETRIES, + identityId, + orgId +}: TPingGatewayAndVerifyDTO) => { + let lastError: Error | null = null; + const quicClient = await createQuicConnection(relayHost, relayPort, tlsOptions, identityId, orgId).catch((err) => { + throw new BadRequestError({ + message: (err as Error)?.message, + error: err as Error + }); + }); + + for (let attempt = 1; attempt <= maxRetries; attempt += 1) { + try { + const stream = quicClient.connection.newStream("bidi"); + const pingWriter = stream.writable.getWriter(); + await pingWriter.write(Buffer.from("PING\n")); + pingWriter.releaseLock(); + + // Read PONG response + const reader = stream.readable.getReader(); + const { value, done } = await reader.read(); + + if (done) { + throw new Error("Gateway closed before receiving PONG"); + } + + const response = Buffer.from(value).toString(); + + if (response !== "PONG\n" && response !== "PONG") { + throw new Error(`Failed to Ping. Unexpected response: ${response}`); + } + + reader.releaseLock(); + return; + } catch (err) { + lastError = err as Error; + + if (attempt < maxRetries) { + await new Promise((resolve) => { + setTimeout(resolve, DEFAULT_RETRY_DELAY); + }); + } + } finally { + await quicClient.destroy(); + } + } + + logger.error(lastError); + throw new BadRequestError({ + message: `Failed to ping gateway after ${maxRetries} attempts. Last error: ${lastError?.message}` + }); +}; + +const setupProxyServer = async ({ + targetPort, + targetHost, + tlsOptions, + relayHost, + relayPort, + identityId, + orgId, + protocol = GatewayProxyProtocol.Tcp, + httpsAgent +}: { + targetHost: string; + targetPort: number; + relayPort: number; + relayHost: string; + tlsOptions: TGatewayTlsOptions; + identityId: string; + orgId: string; + protocol?: GatewayProxyProtocol; + httpsAgent?: https.Agent; +}): Promise => { + const quicClient = await createQuicConnection(relayHost, relayPort, tlsOptions, identityId, orgId).catch((err) => { + throw new BadRequestError({ + error: err as Error + }); + }); + const proxyErrorMsg = [""]; + + return new Promise((resolve, reject) => { + const server = net.createServer(); + + let streamClosed = false; + + // eslint-disable-next-line @typescript-eslint/no-misused-promises + server.on("connection", async (clientConn) => { + try { + clientConn.setKeepAlive(true, 30000); // 30 seconds + clientConn.setNoDelay(true); + + const stream = quicClient.connection.newStream("bidi"); + + const forwardWriter = stream.writable.getWriter(); + let command: string; + + if (protocol === GatewayProxyProtocol.Http) { + const targetUrl = `${targetHost}:${targetPort}`; // note(daniel): targetHost MUST include the scheme (https|http) + command = `FORWARD-HTTP ${targetUrl}`; + logger.debug(`Using HTTP proxy mode: ${command.trim()}`); + + // extract ca certificate from httpsAgent if present + if (httpsAgent && targetHost.startsWith("https://")) { + const agentOptions = httpsAgent.options; + if (agentOptions && agentOptions.ca) { + const caCert = Array.isArray(agentOptions.ca) ? agentOptions.ca.join("\n") : agentOptions.ca; + const caB64 = Buffer.from(caCert as string).toString("base64"); + command += ` ca=${caB64}`; + + const rejectUnauthorized = agentOptions.rejectUnauthorized !== false; + command += ` verify=${rejectUnauthorized}`; + + logger.debug(`Using HTTP proxy mode [command=${command.trim()}]`); + } + } + + command += "\n"; + } else if (protocol === GatewayProxyProtocol.Tcp) { + // For TCP mode, send FORWARD-TCP with host:port + command = `FORWARD-TCP ${targetHost}:${targetPort}\n`; + logger.debug(`Using TCP proxy mode: ${command.trim()}`); + } else { + throw new BadRequestError({ + message: `Invalid protocol: ${protocol as string}` + }); + } + + await forwardWriter.write(Buffer.from(command)); + forwardWriter.releaseLock(); + + // Set up bidirectional copy + const setupCopy = () => { + // Client to QUIC + // eslint-disable-next-line + (async () => { + const writer = stream.writable.getWriter(); + + // Create a handler for client data + clientConn.on("data", (chunk) => { + writer.write(chunk).catch((err) => { + proxyErrorMsg.push((err as Error)?.message); + }); + }); + + // Handle client connection close + clientConn.on("end", () => { + if (!streamClosed) { + try { + writer.close().catch((err) => { + logger.debug(err, "Error closing writer (already closed)"); + }); + } catch (error) { + logger.debug(error, "Error in writer close"); + } + } + }); + + clientConn.on("error", (clientConnErr) => { + writer.abort(clientConnErr?.message).catch((err) => { + proxyErrorMsg.push((err as Error)?.message); + }); + }); + })(); + + // QUIC to Client + void (async () => { + try { + const reader = stream.readable.getReader(); + + let reading = true; + while (reading) { + const { value, done } = await reader.read(); + + if (done) { + reading = false; + clientConn.end(); // Close client connection when QUIC stream ends + break; + } + + // Write data to TCP client + const canContinue = clientConn.write(Buffer.from(value)); + + // Handle backpressure + if (!canContinue) { + await new Promise((res) => { + clientConn.once("drain", res); + }); + } + } + } catch (err) { + proxyErrorMsg.push((err as Error)?.message); + clientConn.destroy(); + } + })(); + }; + + setupCopy(); + // Handle connection closure + clientConn.on("close", () => { + if (!streamClosed) { + streamClosed = true; + stream.destroy().catch((err) => { + logger.debug(err, "Stream already destroyed during close event"); + }); + } + }); + + const cleanup = async () => { + try { + clientConn?.destroy(); + } catch (err) { + logger.debug(err, "Error destroying client connection"); + } + + if (!streamClosed) { + streamClosed = true; + try { + await stream.destroy(); + } catch (err) { + logger.debug(err, "Error destroying stream (might be already closed)"); + } + } + }; + + clientConn.on("error", (clientConnErr) => { + logger.error(clientConnErr, "Client socket error"); + cleanup().catch((err) => { + logger.error(err, "Client conn cleanup"); + }); + }); + + clientConn.on("end", () => { + cleanup().catch((err) => { + logger.error(err, "Client conn end"); + }); + }); + } catch (err) { + logger.error(err, "Failed to establish target connection:"); + clientConn.end(); + reject(err); + } + }); + + server.on("error", (err) => { + reject(err); + }); + + server.on("close", () => { + quicClient?.destroy().catch((err) => { + logger.error(err, "Failed to destroy quic client"); + }); + }); + + server.listen(0, () => { + const address = server.address(); + if (!address || typeof address === "string") { + server.close(); + reject(new Error("Failed to get server port")); + return; + } + + logger.info(`Gateway proxy started on port ${address.port} (${protocol} mode)`); + resolve({ + server, + port: address.port, + cleanup: async () => { + try { + server.close(); + } catch (err) { + logger.debug(err, "Error closing server"); + } + + try { + await quicClient?.destroy(); + } catch (err) { + logger.debug(err, "Error destroying QUIC client"); + } + }, + getProxyError: () => proxyErrorMsg.join(",") + }); + }); + }); +}; + +export const withGatewayProxy = async ( + callback: (port: number, httpsAgent?: https.Agent) => Promise, + options: IGatewayProxyOptions +): Promise => { + const { relayHost, relayPort, targetHost, targetPort, tlsOptions, identityId, orgId, protocol, httpsAgent } = options; + + // Setup the proxy server + const { port, cleanup, getProxyError } = await setupProxyServer({ + targetHost, + targetPort, + relayPort, + relayHost, + tlsOptions, + identityId, + orgId, + protocol, + httpsAgent + }); + + try { + // Execute the callback with the allocated port + return await callback(port, httpsAgent); + } catch (err) { + const proxyErrorMessage = getProxyError(); + if (proxyErrorMessage) { + logger.error(new Error(proxyErrorMessage), "Failed to proxy"); + } + logger.error(err, "Failed to do gateway"); + let errorMessage = proxyErrorMessage || (err as Error)?.message; + if (axios.isAxiosError(err) && (err.response?.data as { message?: string })?.message) { + errorMessage = (err.response?.data as { message: string }).message; + } + + throw new BadRequestError({ message: errorMessage }); + } finally { + // Ensure cleanup happens regardless of success or failure + await cleanup(); + } +}; diff --git a/backend/src/lib/gateway/index.ts b/backend/src/lib/gateway/index.ts index 9ec6a471e..9292473e5 100644 --- a/backend/src/lib/gateway/index.ts +++ b/backend/src/lib/gateway/index.ts @@ -1,439 +1,2 @@ -/* eslint-disable no-await-in-loop */ -import crypto from "node:crypto"; -import net from "node:net"; - -import quicDefault, * as quicModule from "@infisical/quic"; -import axios from "axios"; -import https from "https"; - -import { BadRequestError } from "../errors"; -import { logger } from "../logger"; - -const DEFAULT_MAX_RETRIES = 3; -const DEFAULT_RETRY_DELAY = 1000; // 1 second - -const quic = quicDefault || quicModule; - -const parseSubjectDetails = (data: string) => { - const values: Record = {}; - data.split("\n").forEach((el) => { - const [key, value] = el.split("="); - values[key.trim()] = value.trim(); - }); - return values; -}; - -type TTlsOption = { ca: string; cert: string; key: string }; - -const createQuicConnection = async ( - relayHost: string, - relayPort: number, - tlsOptions: TTlsOption, - identityId: string, - orgId: string -) => { - const client = await quic.QUICClient.createQUICClient({ - host: relayHost, - port: relayPort, - config: { - ca: tlsOptions.ca, - cert: tlsOptions.cert, - key: tlsOptions.key, - applicationProtos: ["infisical-gateway"], - verifyPeer: true, - verifyCallback: async (certs) => { - if (!certs || certs.length === 0) return quic.native.CryptoError.CertificateRequired; - const serverCertificate = new crypto.X509Certificate(Buffer.from(certs[0])); - const caCertificate = new crypto.X509Certificate(tlsOptions.ca); - const isValidServerCertificate = serverCertificate.verify(caCertificate.publicKey); - if (!isValidServerCertificate) return quic.native.CryptoError.BadCertificate; - - const subjectDetails = parseSubjectDetails(serverCertificate.subject); - if (subjectDetails.OU !== "Gateway" || subjectDetails.CN !== identityId || subjectDetails.O !== orgId) { - return quic.native.CryptoError.CertificateUnknown; - } - - if (new Date() > new Date(serverCertificate.validTo) || new Date() < new Date(serverCertificate.validFrom)) { - return quic.native.CryptoError.CertificateExpired; - } - - const formatedRelayHost = - process.env.NODE_ENV === "development" ? relayHost.replace("host.docker.internal", "127.0.0.1") : relayHost; - if (!serverCertificate.checkIP(formatedRelayHost)) return quic.native.CryptoError.BadCertificate; - }, - maxIdleTimeout: 90000, - keepAliveIntervalTime: 30000 - }, - crypto: { - ops: { - randomBytes: async (data) => { - crypto.getRandomValues(new Uint8Array(data)); - } - } - } - }); - return client; -}; - -type TPingGatewayAndVerifyDTO = { - relayHost: string; - relayPort: number; - tlsOptions: TTlsOption; - maxRetries?: number; - identityId: string; - orgId: string; -}; - -export const pingGatewayAndVerify = async ({ - relayHost, - relayPort, - tlsOptions, - maxRetries = DEFAULT_MAX_RETRIES, - identityId, - orgId -}: TPingGatewayAndVerifyDTO) => { - let lastError: Error | null = null; - const quicClient = await createQuicConnection(relayHost, relayPort, tlsOptions, identityId, orgId).catch((err) => { - throw new BadRequestError({ - message: (err as Error)?.message, - error: err as Error - }); - }); - - for (let attempt = 1; attempt <= maxRetries; attempt += 1) { - try { - const stream = quicClient.connection.newStream("bidi"); - const pingWriter = stream.writable.getWriter(); - await pingWriter.write(Buffer.from("PING\n")); - pingWriter.releaseLock(); - - // Read PONG response - const reader = stream.readable.getReader(); - const { value, done } = await reader.read(); - - if (done) { - throw new Error("Gateway closed before receiving PONG"); - } - - const response = Buffer.from(value).toString(); - - if (response !== "PONG\n" && response !== "PONG") { - throw new Error(`Failed to Ping. Unexpected response: ${response}`); - } - - reader.releaseLock(); - return; - } catch (err) { - lastError = err as Error; - - if (attempt < maxRetries) { - await new Promise((resolve) => { - setTimeout(resolve, DEFAULT_RETRY_DELAY); - }); - } - } finally { - await quicClient.destroy(); - } - } - - logger.error(lastError); - throw new BadRequestError({ - message: `Failed to ping gateway after ${maxRetries} attempts. Last error: ${lastError?.message}` - }); -}; - -interface TProxyServer { - server: net.Server; - port: number; - cleanup: () => Promise; - getProxyError: () => string; -} - -export enum ProxyProtocol { - Http = "http", - Tcp = "tcp" -} - -const setupProxyServer = async ({ - targetPort, - targetHost, - tlsOptions, - relayHost, - relayPort, - identityId, - orgId, - protocol = ProxyProtocol.Tcp, - httpsAgent -}: { - targetHost: string; - targetPort: number; - relayPort: number; - relayHost: string; - tlsOptions: TTlsOption; - identityId: string; - orgId: string; - protocol?: ProxyProtocol; - httpsAgent?: https.Agent; -}): Promise => { - const quicClient = await createQuicConnection(relayHost, relayPort, tlsOptions, identityId, orgId).catch((err) => { - throw new BadRequestError({ - error: err as Error - }); - }); - const proxyErrorMsg = [""]; - - return new Promise((resolve, reject) => { - const server = net.createServer(); - - let streamClosed = false; - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - server.on("connection", async (clientConn) => { - try { - clientConn.setKeepAlive(true, 30000); // 30 seconds - clientConn.setNoDelay(true); - - const stream = quicClient.connection.newStream("bidi"); - - const forwardWriter = stream.writable.getWriter(); - let command: string; - - if (protocol === ProxyProtocol.Http) { - const targetUrl = `${targetHost}:${targetPort}`; // note(daniel): targetHost MUST include the scheme (https|http) - command = `FORWARD-HTTP ${targetUrl}`; - logger.debug(`Using HTTP proxy mode: ${command.trim()}`); - - // extract ca certificate from httpsAgent if present - if (httpsAgent && targetHost.startsWith("https://")) { - const agentOptions = httpsAgent.options; - if (agentOptions && agentOptions.ca) { - const caCert = Array.isArray(agentOptions.ca) ? agentOptions.ca.join("\n") : agentOptions.ca; - const caB64 = Buffer.from(caCert as string).toString("base64"); - command += ` ca=${caB64}`; - - const rejectUnauthorized = agentOptions.rejectUnauthorized !== false; - command += ` verify=${rejectUnauthorized}`; - - logger.debug(`Using HTTP proxy mode [command=${command.trim()}]`); - } - } - - command += "\n"; - } else if (protocol === ProxyProtocol.Tcp) { - // For TCP mode, send FORWARD-TCP with host:port - command = `FORWARD-TCP ${targetHost}:${targetPort}\n`; - logger.debug(`Using TCP proxy mode: ${command.trim()}`); - } else { - throw new BadRequestError({ - message: `Invalid protocol: ${protocol as string}` - }); - } - - await forwardWriter.write(Buffer.from(command)); - forwardWriter.releaseLock(); - - // Set up bidirectional copy - const setupCopy = () => { - // Client to QUIC - // eslint-disable-next-line - (async () => { - const writer = stream.writable.getWriter(); - - // Create a handler for client data - clientConn.on("data", (chunk) => { - writer.write(chunk).catch((err) => { - proxyErrorMsg.push((err as Error)?.message); - }); - }); - - // Handle client connection close - clientConn.on("end", () => { - if (!streamClosed) { - try { - writer.close().catch((err) => { - logger.debug(err, "Error closing writer (already closed)"); - }); - } catch (error) { - logger.debug(error, "Error in writer close"); - } - } - }); - - clientConn.on("error", (clientConnErr) => { - writer.abort(clientConnErr?.message).catch((err) => { - proxyErrorMsg.push((err as Error)?.message); - }); - }); - })(); - - // QUIC to Client - void (async () => { - try { - const reader = stream.readable.getReader(); - - let reading = true; - while (reading) { - const { value, done } = await reader.read(); - - if (done) { - reading = false; - clientConn.end(); // Close client connection when QUIC stream ends - break; - } - - // Write data to TCP client - const canContinue = clientConn.write(Buffer.from(value)); - - // Handle backpressure - if (!canContinue) { - await new Promise((res) => { - clientConn.once("drain", res); - }); - } - } - } catch (err) { - proxyErrorMsg.push((err as Error)?.message); - clientConn.destroy(); - } - })(); - }; - - setupCopy(); - // Handle connection closure - clientConn.on("close", () => { - if (!streamClosed) { - streamClosed = true; - stream.destroy().catch((err) => { - logger.debug(err, "Stream already destroyed during close event"); - }); - } - }); - - const cleanup = async () => { - try { - clientConn?.destroy(); - } catch (err) { - logger.debug(err, "Error destroying client connection"); - } - - if (!streamClosed) { - streamClosed = true; - try { - await stream.destroy(); - } catch (err) { - logger.debug(err, "Error destroying stream (might be already closed)"); - } - } - }; - - clientConn.on("error", (clientConnErr) => { - logger.error(clientConnErr, "Client socket error"); - cleanup().catch((err) => { - logger.error(err, "Client conn cleanup"); - }); - }); - - clientConn.on("end", () => { - cleanup().catch((err) => { - logger.error(err, "Client conn end"); - }); - }); - } catch (err) { - logger.error(err, "Failed to establish target connection:"); - clientConn.end(); - reject(err); - } - }); - - server.on("error", (err) => { - reject(err); - }); - - server.on("close", () => { - quicClient?.destroy().catch((err) => { - logger.error(err, "Failed to destroy quic client"); - }); - }); - - server.listen(0, () => { - const address = server.address(); - if (!address || typeof address === "string") { - server.close(); - reject(new Error("Failed to get server port")); - return; - } - - logger.info(`Gateway proxy started on port ${address.port} (${protocol} mode)`); - resolve({ - server, - port: address.port, - cleanup: async () => { - try { - server.close(); - } catch (err) { - logger.debug(err, "Error closing server"); - } - - try { - await quicClient?.destroy(); - } catch (err) { - logger.debug(err, "Error destroying QUIC client"); - } - }, - getProxyError: () => proxyErrorMsg.join(",") - }); - }); - }); -}; - -interface ProxyOptions { - targetHost: string; - targetPort: number; - relayHost: string; - relayPort: number; - tlsOptions: TTlsOption; - identityId: string; - orgId: string; - protocol: ProxyProtocol; - httpsAgent?: https.Agent; -} - -export const withGatewayProxy = async ( - callback: (port: number, httpsAgent?: https.Agent) => Promise, - options: ProxyOptions -): Promise => { - const { relayHost, relayPort, targetHost, targetPort, tlsOptions, identityId, orgId, protocol, httpsAgent } = options; - - // Setup the proxy server - const { port, cleanup, getProxyError } = await setupProxyServer({ - targetHost, - targetPort, - relayPort, - relayHost, - tlsOptions, - identityId, - orgId, - protocol, - httpsAgent - }); - - try { - // Execute the callback with the allocated port - return await callback(port, httpsAgent); - } catch (err) { - const proxyErrorMessage = getProxyError(); - if (proxyErrorMessage) { - logger.error(new Error(proxyErrorMessage), "Failed to proxy"); - } - logger.error(err, "Failed to do gateway"); - let errorMessage = proxyErrorMessage || (err as Error)?.message; - if (axios.isAxiosError(err) && (err.response?.data as { message?: string })?.message) { - errorMessage = (err.response?.data as { message: string }).message; - } - - throw new BadRequestError({ message: errorMessage }); - } finally { - // Ensure cleanup happens regardless of success or failure - await cleanup(); - } -}; +export { pingGatewayAndVerify, withGatewayProxy } from "./gateway"; +export { GatewayHttpProxyActions, GatewayProxyProtocol } from "./types"; diff --git a/backend/src/lib/gateway/types.ts b/backend/src/lib/gateway/types.ts new file mode 100644 index 000000000..5d0ac8237 --- /dev/null +++ b/backend/src/lib/gateway/types.ts @@ -0,0 +1,42 @@ +import net from "node:net"; + +import https from "https"; + +export type TGatewayTlsOptions = { ca: string; cert: string; key: string }; + +export enum GatewayProxyProtocol { + Http = "http", + Tcp = "tcp" +} + +export enum GatewayHttpProxyActions { + InjectGatewayK8sServiceAccountToken = "inject-k8s-sa-auth-token" +} + +export interface IGatewayProxyOptions { + targetHost: string; + targetPort: number; + relayHost: string; + relayPort: number; + tlsOptions: TGatewayTlsOptions; + identityId: string; + orgId: string; + protocol: GatewayProxyProtocol; + httpsAgent?: https.Agent; +} + +export type TPingGatewayAndVerifyDTO = { + relayHost: string; + relayPort: number; + tlsOptions: TGatewayTlsOptions; + maxRetries?: number; + identityId: string; + orgId: string; +}; + +export interface IGatewayProxyServer { + server: net.Server; + port: number; + cleanup: () => Promise; + getProxyError: () => string; +} diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 4eb45ba14..3501c8d28 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -20,7 +20,7 @@ import { import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors"; -import { ProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; +import { GatewayHttpProxyActions, GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; import { logger } from "@app/lib/logger"; @@ -92,7 +92,7 @@ export const identityKubernetesAuthServiceFactory = ({ return res; }, { - protocol: inputs.reviewTokenThroughGateway ? ProxyProtocol.Http : ProxyProtocol.Tcp, + protocol: inputs.reviewTokenThroughGateway ? GatewayProxyProtocol.Http : GatewayProxyProtocol.Tcp, targetHost: inputs.targetHost, targetPort: inputs.targetPort, relayHost, @@ -239,7 +239,7 @@ export const identityKubernetesAuthServiceFactory = ({ { headers: { "Content-Type": "application/json", - "x-infisical-action": "inject-k8s-sa-auth-token" + "x-infisical-action": GatewayHttpProxyActions.InjectGatewayK8sServiceAccountToken }, signal: AbortSignal.timeout(10000), timeout: 10000, From 78c4c3e847430c7f4e296bb4d10e40e9ec02149f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 18:43:46 +0400 Subject: [PATCH 12/14] Update overview.mdx --- docs/documentation/platform/gateways/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/documentation/platform/gateways/overview.mdx b/docs/documentation/platform/gateways/overview.mdx index ae4a3c7ad..30f9641c2 100644 --- a/docs/documentation/platform/gateways/overview.mdx +++ b/docs/documentation/platform/gateways/overview.mdx @@ -128,7 +128,7 @@ Once authenticated, the Gateway establishes a secure connection with Infisical t - + For development or testing, you can run the Gateway directly. Log in with your machine identity and start the Gateway in one command: ```bash infisical gateway --token $(infisical login --method=universal-auth --client-id=<> --client-secret=<> --plain) From ed4882dfac37715c1422c22e890a4494d38e65be Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 5 Jun 2025 23:50:46 +0400 Subject: [PATCH 13/14] fix: simplify gateway http copy logic --- cli/packages/gateway/connection.go | 42 ++++++++++-------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/cli/packages/gateway/connection.go b/cli/packages/gateway/connection.go index 78f614f62..9274086a1 100644 --- a/cli/packages/gateway/connection.go +++ b/cli/packages/gateway/connection.go @@ -210,17 +210,11 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string, // create the request to the target proxyReq, err := http.NewRequest(req.Method, targetFullURL, req.Body) + proxyReq.Header = req.Header.Clone() if err != nil { return fmt.Errorf("failed to create proxy request: %v", err) } - // copy headers - for name, values := range req.Header { - for _, value := range values { - proxyReq.Header.Add(name, value) - } - } - log.Info().Msgf("Proxying %s %s to %s", req.Method, req.URL.Path, targetFullURL) client := &http.Client{ @@ -236,29 +230,21 @@ func handleHTTPProxy(stream quic.Stream, reader *bufio.Reader, targetURL string, } defer resp.Body.Close() - // write response to stream - statusLine := fmt.Sprintf("HTTP/1.1 %d %s\r\n", resp.StatusCode, resp.Status[4:]) - if _, err := stream.Write([]byte(statusLine)); err != nil { - return err + // Write the entire response (status line, headers, body) to the stream + // http.Response.Write handles this for "Connection: close" correctly. + // For other connection tokens, manual removal might be needed if they cause issues with QUIC. + // For a simple proxy, this is generally sufficient. + resp.Header.Del("Connection") // Good practice for proxies + + log.Info().Msgf("Writing response to stream: %s", resp.Status) + if err := resp.Write(stream); err != nil { + // If writing the response fails, the connection to the client might be broken. + // Logging the error is important. The original error will be returned. + log.Error().Err(err).Msg("Failed to write response to stream") + return fmt.Errorf("failed to write response to stream: %w", err) } - // write headers again - for name, values := range resp.Header { - for _, value := range values { - headerLine := fmt.Sprintf("%s: %s\r\n", name, value) - if _, err := stream.Write([]byte(headerLine)); err != nil { - return err - } - } - } - - // write empty line to end headers - if _, err := stream.Write([]byte("\r\n")); err != nil { - return err - } - - _, err = io.Copy(stream, resp.Body) - return err + return nil } func buildHttpInternalServerError(message string) string { From eb7c533261a2ed0ae8161b23294ec1c3ad58e19c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 6 Jun 2025 00:26:01 +0400 Subject: [PATCH 14/14] Update identity-kubernetes-auth-service.ts --- .../identity-kubernetes-auth-service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 3501c8d28..df72b428e 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -107,7 +107,7 @@ export const identityKubernetesAuthServiceFactory = ({ // we always pass this, because its needed for both tcp and http protocol httpsAgent: new https.Agent({ ca: inputs.caCert, - rejectUnauthorized: !!inputs.caCert + rejectUnauthorized: Boolean(inputs.caCert) }) } ); @@ -158,6 +158,7 @@ export const identityKubernetesAuthServiceFactory = ({ if (servername.startsWith("https://") || servername.startsWith("http://")) { servername = new RE2("^https?:\\/\\/").replace(servername, ""); } + // get the last colon index, if it has a port, remove it, including the colon const lastColonIndex = servername.lastIndexOf(":"); if (lastColonIndex !== -1) {