Update Server Alias Annotation with Review Changes

Updates the Server-Alias annotation to create another server
containing the same configuration as the current server, but
with the name provided in the annotation.
This commit is contained in:
Fernando Diaz 2017-08-15 01:23:19 -05:00
parent ac504bdbc0
commit 62fea9aa01
4 changed files with 220 additions and 219 deletions

View file

@ -169,12 +169,8 @@ For more information please check https://enable-cors.org/server_nginx.html
### Server Alias ### 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>"`. To add Server Aliases to an Ingress rule add the annotation `ingress.kubernetes.io/server-alias: "<alias>"`.
This will append a server-alias to the end of the server_name in the NGINX server. A server-alias can accept wildcards, but This will create a server with the same configuration, but a different server_name as the provided host.
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 For more information please see http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name

View file

@ -147,6 +147,9 @@ var (
"toLower": strings.ToLower, "toLower": strings.ToLower,
"formatIP": formatIP, "formatIP": formatIP,
"buildNextUpstream": buildNextUpstream, "buildNextUpstream": buildNextUpstream,
"serverConfig": func(all config.TemplateConfig, server *ingress.Server) interface{} {
return struct { First, Second interface{} } { all, server }
},
} }
) )

View file

@ -295,207 +295,17 @@ http {
{{ $backlogSize := .BacklogSize }} {{ $backlogSize := .BacklogSize }}
{{ range $index, $server := .Servers }} {{ range $index, $server := .Servers }}
server { server {
server_name {{ $server.Hostname }} {{ $server.Alias }}; server_name {{ $server.Hostname }};
listen 80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}}; {{ template "SERVER" serverConfig $all $server }}
{{ 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 "-";
{{/* Listen on 442 because port 443 is used in the TLS sni server */}}
{{/* This listener must always have proxy_protocol enabled, because the SNI listener forwards on source IP info in it. */}}
{{ if not (empty $server.SSLCertificate) }}listen 442 proxy_protocol{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};
{{ if $IsIPV6Enabled }}{{ if not (empty $server.SSLCertificate) }}listen [::]:442 proxy_protocol{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};{{ end }}
{{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}}
# PEM sha: {{ $server.SSLPemChecksum }}
ssl_certificate {{ $server.SSLCertificate }};
ssl_certificate_key {{ $server.SSLCertificate }};
{{ end }}
{{ if (and (not (empty $server.SSLCertificate)) $cfg.HSTS) }}
more_set_headers "Strict-Transport-Security: max-age={{ $cfg.HSTSMaxAge }}{{ if $cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }};{{ if $cfg.HSTSPreload }} preload{{ end }}";
{{ end }}
{{ if $cfg.EnableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }}
{{ range $location := $server.Locations }}
{{ $path := buildLocation $location }}
{{ $authPath := buildAuthLocation $location }}
{{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }}
# PEM sha: {{ $location.CertificateAuth.AuthSSLCert.PemSHA }}
ssl_client_certificate {{ $location.CertificateAuth.AuthSSLCert.CAFileName }};
ssl_verify_client on;
ssl_verify_depth {{ $location.CertificateAuth.ValidationDepth }};
{{ end }}
{{ if not (empty $location.Redirect.AppRoot)}}
if ($uri = /) {
return 302 {{ $location.Redirect.AppRoot }};
}
{{ end }}
{{ if not (empty $authPath) }}
location = {{ $authPath }} {
internal;
set $proxy_upstream_name "internal";
{{ if not $location.ExternalAuth.SendBody }}
proxy_pass_request_body off;
proxy_set_header Content-Length "";
{{ end }}
{{ if not (empty $location.ExternalAuth.Method) }}
proxy_method {{ $location.ExternalAuth.Method }};
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
{{ end }}
proxy_pass_request_headers on;
proxy_set_header Host {{ $location.ExternalAuth.Host }};
proxy_ssl_server_name on;
client_max_body_size "{{ $location.Proxy.BodySize }}";
set $target {{ $location.ExternalAuth.URL }};
proxy_pass $target;
}
{{ end }}
location {{ $path }} {
set $proxy_upstream_name "{{ buildUpstreamName $server.Hostname $backends $location }}";
{{ 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://$best_http_host$request_uri;
}
{{ end }}
{{ if isLocationAllowed $location }}
{{ if gt (len $location.Whitelist.CIDR) 0 }}
if ({{ buildDenyVariable (print $server.Hostname "_" $path) }}) {
return 403;
}
{{ end }}
port_in_redirect {{ if $location.UsePortInRedirects }}on{{ else }}off{{ end }};
{{ if not (empty $authPath) }}
# this location requires authentication
auth_request {{ $authPath }};
{{- range $idx, $line := buildAuthResponseHeaders $location }}
{{ $line }}
{{- end }}
{{ end }}
{{ if not (empty $location.ExternalAuth.SigninURL) }}
error_page 401 = {{ $location.ExternalAuth.SigninURL }};
{{ end }}
{{/* if the location contains a rate limit annotation, create one */}}
{{ $limits := buildRateLimit $location }}
{{ range $limit := $limits }}
{{ $limit }}{{ end }}
{{ if $location.BasicDigestAuth.Secured }}
{{ if eq $location.BasicDigestAuth.Type "basic" }}
auth_basic "{{ $location.BasicDigestAuth.Realm }}";
auth_basic_user_file {{ $location.BasicDigestAuth.File }};
{{ else }}
auth_digest "{{ $location.BasicDigestAuth.Realm }}";
auth_digest_user_file {{ $location.BasicDigestAuth.File }};
{{ end }}
proxy_set_header Authorization "";
{{ end }}
{{ if $location.EnableCORS }}
{{ template "CORS" }}
{{ end }}
client_max_body_size "{{ $location.Proxy.BodySize }}";
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
{{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }}
proxy_set_header ssl-client-cert $ssl_client_cert;
{{ end }}
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $the_real_ip;
proxy_set_header X-Forwarded-For $the_real_ip;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
{{ range $k, $v := $proxyHeaders }}
proxy_set_header {{ $k }} "{{ $v }}";
{{ end }}
proxy_connect_timeout {{ $location.Proxy.ConnectTimeout }}s;
proxy_send_timeout {{ $location.Proxy.SendTimeout }}s;
proxy_read_timeout {{ $location.Proxy.ReadTimeout }}s;
proxy_redirect off;
proxy_buffering off;
proxy_buffer_size "{{ $location.Proxy.BufferSize }}";
proxy_buffers 4 "{{ $location.Proxy.BufferSize }}";
proxy_http_version 1.1;
proxy_cookie_domain {{ $location.Proxy.CookieDomain }};
proxy_cookie_path {{ $location.Proxy.CookiePath }};
# In case of errors try the next upstream server before returning an error
proxy_next_upstream {{ buildNextUpstream $location.Proxy.NextUpstream }}{{ if $cfg.RetryNonIdempotent }} non_idempotent{{ end }};
{{/* rewrite only works if the content is not compressed */}}
{{ if $location.Redirect.AddBaseURL }}
proxy_set_header Accept-Encoding "";
{{ end }}
{{/* Add any additional configuration defined */}}
{{ $location.ConfigurationSnippet }}
{{ buildProxyPass $server.Hostname $backends $location }}
{{ else }}
#{{ $location.Denied }}
return 503;
{{ end }}
}
{{ end }}
{{ if eq $server.Hostname "_" }}
# health checks in cloud providers require the use of port 80
location {{ $healthzURI }} {
access_log off;
return 200;
}
# this is required to avoid error if nginx is being monitored
# with an external software (like sysdig)
location /nginx_status {
allow 127.0.0.1;
{{ if $IsIPV6Enabled }}allow ::1;{{ end }}
deny all;
access_log off;
stub_status on;
}
{{ end }}
{{ template "CUSTOM_ERRORS" $all }} {{ template "CUSTOM_ERRORS" $all }}
} }
{{if $server.Alias }}
server {
server_name {{ $server.Alias }};
{{ template "SERVER" serverConfig $all $server }}
{{ template "CUSTOM_ERRORS" $all }}
}
{{ end }}
{{ end }} {{ end }}
# default server, used for NGINX healthcheck and access to nginx stats # default server, used for NGINX healthcheck and access to nginx stats
@ -666,3 +476,207 @@ stream {
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
} }
{{ end }} {{ end }}
{{/* definition of server-template to avoid repetitions with server-alias */}}
{{ define "SERVER" }}
{{ $all := .First }}
{{ $server := .Second }}
listen 80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}};
{{ if $all.IsIPV6Enabled }}listen [::]:80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{ end }};{{ end }}
set $proxy_upstream_name "-";
{{/* Listen on 442 because port 443 is used in the TLS sni server */}}
{{/* This listener must always have proxy_protocol enabled, because the SNI listener forwards on source IP info in it. */}}
{{ if not (empty $server.SSLCertificate) }}listen 442 proxy_protocol{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }};
{{ if $all.IsIPV6Enabled }}{{ if not (empty $server.SSLCertificate) }}listen [::]:442 proxy_protocol{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }};{{ end }}
{{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}}
# PEM sha: {{ $server.SSLPemChecksum }}
ssl_certificate {{ $server.SSLCertificate }};
ssl_certificate_key {{ $server.SSLCertificate }};
{{ end }}
{{ if (and (not (empty $server.SSLCertificate)) $all.Cfg.HSTS) }}
more_set_headers "Strict-Transport-Security: max-age={{ $all.Cfg.HSTSMaxAge }}{{ if $all.Cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }};{{ if $all.Cfg.HSTSPreload }} preload{{ end }}";
{{ end }}
{{ if $all.Cfg.EnableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }}
{{ range $location := $server.Locations }}
{{ $path := buildLocation $location }}
{{ $authPath := buildAuthLocation $location }}
{{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }}
# PEM sha: {{ $location.CertificateAuth.AuthSSLCert.PemSHA }}
ssl_client_certificate {{ $location.CertificateAuth.AuthSSLCert.CAFileName }};
ssl_verify_client on;
ssl_verify_depth {{ $location.CertificateAuth.ValidationDepth }};
{{ end }}
{{ if not (empty $location.Redirect.AppRoot)}}
if ($uri = /) {
return 302 {{ $location.Redirect.AppRoot }};
}
{{ end }}
{{ if not (empty $authPath) }}
location = {{ $authPath }} {
internal;
set $proxy_upstream_name "internal";
{{ if not $location.ExternalAuth.SendBody }}
proxy_pass_request_body off;
proxy_set_header Content-Length "";
{{ end }}
{{ if not (empty $location.ExternalAuth.Method) }}
proxy_method {{ $location.ExternalAuth.Method }};
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
{{ end }}
proxy_pass_request_headers on;
proxy_set_header Host {{ $location.ExternalAuth.Host }};
proxy_ssl_server_name on;
client_max_body_size "{{ $location.Proxy.BodySize }}";
set $target {{ $location.ExternalAuth.URL }};
proxy_pass $target;
}
{{ end }}
location {{ $path }} {
set $proxy_upstream_name "{{ buildUpstreamName $server.Hostname $all.Backends $location }}";
{{ 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://$best_http_host$request_uri;
}
{{ end }}
{{ if isLocationAllowed $location }}
{{ if gt (len $location.Whitelist.CIDR) 0 }}
if ({{ buildDenyVariable (print .Hostname "_" $path) }}) {
return 403;
}
{{ end }}
port_in_redirect {{ if $location.UsePortInRedirects }}on{{ else }}off{{ end }};
{{ if not (empty $authPath) }}
# this location requires authentication
auth_request {{ $authPath }};
{{- range $idx, $line := buildAuthResponseHeaders $location }}
{{ $line }}
{{- end }}
{{ end }}
{{ if not (empty $location.ExternalAuth.SigninURL) }}
error_page 401 = {{ $location.ExternalAuth.SigninURL }};
{{ end }}
{{/* if the location contains a rate limit annotation, create one */}}
{{ $limits := buildRateLimit $location }}
{{ range $limit := $limits }}
{{ $limit }}{{ end }}
{{ if $location.BasicDigestAuth.Secured }}
{{ if eq $location.BasicDigestAuth.Type "basic" }}
auth_basic "{{ $location.BasicDigestAuth.Realm }}";
auth_basic_user_file {{ $location.BasicDigestAuth.File }};
{{ else }}
auth_digest "{{ $location.BasicDigestAuth.Realm }}";
auth_digest_user_file {{ $location.BasicDigestAuth.File }};
{{ end }}
proxy_set_header Authorization "";
{{ end }}
{{ if $location.EnableCORS }}
{{ template "CORS" }}
{{ end }}
client_max_body_size "{{ $location.Proxy.BodySize }}";
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
{{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }}
proxy_set_header ssl-client-cert $ssl_client_cert;
{{ end }}
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $the_real_ip;
proxy_set_header X-Forwarded-For $the_real_ip;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
{{ range $k, $v := $all.ProxySetHeaders }}
proxy_set_header {{ $k }} "{{ $v }}";
{{ end }}
proxy_connect_timeout {{ $location.Proxy.ConnectTimeout }}s;
proxy_send_timeout {{ $location.Proxy.SendTimeout }}s;
proxy_read_timeout {{ $location.Proxy.ReadTimeout }}s;
proxy_redirect off;
proxy_buffering off;
proxy_buffer_size "{{ $location.Proxy.BufferSize }}";
proxy_buffers 4 "{{ $location.Proxy.BufferSize }}";
proxy_http_version 1.1;
proxy_cookie_domain {{ $location.Proxy.CookieDomain }};
proxy_cookie_path {{ $location.Proxy.CookiePath }};
# In case of errors try the next upstream server before returning an error
proxy_next_upstream {{ buildNextUpstream $location.Proxy.NextUpstream }}{{ if $all.Cfg.RetryNonIdempotent }} non_idempotent{{ end }};
{{/* rewrite only works if the content is not compressed */}}
{{ if $location.Redirect.AddBaseURL }}
proxy_set_header Accept-Encoding "";
{{ end }}
{{/* Add any additional configuration defined */}}
{{ $location.ConfigurationSnippet }}
{{ buildProxyPass $server.Hostname $all.Backends $location }}
{{ else }}
#{{ $location.Denied }}
return 503;
{{ end }}
}
{{ end }}
{{ if eq $server.Hostname "_" }}
# health checks in cloud providers require the use of port 80
location {{ $all.HealthzURI }} {
access_log off;
return 200;
}
# this is required to avoid error if nginx is being monitored
# with an external software (like sysdig)
location /nginx_status {
allow 127.0.0.1;
{{ if $all.IsIPV6Enabled }}allow ::1;{{ end }}
deny all;
access_log off;
stub_status on;
}
{{ end }}
{{ end }}

View file

@ -1062,21 +1062,9 @@ func (ic *GenericController) createServers(data []interface{},
continue continue
} }
// setup server-aliases based on annotations // setup server-alias based on annotations
aliasMap := map[string]string{}
aliasAnnotation := ic.annotations.Alias(ing) 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 == "" {
@ -1084,7 +1072,7 @@ func (ic *GenericController) createServers(data []interface{},
} }
// setup server aliases // setup server aliases
servers[host].Alias = aliasMap[host] servers[host].Alias = aliasAnnotation
// 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 != "" {