Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow UI/API to be served over https #258

Merged
merged 1 commit into from
Apr 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions admin/server.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package admin

import (
"crypto/tls"
"fmt"
"net/http"

"github.com/eBay/fabio/admin/api"
"github.com/eBay/fabio/admin/ui"
"github.com/eBay/fabio/config"
"github.com/eBay/fabio/proxy"
)

// Server provides the HTTP server for the admin UI and API.
Expand All @@ -19,7 +21,7 @@ type Server struct {
}

// ListenAndServe starts the admin server.
func (s *Server) ListenAndServe(addr string) error {
func (s *Server) ListenAndServe(l config.Listen, tlscfg *tls.Config) error {
http.Handle("/api/config", &api.ConfigHandler{s.Cfg})
http.Handle("/api/manual", &api.ManualHandler{})
http.Handle("/api/routes", &api.RoutesHandler{})
Expand All @@ -28,7 +30,7 @@ func (s *Server) ListenAndServe(addr string) error {
http.Handle("/routes", &ui.RoutesHandler{Color: s.Color, Title: s.Title, Version: s.Version})
http.HandleFunc("/health", handleHealth)
http.Handle("/", http.RedirectHandler("/routes", http.StatusSeeOther))
return http.ListenAndServe(addr, nil)
return proxy.ListenAndServeHTTP(l, nil, tlscfg)
}

func handleHealth(w http.ResponseWriter, r *http.Request) {
Expand Down
7 changes: 4 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ type Listen struct {
}

type UI struct {
Addr string
Color string
Title string
Listen Listen
Color string
Title string
}

type Proxy struct {
Expand Down Expand Up @@ -118,4 +118,5 @@ type Consul struct {
ServiceStatus []string
CheckInterval time.Duration
CheckTimeout time.Duration
CheckScheme string
}
8 changes: 7 additions & 1 deletion config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ var defaultValues = struct {
CertSourcesValue []map[string]string
ReadTimeout time.Duration
WriteTimeout time.Duration
UIListenerValue string
GZIPContentTypesValue string
}{
ListenerValue: []string{":9999"},
CertSourcesValue: []map[string]string{},
UIListenerValue: ":9998",
}

var defaultConfig = &Config{
Expand Down Expand Up @@ -51,6 +53,7 @@ var defaultConfig = &Config{
ServiceStatus: []string{"passing"},
CheckInterval: time.Second,
CheckTimeout: 3 * time.Second,
CheckScheme: "http",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that you could default to "" == "http". Would save you an else. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean by this and the change in registry/consul/register.go

},
Timeout: 10 * time.Second,
Retry: 500 * time.Millisecond,
Expand All @@ -60,7 +63,10 @@ var defaultConfig = &Config{
GOMAXPROCS: runtime.NumCPU(),
},
UI: UI{
Addr: ":9998",
Listen: Listen{
Addr: ":9998",
Proto: "http",
},
Color: "light-green",
},
}
15 changes: 14 additions & 1 deletion config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c

// config values
var listenerValue []string
var uiListenerValue string
var certSourcesValue []map[string]string
var readTimeout, writeTimeout time.Duration
var gzipContentTypesValue string
Expand Down Expand Up @@ -163,7 +164,7 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c
f.DurationVar(&cfg.Registry.Consul.CheckTimeout, "registry.consul.register.checkTimeout", defaultConfig.Registry.Consul.CheckTimeout, "service check timeout")
f.IntVar(&cfg.Runtime.GOGC, "runtime.gogc", defaultConfig.Runtime.GOGC, "sets runtime.GOGC")
f.IntVar(&cfg.Runtime.GOMAXPROCS, "runtime.gomaxprocs", defaultConfig.Runtime.GOMAXPROCS, "sets runtime.GOMAXPROCS")
f.StringVar(&cfg.UI.Addr, "ui.addr", defaultConfig.UI.Addr, "address the UI/API is listening on")
f.StringVar(&uiListenerValue, "ui.addr", defaultValues.UIListenerValue, "Address the UI/API is listening on")
f.StringVar(&cfg.UI.Color, "ui.color", defaultConfig.UI.Color, "background color of the UI")
f.StringVar(&cfg.UI.Title, "ui.title", defaultConfig.UI.Title, "optional title for the UI")

Expand Down Expand Up @@ -191,11 +192,23 @@ func load(cmdline, environ, envprefix []string, props *properties.Properties) (c
return nil, err
}

if uiListenerValue != "" {
cfg.UI.Listen, err = parseListen(uiListenerValue, certSources, 0, 0)
if err != nil {
return nil, err
}
}

cfg.Listen, err = parseListeners(listenerValue, certSources, readTimeout, writeTimeout)
if err != nil {
return nil, err
}

cfg.Registry.Consul.CheckScheme = defaultConfig.Registry.Consul.CheckScheme
if cfg.UI.Listen.CertSource.Name != "" {
cfg.Registry.Consul.CheckScheme = "https"
}

if gzipContentTypesValue != "" {
cfg.Proxy.GZIPContentTypes, err = regexp.Compile(gzipContentTypesValue)
if err != nil {
Expand Down
15 changes: 14 additions & 1 deletion config/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,20 @@ func TestLoad(t *testing.T) {
{
args: []string{"-ui.addr", "1.2.3.4:5555"},
cfg: func(cfg *Config) *Config {
cfg.UI.Addr = "1.2.3.4:5555"
cfg.UI.Listen.Addr = "1.2.3.4:5555"
cfg.UI.Listen.Proto = "http"
return cfg
},
},
{
args: []string{"-ui.addr", ":9998;cs=ui", "-proxy.cs", "cs=ui;type=file;cert=value"},
cfg: func(cfg *Config) *Config {
cfg.UI.Listen.Addr = ":9998"
cfg.UI.Listen.Proto = "https"
cfg.UI.Listen.CertSource.Name = "ui"
cfg.UI.Listen.CertSource.Type = "file"
cfg.UI.Listen.CertSource.CertPath = "value"
cfg.Registry.Consul.CheckScheme = "https"
return cfg
},
},
Expand Down
33 changes: 20 additions & 13 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,35 +161,42 @@ func lookupHostFn(cfg *config.Config) func(string) string {
}
}

func makeTLSConfig(l config.Listen) *tls.Config {
if l.CertSource.Name == "" {
return nil
}
src, err := cert.NewSource(l.CertSource)
if err != nil {
exit.Fatalf("[FATAL] Failed to create cert source %s. %s", l.CertSource.Name, err)
}
tlscfg, err := cert.TLSConfig(src, l.StrictMatch)
if err != nil {
exit.Fatalf("[FATAL] Failed to create TLS config for cert source %s. %s", l.CertSource.Name, err)
}
return tlscfg
}

func startAdmin(cfg *config.Config) {
log.Printf("[INFO] Admin server listening on %q", cfg.UI.Addr)
log.Printf("[INFO] Admin server listening on %q", cfg.UI.Listen.Addr)
go func() {
l := cfg.UI.Listen
tlscfg := makeTLSConfig(l)
srv := &admin.Server{
Color: cfg.UI.Color,
Title: cfg.UI.Title,
Version: version,
Commands: route.Commands,
Cfg: cfg,
}
if err := srv.ListenAndServe(cfg.UI.Addr); err != nil {
if err := srv.ListenAndServe(l, tlscfg); err != nil {
exit.Fatal("[FATAL] ui: ", err)
}
}()
}

func startServers(cfg *config.Config) {
for _, l := range cfg.Listen {
var tlscfg *tls.Config
if l.CertSource.Name != "" {
src, err := cert.NewSource(l.CertSource)
if err != nil {
exit.Fatal("[FATAL] Failed to create cert source %s. %s", l.CertSource.Name, err)
}
tlscfg, err = cert.TLSConfig(src, l.StrictMatch)
if err != nil {
exit.Fatal("[FATAL] Failed to create TLS config for cert source %s. %s", l.CertSource.Name, err)
}
}
tlscfg := makeTLSConfig(l)

log.Printf("[INFO] %s proxy listening on %s", strings.ToUpper(l.Proto), l.Addr)
if tlscfg != nil && tlscfg.ClientAuth == tls.RequireAndVerifyClientCert {
Expand Down
2 changes: 1 addition & 1 deletion registry/consul/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (b *be) Register() error {
return nil
}

service, err := serviceRegistration(b.cfg.ServiceAddr, b.cfg.ServiceName, b.cfg.ServiceTags, b.cfg.CheckInterval, b.cfg.CheckTimeout)
service, err := serviceRegistration(b.cfg)
if err != nil {
return err
}
Expand Down
18 changes: 9 additions & 9 deletions registry/consul/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ func register(c *api.Client, service *api.AgentServiceRegistration) (dereg chan
return dereg
}

func serviceRegistration(addr, name string, tags []string, interval, timeout time.Duration) (*api.AgentServiceRegistration, error) {
func serviceRegistration(cfg *config.Consul) (*api.AgentServiceRegistration, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
ipstr, portstr, err := net.SplitHostPort(addr)
ipstr, portstr, err := net.SplitHostPort(cfg.ServiceAddr)
if err != nil {
return nil, err
}
Expand All @@ -101,23 +101,23 @@ func serviceRegistration(addr, name string, tags []string, interval, timeout tim
}
}

serviceID := fmt.Sprintf("%s-%s-%d", name, hostname, port)
serviceID := fmt.Sprintf("%s-%s-%d", cfg.ServiceName, hostname, port)

checkURL := fmt.Sprintf("http://%s:%d/health", ip, port)
checkURL := fmt.Sprintf("%s://%s:%d/health", cfg.CheckScheme, ip, port)
if ip.To16() != nil {
checkURL = fmt.Sprintf("http://[%s]:%d/health", ip, port)
checkURL = fmt.Sprintf("%s://[%s]:%d/health", cfg.CheckScheme, ip, port)
}

service := &api.AgentServiceRegistration{
ID: serviceID,
Name: name,
Name: cfg.ServiceName,
Address: ip.String(),
Port: port,
Tags: tags,
Tags: cfg.ServiceTags,
Check: &api.AgentServiceCheck{
HTTP: checkURL,
Interval: interval.String(),
Timeout: timeout.String(),
Interval: cfg.CheckInterval.String(),
Timeout: cfg.CheckTimeout.String(),
},
}

Expand Down