Skip to content
This repository has been archived by the owner on Apr 27, 2021. It is now read-only.

Commit

Permalink
Ensure certificates are being dynamically served in e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hnrytrn committed Aug 20, 2018
1 parent 6409091 commit afd22c0
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 71 deletions.
81 changes: 43 additions & 38 deletions rootfs/etc/nginx/lua/certificate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,52 @@ local configuration = require("configuration")
local _M = {}

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
return "failed to convert certificate chain from PEM to DER: " .. der_cert_err
end

local set_cert_ok, set_cert_err = ssl.set_der_cert(der_cert)
if not set_cert_ok then
return "failed to set DER cert: " .. set_cert_err
end

local der_priv_key, dev_priv_key_err = ssl.priv_key_pem_to_der(pem_cert_key)
if not der_priv_key then
return "failed to convert private key from PEM to DER: " .. dev_priv_key_err
end

local set_priv_key_ok, set_priv_key_err = ssl.set_der_priv_key(der_priv_key)
if not set_priv_key_ok then
return "failed to set DER private key: " .. set_priv_key_err
end
local der_cert, der_cert_err = ssl.cert_pem_to_der(pem_cert_key)
if not der_cert then
return "failed to convert certificate chain from PEM to DER: " .. der_cert_err
end

local set_cert_ok, set_cert_err = ssl.set_der_cert(der_cert)
if not set_cert_ok then
return "failed to set DER cert: " .. set_cert_err
end

local der_priv_key, dev_priv_key_err = ssl.priv_key_pem_to_der(pem_cert_key)
if not der_priv_key then
return "failed to convert private key from PEM to DER: " .. dev_priv_key_err
end

local set_priv_key_ok, set_priv_key_err = ssl.set_der_priv_key(der_priv_key)
if not set_priv_key_ok then
return "failed to set DER private key: " .. set_priv_key_err
end
end

function _M.call()
local hostname = ssl.server_name()

local pem_cert_key = configuration.get_pem_cert_key(hostname)
if not pem_cert_key or pem_cert_key == "" then
ngx.log(ngx.ERR, "Certificate not found for the given hostname: " .. hostname)
return
end

local clear_ok, clear_err = ssl.clear_certs()
if not clear_ok then
ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates: " .. clear_err)
return
end

local set_pem_cert_key_err = set_pem_cert_key(pem_cert_key)
if set_pem_cert_key_err then
ngx.log(ngx.ERR, set_pem_cert_key_err)
return
end
local hostname, hostname_err = ssl.server_name()

if hostname_err then
ngx.log(ngx.ERR, "Error getting the hostname: " .. hostname_err)
ngx.exit(ngx.ERROR)
end

local pem_cert_key = configuration.get_pem_cert_key(hostname)
if not pem_cert_key then
ngx.log(ngx.ERR, "Certificate not found for the given hostname: " .. hostname)
ngx.exit(ngx.ERROR)
end

local clear_ok, clear_err = ssl.clear_certs()
if not clear_ok then
ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates: " .. clear_err)
ngx.exit(ngx.ERROR)
end

local set_pem_cert_key_err = set_pem_cert_key(pem_cert_key)
if set_pem_cert_key_err then
ngx.log(ngx.ERR, set_pem_cert_key_err)
ngx.exit(ngx.ERROR)
end
end

return _M
31 changes: 21 additions & 10 deletions rootfs/etc/nginx/lua/test/certificate_test.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
_G._TEST = true

local certificate = require("certificate")
local unmocked_ngx = _G.ngx

Expand All @@ -8,12 +6,12 @@ describe("Certificate", function()
local ssl = require("ngx.ssl")
local match = require("luassert.match")

ssl.server_name = function() return "hostname" end
ssl.server_name = function() return "hostname", nil end
ssl.clear_certs = function() return true, "" end
ssl.cert_pem_to_der = function(cert) return cert end
ssl.set_der_cert = function(cert) return cert end
ssl.priv_key_pem_to_der = function(priv_key) return priv_key end
ssl.set_der_priv_key = function(priv_key) return priv_key end
ssl.cert_pem_to_der = function(cert) return cert ~= "" and cert, "" or nil, "error" end
ssl.set_der_cert = function(cert) return true, "" end
ssl.priv_key_pem_to_der = function(priv_key) return priv_key, "" end
ssl.set_der_priv_key = function(priv_key) return true, "" end

it("does not clear fallback certificates and logs error message when host is not in dictionary", function()
spy.on(ngx, "log")
Expand Down Expand Up @@ -43,19 +41,32 @@ describe("Certificate", function()
assert.spy(ssl.set_der_priv_key).was_called_with(fake_pem_cert_key)
end)

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

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_called_with(ngx.ERR, "failed to convert certificate chain from PEM to DER: error")
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

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 for the given hostname: hostname")
assert.spy(ngx.log).was_called_with(ngx.ERR, "Error getting the hostname: 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()
end)
end)
end)
end)
48 changes: 25 additions & 23 deletions test/e2e/lua/dynamic_certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package lua

import (
"crypto/tls"
"fmt"
"net/http"
"strings"
Expand Down Expand Up @@ -49,8 +50,7 @@ var _ = framework.IngressNginxDescribe("Dynamic Certificate", func() {
Expect(err).NotTo(HaveOccurred())
Expect(ing).NotTo(BeNil())

// give some time for Lua to sync the backend
time.Sleep(5 * time.Second)
time.Sleep(waitForLuaSync)

resp, _, errs := gorequest.New().
Get(f.IngressController.HTTPURL).
Expand Down Expand Up @@ -89,7 +89,7 @@ var _ = framework.IngressNginxDescribe("Dynamic Certificate", func() {

_, err = f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.IngressController.Namespace).Update(ingress)
Expect(err).ToNot(HaveOccurred())
time.Sleep(5 * time.Second)
time.Sleep(waitForLuaSync)

log, err := f.NginxLogs()
Expect(err).ToNot(HaveOccurred())
Expand All @@ -108,12 +108,10 @@ var _ = framework.IngressNginxDescribe("Dynamic Certificate", func() {
Expect(restOfLogs).To(ContainSubstring(logSkipBackendReload))
Expect(restOfLogs).ToNot(ContainSubstring(logInitialConfigSync))
})
})

It("should be able to update SSL certificate even when the update POST size(request body) > size(client_body_buffer_size)", func() {
// Update client-body-buffer-size to 1 byte
err := f.UpdateNginxConfigMapData("client-body-buffer-size", "1")
Expect(err).NotTo(HaveOccurred())

Context("when certificates are requested", func() {
It("should serve certificates dynamically from Lua", func() {
ingress, err := f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.IngressController.Namespace).Get("foo.com", metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())

Expand All @@ -132,26 +130,30 @@ var _ = framework.IngressNginxDescribe("Dynamic Certificate", func() {

_, err = f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.IngressController.Namespace).Update(ingress)
Expect(err).ToNot(HaveOccurred())
time.Sleep(5 * time.Second)
time.Sleep(waitForLuaSync)

By("checking SSL Certificate using the NGINX IP address")
resp, _, errs := gorequest.New().
Get(f.IngressController.HTTPURL).
Set("Host", "foo.com").
Get(f.IngressController.HTTPSURL).
Set("Host", ingress.Spec.TLS[0].Hosts[0]).
TLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
}).
End()
Expect(len(errs)).Should(BeNumerically("==", 0))
Expect(resp.StatusCode).Should(Equal(http.StatusOK))

log, err := f.NginxLogs()
Expect(err).ToNot(HaveOccurred())
Expect(log).ToNot(BeEmpty())
index := strings.Index(log, "POST /configuration/servers HTTP/1.1")
restOfLogs := log[index:]

Expect(err).ToNot(HaveOccurred())
Expect(log).ToNot(BeEmpty())
Expect(len(errs)).Should(BeNumerically("==", 0))
Expect(len(resp.TLS.PeerCertificates)).Should(BeNumerically("==", 1))
for _, pc := range resp.TLS.PeerCertificates {
Expect(pc.Issuer.CommonName).Should(Equal("default"))
}

By("POSTing new servers to Lua endpoint")
Expect(restOfLogs).ToNot(ContainSubstring("dynamic-configuration: unable to read valid request body"))
By("checking that only the default certificate is written on disk")
err = f.WaitForNginxServer(ingress.Spec.TLS[0].Hosts[0],
func(server string) bool {
return strings.Contains(server, "ssl_certificate /etc/ingress-controller/ssl/default-fake-certificate.pem;") &&
strings.Contains(server, "ssl_certificate_key /etc/ingress-controller/ssl/default-fake-certificate.pem;")
})
Expect(err).NotTo(HaveOccurred())
})
})
})
Expand Down

0 comments on commit afd22c0

Please sign in to comment.