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

Add GRPC proxy support #575

Merged
merged 13 commits into from
Dec 7, 2018
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 6 additions & 3 deletions config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ func parseListen(cfg map[string]string, cs map[string]CertSource, readTimeout, w
case "proto":
l.Proto = v
switch l.Proto {
case "tcp", "tcp+sni", "http", "https":
case "tcp", "tcp+sni", "http", "https", "grpc", "grpcs":
// ok
default:
return Listen{}, fmt.Errorf("unknown protocol %q", v)
Expand Down Expand Up @@ -391,12 +391,15 @@ func parseListen(cfg map[string]string, cs map[string]CertSource, readTimeout, w
if l.Addr == "" {
return Listen{}, fmt.Errorf("need listening host:port")
}
if csName != "" && l.Proto != "https" && l.Proto != "tcp" {
return Listen{}, fmt.Errorf("cert source requires proto 'https' or 'tcp'")
if csName != "" && l.Proto != "https" && l.Proto != "tcp" && l.Proto != "grpcs" {
return Listen{}, fmt.Errorf("cert source requires proto 'https', 'tcp' or 'grpcs'")
}
if csName == "" && l.Proto == "https" {
return Listen{}, fmt.Errorf("proto 'https' requires cert source")
}
if csName == "" && l.Proto == "grpcs" {
return Listen{}, fmt.Errorf("proto 'grpcs' requires cert source")
}
if cs[csName].Type == "vault-pki" && !l.StrictMatch {
// Without StrictMatch the first issued certificate is used for all
// subsequent requests, even if the common name doesn't match.
Expand Down
21 changes: 17 additions & 4 deletions config/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ func TestLoad(t *testing.T) {
return cfg
},
},
{
args: []string{"-proxy.addr", ":5555;proto=grpc"},
cfg: func(cfg *Config) *Config {
cfg.Listen = []Listen{{Addr: ":5555", Proto: "grpc"}}
return cfg
},
},
{
desc: "-proxy.addr with tls configs",
args: []string{"-proxy.addr", `:5555;rt=1s;wt=2s;tlsmin=0x0300;tlsmax=0x305;tlsciphers="0x123,0x456"`},
Expand Down Expand Up @@ -941,16 +948,22 @@ func TestLoad(t *testing.T) {
err: errors.New("proto 'https' requires cert source"),
},
{
desc: "-proxy.addr with cert source and proto 'http' requires proto 'https' or 'tcp'",
desc: "-proxy.addr with proto 'grpcs' requires cert source",
args: []string{"-proxy.addr", ":5555;proto=grpcs"},
cfg: func(cfg *Config) *Config { return nil },
err: errors.New("proto 'grpcs' requires cert source"),
},
{
desc: "-proxy.addr with cert source and proto 'http' requires proto 'https', 'tcp', or 'grpcs'",
args: []string{"-proxy.addr", ":5555;cs=name;proto=http", "-proxy.cs", "cs=name;type=path;cert=value"},
cfg: func(cfg *Config) *Config { return nil },
err: errors.New("cert source requires proto 'https' or 'tcp'"),
err: errors.New("cert source requires proto 'https', 'tcp' or 'grpcs'"),
},
{
desc: "-proxy.addr with cert source and proto 'tcp+sni' requires proto 'https' or 'tcp'",
desc: "-proxy.addr with cert source and proto 'tcp+sni' requires proto 'https', 'tcp' or 'grpcs'",
args: []string{"-proxy.addr", ":5555;cs=name;proto=tcp+sni", "-proxy.cs", "cs=name;type=path;cert=value"},
cfg: func(cfg *Config) *Config { return nil },
err: errors.New("cert source requires proto 'https' or 'tcp'"),
err: errors.New("cert source requires proto 'https', 'tcp' or 'grpcs'"),
},
{
desc: "-proxy.noroutestatus too small",
Expand Down
36 changes: 36 additions & 0 deletions docs/content/feature/grpc-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: "GRPC Proxy"
since: "1.5.10"
---

fabio can run a transparent GRPC proxy which dynamically forwards an incoming
RPC on a given port to services which advertise rpc service or method. To use GRPC
proxy support the service needs to advertise `urlprefix-/my.service/Method proto=grpc` in
Consul. In addition, fabio needs to be configured with a grpc listener:

```
fabio -proxy.addr ':1234;proto=grpc'
```

As per the HTTP/2 spec, the host header is not required, so host matching is not supported for GRPC proxying.

GRPC proxy support can be combined with [Certificate Stores](/feature/certificate-stores/) to provide TLS termination on fabio. Configure `proxy.addr` with `proto=grpcs`.

```
fabio -proxy.cs 'cs=ssl;type=path;path=/etc/ssl' -proxy.addr ':1234;proto=grpcs;cs=ssl'
```

To support TLS upstream servers add the `proto=grpcs` option to the
`urlprefix-` tag. The current implementation uses the clientca specified in the [Certificate Store](/feature/certificate-stores/) for the listener. To disable certificate
validation for a target set the `tlsskipverify=true` option.

```
urlprefix-/foo proto=grpcs
urlprefix-/foo proto=grpcs tlsskipverify=true
```

For TLS upstream servers (when using the consul registry) fabio will direct your traffic to an advertised service IP. If your service certificate does not contain an IP SAN, the certificate verification will fail. You can set the override the server name in the tls config by setting `grpcservername=<servername>` in the `urlprefix-` tag.

```
urlprefix-/ proto=grpcs grpcservername=my.service.hostname
```
7 changes: 6 additions & 1 deletion docs/content/feature/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ Fabio reports the following metrics:

Name | Type | Description
--------------------------- | -------- | -------------
`{route}.rx` | timer | Number of bytes received by fabion for TCP target
`{route}.rx` | timer | Number of bytes received by fabio for TCP target
`{route}.tx` | timer | Number of bytes transmitted by fabio for TCP target
`{route}` | timer | Average response time for a route
`http.status.code.{code}` | timer | Average response time for all HTTP(S) requests per status code
`notfound` | counter | Number of failed HTTP route lookups
`requests` | timer | Average response time for all HTTP(S) requests
`grpc.requests` | timer | Average response time for all GRPC(S) requests
`grpc.noroute` | counter | Number of failed GRPC route lookups
`grpc.conn` | counter | Number of established GRPC proxy connections
`grpc.status.{code}` | timer | Average response time for all GRPC(S) requests per status code
`tcp.conn` | counter | Number of established TCP proxy connections
`tcp.connfail` | counter | Number of TCP upstream connection failures
`tcp.noroute` | counter | Number of failed TCP upstream route lookups
Expand All @@ -29,6 +33,7 @@ Name | Type | Description
`tcp_sni.noroute` | counter | Number of failed TCP+SNI upstream route lookups
`ws.conn` | gauge | Number of actively open websocket connections


### Legend

#### timer
Expand Down
7 changes: 7 additions & 0 deletions docs/content/quickstart/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ and you need to add a separate `urlprefix-` tag for every `host/path` prefix the

# TCP examples
urlprefix-:3306 proto=tcp # route external port 3306

# GRPC/S examples
urlprefix-/my.service/Method proto=grpc # method specific route
urlprefix-/my.service proto=grpc # service specific route
urlprefix-/my.service proto=grpcs # TLS upstream
urlprefix-/my.service proto=grpcs grpcservername=my.service # TLS upstream with servername override
urlprefix-/my.service proto=grpcs tlsskipverify=true # TLS upstream and self-signed cert
```

5. Start fabio without a config file
Expand Down
8 changes: 8 additions & 0 deletions docs/content/ref/proxy.addr.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ The supported protocols are:

* `http` for HTTP based protocols
* `https` for HTTPS based protocols
* `grpc` for GRPC based protocols
* `grpcs` for GRPC+TLS based protocols
* `tcp` for a raw TCP proxy with or witout TLS support
* `tcp+sni` for an SNI aware TCP proxy

Expand Down Expand Up @@ -76,6 +78,12 @@ to the destination without decrypting the traffic.

# HTTPS listener on port 443 with certificate source and TLS options
proxy.addr = :443;cs=some-name;tlsmin=tls10;tlsmax=tls11;tlsciphers="0xc00a,0xc02b"

# GRPC listener on port 8888
proxy.addr = :8888;proto=grpc

# GRPCS listener on port 8888 with certificate source
proxy.addr = :8888;proto=grpcs;cs=some-name

# TCP listener on port 1234 with port routing
proxy.addr = :1234;proto=tcp
Expand Down
16 changes: 12 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/fabiolb/fabio

require (
cloud.google.com/go v0.33.1 // indirect
contrib.go.opencensus.io/exporter/ocagent v0.3.0 // indirect
github.com/Azure/azure-sdk-for-go v22.2.2+incompatible // indirect
github.com/Azure/go-autorest v11.2.7+incompatible // indirect
Expand Down Expand Up @@ -32,6 +33,7 @@ require (
github.com/gobwas/glob v0.0.0-20180208211842-19c076cdf202
github.com/gogo/protobuf v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff // indirect
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/gorilla/websocket v1.4.0 // indirect
Expand Down Expand Up @@ -62,6 +64,7 @@ require (
github.com/mitchellh/go-homedir v0.0.0-20160606030122-1111e456ffea // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mitchellh/mapstructure v0.0.0-20160212031839-d2dd02622084 // indirect
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76
github.com/ncw/swift v1.0.42 // indirect
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect
github.com/opentracing/opentracing-go v1.0.2
Expand Down Expand Up @@ -91,12 +94,17 @@ require (
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1 // indirect
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 // indirect
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 // indirect
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 // indirect
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba // indirect
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
golang.org/x/tools v0.0.0-20181121193951-91f80e683c10 // indirect
google.golang.org/appengine v1.3.0 // indirect
google.golang.org/grpc v1.16.0 // indirect
google.golang.org/genproto v0.0.0-20181109154231-b5d43981345b // indirect
google.golang.org/grpc v1.16.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3 // indirect
)
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
contrib.go.opencensus.io/exporter/ocagent v0.3.0 h1:fyqPXp7d+BBV3tXa7EE1CYrObJr7R9jTAOO/AsdcQBg=
contrib.go.opencensus.io/exporter/ocagent v0.3.0/go.mod h1:0fnkYHF+ORKj7HWzOExKkUHeFX79gXSKUQbpnAM+wzo=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
Expand Down Expand Up @@ -77,6 +78,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg=
github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -165,6 +167,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160212031839-d2dd02622084 h1:Z2EJ6SUY
github.com/mitchellh/mapstructure v0.0.0-20160212031839-d2dd02622084/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76 h1:LxaK681Aane3f53b4qVTXXq83lL9fWwBTaaZOf9VizA=
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
github.com/ncw/swift v1.0.42 h1:ztvRb6hs52IHOcaYt73f9lXYLIeIuWgdooRDhdyllGI=
github.com/ncw/swift v1.0.42/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
Expand Down Expand Up @@ -237,25 +241,35 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181121193951-91f80e683c10/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf h1:rjxqQmxjyqerRKEj+tZW+MCm4LgpFXu18bsEoCMgDsk=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
Expand All @@ -265,6 +279,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181109154231-b5d43981345b h1:WkFtVmaZoTRVoRYr0LTC9SYNhlw0X0HrVPz2OVssVm4=
google.golang.org/genproto v0.0.0-20181109154231-b5d43981345b/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY=
Expand All @@ -277,3 +293,4 @@ gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
31 changes: 31 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ import (
"github.com/fabiolb/fabio/registry/static"
"github.com/fabiolb/fabio/route"
"github.com/fabiolb/fabio/trace"
grpc_proxy "github.com/mwitkow/grpc-proxy/proxy"
"github.com/pkg/profile"
dmp "github.com/sergi/go-diff/diffmatchpatch"
"google.golang.org/grpc"
)

// version contains the version number
Expand Down Expand Up @@ -139,6 +141,28 @@ func main() {
log.Print("[INFO] Down")
}

func newGrpcProxy(cfg *config.Config, tlscfg *tls.Config) []grpc.ServerOption {
statsHandler := &proxy.GrpcStatsHandler{
Connect: metrics.DefaultRegistry.GetCounter("grpc.conn"),
Request: metrics.DefaultRegistry.GetTimer("grpc.requests"),
NoRoute: metrics.DefaultRegistry.GetCounter("grpc.noroute"),
}

proxyInterceptor := proxy.GrpcProxyInterceptor{
Config: cfg,
StatsHandler: statsHandler,
}

handler := grpc_proxy.TransparentHandler(proxy.GetGRPCDirector(tlscfg))

return []grpc.ServerOption{
grpc.CustomCodec(grpc_proxy.Codec()),
grpc.UnknownServiceHandler(handler),
grpc.StreamInterceptor(proxyInterceptor.Stream),
grpc.StatsHandler(statsHandler),
}
}

func newHTTPProxy(cfg *config.Config) http.Handler {
var w io.Writer
switch cfg.Log.AccessTarget {
Expand Down Expand Up @@ -273,6 +297,13 @@ func startServers(cfg *config.Config) {
exit.Fatal("[FATAL] ", err)
}
}()
case "grpc", "grpcs":
go func() {
h := newGrpcProxy(cfg, tlscfg)
if err := proxy.ListenAndServeGRPC(l, h, tlscfg); err != nil {
exit.Fatal("[FATAL] ", err)
}
}()
case "tcp":
go func() {
h := &tcp.Proxy{
Expand Down
Loading