diff --git a/cli/packages/cmd/vault.go b/cli/packages/cmd/vault.go index 01bee147b2..948667dc46 100644 --- a/cli/packages/cmd/vault.go +++ b/cli/packages/cmd/vault.go @@ -4,6 +4,7 @@ Copyright (c) 2023 Infisical Inc. package cmd import ( + "encoding/base64" "fmt" "strings" @@ -16,10 +17,49 @@ import ( var AvailableVaultsAndDescriptions = []string{"auto (automatically select native vault on system)", "file (encrypted file vault)"} var AvailableVaults = []string{"auto", "file"} +var vaultSetPassphraseCmd = &cobra.Command{ + Example: `infisical vault set-passphrase [your-passphrase]`, + Use: "set-passphrase [your-passphrase]", + Short: "Used to set the passphrase for the file vault", + DisableFlagsInUseLine: true, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + log.Error().Msgf("Please provide a passphrase to set for the file vault") + return + } + + passphrase := args[0] + + configFile, err := util.GetConfigFile() + if err != nil { + log.Error().Msgf("Unable to set passphrase for file vault because of [err=%s]", err) + return + } + + if configFile.VaultBackendType != "file" { + log.Error().Msgf("You are not using file vault to store your login details. You can only set passphrase for file vault") + return + } + + // encode with base64 + encodedPassphrase := base64.StdEncoding.EncodeToString([]byte(passphrase)) + configFile.VaultBackendPassphrase = encodedPassphrase + + err = util.WriteConfigFile(&configFile) + if err != nil { + log.Error().Msgf("Unable to set passphrase for file vault because of [err=%s]", err) + return + } + + fmt.Printf("\nSuccessfully, set passphrase for file vault. You can now store your login details securely at rest\n") + }, +} + var vaultSetCmd = &cobra.Command{ - Example: `infisical vault set pass`, - Use: "set [vault-name]", - Short: "Used to set the vault backend to store your login details securely at rest", + Example: `infisical vault set [file|auto]`, + Use: "set [file|auto]", + Short: "Used to set the type of vault backend to store your login details securely at rest", DisableFlagsInUseLine: true, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -89,5 +129,6 @@ func printAvailableVaultBackends() { func init() { vaultCmd.AddCommand(vaultSetCmd) + vaultCmd.AddCommand(vaultSetPassphraseCmd) rootCmd.AddCommand(vaultCmd) } diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index 4b02cb6f84..65404dafab 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -11,10 +11,11 @@ type UserCredentials struct { // The file struct for Infisical config file type ConfigFile struct { - LoggedInUserEmail string `json:"loggedInUserEmail"` - LoggedInUserDomain string `json:"LoggedInUserDomain,omitempty"` - LoggedInUsers []LoggedInUser `json:"loggedInUsers,omitempty"` - VaultBackendType string `json:"vaultBackendType,omitempty"` + LoggedInUserEmail string `json:"loggedInUserEmail"` + LoggedInUserDomain string `json:"LoggedInUserDomain,omitempty"` + LoggedInUsers []LoggedInUser `json:"loggedInUsers,omitempty"` + VaultBackendType string `json:"vaultBackendType,omitempty"` + VaultBackendPassphrase string `json:"vaultBackendPassphrase,omitempty"` } type LoggedInUser struct { diff --git a/cli/packages/util/config.go b/cli/packages/util/config.go index 55c9df1b0f..02030e1fab 100644 --- a/cli/packages/util/config.go +++ b/cli/packages/util/config.go @@ -1,6 +1,7 @@ package util import ( + "encoding/base64" "encoding/json" "errors" "fmt" @@ -50,10 +51,11 @@ func WriteInitalConfig(userCredentials *models.UserCredentials) error { } configFile := models.ConfigFile{ - LoggedInUserEmail: userCredentials.Email, - LoggedInUserDomain: config.INFISICAL_URL, - LoggedInUsers: existingConfigFile.LoggedInUsers, - VaultBackendType: existingConfigFile.VaultBackendType, + LoggedInUserEmail: userCredentials.Email, + LoggedInUserDomain: config.INFISICAL_URL, + LoggedInUsers: existingConfigFile.LoggedInUsers, + VaultBackendType: existingConfigFile.VaultBackendType, + VaultBackendPassphrase: existingConfigFile.VaultBackendPassphrase, } configFileMarshalled, err := json.Marshal(configFile) @@ -215,6 +217,14 @@ func GetConfigFile() (models.ConfigFile, error) { return models.ConfigFile{}, err } + if configFile.VaultBackendPassphrase != "" { + decodedPassphrase, err := base64.StdEncoding.DecodeString(configFile.VaultBackendPassphrase) + if err != nil { + return models.ConfigFile{}, fmt.Errorf("GetConfigFile: Unable to decode base64 passphrase [err=%s]", err) + } + os.Setenv("INFISICAL_VAULT_FILE_PASSPHRASE", string(decodedPassphrase)) + } + return configFile, nil } diff --git a/cli/packages/util/constants.go b/cli/packages/util/constants.go index 5b0a93513c..5cd66f50b2 100644 --- a/cli/packages/util/constants.go +++ b/cli/packages/util/constants.go @@ -8,6 +8,10 @@ const ( INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json" INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN" INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME = "INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN" + INFISICAL_VAULT_FILE_PASSPHRASE_ENV_NAME = "INFISICAL_VAULT_FILE_PASSPHRASE" // This works because we've forked the keyring package and added support for this env variable. This explains why you won't find any occurrences of it in the CLI codebase. + + VAULT_BACKEND_AUTO_MODE = "auto" + VAULT_BACKEND_FILE_MODE = "file" // Universal Auth INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_NAME = "INFISICAL_UNIVERSAL_AUTH_CLIENT_ID" diff --git a/cli/packages/util/keyringwrapper.go b/cli/packages/util/keyringwrapper.go index 3bf2dd6c44..4f8fd80d45 100644 --- a/cli/packages/util/keyringwrapper.go +++ b/cli/packages/util/keyringwrapper.go @@ -1,11 +1,18 @@ package util import ( + "strings" + + "github.com/fatih/color" "github.com/zalando/go-keyring" ) const MAIN_KEYRING_SERVICE = "infisical-cli" +func keyringNotConfigured(err error) bool { + return err != nil && strings.Contains(err.Error(), "was not provided by any .service files") +} + type TimeoutError struct { message string } @@ -20,16 +27,30 @@ func SetValueInKeyring(key, value string) error { PrintErrorAndExit(1, err, "Unable to get current vault. Tip: run [infisical rest] then try again") } - return keyring.Set(currentVaultBackend, MAIN_KEYRING_SERVICE, key, value) + err = keyring.Set(currentVaultBackend, MAIN_KEYRING_SERVICE, key, value) + + if err == keyring.ErrUnsupportedPlatform || keyringNotConfigured(err) { + boldGreen := color.New(color.FgGreen).Add(color.Bold) + boldGreen.Printf("Warning: Fallback file keyring is being used") + err = keyring.Set(VAULT_BACKEND_FILE_MODE, MAIN_KEYRING_SERVICE, key, value) + } + + return err } func GetValueInKeyring(key string) (string, error) { currentVaultBackend, err := GetCurrentVaultBackend() if err != nil { - PrintErrorAndExit(1, err, "Unable to get current vault. Tip: run [infisical rest] then try again") + PrintErrorAndExit(1, err, "Unable to get current vault. Tip: run [infisical reset] then try again") } - return keyring.Get(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + value, err := keyring.Get(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + + if err == keyring.ErrUnsupportedPlatform || keyringNotConfigured(err) { + value, err = keyring.Get(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + } + return value, err + } func DeleteValueInKeyring(key string) error { @@ -38,5 +59,11 @@ func DeleteValueInKeyring(key string) error { return err } - return keyring.Delete(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + err = keyring.Delete(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + + if err == keyring.ErrUnsupportedPlatform || keyringNotConfigured(err) { + err = keyring.Delete(currentVaultBackend, MAIN_KEYRING_SERVICE, key) + } + + return err } diff --git a/cli/packages/util/vault.go b/cli/packages/util/vault.go index 14d6d10d9f..5907d93fc8 100644 --- a/cli/packages/util/vault.go +++ b/cli/packages/util/vault.go @@ -11,11 +11,11 @@ func GetCurrentVaultBackend() (string, error) { } if configFile.VaultBackendType == "" { - return "auto", nil + return VAULT_BACKEND_AUTO_MODE, nil } - if configFile.VaultBackendType != "auto" && configFile.VaultBackendType != "file" { - return "auto", nil + if configFile.VaultBackendType != VAULT_BACKEND_AUTO_MODE && configFile.VaultBackendType != VAULT_BACKEND_FILE_MODE { + return VAULT_BACKEND_AUTO_MODE, nil } return configFile.VaultBackendType, nil