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
}