Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrects the behaviour of default-ssl-certificate #170

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c0aca18
Fix rate limit issue when more than 2 servers enabled in ingress
tangle329 Jan 24, 2017
725f45b
Corrects the behaviour of default-ssl-certificate
rikatz Jan 24, 2017
a173549
Merge 725f45b996e839f05d1a0f6e608a15fde3297d67 into 40406b148061ede71…
rikatz Jan 24, 2017
07ff578
Removes the need of configuring a default ssl certificate
Jan 25, 2017
f5706d1
prefect unit test cases for core.pkg.ingress.controller.util
chentao11596 Jan 24, 2017
0245868
prefect unit test cases for core.pkg.ingress.controller.annotations
chentao11596 Jan 25, 2017
93c7128
add unit test cases for core.pkg.ingress.sort_ingress
chentao11596 Jan 25, 2017
800d680
Merge pull request #172 from chentao1596/prefect-util-test
aledbf Jan 25, 2017
099fba2
Merge pull request #165 from tangle329/master
aledbf Jan 25, 2017
96df5b3
Clarify usage of Ingress backend.servicePort
jrynyt Jan 25, 2017
08eda50
Update nginx to 1.11.9
aledbf Jan 25, 2017
b7fab72
Merge pull request #173 from jrynyt/ingress-port-clarification
bprashanth Jan 25, 2017
0f7102a
Merge pull request #174 from aledbf/update-nginx-1119
bprashanth Jan 25, 2017
bc810d8
Fix TLS does not get updated when changed
aledbf Jan 26, 2017
ec67f83
Refactoring sysctlFSFileMax helper
aledbf Jan 26, 2017
b134472
Merge pull request #176 from aledbf/fix-ssl-update
aledbf Jan 26, 2017
92ddc6c
Merge pull request #177 from aledbf/fix-rlimit-issues
aledbf Jan 26, 2017
9c73ca4
Changes the behaviour of default ssl cert
Jan 26, 2017
9b26b9a
Merge branch 'defaultsslcert' of https://github.com/rikatz/ingress in…
Jan 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion controllers/gce/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ __Lines 5-7__: Ingress Spec has all the information needed to configure a GCE L7

__Lines 8-9__: Each http rule contains the following information: A host (eg: foo.bar.com, defaults to `*` in this example), a list of paths (eg: `/hostless`) each of which has an associated backend (`test:80`). Both the `host` and `path` must match the content of an incoming request before the L7 directs traffic to the `backend`.

__Lines 10-12__: A `backend` is a service:port combination. It selects a group of pods capable of servicing traffic sent to the path specified in the parent rule.
__Lines 10-12__: A `backend` is a service:port combination. It selects a group of pods capable of servicing traffic sent to the path specified in the parent rule. The `port` is the desired `spec.ports[*].port` from the Service Spec -- Note, though, that the L7 actually directs traffic to the corresponding `NodePort`.

__Global Prameters__: For the sake of simplicity the example Ingress has no global parameters. However, one can specify a default backend (see examples below) in the absence of which requests that don't match a path in the spec are sent to the default backend of glbc. Though glbc doesn't support HTTPS yet, security configs would also be global.

Expand Down
9 changes: 5 additions & 4 deletions controllers/nginx/pkg/cmd/controller/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"syscall"

"k8s.io/kubernetes/pkg/util/sysctl"

Expand All @@ -42,14 +43,14 @@ func sysctlSomaxconn() int {
// sysctlFSFileMax returns the value of fs.file-max, i.e.
// maximum number of open file descriptors
func sysctlFSFileMax() int {
maxConns, err := sysctl.New().GetSysctl("fs/file-max")
var rLimit syscall.Rlimit
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
glog.Errorf("unexpected error reading system maximum number of open file descriptors (fs.file-max): %v", err)
glog.Errorf("unexpected error reading system maximum number of open file descriptors (RLIMIT_NOFILE): %v", err)
// returning 0 means don't render the value
return 0
}

return maxConns
return int(rLimit.Max)
}

func diff(b1, b2 []byte) ([]byte, error) {
Expand Down
16 changes: 11 additions & 5 deletions controllers/nginx/pkg/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"strings"
text_template "text/template"

"k8s.io/kubernetes/pkg/util/sets"

"github.com/golang/glog"

"k8s.io/ingress/controllers/nginx/pkg/config"
Expand Down Expand Up @@ -328,11 +330,11 @@ func buildProxyPass(b interface{}, loc interface{}) string {
// rate limiting of request. Each Ingress rule could have up to two zones, one
// for connection limit by IP address and other for limiting request per second
func buildRateLimitZones(input interface{}) []string {
zones := []string{}
zones := sets.String{}

servers, ok := input.([]*ingress.Server)
if !ok {
return zones
return zones.List()
}

for _, server := range servers {
Expand All @@ -342,20 +344,24 @@ func buildRateLimitZones(input interface{}) []string {
zone := fmt.Sprintf("limit_conn_zone $binary_remote_addr zone=%v:%vm;",
loc.RateLimit.Connections.Name,
loc.RateLimit.Connections.SharedSize)
zones = append(zones, zone)
if !zones.Has(zone) {
zones.Insert(zone)
}
}

if loc.RateLimit.RPS.Limit > 0 {
zone := fmt.Sprintf("limit_req_zone $binary_remote_addr zone=%v:%vm rate=%vr/s;",
loc.RateLimit.RPS.Name,
loc.RateLimit.RPS.SharedSize,
loc.RateLimit.RPS.Limit)
zones = append(zones, zone)
if !zones.Has(zone) {
zones.Insert(zone)
}
}
}
}

return zones
return zones.List()
}

// buildRateLimit produces an array of limit_req to be used inside the Path of
Expand Down
2 changes: 1 addition & 1 deletion controllers/nginx/rootfs/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

FROM gcr.io/google_containers/nginx-slim:0.12
FROM gcr.io/google_containers/nginx-slim:0.13

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
diffutils \
Expand Down
2 changes: 1 addition & 1 deletion controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ http {
server_name {{ $server.Hostname }};
listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $index 0 }} ipv6only=off{{end}}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}};
{{/* Listen on 442 because port 443 is used in the stream section */}}
{{ if not (empty $server.SSLCertificate) }}listen 442 {{ if $cfg.UseProxyProtocol }}proxy_protocol{{ end }} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};
{{ if not (empty $server.SSLCertificate) }}listen 442 {{ if $cfg.UseProxyProtocol }}proxy_protocol{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};
{{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}}
# PEM sha: {{ $server.SSLPemChecksum }}
ssl_certificate {{ $server.SSLCertificate }};
Expand Down
89 changes: 89 additions & 0 deletions core/pkg/ingress/controller/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ import (
"k8s.io/ingress/core/pkg/ingress/resolver"
)

const (
annotation_secureUpstream = "ingress.kubernetes.io/secure-backends"
annotation_upsMaxFails = "ingress.kubernetes.io/upstream-max-fails"
annotation_upsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout"
annotation_passthrough = "ingress.kubernetes.io/ssl-passthrough"
)

type mockCfg struct {
}

Expand Down Expand Up @@ -90,3 +97,85 @@ func buildIngress() *extensions.Ingress {
},
}
}

func TestSecureUpstream(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ing := buildIngress()

fooAnns := []struct {
annotations map[string]string
er bool
}{
{map[string]string{annotation_secureUpstream: "true"}, true},
{map[string]string{annotation_secureUpstream: "false"}, false},
{map[string]string{annotation_secureUpstream + "_no": "true"}, false},
{map[string]string{}, false},
{nil, false},
}

for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.SecureUpstream(ing)
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
}

func TestHealthCheck(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ing := buildIngress()

fooAnns := []struct {
annotations map[string]string
eumf int
euft int
}{
{map[string]string{annotation_upsMaxFails: "3", annotation_upsFailTimeout: "10"}, 3, 10},
{map[string]string{annotation_upsMaxFails: "3"}, 3, 0},
{map[string]string{annotation_upsFailTimeout: "10"}, 0, 10},
{map[string]string{}, 0, 0},
{nil, 0, 0},
}

for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.HealthCheck(ing)
if r == nil {
t.Errorf("Returned nil but expected a healthcheck.Upstream")
continue
}

if r.FailTimeout != foo.euft {
t.Errorf("Returned %d but expected %d for FailTimeout", r.FailTimeout, foo.euft)
}

if r.MaxFails != foo.eumf {
t.Errorf("Returned %d but expected %d for MaxFails", r.MaxFails, foo.eumf)
}
}
}

func TestSSLPassthrough(t *testing.T) {
ec := newAnnotationExtractor(mockCfg{})
ing := buildIngress()

fooAnns := []struct {
annotations map[string]string
er bool
}{
{map[string]string{annotation_passthrough: "true"}, true},
{map[string]string{annotation_passthrough: "false"}, false},
{map[string]string{annotation_passthrough + "_no": "true"}, false},
{map[string]string{}, false},
{nil, false},
}

for _, foo := range fooAnns {
ing.SetAnnotations(foo.annotations)
r := ec.SSLPassthrough(ing)
if r != foo.er {
t.Errorf("Returned %v but expected %v", r, foo.er)
}
}
}
47 changes: 45 additions & 2 deletions core/pkg/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

"github.com/golang/glog"
"github.com/kylelemons/godebug/pretty"

"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
Expand All @@ -46,6 +47,7 @@ import (
"k8s.io/ingress/core/pkg/ingress/resolver"
"k8s.io/ingress/core/pkg/ingress/status"
"k8s.io/ingress/core/pkg/k8s"
ssl "k8s.io/ingress/core/pkg/net/ssl"
local_strings "k8s.io/ingress/core/pkg/strings"
"k8s.io/ingress/core/pkg/task"
)
Expand Down Expand Up @@ -178,6 +180,7 @@ func newIngressController(config *Configuration) *GenericController {
ic.syncQueue.Enqueue(obj)
},
UpdateFunc: func(old, cur interface{}) {
oldIng := old.(*extensions.Ingress)
curIng := cur.(*extensions.Ingress)
if !IsValidClass(curIng, config.IngressClass) {
return
Expand All @@ -186,6 +189,24 @@ func newIngressController(config *Configuration) *GenericController {
if !reflect.DeepEqual(old, cur) {
upIng := cur.(*extensions.Ingress)
ic.recorder.Eventf(upIng, api.EventTypeNormal, "UPDATE", fmt.Sprintf("Ingress %s/%s", upIng.Namespace, upIng.Name))
// the referenced secret is different?
if diff := pretty.Compare(curIng.Spec.TLS, oldIng.Spec.TLS); diff != "" {
for _, secretName := range curIng.Spec.TLS {
secKey := fmt.Sprintf("%v/%v", curIng.Namespace, secretName.SecretName)
go func() {
glog.Infof("TLS section in ingress %v/%v changed (secret is now %v)", upIng.Namespace, upIng.Name, secKey)
// we need to wait until the ingress store is updated
time.Sleep(10 * time.Second)
key, err := ic.GetSecret(secKey)
if err != nil {
glog.Errorf("unexpected error: %v", err)
}
if key != nil {
ic.secretQueue.Enqueue(key)
}
}()
}
}
ic.syncQueue.Enqueue(cur)
}
},
Expand Down Expand Up @@ -807,9 +828,30 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str

dun := ic.getDefaultUpstream().Name

// This adds the Default Certificate to Default Backend and also for vhosts missing the secret
var defaultPemFileName, defaultPemSHA string
defaultCertificate, err := ic.getPemCertificate(ic.cfg.DefaultSSLCertificate)
// If no default Certificate was supplied, tries to generate a new dumb one
if err != nil {
var cert *ingress.SSLCert
defCert, defKey := ssl.GetFakeSSLCert()
cert, err = ssl.AddOrUpdateCertAndKey("system-snake-oil-certificate", defCert, defKey, []byte{})
if err != nil {
glog.Fatalf("Error generating self signed certificate: %v", err)
} else {
defaultPemFileName = cert.PemFileName
defaultPemSHA = cert.PemSHA
}
} else {
defaultPemFileName = defaultCertificate.PemFileName
defaultPemSHA = defaultCertificate.PemSHA
}

// default server
servers[defServerName] = &ingress.Server{
Hostname: defServerName,
Hostname: defServerName,
SSLCertificate: defaultPemFileName,
SSLPemChecksum: defaultPemSHA,
Locations: []*ingress.Location{
{
Path: rootLocation,
Expand Down Expand Up @@ -879,7 +921,8 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str
servers[host].SSLPemChecksum = cert.PemSHA
}
} else {
glog.Warningf("secret %v does not exists", key)
servers[host].SSLCertificate = defaultPemFileName
servers[host].SSLPemChecksum = defaultPemSHA
}
}

Expand Down
10 changes: 5 additions & 5 deletions core/pkg/ingress/controller/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ func NewIngressController(backend ingress.Controller) *GenericController {
tcpConfigMapName = flags.String("tcp-services-configmap", "",
`Name of the ConfigMap that contains the definition of the TCP 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
service with the format namespace/serviceName and the port of the service could be a
number of the name of the port.
The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend`)

udpConfigMapName = flags.String("udp-services-configmap", "",
`Name of the ConfigMap that contains 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
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", 60*time.Second,
Expand All @@ -74,13 +74,13 @@ func NewIngressController(backend ingress.Controller) *GenericController {

profiling = flags.Bool("profiling", true, `Enable profiling via web interface host:port/debug/pprof/`)

defSSLCertificate = flags.String("default-ssl-certificate", "", `Name of the secret
defSSLCertificate = flags.String("default-ssl-certificate", "", `Name of the secret
that contains a SSL certificate to be used as default for a HTTPS catch-all server`)

defHealthzURL = flags.String("health-check-path", "/healthz", `Defines
defHealthzURL = flags.String("health-check-path", "/healthz", `Defines
the URL to be used as health check inside in the default server in NGINX.`)

updateStatus = flags.Bool("update-status", true, `Indicates if the
updateStatus = flags.Bool("update-status", true, `Indicates if the
ingress controller should update the Ingress status IP/hostname. Default is true`)
)

Expand Down
Loading