Managing a whitelist for _/nginx_status (#2187)

Signed-off-by: Sylvain Rabot <s.rabot@lectra.com>
This commit is contained in:
Sylvain Rabot 2018-03-28 14:27:34 +02:00 committed by Manuel Alejandro de Brito Fontes
parent 6bc4dad38a
commit 385368990c
8 changed files with 79 additions and 32 deletions

View file

@ -63,6 +63,8 @@ The following table shows a configuration option's name, type, and the default v
|[log-format-stream](#log-format-stream)|string|`[$time_local] $protocol $status $bytes_sent $bytes_received $session_time`| |[log-format-stream](#log-format-stream)|string|`[$time_local] $protocol $status $bytes_sent $bytes_received $session_time`|
|[max-worker-connections](#max-worker-connections)|int|16384| |[max-worker-connections](#max-worker-connections)|int|16384|
|[map-hash-bucket-size](#max-worker-connections)|int|64| |[map-hash-bucket-size](#max-worker-connections)|int|64|
|[nginx-status-ipv4-whitelist](#nginx-status-ipv4-whitelist)|[]string|"127.0.0.1"|
|[nginx-status-ipv6-whitelist](#nginx-status-ipv6-whitelist)|[]string|"::1"|
|[proxy-real-ip-cidr](#proxy-real-ip-cidr)|[]string|"0.0.0.0/0"| |[proxy-real-ip-cidr](#proxy-real-ip-cidr)|[]string|"0.0.0.0/0"|
|[proxy-set-headers](#proxy-set-headers)|string|""| |[proxy-set-headers](#proxy-set-headers)|string|""|
|[server-name-hash-max-size](#server-name-hash-max-size)|int|1024| |[server-name-hash-max-size](#server-name-hash-max-size)|int|1024|

File diff suppressed because one or more lines are too long

View file

@ -250,6 +250,11 @@ type Configuration struct {
// http://nginx.org/en/docs/http/ngx_http_map_module.html#map_hash_bucket_size // http://nginx.org/en/docs/http/ngx_http_map_module.html#map_hash_bucket_size
MapHashBucketSize int `json:"map-hash-bucket-size,omitempty"` MapHashBucketSize int `json:"map-hash-bucket-size,omitempty"`
// NginxStatusIpv4Whitelist has the list of cidr that are allowed to access
// the /nginx_status endpoint of the "_" server
NginxStatusIpv4Whitelist []string `json:"nginx-status-ipv4-whitelist,omitempty"`
NginxStatusIpv6Whitelist []string `json:"nginx-status-ipv6-whitelist,omitempty"`
// If UseProxyProtocol is enabled ProxyRealIPCIDR defines the default the IP/network address // If UseProxyProtocol is enabled ProxyRealIPCIDR defines the default the IP/network address
// of your external load balancer // of your external load balancer
ProxyRealIPCIDR []string `json:"proxy-real-ip-cidr,omitempty"` ProxyRealIPCIDR []string `json:"proxy-real-ip-cidr,omitempty"`
@ -499,8 +504,14 @@ type Configuration struct {
// NewDefault returns the default nginx configuration // NewDefault returns the default nginx configuration
func NewDefault() Configuration { func NewDefault() Configuration {
defIPCIDR := make([]string, 0) defIPCIDR := make([]string, 0)
defIPCIDR = append(defIPCIDR, "0.0.0.0/0")
defBindAddress := make([]string, 0) defBindAddress := make([]string, 0)
defNginxStatusIpv4Whitelist := make([]string, 0)
defNginxStatusIpv6Whitelist := make([]string, 0)
defIPCIDR = append(defIPCIDR, "0.0.0.0/0")
defNginxStatusIpv4Whitelist = append(defNginxStatusIpv4Whitelist, "127.0.0.1")
defNginxStatusIpv6Whitelist = append(defNginxStatusIpv6Whitelist, "::1")
cfg := Configuration{ cfg := Configuration{
AllowBackendServerHeader: false, AllowBackendServerHeader: false,
AccessLogPath: "/var/log/nginx/access.log", AccessLogPath: "/var/log/nginx/access.log",
@ -534,6 +545,8 @@ func NewDefault() Configuration {
LogFormatUpstream: logFormatUpstream, LogFormatUpstream: logFormatUpstream,
MaxWorkerConnections: 16384, MaxWorkerConnections: 16384,
MapHashBucketSize: 64, MapHashBucketSize: 64,
NginxStatusIpv4Whitelist: defNginxStatusIpv4Whitelist,
NginxStatusIpv6Whitelist: defNginxStatusIpv6Whitelist,
ProxyRealIPCIDR: defIPCIDR, ProxyRealIPCIDR: defIPCIDR,
ServerNameHashMaxSize: 1024, ServerNameHashMaxSize: 1024,
ProxyHeadersHashMaxSize: 512, ProxyHeadersHashMaxSize: 512,
@ -629,6 +642,8 @@ type TemplateConfig struct {
Cfg Configuration Cfg Configuration
IsIPV6Enabled bool IsIPV6Enabled bool
IsSSLPassthroughEnabled bool IsSSLPassthroughEnabled bool
NginxStatusIpv4Whitelist []string
NginxStatusIpv6Whitelist []string
RedirectServers map[string]string RedirectServers map[string]string
ListenPorts *ListenPorts ListenPorts *ListenPorts
PublishService *apiv1.Service PublishService *apiv1.Service

View file

@ -621,6 +621,8 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
CustomErrors: len(cfg.CustomHTTPErrors) > 0, CustomErrors: len(cfg.CustomHTTPErrors) > 0,
Cfg: cfg, Cfg: cfg,
IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6, IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6,
NginxStatusIpv4Whitelist: cfg.NginxStatusIpv4Whitelist,
NginxStatusIpv6Whitelist: cfg.NginxStatusIpv6Whitelist,
RedirectServers: redirectServers, RedirectServers: redirectServers,
IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough, IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough,
ListenPorts: n.cfg.ListenPorts, ListenPorts: n.cfg.ListenPorts,

View file

@ -32,14 +32,16 @@ import (
) )
const ( const (
customHTTPErrors = "custom-http-errors" customHTTPErrors = "custom-http-errors"
skipAccessLogUrls = "skip-access-log-urls" skipAccessLogUrls = "skip-access-log-urls"
whitelistSourceRange = "whitelist-source-range" whitelistSourceRange = "whitelist-source-range"
proxyRealIPCIDR = "proxy-real-ip-cidr" proxyRealIPCIDR = "proxy-real-ip-cidr"
bindAddress = "bind-address" bindAddress = "bind-address"
httpRedirectCode = "http-redirect-code" httpRedirectCode = "http-redirect-code"
proxyStreamResponses = "proxy-stream-responses" proxyStreamResponses = "proxy-stream-responses"
hideHeaders = "hide-headers" hideHeaders = "hide-headers"
nginxStatusIpv4Whitelist = "nginx-status-ipv4-whitelist"
nginxStatusIpv6Whitelist = "nginx-status-ipv6-whitelist"
) )
var ( var (
@ -54,6 +56,7 @@ func ReadConfig(src map[string]string) config.Configuration {
conf[k] = v conf[k] = v
} }
to := config.NewDefault()
errors := make([]int, 0) errors := make([]int, 0)
skipUrls := make([]string, 0) skipUrls := make([]string, 0)
whiteList := make([]string, 0) whiteList := make([]string, 0)
@ -62,7 +65,6 @@ func ReadConfig(src map[string]string) config.Configuration {
bindAddressIpv4List := make([]string, 0) bindAddressIpv4List := make([]string, 0)
bindAddressIpv6List := make([]string, 0) bindAddressIpv6List := make([]string, 0)
redirectCode := 308
if val, ok := conf[customHTTPErrors]; ok { if val, ok := conf[customHTTPErrors]; ok {
delete(conf, customHTTPErrors) delete(conf, customHTTPErrors)
@ -116,7 +118,7 @@ func ReadConfig(src map[string]string) config.Configuration {
glog.Warningf("%v is not a valid HTTP code: %v", val, err) glog.Warningf("%v is not a valid HTTP code: %v", val, err)
} else { } else {
if validRedirectCodes.Has(j) { if validRedirectCodes.Has(j) {
redirectCode = j to.HTTPRedirectCode = j
} else { } else {
glog.Warningf("The code %v is not a valid as HTTP redirect code. Using the default.", val) glog.Warningf("The code %v is not a valid as HTTP redirect code. Using the default.", val)
} }
@ -134,7 +136,22 @@ func ReadConfig(src map[string]string) config.Configuration {
} }
} }
to := config.NewDefault() // Nginx Status whitlelist
if val, ok := conf[nginxStatusIpv4Whitelist]; ok {
whitelist := make([]string, 0)
whitelist = append(whitelist, strings.Split(val, ",")...)
to.NginxStatusIpv4Whitelist = whitelist
delete(conf, nginxStatusIpv4Whitelist)
}
if val, ok := conf[nginxStatusIpv6Whitelist]; ok {
whitelist := make([]string, 0)
whitelist = append(whitelist, strings.Split(val, ",")...)
to.NginxStatusIpv6Whitelist = whitelist
delete(conf, nginxStatusIpv6Whitelist)
}
to.CustomHTTPErrors = filterErrors(errors) to.CustomHTTPErrors = filterErrors(errors)
to.SkipAccessLogURLs = skipUrls to.SkipAccessLogURLs = skipUrls
to.WhitelistSourceRange = whiteList to.WhitelistSourceRange = whiteList
@ -142,7 +159,6 @@ func ReadConfig(src map[string]string) config.Configuration {
to.BindAddressIpv4 = bindAddressIpv4List to.BindAddressIpv4 = bindAddressIpv4List
to.BindAddressIpv6 = bindAddressIpv6List to.BindAddressIpv6 = bindAddressIpv6List
to.HideHeaders = hideHeadersList to.HideHeaders = hideHeadersList
to.HTTPRedirectCode = redirectCode
to.ProxyStreamResponses = streamResponses to.ProxyStreamResponses = streamResponses
to.DisableIpv6DNS = !ing_net.IsIPv6Enabled() to.DisableIpv6DNS = !ing_net.IsIPv6Enabled()

View file

@ -33,20 +33,22 @@ func TestFilterErrors(t *testing.T) {
func TestMergeConfigMapToStruct(t *testing.T) { func TestMergeConfigMapToStruct(t *testing.T) {
conf := map[string]string{ conf := map[string]string{
"custom-http-errors": "300,400,demo", "custom-http-errors": "300,400,demo",
"proxy-read-timeout": "1", "proxy-read-timeout": "1",
"proxy-send-timeout": "2", "proxy-send-timeout": "2",
"skip-access-log-urls": "/log,/demo,/test", "skip-access-log-urls": "/log,/demo,/test",
"use-proxy-protocol": "true", "use-proxy-protocol": "true",
"disable-access-log": "true", "disable-access-log": "true",
"access-log-path": "/var/log/test/access.log", "access-log-path": "/var/log/test/access.log",
"error-log-path": "/var/log/test/error.log", "error-log-path": "/var/log/test/error.log",
"use-gzip": "true", "use-gzip": "true",
"enable-dynamic-tls-records": "false", "enable-dynamic-tls-records": "false",
"gzip-types": "text/html", "gzip-types": "text/html",
"proxy-real-ip-cidr": "1.1.1.1/8,2.2.2.2/24", "proxy-real-ip-cidr": "1.1.1.1/8,2.2.2.2/24",
"bind-address": "1.1.1.1,2.2.2.2,3.3.3,2001:db8:a0b:12f0::1,3731:54:65fe:2::a7,33:33:33::33::33", "bind-address": "1.1.1.1,2.2.2.2,3.3.3,2001:db8:a0b:12f0::1,3731:54:65fe:2::a7,33:33:33::33::33",
"worker-shutdown-timeout": "99s", "worker-shutdown-timeout": "99s",
"nginx-status-ipv4-whitelist": "127.0.0.1,10.0.0.0/24",
"nginx-status-ipv6-whitelist": "::1,2001::/16",
} }
def := config.NewDefault() def := config.NewDefault()
def.CustomHTTPErrors = []int{300, 400} def.CustomHTTPErrors = []int{300, 400}
@ -63,6 +65,8 @@ func TestMergeConfigMapToStruct(t *testing.T) {
def.BindAddressIpv4 = []string{"1.1.1.1", "2.2.2.2"} def.BindAddressIpv4 = []string{"1.1.1.1", "2.2.2.2"}
def.BindAddressIpv6 = []string{"[2001:db8:a0b:12f0::1]", "[3731:54:65fe:2::a7]"} def.BindAddressIpv6 = []string{"[2001:db8:a0b:12f0::1]", "[3731:54:65fe:2::a7]"}
def.WorkerShutdownTimeout = "99s" def.WorkerShutdownTimeout = "99s"
def.NginxStatusIpv4Whitelist = []string{"127.0.0.1", "10.0.0.0/24"}
def.NginxStatusIpv6Whitelist = []string{"::1", "2001::/16"}
to := ReadConfig(conf) to := ReadConfig(conf)
if diff := pretty.Compare(to, def); diff != "" { if diff := pretty.Compare(to, def); diff != "" {

View file

@ -1011,8 +1011,14 @@ stream {
# this is required to avoid error if nginx is being monitored # this is required to avoid error if nginx is being monitored
# with an external software (like sysdig) # with an external software (like sysdig)
location /nginx_status { location /nginx_status {
allow 127.0.0.1; {{ range $v := $all.NginxStatusIpv4Whitelist }}
{{ if $all.IsIPV6Enabled }}allow ::1;{{ end }} allow {{ $v }};
{{ end }}
{{ if $all.IsIPV6Enabled -}}
{{ range $v := $all.NginxStatusIpv6Whitelist }}
allow {{ $v }};
{{ end }}
{{ end -}}
deny all; deny all;
access_log off; access_log off;

View file

@ -26,6 +26,8 @@
"keepAlive": 75, "keepAlive": 75,
"mapHashBucketSize": 64, "mapHashBucketSize": 64,
"maxWorkerConnections": 16384, "maxWorkerConnections": 16384,
"nginxStatusIpv4Whitelist": "127.0.0.1",
"nginxStatusIpv6Whitelist": "::1",
"proxyRealIpCidr": "0.0.0.0/0", "proxyRealIpCidr": "0.0.0.0/0",
"retryNonIdempotent": false, "retryNonIdempotent": false,
"serverNameHashBucketSize": 64, "serverNameHashBucketSize": 64,
@ -113,7 +115,7 @@
"pemSha": "" "pemSha": ""
}, },
"vtsDefaultFilterKey": "$uri $server_name" "vtsDefaultFilterKey": "$uri $server_name"
}, { }, {
"path": "/", "path": "/",
"isDefBackend": true, "isDefBackend": true,
@ -57210,4 +57212,4 @@
"failTimeout": 0 "failTimeout": 0
}] }]
}] }]
} }