// NewRegistry creates a new registry from a context and configuration struct. func NewRegistry(ctx context.Context, config *configuration.Configuration) (*Registry, error) { var err error ctx, err = configureLogging(ctx, config) if err != nil { return nil, fmt.Errorf("error configuring logger: %v", err) } // inject a logger into the uuid library. warns us if there is a problem // with uuid generation under low entropy. uuid.Loggerf = context.GetLogger(ctx).Warnf app := handlers.NewApp(ctx, config) // TODO(aaronl): The global scope of the health checks means NewRegistry // can only be called once per process. app.RegisterHealthChecks() handler := configureReporting(app) handler = alive("/", handler) handler = health.Handler(handler) handler = panicHandler(handler) handler = gorhandlers.CombinedLoggingHandler(os.Stdout, handler) server := &http.Server{ Handler: handler, } return &Registry{ app: app, config: config, server: server, }, nil }
// Execute runs the Docker registry. func Execute(configFile io.Reader) { config, err := configuration.Parse(configFile) if err != nil { log.Fatalf("Error parsing configuration file: %s", err) } tokenPath := "/openshift/token" // If needed, generate and populate the token realm URL in the config. // Must be done prior to instantiating the app, so our auth provider has the config available. _, usingOpenShiftAuth := config.Auth[server.OpenShiftAuth] _, hasTokenRealm := config.Auth[server.OpenShiftAuth][server.TokenRealmKey].(string) if usingOpenShiftAuth && !hasTokenRealm { registryHost := os.Getenv(server.DockerRegistryURLEnvVar) if len(registryHost) == 0 { log.Fatalf("%s is required", server.DockerRegistryURLEnvVar) } tokenURL := &url.URL{Scheme: "https", Host: registryHost, Path: tokenPath} if len(config.HTTP.TLS.Certificate) == 0 { tokenURL.Scheme = "http" } if config.Auth[server.OpenShiftAuth] == nil { config.Auth[server.OpenShiftAuth] = configuration.Parameters{} } config.Auth[server.OpenShiftAuth][server.TokenRealmKey] = tokenURL.String() } ctx := context.Background() ctx, err = configureLogging(ctx, config) if err != nil { log.Fatalf("error configuring logger: %v", err) } log.Infof("version=%s", version.Version) // inject a logger into the uuid library. warns us if there is a problem // with uuid generation under low entropy. uuid.Loggerf = context.GetLogger(ctx).Warnf app := handlers.NewApp(ctx, config) // Add a token handling endpoint if usingOpenShiftAuth { app.NewRoute().Methods("GET").PathPrefix(tokenPath).Handler(server.NewTokenHandler(ctx, server.DefaultRegistryClient)) } // TODO add https scheme adminRouter := app.NewRoute().PathPrefix("/admin/").Subrouter() pruneAccessRecords := func(*http.Request) []auth.Access { return []auth.Access{ { Resource: auth.Resource{ Type: "admin", }, Action: "prune", }, } } app.RegisterRoute( // DELETE /admin/blobs/<digest> adminRouter.Path("/blobs/{digest:"+reference.DigestRegexp.String()+"}").Methods("DELETE"), // handler server.BlobDispatcher, // repo name not required in url handlers.NameNotRequired, // custom access records pruneAccessRecords, ) app.RegisterHealthChecks() handler := alive("/", app) // TODO: temporarily keep for backwards compatibility; remove in the future handler = alive("/healthz", handler) handler = health.Handler(handler) handler = panicHandler(handler) handler = gorillahandlers.CombinedLoggingHandler(os.Stdout, handler) if config.HTTP.TLS.Certificate == "" { context.GetLogger(app).Infof("listening on %v", config.HTTP.Addr) if err := http.ListenAndServe(config.HTTP.Addr, handler); err != nil { context.GetLogger(app).Fatalln(err) } } else { tlsConf := crypto.SecureTLSConfig(&tls.Config{ClientAuth: tls.NoClientCert}) if len(config.HTTP.TLS.ClientCAs) != 0 { pool := x509.NewCertPool() for _, ca := range config.HTTP.TLS.ClientCAs { caPem, err := ioutil.ReadFile(ca) if err != nil { context.GetLogger(app).Fatalln(err) } if ok := pool.AppendCertsFromPEM(caPem); !ok { context.GetLogger(app).Fatalln(fmt.Errorf("Could not add CA to pool")) } } for _, subj := range pool.Subjects() { context.GetLogger(app).Debugf("CA Subject: %s", string(subj)) } tlsConf.ClientAuth = tls.RequireAndVerifyClientCert tlsConf.ClientCAs = pool } context.GetLogger(app).Infof("listening on %v, tls", config.HTTP.Addr) server := &http.Server{ Addr: config.HTTP.Addr, Handler: handler, TLSConfig: tlsConf, } if err := server.ListenAndServeTLS(config.HTTP.TLS.Certificate, config.HTTP.TLS.Key); err != nil { context.GetLogger(app).Fatalln(err) } } }
func main() { flag.Usage = usage flag.Parse() if showVersion { version.PrintVersion() return } ctx := context.Background() ctx = context.WithValue(ctx, "version", version.Version) config, err := resolveConfiguration() if err != nil { fatalf("configuration error: %v", err) } ctx, err = configureLogging(ctx, config) if err != nil { fatalf("error configuring logger: %v", err) } // inject a logger into the uuid library. warns us if there is a problem // with uuid generation under low entropy. uuid.Loggerf = context.GetLogger(ctx).Warnf app := handlers.NewApp(ctx, *config) app.RegisterHealthChecks() handler := configureReporting(app) handler = panicHandler(handler) handler = health.Handler(handler) handler = gorhandlers.CombinedLoggingHandler(os.Stdout, handler) if config.HTTP.Debug.Addr != "" { go debugServer(config.HTTP.Debug.Addr) } server := &http.Server{ Handler: handler, } ln, err := listener.NewListener(config.HTTP.Net, config.HTTP.Addr) if err != nil { context.GetLogger(app).Fatalln(err) } defer ln.Close() if config.HTTP.TLS.Certificate != "" { tlsConf := &tls.Config{ ClientAuth: tls.NoClientCert, NextProtos: []string{"http/1.1"}, Certificates: make([]tls.Certificate, 1), MinVersion: tls.VersionTLS10, PreferServerCipherSuites: true, CipherSuites: []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_256_CBC_SHA, }, } tlsConf.Certificates[0], err = tls.LoadX509KeyPair(config.HTTP.TLS.Certificate, config.HTTP.TLS.Key) if err != nil { context.GetLogger(app).Fatalln(err) } if len(config.HTTP.TLS.ClientCAs) != 0 { pool := x509.NewCertPool() for _, ca := range config.HTTP.TLS.ClientCAs { caPem, err := ioutil.ReadFile(ca) if err != nil { context.GetLogger(app).Fatalln(err) } if ok := pool.AppendCertsFromPEM(caPem); !ok { context.GetLogger(app).Fatalln(fmt.Errorf("Could not add CA to pool")) } } for _, subj := range pool.Subjects() { context.GetLogger(app).Debugf("CA Subject: %s", string(subj)) } tlsConf.ClientAuth = tls.RequireAndVerifyClientCert tlsConf.ClientCAs = pool } ln = tls.NewListener(ln, tlsConf) context.GetLogger(app).Infof("listening on %v, tls", ln.Addr()) } else { context.GetLogger(app).Infof("listening on %v", ln.Addr()) } if err := server.Serve(ln); err != nil { context.GetLogger(app).Fatalln(err) } }
// Execute runs the Docker registry. func Execute(configFile io.Reader) { config, err := configuration.Parse(configFile) if err != nil { log.Fatalf("Error parsing configuration file: %s", err) } ctx := context.Background() ctx, err = configureLogging(ctx, config) if err != nil { log.Fatalf("error configuring logger: %v", err) } log.Infof("version=%s", version.Version) // inject a logger into the uuid library. warns us if there is a problem // with uuid generation under low entropy. uuid.Loggerf = context.GetLogger(ctx).Warnf app := handlers.NewApp(ctx, config) // TODO add https scheme adminRouter := app.NewRoute().PathPrefix("/admin/").Subrouter() pruneAccessRecords := func(*http.Request) []auth.Access { return []auth.Access{ { Resource: auth.Resource{ Type: "admin", }, Action: "prune", }, } } app.RegisterRoute( // DELETE /admin/blobs/<digest> adminRouter.Path("/blobs/{digest:"+reference.DigestRegexp.String()+"}").Methods("DELETE"), // handler server.BlobDispatcher, // repo name not required in url handlers.NameNotRequired, // custom access records pruneAccessRecords, ) app.RegisterHealthChecks() handler := alive("/", app) // TODO: temporarily keep for backwards compatibility; remove in the future handler = alive("/healthz", handler) handler = health.Handler(handler) handler = panicHandler(handler) handler = gorillahandlers.CombinedLoggingHandler(os.Stdout, handler) if config.HTTP.TLS.Certificate == "" { context.GetLogger(app).Infof("listening on %v", config.HTTP.Addr) if err := http.ListenAndServe(config.HTTP.Addr, handler); err != nil { context.GetLogger(app).Fatalln(err) } } else { tlsConf := crypto.SecureTLSConfig(&tls.Config{ClientAuth: tls.NoClientCert}) if len(config.HTTP.TLS.ClientCAs) != 0 { pool := x509.NewCertPool() for _, ca := range config.HTTP.TLS.ClientCAs { caPem, err := ioutil.ReadFile(ca) if err != nil { context.GetLogger(app).Fatalln(err) } if ok := pool.AppendCertsFromPEM(caPem); !ok { context.GetLogger(app).Fatalln(fmt.Errorf("Could not add CA to pool")) } } for _, subj := range pool.Subjects() { context.GetLogger(app).Debugf("CA Subject: %s", string(subj)) } tlsConf.ClientAuth = tls.RequireAndVerifyClientCert tlsConf.ClientCAs = pool } context.GetLogger(app).Infof("listening on %v, tls", config.HTTP.Addr) server := &http.Server{ Addr: config.HTTP.Addr, Handler: handler, TLSConfig: tlsConf, } if err := server.ListenAndServeTLS(config.HTTP.TLS.Certificate, config.HTTP.TLS.Key); err != nil { context.GetLogger(app).Fatalln(err) } } }