Skip to content

Commit

Permalink
support tls termination for tcp traffic
Browse files Browse the repository at this point in the history
Signed-off-by: tanujd11 <[email protected]>
  • Loading branch information
tanujd11 committed May 20, 2023
1 parent 89b8b39 commit e4b5666
Show file tree
Hide file tree
Showing 36 changed files with 688 additions and 279 deletions.
83 changes: 83 additions & 0 deletions docs/latest/user/tls-termination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# TLS Termination for TCP

This guide will walk through the steps required to configure TLS Terminate mode for TCP traffic via Envoy Gateway. The guide uses a self-signed CA, so it should be used for testing and demonstration purposes only.

## Prerequisites

- OpenSSL to generate TLS assets.

## Installation

Follow the steps from the [Quickstart Guide](quickstart.md) to install Envoy Gateway.

## TLS Certificates
Generate the certificates and keys used by the Gateway to terminate client TLS connections.

Create a root certificate and private key to sign certificates:

```shell
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
```

Create a certificate and a private key for `www.example.com`:

```shell
openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization"
openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt
```

Store the cert/key in a Secret:

```shell
kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt
```

Install the TLS Termination for TCP example resources:

```shell
kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/tls-termination.yaml
```

Verify the Gateway status:

```shell
kubectl get gateway/eg -o yaml
```

## Testing

### Clusters without External LoadBalancer Support

Get the name of the Envoy service created the by the example Gateway:

```shell
export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
```

Port forward to the Envoy service:

```shell
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8443:443 &
```

Query the example app through Envoy proxy:

```shell
curl -v -HHost:www.example.com --resolve "www.example.com:8443:127.0.0.1" \
--cacert example.com.crt https://www.example.com:8443/get
```

### Clusters with External LoadBalancer Support

Get the External IP of the Gateway:

```shell
export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')
```

Query the example app through the Gateway:

```shell
curl -v -HHost:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" \
--cacert example.com.crt https://www.example.com/get
```
96 changes: 96 additions & 0 deletions examples/kubernetes/tls-termination.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- allowedRoutes:
namespaces:
from: Same
name: https
port: 443
protocol: TLS
tls:
certificateRefs:
- group: ""
kind: Secret
name: example-cert
mode: Terminate
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
---
apiVersion: v1
kind: Service
metadata:
name: backend
labels:
app: backend
service: backend
spec:
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
version: v1
template:
metadata:
labels:
app: backend
version: v1
spec:
serviceAccountName: backend
containers:
- image: gcr.io/k8s-staging-ingressconformance/echoserver:v20221109-7ee2f3e
imagePullPolicy: IfNotPresent
name: backend
ports:
- containerPort: 3000
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: backend
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: eg
rules:
- backendRefs:
- group: ""
kind: Service
name: backend
port: 3000
weight: 1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ gateways:
type: Programmed
name: tls
supportedKinds:
- group: gateway.networking.k8s.io
kind: TCPRoute
- group: gateway.networking.k8s.io
kind: TLSRoute
httpRoutes:
Expand Down
8 changes: 8 additions & 0 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,11 @@ func irTLSConfigs(tlsSecrets []*v1.Secret) []*ir.TLSListenerConfig {
func irTLSListenerConfigName(secret *v1.Secret) string {
return fmt.Sprintf("%s-%s", secret.Namespace, secret.Name)
}

func protocolSliceToStringSlice(protocols []v1beta1.ProtocolType) []string {
var protocolStrings []string
for _, protocol := range protocols {
protocolStrings = append(protocolStrings, string(protocol))
}
return protocolStrings
}
10 changes: 8 additions & 2 deletions internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ListenersTranslator interface {

func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) {
t.validateConflictedLayer7Listeners(gateways)
t.validateConflictedLayer4Listeners(gateways, v1beta1.TCPProtocolType)
t.validateConflictedLayer4Listeners(gateways, v1beta1.TCPProtocolType, v1beta1.TLSProtocolType)
t.validateConflictedLayer4Listeners(gateways, v1beta1.UDPProtocolType)

// Iterate through all listeners to validate spec
Expand Down Expand Up @@ -50,7 +50,13 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
// Process protocol & supported kinds
switch listener.Protocol {
case v1beta1.TLSProtocolType:
t.validateAllowedRoutes(listener, KindTLSRoute)
if listener.TLS != nil && *listener.TLS.Mode == v1beta1.TLSModePassthrough {
t.validateAllowedRoutes(listener, KindTLSRoute)
} else if listener.TLS != nil && *listener.TLS.Mode == v1beta1.TLSModeTerminate {
t.validateAllowedRoutes(listener, KindTCPRoute)
} else {
t.validateAllowedRoutes(listener, KindTCPRoute, KindTLSRoute)
}
case v1beta1.HTTPProtocolType, v1beta1.HTTPSProtocolType:
t.validateAllowedRoutes(listener, KindHTTPRoute, KindGRPCRoute)
case v1beta1.TCPProtocolType:
Expand Down
11 changes: 6 additions & 5 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour
Name: irTLSListenerName(listener, tlsRoute),
Address: "0.0.0.0",
Port: uint32(containerPort),
TLS: &ir.TLSInspectorConfig{
TLSInspectorConfig: &ir.TLSInspectorConfig{
SNIs: hosts,
},
Destinations: routeDestinations,
Expand Down Expand Up @@ -942,10 +942,11 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
// Create the TCP Listener while parsing the TCPRoute since
// the listener directly links to a routeDestination.
irListener := &ir.TCPListener{
Name: irTCPListenerName(listener, tcpRoute),
Address: "0.0.0.0",
Port: uint32(containerPort),
Destinations: routeDestinations,
Name: irTCPListenerName(listener, tcpRoute),
Address: "0.0.0.0",
Port: uint32(containerPort),
Destinations: routeDestinations,
TLSListenerConfig: irTLSConfigs(listener.tlsSecrets),
}
gwXdsIR := xdsIR[irKey]
gwXdsIR.TCP = append(gwXdsIR.TCP, irListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ xdsIR:
- name: envoy-gateway-gateway-1-tls-passthrough-tlsroute-1
address: 0.0.0.0
port: 10090
tls:
tlsInspectorConfig:
snis:
- "foo.com"
destinations:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ gateways:
namespaces:
from: All
- name: tcp2
protocol: TCP
protocol: TLS
port: 162
allowedRoutes:
namespaces:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ gateways:
namespaces:
from: All
- name: tcp2
protocol: TCP
protocol: TLS
port: 162
allowedRoutes:
namespaces:
Expand All @@ -37,18 +37,20 @@ gateways:
message: Listener has been successfully translated
- name: tcp2
supportedKinds:
- group: gateway.networking.k8s.io
kind: TCPRoute
- group: gateway.networking.k8s.io
kind: TCPRoute
- group: gateway.networking.k8s.io
kind: TLSRoute
AttachedRoutes: 0
conditions:
- type: Conflicted
status: "True"
reason: ProtocolConflict
message: Only one TCP listener is allowed in a given port
message: Only one TCP/TLS listener is allowed in a given port
- type: Programmed
status: "False"
reason: Invalid
message: Listener is invalid, see other Conditions for details.
message: Listener must have TLS set when protocol is TLS.
tcpRoutes:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: tls
protocol: TLS
port: 90
tls:
certificateRefs:
- group: ""
kind: Secret
name: tls-secret-1
mode: Terminate
allowedRoutes:
namespaces:
from: All
tcpRoutes:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
namespace: default
name: tcproute-1
spec:
parentRefs:
- namespace: envoy-gateway
name: gateway-1
rules:
- backendRefs:
- name: service-1
port: 8080

secrets:
- apiVersion: v1
kind: Secret
metadata:
namespace: envoy-gateway
name: tls-secret-1
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNxRENDQVpBQ0NRREVNZ1lZblFyQ29EQU5CZ2txaGtpRzl3MEJBUXNGQURBV01SUXdFZ1lEVlFRRERBdG0KYjI4dVltRnlMbU52YlRBZUZ3MHlNekF4TURVeE16UXpNalJhRncweU5EQXhNRFV4TXpRek1qUmFNQll4RkRBUwpCZ05WQkFNTUMyWnZieTVpWVhJdVkyOXRNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDCkFRRUFuZEh6d21wS2NUSUViamhGZ2RXd1RSTjc1Y3A4b3VsWnhMMUdydlI2SXc3ejdqaTBSNFcvTm85bkdmOU0KWVAyQ1JqaXN6NTFtd3hTeGVCcm9jTGVBK21reGkxK2lEdk5kQytyU0x4MTN6RUxTQ25xYnVzUHM3bUdmSlpxOAo5TGhlbmx5bzQzaDVjYTZINUxqTXd1L1JHVWlGMzFYck5yaVlGQlB2RTJyQitkd24vTkVrUTRoOFJxcXlwcmtuCkYvcWM5Sk1ZQVlGRld1VkNwa0lFbmRYMUN5dlFOT2FkZmN2cmd6dDV2SmwwT2kxQWdyaU5hWGJFUEdudWY3STQKcXBCSEdVWE5lMVdsOVdlVklxS1g0T2FFWERWQzZGQzdHOHptZWVMVzFBa1lFVm5pcFg2b1NCK0JjL1NIVlZOaApzQkxSbXRuc3pmTnRUMlFyZCttcGt4ODBaUUlEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1VKOElDCkJveUVqT3V3enBHYVJoR044QjRqT1B6aHVDT0V0ZDM3UzAybHUwN09IenlCdmJzVEd6S3dCZ0x5bVdmR2tINEIKajdDTHNwOEZ6TkhLWnVhQmdwblo5SjZETE9Od2ZXZTJBWXA3TGRmT0tWQlVkTVhRaU9tN2pKOUhob0Ntdk1ONwpic2pjaFdKb013ckZmK3dkQUthdHowcUFQeWhMeWUvRnFtaVZ4a09SWmF3K1Q5bURaK0g0OXVBU2d1SnVOTXlRClY2RXlYNmd0Z1dxMzc2SHZhWE1TLzNoYW1Zb1ZXWEk1TXhpUE9ZeG5BQmtKQjRTQ2dJUmVqYkpmVmFRdG9RNGEKejAyaVVMZW5ESUllUU9Zb2JLY01CWGYxQjRQQVFtc2VocVZJYnpzUUNHaTU0VkRyczZiWmQvN0pzMXpDcHBncwpKaUQ1SXFNaktXRHdxN2FLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
Loading

0 comments on commit e4b5666

Please sign in to comment.