Add accept_any_key option to accept any SSH key and pass fingerprint

New YAML config option: accept_any_key: true
- Accepts any public key without verification against authorized_keys
- Still passes the client's key fingerprint in the upstream username
- Format: fp:FINGERPRINT.originaluser
- Useful for proxying to apps that identify users by SSH key fingerprint
This commit is contained in:
Russell Ballestrini 2025-12-21 09:05:05 -05:00
parent 065a7c359e
commit 56577b727e
3 changed files with 21 additions and 1 deletions

View file

@ -52,6 +52,15 @@ type SkelPipeFromPublicKey interface {
TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error) TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error)
} }
// SkelPipeFromPublicKeyAcceptAny is an optional interface that allows accepting any public key
// without verification. When AcceptAnyKey() returns true, the key is accepted without checking
// against authorized_keys. The client's key fingerprint is still passed to the upstream.
type SkelPipeFromPublicKeyAcceptAny interface {
SkelPipeFromPublicKey
AcceptAnyKey() bool
}
type SkelPipeTo interface { type SkelPipeTo interface {
Host(conn libplugin.ConnMetadata) string Host(conn libplugin.ConnMetadata) string
User(conn libplugin.ConnMetadata) string User(conn libplugin.ConnMetadata) string
@ -210,6 +219,12 @@ func (p *SkelPlugin) PublicKeyCallback(conn libplugin.ConnMetadata, publicKey []
return false, nil return false, nil
} }
// Check if this pipe accepts any key without verification
if acceptAny, ok := from.(SkelPipeFromPublicKeyAcceptAny); ok && acceptAny.AcceptAnyKey() {
log.Debugf("accepting any public key for user %s (accept_any_key: true)", conn.User())
return true, nil
}
verified := false verified := false
if isCert { if isCert {

View file

@ -172,6 +172,10 @@ func (s *skelpipePublicKeyWrapper) TrustedUserCAKeys(conn libplugin.ConnMetadata
}) })
} }
func (s *skelpipePublicKeyWrapper) AcceptAnyKey() bool {
return s.from.AcceptAnyKey
}
func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) { func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) {
p, err := s.config.loadFileOrDecode(s.to.PrivateKey, s.to.PrivateKeyData, map[string]string{ p, err := s.config.loadFileOrDecode(s.to.PrivateKey, s.to.PrivateKeyData, map[string]string{
"DOWNSTREAM_USER": conn.User(), "DOWNSTREAM_USER": conn.User(),

View file

@ -21,10 +21,11 @@ type yamlPipeFrom struct {
AuthorizedKeysData listOrString `yaml:"authorized_keys_data,omitempty"` AuthorizedKeysData listOrString `yaml:"authorized_keys_data,omitempty"`
TrustedUserCAKeys listOrString `yaml:"trusted_user_ca_keys,omitempty"` TrustedUserCAKeys listOrString `yaml:"trusted_user_ca_keys,omitempty"`
TrustedUserCAKeysData listOrString `yaml:"trusted_user_ca_keys_data,omitempty"` TrustedUserCAKeysData listOrString `yaml:"trusted_user_ca_keys_data,omitempty"`
AcceptAnyKey bool `yaml:"accept_any_key,omitempty"`
} }
func (f yamlPipeFrom) SupportPublicKey() bool { func (f yamlPipeFrom) SupportPublicKey() bool {
return f.AuthorizedKeys.Any() || f.AuthorizedKeysData.Any() || f.TrustedUserCAKeys.Any() || f.TrustedUserCAKeysData.Any() return f.AcceptAnyKey || f.AuthorizedKeys.Any() || f.AuthorizedKeysData.Any() || f.TrustedUserCAKeys.Any() || f.TrustedUserCAKeysData.Any()
} }
type yamlPipeTo struct { type yamlPipeTo struct {