extract skel into its own package (#596)
This breaks the dependency of libplugin on x/crypto, enabling people to use libplugin without having conflicts over the crypto module.
This commit is contained in:
parent
e6d3bb694b
commit
297b8c60e7
12 changed files with 91 additions and 99 deletions
2
go.mod
2
go.mod
|
|
@ -2,7 +2,7 @@ module github.com/tg123/sshpiper
|
||||||
|
|
||||||
go 1.24.0
|
go 1.24.0
|
||||||
|
|
||||||
toolchain go1.24.1
|
toolchain go1.24.3
|
||||||
|
|
||||||
replace golang.org/x/crypto => ./crypto
|
replace golang.org/x/crypto => ./crypto
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,27 @@
|
||||||
package libplugin
|
package skel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
"golang.org/x/crypto/ssh/knownhosts"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SkelPlugin struct {
|
type SkelPlugin struct {
|
||||||
cache *cache.Cache
|
cache *cache.Cache
|
||||||
listPipe func(ConnMetadata) ([]SkelPipe, error)
|
listPipe func(libplugin.ConnMetadata) ([]SkelPipe, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSkelPlugin(listPipe func(ConnMetadata) ([]SkelPipe, error)) *SkelPlugin {
|
func NewSkelPlugin(listPipe func(libplugin.ConnMetadata) ([]SkelPipe, error)) *SkelPlugin {
|
||||||
return &SkelPlugin{
|
return &SkelPlugin{
|
||||||
cache: cache.New(1*time.Minute, 10*time.Minute),
|
cache: cache.New(1*time.Minute, 10*time.Minute),
|
||||||
listPipe: listPipe,
|
listPipe: listPipe,
|
||||||
|
|
@ -29,43 +33,43 @@ type SkelPipe interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeFrom interface {
|
type SkelPipeFrom interface {
|
||||||
MatchConn(conn ConnMetadata) (SkelPipeTo, error)
|
MatchConn(conn libplugin.ConnMetadata) (SkelPipeTo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeFromPassword interface {
|
type SkelPipeFromPassword interface {
|
||||||
SkelPipeFrom
|
SkelPipeFrom
|
||||||
|
|
||||||
TestPassword(conn ConnMetadata, password []byte) (bool, error)
|
TestPassword(conn libplugin.ConnMetadata, password []byte) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeFromPublicKey interface {
|
type SkelPipeFromPublicKey interface {
|
||||||
SkelPipeFrom
|
SkelPipeFrom
|
||||||
|
|
||||||
AuthorizedKeys(conn ConnMetadata) ([]byte, error)
|
AuthorizedKeys(conn libplugin.ConnMetadata) ([]byte, error)
|
||||||
TrustedUserCAKeys(conn ConnMetadata) ([]byte, error)
|
TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeTo interface {
|
type SkelPipeTo interface {
|
||||||
Host(conn ConnMetadata) string
|
Host(conn libplugin.ConnMetadata) string
|
||||||
User(conn ConnMetadata) string
|
User(conn libplugin.ConnMetadata) string
|
||||||
IgnoreHostKey(conn ConnMetadata) bool
|
IgnoreHostKey(conn libplugin.ConnMetadata) bool
|
||||||
KnownHosts(conn ConnMetadata) ([]byte, error)
|
KnownHosts(conn libplugin.ConnMetadata) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeToPassword interface {
|
type SkelPipeToPassword interface {
|
||||||
SkelPipeTo
|
SkelPipeTo
|
||||||
|
|
||||||
OverridePassword(conn ConnMetadata) ([]byte, error)
|
OverridePassword(conn libplugin.ConnMetadata) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SkelPipeToPrivateKey interface {
|
type SkelPipeToPrivateKey interface {
|
||||||
SkelPipeTo
|
SkelPipeTo
|
||||||
|
|
||||||
PrivateKey(conn ConnMetadata) ([]byte, []byte, error)
|
PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) CreateConfig() *SshPiperPluginConfig {
|
func (p *SkelPlugin) CreateConfig() *libplugin.SshPiperPluginConfig {
|
||||||
return &SshPiperPluginConfig{
|
return &libplugin.SshPiperPluginConfig{
|
||||||
NextAuthMethodsCallback: p.SupportedMethods,
|
NextAuthMethodsCallback: p.SupportedMethods,
|
||||||
PasswordCallback: p.PasswordCallback,
|
PasswordCallback: p.PasswordCallback,
|
||||||
PublicKeyCallback: p.PublicKeyCallback,
|
PublicKeyCallback: p.PublicKeyCallback,
|
||||||
|
|
@ -73,7 +77,7 @@ func (p *SkelPlugin) CreateConfig() *SshPiperPluginConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) SupportedMethods(conn ConnMetadata) ([]string, error) {
|
func (p *SkelPlugin) SupportedMethods(conn libplugin.ConnMetadata) ([]string, error) {
|
||||||
set := make(map[string]bool)
|
set := make(map[string]bool)
|
||||||
|
|
||||||
pipes, err := p.listPipe(conn)
|
pipes, err := p.listPipe(conn)
|
||||||
|
|
@ -105,7 +109,7 @@ func (p *SkelPlugin) SupportedMethods(conn ConnMetadata) ([]string, error) {
|
||||||
return methods, nil
|
return methods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) VerifyHostKeyCallback(conn ConnMetadata, hostname, netaddr string, key []byte) error {
|
func (p *SkelPlugin) VerifyHostKeyCallback(conn libplugin.ConnMetadata, hostname, netaddr string, key []byte) error {
|
||||||
item, found := p.cache.Get(conn.UniqueID())
|
item, found := p.cache.Get(conn.UniqueID())
|
||||||
if !found {
|
if !found {
|
||||||
log.Warnf("connection expired when verifying host key for conn [%v]", conn.UniqueID())
|
log.Warnf("connection expired when verifying host key for conn [%v]", conn.UniqueID())
|
||||||
|
|
@ -122,7 +126,7 @@ func (p *SkelPlugin) VerifyHostKeyCallback(conn ConnMetadata, hostname, netaddr
|
||||||
return VerifyHostKeyFromKnownHosts(bytes.NewBuffer(data), hostname, netaddr, key)
|
return VerifyHostKeyFromKnownHosts(bytes.NewBuffer(data), hostname, netaddr, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) match(conn ConnMetadata, verify func(SkelPipeFrom) (bool, error)) (SkelPipeFrom, SkelPipeTo, error) {
|
func (p *SkelPlugin) match(conn libplugin.ConnMetadata, verify func(SkelPipeFrom) (bool, error)) (SkelPipeFrom, SkelPipeTo, error) {
|
||||||
pipes, err := p.listPipe(conn)
|
pipes, err := p.listPipe(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -154,7 +158,7 @@ func (p *SkelPlugin) match(conn ConnMetadata, verify func(SkelPipeFrom) (bool, e
|
||||||
return nil, nil, fmt.Errorf("no matching pipe for username [%v] found", conn.User())
|
return nil, nil, fmt.Errorf("no matching pipe for username [%v] found", conn.User())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) PasswordCallback(conn ConnMetadata, password []byte) (*Upstream, error) {
|
func (p *SkelPlugin) PasswordCallback(conn libplugin.ConnMetadata, password []byte) (*libplugin.Upstream, error) {
|
||||||
_, to, err := p.match(conn, func(from SkelPipeFrom) (bool, error) {
|
_, to, err := p.match(conn, func(from SkelPipeFrom) (bool, error) {
|
||||||
frompass, ok := from.(SkelPipeFromPassword)
|
frompass, ok := from.(SkelPipeFromPassword)
|
||||||
|
|
||||||
|
|
@ -176,8 +180,7 @@ func (p *SkelPlugin) PasswordCallback(conn ConnMetadata, password []byte) (*Upst
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) PublicKeyCallback(conn ConnMetadata, publicKey []byte) (*Upstream, error) {
|
func (p *SkelPlugin) PublicKeyCallback(conn libplugin.ConnMetadata, publicKey []byte) (*libplugin.Upstream, error) {
|
||||||
|
|
||||||
pubKey, err := ssh.ParsePublicKey(publicKey)
|
pubKey, err := ssh.ParsePublicKey(publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -246,7 +249,6 @@ func (p *SkelPlugin) PublicKeyCallback(conn ConnMetadata, publicKey []byte) (*Up
|
||||||
|
|
||||||
return verified, nil
|
return verified, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -259,8 +261,8 @@ func (p *SkelPlugin) PublicKeyCallback(conn ConnMetadata, publicKey []byte) (*Up
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SkelPlugin) createUpstream(conn ConnMetadata, to SkelPipeTo, originalPassword []byte) (*Upstream, error) {
|
func (p *SkelPlugin) createUpstream(conn libplugin.ConnMetadata, to SkelPipeTo, originalPassword []byte) (*libplugin.Upstream, error) {
|
||||||
host, port, err := SplitHostPortForSSH(to.Host(conn))
|
host, port, err := libplugin.SplitHostPortForSSH(to.Host(conn))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +274,7 @@ func (p *SkelPlugin) createUpstream(conn ConnMetadata, to SkelPipeTo, originalPa
|
||||||
|
|
||||||
p.cache.SetDefault(conn.UniqueID(), to)
|
p.cache.SetDefault(conn.UniqueID(), to)
|
||||||
|
|
||||||
u := &Upstream{
|
u := &libplugin.Upstream{
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: int32(port), // port is already checked to be within int32 range in SplitHostPortForSSH
|
Port: int32(port), // port is already checked to be within int32 range in SplitHostPortForSSH
|
||||||
UserName: user,
|
UserName: user,
|
||||||
|
|
@ -287,9 +289,9 @@ func (p *SkelPlugin) createUpstream(conn ConnMetadata, to SkelPipeTo, originalPa
|
||||||
}
|
}
|
||||||
|
|
||||||
if overridepassword != nil {
|
if overridepassword != nil {
|
||||||
u.Auth = CreatePasswordAuth(overridepassword)
|
u.Auth = libplugin.CreatePasswordAuth(overridepassword)
|
||||||
} else {
|
} else {
|
||||||
u.Auth = CreatePasswordAuth(originalPassword)
|
u.Auth = libplugin.CreatePasswordAuth(originalPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
case SkelPipeToPrivateKey:
|
case SkelPipeToPrivateKey:
|
||||||
|
|
@ -298,10 +300,29 @@ func (p *SkelPlugin) createUpstream(conn ConnMetadata, to SkelPipeTo, originalPa
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Auth = CreatePrivateKeyAuth(priv, cert)
|
u.Auth = libplugin.CreatePrivateKeyAuth(priv, cert)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("pipe to does not support any auth method")
|
return nil, fmt.Errorf("pipe to does not support any auth method")
|
||||||
}
|
}
|
||||||
|
|
||||||
return u, err
|
return u, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VerifyHostKeyFromKnownHosts(knownhostsData io.Reader, hostname, netaddr string, key []byte) error {
|
||||||
|
hostKeyCallback, err := knownhosts.NewFromReader(knownhostsData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub, err := ssh.ParsePublicKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", netaddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostKeyCallback(hostname, addr, pub)
|
||||||
|
}
|
||||||
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
"golang.org/x/crypto/ssh/knownhosts"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func AuthMethodTypeToName(a AuthMethod) string {
|
func AuthMethodTypeToName(a AuthMethod) string {
|
||||||
|
|
@ -89,7 +87,6 @@ func SplitHostPortForSSH(addr string) (host string, port int, err error) {
|
||||||
|
|
||||||
// DialForSSH is the modified version of net.Dial, would add ":22" automaticlly
|
// DialForSSH is the modified version of net.Dial, would add ":22" automaticlly
|
||||||
func DialForSSH(addr string) (net.Conn, error) {
|
func DialForSSH(addr string) (net.Conn, error) {
|
||||||
|
|
||||||
if _, _, err := net.SplitHostPort(addr); err != nil && addr != "" {
|
if _, _, err := net.SplitHostPort(addr); err != nil && addr != "" {
|
||||||
// test valid after concat :22
|
// test valid after concat :22
|
||||||
if _, _, err := net.SplitHostPort(addr + ":22"); err == nil {
|
if _, _, err := net.SplitHostPort(addr + ":22"); err == nil {
|
||||||
|
|
@ -154,22 +151,3 @@ func CreateRetryCurrentPluginAuth(meta map[string]string) *Upstream_RetryCurrent
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyHostKeyFromKnownHosts(knownhostsData io.Reader, hostname, netaddr string, key []byte) error {
|
|
||||||
hostKeyCallback, err := knownhosts.NewFromReader(knownhostsData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
pub, err := ssh.ParsePublicKey(key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", netaddr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostKeyCallback(hostname, addr, pub)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
||||||
Name: "docker",
|
Name: "docker",
|
||||||
Usage: "sshpiperd docker plugin, see config in https://github.com/tg123/sshpiper/tree/master/plugin/docker",
|
Usage: "sshpiperd docker plugin, see config in https://github.com/tg123/sshpiper/tree/master/plugin/docker",
|
||||||
|
|
@ -18,7 +18,7 @@ func main() {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
skel := libplugin.NewSkelPlugin(plugin.listPipe)
|
skel := skel.NewSkelPlugin(plugin.listPipe)
|
||||||
return skel.CreateConfig(), nil
|
return skel.CreateConfig(), nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type skelpipeWrapper struct {
|
type skelpipeWrapper struct {
|
||||||
|
|
@ -40,18 +41,17 @@ type skelpipeToPrivateKeyWrapper struct {
|
||||||
skelpipeToWrapper
|
skelpipeToWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeWrapper) From() []libplugin.SkelPipeFrom {
|
func (s *skelpipeWrapper) From() []skel.SkelPipeFrom {
|
||||||
|
|
||||||
w := skelpipeFromWrapper{
|
w := skelpipeFromWrapper{
|
||||||
skelpipeWrapper: *s,
|
skelpipeWrapper: *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.pipe.PrivateKey != "" || s.pipe.AuthorizedKeys != "" {
|
if s.pipe.PrivateKey != "" || s.pipe.AuthorizedKeys != "" {
|
||||||
return []libplugin.SkelPipeFrom{&skelpipePublicKeyWrapper{
|
return []skel.SkelPipeFrom{&skelpipePublicKeyWrapper{
|
||||||
skelpipeFromWrapper: w,
|
skelpipeFromWrapper: w,
|
||||||
}}
|
}}
|
||||||
} else {
|
} else {
|
||||||
return []libplugin.SkelPipeFrom{&skelpipePasswordWrapper{
|
return []skel.SkelPipeFrom{&skelpipePasswordWrapper{
|
||||||
skelpipeFromWrapper: w,
|
skelpipeFromWrapper: w,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +73,7 @@ func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, err
|
||||||
return nil, nil // TODO support this
|
return nil, nil // TODO support this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.SkelPipeTo, error) {
|
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (skel.SkelPipeTo, error) {
|
||||||
user := conn.User()
|
user := conn.User()
|
||||||
|
|
||||||
matched := s.pipe.ClientUsername == user || s.pipe.ClientUsername == ""
|
matched := s.pipe.ClientUsername == user || s.pipe.ClientUsername == ""
|
||||||
|
|
@ -130,13 +130,13 @@ func (s *skelpipeToPasswordWrapper) OverridePassword(conn libplugin.ConnMetadata
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) {
|
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]skel.SkelPipe, error) {
|
||||||
dpipes, err := p.list()
|
dpipes, err := p.list()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipes []libplugin.SkelPipe
|
var pipes []skel.SkelPipe
|
||||||
for _, pipe := range dpipes {
|
for _, pipe := range dpipes {
|
||||||
wrapper := &skelpipeWrapper{
|
wrapper := &skelpipeWrapper{
|
||||||
plugin: p,
|
plugin: p,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,7 +29,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
skel := libplugin.NewSkelPlugin(plugin.listPipe)
|
skel := skel.NewSkelPlugin(plugin.listPipe)
|
||||||
return skel.CreateConfig(), nil
|
return skel.CreateConfig(), nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/tg123/go-htpasswd"
|
"github.com/tg123/go-htpasswd"
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
piperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1"
|
piperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
@ -52,8 +53,8 @@ type skelpipeToPrivateKeyWrapper struct {
|
||||||
skelpipeToWrapper
|
skelpipeToWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeWrapper) From() []libplugin.SkelPipeFrom {
|
func (s *skelpipeWrapper) From() []skel.SkelPipeFrom {
|
||||||
var froms []libplugin.SkelPipeFrom
|
var froms []skel.SkelPipeFrom
|
||||||
for _, f := range s.pipe.Spec.From {
|
for _, f := range s.pipe.Spec.From {
|
||||||
|
|
||||||
w := &skelpipeFromWrapper{
|
w := &skelpipeFromWrapper{
|
||||||
|
|
@ -92,7 +93,7 @@ func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, err
|
||||||
return base64.StdEncoding.DecodeString(s.to.KnownHostsData)
|
return base64.StdEncoding.DecodeString(s.to.KnownHostsData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.SkelPipeTo, error) {
|
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (skel.SkelPipeTo, error) {
|
||||||
user := conn.User()
|
user := conn.User()
|
||||||
|
|
||||||
matched := s.from.Username == user
|
matched := s.from.Username == user
|
||||||
|
|
@ -142,7 +143,6 @@ func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipePasswordWrapper) TestPassword(conn libplugin.ConnMetadata, password []byte) (bool, error) {
|
func (s *skelpipePasswordWrapper) TestPassword(conn libplugin.ConnMetadata, password []byte) (bool, error) {
|
||||||
|
|
||||||
pwds, err := loadStringAndFile(s.from.HtpasswdData, s.from.HtpasswdFile)
|
pwds, err := loadStringAndFile(s.from.HtpasswdData, s.from.HtpasswdFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|
@ -179,7 +179,6 @@ func (s *skelpipePublicKeyWrapper) TrustedUserCAKeys(conn libplugin.ConnMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) {
|
func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) {
|
||||||
|
|
||||||
log.Debugf("mapping to %v private key using secret %v", s.to.Host, s.to.PrivateKeySecret.Name)
|
log.Debugf("mapping to %v private key using secret %v", s.to.Host, s.to.PrivateKeySecret.Name)
|
||||||
secret, err := s.plugin.k8sclient.Secrets(s.pipe.Namespace).Get(context.Background(), s.to.PrivateKeySecret.Name, metav1.GetOptions{})
|
secret, err := s.plugin.k8sclient.Secrets(s.pipe.Namespace).Get(context.Background(), s.to.PrivateKeySecret.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -237,7 +236,6 @@ func (s *skelpipeToPasswordWrapper) OverridePassword(conn libplugin.ConnMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadStringAndFile(base64orraw string, filepath string) ([][]byte, error) {
|
func loadStringAndFile(base64orraw string, filepath string) ([][]byte, error) {
|
||||||
|
|
||||||
all := make([][]byte, 0, 2)
|
all := make([][]byte, 0, 2)
|
||||||
|
|
||||||
if base64orraw != "" {
|
if base64orraw != "" {
|
||||||
|
|
@ -261,13 +259,13 @@ func loadStringAndFile(base64orraw string, filepath string) ([][]byte, error) {
|
||||||
return all, nil
|
return all, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) {
|
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]skel.SkelPipe, error) {
|
||||||
kpipes, err := p.list()
|
kpipes, err := p.list()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipes []libplugin.SkelPipe
|
var pipes []skel.SkelPipe
|
||||||
for _, pipe := range kpipes {
|
for _, pipe := range kpipes {
|
||||||
wrapper := &skelpipeWrapper{
|
wrapper := &skelpipeWrapper{
|
||||||
plugin: p,
|
plugin: p,
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ import (
|
||||||
|
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
libplugin.CreateAndRunPluginTemplate(&libplugin.PluginTemplate{
|
||||||
Name: "workingdir",
|
Name: "workingdir",
|
||||||
Usage: "sshpiperd workingdir plugin",
|
Usage: "sshpiperd workingdir plugin",
|
||||||
|
|
@ -54,7 +54,6 @@ func main() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
||||||
|
|
||||||
fac := workdingdirFactory{
|
fac := workdingdirFactory{
|
||||||
root: c.String("root"),
|
root: c.String("root"),
|
||||||
allowBadUsername: c.Bool("allow-baduser-name"),
|
allowBadUsername: c.Bool("allow-baduser-name"),
|
||||||
|
|
@ -66,10 +65,9 @@ func main() {
|
||||||
|
|
||||||
checktotp := c.Bool("check-totp")
|
checktotp := c.Bool("check-totp")
|
||||||
|
|
||||||
skel := libplugin.NewSkelPlugin(fac.listPipe)
|
skel := skel.NewSkelPlugin(fac.listPipe)
|
||||||
config := skel.CreateConfig()
|
config := skel.CreateConfig()
|
||||||
config.NextAuthMethodsCallback = func(conn libplugin.ConnMetadata) ([]string, error) {
|
config.NextAuthMethodsCallback = func(conn libplugin.ConnMetadata) ([]string, error) {
|
||||||
|
|
||||||
auth := []string{"publickey"}
|
auth := []string{"publickey"}
|
||||||
|
|
||||||
if !fac.noPasswordAuth {
|
if !fac.noPasswordAuth {
|
||||||
|
|
@ -80,7 +78,6 @@ func main() {
|
||||||
if conn.GetMeta("totp") != "checked" {
|
if conn.GetMeta("totp") != "checked" {
|
||||||
auth = []string{"keyboard-interactive"}
|
auth = []string{"keyboard-interactive"}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth, nil
|
return auth, nil
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type workdingdirFactory struct {
|
type workdingdirFactory struct {
|
||||||
|
|
@ -50,18 +51,17 @@ type skelpipeToPrivateKeyWrapper struct {
|
||||||
skelpipeToWrapper
|
skelpipeToWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeWrapper) From() []libplugin.SkelPipeFrom {
|
func (s *skelpipeWrapper) From() []skel.SkelPipeFrom {
|
||||||
|
|
||||||
w := skelpipeFromWrapper{
|
w := skelpipeFromWrapper{
|
||||||
skelpipeWrapper: *s,
|
skelpipeWrapper: *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.dir.Exists(userAuthorizedKeysFile) && s.dir.Exists(userKeyFile) {
|
if s.dir.Exists(userAuthorizedKeysFile) && s.dir.Exists(userKeyFile) {
|
||||||
return []libplugin.SkelPipeFrom{&skelpipePublicKeyWrapper{
|
return []skel.SkelPipeFrom{&skelpipePublicKeyWrapper{
|
||||||
skelpipeFromWrapper: w,
|
skelpipeFromWrapper: w,
|
||||||
}}
|
}}
|
||||||
} else {
|
} else {
|
||||||
return []libplugin.SkelPipeFrom{&skelpipePasswordWrapper{
|
return []skel.SkelPipeFrom{&skelpipePasswordWrapper{
|
||||||
skelpipeFromWrapper: w,
|
skelpipeFromWrapper: w,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
@ -83,8 +83,7 @@ func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, err
|
||||||
return s.dir.Readfile(userKnownHosts)
|
return s.dir.Readfile(userKnownHosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.SkelPipeTo, error) {
|
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (skel.SkelPipeTo, error) {
|
||||||
|
|
||||||
if s.dir.Exists(userKeyFile) {
|
if s.dir.Exists(userKeyFile) {
|
||||||
return &skelpipeToPrivateKeyWrapper{
|
return &skelpipeToPrivateKeyWrapper{
|
||||||
skelpipeToWrapper: skelpipeToWrapper(*s),
|
skelpipeToWrapper: skelpipeToWrapper(*s),
|
||||||
|
|
@ -121,8 +120,7 @@ func (s *skelpipeToPasswordWrapper) OverridePassword(conn libplugin.ConnMetadata
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wf *workdingdirFactory) listPipe(conn libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) {
|
func (wf *workdingdirFactory) listPipe(conn libplugin.ConnMetadata) ([]skel.SkelPipe, error) {
|
||||||
|
|
||||||
user := conn.User()
|
user := conn.User()
|
||||||
|
|
||||||
if !wf.allowBadUsername {
|
if !wf.allowBadUsername {
|
||||||
|
|
@ -131,11 +129,10 @@ func (wf *workdingdirFactory) listPipe(conn libplugin.ConnMetadata) ([]libplugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipes []libplugin.SkelPipe
|
var pipes []skel.SkelPipe
|
||||||
userdir := path.Join(wf.root, conn.User())
|
userdir := path.Join(wf.root, conn.User())
|
||||||
|
|
||||||
_ = filepath.Walk(userdir, func(path string, info os.FileInfo, err error) (stop error) {
|
_ = filepath.Walk(userdir, func(path string, info os.FileInfo, err error) (stop error) {
|
||||||
|
|
||||||
log.Infof("search upstreams in path: %v", path)
|
log.Infof("search upstreams in path: %v", path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("error walking path: %v", err)
|
log.Infof("error walking path: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,10 @@ type workingdir struct {
|
||||||
Strict bool
|
Strict bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
// Base username validation on Debians default: https://sources.debian.net/src/adduser/3.113%2Bnmu3/adduser.conf/#L85
|
||||||
// Base username validation on Debians default: https://sources.debian.net/src/adduser/3.113%2Bnmu3/adduser.conf/#L85
|
// -> NAME_REGEX="^[a-z][-a-z0-9_]*\$"
|
||||||
// -> NAME_REGEX="^[a-z][-a-z0-9_]*\$"
|
// The length is limited to 32 characters. See man 8 useradd: https://linux.die.net/man/8/useradd
|
||||||
// The length is limited to 32 characters. See man 8 useradd: https://linux.die.net/man/8/useradd
|
var usernameRule *regexp.Regexp = regexp.MustCompile("^[a-z_][-a-z0-9_]{0,31}$")
|
||||||
usernameRule *regexp.Regexp = regexp.MustCompile("^[a-z_][-a-z0-9_]{0,31}$")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
userAuthorizedKeysFile = "authorized_keys"
|
userAuthorizedKeysFile = "authorized_keys"
|
||||||
|
|
@ -52,7 +50,7 @@ func (w *workingdir) checkPerm(file string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi.Mode().Perm()&0077 != 0 {
|
if fi.Mode().Perm()&0o077 != 0 {
|
||||||
return fmt.Errorf("%v's perm is too open", filename)
|
return fmt.Errorf("%v's perm is too open", filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ func main() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
CreateConfig: func(c *cli.Context) (*libplugin.SshPiperPluginConfig, error) {
|
||||||
skel := libplugin.NewSkelPlugin(plugin.listPipe)
|
skel := skel.NewSkelPlugin(plugin.listPipe)
|
||||||
return skel.CreateConfig(), nil
|
return skel.CreateConfig(), nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"os/user"
|
"os/user"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/tg123/sshpiper/libplugin"
|
"github.com/tg123/sshpiper/libplugin"
|
||||||
|
"github.com/tg123/sshpiper/libplugin/skel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type skelpipeWrapper struct {
|
type skelpipeWrapper struct {
|
||||||
|
|
@ -45,8 +47,8 @@ type skelpipeToPrivateKeyWrapper struct {
|
||||||
skelpipeToWrapper
|
skelpipeToWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeWrapper) From() []libplugin.SkelPipeFrom {
|
func (s *skelpipeWrapper) From() []skel.SkelPipeFrom {
|
||||||
var froms []libplugin.SkelPipeFrom
|
var froms []skel.SkelPipeFrom
|
||||||
for _, f := range s.pipe.From {
|
for _, f := range s.pipe.From {
|
||||||
|
|
||||||
w := &skelpipeFromWrapper{
|
w := &skelpipeFromWrapper{
|
||||||
|
|
@ -87,7 +89,7 @@ func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.SkelPipeTo, error) {
|
func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (skel.SkelPipeTo, error) {
|
||||||
username := conn.User()
|
username := conn.User()
|
||||||
|
|
||||||
targetuser := s.to.Username
|
targetuser := s.to.Username
|
||||||
|
|
@ -175,7 +177,6 @@ func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([
|
||||||
"DOWNSTREAM_USER": conn.User(),
|
"DOWNSTREAM_USER": conn.User(),
|
||||||
"UPSTREAM_USER": s.username,
|
"UPSTREAM_USER": s.username,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -187,13 +188,13 @@ func (s *skelpipeToPasswordWrapper) OverridePassword(conn libplugin.ConnMetadata
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) {
|
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]skel.SkelPipe, error) {
|
||||||
configs, err := p.loadConfig()
|
configs, err := p.loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipes []libplugin.SkelPipe
|
var pipes []skel.SkelPipe
|
||||||
for _, config := range configs {
|
for _, config := range configs {
|
||||||
for _, pipe := range config.Pipes {
|
for _, pipe := range config.Pipes {
|
||||||
wrapper := &skelpipeWrapper{
|
wrapper := &skelpipeWrapper{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue