From f635033e3e953e74d67b76a520c9760786330af5 Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Tue, 24 Jan 2017 23:43:28 +0000 Subject: Switch to scl, an extension of hcl --- server/config/config.go | 105 +++++++++++++----------------------- server/config/config_test.go | 8 +-- server/config/testdata/config.go | 48 ----------------- server/config/testdata/empty.config | 0 server/config/testdata/test.config | 42 +++++++++++++++ 5 files changed, 82 insertions(+), 121 deletions(-) delete mode 100644 server/config/testdata/config.go create mode 100644 server/config/testdata/empty.config create mode 100644 server/config/testdata/test.config (limited to 'server') diff --git a/server/config/config.go b/server/config/config.go index eec6d73..9ac4a7d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -3,26 +3,24 @@ package config import ( "bytes" "fmt" - "io" "log" "os" "strconv" "strings" "github.com/hashicorp/go-multierror" - "github.com/mitchellh/mapstructure" + "github.com/homemade/scl" "github.com/nsheridan/cashier/server/helpers/vault" "github.com/pkg/errors" - "github.com/spf13/viper" ) // Config holds the final server configuration. type Config struct { - Server *Server `mapstructure:"server"` - Auth *Auth `mapstructure:"auth"` - SSH *SSH `mapstructure:"ssh"` - AWS *AWS `mapstructure:"aws"` - Vault *Vault `mapstructure:"vault"` + Server *Server `hcl:"server"` + Auth *Auth `hcl:"auth"` + SSH *SSH `hcl:"ssh"` + AWS *AWS `hcl:"aws"` + Vault *Vault `hcl:"vault"` } // Database holds database configuration. @@ -30,51 +28,51 @@ type Database map[string]string // Server holds the configuration specific to the web server and sessions. type Server struct { - UseTLS bool `mapstructure:"use_tls"` - TLSKey string `mapstructure:"tls_key"` - TLSCert string `mapstructure:"tls_cert"` - LetsEncryptServername string `mapstructure:"letsencrypt_servername"` - LetsEncryptCache string `mapstructure:"letsencrypt_cachedir"` - Addr string `mapstructure:"address"` - Port int `mapstructure:"port"` - User string `mapstructure:"user"` - CookieSecret string `mapstructure:"cookie_secret"` - CSRFSecret string `mapstructure:"csrf_secret"` - HTTPLogFile string `mapstructure:"http_logfile"` - Database Database `mapstructure:"database"` - Datastore string `mapstructure:"datastore"` // Deprecated. TODO: remove. + UseTLS bool `hcl:"use_tls"` + TLSKey string `hcl:"tls_key"` + TLSCert string `hcl:"tls_cert"` + LetsEncryptServername string `hcl:"letsencrypt_servername"` + LetsEncryptCache string `hcl:"letsencrypt_cachedir"` + Addr string `hcl:"address"` + Port int `hcl:"port"` + User string `hcl:"user"` + CookieSecret string `hcl:"cookie_secret"` + CSRFSecret string `hcl:"csrf_secret"` + HTTPLogFile string `hcl:"http_logfile"` + Database Database `hcl:"database"` + Datastore string `hcl:"datastore"` // Deprecated. TODO: remove. } // Auth holds the configuration specific to the OAuth provider. type Auth struct { - OauthClientID string `mapstructure:"oauth_client_id"` - OauthClientSecret string `mapstructure:"oauth_client_secret"` - OauthCallbackURL string `mapstructure:"oauth_callback_url"` - Provider string `mapstructure:"provider"` - ProviderOpts map[string]string `mapstructure:"provider_opts"` - UsersWhitelist []string `mapstructure:"users_whitelist"` + OauthClientID string `hcl:"oauth_client_id"` + OauthClientSecret string `hcl:"oauth_client_secret"` + OauthCallbackURL string `hcl:"oauth_callback_url"` + Provider string `hcl:"provider"` + ProviderOpts map[string]string `hcl:"provider_opts"` + UsersWhitelist []string `hcl:"users_whitelist"` } // SSH holds the configuration specific to signing ssh keys. type SSH struct { - SigningKey string `mapstructure:"signing_key"` - AdditionalPrincipals []string `mapstructure:"additional_principals"` - MaxAge string `mapstructure:"max_age"` - Permissions []string `mapstructure:"permissions"` + SigningKey string `hcl:"signing_key"` + AdditionalPrincipals []string `hcl:"additional_principals"` + MaxAge string `hcl:"max_age"` + Permissions []string `hcl:"permissions"` } // AWS holds Amazon AWS configuration. // AWS can also be configured using SDK methods. type AWS struct { - Region string `mapstructure:"region"` - AccessKey string `mapstructure:"access_key"` - SecretKey string `mapstructure:"secret_key"` + Region string `hcl:"region"` + AccessKey string `hcl:"access_key"` + SecretKey string `hcl:"secret_key"` } // Vault holds Hashicorp Vault configuration. type Vault struct { - Address string `mapstructure:"address"` - Token string `mapstructure:"token"` + Address string `hcl:"address"` + Token string `hcl:"token"` } func verifyConfig(c *Config) error { @@ -186,38 +184,11 @@ func setFromVault(c *Config) error { return errors.Wrap(errs, "errors reading from vault") } -// Unmarshal the config into a *Config -func decode() (*Config, error) { - var errs error - config := &Config{} - configPieces := map[string]interface{}{ - "auth": &config.Auth, - "aws": &config.AWS, - "server": &config.Server, - "ssh": &config.SSH, - "vault": &config.Vault, - } - for key, val := range configPieces { - conf, ok := viper.Get(key).([]map[string]interface{}) - if !ok { - continue - } - if err := mapstructure.WeakDecode(conf[0], val); err != nil { - errs = multierror.Append(errs, err) - } - } - return config, errs -} - // ReadConfig parses a hcl configuration file into a Config struct. -func ReadConfig(r io.Reader) (*Config, error) { - viper.SetConfigType("hcl") - if err := viper.ReadConfig(r); err != nil { - return nil, errors.Wrap(err, "unable to read config") - } - config, err := decode() - if err != nil { - return nil, errors.Wrap(err, "unable to parse config") +func ReadConfig(f string) (*Config, error) { + config := &Config{} + if err := scl.DecodeFile(config, f); err != nil { + return nil, errors.Wrapf(err, "unable to load config from file %s", f) } if err := setFromVault(config); err != nil { return nil, err diff --git a/server/config/config_test.go b/server/config/config_test.go index 399e143..182436a 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -1,10 +1,8 @@ package config import ( - "bytes" "testing" - "github.com/nsheridan/cashier/server/config/testdata" "github.com/stretchr/testify/assert" ) @@ -21,7 +19,6 @@ var ( CSRFSecret: "supersecret", HTTPLogFile: "cashierd.log", Database: Database{"type": "mysql", "username": "user", "password": "passwd", "address": "localhost:3306"}, - Datastore: "mysql:user:passwd:localhost:3306", }, Auth: &Auth{ OauthClientID: "client_id", @@ -50,7 +47,7 @@ var ( ) func TestConfigParser(t *testing.T) { - c, err := ReadConfig(bytes.NewBuffer(testdata.Config)) + c, err := ReadConfig("testdata/test.config") if err != nil { t.Error(err) } @@ -58,8 +55,7 @@ func TestConfigParser(t *testing.T) { } func TestConfigVerify(t *testing.T) { - bad := bytes.NewBuffer([]byte("")) - _, err := ReadConfig(bad) + _, err := ReadConfig("testdata/empty.config") assert.Contains(t, err.Error(), "missing ssh config section", "missing server config section", "missing auth config section") } diff --git a/server/config/testdata/config.go b/server/config/testdata/config.go deleted file mode 100644 index 27cffcc..0000000 --- a/server/config/testdata/config.go +++ /dev/null @@ -1,48 +0,0 @@ -package testdata - -var Config = []byte(` - server { - use_tls = true - tls_key = "server.key" - tls_cert = "server.crt" - address = "127.0.0.1" - port = 443 - user = "nobody" - cookie_secret = "supersecret" - csrf_secret = "supersecret" - http_logfile = "cashierd.log" - datastore = "mysql:user:passwd:localhost:3306" - database { - type = "mysql" - username = "user" - password = "passwd" - address = "localhost:3306" - } - datastore = "mysql:user:passwd:localhost:3306" - } - auth { - provider = "google" - oauth_client_id = "client_id" - oauth_client_secret = "secret" - oauth_callback_url = "https://sshca.example.com/auth/callback" - provider_opts { - domain = "example.com" - } - users_whitelist = ["a_user"] - } - ssh { - signing_key = "signing_key" - additional_principals = ["ec2-user", "ubuntu"] - max_age = "720h" - permissions = ["permit-pty", "permit-X11-forwarding", "permit-port-forwarding", "permit-user-rc"] - } - aws { - region = "us-east-1" - access_key = "abcdef" - secret_key = "omg123" - } - vault { - address = "https://vault:8200" - token = "abc-def-456-789" - } -`) diff --git a/server/config/testdata/empty.config b/server/config/testdata/empty.config new file mode 100644 index 0000000..e69de29 diff --git a/server/config/testdata/test.config b/server/config/testdata/test.config new file mode 100644 index 0000000..96899e7 --- /dev/null +++ b/server/config/testdata/test.config @@ -0,0 +1,42 @@ +server { + use_tls = true + tls_key = "server.key" + tls_cert = "server.crt" + address = "127.0.0.1" + port = 443 + user = "nobody" + cookie_secret = "supersecret" + csrf_secret = "supersecret" + http_logfile = "cashierd.log" + database { + type = "mysql" + username = "user" + password = "passwd" + address = "localhost:3306" + } +} +auth { + provider = "google" + oauth_client_id = "client_id" + oauth_client_secret = "secret" + oauth_callback_url = "https://sshca.example.com/auth/callback" + provider_opts { + domain = "example.com" + } + users_whitelist = ["a_user"] +} +ssh { + signing_key = "signing_key" + additional_principals = ["ec2-user", "ubuntu"] + max_age = "720h" + permissions = ["permit-pty", "permit-X11-forwarding", "permit-port-forwarding", "permit-user-rc"] +} +aws { + region = "us-east-1" + access_key = "abcdef" + secret_key = "omg123" +} +vault { + address = "https://vault:8200" + token = "abc-def-456-789" +} -- cgit v1.2.3