-
Notifications
You must be signed in to change notification settings - Fork 170
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
Support HTTPS and introduce ssl_certificate policy phase #622
Conversation
ab81e24
to
1df0f9a
Compare
gateway/src/apicast/executor.lua
Outdated
@@ -52,7 +52,7 @@ end | |||
-- @tparam string phase Nginx phase | |||
-- @treturn linked_list The context. Note: The list returned is 'read-write'. | |||
function _M:context(phase) | |||
if phase == 'init' then | |||
if phase == 'init' or phase == 'ssl_certificate' then |
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.
why?
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.
Good question. That is probably a leftover from a debugging session. Will take a look.
{%- assign http_port = port.apicast | default: 8080 %} | ||
{%- assign https_port = env.APICAST_HTTPS_PORT %} | ||
|
||
{% if http_port != https_port -%} |
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.
Have you tried this with https_port = nil
?
I remember problems when comparing nils in Liquid, but maybe it was a different issue.
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.
I'd add a new test case in t/listen-https.t
just to be sure.
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.
So like the variable not set at all? That works - normal blackbox tests run with https_port not set.
The issue was that {% if env.somevar %}
would be true even if it is empty.
This works just fine because http_port
always has value.
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.
Right 👍
gateway/conf/nginx.conf.liquid
Outdated
@@ -77,6 +77,9 @@ http { | |||
{% include tracer_conf %} | |||
{% endif %} | |||
|
|||
ssl_session_fetch_by_lua_block { require('apicast.executor'):ssl_session_fetch() } |
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.
I don't see ssl_session_fetch()
and ssl_session_store()
defined anywhere. What I am missing?
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.
Actually I did not want to commit those lines just say. Will remove them. Want to keep it for the future.
@@ -14,6 +14,8 @@ local PHASES = { | |||
'content', 'balancer', | |||
'header_filter', 'body_filter', | |||
'post_action', 'log', 'metrics', | |||
|
|||
'ssl_certificate', |
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.
Can you add this new phase to the list that we have in policies.md
?
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.
Yep.
end | ||
|
||
_M.rewrite = find_service | ||
_M.ssl_certificate = find_service |
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.
why?
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.
ssl_certificate executes first and needs to have access to the service so it can execute the chain
I'm going to verify the context is shared or not after removing #622 (comment). But then it still needs to find the service in both (but can skip if the service is already found).
gateway/conf/nginx.conf.liquid
Outdated
@@ -131,8 +134,10 @@ http { | |||
|
|||
{% if https_port -%} | |||
listen {{ https_port }} ssl; | |||
ssl_certificate {{ env.APICAST_HTTPS_CERTIFICATE }}; | |||
ssl_certificate_key {{ env.APICAST_HTTPS_CERTIFICATE_KEY }}; | |||
ssl_certificate {{ env.APICAST_HTTPS_CERTIFICATE | default: "conf/server.crt" | filesystem | first }}; |
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.
Why is first
needed?
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.
because | filesystem
produces a table and it can't be serialized.
@@ -30,4 +31,8 @@ function _M:rewrite(context) | |||
context.configuration = configuration_loader.rewrite(self.configuration, context.host) | |||
end | |||
|
|||
function _M.ssl_certificate(_, context) | |||
context.host = ssl.server_name() |
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.
ssl.server_name()
can return an error: https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#server_name
Shouldn't we handle it?
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.
If it returns error then context.host
is going to be nil and no service policy chain will be found.
In that case we serve whatever certificate was set to APICAST_HTTPS_CERTIFICATE or the provided default.
Maybe we should just log the error with some low log level like debug.
doc/policies.md
Outdated
@@ -53,6 +53,9 @@ Notice that we did not indicate what APIcast does in the `init` and the | |||
request. `init` is executed when APIcast boots, and `init_worker` when each | |||
of each of its workers start. | |||
|
|||
Another phase that is not executed for every request is `ssl_certificate' because |
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.
That ' should be a `.
gateway/conf/nginx.conf.liquid
Outdated
listen {{ https_port }} ssl; | ||
|
||
{%- assign https_certificate = env.APICAST_HTTPS_CERTIFICATE -%} | ||
ssl_certificate {% if https_certificate or https_certificate != empty -%} |
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.
I'm not sure I understand this. Shouldn't it be an and
instead of an or
?
Does an empty string pass the first part of the or
in Liquid?
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.
I was trying to work around an issue with the liquid library. {% "somestring" == empty %}
crashes. Will remove the or
part as that would still not execute when using magic tables like in other parts (where we have to check for == empty).
|
||
{%- assign https_certificate = env.APICAST_HTTPS_CERTIFICATE -%} | ||
ssl_certificate {% if https_certificate -%} | ||
{{ https_certificate }} |
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.
This one does not need | filesystem | first
?
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.
This is path that was given by user in ENV, so we should not need to do any transformations.
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.
Also, it does not really work. The | filesystem
filter does not really work with absolute paths (yet).
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.
👍
👍 |
includes 3scale/Test-APIcast#9 includes 3scale/Test-APIcast#10
* when APICAST_HTTPS_PORT is set * APICAST_HTTPS_CERTIFICATE needs to point to a certificate * APICAST_HTTPS_CERTIFICATE_KEY needs to point to a private key
* allows policies to serve ssl certificate * service is detected by host from SNI * policy should clear certificates before setting them
Allow APIcast to listen for HTTPS connections. Either by using static certificate or allow policy to supply one.
This PR has two parts:
Listen on HTTPS
Controlled by
APICAST_HTTPS_PORT
ENV variable.Path to the certificate and key is defined by
APICAST_HTTPS_CERTIFICATE
andAPICAST_HTTPS_CERTIFICATE_KEY
ENV variables.ssl_certificate
phaseNew policy phase can select a certificate. It can load it from network or a file. See lua-resty-autossl how to get letsencrypt certificates automatically.
Fixes #609
Depends on 3scale/Test-APIcast#9
Depends on 3scale/Test-APIcast#10