Skip to content

Commit

Permalink
Revert "fix(tls-metadata-headers): add intermediate certificates meta…
Browse files Browse the repository at this point in the history
…data (#1…" (#10112)

This reverts commit 0dff95f.
  • Loading branch information
locao authored Aug 28, 2024
1 parent 2b395de commit 78816c2
Show file tree
Hide file tree
Showing 9 changed files with 21 additions and 321 deletions.

This file was deleted.

3 changes: 0 additions & 3 deletions kong/clustering/compat/removed_fields.lua
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,5 @@ return {
statsd_advanced = {
"queue.concurrency_limit",
},
tls_metadata_headers = {
"forwarded_client_cert_header_name",
},
},
}
93 changes: 17 additions & 76 deletions kong/plugins/tls-metadata-headers/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@
local ngx = ngx
local kong = kong
local set_header = kong.service.request.set_header
local clear_header = kong.service.request.clear_header
local ngx_var = ngx.var
local meta = require "kong.meta"
local openssl_x509 = require "resty.openssl.x509"
local resty_kong_tls = require "resty.kong.tls"
local escape_uri = ngx.escape_uri
local ngx_re_match = ngx.re.match
local fmt = string.format
local to_hex = require "resty.string".to_hex


local TLSMetadataHandler = {
Expand All @@ -27,85 +20,33 @@ local TLSMetadataHandler = {
VERSION = meta.core_version
}


local function escape_fwcc_header_element_value(value)
if ngx_re_match(value, [=[["]]=]) then
value = value:gsub([["]], [[\"]])
end

if ngx_re_match(value, [=[[=,;]]=]) then
value = fmt([["%s"]], value)
end

return value
end


-- envoy implementation of the XFCC header:
-- https://github.com/envoyproxy/envoy/blob/8809f6bfe62e35c5bc42a1c6739167b71c64f637/source/common/http/conn_manager_utility.cc#L411-L504
-- https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers.html#x-forwarded-client-cert
function TLSMetadataHandler:access(conf)

if not conf.inject_client_cert_details then
return
end
if conf.inject_client_cert_details then

local ssl_client_escaped_cert = ngx.var.ssl_client_escaped_cert
if ssl_client_escaped_cert then
-- add http headers
set_header(conf.client_cert_header_name, ssl_client_escaped_cert)
if ngx.var.ssl_client_escaped_cert then
-- add http headers
set_header(conf.client_cert_header_name,
ngx_var.ssl_client_escaped_cert)

set_header(conf.client_serial_header_name,
ngx_var.ssl_client_serial)
set_header(conf.client_serial_header_name,
ngx_var.ssl_client_serial)

set_header(conf.client_cert_issuer_dn_header_name,
ngx_var.ssl_client_i_dn)
set_header(conf.client_cert_issuer_dn_header_name,
ngx_var.ssl_client_i_dn)

set_header(conf.client_cert_subject_dn_header_name,
ngx_var.ssl_client_s_dn)
set_header(conf.client_cert_subject_dn_header_name,
ngx_var.ssl_client_s_dn)

set_header(conf.client_cert_fingerprint_header_name,
ngx_var.ssl_client_fingerprint)
set_header(conf.client_cert_fingerprint_header_name,
ngx_var.ssl_client_fingerprint)

else
-- if the connection is not mutual TLS, remove the XFCC header
clear_header(conf.forwarded_client_cert_header_name)
kong.log.err("plugin enabled to inject tls client certificate headers, but " ..
"no client certificate was provided")
return
end

-- TODO: `By` needs the current proxy's cert.
-- Should call `SSL_get_certificate` in `lua-kong-nginx-modulel` or `lua-resty-openssl` first
local fwcc_header_value = fmt("Cert=%s;Subject=%s",
escape_fwcc_header_element_value(ssl_client_escaped_cert),
escape_fwcc_header_element_value(ngx_var.ssl_client_s_dn))

local x509, err = openssl_x509.new(ngx_var.ssl_client_raw_cert, "PEM")
if x509 then
local cert_hash = to_hex(x509:digest("sha256"))
fwcc_header_value = fmt("%s;Hash=%s", fwcc_header_value, cert_hash)

else
kong.log.err("could not create a new x509 instance: ", err)
end

local full_chain = resty_kong_tls.get_full_client_certificate_chain()
if full_chain then
fwcc_header_value = fmt("%s;Chain=%s", fwcc_header_value,
escape_fwcc_header_element_value(escape_uri(full_chain)))
else
kong.log.err("could not get full client certificate chain")
end

local orig_fwcc_header_value = ngx.req.get_headers()[conf.forwarded_client_cert_header_name]
if orig_fwcc_header_value then
if type(orig_fwcc_header_value) == "string" then
fwcc_header_value = fmt("%s,%s", orig_fwcc_header_value, fwcc_header_value)
else
kong.log.err("plugin enabled to inject tls client certificate headers, but " ..
"no client certificate was provided")
end
end

set_header(conf.forwarded_client_cert_header_name, fwcc_header_value)
end

end

Expand Down
6 changes: 0 additions & 6 deletions kong/plugins/tls-metadata-headers/schema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ return {
description = "Define the HTTP header name used for the SHA1 fingerprint of the client certificate.",
default = "X-Client-Cert-Fingerprint"
}, },
{ forwarded_client_cert_header_name = {
type = "string",
required = true,
description = "Define the HTTP header name used for clients or proxies certificate information. If inject_client_cert_details is set to true, the plugin will add certificate details to this header. If set to false, the plugin will forward the certificate information as it was received.",
default = "X-Forwarded-Client-Cert"
}, },
},
}, },
},
Expand Down
19 changes: 0 additions & 19 deletions spec-ee/03-plugins/38-tls-metadata-headers/01-access_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,6 @@ local tls_fixtures = { http_mock = {
proxy_pass https://127.0.0.1:9443/get;
}
location = /intermediate_client {
proxy_ssl_certificate ]] .. fixtures_path .. [[/intermediate_client_example.com.crt;
proxy_ssl_certificate_key ]] .. fixtures_path .. [[/intermediate_client_example.com.key;
proxy_ssl_name example.com;
proxy_set_header Host example.com;
proxy_pass https://127.0.0.1:9443/get;
}
}
]], }
}
Expand Down Expand Up @@ -147,17 +139,6 @@ for _, strategy in strategies() do
assert.is_nil(json.headers["X-Client-Cert"])
end)

it("returns HTTP 200 on https request if intermediate certificate passed", function()
local res = assert(tls_client:send {
method = "GET",
path = "/intermediate_client",
})
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.is_nil(json.headers["X-Client-Cert"])
assert.is_nil(json.headers["X-Forwarded-Client-Cert"])
end)

end)


Expand Down
107 changes: 4 additions & 103 deletions spec-ee/03-plugins/38-tls-metadata-headers/02-integration_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
local helpers = require "spec.helpers"
local cjson = require "cjson"
local escape_uri = ngx.escape_uri
local openssl_x509 = require "resty.openssl.x509"
local to_hex = require "resty.string".to_hex

local strategies = helpers.all_strategies ~= nil and helpers.all_strategies or helpers.each_strategy

Expand All @@ -19,7 +17,7 @@ local fixture_path_from_prefix = "../" .. fixture_path

local function read_fixture(filename)
local content = assert(helpers.utils.readfile(fixture_path .. filename))
return content
return content
end


Expand Down Expand Up @@ -69,22 +67,6 @@ local tls_fixtures = { http_mock = {
proxy_pass https://127.0.0.1:9443/anything;
}
location = /intermediate_client {
proxy_ssl_certificate ]] .. fixture_path_from_prefix .. [[/intermediate_client_example.com.crt;
proxy_ssl_certificate_key ]] .. fixture_path_from_prefix .. [[/intermediate_client_example.com.key;
proxy_ssl_name example.com;
proxy_set_header Host example.com;
proxy_pass https://127.0.0.1:9443/get;
}
location = /good_client_multi-chain {
proxy_ssl_certificate ]] .. fixture_path_from_prefix .. [[/client_example.com.crt;
proxy_ssl_certificate_key ]] .. fixture_path_from_prefix .. [[/client_example.com.key;
proxy_ssl_name example.com;
proxy_set_header Host example.com;
proxy_pass https://127.0.0.1:9443/get;
}
}
]], }
}
Expand All @@ -93,7 +75,7 @@ for _, strategy in strategies() do
describe("Plugin: tls plugins (access) [#" .. strategy .. "]", function()
local proxy_ssl_client, tls_client
local bp, db
local ca_cert, intermediate_cert
local ca_cert
local service_https, route_https1, route_https2, route_https3
local db_strategy = strategy ~= "off" and strategy or nil

Expand Down Expand Up @@ -158,10 +140,6 @@ for _, strategy in strategies() do
cert = read_fixture("ca.crt"),
}))

intermediate_cert = assert(db.ca_certificates:insert({
cert = read_fixture("intermediate_ca.crt"),
}))

route_https3 = bp.routes:insert {
service = { id = service_https.id, },
hosts = { "example.com" },
Expand All @@ -172,13 +150,8 @@ for _, strategy in strategies() do
assert(bp.plugins:insert {
name = "mtls-auth",
route = { id = route_https3.id },
config = { skip_consumer_lookup = true,
allow_partial_chain = true,
ca_certificates = {
ca_cert.id,
intermediate_cert.id,
},
},
config = { skip_consumer_lookup = true,
ca_certificates = { ca_cert.id, }, },
})

assert(bp.plugins:insert {
Expand Down Expand Up @@ -253,78 +226,6 @@ for _, strategy in strategies() do
assert.equal("88b74971771571c618e6c6215ba4f6ef71ccc2c7", json.headers["x-client-cert-fingerprint-custom"])
end)

it("returns HTTP 200 on https request if intermediate certificate validation passed", function()
local res = assert(tls_client:send {
method = "GET",
path = "/intermediate_client",
})
local body = assert.res_status(200, res)
local json = cjson.decode(body)
local m = assert(ngx.re.match(read_fixture("intermediate_client_example.com.crt"),
[[^\X+(?<cert>-----BEGIN CERTIFICATE-----\X+-----END CERTIFICATE-----\X*)]]))

local cert = escape_uri(m["cert"])
assert.equal(cert, json.headers["x-client-cert"])
assert.equal("1001", json.headers["x-client-cert-serial"])
assert.equal("CN=Interm.", json.headers["x-client-cert-issuer-dn"])
assert.equal("CN=1.example.com", json.headers["x-client-cert-subject-dn"])
assert.equal("4cf374a3d5a4afc25b87b7bb315b4140dfc69165", json.headers["x-client-cert-fingerprint"])
end)

it("returns HTTP 200 on https request if multi-chain certificate validation passed", function()
local res = assert(tls_client:send {
method = "GET",
path = "/good_client_multi-chain",
})
local body = assert.res_status(200, res)
local json = cjson.decode(body)
local certs = read_fixture("client_example.com.crt")
local it = assert(ngx.re.gmatch(certs,
[[(-----[BEGIN \S\ ]+?-----[\S\s]+?-----[END \S\ ]+?-----\X)]]))
local client_cert = assert(it()[1])
local escaped_client_cert = escape_uri(client_cert)
local x509 = assert(openssl_x509.new(client_cert, "PEM"))

-- x-client-cert should contain a single certificate
assert.equal("string", type(json.headers["x-client-cert"]))

assert.equal(escaped_client_cert, json.headers["x-client-cert"])
assert.equal("a65e0ff498d954b0ac33fd4f35f6d02de145667b", json.headers["x-client-cert-fingerprint"])

local xfcc_element = json.headers["x-forwarded-client-cert"]

local expected_cert = escaped_client_cert
local expected_subject = "\"[email protected],O=Kong Testing,ST=California,C=US\""
local expected_hash = to_hex(x509:digest("sha256"))
local expected_chain = escape_uri(certs)
local expected_xfcc = string.format("Cert=%s;Subject=%s;Hash=%s;Chain=%s",
expected_cert, expected_subject, expected_hash, expected_chain)

local xfcc_cert = ngx.re.match(xfcc_element, [[Cert=([^;]+);]])
assert.equal(expected_cert, xfcc_cert[1])
local xfcc_subject = ngx.re.match(xfcc_element, [[Subject=("[^";]+");]])
assert.equal(expected_subject, xfcc_subject[1])
local xfcc_hash = ngx.re.match(xfcc_element, [[Hash=([^;]+);]])
assert.equal(expected_hash, xfcc_hash[1])
local xfcc_chain = ngx.re.match(xfcc_element, [[Chain=(\S+0A)]])
assert.equal(expected_chain, xfcc_chain[1])
assert.equal(expected_xfcc, xfcc_element)

-- should append the xfcc element correcly
local original_xfcc = "Subject=\"CN=test\";Hash=194a2e827dd41919e5385a8776ddc211326dd7fc78752c671e35001ba8ef1936"
res = assert(tls_client:send {
method = "GET",
path = "/good_client_multi-chain",
headers = {
["x-forwarded-client-cert"] = original_xfcc,
}
})
body = assert.res_status(200, res)
json = cjson.decode(body)
local xfcc = json.headers["x-forwarded-client-cert"]
assert.equal(original_xfcc .. "," .. xfcc_element, xfcc)
end)

end)

describe("no certificate", function()
Expand Down
17 changes: 0 additions & 17 deletions spec/fixtures/tls-metadata-headers/intermediate_ca.crt

This file was deleted.

Loading

0 comments on commit 78816c2

Please sign in to comment.