diff --git a/cli/go.mod b/cli/go.mod index 6132f56c8..c713417e2 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -12,7 +12,7 @@ require ( github.com/fatih/semgroup v1.2.0 github.com/gitleaks/go-gitdiff v0.8.0 github.com/h2non/filetype v1.1.3 - github.com/infisical/go-sdk v0.5.7 + github.com/infisical/go-sdk v0.5.8 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 410a61154..68bce9cd3 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -277,8 +277,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/infisical/go-sdk v0.5.7 h1:q/gQGmbTvpCJYlhE3pyyWqifdQeM6yJyiYRIlXK4nXw= -github.com/infisical/go-sdk v0.5.7/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= +github.com/infisical/go-sdk v0.5.8 h1:bCetYLp7HWt8DnU9KPh1n8n3z5pjmunkGDB4bA3lEFs= +github.com/infisical/go-sdk v0.5.8/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/ssh.go b/cli/packages/cmd/ssh.go index 274b9bd7c..5b2bb37bb 100644 --- a/cli/packages/cmd/ssh.go +++ b/cli/packages/cmd/ssh.go @@ -610,28 +610,23 @@ func signKey(cmd *cobra.Command, args []string) { } func sshConnect(cmd *cobra.Command, args []string) { - token, err := util.GetInfisicalToken(cmd) + util.RequireLogin() + util.RequireLocalWorkspaceFile() + + loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails(true) if err != nil { - util.HandleError(err, "Unable to parse token") + util.HandleError(err, "Unable to authenticate") } - var infisicalToken string - if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) { - infisicalToken = token.Token - } else { - util.RequireLogin() - util.RequireLocalWorkspaceFile() + if loggedInUserDetails.LoginExpired { + util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again") + } - loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails(true) - if err != nil { - util.HandleError(err, "Unable to authenticate") - } + infisicalToken := loggedInUserDetails.UserCredentials.JTWToken - if loggedInUserDetails.LoginExpired { - util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again") - } - - infisicalToken = loggedInUserDetails.UserCredentials.JTWToken + writeHostCaToFile, err := cmd.Flags().GetBool("writeHostCaToFile") + if err != nil { + util.HandleError(err, "Unable to parse --writeHostCaToFile flag") } customHeaders, err := util.GetInfisicalCustomHeadersMap() @@ -702,6 +697,44 @@ func sshConnect(cmd *cobra.Command, args []string) { util.HandleError(err, "Failed to issue SSH credentials") } + // Write Host CA public key to known_hosts if enabled + if writeHostCaToFile { + hostCaPublicKey, err := infisicalClient.Ssh().GetSshHostHostCaPublicKey(selectedHost.ID) + if err != nil { + util.HandleError(err, "Failed to fetch Host CA public key") + } + + // Build @cert-authority line + caLine := fmt.Sprintf("@cert-authority %s %s\n", selectedHost.Hostname, strings.TrimSpace(hostCaPublicKey)) + + // Determine known_hosts path + sshDir := filepath.Join(os.Getenv("HOME"), ".ssh") + knownHostsPath := filepath.Join(sshDir, "known_hosts") + + // Ensure ~/.ssh exists + if _, err := os.Stat(sshDir); os.IsNotExist(err) { + if err := os.MkdirAll(sshDir, 0700); err != nil { + util.HandleError(err, "Failed to create ~/.ssh directory") + } + } + + // Check if CA line already exists + knownHostsBytes, _ := os.ReadFile(knownHostsPath) + if !strings.Contains(string(knownHostsBytes), caLine) { + f, err := os.OpenFile(knownHostsPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + util.HandleError(err, "Failed to open known_hosts file") + } + defer f.Close() + + if _, err := f.WriteString(caLine); err != nil { + util.HandleError(err, "Failed to write Host CA to known_hosts") + } + + fmt.Printf("📁 Wrote Host CA entry to %s\n", knownHostsPath) + } + } + // Load credentials into SSH agent err = addCredentialsToAgent(creds.PrivateKey, creds.SignedKey) if err != nil { @@ -973,7 +1006,7 @@ func init() { sshIssueCredentialsCmd.Flags().Bool("addToAgent", false, "Whether to add issued SSH credentials to the SSH agent") sshCmd.AddCommand(sshIssueCredentialsCmd) - sshConnectCmd.Flags().String("token", "", "Use a machine identity access token") + sshConnectCmd.Flags().Bool("writeHostCaToFile", true, "Write Host CA public key to ~/.ssh/known_hosts as a separate entry if doesn't already exist") sshCmd.AddCommand(sshConnectCmd) sshAddHostCmd.Flags().String("token", "", "Use a machine identity access token")