Harden ssl cert logic to handle unknown state
This commit is contained in:
parent
94d256e44d
commit
9ffa23beaa
1 changed files with 57 additions and 27 deletions
|
@ -352,25 +352,50 @@ func (l *L7) deleteOldSSLCert() (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *L7) checkSSLCert() (err error) {
|
// Returns the name portion of a link - which is the last section
|
||||||
certName := l.runtimeInfo.TLSName
|
func getResourceNameFromLink(link string) string {
|
||||||
|
s := strings.Split(link, "/")
|
||||||
|
if len(s) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s[len(s)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *L7) checkSSLCert() (err error) {
|
||||||
|
// Handle Pre-Shared cert
|
||||||
|
preSharedCertName := l.runtimeInfo.TLSName
|
||||||
// Use the named GCE cert when it is specified by the annotation.
|
// Use the named GCE cert when it is specified by the annotation.
|
||||||
if certName != "" {
|
if preSharedCertName != "" {
|
||||||
// Ask GCE for the cert, checking for problems and existence.
|
// Ask GCE for the cert, checking for problems and existence.
|
||||||
cert, err := l.cloud.GetSslCertificate(certName)
|
cert, err := l.cloud.GetSslCertificate(preSharedCertName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cert == nil {
|
if cert == nil {
|
||||||
return fmt.Errorf("cannot find existing sslCertificate %v for %v", certName, l.Name)
|
return fmt.Errorf("cannot find existing sslCertificate %v for %v", preSharedCertName, l.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Using existing sslCertificate %v for %v", certName, l.Name)
|
glog.V(2).Infof("Using existing sslCertificate %v for %v", preSharedCertName, l.Name)
|
||||||
l.sslCert = cert
|
l.sslCert = cert
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle secret-created cert
|
||||||
|
// Determine what certificate name is being used
|
||||||
|
var expectedCertName string
|
||||||
|
if l.sslCert != nil {
|
||||||
|
expectedCertName = l.sslCert.Name
|
||||||
|
} else {
|
||||||
|
// Retrieve the ssl certificate in use by the expected target proxy (if exists)
|
||||||
|
expectedCertName = getResourceNameFromLink(l.getSslCertInUse())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve known ssl certificate
|
||||||
|
var usedCert *compute.SslCertificate
|
||||||
|
if expectedCertName != "" {
|
||||||
|
usedCert, _ = l.cloud.GetSslCertificate(expectedCertName)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Currently, GCE only supports a single certificate per static IP
|
// TODO: Currently, GCE only supports a single certificate per static IP
|
||||||
// so we don't need to bother with disambiguation. Naming the cert after
|
// so we don't need to bother with disambiguation. Naming the cert after
|
||||||
// the loadbalancer is a simplification.
|
// the loadbalancer is a simplification.
|
||||||
|
@ -384,32 +409,28 @@ func (l *L7) checkSSLCert() (err error) {
|
||||||
// TODO: Clean this code up into a ring buffer.
|
// TODO: Clean this code up into a ring buffer.
|
||||||
primaryCertName := l.namer.Truncate(fmt.Sprintf("%v-%v", sslCertPrefix, l.Name))
|
primaryCertName := l.namer.Truncate(fmt.Sprintf("%v-%v", sslCertPrefix, l.Name))
|
||||||
secondaryCertName := l.namer.Truncate(fmt.Sprintf("%v-%d-%v", sslCertPrefix, 1, l.Name))
|
secondaryCertName := l.namer.Truncate(fmt.Sprintf("%v-%d-%v", sslCertPrefix, 1, l.Name))
|
||||||
certName = primaryCertName
|
|
||||||
if l.sslCert != nil {
|
|
||||||
certName = l.sslCert.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip error checking because error-ing out will retry and loop, when we
|
|
||||||
// should create/update the cert if there is an error or does not exist.
|
|
||||||
cert, _ := l.cloud.GetSslCertificate(certName)
|
|
||||||
|
|
||||||
// PrivateKey is write only, so compare certs alone. We're assuming that
|
// PrivateKey is write only, so compare certs alone. We're assuming that
|
||||||
// no one will change just the key. We can remember the key and compare,
|
// no one will change just the key. We can remember the key and compare,
|
||||||
// but a bug could end up leaking it, which feels worse.
|
// but a bug could end up leaking it, which feels worse.
|
||||||
if cert == nil || ingCert != cert.Certificate {
|
if usedCert == nil || ingCert != usedCert.Certificate {
|
||||||
|
newCertName := primaryCertName
|
||||||
certChanged := cert != nil && (ingCert != cert.Certificate)
|
if usedCert != nil && (ingCert != usedCert.Certificate) {
|
||||||
if certChanged {
|
if usedCert.Name == primaryCertName {
|
||||||
if certName == primaryCertName {
|
newCertName = secondaryCertName
|
||||||
certName = secondaryCertName
|
|
||||||
} else {
|
|
||||||
certName = primaryCertName
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Creating new sslCertificates %v for %v", certName, l.Name)
|
// Perform a delete in case a certificate exists with the exact name
|
||||||
cert, err = l.cloud.CreateSslCertificate(&compute.SslCertificate{
|
// This certificate should be unused since we check the target proxy's certificate prior
|
||||||
Name: certName,
|
// to this point. Although, it's possible an actor pointed a target proxy to this certificate.
|
||||||
|
if err = l.cloud.DeleteSslCertificate(newCertName); err != nil && !utils.IsHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
|
return fmt.Errorf("unable to delete ssl certificate with name %q, expected it to be unused. err: %v", newCertName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Infof("Creating new sslCertificates %v for %v", newCertName, l.Name)
|
||||||
|
cert, err := l.cloud.CreateSslCertificate(&compute.SslCertificate{
|
||||||
|
Name: newCertName,
|
||||||
Certificate: ingCert,
|
Certificate: ingCert,
|
||||||
PrivateKey: ingKey,
|
PrivateKey: ingKey,
|
||||||
})
|
})
|
||||||
|
@ -417,13 +438,22 @@ func (l *L7) checkSSLCert() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Save the current cert for cleanup after we update the target proxy.
|
// Save the current cert for cleanup after we update the target proxy.
|
||||||
l.oldSSLCert = l.sslCert
|
l.oldSSLCert = usedCert
|
||||||
|
l.sslCert = cert
|
||||||
}
|
}
|
||||||
|
|
||||||
l.sslCert = cert
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *L7) getSslCertInUse() string {
|
||||||
|
proxyName := l.namer.Truncate(fmt.Sprintf("%v-%v", targetHTTPSProxyPrefix, l.Name))
|
||||||
|
proxy, _ := l.cloud.GetTargetHttpsProxy(proxyName)
|
||||||
|
if proxy != nil && len(proxy.SslCertificates) > 0 {
|
||||||
|
return proxy.SslCertificates[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (l *L7) checkHttpsProxy() (err error) {
|
func (l *L7) checkHttpsProxy() (err error) {
|
||||||
if l.sslCert == nil {
|
if l.sslCert == nil {
|
||||||
glog.V(3).Infof("No SSL certificates for %v, will not create HTTPS proxy.", l.Name)
|
glog.V(3).Infof("No SSL certificates for %v, will not create HTTPS proxy.", l.Name)
|
||||||
|
|
Loading…
Reference in a new issue