Add ssl certificate checksum to template
This commit is contained in:
parent
8a652e94f5
commit
c4228a150f
5 changed files with 61 additions and 30 deletions
|
@ -733,11 +733,12 @@ func (lbc *loadBalancerController) createServers(data []interface{}) map[string]
|
||||||
servers[host] = &nginx.Server{Name: host, Locations: locs}
|
servers[host] = &nginx.Server{Name: host, Locations: locs}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pemFile, ok := pems[host]; ok {
|
if ngxCert, ok := pems[host]; ok {
|
||||||
server := servers[host]
|
server := servers[host]
|
||||||
server.SSL = true
|
server.SSL = true
|
||||||
server.SSLCertificate = pemFile
|
server.SSLCertificate = ngxCert.PemFileName
|
||||||
server.SSLCertificateKey = pemFile
|
server.SSLCertificateKey = ngxCert.PemFileName
|
||||||
|
server.SSLPemChecksum = ngxCert.PemSHA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -745,8 +746,8 @@ func (lbc *loadBalancerController) createServers(data []interface{}) map[string]
|
||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[string]string {
|
func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[string]nginx.SSLCert {
|
||||||
pems := make(map[string]string)
|
pems := make(map[string]nginx.SSLCert)
|
||||||
|
|
||||||
for _, ingIf := range data {
|
for _, ingIf := range data {
|
||||||
ing := ingIf.(*extensions.Ingress)
|
ing := ingIf.(*extensions.Ingress)
|
||||||
|
@ -769,12 +770,7 @@ func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[st
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pemFileName, err := lbc.nginx.AddOrUpdateCertAndKey(fmt.Sprintf("%v-%v", ing.Namespace, secretName), string(cert), string(key))
|
ngxCert, err := lbc.nginx.AddOrUpdateCertAndKey(fmt.Sprintf("%v-%v", ing.Namespace, secretName), string(cert), string(key))
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("No valid SSL certificate found in secret %v: %v", secretName, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cn, err := lbc.nginx.CheckSSLCertificate(pemFileName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("No valid SSL certificate found in secret %v: %v", secretName, err)
|
glog.Errorf("No valid SSL certificate found in secret %v: %v", secretName, err)
|
||||||
continue
|
continue
|
||||||
|
@ -786,14 +782,14 @@ func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[st
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pems["_"] = pemFileName
|
pems["_"] = ngxCert
|
||||||
glog.Infof("Using the secret %v as source for the default SSL certificate", secretName)
|
glog.Infof("Using the secret %v as source for the default SSL certificate", secretName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, host := range tls.Hosts {
|
for _, host := range tls.Hosts {
|
||||||
if isHostValid(host, cn) {
|
if isHostValid(host, ngxCert.CN) {
|
||||||
pems[host] = pemFileName
|
pems[host] = ngxCert
|
||||||
} else {
|
} 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)
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,8 @@ http {
|
||||||
server {
|
server {
|
||||||
listen 80{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }};
|
listen 80{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }};
|
||||||
{{ if $server.SSL }}listen 443{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }} ssl http2;
|
{{ if $server.SSL }}listen 443{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }} ssl http2;
|
||||||
|
{{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}}
|
||||||
|
# PEM sha: {{ $server.SSLPemChecksum }}
|
||||||
ssl_certificate {{ $server.SSLCertificate }};
|
ssl_certificate {{ $server.SSLCertificate }};
|
||||||
ssl_certificate_key {{ $server.SSLCertificateKey }};{{ end }}
|
ssl_certificate_key {{ $server.SSLCertificateKey }};{{ end }}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ type Server struct {
|
||||||
SSL bool
|
SSL bool
|
||||||
SSLCertificate string
|
SSLCertificate string
|
||||||
SSLCertificateKey string
|
SSLCertificateKey string
|
||||||
|
SSLPemChecksum string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerByName sorts server by name
|
// ServerByName sorts server by name
|
||||||
|
|
|
@ -17,7 +17,9 @@ limitations under the License.
|
||||||
package nginx
|
package nginx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -26,28 +28,52 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SSLCert describes a SSL certificate to be used in NGINX
|
||||||
|
type SSLCert struct {
|
||||||
|
CertFileName string
|
||||||
|
KeyFileName string
|
||||||
|
// PemFileName contains the path to the file with the certificate and key concatenated
|
||||||
|
PemFileName string
|
||||||
|
// PemSHA contains the sha1 of the pem file.
|
||||||
|
// This is used to detect changes in the secret that contains the certificates
|
||||||
|
PemSHA string
|
||||||
|
// CN contains all the common names defined in the SSL certificate
|
||||||
|
CN []string
|
||||||
|
}
|
||||||
|
|
||||||
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
|
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
|
||||||
func (nginx *Manager) AddOrUpdateCertAndKey(name string, cert string, key string) (string, error) {
|
func (nginx *Manager) AddOrUpdateCertAndKey(name string, cert string, key string) (SSLCert, error) {
|
||||||
pemFileName := sslDirectory + "/" + name + ".pem"
|
pemFileName := sslDirectory + "/" + name + ".pem"
|
||||||
|
|
||||||
pem, err := os.Create(pemFileName)
|
pem, err := os.Create(pemFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Couldn't create pem file %v: %v", pemFileName, err)
|
return SSLCert{}, fmt.Errorf("Couldn't create pem file %v: %v", pemFileName, err)
|
||||||
}
|
}
|
||||||
defer pem.Close()
|
defer pem.Close()
|
||||||
|
|
||||||
_, err = pem.WriteString(fmt.Sprintf("%v\n%v", cert, key))
|
_, err = pem.WriteString(fmt.Sprintf("%v\n%v", cert, key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Couldn't write to pem file %v: %v", pemFileName, err)
|
return SSLCert{}, fmt.Errorf("Couldn't write to pem file %v: %v", pemFileName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pemFileName, nil
|
cn, err := nginx.commonNames(pemFileName)
|
||||||
|
if err != nil {
|
||||||
|
return SSLCert{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckSSLCertificate checks if the certificate and key file are valid
|
return SSLCert{
|
||||||
|
CertFileName: cert,
|
||||||
|
KeyFileName: key,
|
||||||
|
PemFileName: pemFileName,
|
||||||
|
PemSHA: nginx.pemSHA1(pemFileName),
|
||||||
|
CN: cn,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// commonNames checks if the certificate and key file are valid
|
||||||
// returning the result of the validation and the list of hostnames
|
// returning the result of the validation and the list of hostnames
|
||||||
// contained in the common name/s
|
// contained in the common name/s
|
||||||
func (nginx *Manager) CheckSSLCertificate(pemFileName string) ([]string, error) {
|
func (nginx *Manager) commonNames(pemFileName string) ([]string, error) {
|
||||||
pemCerts, err := ioutil.ReadFile(pemFileName)
|
pemCerts, err := ioutil.ReadFile(pemFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
|
@ -92,3 +118,14 @@ func (nginx *Manager) SearchDHParamFile(baseDir string) string {
|
||||||
glog.Warning("no file dhparam.pem found in secrets")
|
glog.Warning("no file dhparam.pem found in secrets")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nginx *Manager) pemSHA1(filename string) string {
|
||||||
|
hasher := sha1.New()
|
||||||
|
s, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher.Write(s)
|
||||||
|
return hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
}
|
||||||
|
|
|
@ -44,25 +44,20 @@ func TestAddOrUpdateCertAndKey(t *testing.T) {
|
||||||
ngx := &Manager{}
|
ngx := &Manager{}
|
||||||
|
|
||||||
name := fmt.Sprintf("test-%v", time.Now().UnixNano())
|
name := fmt.Sprintf("test-%v", time.Now().UnixNano())
|
||||||
pemPath, err := ngx.AddOrUpdateCertAndKey(name, string(dCrt), string(dKey))
|
ngxCert, err := ngx.AddOrUpdateCertAndKey(name, string(dCrt), string(dKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error checking SSL certificate: %v", err)
|
t.Fatalf("unexpected error checking SSL certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pemPath == "" {
|
if ngxCert.PemFileName == "" {
|
||||||
t.Fatalf("expected path to pem file but returned empty")
|
t.Fatalf("expected path to pem file but returned empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
cnames, err := ngx.CheckSSLCertificate(pemPath)
|
if len(ngxCert.CN) == 0 {
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error checking SSL certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cnames) == 0 {
|
|
||||||
t.Fatalf("expected at least one cname but none returned")
|
t.Fatalf("expected at least one cname but none returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cnames[0] != "echoheaders" {
|
if ngxCert.CN[0] != "echoheaders" {
|
||||||
t.Fatalf("expected cname echoheaders but %v returned", cnames[0])
|
t.Fatalf("expected cname echoheaders but %v returned", ngxCert.CN[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue