mirror of https://github.com/docker/docs.git
Move the configuration parsing for notary-server to its own file
Signed-off-by: Ying Li <ying.li@docker.com>
This commit is contained in:
parent
e1397f4b03
commit
84f5ed28d2
|
@ -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
|
||||||
|
}
|
|
@ -1,30 +1,19 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
_ "expvar"
|
_ "expvar"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/distribution/health"
|
"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/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"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
|
||||||
"github.com/docker/notary/server"
|
"github.com/docker/notary/server"
|
||||||
"github.com/docker/notary/server/handlers"
|
|
||||||
"github.com/docker/notary/utils"
|
"github.com/docker/notary/utils"
|
||||||
"github.com/docker/notary/version"
|
"github.com/docker/notary/version"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -37,7 +26,7 @@ const (
|
||||||
// This is the generally recommended maximum age for Cache-Control headers
|
// This is the generally recommended maximum age for Cache-Control headers
|
||||||
// (one year, in seconds, since one year is forever in terms of internet
|
// (one year, in seconds, since one year is forever in terms of internet
|
||||||
// content)
|
// content)
|
||||||
maxMaxAge = 31536000
|
maxMaxAge = 60 * 60 * 24 * 365
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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() {
|
func main() {
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
Loading…
Reference in New Issue