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

tcpproxy: add tls passthrough #850

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/ingressroute.md
Expand Up @@ -776,14 +776,17 @@ spec:
The `spec.tcpproxy` key indicates that this _root_ IngressRoute will forward all de-encrypted TCP traffic to the backend service.
In case `spec.virtualhost.tls` is not present, TLS is not going to be terminated
on Envoy and will be forwarded to the specified services, where the termination
would happen. This is called SSL/TLS Passthrough.
### Limitations
The current limitations are present in Contour 0.8. These will be addressed in later Contour versions.
- `spec.routes` must be present in the `IngressRoute` document to pass validation, however they are ignored when `spec.tcpproxy` is present.
- TCP Proxy IngressRoutes must be roots and can not delegate to other IngressRoutes.
- TCP Proxying is not available on Kubernetes Ingress objects.
- `spec.virtualhost.tls` is required for TCP proxying. If not present, `spec.tcpproxy` will be ignored.
## Status Reporting
Expand Down
17 changes: 9 additions & 8 deletions internal/contour/listener.go
Expand Up @@ -16,12 +16,13 @@ package contour
import (
"sync"

"github.com/envoyproxy/go-control-plane/envoy/api/v2"
v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
"github.com/gogo/protobuf/proto"
"github.com/heptio/contour/internal/dag"
"github.com/heptio/contour/internal/envoy"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
)

const (
Expand Down Expand Up @@ -230,11 +231,6 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) {
// the listener properly.
v.http = true
case *dag.SecureVirtualHost:
data := vh.Data()
if data == nil {
// no secret for this vhost, skip it
return
}
filters := []listener.Filter{
envoy.HTTPConnectionManager(ENVOY_HTTPS_LISTENER, v.httpsAccessLog()),
}
Expand All @@ -246,11 +242,16 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) {
alpnProtos = nil // do not offer ALPN
}

var tlsContext *auth.DownstreamTlsContext
if vh.Secret != nil && vh.Secret.Data() != nil {
data := vh.Secret.Data()
tlsContext = envoy.DownstreamTLSContext(data[v1.TLSCertKey], data[v1.TLSPrivateKeyKey], vh.MinProtoVersion, alpnProtos...)
}
fc := listener.FilterChain{
FilterChainMatch: &listener.FilterChainMatch{
ServerNames: []string{vh.Host},
},
TlsContext: envoy.DownstreamTLSContext(data[v1.TLSCertKey], data[v1.TLSPrivateKeyKey], vh.MinProtoVersion, alpnProtos...),
TlsContext: tlsContext,
Filters: filters,
UseProxyProto: bv(v.UseProxyProto),
}
Expand Down
8 changes: 4 additions & 4 deletions internal/dag/builder.go
Expand Up @@ -23,7 +23,7 @@ import (
"sync"
"time"

"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/tools/cache"
Expand Down Expand Up @@ -540,8 +540,8 @@ func (b *builder) DAG() *DAG {
}
}
for _, svh := range b.svhosts {
// suppress secure virtual hosts without secrets.
if svh.Secret != nil {
// suppress secure virtual hosts without secrets or tcpproxy.
if svh.Secret != nil || svh.TCPProxy != nil {
dag.roots = append(dag.roots, svh)
}
}
Expand Down Expand Up @@ -586,7 +586,7 @@ func (b *builder) processIngressRoute(ir *ingressroutev1.IngressRoute, prefixMat
visited = append(visited, ir)

proxy := ir.Spec.TCPProxy
if proxy != nil && enforceTLS {
if proxy != nil {
var ts []*TCPService
for _, service := range proxy.Services {
m := meta{name: service.Name, namespace: ir.Namespace}
Expand Down
45 changes: 42 additions & 3 deletions internal/dag/builder_test.go
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
"github.com/google/go-cmp/cmp"
ingressroutev1 "github.com/heptio/contour/apis/contour/v1beta1"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
Expand Down Expand Up @@ -615,7 +615,8 @@ func TestDAGInsert(t *testing.T) {
},
}

// ir1a tcp forwards traffic to default/kuard:8080
// ir1a tcp forwards traffic to default/kuard:8080 by TLS terminating it
// first.
ir1a := &ingressroutev1.IngressRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "kuard-tcp",
Expand Down Expand Up @@ -644,6 +645,26 @@ func TestDAGInsert(t *testing.T) {
},
}

// ir1b tcp forwards traffic to default/kuard:8080 by TLS pass-throughing
// it.
ir1b := &ingressroutev1.IngressRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "kuard-tcp",
Namespace: "default",
},
Spec: ingressroutev1.IngressRouteSpec{
VirtualHost: &ingressroutev1.VirtualHost{
Fqdn: "kuard.example.com",
},
TCPProxy: &ingressroutev1.TCPProxy{
Services: []ingressroutev1.Service{{
Name: "kuard",
Port: 8080,
}},
},
},
}

// ir2 is like ir1 but refers to two backend services
ir2 := &ingressroutev1.IngressRoute{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -1706,7 +1727,7 @@ func TestDAGInsert(t *testing.T) {
),
}},
},
"insert ingressroute with tcp forward": {
"insert ingressroute with tcp forward with TLS termination": {
objs: []interface{}{
ir1a, s1, sec1,
},
Expand All @@ -1726,6 +1747,24 @@ func TestDAGInsert(t *testing.T) {
},
},
},
"insert ingressroute with tcp forward without TLS termination": {
objs: []interface{}{
ir1b, s1,
},
want: []Vertex{
&SecureVirtualHost{
VirtualHost: VirtualHost{
Host: "kuard.example.com",
Port: 443,
TCPProxy: &TCPProxy{
Services: []*TCPService{
tcpService(s1),
},
},
},
},
},
},
"insert ingressroute with prefix rewrite route": {
objs: []interface{}{
ir10, s1,
Expand Down