func main() { flag.Parse() hkjnweb.Register(os.Getenv("PROD") != "") registerStatic(os.Getenv("STATIC_DIR")) addr := os.Getenv("BIND_ADDR") if addr == "" { addr = ":12345" } if os.Getenv("SERVE_HTTP") != "" { log.Printf("webserver serving HTTP on %s..\n", addr) err := http.ListenAndServe(addr, nil) if err != nil { log.Fatalf("FATAL: http server exited: %v\n", err) } } else { log.Println("Since SERVE_HTTP isn't set, we should serve https") m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(hosts...), } s := &http.Server{ Addr: addr, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } log.Printf("webserver serving HTTPS on %s..\n", addr) err := s.ListenAndServeTLS("", "") if err != nil { log.Fatalf("FATAL: https server exited: %v\n", err) } } }
// Run the application, start http and scp server. func Run(appConfig Config) { config = appConfig // Connect to DB db, err := lib.Connect() if err != nil { fmt.Printf("Failed to connect to db") return } // Logging log := logrus.New() log.Level = logrus.DebugLevel log.Out = os.Stdout log.Formatter = &logrus.TextFormatter{} // Websockets ws := ws.NewServer() // Shared dependencies between all controller deps := dependencies.Dependencies{ Fs: afero.NewOsFs(), Logger: log, DB: db, WS: ws, } ws.Dependencies = &deps go ws.Start() // // Start SCP // scp := scp.Server{} // scp.DB = deps.DB // scp.Logger = deps.Logger // scp.CertPath = "certs/scp.rsa" // scp.BindAddr = config.SCPBindAddr // go scp.ListenAndServe() if config.Secure { c := autocert.DirCache("certs") m := autocert.Manager{ Cache: c, Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("x.zqz.ca"), } s := &http.Server{ Addr: config.HTTPBindAddr, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } deps.Info("Listening for HTTP1.1 Connections", "addr", ":3001") deps.Info("Listening for HTTP2 Connections", "addr", config.HTTPBindAddr) go http.ListenAndServe(":3001", secureRedirect()) s.ListenAndServeTLS("", "") } else { deps.Info("Listening for HTTP1.1 Connections", "addr", config.HTTPBindAddr) http.ListenAndServe(config.HTTPBindAddr, Routes(deps)) } }
func setupTLS(ws *webserver.Server, conf *config) error { if conf.HTTPSCert != "" && conf.HTTPSKey != "" { ws.SetTLS(webserver.TLSSetup{ CertFile: conf.HTTPSCert, KeyFile: conf.HTTPSKey, }) return nil } if !conf.CertManager { return nil } // As all requests to the publisher are proxied through Camlistore's app // handler, it makes sense to assume that both Camlistore and the publisher // are behind the same domain name. Therefore, it follows that // camlistored's autocert is the one actually getting a cert (and answering // the challenge) for the both of them. Plus, if they run on the same host // (default setup), they can't both listen on 443 to answer the TLS-SNI // challenge. // TODO(mpl): however, camlistored and publisher could be running on // different hosts, in which case we need to find a way for camlistored to // share its autocert cache with publisher. But I think that can wait a // later CL. hostname := os.Getenv("CAMLI_API_HOST") hostname = strings.TrimPrefix(hostname, "https://") hostname = strings.SplitN(hostname, "/", 2)[0] hostname = strings.SplitN(hostname, ":", 2)[0] if !netutil.IsFQDN(hostname) { return fmt.Errorf("cannot ask Let's Encrypt for a cert because %v is not a fully qualified domain name", hostname) } logger.Print("TLS enabled, with Let's Encrypt") // TODO(mpl): we only want publisher to use the same cache as // camlistored, and we don't actually need an autocert.Manager. // So we could just instantiate an autocert.DirCache, and generate // from there a *tls.Certificate, but it looks like it would mean // extracting quite a bit of code from the autocert pkg to do it properly. // Instead, I've opted for using an autocert.Manager (even though it's // never going to reply to any challenge), but with NOOP for Put and // Delete, just to be on the safe side. It's simple enough, but there's // still a catch: there's no ServerName in the clientHello we get, so we // reinject one so we can simply use the autocert.Manager.GetCertificate // method as the way to get the certificate from the cache. Is that OK? m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(hostname), Cache: roCertCacheDir(osutil.DefaultLetsEncryptCache()), } ws.SetTLS(webserver.TLSSetup{ CertManager: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { if clientHello.ServerName == "" { clientHello.ServerName = hostname } return m.GetCertificate(clientHello) }, }) return nil }
func main() { flag.Parse() log.Println("Starting") // http.ListenAndServe(":443", nil) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("www.homedroids.io"), } s := &http.Server{ Addr: *httpsAddr, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } log.Fatal(s.ListenAndServeTLS("", "")) }
func serveHTTPS(httpServer *http.Server) error { log.Printf("Starting TLS server on %s", *httpsAddr) httpsServer := new(http.Server) *httpsServer = *httpServer httpsServer.Addr = *httpsAddr cacheDir := autocert.DirCache("letsencrypt.cache") var domain string if !inProd { if *tlsCertFile != "" && *tlsKeyFile != "" { return httpsServer.ListenAndServeTLS(*tlsCertFile, *tlsKeyFile) } // Otherwise use Let's Encrypt, i.e. same use case as in prod if strings.HasPrefix(*httpsAddr, ":") { return errors.New("for Let's Encrypt, -https needs to start with a host name") } host, _, err := net.SplitHostPort(*httpsAddr) if err != nil { return err } domain = host } else { domain = "camlistore.org" cacheDir = autocert.DirCache(prodLECacheDir) } m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(domain), Cache: cacheDir, } if *adminEmail != "" { m.Email = *adminEmail } httpsServer.TLSConfig = &tls.Config{ GetCertificate: m.GetCertificate, } log.Printf("Listening for HTTPS on %v", *httpsAddr) ln, err := net.Listen("tcp", *httpsAddr) if err != nil { return err } return httpsServer.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, httpsServer.TLSConfig)) }
func main() { flag.Parse() log.Printf("Starting (prod=%t)", *prod) client := &acme.Client{} if !*prod { client = &acme.Client{ DirectoryURL: "https://acme-staging.api.letsencrypt.org/directory", } } m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("www.homedroids.io"), Client: client, } s := &http.Server{ Addr: *httpsAddr, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } log.Fatal(s.ListenAndServeTLS("", "")) }
func serveProdTLS() error { const cacheDir = "/var/cache/autocert" if err := os.MkdirAll(cacheDir, 0700); err != nil { return err } m := autocert.Manager{ Cache: autocert.DirCache(cacheDir), Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("http2.golang.org"), } srv := &http.Server{ TLSConfig: &tls.Config{ GetCertificate: m.GetCertificate, }, } http2.ConfigureServer(srv, &http2.Server{}) ln, err := net.Listen("tcp", ":443") if err != nil { return err } return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig)) }
func (srv *Server) newTLSConfig(cfg ServerConfig) *tls.Config { tlsConfig := utils.SecureTLSConfig() if cfg.AutocertDNSName == "" { // No official DNS name, no certificate. tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { cert, _ := srv.localCertificate(clientHello.ServerName) return cert, nil } return tlsConfig } m := autocert.Manager{ Prompt: autocert.AcceptTOS, Cache: srv.state.AutocertCache(), HostPolicy: autocert.HostWhitelist(cfg.AutocertDNSName), } if cfg.AutocertURL != "" { m.Client = &acme.Client{ DirectoryURL: cfg.AutocertURL, } } tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { logger.Infof("getting certificate for server name %q", clientHello.ServerName) // Get the locally created certificate and whether it's appropriate // for the SNI name. If not, we'll try to get an acme cert and // fall back to the local certificate if that fails. cert, shouldUse := srv.localCertificate(clientHello.ServerName) if shouldUse { return cert, nil } acmeCert, err := m.GetCertificate(clientHello) if err == nil { return acmeCert, nil } logger.Errorf("cannot get autocert certificate for %q: %v", clientHello.ServerName, err) return cert, nil } return tlsConfig }
func main() { flag.Parse() log.Printf("Starting (prod=%t)", *prod) client := &acme.Client{} if !*prod { client = &acme.Client{ DirectoryURL: "https://acme-staging.api.letsencrypt.org/directory", } } m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(reg.Hosts()...), Cache: autocert.DirCache("certs"), Client: client, } hs := newHostSwitch(reg) s := &http.Server{ Addr: *httpsAddr, Handler: hs, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } log.Fatal(s.ListenAndServeTLS("", "")) }
func main() { log.SetLevel(log.DebugLevel) log.SetFlags(0) // выводим информацию о версии сборки log.WithFields(log.Fields{ "version": version, "date": date, "build": build, "name": appName, }).Info("starting service") // разбираем параметры запуска приложения config := flag.String("config", appName+".json", "configuration `filename`") address := flag.String("address", host, "server address and `port`") flag.Parse() // загружаем конфигурацию сервиса log.WithField("file", *config).Info("loading service config") service, err := LoadConfig(*config) if err != nil { log.WithError(err).Error("loading config error") os.Exit(1) } // выводим список поддерживаемых MX-серверов mxnames := service.Auth.Names() if len(mxnames) == 0 { log.Error("no MX servers configured") os.Exit(1) } log.WithField("names", strings.Join(mxnames, ", ")). Info("supported MX servers") // выводим информацию о кеше авторизации log.WithField("lifeTime", mxlogin.CacheLifetime). Info("authorization cache") // удаляем устаревшие файлы раз в сутки cleanInterval := time.Hour * 24 // выводим информацию о хранилище файлов log.WithFields(log.Fields{ "path": service.FileStore.Store.Path(), "lifeTime": service.FileStore.Lifetime, "cleanInterval": cleanInterval, }).Info("file store") // запускаем процесс автоматического удаления старых файлов go func() { for { time.Sleep(cleanInterval) err = service.FileStore.Clean() if err != nil { log.WithField("service", "filestore"). WithError(err).Debug("file store clean error") } } }() // инициализируем мультиплексор HTTP-запросов mux := &rest.ServeMux{ Headers: map[string]string{ "Server": "MXStore/2.0", "X-API-Version": "1.1", "X-Service-Version": version, }, Logger: log.WithField("service", "http"), Encoder: Encoder, } // обработчики файлов хранилища и аватарок mux.Handles(rest.Paths{ "/mx/:mx-name/store": { // переходим на основное имя MX сервера, если используется синоним // возвращает пустой ответ, если имя сервера и так основное "GET": nil, // сохраняем в хранилище новый файл "POST": service.FileStore.Save, }, // отдаем файл по запросу "/mx/:mx-name/store/*filename": { "GET": service.FileStore.Get, }, "/mx/:mx-name/avatar": { // переходим на основное имя MX сервера, если используется синоним // возвращаем список идентификаторов пользователей и аватарок "GET": service.Avatars.List, // сохраняем в хранилище новый файл "POST": service.Avatars.Save, }, // отдаем файл с аватаркой по запросу "/mx/:mx-name/avatar/*filename": { "GET": service.Avatars.Get, }, }, // для всех запросов требуется авторизация service.Auth.Authorize, ) // добавляем обработчик отдачи документации mux.Handle("GET", "/", rest.Redirect("https://www.connector73.com/en#softphone")) // запускаем сервис с ответом об информации о ссылке mux.Handle("GET", "/urlinfo/*url", URLInfo) // генератор аватарок mux.Handle("GET", "/avatar/:id", AvatarGenerator) // инициализируем HTTP-сервер server := &http.Server{ Addr: *address, Handler: mux, ReadTimeout: time.Second * 60, WriteTimeout: time.Second * 120, } // для защищенного соединения проделываем дополнительные настройки host, port, err := net.SplitHostPort(*address) if err != nil { log.WithError(err).Error("bad server address") os.Exit(2) } if port == "https" || port == "443" { if host != "localhost" && host != "127.0.0.1" { manager := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(host), Email: "*****@*****.**", Cache: autocert.DirCache("letsEncript.cache"), } server.TLSConfig = &tls.Config{ GetCertificate: manager.GetCertificate, } } else { // исключительно для отладки cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey) if err != nil { panic(fmt.Sprintf("local certificates error: %v", err)) } server.TLSConfig = &tls.Config{ Certificates: []tls.Certificate{cert}, } } // запускаем автоматический переход для HTTP на HTTPS go func() { log.Info("starting http to https redirect server") err := http.ListenAndServe(":http", http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently) })) if err != nil { log.WithError(err).Warning("http redirect server error") } }() // запускаем основной сервер go func() { log.WithFields(log.Fields{ "address": server.Addr, "host": host, }).Info("starting https server") err = server.ListenAndServeTLS("", "") // // корректно закрываем сервисы по окончании работы // service.Close() log.WithError(err).Warning("https server stoped") os.Exit(3) }() } else { // не защищенный HTTP сервер go func() { log.WithField("address", *address).Info("starting service") err = server.ListenAndServe() // service.Close() log.WithError(err).Warning("http server stoped") os.Exit(3) }() } // инициализируем поддержку системных сигналов и ждем, когда он случится monitorSignals(os.Interrupt, os.Kill) // service.Close() log.Info("service stoped") }
// If cert/key files are specified, and found, use them. // If cert/key files are specified, not found, and the default values, generate // them (self-signed CA used as a cert), and use them. // If cert/key files are not specified, use Let's Encrypt. func setupTLS(ws *webserver.Server, config *serverinit.Config, hostname string) { cert, key := config.OptionalString("httpsCert", ""), config.OptionalString("httpsKey", "") if !config.OptionalBool("https", true) { return } if (cert != "") != (key != "") { exitf("httpsCert and httpsKey must both be either present or absent") } defCert := osutil.DefaultTLSCert() defKey := osutil.DefaultTLSKey() const hint = "You must add this certificate's fingerprint to your client's trusted certs list to use it. Like so:\n\"trustedCerts\": [\"%s\"]," if cert == defCert && key == defKey { _, err1 := wkfs.Stat(cert) _, err2 := wkfs.Stat(key) if err1 != nil || err2 != nil { if os.IsNotExist(err1) || os.IsNotExist(err2) { sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey) if err != nil { exitf("Could not generate self-signed TLS cert: %q", err) } log.Printf(hint, sig) } else { exitf("Could not stat cert or key: %q, %q", err1, err2) } } } if cert == "" && key == "" { // Use Let's Encrypt if no files are specified, and we have a usable hostname. if netutil.IsFQDN(hostname) { m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(hostname), Cache: autocert.DirCache(osutil.DefaultLetsEncryptCache()), } log.Print("TLS enabled, with Let's Encrypt") ws.SetTLS(webserver.TLSSetup{ CertManager: m.GetCertificate, }) return } // Otherwise generate new certificates sig, err := httputil.GenSelfTLSFiles(hostname, defCert, defKey) if err != nil { exitf("Could not generate self signed creds: %q", err) } log.Printf(hint, sig) cert = defCert key = defKey } data, err := wkfs.ReadFile(cert) if err != nil { exitf("Failed to read pem certificate: %s", err) } sig, err := httputil.CertFingerprint(data) if err != nil { exitf("certificate error: %v", err) } log.Printf("TLS enabled, with SHA-256 certificate fingerprint: %v", sig) ws.SetTLS(webserver.TLSSetup{ CertFile: cert, KeyFile: key, }) }
func (r *Runner) start() error { r.authKey = os.Getenv("AUTH_KEY") if r.authKey == "" { return errors.New("AUTH_KEY not set") } r.runEnv["TEST_RUNNER_AUTH_KEY"] = r.authKey for _, s := range []string{"S3", "GCS", "AZURE"} { name := fmt.Sprintf("BLOBSTORE_%s_CONFIG", s) if c := os.Getenv(name); c != "" { r.runEnv[name] = c } else { return fmt.Errorf("%s not set", name) } } r.githubToken = os.Getenv("GITHUB_TOKEN") if r.githubToken == "" { return errors.New("GITHUB_TOKEN not set") } am := autocert.Manager{ Prompt: autocert.AcceptTOS, Cache: autocert.DirCache(args.TLSDir), HostPolicy: autocert.HostWhitelist(args.Domain), } awsAuth, err := aws.EnvCreds() if err != nil { return err } r.s3 = s3.New(awsAuth, "us-east-1", nil) _, listenPort, err = net.SplitHostPort(args.ListenAddr) if err != nil { return err } bc := r.bc bc.Network = r.allocateNet() if r.rootFS, err = cluster.BuildFlynn(bc, args.RootFS, "origin/master", false, os.Stdout); err != nil { return fmt.Errorf("could not build flynn: %s", err) } r.releaseNet(bc.Network) shutdown.BeforeExit(func() { removeRootFS(r.rootFS) }) db, err := bolt.Open(args.DBPath, 0600, &bolt.Options{Timeout: 5 * time.Second}) if err != nil { return fmt.Errorf("could not open db: %s", err) } r.db = db shutdown.BeforeExit(func() { r.db.Close() }) if err := r.db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucketIfNotExists(dbBucket) return err }); err != nil { return fmt.Errorf("could not create builds bucket: %s", err) } for i := 0; i < args.ConcurrentBuilds; i++ { r.buildCh <- struct{}{} } if err := r.buildPending(); err != nil { log.Printf("could not build pending builds: %s", err) } go r.connectIRC() go r.watchEvents() router := httprouter.New() router.RedirectTrailingSlash = true router.Handler("GET", "/", http.RedirectHandler("/builds", 302)) router.POST("/", r.handleEvent) router.GET("/builds/:build", r.getBuildLog) router.GET("/builds/:build/download", r.downloadBuildLog) router.POST("/builds/:build/restart", r.restartBuild) router.POST("/builds/:build/explain", r.explainBuild) router.GET("/builds", r.getBuilds) router.ServeFiles("/assets/*filepath", http.Dir(args.AssetsDir)) router.GET("/cluster/:cluster", r.clusterAPI(r.getCluster)) router.POST("/cluster/:cluster", r.clusterAPI(r.addHost)) router.POST("/cluster/:cluster/release", r.clusterAPI(r.addReleaseHosts)) router.DELETE("/cluster/:cluster/:host", r.clusterAPI(r.removeHost)) srv := &http.Server{ Addr: args.ListenAddr, Handler: router, TLSConfig: tlsconfig.SecureCiphers(&tls.Config{ GetCertificate: am.GetCertificate, }), } log.Println("Listening on", args.ListenAddr, "...") if err := srv.ListenAndServeTLS("", ""); err != nil { return fmt.Errorf("ListenAndServeTLS: %s", err) } return nil }
func main() { launchConfig.MaybeDeploy() flag.Parse() var kv keyValue var httpsListenAddr string if metadata.OnGCE() { httpsListenAddr = ":443" dsClient, err := datastore.NewClient(context.Background(), GCEProjectID) if err != nil { log.Fatalf("Error creating datastore client for records: %v", err) } kv = cachedStore{ dsClient: dsClient, cache: lru.New(cacheSize), } } else { httpsListenAddr = ":4430" kv = memkv{skv: sorted.NewMemoryKeyValue()} } if err := kv.Set("6401800c.camlistore.net.", "159.203.246.79"); err != nil { log.Fatalf("Error adding %v:%v record: %v", "6401800c.camlistore.net.", "159.203.246.79", err) } if err := kv.Set(domain, *flagServerIP); err != nil { log.Fatalf("Error adding %v:%v record: %v", domain, *flagServerIP, err) } if err := kv.Set("www.camlistore.net.", *flagServerIP); err != nil { log.Fatalf("Error adding %v:%v record: %v", "www.camlistore.net.", *flagServerIP, err) } ds := newDNSServer(kv) cs := &gpgchallenge.Server{ OnSuccess: func(identity string, address string) error { log.Printf("Adding %v.camlistore.net. as %v", identity, address) return ds.dataSource.Set(strings.ToLower(identity+".camlistore.net."), address) }, } tcperr := make(chan error, 1) udperr := make(chan error, 1) httperr := make(chan error, 1) log.Printf("serving DNS on %s\n", *addr) go func() { tcperr <- dns.ListenAndServe(*addr, "tcp", ds) }() go func() { udperr <- dns.ListenAndServe(*addr, "udp", ds) }() if metadata.OnGCE() { // TODO(mpl): if we want to get a cert for anything // *.camlistore.net, it's a bit of a chicken and egg problem, since // we need camnetdns itself to be already running and answering DNS // queries. It's probably doable, but easier for now to just ask // one for camnetdns.camlistore.org, since that name is not // resolved by camnetdns. hostname := strings.TrimSuffix(authorityNS, ".") m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(hostname), Cache: autocert.DirCache(osutil.DefaultLetsEncryptCache()), } ln, err := tls.Listen("tcp", httpsListenAddr, &tls.Config{ Rand: rand.Reader, Time: time.Now, NextProtos: []string{http2.NextProtoTLS, "http/1.1"}, MinVersion: tls.VersionTLS12, GetCertificate: m.GetCertificate, }) if err != nil { log.Fatalf("Error listening on %v: %v", httpsListenAddr, err) } go func() { httperr <- http.Serve(ln, cs) }() } select { case err := <-tcperr: log.Fatalf("DNS over TCP error: %v", err) case err := <-udperr: log.Fatalf("DNS error: %v", err) case err := <-httperr: log.Fatalf("HTTP server error: %v", err) } }