Resolve conflicts

This commit is contained in:
Bo0km4n 2020-06-20 17:13:31 +09:00
commit 7ab0916c92
161 changed files with 2159 additions and 1223 deletions

View file

@ -108,7 +108,7 @@ type Ingress struct {
UpstreamVhost string
Whitelist ipwhitelist.SourceRange
XForwardedPrefix string
SSLCiphers string
SSLCipher sslcipher.Config
Logs log.Config
InfluxDB influxdb.Config
ModSecurity modsecurity.Config
@ -156,7 +156,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"UpstreamVhost": upstreamvhost.NewParser(cfg),
"Whitelist": ipwhitelist.NewParser(cfg),
"XForwardedPrefix": xforwardedprefix.NewParser(cfg),
"SSLCiphers": sslcipher.NewParser(cfg),
"SSLCipher": sslcipher.NewParser(cfg),
"Logs": log.NewParser(cfg),
"InfluxDB": influxdb.NewParser(cfg),
"BackendProtocol": backendprotocol.NewParser(cfg),

View file

@ -27,13 +27,36 @@ type sslCipher struct {
r resolver.Resolver
}
// Config contains the ssl-ciphers & ssl-prefer-server-ciphers configuration
type Config struct {
SSLCiphers string
SSLPreferServerCiphers string
}
// NewParser creates a new sslCipher annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return sslCipher{r}
}
// Parse parses the annotations contained in the ingress rule
// used to add ssl-ciphers to the server name
// used to add ssl-ciphers & ssl-prefer-server-ciphers to the server name
func (sc sslCipher) Parse(ing *networking.Ingress) (interface{}, error) {
return parser.GetStringAnnotation("ssl-ciphers", ing)
config := &Config{}
var err error
var sslPreferServerCiphers bool
sslPreferServerCiphers, err = parser.GetBoolAnnotation("ssl-prefer-server-ciphers", ing)
if err != nil {
config.SSLPreferServerCiphers = ""
} else {
if sslPreferServerCiphers {
config.SSLPreferServerCiphers = "on"
} else {
config.SSLPreferServerCiphers = "off"
}
}
config.SSLCiphers, _ = parser.GetStringAnnotation("ssl-ciphers", ing)
return config, nil
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package sslcipher
import (
"reflect"
"testing"
api "k8s.io/api/core/v1"
@ -27,22 +28,27 @@ import (
)
func TestParse(t *testing.T) {
annotation := parser.GetAnnotationWithPrefix("ssl-ciphers")
ap := NewParser(&resolver.Mock{})
if ap == nil {
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
}
annotationSSLCiphers := parser.GetAnnotationWithPrefix("ssl-ciphers")
annotationSSLPreferServerCiphers := parser.GetAnnotationWithPrefix("ssl-prefer-server-ciphers")
testCases := []struct {
annotations map[string]string
expected string
expected Config
}{
{map[string]string{annotation: "ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"}, "ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"},
{map[string]string{annotation: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"},
"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"},
{map[string]string{annotation: ""}, ""},
{map[string]string{}, ""},
{nil, ""},
{map[string]string{annotationSSLCiphers: "ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"}, Config{"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP", ""}},
{map[string]string{annotationSSLCiphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"},
Config{"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", ""}},
{map[string]string{annotationSSLCiphers: ""}, Config{"", ""}},
{map[string]string{annotationSSLPreferServerCiphers: "true"}, Config{"", "on"}},
{map[string]string{annotationSSLPreferServerCiphers: "false"}, Config{"", "off"}},
{map[string]string{annotationSSLCiphers: "ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP", annotationSSLPreferServerCiphers: "true"}, Config{"ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP", "on"}},
{map[string]string{}, Config{"", ""}},
{nil, Config{"", ""}},
}
ing := &networking.Ingress{
@ -56,7 +62,7 @@ func TestParse(t *testing.T) {
for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations)
result, _ := ap.Parse(ing)
if result != testCase.expected {
if !reflect.DeepEqual(result, &testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
}
}

View file

@ -39,6 +39,7 @@ func TestParse(t *testing.T) {
expected string
}{
{map[string]string{annotation: "$request_uri"}, "$request_uri"},
{map[string]string{annotation: "$request_uri$scheme"}, "$request_uri$scheme"},
{map[string]string{annotation: "false"}, "false"},
{map[string]string{}, ""},
{nil, ""},

View file

@ -111,11 +111,20 @@ type Configuration struct {
// By default this is disabled
EnableAccessLogForDefaultBackend bool `json:"enable-access-log-for-default-backend"`
// AccessLogPath sets the path of the access logs if enabled
// AccessLogPath sets the path of the access logs for both http and stream contexts if enabled
// http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log
// http://nginx.org/en/docs/stream/ngx_stream_log_module.html#access_log
// By default access logs go to /var/log/nginx/access.log
AccessLogPath string `json:"access-log-path,omitempty"`
// HttpAccessLogPath sets the path of the access logs for http context globally if enabled
// http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log
HttpAccessLogPath string `json:"http-access-log-path,omitempty"`
// StreamAccessLogPath sets the path of the access logs for stream context globally if enabled
// http://nginx.org/en/docs/stream/ngx_stream_log_module.html#access_log
StreamAccessLogPath string `json:"stream-access-log-path,omitempty"`
// WorkerCPUAffinity bind nginx worker processes to CPUs this will improve response latency
// http://nginx.org/en/docs/ngx_core_module.html#worker_cpu_affinity
// By default this is disabled

View file

@ -1053,8 +1053,9 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
Locations: []*ingress.Location{
loc,
},
SSLPassthrough: anns.SSLPassthrough,
SSLCiphers: anns.SSLCiphers,
SSLPassthrough: anns.SSLPassthrough,
SSLCiphers: anns.SSLCipher.SSLCiphers,
SSLPreferServerCiphers: anns.SSLCipher.SSLPreferServerCiphers,
}
}
}
@ -1094,8 +1095,13 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
}
// only add SSL ciphers if the server does not have them previously configured
if servers[host].SSLCiphers == "" && anns.SSLCiphers != "" {
servers[host].SSLCiphers = anns.SSLCiphers
if servers[host].SSLCiphers == "" && anns.SSLCipher.SSLCiphers != "" {
servers[host].SSLCiphers = anns.SSLCipher.SSLCiphers
}
// only add SSLPreferServerCiphers if the server does not have them previously configured
if servers[host].SSLPreferServerCiphers == "" && anns.SSLCipher.SSLPreferServerCiphers != "" {
servers[host].SSLPreferServerCiphers = anns.SSLCipher.SSLPreferServerCiphers
}
// only add a certificate if the server does not have one previously configured

View file

@ -343,17 +343,10 @@ func (n *NGINXController) Start() {
// issues because of this behavior.
// To avoid this issue we restart nginx in case of errors.
if process.IsRespawnIfRequired(err) {
process.WaitUntilPortIsAvailable(n.cfg.ListenPorts.HTTP)
// release command resources
cmd.Process.Release()
// start a new nginx master process if the controller is not being stopped
cmd = n.command.ExecCommand()
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pgid: 0,
}
n.start(cmd)
return
}
case event := <-n.updateCh.Out():
if n.isShuttingDown {
break

View file

@ -17,14 +17,9 @@ limitations under the License.
package process
import (
"fmt"
"net"
"os"
"os/exec"
"syscall"
"time"
"github.com/ncabatoff/process-exporter/proc"
"k8s.io/klog"
)
@ -43,41 +38,3 @@ NGINX master process died (%v): %v
`, waitStatus.ExitStatus(), err)
return true
}
// WaitUntilPortIsAvailable waits until there is no NGINX master or worker
// process/es listening in a particular port.
func WaitUntilPortIsAvailable(port int) {
// we wait until the workers are killed
for {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("0.0.0.0:%v", port), 1*time.Second)
if err != nil {
break
}
conn.Close()
// kill nginx worker processes
fs, err := proc.NewFS("/proc", false)
if err != nil {
klog.Errorf("unexpected error reading /proc information: %v", err)
continue
}
procs, _ := fs.FS.AllProcs()
for _, p := range procs {
pn, err := p.Comm()
if err != nil {
klog.Errorf("unexpected error obtaining process information: %v", err)
continue
}
if pn == "nginx" {
osp, err := os.FindProcess(p.PID)
if err != nil {
klog.Errorf("unexpected error obtaining process information: %v", err)
continue
}
osp.Signal(syscall.SIGQUIT)
}
}
time.Sleep(100 * time.Millisecond)
}
}

View file

@ -261,10 +261,24 @@ func New(
store.listers.IngressWithAnnotation.Store = cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)
// As we currently do not filter out kubernetes objects we list, we can
// retrieve a huge amount of data from the API server.
// In a cluster using HELM < v3 configmaps are used to store binary data.
// If you happen to have a lot of HELM releases in the cluster it will make
// the memory consumption of nginx-ingress-controller explode.
// In order to avoid that we filter out labels OWNER=TILLER.
tweakListOptionsFunc := func(options *metav1.ListOptions) {
if len(options.LabelSelector) > 0 {
options.LabelSelector += ",OWNER!=TILLER"
} else {
options.LabelSelector = "OWNER!=TILLER"
}
}
// create informers factory, enable and assign required informers
infFactory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
informers.WithNamespace(namespace),
informers.WithTweakListOptions(func(*metav1.ListOptions) {}))
informers.WithTweakListOptions(tweakListOptionsFunc))
if k8s.IsNetworkingIngressAvailable {
store.informers.Ingress = infFactory.Networking().V1beta1().Ingresses().Informer()

View file

@ -1229,18 +1229,17 @@ func commonListenOptions(template config.TemplateConfig, hostname string) string
func httpListener(addresses []string, co string, tc config.TemplateConfig) []string {
out := make([]string, 0)
for _, address := range addresses {
l := make([]string, 0)
l = append(l, "listen")
lo := []string{"listen"}
if address == "" {
l = append(l, fmt.Sprintf("%v", tc.ListenPorts.HTTP))
lo = append(lo, fmt.Sprintf("%v", tc.ListenPorts.HTTP))
} else {
l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTP))
lo = append(lo, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTP))
}
l = append(l, co)
l = append(l, ";")
out = append(out, strings.Join(l, " "))
lo = append(lo, co)
lo = append(lo, ";")
out = append(out, strings.Join(lo, " "))
}
return out
@ -1249,38 +1248,35 @@ func httpListener(addresses []string, co string, tc config.TemplateConfig) []str
func httpsListener(addresses []string, co string, tc config.TemplateConfig) []string {
out := make([]string, 0)
for _, address := range addresses {
l := make([]string, 0)
l = append(l, "listen")
lo := []string{"listen"}
if tc.IsSSLPassthroughEnabled {
if address == "" {
l = append(l, fmt.Sprintf("%v", tc.ListenPorts.SSLProxy))
lo = append(lo, fmt.Sprintf("%v", tc.ListenPorts.SSLProxy))
} else {
l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.SSLProxy))
lo = append(lo, fmt.Sprintf("%v:%v", address, tc.ListenPorts.SSLProxy))
}
l = append(l, "proxy_protocol")
if !strings.Contains(co, "proxy_protocol") {
lo = append(lo, "proxy_protocol")
}
} else {
if address == "" {
l = append(l, fmt.Sprintf("%v", tc.ListenPorts.HTTPS))
lo = append(lo, fmt.Sprintf("%v", tc.ListenPorts.HTTPS))
} else {
l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTPS))
}
if tc.Cfg.UseProxyProtocol {
l = append(l, "proxy_protocol")
lo = append(lo, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTPS))
}
}
l = append(l, co)
l = append(l, "ssl")
lo = append(lo, co)
lo = append(lo, "ssl")
if tc.Cfg.UseHTTP2 {
l = append(l, "http2")
lo = append(lo, "http2")
}
l = append(l, ";")
out = append(out, strings.Join(l, " "))
lo = append(lo, ";")
out = append(out, strings.Join(lo, " "))
}
return out

View file

@ -200,6 +200,9 @@ type Server struct {
ServerSnippet string `json:"serverSnippet"`
// SSLCiphers returns list of ciphers to be enabled
SSLCiphers string `json:"sslCiphers,omitempty"`
// SSLPreferServerCiphers indicates that server ciphers should be preferred
// over client ciphers when using the SSLv3 and TLS protocols.
SSLPreferServerCiphers string `sslPreferServerCiphers,omitempty`
// AuthTLSError contains the reason why the access to a server should be denied
AuthTLSError string `json:"authTLSError,omitempty"`
}

View file

@ -308,6 +308,9 @@ func (s1 *Server) Equal(s2 *Server) bool {
if s1.SSLCiphers != s2.SSLCiphers {
return false
}
if s1.SSLPreferServerCiphers != s2.SSLPreferServerCiphers {
return false
}
if s1.AuthTLSError != s2.AuthTLSError {
return false
}

View file

@ -1,3 +1,5 @@
// +build linux
/*
Copyright 2018 The Kubernetes Authors.

View file

@ -0,0 +1,28 @@
// +build !linux
/*
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 runtime
import (
"runtime"
)
// NumCPU ...
func NumCPU() int {
return runtime.NumCPU()
}