diff --git a/controllers/nginx/configuration.md b/controllers/nginx/configuration.md index e8ffd81fff..f27bde70ae 100644 --- a/controllers/nginx/configuration.md +++ b/controllers/nginx/configuration.md @@ -40,6 +40,7 @@ The following annotations are supported: |Name |type| |---------------------------|------| |[ingress.kubernetes.io/add-base-url](#rewrite)|true or false| +|[ingress.kubernetes.io/app-root](#rewrite)|string| |[ingress.kubernetes.io/affinity](#session-affinity)|true or false| |[ingress.kubernetes.io/auth-realm](#authentication)|string| |[ingress.kubernetes.io/auth-secret](#authentication)|string| @@ -174,7 +175,9 @@ Set the annotation `ingress.kubernetes.io/rewrite-target` to the path expected b If the application contains relative links it is possible to add an additional annotation `ingress.kubernetes.io/add-base-url` that will prepend a [`base` tag](https://developer.mozilla.org/en/docs/Web/HTML/Element/base) in the header of the returned HTML from the backend. -Please check the [rewrite](examples/rewrite/README.md) example. +If the Application Root is exposed in a different path and needs to be redirected, the annotation `ingress.kubernetes.io/app-root` might be used. + +Please check the [rewrite](/examples/rewrite/README.md) example. ### Rate limiting diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index 73472122f2..efe2964226 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -236,7 +236,19 @@ http { ssl_verify_client on; ssl_verify_depth {{ $location.CertificateAuth.ValidationDepth }}; {{ end }} + + {{ if (or $location.Redirect.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Redirect.SSLRedirect)) }} + # enforce ssl on server side + if ($pass_access_scheme = http) { + return 301 https://$host$request_uri; + } + {{ end }} + {{ if not (empty $location.Redirect.AppRoot)}} + if ($uri = /) { + return 302 {{ $location.Redirect.AppRoot }}; + } + {{ end }} {{ if not (empty $authPath) }} location = {{ $authPath }} { internal; @@ -279,12 +291,7 @@ http { error_page 401 = {{ $location.ExternalAuth.SigninURL }}; {{ end }} - {{ if (or $location.Redirect.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Redirect.SSLRedirect)) }} - # enforce ssl on server side - if ($pass_access_scheme = http) { - return 301 https://$host$request_uri; - } - {{ end }} + {{/* if the location contains a rate limit annotation, create one */}} {{ $limits := buildRateLimit $location }} {{ range $limit := $limits }} diff --git a/core/pkg/ingress/annotations/rewrite/main.go b/core/pkg/ingress/annotations/rewrite/main.go index 999ef78447..e522a275a9 100644 --- a/core/pkg/ingress/annotations/rewrite/main.go +++ b/core/pkg/ingress/annotations/rewrite/main.go @@ -28,6 +28,7 @@ const ( addBaseURL = "ingress.kubernetes.io/add-base-url" sslRedirect = "ingress.kubernetes.io/ssl-redirect" forceSSLRedirect = "ingress.kubernetes.io/force-ssl-redirect" + appRoot = "ingress.kubernetes.io/app-root" ) // Redirect describes the per location redirect config @@ -41,6 +42,8 @@ type Redirect struct { SSLRedirect bool `json:"sslRedirect"` // ForceSSLRedirect indicates if the location section is accessible SSL only ForceSSLRedirect bool `json:"forceSSLRedirect"` + // AppRoot defines the Application Root that the Controller must redirect if it's not in '/' context + AppRoot string `json:"appRoot"` } type rewrite struct { @@ -65,10 +68,12 @@ func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) { fSslRe = a.backendResolver.GetDefaultBackend().ForceSSLRedirect } abu, _ := parser.GetBoolAnnotation(addBaseURL, ing) + ar, _ := parser.GetStringAnnotation(appRoot, ing) return &Redirect{ Target: rt, AddBaseURL: abu, SSLRedirect: sslRe, ForceSSLRedirect: fSslRe, + AppRoot: ar, }, nil } diff --git a/core/pkg/ingress/annotations/rewrite/main_test.go b/core/pkg/ingress/annotations/rewrite/main_test.go index 75daf01bcd..2a32521848 100644 --- a/core/pkg/ingress/annotations/rewrite/main_test.go +++ b/core/pkg/ingress/annotations/rewrite/main_test.go @@ -158,3 +158,20 @@ func TestForceSSLRedirect(t *testing.T) { t.Errorf("Expected true but returned false") } } +func TestAppRoot(t *testing.T) { + ing := buildIngress() + + data := map[string]string{} + data[appRoot] = "/app1" + ing.SetAnnotations(data) + + i, _ := NewParser(mockBackend{true}).Parse(ing) + redirect, ok := i.(*Redirect) + if !ok { + t.Errorf("expected a App Context") + } + if redirect.AppRoot != "/app1" { + t.Errorf("Unexpected value got in AppRoot") + } + +} diff --git a/core/pkg/ingress/defaults/main.go b/core/pkg/ingress/defaults/main.go index d8420da046..92f5a72a29 100644 --- a/core/pkg/ingress/defaults/main.go +++ b/core/pkg/ingress/defaults/main.go @@ -6,6 +6,8 @@ import "net" // The reason of this requirements is the annotations are generic. If some implementation do not supports // one or more annotations it just can provides defaults type Backend struct { + // AppRoot contains the AppRoot for apps that doesn't exposes its content in the 'root' context + AppRoot string `json:"app-root"` // enables which HTTP codes should be passed for processing with the error_page directive // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors diff --git a/examples/rewrite/README.md b/examples/rewrite/README.md deleted file mode 100644 index a878d52ea7..0000000000 --- a/examples/rewrite/README.md +++ /dev/null @@ -1,66 +0,0 @@ -Create an Ingress rule with a rewrite annotation: -``` -$ echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/rewrite-target: / - name: rewrite - namespace: default -spec: - rules: - - host: rewrite.bar.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: /something -" | kubectl create -f - -``` - -Check the rewrite is working - -``` -$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET /something HTTP/1.1 -> Host: rewrite.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.11.0 -< Date: Tue, 31 May 2016 16:07:31 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< -CLIENT VALUES: -client_address=10.2.56.9 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://rewrite.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=rewrite.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.56.1 -x-forwarded-host=rewrite.bar.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.56.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact --no body in request- -``` - diff --git a/examples/rewrite/nginx/README.md b/examples/rewrite/nginx/README.md new file mode 100644 index 0000000000..f934eb6169 --- /dev/null +++ b/examples/rewrite/nginx/README.md @@ -0,0 +1,127 @@ +# Rewrite + +This example demonstrates how to use the Rewrite annotations + +## Prerequisites + +You will need to make sure you Ingress targets exactly one Ingress +controller by specifying the [ingress.class annotation](/examples/PREREQUISITES.md#ingress-class), +and that you have an ingress controller [running](/examples/deployment) in your cluster. + +## Deployment + +Rewriting can be controlled using the following annotations: + +|Name|Description|Values| +| --- | --- | --- | +|ingress.kubernetes.io/rewrite-target|Target URI where the traffic must be redirected|string| +|ingress.kubernetes.io/add-base-url|indicates if is required to add a base tag in the head of the responses from the upstream servers|bool| +|ingress.kubernetes.io/ssl-redirect|Indicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)|bool| +|ingress.kubernetes.io/force-ssl-redirect|Forces the redirection to HTTPS even if the Ingress is not TLS Enabled|bool| +|ingress.kubernetes.io/app-root|Defines the Application Root that the Controller must redirect if it's not in '/' context|string| + +## Validation + +### Rewrite Target +Create an Ingress rule with a rewrite annotation: +``` +$ echo " +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/rewrite-target: / + name: rewrite + namespace: default +spec: + rules: + - host: rewrite.bar.com + http: + paths: + - backend: + serviceName: echoheaders + servicePort: 80 + path: /something +" | kubectl create -f - +``` + +Check the rewrite is working + +``` +$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' +* Trying 172.17.4.99... +* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) +> GET /something HTTP/1.1 +> Host: rewrite.bar.com +> User-Agent: curl/7.43.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.11.0 +< Date: Tue, 31 May 2016 16:07:31 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Connection: keep-alive +< +CLIENT VALUES: +client_address=10.2.56.9 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://rewrite.bar.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.9.11 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=rewrite.bar.com +user-agent=curl/7.43.0 +x-forwarded-for=10.2.56.1 +x-forwarded-host=rewrite.bar.com +x-forwarded-port=80 +x-forwarded-proto=http +x-real-ip=10.2.56.1 +BODY: +* Connection #0 to host 172.17.4.99 left intact +-no body in request- +``` + +### App Root + +Create an Ingress rule with a app-root annotation: +``` +$ echo " +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/app-root: /app1 + name: approot + namespace: default +spec: + rules: + - host: approot.bar.com + http: + paths: + - backend: + serviceName: echoheaders + servicePort: 80 + path: / +" | kubectl create -f - +``` + +Check the rewrite is working + +``` +$ curl -I -k http://approot.bar.com/ +HTTP/1.1 302 Moved Temporarily +Server: nginx/1.11.10 +Date: Mon, 13 Mar 2017 14:57:15 GMT +Content-Type: text/html +Content-Length: 162 +Location: http://stickyingress.example.com/app1 +Connection: keep-alive +```