Use system self signed certificate as default SSL certificate

This commit is contained in:
Manuel de Brito Fontes 2016-07-21 11:40:47 -04:00
parent 2c7d921d76
commit 9f64273b9c
7 changed files with 85 additions and 30 deletions

View file

@ -14,10 +14,12 @@
FROM gcr.io/google_containers/nginx-slim:0.8
RUN apt-get update && apt-get install -y \
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
diffutils \
ssl-cert \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
&& rm -rf /var/lib/apt/lists/* \
&& make-ssl-cert generate-default-snakeoil --force-overwrite
COPY nginx-ingress-controller /
COPY nginx.tmpl /etc/nginx/template/nginx.tmpl

View file

@ -138,16 +138,15 @@ Check the [example](examples/tls/README.md)
### Default SSL Certificate
NGINX provides the option [default_server](http://nginx.org/en/docs/http/server_names.html) to allow a catch-all server in case of request with a not configured server name. This configuration works without issues for HTTP traffic.
In case of HTTPS NGINX requires a certificate. For this reason the Ingress controller provides the flag `--default-ssl-certificate`. The secret behind this flag contains the default certificate to be used in the mentioned case.
If this flag is not provided NGINX will reject the request with the HTTP code 444.
NGINX provides the option serve rname [_](http://nginx.org/en/docs/http/server_names.html) as a catch-all in case of requests that do not match one of the configured server names. This configuration works without issues for HTTP traffic. In case of HTTPS NGINX requires a certificate. For this reason the Ingress controller provides the flag `--default-ssl-certificate`. The secret behind this flag contains the default certificate to be used in the mentioned case.
If this flag is not provided NGINX will use a self signed certificate.
Running without the flag `--default-ssl-certificate`:
```
$ curl -v https://10.2.78.7:443
$ curl -v https://10.2.78.7:443 -k
* Rebuilt URL to: https://10.2.78.7:443/
* Trying 10.2.78.7...
* Trying 10.2.78.4...
* Connected to 10.2.78.7 (10.2.78.7) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
@ -156,9 +155,39 @@ $ curl -v https://10.2.78.7:443
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* Unknown SSL protocol error in connection to 10.2.78.7:443
* Closing connection 0
curl: (35) Unknown SSL protocol error in connection to 10.2.78.7:443
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=foo.bar.com
* start date: Apr 13 00:50:56 2016 GMT
* expire date: Apr 13 00:50:56 2017 GMT
* issuer: CN=foo.bar.com
* SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: 10.2.78.7
> User-Agent: curl/7.47.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Server: nginx/1.11.1
< Date: Thu, 21 Jul 2016 15:38:46 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Strict-Transport-Security: max-age=15724800; includeSubDomains; preload
<
<span>The page you're looking for could not be found.</span>
* Connection #0 to host 10.2.78.7 left intact
```
Specifyng `--default-ssl-certificate=default/foo-tls`:

View file

@ -33,7 +33,7 @@ Please check the [custom configuration](examples/custom-configuration/README.md)
#### Annotations
The following annotaitons are supported:
The following annotations are supported:
|Name |type|
|---------------------------|------|

View file

@ -870,13 +870,22 @@ func (lbc *loadBalancerController) createServers(data []interface{}) map[string]
servers := make(map[string]*nginx.Server)
pems := lbc.getPemsFromIngress(data)
if lbc.defSSLCertificate != "" {
ngxCert, err := lbc.getPemCertificate(lbc.defSSLCertificate)
if err == nil {
pems["_"] = ngxCert
} else {
glog.Warningf("%v", err)
}
var ngxCert nginx.SSLCert
var err error
if lbc.defSSLCertificate == "" {
// use system certificated generated at image build time
cert, key := getFakeSSLCert()
ngxCert, err = lbc.nginx.AddOrUpdateCertAndKey("system-snake-oil-certificate", cert, key)
} else {
ngxCert, err = lbc.getPemCertificate(lbc.defSSLCertificate)
}
if err == nil {
pems["_"] = ngxCert
} else {
glog.Warningf("%v", err)
}
for _, ingIf := range data {

View file

@ -180,16 +180,6 @@ http {
{{ end }}
{{ range $server := .servers }}
{{/* Check for default SSL backend */}}
{{ if and (eq $server.Name "_") (not $server.SSL) -}}
server {
server_name {{ $server.Name }};
listen 443;
# return protocol error.
return 444;
}
{{ end }}
server {
server_name {{ $server.Name }};
listen 80{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }};
@ -289,8 +279,11 @@ http {
}
{{ end }}
# default server, including healthcheck
# default server, used for NGINX healthcheck and access to nginx stats
server {
# Use the port 18080 (random value just to avoid known ports) as default port for nginx.
# Changing this value requires a change in:
# https://github.com/kubernetes/contrib/blob/master/ingress/controllers/nginx/nginx/command.go#L104
listen 18080 default_server reuseport backlog={{ .backlogSize }};
location /healthz {

View file

@ -108,7 +108,7 @@ func (nginx *Manager) commonNames(pemFileName string) ([]string, error) {
cn = append(cn, cert.DNSNames...)
}
glog.V(2).Infof("found %v common names: %v\n", cn, len(cn))
glog.V(3).Infof("found %v common names: %v\n", cn, len(cn))
return cn, nil
}

View file

@ -18,6 +18,7 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
"time"
@ -273,3 +274,24 @@ func isNGINXIngress(ing *extensions.Ingress) bool {
class := ingAnnotations(ing.ObjectMeta.Annotations).ingressClass()
return class == "" || class == nginxIngressClass
}
const (
snakeOilPem = "/etc/ssl/certs/ssl-cert-snakeoil.pem"
snakeOilKey = "/etc/ssl/private/ssl-cert-snakeoil.key"
)
// getFakeSSLCert returns the snake oil ssl certificate created by the command
// make-ssl-cert generate-default-snakeoil --force-overwrite
func getFakeSSLCert() (string, string) {
cert, err := ioutil.ReadFile(snakeOilPem)
if err != nil {
return "", ""
}
key, err := ioutil.ReadFile(snakeOilKey)
if err != nil {
return "", ""
}
return string(cert), string(key)
}