Skip to content

Commit

Permalink
Issue #8: Add support for SSL client authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
magiconair committed Nov 1, 2015
1 parent 5b7d611 commit 8a223b0
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ fabio.sublime-*
*.pem
.DS_Store
*.out
*.p12
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Changelog

### ???

* Add support for SSL client certificate authentication

### [v1.0.3](https://github.com/eBay/fabio/releases/tag/v1.0.3) - 25 Oct 2015

* Add Docker support and official Docker image `magiconair/fabio`
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ instances.
* Hot-reloading of routing table through backend watchers
* Round robin and random distribution
* [Traffic Shaping](#Traffic Shaping) (send 5% of traffic to new instances)
* SSL client certificate authentication support
* Graphite metrics
* Request tracing
* WebUI
Expand Down
7 changes: 5 additions & 2 deletions fabio.properties
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# proxy.addr configures the HTTP and HTTPS listeners as a comma separated list.
#
# To configure an HTTP listener provide [host]:port.
# To configure an HTTPS listener provide [host]:port;certFile;keyFile.
# To configure an HTTPS listener provide [host]:port;certFile;keyFile;clientAuthFile.
# certFile and keyFile contain the public/private key pair for that listener
# in PEM format. If certFile contains both the public and private key then
# keyFile can be omittted.
# clientAuthFile contains the root CAs for client certificate validation.
# When clientAuthFile is provided the TLS configuration is set to
# RequireAndVerifyClientCert.
#
# Configure a single HTTP listener on port 9999:
#
# proxy.addr = :9999
#
# Configure both an HTTP and HTTPS listener:
#
# proxy.addr = :9999,:443;path/to/cert.pem;path/to/key.pem
# proxy.addr = :9999,:443;path/to/cert.pem;path/to/key.pem;path/to/clientauth.pem
#
# Configure multiple HTTP and HTTPS listeners on IPv4 and IPv6:
#
Expand Down
27 changes: 23 additions & 4 deletions listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"net"
"net/http"
Expand Down Expand Up @@ -36,14 +38,16 @@ func listen(addrs string, wait time.Duration, h http.Handler) {
continue
}

p := semicolons.Split(addr, 4)
p := semicolons.Split(addr, 5)
switch len(p) {
case 1:
go listenAndServe(p[0], h)
case 2:
go listenAndServeTLS(p[0], p[1], p[1], h)
go listenAndServeTLS(p[0], p[1], p[1], "", h)
case 3:
go listenAndServeTLS(p[0], p[1], p[2], h)
go listenAndServeTLS(p[0], p[1], p[2], "", h)
case 4:
go listenAndServeTLS(p[0], p[1], p[2], p[3], h)
default:
log.Fatal("[FATAL] Invalid address format ", addr)
}
Expand All @@ -69,7 +73,7 @@ func listenAndServe(addr string, h http.Handler) {
}

// listenAndServeTLS starts an HTTPS server with the given certificate.
func listenAndServeTLS(addr, certFile, keyFile string, h http.Handler) {
func listenAndServeTLS(addr, certFile, keyFile, clientAuthFile string, h http.Handler) {
log.Printf("[INFO] HTTPS proxy listening on %s with certificate %s", addr, certFile)
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
Expand All @@ -80,6 +84,21 @@ func listenAndServeTLS(addr, certFile, keyFile string, h http.Handler) {
NextProtos: []string{"http/1.1"},
Certificates: []tls.Certificate{cert},
}

if clientAuthFile != "" {
pemBlock, err := ioutil.ReadFile(clientAuthFile)
if err != nil {
log.Fatal("[FATAL] ", err)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(pemBlock) {
log.Fatal("[FATAL] failed to add client auth certs")
}
config.ClientCAs = pool
config.ClientAuth = tls.RequireAndVerifyClientCert
log.Printf("[INFO] Client certificate authentication enabled on %s with certificates from %s", addr, clientAuthFile)
}

srv := &http.Server{Addr: addr, TLSConfig: config, Handler: h}

ln, err := net.Listen("tcp", addr)
Expand Down
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/eBay/fabio/ui"
)

var version = "1.0.3"
var version = "1.0.4-issue-8-ssl-client-auth"

func main() {
var cfg string
Expand Down Expand Up @@ -67,8 +67,8 @@ func main() {
log.Fatal("[FATAL] ", err)
}

consul.Addr = consulAddr;
consul.URL = consulURL;
consul.Addr = consulAddr
consul.URL = consulURL

dc, err := consul.Datacenter()
if err != nil {
Expand Down

0 comments on commit 8a223b0

Please sign in to comment.