1
0
Fork 0

Merge current v2.5 into master

This commit is contained in:
romain 2021-08-30 14:51:57 +02:00
commit f81ceaef8a
64 changed files with 949 additions and 208 deletions

View file

@ -24,7 +24,7 @@ func DecodeToNode(pairs []*store.KVPair, rootName string, filters ...string) (*p
return nil, fmt.Errorf("invalid label root %s", rootName)
}
split := strings.Split(pair.Key[len(rootName)+1:], "/")
split := strings.FieldsFunc(pair.Key[len(rootName)+1:], func(c rune) bool { return c == '/' })
parts := []string{rootName}
for _, fragment := range split {

View file

@ -28,6 +28,7 @@ func TestDecode(t *testing.T) {
"traefik/fieldf/Test2": "B",
"traefik/fieldg/0/name": "A",
"traefik/fieldg/1/name": "B",
"traefik/fieldh/": "foo",
},
expected: &sample{
FieldA: "bar",
@ -45,6 +46,7 @@ func TestDecode(t *testing.T) {
{Name: "A"},
{Name: "B"},
},
FieldH: "foo",
},
},
{
@ -61,6 +63,7 @@ func TestDecode(t *testing.T) {
"foo/bar/traefik/fieldf/Test2": "B",
"foo/bar/traefik/fieldg/0/name": "A",
"foo/bar/traefik/fieldg/1/name": "B",
"foo/bar/traefik/fieldh/": "foo",
},
expected: &sample{
FieldA: "bar",
@ -78,6 +81,7 @@ func TestDecode(t *testing.T) {
{Name: "A"},
{Name: "B"},
},
FieldH: "foo",
},
},
}
@ -107,6 +111,7 @@ type sample struct {
} `label:"allowEmpty"`
FieldF map[string]string
FieldG []sub
FieldH string
}
type sub struct {

View file

@ -27,6 +27,12 @@ func TestIsAuthorized(t *testing.T) {
remoteAddr: "1.2.3.1:123",
authorized: true,
},
{
desc: "octal ip in remoteAddr",
whiteList: []string{"127.2.3.4/24"},
remoteAddr: "0127.2.3.1:123",
authorized: false,
},
}
for _, test := range testCases {

View file

@ -15,6 +15,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/middlewares/connectionheader"
"github.com/traefik/traefik/v2/pkg/tracing"
"github.com/vulcand/oxy/forward"
"github.com/vulcand/oxy/utils"
@ -89,7 +90,7 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
fa.authResponseHeadersRegex = re
}
return fa, nil
return connectionheader.Remover(fa), nil
}
func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) {

View file

@ -0,0 +1,46 @@
package connectionheader
import (
"net/http"
"net/textproto"
"strings"
"golang.org/x/net/http/httpguts"
)
const (
connectionHeader = "Connection"
upgradeHeader = "Upgrade"
)
// Remover removes hop-by-hop headers listed in the "Connection" header.
// See RFC 7230, section 6.1.
func Remover(next http.Handler) http.HandlerFunc {
return func(rw http.ResponseWriter, req *http.Request) {
var reqUpType string
if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) {
reqUpType = req.Header.Get(upgradeHeader)
}
removeConnectionHeaders(req.Header)
if reqUpType != "" {
req.Header.Set(connectionHeader, upgradeHeader)
req.Header.Set(upgradeHeader, reqUpType)
} else {
req.Header.Del(connectionHeader)
}
next.ServeHTTP(rw, req)
}
}
func removeConnectionHeaders(h http.Header) {
for _, f := range h[connectionHeader] {
for _, sf := range strings.Split(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
h.Del(sf)
}
}
}
}

View file

@ -0,0 +1,71 @@
package connectionheader
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestRemover(t *testing.T) {
testCases := []struct {
desc string
reqHeaders map[string]string
expected http.Header
}{
{
desc: "simple remove",
reqHeaders: map[string]string{
"Foo": "bar",
connectionHeader: "foo",
},
expected: http.Header{},
},
{
desc: "remove and Upgrade",
reqHeaders: map[string]string{
upgradeHeader: "test",
"Foo": "bar",
connectionHeader: "Upgrade,foo",
},
expected: http.Header{
upgradeHeader: []string{"test"},
connectionHeader: []string{"Upgrade"},
},
},
{
desc: "no remove",
reqHeaders: map[string]string{
"Foo": "bar",
connectionHeader: "fii",
},
expected: http.Header{
"Foo": []string{"bar"},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
h := Remover(next)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
for k, v := range test.reqHeaders {
req.Header.Set(k, v)
}
rw := httptest.NewRecorder()
h.ServeHTTP(rw, req)
assert.Equal(t, test.expected, req.Header)
})
}
}

View file

@ -10,6 +10,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/middlewares/connectionheader"
"github.com/traefik/traefik/v2/pkg/tracing"
)
@ -68,11 +69,12 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin
if hasCustomHeaders || hasCorsHeaders {
logger.Debugf("Setting up customHeaders/Cors from %v", cfg)
var err error
handler, err = NewHeader(nextHandler, cfg)
h, err := NewHeader(nextHandler, cfg)
if err != nil {
return nil, err
}
handler = connectionheader.Remover(h)
}
return &headers{

View file

@ -22,13 +22,18 @@ type responseModifier struct {
}
// modifier can be nil.
func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) *responseModifier {
return &responseModifier{
func newResponseModifier(w http.ResponseWriter, r *http.Request, modifier func(*http.Response) error) http.ResponseWriter {
rm := &responseModifier{
req: r,
rw: w,
modifier: modifier,
code: http.StatusOK,
}
if _, ok := w.(http.CloseNotifier); ok {
return responseModifierWithCloseNotify{responseModifier: rm}
}
return rm
}
func (r *responseModifier) WriteHeader(code int) {
@ -93,7 +98,11 @@ func (r *responseModifier) Flush() {
}
}
// CloseNotify implements http.CloseNotifier.
func (r *responseModifier) CloseNotify() <-chan bool {
return r.rw.(http.CloseNotifier).CloseNotify()
type responseModifierWithCloseNotify struct {
*responseModifier
}
// CloseNotify implements http.CloseNotifier.
func (r *responseModifierWithCloseNotify) CloseNotify() <-chan bool {
return r.responseModifier.rw.(http.CloseNotifier).CloseNotify()
}

View file

@ -4,13 +4,17 @@ import (
"net/http"
"net/url"
"regexp"
"strings"
"github.com/opentracing/opentracing-go/ext"
"github.com/traefik/traefik/v2/pkg/tracing"
"github.com/vulcand/oxy/utils"
)
const (
schemeHTTP = "http"
schemeHTTPS = "https"
)
type redirect struct {
next http.Handler
regex *regexp.Regexp
@ -18,10 +22,11 @@ type redirect struct {
permanent bool
errHandler utils.ErrorHandler
name string
rawURL func(*http.Request) string
}
// New creates a Redirect middleware.
func newRedirect(next http.Handler, regex, replacement string, permanent bool, name string) (http.Handler, error) {
func newRedirect(next http.Handler, regex, replacement string, permanent bool, rawURL func(*http.Request) string, name string) (http.Handler, error) {
re, err := regexp.Compile(regex)
if err != nil {
return nil, err
@ -34,6 +39,7 @@ func newRedirect(next http.Handler, regex, replacement string, permanent bool, n
errHandler: utils.DefaultHandler,
next: next,
name: name,
rawURL: rawURL,
}, nil
}
@ -42,7 +48,7 @@ func (r *redirect) GetTracingInformation() (string, ext.SpanKindEnum) {
}
func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
oldURL := rawURL(req)
oldURL := r.rawURL(req)
// If the Regexp doesn't match, skip to the next handler.
if !r.regex.MatchString(oldURL) {
@ -98,33 +104,3 @@ func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}
func rawURL(req *http.Request) string {
scheme := "http"
host := req.Host
port := ""
uri := req.RequestURI
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
re, _ := regexp.Compile(schemeRegex)
if re.Match([]byte(req.RequestURI)) {
match := re.FindStringSubmatch(req.RequestURI)
scheme = match[1]
if len(match[2]) > 0 {
host = match[2]
}
if len(match[3]) > 0 {
port = match[3]
}
uri = match[4]
}
if req.TLS != nil {
scheme = "https"
}
return strings.Join([]string{scheme, "://", host, port, uri}, "")
}

View file

@ -3,6 +3,8 @@ package redirect
import (
"context"
"net/http"
"regexp"
"strings"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
@ -19,5 +21,35 @@ func NewRedirectRegex(ctx context.Context, next http.Handler, conf dynamic.Redir
logger.Debug("Creating middleware")
logger.Debugf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, name)
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, rawURL, name)
}
func rawURL(req *http.Request) string {
scheme := schemeHTTP
host := req.Host
port := ""
uri := req.RequestURI
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
re, _ := regexp.Compile(schemeRegex)
if re.Match([]byte(req.RequestURI)) {
match := re.FindStringSubmatch(req.RequestURI)
scheme = match[1]
if len(match[2]) > 0 {
host = match[2]
}
if len(match[3]) > 0 {
port = match[3]
}
uri = match[4]
}
if req.TLS != nil {
scheme = schemeHTTPS
}
return strings.Join([]string{scheme, "://", host, port, uri}, "")
}

View file

@ -3,7 +3,10 @@ package redirect
import (
"context"
"errors"
"net"
"net/http"
"regexp"
"strings"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
@ -26,9 +29,47 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
}
port := ""
if len(conf.Port) > 0 && !(conf.Scheme == "http" && conf.Port == "80" || conf.Scheme == "https" && conf.Port == "443") {
if len(conf.Port) > 0 && !(conf.Scheme == schemeHTTP && conf.Port == "80" || conf.Scheme == schemeHTTPS && conf.Port == "443") {
port = ":" + conf.Port
}
return newRedirect(next, schemeRedirectRegex, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, name)
return newRedirect(next, schemeRedirectRegex, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, rawURLScheme, name)
}
func rawURLScheme(req *http.Request) string {
scheme := schemeHTTP
host, port, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
} else {
port = ":" + port
}
uri := req.RequestURI
schemeRegex := `^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
re, _ := regexp.Compile(schemeRegex)
if re.Match([]byte(req.RequestURI)) {
match := re.FindStringSubmatch(req.RequestURI)
scheme = match[1]
if len(match[2]) > 0 {
host = match[2]
}
if len(match[3]) > 0 {
port = match[3]
}
uri = match[4]
}
if req.TLS != nil {
scheme = schemeHTTPS
}
if scheme == schemeHTTP && port == ":80" || scheme == schemeHTTPS && port == ":443" || port == "" {
port = ""
}
return strings.Join([]string{scheme, "://", host, port, uri}, "")
}

View file

@ -127,8 +127,18 @@ func TestRedirectSchemeHandler(t *testing.T) {
Port: "80",
},
url: "http://foo:80",
expectedURL: "http://foo",
expectedStatus: http.StatusFound,
expectedURL: "http://foo:80",
expectedStatus: http.StatusOK,
},
{
desc: "to HTTPS 443",
config: dynamic.RedirectScheme{
Scheme: "https",
Port: "443",
},
url: "https://foo:443",
expectedURL: "https://foo:443",
expectedStatus: http.StatusOK,
},
{
desc: "HTTP to wss",
@ -248,6 +258,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
if test.method != "" {
method = test.method
}
req := httptest.NewRequest(method, test.url, nil)
for k, v := range test.headers {

View file

@ -11,6 +11,15 @@ type statusCodeRecoder interface {
Status() int
}
// newStatusCodeRecoder returns an initialized statusCodeRecoder.
func newStatusCodeRecoder(rw http.ResponseWriter, status int) statusCodeRecoder {
recorder := &statusCodeWithoutCloseNotify{rw, status}
if _, ok := rw.(http.CloseNotifier); ok {
return &statusCodeWithCloseNotify{recorder}
}
return recorder
}
type statusCodeWithoutCloseNotify struct {
http.ResponseWriter
status int
@ -46,12 +55,3 @@ type statusCodeWithCloseNotify struct {
func (s *statusCodeWithCloseNotify) CloseNotify() <-chan bool {
return s.ResponseWriter.(http.CloseNotifier).CloseNotify()
}
// newStatusCodeRecoder returns an initialized statusCodeRecoder.
func newStatusCodeRecoder(rw http.ResponseWriter, status int) statusCodeRecoder {
recorder := &statusCodeWithoutCloseNotify{rw, status}
if _, ok := rw.(http.CloseNotifier); ok {
return &statusCodeWithCloseNotify{recorder}
}
return recorder
}

View file

@ -28,6 +28,15 @@ spec:
port: 80
middlewares:
- name: test-errorpage
- match: Host(`foo.com`) && PathPrefix(`/bur`)
kind: Rule
priority: 12
services:
- name: whoami
namespace: default
port: 80
middlewares:
- name: cross-ns-stripprefix@kubernetescrd
---
apiVersion: traefik.containo.us/v1alpha1

View file

@ -703,6 +703,12 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
id = tlsOption.Name
nsDefault = append(nsDefault, tlsOption.Namespace)
}
alpnProtocols := tls.DefaultTLSOptions.ALPNProtocols
if len(tlsOption.Spec.ALPNProtocols) > 0 {
alpnProtocols = tlsOption.Spec.ALPNProtocols
}
tlsOptions[id] = tls.Options{
MinVersion: tlsOption.Spec.MinVersion,
MaxVersion: tlsOption.Spec.MaxVersion,
@ -714,6 +720,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
},
SniStrict: tlsOption.Spec.SniStrict,
PreferServerCipherSuites: tlsOption.Spec.PreferServerCipherSuites,
ALPNProtocols: alpnProtocols,
}
}

View file

@ -147,13 +147,23 @@ func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace str
var mds []string
for _, mi := range middlewares {
if strings.Contains(mi.Name, providerNamespaceSeparator) {
name := mi.Name
if !p.AllowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+providerName) {
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
// if the provider namespace kubernetescrd is used,
// we don't allow this format to avoid cross namespace references.
return nil, fmt.Errorf("invalid reference to middleware %s: with crossnamespace disallowed, the namespace field needs to be explicitly specified", mi.Name)
}
if strings.Contains(name, providerNamespaceSeparator) {
if len(mi.Namespace) > 0 {
log.FromContext(ctx).
WithField(log.MiddlewareName, mi.Name).
Warnf("namespace %q is ignored in cross-provider context", mi.Namespace)
}
mds = append(mds, mi.Name)
mds = append(mds, name)
continue
}
@ -166,7 +176,7 @@ func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace str
ns = mi.Namespace
}
mds = append(mds, makeID(ns, mi.Name))
mds = append(mds, makeID(ns, name))
}
return mds, nil

View file

@ -616,6 +616,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
},
SniStrict: true,
PreferServerCipherSuites: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -678,6 +683,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
ClientAuthType: "VerifyClientCertIfGiven",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -739,6 +749,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
ClientAuthType: "VerifyClientCertIfGiven",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -789,6 +804,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
Options: map[string]tls.Options{
"default-foo": {
MinVersion: "VersionTLS12",
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -839,6 +859,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
Options: map[string]tls.Options{
"default-foo": {
MinVersion: "VersionTLS12",
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2539,6 +2564,11 @@ func TestLoadIngressRoutes(t *testing.T) {
},
SniStrict: true,
PreferServerCipherSuites: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2648,6 +2678,11 @@ func TestLoadIngressRoutes(t *testing.T) {
},
SniStrict: true,
PreferServerCipherSuites: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2716,6 +2751,11 @@ func TestLoadIngressRoutes(t *testing.T) {
ClientAuthType: "VerifyClientCertIfGiven",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2779,6 +2819,11 @@ func TestLoadIngressRoutes(t *testing.T) {
ClientAuthType: "VerifyClientCertIfGiven",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2831,6 +2876,11 @@ func TestLoadIngressRoutes(t *testing.T) {
Options: map[string]tls.Options{
"default-foo": {
MinVersion: "VersionTLS12",
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -2883,6 +2933,11 @@ func TestLoadIngressRoutes(t *testing.T) {
Options: map[string]tls.Options{
"default-foo": {
MinVersion: "VersionTLS12",
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
@ -4313,6 +4368,13 @@ func TestCrossNamespace(t *testing.T) {
Priority: 12,
Middlewares: []string{"default-test-errorpage"},
},
"default-test-crossnamespace-route-a1963878aac7331b7950": {
EntryPoints: []string{"foo"},
Service: "default-test-crossnamespace-route-a1963878aac7331b7950",
Rule: "Host(`foo.com`) && PathPrefix(`/bur`)",
Priority: 12,
Middlewares: []string{"cross-ns-stripprefix@kubernetescrd"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"cross-ns-stripprefix": {
@ -4369,6 +4431,19 @@ func TestCrossNamespace(t *testing.T) {
PassHostHeader: Bool(true),
},
},
"default-test-crossnamespace-route-a1963878aac7331b7950": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},

View file

@ -27,6 +27,7 @@ type TLSOptionSpec struct {
ClientAuth ClientAuth `json:"clientAuth,omitempty"`
SniStrict bool `json:"sniStrict,omitempty"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty"`
ALPNProtocols []string `json:"alpnProtocols,omitempty"`
}
// +k8s:deepcopy-gen=true

View file

@ -1327,6 +1327,11 @@ func (in *TLSOptionSpec) DeepCopyInto(out *TLSOptionSpec) {
copy(*out, *in)
}
in.ClientAuth.DeepCopyInto(&out.ClientAuth)
if in.ALPNProtocols != nil {
in, out := &in.ALPNProtocols, &out.ALPNProtocols
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View file

@ -417,7 +417,7 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *
}
if tlsModeType == v1alpha1.TLSModePassthrough && listener.TLS.CertificateRef != nil {
// https://gateway-api.sigs.k8s.io/guides/tls/
// https://gateway-api.sigs.k8s.io/v1alpha1/guides/tls/
logger.Warnf("In case of Passthrough TLS mode, no TLS settings take effect as the TLS session from the client is NOT terminated at the Gateway")
}
@ -900,7 +900,7 @@ func hostRule(httpRouteSpec v1alpha1.HTTPRouteSpec) (string, error) {
continue
}
// https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.Hostname
// https://gateway-api.sigs.k8s.io/v1alpha1/references/spec/#networking.x-k8s.io/v1alpha1.Hostname
if !strings.HasPrefix(host, "*.") || wildcard > 1 {
return "", fmt.Errorf("invalid rule: %q", host)
}

View file

@ -48,12 +48,10 @@ func objChanged(oldObj, newObj interface{}) bool {
}
if _, ok := oldObj.(*corev1.Endpoints); ok {
if endpointsChanged(oldObj.(*corev1.Endpoints), newObj.(*corev1.Endpoints)) {
return true
}
return endpointsChanged(oldObj.(*corev1.Endpoints), newObj.(*corev1.Endpoints))
}
return false
return true
}
func endpointsChanged(a, b *corev1.Endpoints) bool {

View file

@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -60,6 +61,33 @@ func Test_detectChanges(t *testing.T) {
},
},
},
{
name: "Ingress With same version",
oldObj: &v1.Ingress{
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: "1",
},
},
newObj: &v1.Ingress{
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: "1",
},
},
},
{
name: "Ingress With different version",
oldObj: &v1.Ingress{
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: "1",
},
},
newObj: &v1.Ingress{
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: "2",
},
},
want: true,
},
{
name: "With same annotations",
oldObj: &corev1.Endpoints{

View file

@ -848,6 +848,11 @@ func Test_buildConfiguration(t *testing.T) {
ClientAuthType: "foobar",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
"Options1": {
MinVersion: "foobar",
@ -868,6 +873,11 @@ func Test_buildConfiguration(t *testing.T) {
ClientAuthType: "foobar",
},
SniStrict: true,
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
Stores: map[string]tls.Store{

View file

@ -182,7 +182,13 @@ func Test_mergeConfiguration_tlsOptions(t *testing.T) {
desc: "Nil returns an empty configuration",
given: nil,
expected: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
},
{
@ -199,7 +205,13 @@ func Test_mergeConfiguration_tlsOptions(t *testing.T) {
},
},
expected: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
"foo@provider-1": {
MinVersion: "VersionTLS12",
},
@ -228,7 +240,13 @@ func Test_mergeConfiguration_tlsOptions(t *testing.T) {
},
},
expected: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
"foo@provider-1": {
MinVersion: "VersionTLS13",
},
@ -334,7 +352,13 @@ func Test_mergeConfiguration_tlsOptions(t *testing.T) {
},
},
expected: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
"foo@provider-1": {
MinVersion: "VersionTLS12",
},

View file

@ -76,7 +76,13 @@ func TestNewConfigurationWatcher(t *testing.T) {
},
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
Stores: map[string]tls.Store{},
},
@ -236,7 +242,13 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
},
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
Stores: map[string]tls.Store{},
},
@ -292,7 +304,13 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
},
TLS: &dynamic.TLSConfiguration{
Options: map[string]tls.Options{
"default": {},
"default": {
ALPNProtocols: []string{
"h2",
"http/1.1",
"acme-tls/1",
},
},
},
Stores: map[string]tls.Store{},
},

View file

@ -23,6 +23,13 @@ type Options struct {
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites,omitempty" toml:"preferServerCipherSuites,omitempty" yaml:"preferServerCipherSuites,omitempty" export:"true"`
ALPNProtocols []string `json:"alpnProtocols,omitempty" toml:"alpnProtocols,omitempty" yaml:"alpnProtocols,omitempty" export:"true"`
}
// SetDefaults sets the default values for an Options struct.
func (o *Options) SetDefaults() {
// ensure http2 enabled
o.ALPNProtocols = DefaultTLSOptions.ALPNProtocols
}
// +k8s:deepcopy-gen=true

View file

@ -24,7 +24,10 @@ const (
)
// DefaultTLSOptions the default TLS options.
var DefaultTLSOptions = Options{}
var DefaultTLSOptions = Options{
// ensure http2 enabled
ALPNProtocols: []string{"h2", "http/1.1", tlsalpn01.ACMETLS1Protocol},
}
// Manager is the TLS option/store/configuration factory.
type Manager struct {
@ -230,10 +233,9 @@ func buildCertificateStore(ctx context.Context, tlsStore Store, storename string
// creates a TLS config that allows terminating HTTPS for multiple domains using SNI.
func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
conf := &tls.Config{}
// ensure http2 enabled
conf.NextProtos = []string{"h2", "http/1.1", tlsalpn01.ACMETLS1Protocol}
conf := &tls.Config{
NextProtos: tlsOption.ALPNProtocols,
}
if len(tlsOption.ClientAuth.CAFiles) > 0 {
pool := x509.NewCertPool()

View file

@ -85,6 +85,11 @@ func (in *Options) DeepCopyInto(out *Options) {
copy(*out, *in)
}
in.ClientAuth.DeepCopyInto(&out.ClientAuth)
if in.ALPNProtocols != nil {
in, out := &in.ALPNProtocols, &out.ALPNProtocols
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}