From 84f5ed28d2f1eaeb8488c3c02e199a099311fbab Mon Sep 17 00:00:00 2001 From: Ying Li Date: Tue, 1 Mar 2016 18:17:04 -0500 Subject: [PATCH] Move the configuration parsing for notary-server to its own file Signed-off-by: Ying Li --- cmd/notary-server/config.go | 165 ++++++++++++++++++++++++++++++++++++ cmd/notary-server/main.go | 158 +--------------------------------- 2 files changed, 166 insertions(+), 157 deletions(-) create mode 100644 cmd/notary-server/config.go diff --git a/cmd/notary-server/config.go b/cmd/notary-server/config.go new file mode 100644 index 0000000000..74ffab2e79 --- /dev/null +++ b/cmd/notary-server/config.go @@ -0,0 +1,165 @@ +package main + +import ( + "crypto/tls" + "fmt" + "strconv" + "time" + + "github.com/Sirupsen/logrus" + "github.com/docker/distribution/health" + _ "github.com/docker/distribution/registry/auth/htpasswd" + _ "github.com/docker/distribution/registry/auth/token" + "github.com/docker/go-connections/tlsconfig" + "github.com/docker/notary/server/handlers" + "github.com/docker/notary/server/storage" + "github.com/docker/notary/signer/client" + "github.com/docker/notary/tuf/data" + "github.com/docker/notary/tuf/signed" + "github.com/docker/notary/utils" + _ "github.com/go-sql-driver/mysql" + "github.com/spf13/viper" +) + +// get the address for the HTTP server, and parses the optional TLS +// configuration for the server - if no TLS configuration is specified, +// TLS is not enabled. +func getAddrAndTLSConfig(configuration *viper.Viper) (string, *tls.Config, error) { + httpAddr := configuration.GetString("server.http_addr") + if httpAddr == "" { + return "", nil, fmt.Errorf("http listen address required for server") + } + + tlsConfig, err := utils.ParseServerTLS(configuration, false) + if err != nil { + return "", nil, fmt.Errorf(err.Error()) + } + return httpAddr, tlsConfig, nil +} + +// sets up TLS for the GRPC connection to notary-signer +func grpcTLS(configuration *viper.Viper) (*tls.Config, error) { + rootCA := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_ca_file") + clientCert := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_client_cert") + clientKey := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_client_key") + + if clientCert == "" && clientKey != "" || clientCert != "" && clientKey == "" { + return nil, fmt.Errorf("either pass both client key and cert, or neither") + } + + tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ + CAFile: rootCA, + CertFile: clientCert, + KeyFile: clientKey, + }) + if err != nil { + return nil, fmt.Errorf( + "Unable to configure TLS to the trust service: %s", err.Error()) + } + return tlsConfig, nil +} + +// parses the configuration and returns a backing store for the TUF files +func getStore(configuration *viper.Viper, allowedBackends []string) ( + storage.MetaStore, error) { + + storeConfig, err := utils.ParseStorage(configuration, allowedBackends) + if err != nil { + return nil, err + } + logrus.Infof("Using %s backend", storeConfig.Backend) + + if storeConfig.Backend == utils.MemoryBackend { + return storage.NewMemStorage(), nil + } + + store, err := storage.NewSQLStorage(storeConfig.Backend, storeConfig.Source) + if err != nil { + return nil, fmt.Errorf("Error starting DB driver: %s", err.Error()) + } + health.RegisterPeriodicFunc( + "DB operational", store.CheckHealth, time.Second*60) + return store, nil +} + +type signerFactory func(hostname, port string, tlsConfig *tls.Config) *client.NotarySigner +type healthRegister func(name string, checkFunc func() error, duration time.Duration) + +// parses the configuration and determines which trust service and key algorithm +// to return +func getTrustService(configuration *viper.Viper, sFactory signerFactory, + hRegister healthRegister) (signed.CryptoService, string, error) { + + switch configuration.GetString("trust_service.type") { + case "local": + logrus.Info("Using local signing service, which requires ED25519. " + + "Ignoring all other trust_service parameters, including keyAlgorithm") + return signed.NewEd25519(), data.ED25519Key, nil + case "remote": + default: + return nil, "", fmt.Errorf( + "must specify either a \"local\" or \"remote\" type for trust_service") + } + + keyAlgo := configuration.GetString("trust_service.key_algorithm") + if keyAlgo != data.ED25519Key && keyAlgo != data.ECDSAKey && keyAlgo != data.RSAKey { + return nil, "", fmt.Errorf("invalid key algorithm configured: %s", keyAlgo) + } + + clientTLS, err := grpcTLS(configuration) + if err != nil { + return nil, "", err + } + + logrus.Info("Using remote signing service") + + notarySigner := sFactory( + configuration.GetString("trust_service.hostname"), + configuration.GetString("trust_service.port"), + clientTLS, + ) + + minute := 1 * time.Minute + hRegister( + "Trust operational", + // If the trust service fails, the server is degraded but not + // exactly unheatlthy, so always return healthy and just log an + // error. + func() error { + err := notarySigner.CheckHealth(minute) + if err != nil { + logrus.Error("Trust not fully operational: ", err.Error()) + } + return nil + }, + minute) + return notarySigner, keyAlgo, nil +} + +// Gets the cache configuration for GET-ting metadata. This is the max-age +// (an integer in seconds, just like in the Cache-Control header) for consistent +// (content-addressable) downloads and current (latest version) downloads. +// The max-age must be between 0 and 31536000 (one year in seconds, which is +// the recommended maximum time data is cached), else parsing will return an +// error. A max-age of 0 will disable caching for that type of download +// (consistent or current). +func getCacheConfig(configuration *viper.Viper) (*handlers.CacheControlConfig, error) { + cacheConfig := handlers.NewCacheControlConfig() + for option, setMaxAge := range map[string]func(int){ + "current_metadata": cacheConfig.SetCurrentCacheMaxAge, + "metadata_by_checksum": cacheConfig.SetConsistentCacheMaxAge, + } { + m := configuration.GetString(fmt.Sprintf("caching.max_age.%s", option)) + if m == "" { + continue + } + seconds, err := strconv.Atoi(m) + if err != nil || seconds < 0 || seconds > maxMaxAge { + return nil, fmt.Errorf( + "must specify a cache-control max-age between 0 and %v", maxMaxAge) + } + + setMaxAge(seconds) + } + return cacheConfig, nil +} diff --git a/cmd/notary-server/main.go b/cmd/notary-server/main.go index af75aefd54..2c6aa23112 100644 --- a/cmd/notary-server/main.go +++ b/cmd/notary-server/main.go @@ -1,30 +1,19 @@ package main import ( - "crypto/tls" _ "expvar" "flag" "fmt" "net/http" _ "net/http/pprof" "os" - "strconv" - "time" "github.com/Sirupsen/logrus" "github.com/docker/distribution/health" - _ "github.com/docker/distribution/registry/auth/htpasswd" - _ "github.com/docker/distribution/registry/auth/token" - "github.com/docker/notary/server/storage" "github.com/docker/notary/signer/client" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - _ "github.com/go-sql-driver/mysql" "golang.org/x/net/context" - "github.com/docker/go-connections/tlsconfig" "github.com/docker/notary/server" - "github.com/docker/notary/server/handlers" "github.com/docker/notary/utils" "github.com/docker/notary/version" "github.com/spf13/viper" @@ -37,7 +26,7 @@ const ( // This is the generally recommended maximum age for Cache-Control headers // (one year, in seconds, since one year is forever in terms of internet // content) - maxMaxAge = 31536000 + maxMaxAge = 60 * 60 * 24 * 365 ) var ( @@ -61,151 +50,6 @@ func init() { } } -// get the address for the HTTP server, and parses the optional TLS -// configuration for the server - if no TLS configuration is specified, -// TLS is not enabled. -func getAddrAndTLSConfig(configuration *viper.Viper) (string, *tls.Config, error) { - httpAddr := configuration.GetString("server.http_addr") - if httpAddr == "" { - return "", nil, fmt.Errorf("http listen address required for server") - } - - tlsConfig, err := utils.ParseServerTLS(configuration, false) - if err != nil { - return "", nil, fmt.Errorf(err.Error()) - } - return httpAddr, tlsConfig, nil -} - -// sets up TLS for the GRPC connection to notary-signer -func grpcTLS(configuration *viper.Viper) (*tls.Config, error) { - rootCA := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_ca_file") - clientCert := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_client_cert") - clientKey := utils.GetPathRelativeToConfig(configuration, "trust_service.tls_client_key") - - if clientCert == "" && clientKey != "" || clientCert != "" && clientKey == "" { - return nil, fmt.Errorf("either pass both client key and cert, or neither") - } - - tlsConfig, err := tlsconfig.Client(tlsconfig.Options{ - CAFile: rootCA, - CertFile: clientCert, - KeyFile: clientKey, - }) - if err != nil { - return nil, fmt.Errorf( - "Unable to configure TLS to the trust service: %s", err.Error()) - } - return tlsConfig, nil -} - -// parses the configuration and returns a backing store for the TUF files -func getStore(configuration *viper.Viper, allowedBackends []string) ( - storage.MetaStore, error) { - - storeConfig, err := utils.ParseStorage(configuration, allowedBackends) - if err != nil { - return nil, err - } - logrus.Infof("Using %s backend", storeConfig.Backend) - - if storeConfig.Backend == utils.MemoryBackend { - return storage.NewMemStorage(), nil - } - - store, err := storage.NewSQLStorage(storeConfig.Backend, storeConfig.Source) - if err != nil { - return nil, fmt.Errorf("Error starting DB driver: %s", err.Error()) - } - health.RegisterPeriodicFunc( - "DB operational", store.CheckHealth, time.Second*60) - return store, nil -} - -type signerFactory func(hostname, port string, tlsConfig *tls.Config) *client.NotarySigner -type healthRegister func(name string, checkFunc func() error, duration time.Duration) - -// parses the configuration and determines which trust service and key algorithm -// to return -func getTrustService(configuration *viper.Viper, sFactory signerFactory, - hRegister healthRegister) (signed.CryptoService, string, error) { - - switch configuration.GetString("trust_service.type") { - case "local": - logrus.Info("Using local signing service, which requires ED25519. " + - "Ignoring all other trust_service parameters, including keyAlgorithm") - return signed.NewEd25519(), data.ED25519Key, nil - case "remote": - default: - return nil, "", fmt.Errorf( - "must specify either a \"local\" or \"remote\" type for trust_service") - } - - keyAlgo := configuration.GetString("trust_service.key_algorithm") - if keyAlgo != data.ED25519Key && keyAlgo != data.ECDSAKey && keyAlgo != data.RSAKey { - return nil, "", fmt.Errorf("invalid key algorithm configured: %s", keyAlgo) - } - - clientTLS, err := grpcTLS(configuration) - if err != nil { - return nil, "", err - } - - logrus.Info("Using remote signing service") - - notarySigner := sFactory( - configuration.GetString("trust_service.hostname"), - configuration.GetString("trust_service.port"), - clientTLS, - ) - - minute := 1 * time.Minute - hRegister( - "Trust operational", - // If the trust service fails, the server is degraded but not - // exactly unheatlthy, so always return healthy and just log an - // error. - func() error { - err := notarySigner.CheckHealth(minute) - if err != nil { - logrus.Error("Trust not fully operational: ", err.Error()) - } - return nil - }, - minute) - return notarySigner, keyAlgo, nil -} - -// Gets the cache configuration for GET-ting metadata. This is the max-age -// (an integer in seconds, just like in the Cache-Control header) for consistent -// (content-addressable) downloads and current (latest version) downloads. -// The max-age must be between 0 and 31536000 (one year in seconds, which is -// the recommended maximum time data is cached), else parsing will return an -// error. A max-age of 0 will disable caching for that type of download -// (consistent or current). -func getCacheConfig(configuration *viper.Viper) (*handlers.CacheControlConfig, error) { - cacheConfig := handlers.NewCacheControlConfig() - for _, option := range []string{"current_metadata", "metadata_by_checksum"} { - m := configuration.GetString(fmt.Sprintf("caching.max_age.%s", option)) - if m == "" { - continue - } - seconds, err := strconv.Atoi(m) - if err != nil || seconds < 0 || seconds > maxMaxAge { - return nil, fmt.Errorf( - "must specify a cache-control max-age between 0 and %v", maxMaxAge) - } - - switch option { - case "current_metadata": - cacheConfig.SetCurrentCacheMaxAge(seconds) - default: - cacheConfig.SetConsistentCacheMaxAge(seconds) - } - } - return cacheConfig, nil -} - func main() { flag.Usage = usage flag.Parse()