@@ -27,10 +27,10 @@ import (
27
27
"github.com/stretchr/testify/assert"
28
28
appsv1 "k8s.io/api/apps/v1"
29
29
corev1 "k8s.io/api/core/v1"
30
-
31
30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
31
33
32
"k8s.io/ingress-nginx/test/e2e/framework"
33
+ "k8s.io/ingress-nginx/test/e2e/framework/httpexpect"
34
34
)
35
35
36
36
var _ = framework .IngressNginxDescribe ("[Flag] enable-ssl-passthrough" , func () {
@@ -75,114 +75,208 @@ var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
75
75
Status (http .StatusNotFound )
76
76
})
77
77
78
- ginkgo .It ("should pass unknown traffic to default backend and handle known traffic" , func () {
78
+ ginkgo .Context ("when handling traffic" , func () {
79
+ var tlsConfig * tls.Config
79
80
host := "testpassthrough.com"
80
81
echoName := "echopass"
82
+ secretName := host
83
+
84
+ ginkgo .BeforeEach (func () {
85
+ /* Even with enable-ssl-passthrough enabled, only annotated ingresses may receive the traffic */
86
+ annotations := map [string ]string {
87
+ "nginx.ingress.kubernetes.io/ssl-passthrough" : "true" ,
88
+ }
81
89
82
- /* Even with enable-ssl-passthrough enabled, only annotated ingresses may receive the traffic */
83
- annotations := map [string ]string {
84
- "nginx.ingress.kubernetes.io/ssl-passthrough" : "true" ,
85
- }
86
-
87
- ingressDef := framework .NewSingleIngressWithTLS (host ,
88
- "/" ,
89
- host ,
90
- []string {host },
91
- f .Namespace ,
92
- echoName ,
93
- 80 ,
94
- annotations )
95
- tlsConfig , err := framework .CreateIngressTLSSecret (f .KubeClientSet ,
96
- ingressDef .Spec .TLS [0 ].Hosts ,
97
- ingressDef .Spec .TLS [0 ].SecretName ,
98
- ingressDef .Namespace )
99
-
100
- volumeMount := []corev1.VolumeMount {
101
- {
102
- Name : "certs" ,
103
- ReadOnly : true ,
104
- MountPath : "/certs" ,
105
- },
106
- }
107
- volume := []corev1.Volume {
108
- {
109
- Name : "certs" ,
110
- VolumeSource : corev1.VolumeSource {
111
- Secret : & corev1.SecretVolumeSource {
112
- SecretName : ingressDef .Spec .TLS [0 ].SecretName ,
90
+ ingressDef := framework .NewSingleIngress (host ,
91
+ "/" ,
92
+ host ,
93
+ f .Namespace ,
94
+ echoName ,
95
+ 80 ,
96
+ annotations )
97
+ var err error
98
+ tlsConfig , err = framework .CreateIngressTLSSecret (f .KubeClientSet ,
99
+ []string {host },
100
+ secretName ,
101
+ ingressDef .Namespace )
102
+
103
+ volumeMount := []corev1.VolumeMount {
104
+ {
105
+ Name : "certs" ,
106
+ ReadOnly : true ,
107
+ MountPath : "/certs" ,
108
+ },
109
+ }
110
+ volume := []corev1.Volume {
111
+ {
112
+ Name : "certs" ,
113
+ VolumeSource : corev1.VolumeSource {
114
+ Secret : & corev1.SecretVolumeSource {
115
+ SecretName : secretName ,
116
+ },
113
117
},
114
118
},
115
- },
116
- }
117
- envs := []corev1.EnvVar {
118
- {
119
- Name : "HTTPBUN_SSL_CERT" ,
120
- Value : "/certs/tls.crt" ,
121
- },
122
- {
123
- Name : "HTTPBUN_SSL_KEY" ,
124
- Value : "/certs/tls.key" ,
125
- },
126
- }
127
-
128
- f .NewDeploymentWithOpts ("echopass" ,
129
- framework .HTTPBunImage ,
130
- 80 ,
131
- 1 ,
132
- nil ,
133
- nil ,
134
- envs ,
135
- volumeMount ,
136
- volume ,
137
- false )
138
-
139
- f .EnsureIngress (ingressDef )
140
-
141
- assert .Nil (ginkgo .GinkgoT (), err )
142
- framework .WaitForTLS (f .GetURL (framework .HTTPS ), tlsConfig )
143
-
144
- f .WaitForNginxServer (host ,
145
- func (server string ) bool {
146
- return strings .Contains (server , "listen 442" )
147
- })
119
+ }
120
+ envs := []corev1.EnvVar {
121
+ {
122
+ Name : "HTTPBUN_SSL_CERT" ,
123
+ Value : "/certs/tls.crt" ,
124
+ },
125
+ {
126
+ Name : "HTTPBUN_SSL_KEY" ,
127
+ Value : "/certs/tls.key" ,
128
+ },
129
+ }
148
130
149
- /* This one should not receive traffic as it does not contain passthrough annotation */
150
- hostBad := "noannotationnopassthrough.com"
151
- ingBad := f .EnsureIngress (framework .NewSingleIngressWithTLS (hostBad ,
152
- "/" ,
153
- hostBad ,
154
- []string {hostBad },
155
- f .Namespace ,
156
- echoName ,
157
- 80 ,
158
- nil ))
159
- tlsConfigBad , err := framework .CreateIngressTLSSecret (f .KubeClientSet ,
160
- ingBad .Spec .TLS [0 ].Hosts ,
161
- ingBad .Spec .TLS [0 ].SecretName ,
162
- ingBad .Namespace )
163
- assert .Nil (ginkgo .GinkgoT (), err )
164
- framework .WaitForTLS (f .GetURL (framework .HTTPS ), tlsConfigBad )
165
-
166
- f .WaitForNginxServer (hostBad ,
167
- func (server string ) bool {
168
- return strings .Contains (server , "listen 442" )
131
+ f .NewDeploymentWithOpts ("echopass" ,
132
+ framework .HTTPBunImage ,
133
+ 80 ,
134
+ 1 ,
135
+ nil ,
136
+ nil ,
137
+ envs ,
138
+ volumeMount ,
139
+ volume ,
140
+ false )
141
+
142
+ f .EnsureIngress (ingressDef )
143
+
144
+ assert .Nil (ginkgo .GinkgoT (), err )
145
+ framework .WaitForTLS (f .GetURL (framework .HTTPS ), tlsConfig )
146
+
147
+ f .WaitForNginxServer (host ,
148
+ func (server string ) bool {
149
+ return strings .Contains (server , "listen 442" )
150
+ })
151
+ })
152
+
153
+ ginkgo .It ("should pass unknown traffic to default backend and handle known traffic" , func () {
154
+ /* This one should not receive traffic as it does not contain passthrough annotation */
155
+ hostBad := "noannotationnopassthrough.com"
156
+ ingBad := f .EnsureIngress (framework .NewSingleIngressWithTLS (hostBad ,
157
+ "/" ,
158
+ hostBad ,
159
+ []string {hostBad },
160
+ f .Namespace ,
161
+ echoName ,
162
+ 80 ,
163
+ nil ))
164
+ tlsConfigBad , err := framework .CreateIngressTLSSecret (f .KubeClientSet ,
165
+ ingBad .Spec .TLS [0 ].Hosts ,
166
+ ingBad .Spec .TLS [0 ].SecretName ,
167
+ ingBad .Namespace )
168
+ assert .Nil (ginkgo .GinkgoT (), err )
169
+ framework .WaitForTLS (f .GetURL (framework .HTTPS ), tlsConfigBad )
170
+
171
+ f .WaitForNginxServer (hostBad ,
172
+ func (server string ) bool {
173
+ return strings .Contains (server , "listen 442" )
174
+ })
175
+
176
+ //nolint:gosec // Ignore the gosec error in testing
177
+ f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : host , InsecureSkipVerify : true }).
178
+ GET ("/" ).
179
+ WithURL ("https://" + net .JoinHostPort (host , "443" )).
180
+ ForceResolve (f .GetNginxIP (), 443 ).
181
+ Expect ().
182
+ Status (http .StatusOK )
183
+
184
+ //nolint:gosec // Ignore the gosec error in testing
185
+ f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : hostBad , InsecureSkipVerify : true }).
186
+ GET ("/" ).
187
+ WithURL ("https://" + net .JoinHostPort (hostBad , "443" )).
188
+ ForceResolve (f .GetNginxIP (), 443 ).
189
+ Expect ().
190
+ Status (http .StatusNotFound )
191
+
192
+ //nolint:gosec // Ignore the gosec error in testing
193
+ f .HTTPTestClientWithTLSConfig (tlsConfig ).
194
+ GET ("/" ).
195
+ WithURL ("https://" + net .JoinHostPort (host , "443" )).
196
+ ForceResolve (f .GetNginxIP (), 443 ).
197
+ Expect ().
198
+ Status (http .StatusOK )
199
+
200
+ //nolint:gosec // Ignore the gosec error in testing
201
+ f .HTTPTestClientWithTLSConfig (tlsConfigBad ).
202
+ GET ("/" ).
203
+ WithURL ("https://" + net .JoinHostPort (hostBad , "443" )).
204
+ ForceResolve (f .GetNginxIP (), 443 ).
205
+ Expect ().
206
+ Status (http .StatusNotFound )
207
+ })
208
+
209
+ ginkgo .Context ("on throttled connections" , func () {
210
+ throttleMiddleware := func (next httpexpect.DialContextFunc ) httpexpect.DialContextFunc {
211
+ return func (ctx context.Context , network , addr string ) (net.Conn , error ) {
212
+ // Wrap the connection with a throttled writer to simulate real
213
+ // world traffic where streaming data may arrive in chunks
214
+ conn , err := next (ctx , network , addr )
215
+ return & writeThrottledConn {
216
+ Conn : conn ,
217
+ chunkSize : 50 ,
218
+ }, err
219
+ }
220
+ }
221
+ tries := 3
222
+
223
+ ginkgo .It ("should handle known traffic without Host header" , func () {
224
+ for i := 0 ; i < tries ; i ++ {
225
+ //nolint:gosec // Ignore the gosec error in testing
226
+ f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : host , InsecureSkipVerify : true }).
227
+ GET ("/" ).
228
+ WithURL ("https://" + net .JoinHostPort (host , "443" )).
229
+ ForceResolve (f .GetNginxIP (), 443 ).
230
+ WithDialContextMiddleware (throttleMiddleware ).
231
+ Expect ().
232
+ Status (http .StatusOK )
233
+ }
169
234
})
170
235
171
- //nolint:gosec // Ignore the gosec error in testing
172
- f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : host , InsecureSkipVerify : true }).
173
- GET ("/" ).
174
- WithURL ("https://" + net .JoinHostPort (host , "443" )).
175
- ForceResolve (f .GetNginxIP (), 443 ).
176
- Expect ().
177
- Status (http .StatusOK )
236
+ ginkgo .It ("should handle known traffic with Host header" , func () {
237
+ for i := 0 ; i < tries ; i ++ {
238
+ //nolint:gosec // Ignore the gosec error in testing
239
+ f .HTTPTestClientWithTLSConfig (tlsConfig ).
240
+ GET ("/" ).
241
+ WithURL ("https://" + net .JoinHostPort (host , "443" )).
242
+ WithHeader ("Host" , host ).
243
+ ForceResolve (f .GetNginxIP (), 443 ).
244
+ WithDialContextMiddleware (throttleMiddleware ).
245
+ Expect ().
246
+ Status (http .StatusOK )
247
+ }
248
+ })
178
249
179
- //nolint:gosec // Ignore the gosec error in testing
180
- f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : hostBad , InsecureSkipVerify : true }).
181
- GET ("/" ).
182
- WithURL ("https://" + net .JoinHostPort (hostBad , "443" )).
183
- ForceResolve (f .GetNginxIP (), 443 ).
184
- Expect ().
185
- Status (http .StatusNotFound )
250
+ ginkgo .It ("should handle insecure traffic with Host header" , func () {
251
+ for i := 0 ; i < tries ; i ++ {
252
+ //nolint:gosec // Ignore the gosec error in testing
253
+ f .HTTPTestClientWithTLSConfig (& tls.Config {ServerName : host , InsecureSkipVerify : true }).
254
+ GET ("/" ).
255
+ WithURL ("https://" + net .JoinHostPort (host , "443" )).
256
+ WithHeader ("Host" , host ).
257
+ ForceResolve (f .GetNginxIP (), 443 ).
258
+ WithDialContextMiddleware (throttleMiddleware ).
259
+ Expect ().
260
+ Status (http .StatusOK )
261
+ }
262
+ })
263
+ })
186
264
})
187
265
})
188
266
})
267
+
268
+ type writeThrottledConn struct {
269
+ net.Conn
270
+ chunkSize int
271
+ }
272
+
273
+ // Write writes data to the connection `chunkSize` bytes (or less) at a time.
274
+ func (c * writeThrottledConn ) Write (b []byte ) (n int , err error ) {
275
+ for i := 0 ; i < len (b ); i += c .chunkSize {
276
+ n , err := c .Conn .Write (b [i :min (i + c .chunkSize , len (b ))])
277
+ if err != nil {
278
+ return i + n , err
279
+ }
280
+ }
281
+ return len (b ), nil
282
+ }
0 commit comments