Skip to content

Commit fe2bf5c

Browse files
authored
Add sslpassthrough tests (#9457)
1 parent a8f4f29 commit fe2bf5c

File tree

6 files changed

+231
-28
lines changed

6 files changed

+231
-28
lines changed

build/build.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
GO_BUILD_CMD="go build"
1818

19-
if [ -n "$DEBUG" ]; then
20-
set -x
21-
GO_BUILD_CMD="go build -v"
22-
fi
19+
#if [ -n "$DEBUG" ]; then
20+
# set -x
21+
# GO_BUILD_CMD="go build -v"
22+
#fi
2323

2424
set -o errexit
2525
set -o nounset

build/run-in-docker.sh

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,21 @@ fi
6565

6666
USER=${USER:-nobody}
6767

68-
echo "..printing env & other vars to stdout"
69-
echo "HOSTNAME=`hostname`"
70-
uname -a
71-
env
72-
echo "DIND_ENABLED=$DOCKER_IN_DOCKER_ENABLED"
73-
echo "done..printing env & other vars to stdout"
68+
#echo "..printing env & other vars to stdout"
69+
#echo "HOSTNAME=`hostname`"
70+
#uname -a
71+
#env
72+
#echo "DIND_ENABLED=$DOCKER_IN_DOCKER_ENABLED"
73+
#echo "done..printing env & other vars to stdout"
7474

7575
if [[ "$DOCKER_IN_DOCKER_ENABLED" == "true" ]]; then
7676
echo "..reached DIND check TRUE block, inside run-in-docker.sh"
7777
echo "FLAGS=$FLAGS"
78-
go env
79-
set -x
78+
#go env
8079
go install -mod=mod github.com/onsi/ginkgo/v2/[email protected]
8180
find / -type f -name ginkgo 2>/dev/null
8281
which ginkgo
8382
/bin/bash -c "${FLAGS}"
84-
set +x
8583
else
8684
echo "Reached DIND check ELSE block, inside run-in-docker.sh"
8785
docker run \

pkg/tcpproxy/tcp.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (p *TCPProxy) Handle(conn net.Conn) {
8080
}
8181

8282
hostPort := net.JoinHostPort(proxy.IP, fmt.Sprintf("%v", proxy.Port))
83+
klog.V(4).InfoS("passing to", "hostport", hostPort)
8384
clientConn, err := net.Dial("tcp", hostPort)
8485
if err != nil {
8586
klog.V(4).ErrorS(err, "error dialing proxy", "ip", proxy.IP, "port", proxy.Port, "hostname", proxy.Hostname)
@@ -99,7 +100,7 @@ func (p *TCPProxy) Handle(conn net.Conn) {
99100
}
100101
proxyProtocolHeader := fmt.Sprintf("PROXY %s %s %s %d %d\r\n", protocol, remoteAddr.IP.String(), localAddr.IP.String(), remoteAddr.Port, localAddr.Port)
101102
klog.V(4).InfoS("Writing Proxy Protocol", "header", proxyProtocolHeader)
102-
_, err = fmt.Fprintf(clientConn, proxyProtocolHeader)
103+
_, err = fmt.Fprint(clientConn, proxyProtocolHeader)
103104
}
104105
if err != nil {
105106
klog.ErrorS(err, "Error writing Proxy Protocol header")
@@ -126,8 +127,5 @@ func pipe(client, server net.Conn) {
126127
go doCopy(server, client, cancel)
127128
go doCopy(client, server, cancel)
128129

129-
select {
130-
case <-cancel:
131-
return
132-
}
130+
<-cancel
133131
}

test/e2e/framework/deployment.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ func (f *Framework) NewEchoDeployment(opts ...func(*deploymentOptions)) {
8585
}
8686

8787
deployment := newDeployment(options.name, options.namespace, "registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:778ac6d1188c8de8ecabeddd3c37b72c8adc8c712bad2bd7a81fb23a3514934c", 80, int32(options.replicas),
88-
nil,
88+
nil, nil, nil,
8989
[]corev1.VolumeMount{},
9090
[]corev1.Volume{},
91+
true,
9192
)
9293

9394
f.EnsureDeployment(deployment)
@@ -183,7 +184,7 @@ func (f *Framework) NGINXDeployment(name string, cfg string, waitendpoint bool)
183184
assert.Nil(ginkgo.GinkgoT(), err, "creating configmap")
184185

185186
deployment := newDeployment(name, f.Namespace, f.GetNginxBaseImage(), 80, 1,
186-
nil,
187+
nil, nil, nil,
187188
[]corev1.VolumeMount{
188189
{
189190
Name: name,
@@ -203,7 +204,7 @@ func (f *Framework) NGINXDeployment(name string, cfg string, waitendpoint bool)
203204
},
204205
},
205206
},
206-
},
207+
}, true,
207208
)
208209

209210
f.EnsureDeployment(deployment)
@@ -334,8 +335,8 @@ func (f *Framework) NewGRPCBinDeployment() {
334335
assert.Nil(ginkgo.GinkgoT(), err, "waiting for endpoints to become ready")
335336
}
336337

337-
func newDeployment(name, namespace, image string, port int32, replicas int32, command []string,
338-
volumeMounts []corev1.VolumeMount, volumes []corev1.Volume) *appsv1.Deployment {
338+
func newDeployment(name, namespace, image string, port int32, replicas int32, command []string, args []string, env []corev1.EnvVar,
339+
volumeMounts []corev1.VolumeMount, volumes []corev1.Volume, setProbe bool) *appsv1.Deployment {
339340
probe := &corev1.Probe{
340341
InitialDelaySeconds: 2,
341342
PeriodSeconds: 1,
@@ -381,9 +382,7 @@ func newDeployment(name, namespace, image string, port int32, replicas int32, co
381382
ContainerPort: port,
382383
},
383384
},
384-
ReadinessProbe: probe,
385-
LivenessProbe: probe,
386-
VolumeMounts: volumeMounts,
385+
VolumeMounts: volumeMounts,
387386
},
388387
},
389388
Volumes: volumes,
@@ -392,10 +391,20 @@ func newDeployment(name, namespace, image string, port int32, replicas int32, co
392391
},
393392
}
394393

394+
if setProbe {
395+
d.Spec.Template.Spec.Containers[0].ReadinessProbe = probe
396+
d.Spec.Template.Spec.Containers[0].LivenessProbe = probe
397+
}
395398
if len(command) > 0 {
396399
d.Spec.Template.Spec.Containers[0].Command = command
397400
}
398401

402+
if len(args) > 0 {
403+
d.Spec.Template.Spec.Containers[0].Args = args
404+
}
405+
if len(env) > 0 {
406+
d.Spec.Template.Spec.Containers[0].Env = env
407+
}
399408
return d
400409
}
401410

@@ -404,9 +413,13 @@ func (f *Framework) NewHttpbinDeployment() {
404413
f.NewDeployment(HTTPBinService, "registry.k8s.io/ingress-nginx/e2e-test-httpbin@sha256:c6372ef57a775b95f18e19d4c735a9819f2e7bb4641e5e3f27287d831dfeb7e8", 80, 1)
405414
}
406415

407-
// NewDeployment creates a new deployment in a particular namespace.
408416
func (f *Framework) NewDeployment(name, image string, port int32, replicas int32) {
409-
deployment := newDeployment(name, f.Namespace, image, port, replicas, nil, nil, nil)
417+
f.NewDeploymentWithOpts(name, image, port, replicas, nil, nil, nil, nil, nil, true)
418+
}
419+
420+
// NewDeployment creates a new deployment in a particular namespace.
421+
func (f *Framework) NewDeploymentWithOpts(name, image string, port int32, replicas int32, command []string, args []string, env []corev1.EnvVar, volumeMounts []corev1.VolumeMount, volumes []corev1.Volume, setProbe bool) {
422+
deployment := newDeployment(name, f.Namespace, image, port, replicas, command, args, env, volumeMounts, volumes, setProbe)
410423

411424
f.EnsureDeployment(deployment)
412425

test/e2e/framework/httpexpect/request.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ limitations under the License.
1717
package httpexpect
1818

1919
import (
20+
"context"
2021
"fmt"
2122
"io"
23+
"net"
2224
"net/http"
2325
"net/url"
2426
"path"
@@ -71,6 +73,33 @@ func (h *HTTPRequest) DoRequest(method, rpath string) *HTTPRequest {
7173
return h
7274
}
7375

76+
// ForceResolve forces the test resolver to point to a specific endpoint
77+
func (h *HTTPRequest) ForceResolve(ip string, port uint16) *HTTPRequest {
78+
addr := net.ParseIP(ip)
79+
if addr == nil {
80+
h.chain.fail(fmt.Sprintf("invalid ip address: %s", ip))
81+
return h
82+
}
83+
dialer := &net.Dialer{
84+
Timeout: h.client.Timeout,
85+
KeepAlive: h.client.Timeout,
86+
DualStack: true,
87+
}
88+
resolveAddr := fmt.Sprintf("%s:%d", ip, int(port))
89+
90+
oldTransport, ok := h.client.Transport.(*http.Transport)
91+
if !ok {
92+
h.chain.fail("invalid old transport address")
93+
return h
94+
}
95+
newTransport := oldTransport.Clone()
96+
newTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
97+
return dialer.DialContext(ctx, network, resolveAddr)
98+
}
99+
h.client.Transport = newTransport
100+
return h
101+
}
102+
74103
// Expect executes the request and returns an HTTP response.
75104
func (h *HTTPRequest) Expect() *HTTPResponse {
76105
if h.query != nil {
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package settings
18+
19+
import (
20+
"context"
21+
"crypto/tls"
22+
"fmt"
23+
"net/http"
24+
"strings"
25+
26+
"github.com/onsi/ginkgo/v2"
27+
"github.com/stretchr/testify/assert"
28+
appsv1 "k8s.io/api/apps/v1"
29+
corev1 "k8s.io/api/core/v1"
30+
31+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+
33+
"k8s.io/ingress-nginx/test/e2e/framework"
34+
)
35+
36+
var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
37+
f := framework.NewDefaultFramework("ssl-passthrough")
38+
39+
ginkgo.BeforeEach(func() {
40+
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
41+
args := deployment.Spec.Template.Spec.Containers[0].Args
42+
args = append(args, "--enable-ssl-passthrough")
43+
deployment.Spec.Template.Spec.Containers[0].Args = args
44+
_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
45+
return err
46+
})
47+
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
48+
49+
f.WaitForNginxServer("_",
50+
func(server string) bool {
51+
return strings.Contains(server, "listen 442")
52+
})
53+
})
54+
55+
ginkgo.Describe("With enable-ssl-passthrough enabled", func() {
56+
ginkgo.It("should enable ssl-passthrough-proxy-port on a different port", func() {
57+
58+
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
59+
args := deployment.Spec.Template.Spec.Containers[0].Args
60+
args = append(args, "--ssl-passthrough-proxy-port=1442")
61+
deployment.Spec.Template.Spec.Containers[0].Args = args
62+
_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
63+
return err
64+
})
65+
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
66+
67+
f.WaitForNginxServer("_",
68+
func(server string) bool {
69+
return strings.Contains(server, "listen 1442")
70+
})
71+
72+
f.HTTPTestClient().
73+
GET("/").
74+
WithHeader("Host", "something").
75+
Expect().
76+
Status(http.StatusNotFound)
77+
})
78+
79+
ginkgo.It("should pass unknown traffic to default backend and handle known traffic", func() {
80+
81+
host := "testpassthrough.com"
82+
echoName := "echopass"
83+
84+
/* Even with enable-ssl-passthrough enabled, only annotated ingresses may receive the trafic */
85+
annotations := map[string]string{
86+
"nginx.ingress.kubernetes.io/ssl-passthrough": "true",
87+
}
88+
89+
ingressDef := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, echoName, 80, annotations)
90+
tlsConfig, err := framework.CreateIngressTLSSecret(f.KubeClientSet,
91+
ingressDef.Spec.TLS[0].Hosts,
92+
ingressDef.Spec.TLS[0].SecretName,
93+
ingressDef.Namespace)
94+
95+
volumeMount := []corev1.VolumeMount{
96+
{
97+
Name: "certs",
98+
ReadOnly: true,
99+
MountPath: "/certs",
100+
},
101+
}
102+
volume := []corev1.Volume{
103+
{
104+
Name: "certs",
105+
VolumeSource: corev1.VolumeSource{
106+
Secret: &corev1.SecretVolumeSource{
107+
SecretName: ingressDef.Spec.TLS[0].SecretName,
108+
},
109+
},
110+
},
111+
}
112+
envs := []corev1.EnvVar{
113+
{
114+
Name: "HTTPBUN_SSL_CERT",
115+
Value: "/certs/tls.crt",
116+
},
117+
{
118+
Name: "HTTPBUN_SSL_KEY",
119+
Value: "/certs/tls.key",
120+
},
121+
}
122+
f.NewDeploymentWithOpts("echopass", "ghcr.io/sharat87/httpbun:latest", 80, 1, nil, nil, envs, volumeMount, volume, false)
123+
124+
f.EnsureIngress(ingressDef)
125+
126+
assert.Nil(ginkgo.GinkgoT(), err)
127+
framework.WaitForTLS(f.GetURL(framework.HTTPS), tlsConfig)
128+
129+
f.WaitForNginxServer(host,
130+
func(server string) bool {
131+
return strings.Contains(server, "listen 442")
132+
})
133+
134+
/* This one should not receive traffic as it does not contain passthrough annotation */
135+
hostBad := "noannotationnopassthrough.com"
136+
ingBad := f.EnsureIngress(framework.NewSingleIngressWithTLS(hostBad, "/", hostBad, []string{hostBad}, f.Namespace, echoName, 80, nil))
137+
tlsConfigBad, err := framework.CreateIngressTLSSecret(f.KubeClientSet,
138+
ingBad.Spec.TLS[0].Hosts,
139+
ingBad.Spec.TLS[0].SecretName,
140+
ingBad.Namespace)
141+
assert.Nil(ginkgo.GinkgoT(), err)
142+
framework.WaitForTLS(f.GetURL(framework.HTTPS), tlsConfigBad)
143+
144+
f.WaitForNginxServer(hostBad,
145+
func(server string) bool {
146+
return strings.Contains(server, "listen 442")
147+
})
148+
149+
f.HTTPTestClientWithTLSConfig(&tls.Config{ServerName: host, InsecureSkipVerify: true}).
150+
GET("/").
151+
WithURL(fmt.Sprintf("https://%s:443", host)).
152+
ForceResolve(f.GetNginxIP(), 443).
153+
Expect().
154+
Status(http.StatusOK)
155+
156+
f.HTTPTestClientWithTLSConfig(&tls.Config{ServerName: hostBad, InsecureSkipVerify: true}).
157+
GET("/").
158+
WithURL(fmt.Sprintf("https://%s:443", hostBad)).
159+
ForceResolve(f.GetNginxIP(), 443).
160+
Expect().
161+
Status(http.StatusNotFound)
162+
163+
})
164+
})
165+
})

0 commit comments

Comments
 (0)