v0.10.0
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed

This commit is contained in:
Andrew Woodlee 2025-03-05 00:35:14 -06:00
parent bcba6b2086
commit 25ddd65f25
5 changed files with 27 additions and 91 deletions

View 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

View File

@ -0,0 +1,3 @@
kind: Fixed
body: 'SSH: password authentication bugs'
time: 2025-03-04T23:57:06.326604774-06:00

View File

@ -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 {

View File

@ -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 {

View File

@ -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()