Merge pull request #1699 from aledbf/disable-cert-chain-validation

Refactor SSL intermediate CA certificate check
This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-11-13 13:55:13 -03:00 committed by GitHub
commit a479bcd4fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 42 deletions

View file

@ -18,10 +18,11 @@ package controller
import (
"fmt"
"reflect"
"io/ioutil"
"strings"
"github.com/golang/glog"
"github.com/imdario/mergo"
apiv1 "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
@ -48,7 +49,7 @@ func (ic *NGINXController) syncSecret(key string) {
cur, exists := ic.sslCertTracker.Get(key)
if exists {
s := cur.(*ingress.SSLCert)
if reflect.DeepEqual(s, cert) {
if s.Equal(cert) {
// no need to update
return
}
@ -123,6 +124,47 @@ func (ic *NGINXController) getPemCertificate(secretName string) (*ingress.SSLCer
return s, nil
}
func (ic *NGINXController) checkSSLChainIssues() {
for _, secretName := range ic.sslCertTracker.ListKeys() {
s, _ := ic.sslCertTracker.Get(secretName)
secret := s.(*ingress.SSLCert)
if secret.FullChainPemFileName != "" {
// chain already checked
continue
}
data, err := ssl.FullChainCert(secret.PemFileName)
if err != nil {
glog.Errorf("unexpected error generating SSL certificate with full intermediate chain CA certs: %v", err)
continue
}
fullChainPemFileName := fmt.Sprintf("%v/%v-%v-full-chain.pem", ingress.DefaultSSLDirectory, secret.Namespace, secret.Name)
err = ioutil.WriteFile(fullChainPemFileName, data, 0655)
if err != nil {
glog.Errorf("unexpected error creating SSL certificate: %v", err)
continue
}
dst := &ingress.SSLCert{}
err = mergo.MergeWithOverwrite(dst, secret)
if err != nil {
glog.Errorf("unexpected error creating SSL certificate: %v", err)
continue
}
dst.FullChainPemFileName = fullChainPemFileName
glog.Infof("updating local copy of ssl certificate %v with missing intermediate CA certs", secretName)
ic.sslCertTracker.Update(secretName, dst)
// this update must trigger an update
// (like an update event from a change in Ingress)
ic.syncQueue.Enqueue(&extensions.Ingress{})
}
}
// checkMissingSecrets verify if one or more ingress rules contains a reference
// to a secret that is not present in the local secret store.
// In this case we call syncSecret.

View file

@ -106,6 +106,8 @@ type Configuration struct {
EnableProfiling bool
EnableSSLChainCompletion bool
FakeCertificatePath string
FakeCertificateSHA string
}

View file

@ -257,6 +257,10 @@ func (n *NGINXController) Start() {
go n.syncQueue.Run(time.Second, n.stopCh)
if n.cfg.EnableSSLChainCompletion {
go wait.Until(n.checkSSLChainIssues, 60*time.Second, n.stopCh)
}
if n.syncStatus != nil {
go n.syncStatus.Run(n.stopCh)
}

View file

@ -271,6 +271,9 @@ func (s1 *Server) Equal(s2 *Server) bool {
if !(&s1.CertificateAuth).Equal(&s2.CertificateAuth) {
return false
}
if s1.SSLFullChainCertificate != s2.SSLFullChainCertificate {
return false
}
if s1.RedirectFromToWWW != s2.RedirectFromToWWW {
return false
}
@ -461,3 +464,37 @@ func (l4b1 *L4Backend) Equal(l4b2 *L4Backend) bool {
return true
}
// Equal tests for equality between two L4Backend types
func (s1 *SSLCert) Equal(s2 *SSLCert) bool {
if s1 == s2 {
return true
}
if s1 == nil || s2 == nil {
return false
}
if s1.PemFileName != s2.PemFileName {
return false
}
if s1.PemSHA != s2.PemSHA {
return false
}
if !s1.ExpireTime.Equal(s2.ExpireTime) {
return false
}
for _, cn1 := range s1.CN {
found := false
for _, cn2 := range s2.CN {
if cn1 == cn2 {
found = true
break
}
}
if !found {
return false
}
}
return true
}

View file

@ -50,8 +50,6 @@ var (
func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert, error) {
pemName := fmt.Sprintf("%v.pem", name)
pemFileName := fmt.Sprintf("%v/%v", ingress.DefaultSSLDirectory, pemName)
fullChainPemFileName := fmt.Sprintf("%v/%v-full-chain.pem", ingress.DefaultSSLDirectory, name)
tempPemFile, err := ioutil.TempFile(ingress.DefaultSSLDirectory, pemName)
if err != nil {
@ -180,14 +178,6 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
ExpireTime: pemCert.NotAfter,
}
err = fullChainCert(pemFileName, fullChainPemFileName)
if err != nil {
glog.Errorf("unexpected error generating SSL certificate with full chain: %v", err)
return s, nil
}
s.FullChainPemFileName = fullChainPemFileName
return s, nil
}
@ -389,32 +379,44 @@ func GetFakeSSLCert() ([]byte, []byte) {
return cert, key
}
func fullChainCert(in, out string) error {
// FullChainCert checks if a certificate file contains issues in the intermediate CA chain
// Returns a new certificate with the intermediate certificates.
// If the certificate does not contains issues with the chain it return an empty byte array
func FullChainCert(in string) ([]byte, error) {
inputFile, err := os.Open(in)
if err != nil {
return err
return nil, err
}
data, err := ioutil.ReadAll(inputFile)
if err != nil {
return err
return nil, err
}
cert, err := certUtil.DecodeCertificate(data)
if err != nil {
return err
return nil, err
}
certPool := x509.NewCertPool()
certPool.AddCert(cert)
_, err = cert.Verify(x509.VerifyOptions{
Intermediates: certPool,
})
if err == nil {
return nil, nil
}
certs, err := certUtil.FetchCertificateChain(cert)
if err != nil {
return err
return nil, err
}
certs, err = certUtil.AddRootCA(certs)
if err != nil {
return err
return nil, err
}
data = certUtil.EncodeCertificates(certs)
return ioutil.WriteFile(out, data, 0644)
return certUtil.EncodeCertificates(certs), nil
}