-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(healthchecks) add support for HTTPS in active health checks #3815
Changes from all commits
925e402
b8d2608
ea8568a
20011dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,11 +55,30 @@ local header_name = Schema.define { | |
} | ||
|
||
|
||
local healthchecks_defaults = { | ||
local check_type = Schema.define { | ||
type = "string", | ||
one_of = { "tcp", "http", "https" }, | ||
default = "http", | ||
} | ||
|
||
|
||
local check_verify_certificate = Schema.define { | ||
type = "boolean", | ||
default = true, | ||
} | ||
|
||
|
||
local NO_DEFAULT = {} | ||
|
||
|
||
local healthchecks_config = { | ||
active = { | ||
type = "http", | ||
timeout = 1, | ||
concurrency = 10, | ||
http_path = "/", | ||
https_sni = NO_DEFAULT, | ||
https_verify_certificate = true, | ||
healthy = { | ||
interval = 0, -- 0 = probing disabled by default | ||
http_statuses = { 200, 302 }, | ||
|
@@ -75,6 +94,7 @@ local healthchecks_defaults = { | |
}, | ||
}, | ||
passive = { | ||
type = "http", | ||
healthy = { | ||
http_statuses = { 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, | ||
300, 301, 302, 303, 304, 305, 306, 307, 308 }, | ||
|
@@ -91,6 +111,7 @@ local healthchecks_defaults = { | |
|
||
|
||
local types = { | ||
type = check_type, | ||
timeout = seconds, | ||
concurrency = positive_int, | ||
interval = seconds, | ||
|
@@ -100,26 +121,37 @@ local types = { | |
http_failures = positive_int_or_zero, | ||
http_path = typedefs.path, | ||
http_statuses = http_statuses, | ||
https_sni = typedefs.sni, | ||
https_verify_certificate = check_verify_certificate, | ||
} | ||
|
||
|
||
local function gen_fields(tbl) | ||
local fields = {} | ||
local count = 0 | ||
for name, default in pairs(tbl) do | ||
local typ = types[name] | ||
local def | ||
local def, required | ||
if default == NO_DEFAULT then | ||
default = nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This answers the question in my first comment; ignore it :) |
||
required = false | ||
tbl[name] = nil | ||
end | ||
if typ then | ||
def = typ{ default = default } | ||
def = typ{ default = default, required = required } | ||
else | ||
def = { type = "record", fields = gen_fields(default), default = default } | ||
end | ||
count = count + 1 | ||
fields[count] = { [name] = def } | ||
end | ||
return fields | ||
return fields, tbl | ||
end | ||
|
||
|
||
local healthchecks_fields, healthchecks_defaults = gen_fields(healthchecks_config) | ||
|
||
|
||
local r = { | ||
name = "upstreams", | ||
primary_key = { "id" }, | ||
|
@@ -137,9 +169,9 @@ local r = { | |
{ slots = { type = "integer", default = 10000, between = { 10, 2^16 }, }, }, | ||
{ healthchecks = { type = "record", | ||
default = healthchecks_defaults, | ||
fields = gen_fields(healthchecks_defaults), | ||
fields = healthchecks_fields, | ||
}, }, | ||
}, | ||
}, | ||
entity_checks = { | ||
-- hash_on_header must be present when hashing on header | ||
{ conditional = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,24 @@ local function validate_name(name) | |
end | ||
|
||
|
||
local function validate_sni(host) | ||
local res, err_or_port = utils.normalize_ip(host) | ||
if type(err_or_port) == "string" and err_or_port ~= "invalid port number" then | ||
return nil, "invalid value: " .. host | ||
end | ||
|
||
if res.type ~= "name" then | ||
return nil, "must not be an IP" | ||
end | ||
|
||
if err_or_port == "invalid port number" or type(res.port) == "number" then | ||
return nil, "must not have a port" | ||
end | ||
|
||
return true | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I were to specify Also, are we lacking tests for this function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It was being tested indirectly via the upstreams tests (as is the case for some other typedefs). |
||
|
||
|
||
local typedefs = {} | ||
|
||
|
||
|
@@ -161,4 +179,10 @@ typedefs.name = Schema.define { | |
} | ||
|
||
|
||
typedefs.sni = Schema.define { | ||
type = "string", | ||
custom_validator = validate_sni, | ||
} | ||
|
||
|
||
return typedefs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https_sni
expects ahost
typedef (which in turn, if of typestring
), but the default is a table? Doesn't this feel strange?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the
host
typedef allows for IP addresses (https://github.com/Kong/kong/blob/master/kong/db/schema/typedefs.lua#L10-L19), while as per RFC 6066, an SNI can only contain DNS hostnames:This probably warrants the creation of a new
sni
typedef.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thibaultcha good catch! updated the code with the new
sni
typedef, and also applied it to thesnis.name
attribute while I was at it!