我正在研究软件包config
,该软件包指定了用于批量配置网络设备的配置选项和命令。现在,config.New
函数接受可以包含文本模板值的yaml源文本。对于yaml文件中的auth
键,您可以指定模板值auth: {{.Password}}
来提示用户输入执行模板的密码。
此功能安全吗?原始yaml源文件不会在模板执行时进行修改,据我所知,只能通过从*Config
返回的config.New
结构访问用户指定的密码值。不幸的是,必须导出Config
的字段,才能使yaml被viper
编组。这会带来安全问题吗?
这是我的代码:
package config
import (
"fmt"
"github.com/spf13/viper"
"golang.org/x/crypto/ssh/terminal"
"io"
"os"
"text/template"
)
// Config contains network device configuration options and commands.
type Config struct {
Hosts string `yaml:"hosts"` // hosts to configure
User string `yaml:"user"` // username for host login
Auth string `yaml:"auth"` // SSH authentication method
Allow string `yaml:"allow"` // allow either all or known hosts
Timeout int `yaml:"timeout"` // duration to wait to establish a connection
Config []struct {
Vendor string `yaml:"vendor"` // vendor that supports `cmds`
Cmds []string `yaml:"cmds"` // configuration commands to run
} `yaml:"config"` // list of vendor-configuration command sets
}
// New creates a new Config from a yaml or text template file.
func New(src string) (*Config, error) {
var cfg Config
pr, pw := io.Pipe()
tmpl, err := template.New("config").Parse(src)
if err != nil {
return nil, err
}
tmplErr := make(chan error, 1)
go func(tmpl *template.Template, cfg Config, pw *io.PipeWriter, tmplErr chan<- error) {
defer pw.Close()
if err := tmpl.Execute(pw, &cfg); err != nil {
tmplErr <- err
}
close(tmplErr)
}(tmpl, cfg, pw, tmplErr)
select {
case err := <-tmplErr:
return nil, err
default:
v := viper.New()
v.SetConfigType("yaml")
if err := v.ReadConfig(pr); err != nil {
return nil, err
}
if err := v.Unmarshal(&cfg); err != nil {
return nil, err
}
return &cfg, nil
}
}
// Password prompts the user for their password.
func (c *Config) Password() string {
fmt.Fprint(os.Stderr, "Password: ")
password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
fmt.Fprintln(os.Stderr)
return string(password)
}
示例main.go
:
package main
import (
"fmt"
".../config"
"log"
)
const TestConfig = `
# Example configuration for restarting access points.
---
hosts : access_points
user : user
auth : &password {{.Password}} # Prompt for password and store the value.
allow : known_hosts # Only allow connections to known hosts.
timeout: 5
config:
- vendor: cisco
cmds:
- enable
- *password # Pass the password value to enter enabled mode.
- capwap ap restart
- exit
`
func main() {
cfg, err := config.New(TestConfig)
if err != nil {
log.Fatal(err)
}
fmt.Println(cfg.Auth)
}
任何提示或建议,不胜感激。我不想意外泄露任何人的密码或泄漏敏感数据。