Add ump load balancing and naxsi as WAF. Update nginx to 1.9.13

This commit is contained in:
Manuel de Brito Fontes 2016-03-29 20:30:44 -03:00
parent a06f0a707e
commit c9f8a06399
9 changed files with 105 additions and 15 deletions

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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)
} }

View 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;

View file

@ -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 */}}

View file

@ -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

View file

@ -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)