Skip to content

Add connection-proxy-header annotation #1999

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

Merged
merged 1 commit into from
Jan 30, 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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/ingress/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/clientbodybuffersize"
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend"
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
Expand Down Expand Up @@ -63,6 +64,7 @@ type Ingress struct {
CertificateAuth authtls.Config
ClientBodyBufferSize string
ConfigurationSnippet string
Connection connection.Config
CorsConfig cors.Config
DefaultBackend string
Denied error
Expand Down Expand Up @@ -99,6 +101,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"CertificateAuth": authtls.NewParser(cfg),
"ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg),
"ConfigurationSnippet": snippet.NewParser(cfg),
"Connection": connection.NewParser(cfg),
"CorsConfig": cors.NewParser(cfg),
"DefaultBackend": defaultbackend.NewParser(cfg),
"ExternalAuth": authreq.NewParser(cfg),
Expand Down
72 changes: 72 additions & 0 deletions internal/ingress/annotations/connection/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package connection

import (
extensions "k8s.io/api/extensions/v1beta1"

"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

// Config returns the connection header configuration for an Ingress rule
type Config struct {
Header string `json:"header"`
Enabled bool `json:"enabled"`
}

type connection struct {
r resolver.Resolver
}

// NewParser creates a new port in redirect annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return connection{r}
}

// Parse parses the annotations contained in the ingress
// rule used to indicate if the connection header should be overridden.
func (a connection) Parse(ing *extensions.Ingress) (interface{}, error) {
cp, err := parser.GetStringAnnotation("connection-proxy-header", ing)
if err != nil {
return &Config{
Enabled: false,
}, err
}
return &Config{
Enabled: true,
Header: cp,
}, nil
}

// Equal tests for equality between two Connection types
func (r1 *Config) Equal(r2 *Config) bool {
if r1 == r2 {
return true
}
if r1 == nil || r2 == nil {
return false
}
if r1.Enabled != r2.Enabled {
return false
}
if r1.Header != r2.Header {
return false
}

return true
}
64 changes: 64 additions & 0 deletions internal/ingress/annotations/connection/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package connection

import (
"testing"

api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

func TestParse(t *testing.T) {
annotation := parser.GetAnnotationWithPrefix("connection-proxy-header")

ap := NewParser(&resolver.Mock{})
if ap == nil {
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
}

testCases := []struct {
annotations map[string]string
expected *Config
}{
{map[string]string{annotation: ""}, &Config{Enabled: true, Header: ""}},
{map[string]string{annotation: "keep-alive"}, &Config{Enabled: true, Header: "keep-alive"}},
{map[string]string{}, &Config{Enabled: false}},
{nil, &Config{Enabled: false}},
}

ing := &extensions.Ingress{
ObjectMeta: meta_v1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: extensions.IngressSpec{},
}

for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations)
i, _ := ap.Parse(ing)
p, _ := i.(*Config)

if !p.Equal(testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, p, testCase.annotations)
}
}
}
2 changes: 2 additions & 0 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
loc.Denied = anns.Denied
loc.XForwardedPrefix = anns.XForwardedPrefix
loc.UsePortInRedirects = anns.UsePortInRedirects
loc.Connection = anns.Connection

if loc.Redirect.FromToWWW {
server.RedirectFromToWWW = true
Expand Down Expand Up @@ -458,6 +459,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
Denied: anns.Denied,
XForwardedPrefix: anns.XForwardedPrefix,
UsePortInRedirects: anns.UsePortInRedirects,
Connection: anns.Connection,
}

if loc.Redirect.FromToWWW {
Expand Down
5 changes: 5 additions & 0 deletions internal/ingress/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/auth"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
Expand Down Expand Up @@ -240,6 +241,10 @@ type Location struct {
// ConfigurationSnippet contains additional configuration for the backend
// to be considered in the configuration of the location
ConfigurationSnippet string `json:"configurationSnippet"`
// Connection contains connection header to orverride the default Connection header
// to the request.
// +optional
Connection connection.Config `json:"connection"`
// ClientBodyBufferSize allows for the configuration of the client body
// buffer size for a specific location.
// +optional
Expand Down
3 changes: 3 additions & 0 deletions internal/ingress/types_equals.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ func (l1 *Location) Equal(l2 *Location) bool {
if l1.XForwardedPrefix != l2.XForwardedPrefix {
return false
}
if !(&l1.Connection).Equal(&l2.Connection) {
return false
}

return true
}
Expand Down
14 changes: 9 additions & 5 deletions rootfs/etc/nginx/template/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ http {

include /etc/nginx/mime.types;
default_type text/html;

{{ if $cfg.EnableBrotli }}
brotli on;
brotli_comp_level {{ $cfg.BrotliLevel }};
Expand Down Expand Up @@ -242,7 +242,7 @@ http {
port_in_redirect off;

rewrite_log on;

ssl_protocols {{ $cfg.SSLProtocols }};

# turn on session caching to drastically improve performance
Expand Down Expand Up @@ -294,7 +294,7 @@ http {

{{ range $header := $cfg.HideHeaders }}proxy_hide_header {{ $header }};
{{ end }}

{{ if not (empty $cfg.HTTPSnippet) }}
# Custom code snippet configured in the configuration configmap
{{ $cfg.HTTPSnippet }}
Expand Down Expand Up @@ -700,10 +700,10 @@ stream {
{{/* redirect to HTTPS can be achieved forcing the redirect or having a SSL Certificate configured for the server */}}
{{ if (or $location.Rewrite.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Rewrite.SSLRedirect)) }}
# enforce ssl on server side
if ($redirect_to_https) {
if ($redirect_to_https) {
{{ if $location.UsePortInRedirects }}
# using custom ports require a different rewrite directive
{{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }}
{{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }}
error_page 497 ={{ $all.Cfg.HTTPRedirectCode }} https://$host{{ $redirect_port }}$request_uri;

return 497;
Expand Down Expand Up @@ -798,7 +798,11 @@ stream {

# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
{{ if $location.Connection.Enabled}}
proxy_set_header Connection {{ $location.Connection.Header }};
{{ else }}
proxy_set_header Connection $connection_upgrade;
{{ end }}

proxy_set_header X-Real-IP $the_real_ip;
{{ if $all.Cfg.ComputeFullForwardedFor }}
Expand Down