Add ump load balancing and naxsi as WAF. Update nginx to 1.9.13
This commit is contained in:
parent
a06f0a707e
commit
c9f8a06399
9 changed files with 105 additions and 15 deletions
|
@ -12,7 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM gcr.io/google_containers/nginx-slim:0.4
|
FROM gcr.io/google_containers/nginx-slim:0.5
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
diffutils \
|
diffutils \
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
all: push
|
all: push
|
||||||
|
|
||||||
# 0.0 shouldn't clobber any release builds
|
# 0.0 shouldn't clobber any release builds
|
||||||
TAG = 0.4
|
TAG = 0.5
|
||||||
PREFIX = gcr.io/google_containers/nginx-ingress-controller
|
PREFIX = gcr.io/google_containers/nginx-ingress-controller
|
||||||
|
|
||||||
controller: controller.go clean
|
controller: controller.go clean
|
||||||
|
|
|
@ -130,6 +130,27 @@ data:
|
||||||
|
|
||||||
Please check the [tcp services](examples/tcp/README.md) example
|
Please check the [tcp services](examples/tcp/README.md) example
|
||||||
|
|
||||||
|
## Exposing UDP services
|
||||||
|
|
||||||
|
Since 1.9.13 NGINX provides [UDP Load Balancing](https://www.nginx.com/blog/announcing-udp-load-balancing/).
|
||||||
|
|
||||||
|
Ingress does not support UDP services (yet). For this reason this Ingress controller uses a ConfigMap where the key is the external port to use and the value is
|
||||||
|
`<namespace/service name>:<service port>`
|
||||||
|
It is possible to use a number or the name of the port.
|
||||||
|
|
||||||
|
The next example shows how to expose the service `kube-dns` running in the namespace `kube-system` in the port `53` using the port `53`
|
||||||
|
```
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: udp-configmap-example
|
||||||
|
data:
|
||||||
|
53: "kube-system/kube-dns:53"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Please check the [udp services](examples/udp/README.md) example
|
||||||
|
|
||||||
|
|
||||||
## Custom NGINX configuration
|
## Custom NGINX configuration
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ type loadBalancerController struct {
|
||||||
defaultSvc string
|
defaultSvc string
|
||||||
nxgConfigMap string
|
nxgConfigMap string
|
||||||
tcpConfigMap string
|
tcpConfigMap string
|
||||||
|
udpConfigMap string
|
||||||
|
|
||||||
syncQueue *taskQueue
|
syncQueue *taskQueue
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ type loadBalancerController struct {
|
||||||
|
|
||||||
// newLoadBalancerController creates a controller for nginx loadbalancer
|
// newLoadBalancerController creates a controller for nginx loadbalancer
|
||||||
func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Duration, defaultSvc,
|
func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Duration, defaultSvc,
|
||||||
namespace, nxgConfigMapName, tcpConfigMapName string, lbRuntimeInfo *lbInfo) (*loadBalancerController, error) {
|
namespace, nxgConfigMapName, tcpConfigMapName, udpConfigMapName string, lbRuntimeInfo *lbInfo) (*loadBalancerController, error) {
|
||||||
lbc := loadBalancerController{
|
lbc := loadBalancerController{
|
||||||
client: kubeClient,
|
client: kubeClient,
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
|
@ -83,6 +84,7 @@ func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Dura
|
||||||
nginx: nginx.NewManager(kubeClient),
|
nginx: nginx.NewManager(kubeClient),
|
||||||
nxgConfigMap: nxgConfigMapName,
|
nxgConfigMap: nxgConfigMapName,
|
||||||
tcpConfigMap: tcpConfigMapName,
|
tcpConfigMap: tcpConfigMapName,
|
||||||
|
udpConfigMap: udpConfigMapName,
|
||||||
defaultSvc: defaultSvc,
|
defaultSvc: defaultSvc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +176,10 @@ func (lbc *loadBalancerController) getTCPConfigMap(ns, name string) (*api.Config
|
||||||
return lbc.client.ConfigMaps(ns).Get(name)
|
return lbc.client.ConfigMaps(ns).Get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lbc *loadBalancerController) getUDPConfigMap(ns, name string) (*api.ConfigMap, error) {
|
||||||
|
return lbc.client.ConfigMaps(ns).Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
func (lbc *loadBalancerController) sync(key string) {
|
func (lbc *loadBalancerController) sync(key string) {
|
||||||
if !lbc.controllersInSync() {
|
if !lbc.controllersInSync() {
|
||||||
lbc.syncQueue.requeue(key, fmt.Errorf("deferring sync till endpoints controller has synced"))
|
lbc.syncQueue.requeue(key, fmt.Errorf("deferring sync till endpoints controller has synced"))
|
||||||
|
@ -217,10 +223,34 @@ func (lbc *loadBalancerController) getTCPServices() []*nginx.Location {
|
||||||
return []*nginx.Location{}
|
return []*nginx.Location{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tcpSvcs []*nginx.Location
|
return lbc.getServices(tcpMap.Data, api.ProtocolTCP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lbc *loadBalancerController) getUDPServices() []*nginx.Location {
|
||||||
|
if lbc.udpConfigMap == "" {
|
||||||
|
// no configmap for TCP services
|
||||||
|
return []*nginx.Location{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ns, name, err := parseNsName(lbc.udpConfigMap)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("%v", err)
|
||||||
|
return []*nginx.Location{}
|
||||||
|
}
|
||||||
|
tcpMap, err := lbc.getUDPConfigMap(ns, name)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(3).Infof("no configured tcp services found: %v", err)
|
||||||
|
return []*nginx.Location{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lbc.getServices(tcpMap.Data, api.ProtocolUDP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lbc *loadBalancerController) getServices(data map[string]string, proto api.Protocol) []*nginx.Location {
|
||||||
|
var svcs []*nginx.Location
|
||||||
// k -> port to expose in nginx
|
// k -> port to expose in nginx
|
||||||
// v -> <namespace>/<service name>:<port from service to be used>
|
// v -> <namespace>/<service name>:<port from service to be used>
|
||||||
for k, v := range tcpMap.Data {
|
for k, v := range data {
|
||||||
port, err := strconv.Atoi(k)
|
port, err := strconv.Atoi(k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("%v is not valid as a TCP port", k)
|
glog.Warningf("%v is not valid as a TCP port", k)
|
||||||
|
@ -273,7 +303,7 @@ func (lbc *loadBalancerController) getTCPServices() []*nginx.Location {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpSvcs = append(tcpSvcs, &nginx.Location{
|
svcs = append(svcs, &nginx.Location{
|
||||||
Path: k,
|
Path: k,
|
||||||
Upstream: nginx.Upstream{
|
Upstream: nginx.Upstream{
|
||||||
Name: fmt.Sprintf("%v-%v-%v", svcNs, svcName, port),
|
Name: fmt.Sprintf("%v-%v-%v", svcNs, svcName, port),
|
||||||
|
@ -282,7 +312,7 @@ func (lbc *loadBalancerController) getTCPServices() []*nginx.Location {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return tcpSvcs
|
return svcs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lbc *loadBalancerController) getDefaultUpstream() *nginx.Upstream {
|
func (lbc *loadBalancerController) getDefaultUpstream() *nginx.Upstream {
|
||||||
|
|
|
@ -57,6 +57,12 @@ var (
|
||||||
name of the port.
|
name of the port.
|
||||||
The ports 80 and 443 are not allowed as external ports. This ports are reserved for nginx`)
|
The ports 80 and 443 are not allowed as external ports. This ports are reserved for nginx`)
|
||||||
|
|
||||||
|
udpConfigMapName = flags.String("udp-services-configmap", "",
|
||||||
|
`Name of the ConfigMap that containes the definition of the UDP services to expose.
|
||||||
|
The key in the map indicates the external port to be used. The value is the name of the
|
||||||
|
service with the format namespace/serviceName and the port of the service could be a number of the
|
||||||
|
name of the port.`)
|
||||||
|
|
||||||
resyncPeriod = flags.Duration("sync-period", 30*time.Second,
|
resyncPeriod = flags.Duration("sync-period", 30*time.Second,
|
||||||
`Relist and confirm cloud resources this often.`)
|
`Relist and confirm cloud resources this often.`)
|
||||||
|
|
||||||
|
@ -99,7 +105,7 @@ func main() {
|
||||||
glog.Fatalf("no service with name %v found: %v", *defaultSvc, err)
|
glog.Fatalf("no service with name %v found: %v", *defaultSvc, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lbc, err := newLoadBalancerController(kubeClient, *resyncPeriod, *defaultSvc, *watchNamespace, *nxgConfigMap, *tcpConfigMapName, lbInfo)
|
lbc, err := newLoadBalancerController(kubeClient, *resyncPeriod, *defaultSvc, *watchNamespace, *nxgConfigMap, *tcpConfigMapName, *udpConfigMapName, lbInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("%v", err)
|
glog.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
|
8
controllers/nginx/naxsi/basic.rules
Normal file
8
controllers/nginx/naxsi/basic.rules
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
SecRulesEnabled;
|
||||||
|
DeniedUrl "/RequestDenied";
|
||||||
|
## check rules
|
||||||
|
CheckRule "$SQL >= 8" BLOCK;
|
||||||
|
CheckRule "$RFI >= 8" BLOCK;
|
||||||
|
CheckRule "$TRAVERSAL >= 4" BLOCK;
|
||||||
|
CheckRule "$EVADE >= 4" BLOCK;
|
||||||
|
CheckRule "$XSS >= 8" BLOCK;
|
|
@ -24,6 +24,11 @@ http {
|
||||||
require("error_page")
|
require("error_page")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{{ if $cfg.enableWaf}}
|
||||||
|
# https://github.com/nbs-system/naxsi/wiki/basicsetup
|
||||||
|
include /etc/nginx/naxsi/*.rules;
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
aio threads;
|
aio threads;
|
||||||
tcp_nopush on;
|
tcp_nopush on;
|
||||||
|
@ -80,11 +85,6 @@ http {
|
||||||
'' $scheme;
|
'' $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
map $http_x_forwarded_proto $pass_forwarded_for {
|
|
||||||
default $http_x_forwarded_for;
|
|
||||||
'' $proxy_add_x_forwarded_for;
|
|
||||||
}
|
|
||||||
|
|
||||||
map $pass_access_scheme $sts {
|
map $pass_access_scheme $sts {
|
||||||
'https' 'max-age={{ $cfg.htsMaxAge }}{{ if $cfg.htsIncludeSubdomains }}; includeSubDomains{{ end }}; preload';
|
'https' 'max-age={{ $cfg.htsMaxAge }}{{ if $cfg.htsIncludeSubdomains }}; includeSubDomains{{ end }}; preload';
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ http {
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection $connection_upgrade;
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
proxy_set_header X-Forwarded-For $pass_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
proxy_set_header X-Forwarded-Server $host;
|
proxy_set_header X-Forwarded-Server $host;
|
||||||
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
|
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
|
||||||
|
@ -219,6 +219,11 @@ http {
|
||||||
proxy_pass http://{{ $location.Upstream.Name }};
|
proxy_pass http://{{ $location.Upstream.Name }};
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if $cfg.enableWaf}}
|
||||||
|
location /RequestDenied {
|
||||||
|
return 418;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
{{ template "CUSTOM_ERRORS" $cfg }}
|
{{ template "CUSTOM_ERRORS" $cfg }}
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -265,8 +270,10 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# TCP services
|
|
||||||
stream {
|
stream {
|
||||||
|
|
||||||
|
# TCP services
|
||||||
{{ range $i, $tcpServer := .tcpUpstreams }}
|
{{ range $i, $tcpServer := .tcpUpstreams }}
|
||||||
upstream tcp-{{ $tcpServer.Upstream.Name }} {
|
upstream tcp-{{ $tcpServer.Upstream.Name }} {
|
||||||
{{ range $server := $tcpServer.Upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }};
|
{{ range $server := $tcpServer.Upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }};
|
||||||
|
@ -280,6 +287,22 @@ stream {
|
||||||
proxy_pass tcp-{{ $tcpServer.Upstream.Name }};
|
proxy_pass tcp-{{ $tcpServer.Upstream.Name }};
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
# UDP services
|
||||||
|
{{ range $i, $udpServer := .udpUpstreams }}
|
||||||
|
upstream udp-{{ $udpServer.Upstream.Name }} {
|
||||||
|
{{ range $server := $tcpServer.Upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }};
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen {{ $tcpServer.Path }} udp;
|
||||||
|
proxy_timeout 1s;
|
||||||
|
proxy_responses 1;
|
||||||
|
proxy_pass udp-{{ $tcpServer.Upstream.Name }};
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{{/* definition of templates to avoid repetitions */}}
|
{{/* definition of templates to avoid repetitions */}}
|
||||||
|
|
|
@ -21,6 +21,7 @@ type IngressConfig struct {
|
||||||
Upstreams []*Upstream
|
Upstreams []*Upstream
|
||||||
Servers []*Server
|
Servers []*Server
|
||||||
TCPUpstreams []*Location
|
TCPUpstreams []*Location
|
||||||
|
UDPUpstreams []*Location
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upstream describes an NGINX upstream
|
// Upstream describes an NGINX upstream
|
||||||
|
|
|
@ -56,6 +56,7 @@ func (ngx *Manager) writeCfg(cfg nginxConfiguration, ingressCfg IngressConfig) (
|
||||||
conf["upstreams"] = ingressCfg.Upstreams
|
conf["upstreams"] = ingressCfg.Upstreams
|
||||||
conf["servers"] = ingressCfg.Servers
|
conf["servers"] = ingressCfg.Servers
|
||||||
conf["tcpUpstreams"] = ingressCfg.TCPUpstreams
|
conf["tcpUpstreams"] = ingressCfg.TCPUpstreams
|
||||||
|
conf["udpUpstreams"] = ingressCfg.UDPUpstreams
|
||||||
conf["defResolver"] = ngx.defResolver
|
conf["defResolver"] = ngx.defResolver
|
||||||
conf["sslDHParam"] = ngx.sslDHParam
|
conf["sslDHParam"] = ngx.sslDHParam
|
||||||
conf["cfg"] = fixKeyNames(curNginxCfg)
|
conf["cfg"] = fixKeyNames(curNginxCfg)
|
||||||
|
|
Loading…
Reference in a new issue