Refactor plugin/yaml/main.go and plugin/yaml/yaml.go to support multiple YAML config files (#477)

This commit is contained in:
Boshi Lian 2024-10-28 01:57:55 -07:00 committed by GitHub
parent 23e18f4f7c
commit 4694964c11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 43 deletions

View file

@ -14,12 +14,12 @@ func main() {
Name: "yaml", Name: "yaml",
Usage: "sshpiperd yaml plugin", Usage: "sshpiperd yaml plugin",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringSliceFlag{
Name: "config", Name: "config",
Usage: "path to yaml config file", Usage: "path to yaml config files, can be globs as well",
Required: true, Required: true,
EnvVars: []string{"SSHPIPERD_YAML_CONFIG"}, EnvVars: []string{"SSHPIPERD_YAML_CONFIG"},
Destination: &plugin.File, Destination: &plugin.FileGlobs,
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "no-check-perm", Name: "no-check-perm",

View file

@ -9,12 +9,11 @@ import (
) )
type skelpipeWrapper struct { type skelpipeWrapper struct {
plugin *plugin pipe *yamlPipe
config *piperConfig
pipe *yamlPipe
} }
type skelpipeFromWrapper struct { type skelpipeFromWrapper struct {
plugin *plugin config *piperConfig
from *yamlPipeFrom from *yamlPipeFrom
to *yamlPipeTo to *yamlPipeTo
@ -28,7 +27,7 @@ type skelpipePublicKeyWrapper struct {
} }
type skelpipeToWrapper struct { type skelpipeToWrapper struct {
plugin *plugin config *piperConfig
username string username string
to *yamlPipeTo to *yamlPipeTo
@ -39,7 +38,7 @@ func (s *skelpipeWrapper) From() []libplugin.SkelPipeFrom {
for _, f := range s.pipe.From { for _, f := range s.pipe.From {
w := &skelpipeFromWrapper{ w := &skelpipeFromWrapper{
plugin: s.plugin, config: s.config,
from: &f, from: &f,
to: &s.pipe.To, to: &s.pipe.To,
} }
@ -70,7 +69,7 @@ func (s *skelpipeToWrapper) IgnoreHostKey(conn libplugin.ConnMetadata) bool {
} }
func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, error) { func (s *skelpipeToWrapper) KnownHosts(conn libplugin.ConnMetadata) ([]byte, error) {
return s.plugin.loadFileOrDecodeMany(s.to.KnownHosts, s.to.KnownHostsData, map[string]string{ return s.config.loadFileOrDecodeMany(s.to.KnownHosts, s.to.KnownHostsData, map[string]string{
"DOWNSTREAM_USER": conn.User(), "DOWNSTREAM_USER": conn.User(),
"UPSTREAM_USER": s.username, "UPSTREAM_USER": s.username,
}) })
@ -101,7 +100,7 @@ func (s *skelpipeFromWrapper) MatchConn(conn libplugin.ConnMetadata) (libplugin.
if matched { if matched {
return &skelpipeToWrapper{ return &skelpipeToWrapper{
plugin: s.plugin, config: s.config,
username: targetuser, username: targetuser,
to: s.to, to: s.to,
}, nil }, nil
@ -115,19 +114,19 @@ func (s *skelpipePasswordWrapper) TestPassword(conn libplugin.ConnMetadata, pass
} }
func (s *skelpipePublicKeyWrapper) AuthorizedKeys(conn libplugin.ConnMetadata) ([]byte, error) { func (s *skelpipePublicKeyWrapper) AuthorizedKeys(conn libplugin.ConnMetadata) ([]byte, error) {
return s.plugin.loadFileOrDecodeMany(s.from.AuthorizedKeys, s.from.AuthorizedKeysData, map[string]string{ return s.config.loadFileOrDecodeMany(s.from.AuthorizedKeys, s.from.AuthorizedKeysData, map[string]string{
"DOWNSTREAM_USER": conn.User(), "DOWNSTREAM_USER": conn.User(),
}) })
} }
func (s *skelpipePublicKeyWrapper) TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error) { func (s *skelpipePublicKeyWrapper) TrustedUserCAKeys(conn libplugin.ConnMetadata) ([]byte, error) {
return s.plugin.loadFileOrDecodeMany(s.from.TrustedUserCAKeys, s.from.TrustedUserCAKeysData, map[string]string{ return s.config.loadFileOrDecodeMany(s.from.TrustedUserCAKeys, s.from.TrustedUserCAKeysData, map[string]string{
"DOWNSTREAM_USER": conn.User(), "DOWNSTREAM_USER": conn.User(),
}) })
} }
func (s *skelpipeToWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) { func (s *skelpipeToWrapper) PrivateKey(conn libplugin.ConnMetadata) ([]byte, []byte, error) {
p, err := s.plugin.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(),
"UPSTREAM_USER": s.username, "UPSTREAM_USER": s.username,
}) })
@ -144,19 +143,21 @@ func (s *skelpipeToWrapper) OverridePassword(conn libplugin.ConnMetadata) ([]byt
} }
func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) { func (p *plugin) listPipe(_ libplugin.ConnMetadata) ([]libplugin.SkelPipe, error) {
config, 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 []libplugin.SkelPipe
for _, pipe := range config.Pipes { for _, config := range configs {
wrapper := &skelpipeWrapper{ for _, pipe := range config.Pipes {
plugin: p, wrapper := &skelpipeWrapper{
pipe: &pipe, config: &config,
} pipe: &pipe,
pipes = append(pipes, wrapper) }
pipes = append(pipes, wrapper)
}
} }
return pipes, nil return pipes, nil

View file

@ -9,6 +9,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -76,10 +77,12 @@ type yamlPipe struct {
type piperConfig struct { type piperConfig struct {
Version string `yaml:"version"` Version string `yaml:"version"`
Pipes []yamlPipe `yaml:"pipes,flow"` Pipes []yamlPipe `yaml:"pipes,flow"`
filename string
} }
type plugin struct { type plugin struct {
File string FileGlobs cli.StringSlice
NoCheckPerm bool NoCheckPerm bool
} }
@ -87,8 +90,7 @@ func newYamlPlugin() *plugin {
return &plugin{} return &plugin{}
} }
func (p *plugin) checkPerm() error { func (p *plugin) checkPerm(filename string) error {
filename := p.File
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return err return err
@ -111,28 +113,44 @@ func (p *plugin) checkPerm() error {
return nil return nil
} }
func (p *plugin) loadConfig() (piperConfig, error) { func (p *plugin) loadConfig() ([]piperConfig, error) {
var config piperConfig var allconfig []piperConfig
err := p.checkPerm() for _, fg := range p.FileGlobs.Value() {
if err != nil { files, err := filepath.Glob(fg)
return config, err if err != nil {
return nil, err
}
for _, file := range files {
if err := p.checkPerm(file); err != nil {
return nil, err
}
configbyte, err := os.ReadFile(file)
if err != nil {
return nil, err
}
var config piperConfig
err = yaml.Unmarshal(configbyte, &config)
if err != nil {
return nil, err
}
config.filename = file
allconfig = append(allconfig, config)
}
} }
configbyte, err := os.ReadFile(p.File) return allconfig, nil
if err != nil {
return config, err
}
err = yaml.Unmarshal(configbyte, &config)
if err != nil {
return config, err
}
return config, nil
} }
func (p *plugin) loadFileOrDecode(file string, base64data string, vars map[string]string) ([]byte, error) { func (p *piperConfig) loadFileOrDecode(file string, base64data string, vars map[string]string) ([]byte, error) {
if file != "" { if file != "" {
file = os.Expand(file, func(placeholderName string) string { file = os.Expand(file, func(placeholderName string) string {
@ -145,7 +163,7 @@ func (p *plugin) loadFileOrDecode(file string, base64data string, vars map[strin
}) })
if !filepath.IsAbs(file) { if !filepath.IsAbs(file) {
file = filepath.Join(filepath.Dir(p.File), file) file = filepath.Join(filepath.Dir(p.filename), file)
} }
return os.ReadFile(file) return os.ReadFile(file)
@ -158,7 +176,7 @@ func (p *plugin) loadFileOrDecode(file string, base64data string, vars map[strin
return nil, nil return nil, nil
} }
func (p *plugin) loadFileOrDecodeMany(files listOrString, base64data listOrString, vars map[string]string) ([]byte, error) { func (p *piperConfig) loadFileOrDecodeMany(files listOrString, base64data listOrString, vars map[string]string) ([]byte, error) {
var byteSlices [][]byte var byteSlices [][]byte
for _, file := range files.Combine() { for _, file := range files.Combine() {