parent
bcba6b2086
commit
25ddd65f25
3
.changes/unreleased/Changed-20250305-003415.yaml
Normal file
3
.changes/unreleased/Changed-20250305-003415.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
kind: Changed
|
||||||
|
body: 'FileDirective: use the config directory if path is not absolute'
|
||||||
|
time: 2025-03-05T00:34:15.689980075-06:00
|
3
.changes/unreleased/Fixed-20250304-235706.yaml
Normal file
3
.changes/unreleased/Fixed-20250304-235706.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: 'SSH: password authentication bugs'
|
||||||
|
time: 2025-03-04T23:57:06.326604774-06:00
|
@ -127,7 +127,7 @@ func (opts *ConfigOpts) ReadConfig() *ConfigOpts {
|
|||||||
|
|
||||||
unmarshalConfig(backyKoanf, "commands", &opts.Cmds, opts.Logger)
|
unmarshalConfig(backyKoanf, "commands", &opts.Cmds, opts.Logger)
|
||||||
|
|
||||||
validateCommandEnvironments(opts)
|
getCommandEnvironments(opts)
|
||||||
|
|
||||||
unmarshalConfig(backyKoanf, "hosts", &opts.Hosts, opts.Logger)
|
unmarshalConfig(backyKoanf, "hosts", &opts.Hosts, opts.Logger)
|
||||||
|
|
||||||
@ -245,11 +245,11 @@ func unmarshalConfig(k *koanf.Koanf, key string, target interface{}, log zerolog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCommandEnvironments(opts *ConfigOpts) {
|
func getCommandEnvironments(opts *ConfigOpts) {
|
||||||
for cmdName, cmdConf := range opts.Cmds {
|
for cmdName, cmdConf := range opts.Cmds {
|
||||||
|
opts.Logger.Debug().Str("env file", cmdConf.Env).Str("cmd", cmdName).Send()
|
||||||
if err := testFile(cmdConf.Env); err != nil {
|
if err := testFile(cmdConf.Env); err != nil {
|
||||||
opts.Logger.Info().Str("cmd", cmdName).Err(err).Send()
|
logging.ExitWithMSG("Could not open file"+cmdConf.Env+": "+err.Error(), 1, &opts.Logger)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
expandEnvVars(opts.backyEnv, cmdConf.Environment)
|
expandEnvVars(opts.backyEnv, cmdConf.Environment)
|
||||||
}
|
}
|
||||||
@ -499,16 +499,7 @@ func getVaultSecret(vaultClient *vault.Client, key *VaultKey) (string, error) {
|
|||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isVaultKey(str string) (string, bool) {
|
func parseVaultKey(keyName string, keys []*VaultKey) (*VaultKey, error) {
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
return strings.TrimPrefix(str, "vault:"), strings.HasPrefix(str, "vault:")
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseVaultKey(str string, keys []*VaultKey) (*VaultKey, error) {
|
|
||||||
keyName, isKey := isVaultKey(str)
|
|
||||||
if !isKey {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if k.Name == keyName {
|
if k.Name == keyName {
|
||||||
@ -635,7 +626,7 @@ func processCmds(opts *ConfigOpts) error {
|
|||||||
case "add", "remove", "modify", "checkIfExists", "delete", "password":
|
case "add", "remove", "modify", "checkIfExists", "delete", "password":
|
||||||
cmd.userMan, err = usermanager.NewUserManager(cmd.OS)
|
cmd.userMan, err = usermanager.NewUserManager(cmd.OS)
|
||||||
if cmd.UserOperation == "password" {
|
if cmd.UserOperation == "password" {
|
||||||
cmd.UserPassword = expandExternalConfigDirectives(cmd.UserPassword, opts)
|
cmd.UserPassword = getExternalConfigDirectiveValue(cmd.UserPassword, opts)
|
||||||
}
|
}
|
||||||
if cmd.Host != nil {
|
if cmd.Host != nil {
|
||||||
host, ok := opts.Hosts[*cmd.Host]
|
host, ok := opts.Hosts[*cmd.Host]
|
||||||
@ -645,7 +636,7 @@ func processCmds(opts *ConfigOpts) error {
|
|||||||
}
|
}
|
||||||
for indx, key := range cmd.UserSshPubKeys {
|
for indx, key := range cmd.UserSshPubKeys {
|
||||||
opts.Logger.Debug().Msg("adding SSH Keys")
|
opts.Logger.Debug().Msg("adding SSH Keys")
|
||||||
key = expandExternalConfigDirectives(key, opts)
|
key = getExternalConfigDirectiveValue(key, opts)
|
||||||
cmd.UserSshPubKeys[indx] = key
|
cmd.UserSshPubKeys[indx] = key
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"golang.org/x/crypto/ssh/knownhosts"
|
"golang.org/x/crypto/ssh/knownhosts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var PrivateKeyExtraInfoErr = errors.New("Private key may be encrypted. \nIf encrypted, make sure the password is specified correctly in the correct section. This may be done in one of three ways: \n privatekeypassword: env:PR_KEY_PASS \n privatekeypassword: file:/path/to/password-file \n privatekeypassword: password (not recommended). \n ")
|
var PrivateKeyExtraInfoErr = errors.New("Private key may be encrypted. \nIf encrypted, make sure the password is specified correctly in the correct section. This may be done in one of two ways: \n Using external directives - see docs \n privatekeypassword: password (not recommended). \n ")
|
||||||
var TS = strings.TrimSpace
|
var TS = strings.TrimSpace
|
||||||
|
|
||||||
// ConnectToHost connects to a host by looking up the config values in the file ~/.ssh/config
|
// ConnectToHost connects to a host by looking up the config values in the file ~/.ssh/config
|
||||||
@ -120,7 +120,6 @@ func (remoteConfig *Host) ConnectToHost(opts *ConfigOpts) error {
|
|||||||
return errors.Wrap(err, "could not create hostkeycallback function")
|
return errors.Wrap(err, "could not create hostkeycallback function")
|
||||||
}
|
}
|
||||||
remoteConfig.ClientConfig.HostKeyCallback = hostKeyCallback
|
remoteConfig.ClientConfig.HostKeyCallback = hostKeyCallback
|
||||||
// opts.Logger.Info().Str("user", remoteConfig.ClientConfig.User).Send()
|
|
||||||
|
|
||||||
remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.Logger)
|
remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.Logger)
|
||||||
if connectErr != nil {
|
if connectErr != nil {
|
||||||
@ -181,11 +180,7 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteHost.PrivateKeyPassword, err = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts, opts.Logger)
|
remoteHost.PrivateKeyPassword = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if remoteHost.PrivateKeyPassword == "" {
|
if remoteHost.PrivateKeyPassword == "" {
|
||||||
|
|
||||||
@ -208,14 +203,9 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if remoteHost.Password == "" {
|
if remoteHost.Password != "" {
|
||||||
|
|
||||||
remoteHost.Password, err = GetPassword(remoteHost.Password, opts, opts.Logger)
|
remoteHost.Password = GetPassword(remoteHost.Password, opts)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteHost.ClientConfig.Auth = append(remoteHost.ClientConfig.Auth, ssh.Password(remoteHost.Password))
|
remoteHost.ClientConfig.Auth = append(remoteHost.ClientConfig.Auth, ssh.Password(remoteHost.Password))
|
||||||
}
|
}
|
||||||
@ -250,14 +240,13 @@ func (remoteHost *Host) GetPrivateKeyFileFromConfig() {
|
|||||||
// If it is the port is searched in the SSH config file(s)
|
// If it is the port is searched in the SSH config file(s)
|
||||||
func (remoteHost *Host) GetPort() {
|
func (remoteHost *Host) GetPort() {
|
||||||
port := fmt.Sprintf("%d", remoteHost.Port)
|
port := fmt.Sprintf("%d", remoteHost.Port)
|
||||||
// port specifed?
|
// port specified?
|
||||||
// port will be 0 if missing from backy config
|
// port will be 0 if missing from backy config
|
||||||
if port == "0" {
|
if port == "0" {
|
||||||
port, _ = remoteHost.SSHConfigFile.SshConfigFile.Get(remoteHost.Host, "Port")
|
port, _ = remoteHost.SSHConfigFile.SshConfigFile.Get(remoteHost.Host, "Port")
|
||||||
|
|
||||||
if port == "" {
|
if port == "" {
|
||||||
|
|
||||||
// get port from default SSH config file
|
|
||||||
port = remoteHost.SSHConfigFile.DefaultUserSettings.Get(remoteHost.Host, "Port")
|
port = remoteHost.SSHConfigFile.DefaultUserSettings.Get(remoteHost.Host, "Port")
|
||||||
|
|
||||||
// set port to be default
|
// set port to be default
|
||||||
@ -272,7 +261,6 @@ func (remoteHost *Host) GetPort() {
|
|||||||
|
|
||||||
func (remoteHost *Host) CombineHostNameWithPort() {
|
func (remoteHost *Host) CombineHostNameWithPort() {
|
||||||
|
|
||||||
// if the port is already in the HostName, leave it
|
|
||||||
if strings.HasSuffix(remoteHost.HostName, fmt.Sprintf(":%d", remoteHost.Port)) {
|
if strings.HasSuffix(remoteHost.HostName, fmt.Sprintf(":%d", remoteHost.Port)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -332,64 +320,13 @@ func (remotehHost *Host) GetKnownHosts() error {
|
|||||||
return knownHostsFileErr
|
return knownHostsFileErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPrivateKeyPassword(key string, opts *ConfigOpts, log zerolog.Logger) (string, error) {
|
func GetPrivateKeyPassword(key string, opts *ConfigOpts) string {
|
||||||
|
return getExternalConfigDirectiveValue(key, opts)
|
||||||
var prKeyPassword string
|
|
||||||
if strings.HasPrefix(key, "file:") {
|
|
||||||
privKeyPassFilePath := strings.TrimPrefix(key, "file:")
|
|
||||||
privKeyPassFilePath, _ = getFullPathWithHomeDir(privKeyPassFilePath)
|
|
||||||
keyFile, keyFileErr := os.Open(privKeyPassFilePath)
|
|
||||||
if keyFileErr != nil {
|
|
||||||
return "", errors.Errorf("Private key password file %s failed to open. \n Make sure it is accessible and correct.", privKeyPassFilePath)
|
|
||||||
}
|
|
||||||
passwordScanner := bufio.NewScanner(keyFile)
|
|
||||||
for passwordScanner.Scan() {
|
|
||||||
prKeyPassword = passwordScanner.Text()
|
|
||||||
}
|
|
||||||
} else if strings.HasPrefix(key, "env:") {
|
|
||||||
privKey := strings.TrimPrefix(key, "env:")
|
|
||||||
privKey = strings.TrimPrefix(privKey, "${")
|
|
||||||
privKey = strings.TrimSuffix(privKey, "}")
|
|
||||||
privKey = strings.TrimPrefix(privKey, "$")
|
|
||||||
prKeyPassword = os.Getenv(privKey)
|
|
||||||
} else {
|
|
||||||
prKeyPassword = key
|
|
||||||
}
|
|
||||||
prKeyPassword = GetVaultKey(prKeyPassword, opts, opts.Logger)
|
|
||||||
return prKeyPassword, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPassword gets any password
|
// GetPassword gets any password
|
||||||
func GetPassword(pass string, opts *ConfigOpts, log zerolog.Logger) (string, error) {
|
func GetPassword(pass string, opts *ConfigOpts) string {
|
||||||
|
return getExternalConfigDirectiveValue(pass, opts)
|
||||||
pass = strings.TrimSpace(pass)
|
|
||||||
if pass == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
var password string
|
|
||||||
if strings.HasPrefix(pass, "file:") {
|
|
||||||
passFilePath := strings.TrimPrefix(pass, "file:")
|
|
||||||
passFilePath, _ = getFullPathWithHomeDir(passFilePath)
|
|
||||||
keyFile, keyFileErr := os.Open(passFilePath)
|
|
||||||
if keyFileErr != nil {
|
|
||||||
return "", errors.New("Password file failed to open")
|
|
||||||
}
|
|
||||||
passwordScanner := bufio.NewScanner(keyFile)
|
|
||||||
for passwordScanner.Scan() {
|
|
||||||
password = passwordScanner.Text()
|
|
||||||
}
|
|
||||||
} else if strings.HasPrefix(pass, "env:") {
|
|
||||||
passEnv := strings.TrimPrefix(pass, "env:")
|
|
||||||
passEnv = strings.TrimPrefix(passEnv, "${")
|
|
||||||
passEnv = strings.TrimSuffix(passEnv, "}")
|
|
||||||
passEnv = strings.TrimPrefix(passEnv, "$")
|
|
||||||
password = os.Getenv(passEnv)
|
|
||||||
} else {
|
|
||||||
password = pass
|
|
||||||
}
|
|
||||||
password = GetVaultKey(password, opts, opts.Logger)
|
|
||||||
|
|
||||||
return password, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (remoteConfig *Host) GetProxyJumpFromConfig(hosts map[string]*Host) error {
|
func (remoteConfig *Host) GetProxyJumpFromConfig(hosts map[string]*Host) error {
|
||||||
|
@ -258,7 +258,6 @@ func expandEnvVars(backyEnv map[string]string, envVars []string) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse env variables using new macros
|
|
||||||
for indx, v := range envVars {
|
for indx, v := range envVars {
|
||||||
if strings.HasPrefix(v, externDirectiveStart) && strings.HasSuffix(v, externDirectiveEnd) {
|
if strings.HasPrefix(v, externDirectiveStart) && strings.HasSuffix(v, externDirectiveEnd) {
|
||||||
if strings.HasPrefix(v, envExternDirectiveStart) {
|
if strings.HasPrefix(v, envExternDirectiveStart) {
|
||||||
@ -349,7 +348,7 @@ func parsePackageVersion(output string, cmdCtxLogger zerolog.Logger, command *Co
|
|||||||
return collectOutput(&cmdOutBuf, command.Name, cmdCtxLogger, false), err
|
return collectOutput(&cmdOutBuf, command.Name, cmdCtxLogger, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandExternalConfigDirectives(key string, opts *ConfigOpts) string {
|
func getExternalConfigDirectiveValue(key string, opts *ConfigOpts) string {
|
||||||
if !(strings.HasPrefix(key, externDirectiveStart) && strings.HasSuffix(key, externDirectiveEnd)) {
|
if !(strings.HasPrefix(key, externDirectiveStart) && strings.HasSuffix(key, externDirectiveEnd)) {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
@ -357,7 +356,7 @@ func expandExternalConfigDirectives(key string, opts *ConfigOpts) string {
|
|||||||
if strings.HasPrefix(key, envExternDirectiveStart) {
|
if strings.HasPrefix(key, envExternDirectiveStart) {
|
||||||
key = strings.TrimPrefix(key, envExternDirectiveStart)
|
key = strings.TrimPrefix(key, envExternDirectiveStart)
|
||||||
key = strings.TrimSuffix(key, externDirectiveEnd)
|
key = strings.TrimSuffix(key, externDirectiveEnd)
|
||||||
return os.Getenv(key)
|
key = os.Getenv(key)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(key, externFileDirectiveStart) {
|
if strings.HasPrefix(key, externFileDirectiveStart) {
|
||||||
var err error
|
var err error
|
||||||
@ -369,6 +368,9 @@ func expandExternalConfigDirectives(key string, opts *ConfigOpts) string {
|
|||||||
opts.Logger.Err(err).Send()
|
opts.Logger.Err(err).Send()
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
if !path.IsAbs(key) {
|
||||||
|
key = path.Join(opts.ConfigDir, key)
|
||||||
|
}
|
||||||
keyValue, err = os.ReadFile(key)
|
keyValue, err = os.ReadFile(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
opts.Logger.Err(err).Send()
|
opts.Logger.Err(err).Send()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user