Add support for Server Alias in Nginx
Adds support for server alias in nginx. Adds a new annotation which allows us to specify a server alias that will be appended to the server name.
This commit is contained in:
parent
198c926bb9
commit
ac504bdbc0
8 changed files with 146 additions and 4 deletions
|
@ -64,7 +64,7 @@ The following annotations are supported:
|
||||||
|[ingress.kubernetes.io/upstream-max-fails](#custom-nginx-upstream-checks)|number|
|
|[ingress.kubernetes.io/upstream-max-fails](#custom-nginx-upstream-checks)|number|
|
||||||
|[ingress.kubernetes.io/upstream-fail-timeout](#custom-nginx-upstream-checks)|number|
|
|[ingress.kubernetes.io/upstream-fail-timeout](#custom-nginx-upstream-checks)|number|
|
||||||
|[ingress.kubernetes.io/whitelist-source-range](#whitelist-source-range)|CIDR|
|
|[ingress.kubernetes.io/whitelist-source-range](#whitelist-source-range)|CIDR|
|
||||||
|
|[ingress.kubernetes.io/server-alias](#server-alias)|string|
|
||||||
|
|
||||||
|
|
||||||
#### Custom NGINX template
|
#### Custom NGINX template
|
||||||
|
@ -155,7 +155,7 @@ Please check the [tls-auth](/examples/auth/client-certs/nginx/README.md) example
|
||||||
|
|
||||||
### Configuration snippet
|
### Configuration snippet
|
||||||
|
|
||||||
Using this annotion you can add additional configuration to the NGINX location. For example:
|
Using this annotation you can add additional configuration to the NGINX location. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
ingress.kubernetes.io/configuration-snippet: |
|
ingress.kubernetes.io/configuration-snippet: |
|
||||||
|
@ -167,6 +167,17 @@ ingress.kubernetes.io/configuration-snippet: |
|
||||||
To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation `ingress.kubernetes.io/enable-cors: "true"`. This will add a section in the server location enabling this functionality.
|
To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation `ingress.kubernetes.io/enable-cors: "true"`. This will add a section in the server location enabling this functionality.
|
||||||
For more information please check https://enable-cors.org/server_nginx.html
|
For more information please check https://enable-cors.org/server_nginx.html
|
||||||
|
|
||||||
|
### Server Alias
|
||||||
|
|
||||||
|
To add Server Aliases to an Ingress rule add the annotation `ingress.kubernetes.io/server-alias: "<server-name_0>:<server-alias_0>;...;<server-name_n>:<server-alias_n>"`.
|
||||||
|
This will append a server-alias to the end of the server_name in the NGINX server. A server-alias can accept wildcards, but
|
||||||
|
it cannot accept port numbers.
|
||||||
|
|
||||||
|
The server-name must match a valid server within the ingress resource for it to append the server-alias. Multiple server-aliases
|
||||||
|
can be added for multiple server-names using `;` as a delimiter.
|
||||||
|
|
||||||
|
For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
|
||||||
|
|
||||||
### External Authentication
|
### External Authentication
|
||||||
|
|
||||||
To use an existing service that provides authentication the Ingress rule can be annotated with `ingress.kubernetes.io/auth-url` to indicate the URL where the HTTP request should be sent.
|
To use an existing service that provides authentication the Ingress rule can be annotated with `ingress.kubernetes.io/auth-url` to indicate the URL where the HTTP request should be sent.
|
||||||
|
|
|
@ -452,6 +452,7 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
|
||||||
IP: svc.Spec.ClusterIP,
|
IP: svc.Spec.ClusterIP,
|
||||||
Port: port,
|
Port: port,
|
||||||
ProxyProtocol: false,
|
ProxyProtocol: false,
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ http {
|
||||||
{{ $backlogSize := .BacklogSize }}
|
{{ $backlogSize := .BacklogSize }}
|
||||||
{{ range $index, $server := .Servers }}
|
{{ range $index, $server := .Servers }}
|
||||||
server {
|
server {
|
||||||
server_name {{ $server.Hostname }};
|
server_name {{ $server.Hostname }} {{ $server.Alias }};
|
||||||
listen 80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}};
|
listen 80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}};
|
||||||
{{ if $IsIPV6Enabled }}listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{ end }};{{ end }}
|
{{ if $IsIPV6Enabled }}listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{ end }};{{ end }}
|
||||||
set $proxy_upstream_name "-";
|
set $proxy_upstream_name "-";
|
||||||
|
|
42
core/pkg/ingress/annotations/alias/main.go
Normal file
42
core/pkg/ingress/annotations/alias/main.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
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 alias
|
||||||
|
|
||||||
|
import (
|
||||||
|
extensions "k8s.io/api/extensions/v1beta1"
|
||||||
|
|
||||||
|
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
annotation = "ingress.kubernetes.io/server-alias"
|
||||||
|
)
|
||||||
|
|
||||||
|
type alias struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewParser creates a new CORS annotation parser
|
||||||
|
func NewParser() parser.IngressAnnotation {
|
||||||
|
return alias{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the annotations contained in the ingress rule
|
||||||
|
// used to indicate if the location/s contains a fragment of
|
||||||
|
// configuration to be included inside the paths of the rules
|
||||||
|
func (a alias) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||||
|
return parser.GetStringAnnotation(annotation, ing)
|
||||||
|
}
|
60
core/pkg/ingress/annotations/alias/main_test.go
Normal file
60
core/pkg/ingress/annotations/alias/main_test.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
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 alias
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
api "k8s.io/api/core/v1"
|
||||||
|
extensions "k8s.io/api/extensions/v1beta1"
|
||||||
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
ap := NewParser()
|
||||||
|
if ap == nil {
|
||||||
|
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
annotations map[string]string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{map[string]string{annotation: "www.example.com"}, "www.example.com"},
|
||||||
|
{map[string]string{annotation: "*.example.com www.example.*"}, "*.example.com www.example.*"},
|
||||||
|
{map[string]string{annotation: `~^www\d+\.example\.com$`}, `~^www\d+\.example\.com$`},
|
||||||
|
{map[string]string{annotation: ""}, ""},
|
||||||
|
{map[string]string{}, ""},
|
||||||
|
{nil, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
ing := &extensions.Ingress{
|
||||||
|
ObjectMeta: meta_v1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: extensions.IngressSpec{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ing.SetAnnotations(testCase.annotations)
|
||||||
|
result, _ := ap.Parse(ing)
|
||||||
|
if result != testCase.expected {
|
||||||
|
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"k8s.io/ingress/core/pkg/ingress/annotations/sslpassthrough"
|
"k8s.io/ingress/core/pkg/ingress/annotations/sslpassthrough"
|
||||||
"k8s.io/ingress/core/pkg/ingress/errors"
|
"k8s.io/ingress/core/pkg/ingress/errors"
|
||||||
"k8s.io/ingress/core/pkg/ingress/resolver"
|
"k8s.io/ingress/core/pkg/ingress/resolver"
|
||||||
|
"k8s.io/ingress/core/pkg/ingress/annotations/alias"
|
||||||
)
|
)
|
||||||
|
|
||||||
type extractorConfig interface {
|
type extractorConfig interface {
|
||||||
|
@ -69,6 +70,7 @@ func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
||||||
"SessionAffinity": sessionaffinity.NewParser(),
|
"SessionAffinity": sessionaffinity.NewParser(),
|
||||||
"SSLPassthrough": sslpassthrough.NewParser(),
|
"SSLPassthrough": sslpassthrough.NewParser(),
|
||||||
"ConfigurationSnippet": snippet.NewParser(),
|
"ConfigurationSnippet": snippet.NewParser(),
|
||||||
|
"Alias": alias.NewParser(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +109,7 @@ const (
|
||||||
sslPassthrough = "SSLPassthrough"
|
sslPassthrough = "SSLPassthrough"
|
||||||
sessionAffinity = "SessionAffinity"
|
sessionAffinity = "SessionAffinity"
|
||||||
serviceUpstream = "ServiceUpstream"
|
serviceUpstream = "ServiceUpstream"
|
||||||
|
serverAlias = "Alias"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *annotationExtractor) ServiceUpstream(ing *extensions.Ingress) bool {
|
func (e *annotationExtractor) ServiceUpstream(ing *extensions.Ingress) bool {
|
||||||
|
@ -133,6 +136,11 @@ func (e *annotationExtractor) SSLPassthrough(ing *extensions.Ingress) bool {
|
||||||
return val.(bool)
|
return val.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *annotationExtractor) Alias(ing *extensions.Ingress) string {
|
||||||
|
val, _ := e.annotations[serverAlias].Parse(ing)
|
||||||
|
return val.(string)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessionaffinity.AffinityConfig {
|
func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessionaffinity.AffinityConfig {
|
||||||
val, _ := e.annotations[sessionAffinity].Parse(ing)
|
val, _ := e.annotations[sessionAffinity].Parse(ing)
|
||||||
return val.(*sessionaffinity.AffinityConfig)
|
return val.(*sessionaffinity.AffinityConfig)
|
||||||
|
|
|
@ -1055,19 +1055,37 @@ func (ic *GenericController) createServers(data []interface{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure default location and SSL
|
// configure default location, alias, and SSL
|
||||||
for _, ingIf := range data {
|
for _, ingIf := range data {
|
||||||
ing := ingIf.(*extensions.Ingress)
|
ing := ingIf.(*extensions.Ingress)
|
||||||
if !class.IsValid(ing, ic.cfg.IngressClass, ic.cfg.DefaultIngressClass) {
|
if !class.IsValid(ing, ic.cfg.IngressClass, ic.cfg.DefaultIngressClass) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup server-aliases based on annotations
|
||||||
|
aliasMap := map[string]string{}
|
||||||
|
aliasAnnotation := ic.annotations.Alias(ing)
|
||||||
|
|
||||||
|
// Here we parse the annotation string in the following format:
|
||||||
|
// ingress.kubernetes.io/server-alias: "host_0:alias_0;...;host_n:alias_n"
|
||||||
|
aliases := strings.Split(aliasAnnotation, ";")
|
||||||
|
for _, alias := range aliases {
|
||||||
|
aliasParts := strings.Split(alias, ":")
|
||||||
|
if len(aliasParts) == 2 {
|
||||||
|
// aliasMap[host] = alias
|
||||||
|
aliasMap[aliasParts[0]] = aliasParts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
host := rule.Host
|
host := rule.Host
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = defServerName
|
host = defServerName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup server aliases
|
||||||
|
servers[host].Alias = aliasMap[host]
|
||||||
|
|
||||||
// only add a certificate if the server does not have one previously configured
|
// only add a certificate if the server does not have one previously configured
|
||||||
if len(ing.Spec.TLS) == 0 || servers[host].SSLCertificate != "" {
|
if len(ing.Spec.TLS) == 0 || servers[host].SSLCertificate != "" {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -220,6 +220,8 @@ type Server struct {
|
||||||
SSLPemChecksum string `json:"sslPemChecksum"`
|
SSLPemChecksum string `json:"sslPemChecksum"`
|
||||||
// Locations list of URIs configured in the server.
|
// Locations list of URIs configured in the server.
|
||||||
Locations []*Location `json:"locations,omitempty"`
|
Locations []*Location `json:"locations,omitempty"`
|
||||||
|
// return the alias of the server name
|
||||||
|
Alias string `json:"alias,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location describes an URI inside a server.
|
// Location describes an URI inside a server.
|
||||||
|
|
Loading…
Reference in a new issue