// TODO: Build a fake CA and make sure it loads up func TestNewTLSConfig(t *testing.T) { fakeCA := writeFakeFile(pemCertificate) defer syscall.Unlink(fakeCA) conf, err := ssl.NewTLSConfig(fakeCA, true) if err != nil { t.Errorf("Could not create new TLS config: %s", err) } if conf.ClientAuth != tls.VerifyClientCertIfGiven { t.Errorf("Client certificate verification was not enabled") } if conf.ClientCAs == nil { t.Errorf("ClientCA empty even though cert provided") } conf, err = ssl.NewTLSConfig("", false) if err != nil { t.Errorf("Could not create new TLS config: %s", err) } if conf.ClientAuth == tls.VerifyClientCertIfGiven { t.Errorf("Client certificate verification was enabled unexpectedly") } if conf.ClientCAs != nil { t.Errorf("Filling in ClientCA somehow without a cert") } }
// Http starts serving HTTP (api/web) requests func Http() { martini.Env = martini.Prod m := martini.Classic() if config.Config.HTTPAuthUser != "" { m.Use(auth.Basic(config.Config.HTTPAuthUser, config.Config.HTTPAuthPassword)) } m.Use(gzip.All()) // Render html templates from templates directory m.Use(render.Renderer(render.Options{ Directory: "resources", Layout: "templates/layout", HTMLContentType: "text/html", })) m.Use(martini.Static("resources/public")) if config.Config.UseMutualTLS { m.Use(ssl.VerifyOUs(config.Config.SSLValidOUs)) } go agent.ContinuousOperation() log.Infof("Starting HTTP on port %d", config.Config.HTTPPort) http.API.RegisterRequests(m) listenAddress := fmt.Sprintf(":%d", config.Config.HTTPPort) // Serve if config.Config.UseSSL { if len(config.Config.SSLCertFile) == 0 { log.Fatale(errors.New("UseSSL is true but SSLCertFile is unspecified")) } if len(config.Config.SSLPrivateKeyFile) == 0 { log.Fatale(errors.New("UseSSL is true but SSLPrivateKeyFile is unspecified")) } log.Info("Starting HTTPS listener") tlsConfig, err := ssl.NewTLSConfig(config.Config.SSLCAFile, config.Config.UseMutualTLS) if err != nil { log.Fatale(err) } if err = ssl.AppendKeyPair(tlsConfig, config.Config.SSLCertFile, config.Config.SSLPrivateKeyFile); err != nil { log.Fatale(err) } if err = ssl.ListenAndServeTLS(listenAddress, m, tlsConfig); err != nil { log.Fatale(err) } } else { log.Info("Starting HTTP listener") if err := nethttp.ListenAndServe(listenAddress, m); err != nil { log.Fatale(err) } } log.Info("Web server started") }
func TestAppendKeyPairWithPassword(t *testing.T) { c, err := ssl.NewTLSConfig("", false) if err != nil { t.Fatal(err) } pemCertFile := writeFakeFile(pemCertificate) defer syscall.Unlink(pemCertFile) pemPKFile := writeFakeFile(pemPrivateKeyWithPass) defer syscall.Unlink(pemPKFile) if err := ssl.AppendKeyPairWithPassword(c, pemCertFile, pemPKFile, []byte("testing")); err != nil { t.Errorf("Failed to append certificate and key to tls config: %s", err) } }
// Create a TLS configuration from the config supplied CA, Certificate, and Private key. // Register the TLS config with the mysql drivers as the "orchestrator" config // Modify the supplied URI to call the TLS config func SetupMySQLOrchestratorTLS(uri string) (string, error) { if !orchestratorTLSConfigured { tlsConfig, err := ssl.NewTLSConfig(config.Config.MySQLOrchestratorSSLCAFile, true) if err != nil { return "", log.Fatalf("Can't create TLS configuration for Orchestrator connection %s: %s", uri, err) } tlsConfig.InsecureSkipVerify = config.Config.MySQLOrchestratorSSLSkipVerify if err = ssl.AppendKeyPair(tlsConfig, config.Config.MySQLOrchestratorSSLCertFile, config.Config.MySQLOrchestratorSSLPrivateKeyFile); err != nil { return "", log.Fatalf("Can't setup TLS key pairs for %s: %s", uri, err) } if err = mysql.RegisterTLSConfig("orchestrator", tlsConfig); err != nil { return "", log.Fatalf("Can't register mysql TLS config for orchestrator: %s", err) } orchestratorTLSConfigured = true } return fmt.Sprintf("%s&tls=orchestrator", uri), nil }
// Create a TLS configuration from the config supplied CA, Certificate, and Private key. // Register the TLS config with the mysql drivers as the "topology" config // Modify the supplied URI to call the TLS config // TODO: Way to have password mixed with TLS for various nodes in the topology. Currently everything is TLS or everything is password func SetupMySQLTopologyTLS(uri string) (string, error) { if !topologyTLSConfigured { tlsConfig, err := ssl.NewTLSConfig(config.Config.MySQLTopologySSLCAFile, !config.Config.MySQLTopologySSLSkipVerify) // Drop to TLS 1.0 for talking to MySQL tlsConfig.MinVersion = tls.VersionTLS10 if err != nil { return "", log.Fatalf("Can't create TLS configuration for Topology connection %s: %s", uri, err) } tlsConfig.InsecureSkipVerify = config.Config.MySQLTopologySSLSkipVerify if err = ssl.AppendKeyPair(tlsConfig, config.Config.MySQLTopologySSLCertFile, config.Config.MySQLTopologySSLPrivateKeyFile); err != nil { return "", log.Fatalf("Can't setup TLS key pairs for %s: %s", uri, err) } if err = mysql.RegisterTLSConfig("topology", tlsConfig); err != nil { return "", log.Fatalf("Can't register mysql TLS config for topology: %s", err) } topologyTLSConfigured = true } return fmt.Sprintf("%s&tls=topology", uri), nil }
// agentsHttp startes serving agents HTTP or HTTPS API requests func agentsHttp() { m := martini.Classic() m.Use(gzip.All()) m.Use(render.Renderer()) if config.Config.AgentsUseMutualTLS { m.Use(ssl.VerifyOUs(config.Config.AgentSSLValidOUs)) } log.Info("Starting agents listener") go logic.ContinuousAgentsPoll() http.AgentsAPI.RegisterRequests(m) // Serve if config.Config.AgentsUseSSL { log.Info("Starting agent HTTPS listener") tlsConfig, err := ssl.NewTLSConfig(config.Config.AgentSSLCAFile, config.Config.AgentsUseMutualTLS) if err != nil { log.Fatale(err) } tlsConfig.InsecureSkipVerify = config.Config.AgentSSLSkipVerify if err = ssl.AppendKeyPairWithPassword(tlsConfig, config.Config.AgentSSLCertFile, config.Config.AgentSSLPrivateKeyFile, agentSSLPEMPassword); err != nil { log.Fatale(err) } if err = ssl.ListenAndServeTLS(config.Config.AgentsServerPort, m, tlsConfig); err != nil { log.Fatale(err) } } else { log.Info("Starting agent HTTP listener") if err := nethttp.ListenAndServe(config.Config.AgentsServerPort, m); err != nil { log.Fatale(err) } } log.Info("Agent server started") }
// standardHttp starts serving HTTP or HTTPS (api/web) requests, to be used by normal clients func standardHttp(discovery bool) { m := martini.Classic() switch strings.ToLower(config.Config.AuthenticationMethod) { case "basic": { if config.Config.HTTPAuthUser == "" { // Still allowed; may be disallowed in future versions log.Warning("AuthenticationMethod is configured as 'basic' but HTTPAuthUser undefined. Running without authentication.") } m.Use(auth.Basic(config.Config.HTTPAuthUser, config.Config.HTTPAuthPassword)) } case "multi": { if config.Config.HTTPAuthUser == "" { // Still allowed; may be disallowed in future versions log.Fatal("AuthenticationMethod is configured as 'multi' but HTTPAuthUser undefined") } m.Use(auth.BasicFunc(func(username, password string) bool { if username == "readonly" { // Will be treated as "read-only" return true } return auth.SecureCompare(username, config.Config.HTTPAuthUser) && auth.SecureCompare(password, config.Config.HTTPAuthPassword) })) } default: { // We inject a dummy User object because we have function signatures with User argument in api.go m.Map(auth.User("")) } } m.Use(gzip.All()) // Render html templates from templates directory m.Use(render.Renderer(render.Options{ Directory: "resources", Layout: "templates/layout", HTMLContentType: "text/html", })) m.Use(martini.Static("resources/public")) if config.Config.UseMutualTLS { m.Use(ssl.VerifyOUs(config.Config.SSLValidOUs)) } inst.SetMaintenanceOwner(process.ThisHostname) if discovery { log.Info("Starting Discovery") go logic.ContinuousDiscovery() } log.Info("Registering endpoints") http.API.RegisterRequests(m) http.Web.RegisterRequests(m) // Serve if config.Config.ListenSocket != "" { log.Infof("Starting HTTP listener on unix socket %v", config.Config.ListenSocket) unixListener, err := net.Listen("unix", config.Config.ListenSocket) if err != nil { log.Fatale(err) } defer unixListener.Close() if err := nethttp.Serve(unixListener, m); err != nil { log.Fatale(err) } } else if config.Config.UseSSL { log.Info("Starting HTTPS listener") tlsConfig, err := ssl.NewTLSConfig(config.Config.SSLCAFile, config.Config.UseMutualTLS) if err != nil { log.Fatale(err) } tlsConfig.InsecureSkipVerify = config.Config.SSLSkipVerify if err = ssl.AppendKeyPairWithPassword(tlsConfig, config.Config.SSLCertFile, config.Config.SSLPrivateKeyFile, sslPEMPassword); err != nil { log.Fatale(err) } if err = ssl.ListenAndServeTLS(config.Config.ListenAddress, m, tlsConfig); err != nil { log.Fatale(err) } } else { log.Infof("Starting HTTP listener on %+v", config.Config.ListenAddress) if err := nethttp.ListenAndServe(config.Config.ListenAddress, m); err != nil { log.Fatale(err) } } log.Info("Web server started") }