Skip to content

Commit

Permalink
Merge pull request #4000 from ElvinEfendi/dynamic-ssl-improvements
Browse files Browse the repository at this point in the history
Dynamic ssl improvements
  • Loading branch information
k8s-ci-robot authored Apr 13, 2019
2 parents 6fead82 + b1a6aa2 commit 6b6610d
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 125 deletions.
8 changes: 4 additions & 4 deletions cmd/nginx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const (
// client code is overriding it.
defaultBurst = 1e6

fakeCertificate = "default-fake-certificate"
fakeCertificateName = "default-fake-certificate"
)

func main() {
Expand Down Expand Up @@ -116,12 +116,12 @@ func main() {
if err != nil {
klog.Fatalf("unexpected error creating fake SSL Cert: %v", err)
}
err = ssl.StoreSSLCertOnDisk(fs, fakeCertificate, sslCert)
err = ssl.StoreSSLCertOnDisk(fs, fakeCertificateName, sslCert)
if err != nil {
klog.Fatalf("unexpected error storing fake SSL Cert: %v", err)
}
conf.FakeCertificatePath = sslCert.PemFileName
conf.FakeCertificateSHA = sslCert.PemSHA
conf.FakeCertificate = sslCert
klog.Infof("Created fake certificate with PemFileName: %v", conf.FakeCertificate.PemFileName)
// end create default fake SSL certificates

conf.Client = kubeClient
Expand Down
48 changes: 27 additions & 21 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ type Configuration struct {

EnableSSLChainCompletion bool

FakeCertificatePath string
FakeCertificateSHA string
FakeCertificate *ingress.SSLCert

SyncRateLimit float32

Expand Down Expand Up @@ -829,6 +828,21 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
return upstreams, nil
}

// overridePemFileNameAndPemSHA should only be called when DynamicCertificatesEnabled
// ideally this function should not exist, the only reason why we use it is that
// we rely on PemFileName in nginx.tmpl to configure SSL directives
// and PemSHA to force reload
func (n *NGINXController) overridePemFileNameAndPemSHA(cert *ingress.SSLCert) {
// TODO(elvinefendi): It is not great but we currently use PemFileName to decide whether SSL needs to be configured
// in nginx configuration or not. The whole thing needs to be refactored, we should rely on a proper
// signal to configure SSL, not PemFileName.
cert.PemFileName = n.cfg.FakeCertificate.PemFileName

// TODO(elvinefendi): This is again another hacky way of avoiding Nginx reload when certificate
// changes in dynamic SSL mode since FakeCertificate never changes.
cert.PemSHA = n.cfg.FakeCertificate.PemSHA
}

// createServers builds a map of host name to Server structs from a map of
// already computed Upstream structs. Each Server is configured with at least
// one root location, which uses a default backend if left unspecified.
Expand Down Expand Up @@ -856,16 +870,16 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
ProxyBuffering: bdef.ProxyBuffering,
}

// generated on Start() with createDefaultSSLCertificate()
defaultPemFileName := n.cfg.FakeCertificatePath
defaultPemSHA := n.cfg.FakeCertificateSHA
defaultCertificate := n.cfg.FakeCertificate

// read custom default SSL certificate, fall back to generated default certificate
if n.cfg.DefaultSSLCertificate != "" {
defaultCertificate, err := n.store.GetLocalSSLCert(n.cfg.DefaultSSLCertificate)
certificate, err := n.store.GetLocalSSLCert(n.cfg.DefaultSSLCertificate)
if err == nil {
defaultPemFileName = defaultCertificate.PemFileName
defaultPemSHA = defaultCertificate.PemSHA
defaultCertificate = certificate
if n.cfg.DynamicCertificatesEnabled {
n.overridePemFileNameAndPemSHA(defaultCertificate)
}
} else {
klog.Warningf("Error loading custom default certificate, falling back to generated default:\n%v", err)
}
Expand All @@ -874,10 +888,7 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
// initialize default server and root location
servers[defServerName] = &ingress.Server{
Hostname: defServerName,
SSLCert: ingress.SSLCert{
PemFileName: defaultPemFileName,
PemSHA: defaultPemSHA,
},
SSLCert: *defaultCertificate,
Locations: []*ingress.Location{
{
Path: rootLocation,
Expand Down Expand Up @@ -1021,17 +1032,15 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,

if tlsSecretName == "" {
klog.V(3).Infof("Host %q is listed in the TLS section but secretName is empty. Using default certificate.", host)
servers[host].SSLCert.PemFileName = defaultPemFileName
servers[host].SSLCert.PemSHA = defaultPemSHA
servers[host].SSLCert = *defaultCertificate
continue
}

secrKey := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName)
cert, err := n.store.GetLocalSSLCert(secrKey)
if err != nil {
klog.Warningf("Error getting SSL certificate %q: %v. Using default certificate", secrKey, err)
servers[host].SSLCert.PemFileName = defaultPemFileName
servers[host].SSLCert.PemSHA = defaultPemSHA
servers[host].SSLCert = *defaultCertificate
continue
}

Expand All @@ -1046,16 +1055,13 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
klog.Warningf("SSL certificate %q does not contain a Common Name or Subject Alternative Name for server %q: %v",
secrKey, host, err)
klog.Warningf("Using default certificate")
servers[host].SSLCert.PemFileName = defaultPemFileName
servers[host].SSLCert.PemSHA = defaultPemSHA
servers[host].SSLCert = *defaultCertificate
continue
}
}

if n.cfg.DynamicCertificatesEnabled {
// useless placeholders: just to shut up NGINX configuration loader errors:
cert.PemFileName = defaultPemFileName
cert.PemSHA = defaultPemSHA
n.overridePemFileNameAndPemSHA(cert)
}

servers[host].SSLCert = *cert
Expand Down
15 changes: 15 additions & 0 deletions internal/ingress/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ import (
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/controller/store"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/net/ssl"
)

const fakeCertificateName = "default-fake-certificate"

func TestMergeAlternativeBackends(t *testing.T) {
testCases := map[string]struct {
ingress *ingress.Ingress
Expand Down Expand Up @@ -918,7 +921,19 @@ func newNGINXController(t *testing.T) *NGINXController {
pod,
false)

// BEGIN create fake ssl cert
defCert, defKey := ssl.GetFakeSSLCert()
sslCert, err := ssl.CreateSSLCert(defCert, defKey)
if err != nil {
t.Fatalf("unexpected error creating fake SSL Cert: %v", err)
}
err = ssl.StoreSSLCertOnDisk(fs, fakeCertificateName, sslCert)
if err != nil {
t.Fatalf("unexpected error storing fake SSL Cert: %v", err)
}
// END create fake ssl cert
config := &Configuration{
FakeCertificate: sslCert,
ListenPorts: &ngx_config.ListenPorts{
Default: 80,
},
Expand Down
2 changes: 1 addition & 1 deletion internal/ingress/controller/store/backend_ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
return nil, fmt.Errorf("unexpected error creating SSL Cert: %v", err)
}

if !s.isDynamicCertificatesEnabled || len(ca) > 0 || s.defaultSSLCertificate == secretName {
if !s.isDynamicCertificatesEnabled || len(ca) > 0 {
err = ssl.StoreSSLCertOnDisk(s.filesystem, nsSecName, sslCert)
if err != nil {
return nil, fmt.Errorf("error while storing certificate and key: %v", err)
Expand Down
17 changes: 13 additions & 4 deletions rootfs/etc/nginx/lua/certificate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ local re_sub = ngx.re.sub

local _M = {}

local DEFAULT_CERT_HOSTNAME = "_"

local function set_pem_cert_key(pem_cert_key)
local der_cert, der_cert_err = ssl.cert_pem_to_der(pem_cert_key)
if not der_cert then
Expand Down Expand Up @@ -47,13 +49,20 @@ end
function _M.call()
local hostname, hostname_err = ssl.server_name()
if hostname_err then
ngx.log(ngx.ERR, "Error getting the hostname, falling back on default certificate: " .. hostname_err)
return
ngx.log(ngx.ERR, "error while obtaining hostname: " .. hostname_err)
end
if not hostname then
ngx.log(ngx.INFO,
"obtained hostname is nil (the client does not support SNI?), falling back to default certificate")
hostname = DEFAULT_CERT_HOSTNAME
end

local pem_cert_key = get_pem_cert_key(hostname)
if not pem_cert_key or pem_cert_key == "" then
ngx.log(ngx.ERR, "Certificate not found, falling back on default certificate for hostname: " .. tostring(hostname))
if not pem_cert_key then
pem_cert_key = get_pem_cert_key(DEFAULT_CERT_HOSTNAME)
end
if not pem_cert_key then
ngx.log(ngx.ERR, "certificate not found, falling back to fake certificate for hostname: " .. tostring(hostname))
return
end

Expand Down
140 changes: 61 additions & 79 deletions rootfs/etc/nginx/lua/test/certificate_test.lua
Original file line number Diff line number Diff line change
@@ -1,123 +1,105 @@
local certificate = require("certificate")

local PEM_CERT_KEY = "-----BEGIN CERTIFICATE-----\nMIID6DCCAlCgAwIBAgIQcfG0mA7BIFqhlnr/Zwh6TzANBgkqhkiG9w0BAQsFADBC\nMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExIDAeBgNVBAsMF2hlbnJ5\ndHJhbkBPVFQtSGVucnlUcmFuMB4XDTE4MDcwOTIwMTY1MloXDTI4MDcwOTIwMTY1\nMlowSzEnMCUGA1UEChMebWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMSAw\nHgYDVQQLDBdoZW5yeXRyYW5AT1RULUhlbnJ5VHJhbjCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBALIrsgHzjZZyKWPn3rGzTkaj9jADYAMhM+0wY3iky2Dx\ndr2YbKnZbbGxKLfVukYRsUUOK0SnBMTX15fsGanirj2hflMHfGvHilaVkVAkPJgD\nBTf2PkxFff99hS7/Ncz20MR6+E/vqp7Hx7IKDrg9lC9u1n82aotfN3gPhif8HyQu\n+P9cltsr9PewyPe4573WQmzXhTKaFm9+U9xZ2qS1J0DMEizRs45vuM040hxtiwVz\nM4Lm8DVpaYxMBWNI/zo9EZzoSJZH1sYUpTMwhNj+caEX+LK9PCM4Sht/yhPUc6aD\nnIEqraz+bS8dNFH5Ehp7n1SZL7YH6xT6da4F3ci7jEECAwEAAaNRME8wDgYDVR0P\nAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwGgYD\nVR0RBBMwEYIPbXltaW5pa3ViZS5pbmZvMA0GCSqGSIb3DQEBCwUAA4IBgQC/TEpx\nJkL/ek37L2XKwGq96hNT10IZ9yE+RlndNGNY6eAc8y313sXBHTFbDCWQ2s0pWZZS\n+va20dnTQNyWzJAxFpdNvcKOCUGat4RPD/j+pBTEYk5n/oo7s2FWkG8kW6tKDilf\njWHpk7m9uYCO2sOZFiQPR81idR5PLox46SpJmIhDVfCi6VS4N+8fAT8Tbt9xkPmS\nmODhpnuIUt0NVTi62eqnxeO185qAt73xhz9Gj1KHntAK1ebcx0k3UxKRXQp9WY76\nF39sSz8OuhEhvv9ayl6uS6ZdSLvvb6kJrRRneKr01ridCOtiYB7cuXykDL1c6PUk\nugxDgTyCjiuPnRl0CLwxWT659PVozA2SO1YCW6UcoGdj2KMvsXezeWKpNGx3NHXO\nufdlxSbzWlamn+sPunWP3v2tfV0J8sHG3n1roeBO2N52197/ennGuCZfnF8C5MoG\n9YfMjKg9Z03G8sDpk9g5bHp9p28TO1X+Ht30PQzkUNhx3fjTO2DDvCyGk2k=\n-----END CERTIFICATE-----\n\n-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyK7IB842Wcilj\n596xs05Go/YwA2ADITPtMGN4pMtg8Xa9mGyp2W2xsSi31bpGEbFFDitEpwTE19eX\n7Bmp4q49oX5TB3xrx4pWlZFQJDyYAwU39j5MRX3/fYUu/zXM9tDEevhP76qex8ey\nCg64PZQvbtZ/NmqLXzd4D4Yn/B8kLvj/XJbbK/T3sMj3uOe91kJs14UymhZvflPc\nWdqktSdAzBIs0bOOb7jNONIcbYsFczOC5vA1aWmMTAVjSP86PRGc6EiWR9bGFKUz\nMITY/nGhF/iyvTwjOEobf8oT1HOmg5yBKq2s/m0vHTRR+RIae59UmS+2B+sU+nWu\nBd3Iu4xBAgMBAAECggEBAIbuUIDp0fB9xJrEnwI0qLMWuPrjk3LLUmfunWZgZyWj\nuCkdpi17XHeVkyCl28v02itR77KuSg5I6B1F0Km34f0KsIBwyulU1I999e6bgsgc\ngXdAJS3d8u3qQVK2NChlQvWJq0PeXXiiE7nhpAQjnnXNmuP8cfPayEdEenUNmwfq\nxjEh2/oDzUTPD/4z5Hpw8n728SItgBolMNgGvmv5cC4JNLqujCUPwkLiZ3a2YbTY\nrmOO1xDkZnQWqyNP+baOwYwpu/kISPM3IveP5GGBNQsUsDxs6t80HNW/w8Ry0f50\n+gNTIuJVOLXfpVLIo87wTMEtRAqMzT4vxQIi+vj2XYECgYEA6QftSRKqur1G4P6Y\n9cseDnljJFWIjqex2q3NrvMaHbnlXp6AtPROoNz6L8H+PnBy8o1yZJwWnhKTvPaD\nsi+a1g7dqQIM4TjKLlidV57lt5ENw4ueW1o7Jbk75gawLhrBPSCFxR5xSqF+kQxn\nmWGjLnZoomD6fM2CG7EF1fg+wjsCgYEAw7t6db9tjGGM9J0rUe+jVtxMWiG9ArT0\nhmaLZQlKrOSFeEf8c4ZYBNxp/X+/jg0GWBX8P4KRubAz6bbn0A+07K9TClrvMFWq\nveqnK1JUsMGWsYQPp8dX8VS/jOFzYdiji9Ekyzs9RiXW8jzp0wzrccSjEr0de8HK\niEa9CH7cZ7MCgYB1V5mD51NzbyZG281YT+yVq0hiHnQCKa1kiYp+I0ouV9KJP9Vd\nyXvigwO0ksIc3PD09Ib65KJ6/K3KRHPygQg97ARwO2kS7E7a4aJxYcEZG4DLy/10\n0M3h5BGmdg23WZ+e0UarCPZRd1rNXWq5kLHkDpoH0j+wIqf2m8Bti3DGywKBgBEK\nn6zkz9rrG2So0n69yJDleVhXm6dCrg+NmhFf77qB4wUH73j3d25k6m2B0+HATI8a\nyu2Upq9uIfb1T9WTqIL6+NXr+OtSah1C8u8YqfsBv+cQwnQvLP78C/luH6ejPwoL\nWZLAQ6N54+8PUqRneZBcOH6HLKv7wXCACDFXKkV1AoGAfDb5GJ0NsovWhLfU5WEB\nSfdzHBplbp72q08S0aqTNm0wlTiCGYgm2Lle4IaOGoJ+7ipirL0KzuwisAZJFTvJ\nhsMqOmH/Ckledmf2JpLxyg8KB5KVA+RVQkrfVEv8yhqLcKQU6Z2n4jSTon7hXb1T\nf8neDpZ8DwO0W9cOdYLYyTg=\n-----END PRIVATE KEY-----"
local ssl = require("ngx.ssl")

local function read_file(path)
local file = assert(io.open(path, "rb"))
local content = file:read("*a")
file:close()
return content
end

local EXAMPLE_CERT = read_file("rootfs/etc/nginx/lua/test/fixtures/example-com-cert.pem")
local DEFAULT_CERT = read_file("rootfs/etc/nginx/lua/test/fixtures/default-cert.pem")
local DEFAULT_CERT_HOSTNAME = "_"

local function assert_certificate_is_set(cert)
spy.on(ngx, "log")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_not_called_with(ngx.ERR, _)
assert.spy(ssl.set_der_cert).was_called_with(ssl.cert_pem_to_der(cert))
assert.spy(ssl.set_der_priv_key).was_called_with(ssl.priv_key_pem_to_der(cert))
end

local function refute_certificate_is_set()
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ssl.set_der_cert).was_not_called()
assert.spy(ssl.set_der_priv_key).was_not_called()
end

local unmocked_ngx = _G.ngx

describe("Certificate", function()
describe("call", function()
local ssl = require("ngx.ssl")
local match = require("luassert.match")

before_each(function()
ssl.server_name = function() return "hostname", nil end
ssl.clear_certs = function() return true, "" end
ssl.set_der_cert = function(cert) return true, "" end
ssl.set_der_priv_key = function(priv_key) return true, "" end

ngx.exit = function(status) end


ngx.shared.certificate_data:set(DEFAULT_CERT_HOSTNAME, DEFAULT_CERT)
end)

after_each(function()
ngx = unmocked_ngx
ngx.shared.certificate_data:flush_all()
end)

it("does not clear fallback certificates and logs error message when host is not in dictionary", function()
ngx.shared.certificate_data:set("hostname", "")

spy.on(ngx, "log")
spy.on(ssl, "clear_certs")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_called_with(ngx.ERR, "Certificate not found, falling back on default certificate for hostname: hostname")
assert.spy(ssl.clear_certs).was_not_called()
assert.spy(ssl.set_der_cert).was_not_called()
assert.spy(ssl.set_der_priv_key).was_not_called()
end)

it("does not clear fallback certificates and logs error message when the cert is empty for given host", function()
spy.on(ngx, "log")
spy.on(ssl, "clear_certs")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_called_with(ngx.ERR, "Certificate not found, falling back on default certificate for hostname: hostname")
assert.spy(ssl.clear_certs).was_not_called()
assert.spy(ssl.set_der_cert).was_not_called()
assert.spy(ssl.set_der_priv_key).was_not_called()
end)

it("successfully sets SSL certificate and key when hostname is found in dictionary", function()
ngx.shared.certificate_data:set("hostname", PEM_CERT_KEY)

spy.on(ngx, "log")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")
it("sets certificate and key when hostname is found in dictionary", function()
ngx.shared.certificate_data:set("hostname", EXAMPLE_CERT)

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_not_called_with(ngx.ERR, _)
assert.spy(ssl.set_der_cert).was_called_with(ssl.cert_pem_to_der(PEM_CERT_KEY))
assert.spy(ssl.set_der_priv_key).was_called_with(ssl.priv_key_pem_to_der(PEM_CERT_KEY))
assert_certificate_is_set(EXAMPLE_CERT)
end)

it("successfully sets SSL certificate and key for wildcard cert", function()
it("sets certificate and key for wildcard cert", function()
ssl.server_name = function() return "sub.hostname", nil end
ngx.shared.certificate_data:set("*.hostname", PEM_CERT_KEY)

spy.on(ngx, "log")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")
ngx.shared.certificate_data:set("*.hostname", EXAMPLE_CERT)

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_not_called_with(ngx.ERR, _)
assert.spy(ssl.set_der_cert).was_called_with(ssl.cert_pem_to_der(PEM_CERT_KEY))
assert.spy(ssl.set_der_priv_key).was_called_with(ssl.priv_key_pem_to_der(PEM_CERT_KEY))
assert_certificate_is_set(EXAMPLE_CERT)
end)

it("successfully sets SSL certificate and key for nested wildcard cert", function()
it("sets certificate and key for nested wildcard cert", function()
ssl.server_name = function() return "sub.nested.hostname", nil end
ngx.shared.certificate_data:set("*.nested.hostname", PEM_CERT_KEY)
ngx.shared.certificate_data:set("*.nested.hostname", EXAMPLE_CERT)

spy.on(ngx, "log")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_not_called_with(ngx.ERR, _)
assert.spy(ssl.set_der_cert).was_called_with(ssl.cert_pem_to_der(PEM_CERT_KEY))
assert.spy(ssl.set_der_priv_key).was_called_with(ssl.priv_key_pem_to_der(PEM_CERT_KEY))
assert_certificate_is_set(EXAMPLE_CERT)
end)

it("logs error message when certificate in dictionary is invalid", function()
ngx.shared.certificate_data:set("hostname", "something invalid")

spy.on(ngx, "log")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
refute_certificate_is_set()
assert.spy(ngx.log).was_called_with(ngx.ERR, "failed to convert certificate chain from PEM to DER: PEM_read_bio_X509_AUX() failed")
assert.spy(ssl.set_der_cert).was_not_called()
assert.spy(ssl.set_der_priv_key).was_not_called()
end)

it("does not clear fallback certificates and logs error message when hostname could not be fetched", function()
ssl.server_name = function() return nil, "error" end
it("uses default certificate when there's none found for given hostname", function()
assert_certificate_is_set(DEFAULT_CERT)
end)

it("uses default certificate when hostname can not be obtained", function()
ssl.server_name = function() return nil, "crazy hostname error" end

assert_certificate_is_set(DEFAULT_CERT)
assert.spy(ngx.log).was_called_with(ngx.ERR, "error while obtaining hostname: crazy hostname error")
end)

it("fails when hostname does not have certificate and default cert is invalid", function()
ngx.shared.certificate_data:set(DEFAULT_CERT_HOSTNAME, "invalid")

spy.on(ngx, "log")
spy.on(ssl, "clear_certs")
spy.on(ssl, "set_der_cert")
spy.on(ssl, "set_der_priv_key")

assert.has_no.errors(certificate.call)
assert.spy(ngx.log).was_called_with(ngx.ERR, "Error getting the hostname, falling back on default certificate: error")
assert.spy(ssl.clear_certs).was_not_called()
assert.spy(ssl.set_der_cert).was_not_called()
assert.spy(ssl.set_der_priv_key).was_not_called()

refute_certificate_is_set()
assert.spy(ngx.log).was_called_with(ngx.ERR, "failed to convert certificate chain from PEM to DER: PEM_read_bio_X509_AUX() failed")
end)
end)
end)
Loading

0 comments on commit 6b6610d

Please sign in to comment.