Add annotation backend-protocol
This commit is contained in:
parent
c97a90f3ce
commit
7af93e03c7
8 changed files with 187 additions and 13 deletions
|
@ -27,6 +27,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|
|||
|[nginx.ingress.kubernetes.io/auth-tls-error-page](#client-certificate-authentication)|string|
|
||||
|[nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream](#client-certificate-authentication)|"true" or "false"|
|
||||
|[nginx.ingress.kubernetes.io/auth-url](#external-authentication)|string|
|
||||
|[nginx.ingress.kubernetes.io/backend-protocol](#backend-protocol)|string|HTTP,HTTPS,GRPC,GRPCS,AJP|
|
||||
|[nginx.ingress.kubernetes.io/base-url-scheme](#rewrite)|string|
|
||||
|[nginx.ingress.kubernetes.io/client-body-buffer-size](#client-body-buffer-size)|string|
|
||||
|[nginx.ingress.kubernetes.io/configuration-snippet](#configuration-snippet)|string|
|
||||
|
@ -382,7 +383,9 @@ The annotation `nginx.ingress.kubernetes.io/ssl-passthrough` allows to configure
|
|||
!!! attention
|
||||
The use of this annotation requires the flag `--enable-ssl-passthrough` (By default it is disabled).
|
||||
|
||||
### Secure backends
|
||||
### Secure backends DEPRECATED (since 0.18.0)
|
||||
|
||||
Please use `nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"`
|
||||
|
||||
By default NGINX uses plain HTTP to reach the services.
|
||||
Adding the annotation `nginx.ingress.kubernetes.io/secure-backends: "true"` in the Ingress rule changes the protocol to HTTPS.
|
||||
|
@ -569,7 +572,9 @@ nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules: '[=[ { "access": [ { "act
|
|||
|
||||
For details on how to write WAF rules, please refer to [https://github.com/p0pr0ck5/lua-resty-waf](https://github.com/p0pr0ck5/lua-resty-waf).
|
||||
|
||||
### gRPC backend
|
||||
### gRPC backend DEPRECATED (since 0.18.0)
|
||||
|
||||
Please use `nginx.ingress.kubernetes.io/backend-protocol: "GRPC"` or `nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"`
|
||||
|
||||
Since NGINX 1.13.10 it is possible to expose [gRPC services natively](http://nginx.org/en/docs/http/ngx_http_grpc_module.html)
|
||||
|
||||
|
@ -602,3 +607,16 @@ To use the module in the Kubernetes Nginx ingress controller, you have two optio
|
|||
- Use an InfluxDB server configured to enable the [UDP protocol](https://docs.influxdata.com/influxdb/v1.5/supported_protocols/udp/).
|
||||
- Deploy Telegraf as a sidecar proxy to the Ingress controller configured to listen UDP with the [socket listener input](https://github.com/influxdata/telegraf/tree/release-1.6/plugins/inputs/socket_listener) and to write using
|
||||
anyone of the [outputs plugins](https://github.com/influxdata/telegraf/tree/release-1.6/plugins/outputs)
|
||||
|
||||
### Backend Protocol
|
||||
|
||||
Using `backend-protocol` annotations is possible to indicate how NGINX should communicate with the backend service.
|
||||
Valid Values: HTTP, HTTPS, GRPC, GRPCS and AJP
|
||||
|
||||
By default NGINX uses `HTTP`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
||||
```
|
||||
|
|
|
@ -29,6 +29,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/backendprotocol"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/clientbodybuffersize"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
|
||||
|
@ -65,6 +66,7 @@ const DeniedKeyName = "Denied"
|
|||
// Ingress defines the valid annotations present in one NGINX Ingress rule
|
||||
type Ingress struct {
|
||||
metav1.ObjectMeta
|
||||
BackendProtocol string
|
||||
Alias string
|
||||
BasicDigestAuth auth.Config
|
||||
CertificateAuth authtls.Config
|
||||
|
@ -137,6 +139,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
|
|||
"GRPC": grpc.NewParser(cfg),
|
||||
"LuaRestyWAF": luarestywaf.NewParser(cfg),
|
||||
"InfluxDB": influxdb.NewParser(cfg),
|
||||
"BackendProtocol": backendprotocol.NewParser(cfg),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
62
internal/ingress/annotations/backendprotocol/main.go
Normal file
62
internal/ingress/annotations/backendprotocol/main.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright 2018 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 backendprotocol
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
var (
|
||||
validProtocols = regexp.MustCompile(`^(HTTP|HTTPS|AJP|GRPC|GRPCS)$`)
|
||||
)
|
||||
|
||||
type backendProtocol struct {
|
||||
r resolver.Resolver
|
||||
}
|
||||
|
||||
// NewParser creates a new backend protocol annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return backendProtocol{r}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to indicate the backend protocol.
|
||||
func (a backendProtocol) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
if ing.GetAnnotations() == nil {
|
||||
return "HTTP", nil
|
||||
}
|
||||
|
||||
proto, err := parser.GetStringAnnotation("backend-protocol", ing)
|
||||
if err != nil {
|
||||
return "HTTP", nil
|
||||
}
|
||||
|
||||
proto = strings.TrimSpace(strings.ToUpper(proto))
|
||||
if !validProtocols.MatchString(proto) {
|
||||
glog.Warningf("Protocol %v is not a valid value for the backend-protocol annotation. Using HTTP as protocol", proto)
|
||||
return "HTTP", nil
|
||||
}
|
||||
|
||||
return proto, nil
|
||||
}
|
68
internal/ingress/annotations/backendprotocol/main_test.go
Normal file
68
internal/ingress/annotations/backendprotocol/main_test.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2018 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 backendprotocol
|
||||
|
||||
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"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
_, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix("backend-protocol")] = "HTTPS"
|
||||
ing.SetAnnotations(data)
|
||||
i, err := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error parsing ingress with backend-protocol")
|
||||
}
|
||||
val, ok := i.(string)
|
||||
if !ok {
|
||||
t.Errorf("expected a string type")
|
||||
}
|
||||
if val != "HTTPS" {
|
||||
t.Errorf("expected HTTPS but %v returned", val)
|
||||
}
|
||||
}
|
|
@ -469,6 +469,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
loc.LuaRestyWAF = anns.LuaRestyWAF
|
||||
loc.InfluxDB = anns.InfluxDB
|
||||
loc.DefaultBackend = anns.DefaultBackend
|
||||
loc.BackendProtocol = anns.BackendProtocol
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
server.RedirectFromToWWW = true
|
||||
|
@ -509,6 +510,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
LuaRestyWAF: anns.LuaRestyWAF,
|
||||
InfluxDB: anns.InfluxDB,
|
||||
DefaultBackend: anns.DefaultBackend,
|
||||
BackendProtocol: anns.BackendProtocol,
|
||||
}
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
|
|
|
@ -403,12 +403,28 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur
|
|||
}
|
||||
|
||||
path := location.Path
|
||||
proto := "http"
|
||||
proto := "http://"
|
||||
|
||||
proxyPass := "proxy_pass"
|
||||
|
||||
switch location.BackendProtocol {
|
||||
case "HTTPS":
|
||||
proto = "https://"
|
||||
case "GRPC":
|
||||
proto = "grpc://"
|
||||
proxyPass = "grpc_pass"
|
||||
case "GRPCS":
|
||||
proto = "grpcs://"
|
||||
proxyPass = "grpc_pass"
|
||||
case "AJP":
|
||||
proto = ""
|
||||
proxyPass = "ajp_pass"
|
||||
}
|
||||
|
||||
// TODO: Remove after the deprecation of grpc-backend annotation
|
||||
if location.GRPC {
|
||||
proxyPass = "grpc_pass"
|
||||
proto = "grpc"
|
||||
proto = "grpc://"
|
||||
}
|
||||
|
||||
upstreamName := "upstream_balancer"
|
||||
|
@ -420,9 +436,11 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur
|
|||
for _, backend := range backends {
|
||||
if backend.Name == location.Backend {
|
||||
if backend.Secure || backend.SSLPassthrough {
|
||||
proto = "https"
|
||||
// TODO: Remove after the deprecation of secure-backend annotation
|
||||
proto = "https://"
|
||||
// TODO: Remove after the deprecation of grpc-backend annotation
|
||||
if location.GRPC {
|
||||
proto = "grpcs"
|
||||
proto = "grpcs://"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,7 +453,7 @@ func buildProxyPass(host string, b interface{}, loc interface{}, dynamicConfigur
|
|||
}
|
||||
|
||||
// defProxyPass returns the default proxy_pass, just the name of the upstream
|
||||
defProxyPass := fmt.Sprintf("%v %s://%s;", proxyPass, proto, upstreamName)
|
||||
defProxyPass := fmt.Sprintf("%v %s%s;", proxyPass, proto, upstreamName)
|
||||
|
||||
// if the path in the ingress rule is equals to the target: no special rewrite
|
||||
if path == location.Rewrite.Target {
|
||||
|
@ -476,13 +494,13 @@ subs_filter '%v' '$1<base href="%v://$http_host%v">' ro;
|
|||
return fmt.Sprintf(`
|
||||
rewrite (?i)%s(.*) /$1 break;
|
||||
rewrite (?i)%s / break;
|
||||
%v%v %s://%s;
|
||||
%v%v %s%s;
|
||||
%v`, path, location.Path, xForwardedPrefix, proxyPass, proto, upstreamName, abu)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`
|
||||
rewrite (?i)%s(.*) %s/$1 break;
|
||||
%v%v %s://%s;
|
||||
%v%v %s%s;
|
||||
%v`, path, location.Rewrite.Target, xForwardedPrefix, proxyPass, proto, upstreamName, abu)
|
||||
}
|
||||
|
||||
|
@ -752,8 +770,8 @@ func isValidClientBodyBufferSize(input interface{}) bool {
|
|||
if err != nil {
|
||||
sLowercase := strings.ToLower(s)
|
||||
|
||||
kCheck := strings.TrimSuffix(sLowercase, "k")
|
||||
_, err := strconv.Atoi(kCheck)
|
||||
check := strings.TrimSuffix(sLowercase, "k")
|
||||
_, err := strconv.Atoi(check)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
@ -921,7 +939,7 @@ func proxySetHeader(loc interface{}) string {
|
|||
return "proxy_set_header"
|
||||
}
|
||||
|
||||
if location.GRPC {
|
||||
if location.GRPC || location.BackendProtocol == "GRPC" || location.BackendProtocol == "GRPCS" {
|
||||
return "grpc_set_header"
|
||||
}
|
||||
|
||||
|
|
|
@ -270,6 +270,9 @@ type Location struct {
|
|||
// InfluxDB allows to monitor the incoming request by sending them to an influxdb database
|
||||
// +optional
|
||||
InfluxDB influxdb.Config `json:"influxDB,omitempty"`
|
||||
// BackendProtocol indicates which protocol should be used to communicate with the service
|
||||
// By default this is HTTP
|
||||
BackendProtocol string `json:"backend-protocol"`
|
||||
}
|
||||
|
||||
// SSLPassthroughBackend describes a SSL upstream server configured
|
||||
|
|
|
@ -38,7 +38,7 @@ var _ = framework.IngressNginxDescribe("Annotations - grpc", func() {
|
|||
host := "grpc"
|
||||
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/grpc-backend": "true",
|
||||
"nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
|
||||
}
|
||||
ing, err := f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.IngressController.Namespace, "fortune-teller", 50051, &annotations))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
|
Loading…
Reference in a new issue