Add ssl certificate verification

This commit is contained in:
Manuel de Brito Fontes 2016-03-18 21:41:31 -03:00
parent 5ed462db09
commit ffe6baa14c
6 changed files with 129 additions and 33 deletions

View file

@ -396,10 +396,20 @@ func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[st
continue continue
} }
cn, err := lbc.nginx.CheckSSLCertificate(secretName)
if err != nil {
glog.Warningf("No valid SSL certificate found in secret %v", secretName)
continue
}
pemFileName := lbc.nginx.AddOrUpdateCertAndKey(secretName, string(cert), string(key)) pemFileName := lbc.nginx.AddOrUpdateCertAndKey(secretName, string(cert), string(key))
for _, host := range tls.Hosts { for _, host := range tls.Hosts {
pems[host] = pemFileName if isHostValid(host, cn) {
pems[host] = pemFileName
} else {
glog.Warningf("SSL Certificate stored in secret %v is not valid for the host %v defined in the Ingress rule %v", secretName, host, ing.Name)
}
} }
} }
} }

View file

@ -16,13 +16,6 @@ limitations under the License.
package nginx package nginx
import (
"fmt"
"os"
"github.com/golang/glog"
)
// IngressNGINXConfig describes an NGINX configuration // IngressNGINXConfig describes an NGINX configuration
type IngressNGINXConfig struct { type IngressNGINXConfig struct {
Upstreams []Upstream Upstreams []Upstream
@ -35,7 +28,7 @@ type Upstream struct {
Backends []UpstreamServer Backends []UpstreamServer
} }
// UpstreamByNameServers Upstream sorter by name // UpstreamByNameServers sorts upstreams by name
type UpstreamByNameServers []*Upstream type UpstreamByNameServers []*Upstream
func (c UpstreamByNameServers) Len() int { return len(c) } func (c UpstreamByNameServers) Len() int { return len(c) }
@ -50,7 +43,7 @@ type UpstreamServer struct {
Port string Port string
} }
// UpstreamServerByAddrPort UpstreamServer sorter by address and port // UpstreamServerByAddrPort sorts upstream servers by address and port
type UpstreamServerByAddrPort []UpstreamServer type UpstreamServerByAddrPort []UpstreamServer
func (c UpstreamServerByAddrPort) Len() int { return len(c) } func (c UpstreamServerByAddrPort) Len() int { return len(c) }
@ -76,7 +69,7 @@ type Server struct {
SSLCertificateKey string SSLCertificateKey string
} }
// ServerByName Server sorter by name // ServerByName sorts server by name
type ServerByName []*Server type ServerByName []*Server
func (c ServerByName) Len() int { return len(c) } func (c ServerByName) Len() int { return len(c) }
@ -91,7 +84,7 @@ type Location struct {
Upstream Upstream Upstream Upstream
} }
// LocationByPath Location sorter by path // LocationByPath sorts location by path
type LocationByPath []Location type LocationByPath []Location
func (c LocationByPath) Len() int { return len(c) } func (c LocationByPath) Len() int { return len(c) }
@ -112,21 +105,3 @@ func NewUpstream(name string) *Upstream {
Backends: []UpstreamServer{}, Backends: []UpstreamServer{},
} }
} }
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
func (nginx *NginxManager) AddOrUpdateCertAndKey(name string, cert string, key string) string {
pemFileName := sslDirectory + "/" + name + ".pem"
pem, err := os.Create(pemFileName)
if err != nil {
glog.Fatalf("Couldn't create pem file %v: %v", pemFileName, err)
}
defer pem.Close()
_, err = pem.WriteString(fmt.Sprintf("%v\n%v", key, cert))
if err != nil {
glog.Fatalf("Couldn't write to pem file %v: %v", pemFileName, err)
}
return pemFileName
}

View file

@ -0,0 +1,72 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 nginx
import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"github.com/golang/glog"
)
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
func (nginx *NginxManager) AddOrUpdateCertAndKey(name string, cert string, key string) string {
pemFileName := sslDirectory + "/" + name + ".pem"
pem, err := os.Create(pemFileName)
if err != nil {
glog.Fatalf("Couldn't create pem file %v: %v", pemFileName, err)
}
defer pem.Close()
_, err = pem.WriteString(fmt.Sprintf("%v\n%v", key, cert))
if err != nil {
glog.Fatalf("Couldn't write to pem file %v: %v", pemFileName, err)
}
return pemFileName
}
// CheckSSLCertificate checks if the certificate and key file are valid
// returning the result of the validation and the list of hostnames
// contained in the common name/s
func (nginx *NginxManager) CheckSSLCertificate(secretName string) ([]string, error) {
pemFileName := sslDirectory + "/" + secretName + ".pem"
pemCerts, err := ioutil.ReadFile(pemFileName)
if err != nil {
return []string{}, err
}
var block *pem.Block
block, pemCerts = pem.Decode(pemCerts)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return []string{}, err
}
cn := []string{cert.Subject.CommonName}
if len(cert.DNSNames) > 0 {
cn = append(cn, cert.DNSNames...)
}
glog.V(2).Infof("DNS %v %v\n", cn, len(cn))
return cn, nil
}

View file

@ -83,7 +83,7 @@ func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, upstreams []*Upstream
return false, err return false, err
} }
changed, err := checkChanges(ngx.ConfigFile, buffer) changed, err := ngx.needsReload(buffer)
if err != nil { if err != nil {
return false, err return false, err
} }

View file

@ -120,7 +120,8 @@ func toMap(iface interface{}) (map[string]interface{}, bool) {
return map[string]interface{}{}, false return map[string]interface{}{}, false
} }
func checkChanges(filename string, data *bytes.Buffer) (bool, error) { func (ngx *NginxManager) needsReload(data *bytes.Buffer) (bool, error) {
filename := ngx.ConfigFile
in, err := os.Open(filename) in, err := os.Open(filename)
if err != nil { if err != nil {
return false, err return false, err
@ -141,7 +142,8 @@ func checkChanges(filename string, data *bytes.Buffer) (bool, error) {
dData, err := diff(src, res) dData, err := diff(src, res)
if err != nil { if err != nil {
return false, fmt.Errorf("computing diff: %s", err) glog.Errorf("error computing diff: %s", err)
return true, nil
} }
if glog.V(2) { if glog.V(2) {

View file

@ -175,3 +175,40 @@ func getTCPServices(kubeClient *unversioned.Client, tcpServices string) []nginx.
return svcs return svcs
} }
func isHostValid(host string, cns []string) bool {
for _, cn := range cns {
if matchHostnames(cn, host) {
return true
}
}
return false
}
func matchHostnames(pattern, host string) bool {
host = strings.TrimSuffix(host, ".")
pattern = strings.TrimSuffix(pattern, ".")
if len(pattern) == 0 || len(host) == 0 {
return false
}
patternParts := strings.Split(pattern, ".")
hostParts := strings.Split(host, ".")
if len(patternParts) != len(hostParts) {
return false
}
for i, patternPart := range patternParts {
if i == 0 && patternPart == "*" {
continue
}
if patternPart != hostParts[i] {
return false
}
}
return true
}