-
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(proxy) X-Forwarded-* upstream headers #2236
Changes from 13 commits
ac2000d
4193423
8e2fcb1
f885be2
77b394b
618c19b
ccc4781
d0c40c5
514ff60
89eaeea
bad20fc
600c4c5
1f8b67b
d966e41
79c2743
f4d7859
5045b3d
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 |
---|---|---|
|
@@ -19,6 +19,8 @@ local balancer_execute = require("kong.core.balancer").execute | |
|
||
|
||
local router, router_err | ||
local tostring = tostring | ||
local ngx = ngx | ||
local ngx_now = ngx.now | ||
local server_header = _KONG._NAME.."/".._KONG._VERSION | ||
|
||
|
@@ -119,9 +121,25 @@ return { | |
end | ||
|
||
-- if set `host_header` is the original header to be preserved | ||
var.upstream_host = host_header or | ||
var.upstream_host = host_header or | ||
balancer_address.hostname..":"..balancer_address.port | ||
|
||
-- X-Forwarded Headers | ||
local realip_remote_addr = var.realip_remote_addr | ||
|
||
if not singletons.ip.trusted(realip_remote_addr) then | ||
var.upstream_x_forwarded_proto = var.scheme | ||
var.upstream_x_forwarded_host = var.host | ||
var.upstream_x_forwarded_port = var.server_port | ||
end | ||
|
||
local http_x_forwarded_for = var.http_x_forwarded_for | ||
if http_x_forwarded_for then | ||
var.upstream_x_forwarded_for = http_x_forwarded_for .. ", " .. realip_remote_addr | ||
|
||
else | ||
var.upstream_x_forwarded_for = var.remote_addr | ||
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. I think some comments here would be very beneficial to avoid future confusion, regarding the usage of 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. Comments were added. |
||
end | ||
end, | ||
-- Only executed if the `router` module found an API and allows nginx to proxy it. | ||
after = function() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,10 +23,6 @@ client_max_body_size 0; | |
proxy_ssl_server_name on; | ||
underscores_in_headers on; | ||
|
||
real_ip_header X-Forwarded-For; | ||
set_real_ip_from 0.0.0.0/0; | ||
real_ip_recursive on; | ||
|
||
lua_package_path '${{LUA_PACKAGE_PATH}};;'; | ||
lua_package_cpath '${{LUA_PACKAGE_CPATH}};;'; | ||
lua_code_cache ${{LUA_CODE_CACHE}}; | ||
|
@@ -65,25 +61,48 @@ upstream kong_upstream { | |
} | ||
|
||
map $http_upgrade $upstream_connection { | ||
default keep-alive; | ||
default keep-alive; | ||
websocket upgrade; | ||
} | ||
|
||
map $http_upgrade $upstream_upgrade { | ||
default ''; | ||
default ''; | ||
websocket websocket; | ||
} | ||
|
||
map $http_x_forwarded_proto $upstream_x_forwarded_proto { | ||
default $http_x_forwarded_proto; | ||
'' $scheme; | ||
} | ||
|
||
map $http_x_forwarded_host $upstream_x_forwarded_host { | ||
default $http_x_forwarded_host; | ||
'' $host; | ||
} | ||
|
||
map $http_x_forwarded_port $upstream_x_forwarded_port { | ||
default $http_x_forwarded_port; | ||
'' $server_port; | ||
} | ||
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. Any reason why we're not handling those in the Lua logic but need those maps again instead? I don't remember if there was a special case that they handle in lieu of an 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. We just initialize the vars with defaults. We can do it in Lua land as well. 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. That would avoid having pieces of the logic in two different places indeed |
||
|
||
server { | ||
server_name kong; | ||
> if real_ip_header == "proxy_protocol" then | ||
listen ${{PROXY_LISTEN}} proxy_protocol; | ||
> else | ||
listen ${{PROXY_LISTEN}}; | ||
> end | ||
error_page 404 408 411 412 413 414 417 /kong_error_handler; | ||
error_page 500 502 503 504 /kong_error_handler; | ||
|
||
access_log logs/access.log; | ||
|
||
> if ssl then | ||
> if real_ip_header == "proxy_protocol" then | ||
listen ${{PROXY_LISTEN_SSL}} proxy_protocol ssl; | ||
> else | ||
listen ${{PROXY_LISTEN_SSL}} ssl; | ||
> end | ||
ssl_certificate ${{SSL_CERT}}; | ||
ssl_certificate_key ${{SSL_CERT_KEY}}; | ||
ssl_protocols TLSv1.1 TLSv1.2; | ||
|
@@ -92,24 +111,33 @@ server { | |
} | ||
> end | ||
|
||
real_ip_header ${{REAL_IP_HEADER}}; | ||
real_ip_recursive ${{REAL_IP_RECURSIVE}}; | ||
> for i = 1, #trusted_ips do | ||
set_real_ip_from $(trusted_ips[i]); | ||
> end | ||
|
||
location / { | ||
set $upstream_host nil; | ||
set $upstream_scheme nil; | ||
set $upstream_host nil; | ||
set $upstream_scheme nil; | ||
set $upstream_x_forwarded_for nil; | ||
|
||
access_by_lua_block { | ||
kong.access() | ||
} | ||
|
||
proxy_http_version 1.1; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
proxy_set_header X-Forwarded-Proto $scheme; | ||
proxy_set_header Host $upstream_host; | ||
proxy_set_header Upgrade $upstream_upgrade; | ||
proxy_set_header Connection $upstream_connection; | ||
|
||
proxy_pass_header Server; | ||
proxy_pass $upstream_scheme://kong_upstream; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Forwarded-For $upstream_x_forwarded_for; | ||
proxy_set_header X-Forwarded-Proto $upstream_x_forwarded_proto; | ||
proxy_set_header X-Forwarded-Host $upstream_x_forwarded_host; | ||
proxy_set_header X-Forwarded-Port $upstream_x_forwarded_port; | ||
proxy_set_header Host $upstream_host; | ||
proxy_set_header Upgrade $upstream_upgrade; | ||
proxy_set_header Connection $upstream_connection; | ||
proxy_pass_header Server; | ||
proxy_pass_header Date; | ||
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. note: We should also mention this in the changelog and add it to the proxy guide list of forwarded headers from upstream |
||
proxy_pass $upstream_scheme://kong_upstream; | ||
|
||
header_filter_by_lua_block { | ||
kong.header_filter() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
local ip = require "resty.mediador.ip" | ||
local px = require "resty.mediador.proxy" | ||
|
||
|
||
local function trust_all() return true end | ||
local function trust_none() return false end | ||
|
||
|
||
local _M = { valid = ip.valid } | ||
|
||
|
||
function _M.init(config) | ||
local ips = config.trusted_ips | ||
local count = #ips | ||
local trusted_ips = {} | ||
local trust_all_ipv4, trust_all_ipv6 | ||
|
||
-- This is because we don't support unix: that the ngx_http_realip module supports. | ||
-- Also as an optimization we will only compile trusted ips if the Kong is not run | ||
-- with the default 0.0.0.0/0, ::/0 aka trust all ip addresses settings. | ||
for i = 1, count do | ||
local address = ips[i] | ||
|
||
if ip.valid(address) then | ||
trusted_ips[#trusted_ips+1] = address | ||
if address == "0.0.0.0/0" then | ||
trust_all_ipv4 = true | ||
|
||
elseif address == "::/0" then | ||
trust_all_ipv6 = true | ||
end | ||
end | ||
end | ||
|
||
if #trusted_ips == 0 then | ||
return { | ||
valid = ip.valid, | ||
trusted = trust_none, | ||
} | ||
end | ||
|
||
if trust_all_ipv4 and trust_all_ipv6 then | ||
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. note: we need to make sure to document that one needs both ipv4 and ipv6 forms specified to "trust all" (but tbh, I feel like we should respect the 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. Wasn't it so that 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. Yeah sorry I wasn't very clear here. Yes,
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. Do you think this is enough for now: |
||
return { | ||
valid = ip.valid, | ||
trusted = trust_all, | ||
} | ||
end | ||
|
||
return { | ||
valid = ip.valid, | ||
trusted = px.compile(trusted_ips), | ||
} | ||
end | ||
|
||
|
||
return _M |
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.
note to self: slightly rephrase for merge