I've been working through troubleshooting template requests via a
smart-proxy without a token present.
The request is from the client IP, which gets masked by the proxy on
forward, but when I reviewed the code I noticed that the proxy inserts an
X-Forwarded-For header, which foreman's unattended_controller looks at and
is supposed to honour.
However, I can't make sense of the following code:
def ip_from_request_env
ip = request.env['REMOTE_ADDR']
# check if someone is asking on behalf of another system (load balance
etc)
if request.env['HTTP_X_FORWARDED_FOR'].present? and (ip =~
Regexp.new(Setting[:remote_addr]))
ip = request.env['HTTP_X_FORWARDED_FOR']
end
ip
end
In my environment, foreman is running behind passenger, and the remote_addr
setting is 127.0.0.1.
When a request comes from a smart-proxy, the Regexp.new check fails, and
'ip' never gets set to the X-Forwarded-For IP, it retains the proxy's
source IP, which fails to render.
If I change the code to:
if request.env['HTTP_X_FORWARDED_FOR'].present?
everything works as I expect it to.
Am I missing something here, or is the code not quite right?
If I recall correctly (disclaimer, it's been a while :P), the default of
127.0.0.1 is a security default which will prevent matching anything on the
network spoofing hosts without a valid token. This is the only sane default
when we (a priori) know little about the users network setup. I think you
just need to set :remote_addr to a regular expression which will match the
Smart Proxy's IP, so that the second half will succeed and use the header.
Greg
···
On 17 July 2016 at 06:42, adiran wrote:
I’ve been working through troubleshooting template requests via a
smart-proxy without a token present.
The request is from the client IP, which gets masked by the proxy on
forward, but when I reviewed the code I noticed that the proxy inserts an
X-Forwarded-For header, which foreman’s unattended_controller looks at and
is supposed to honour.
However, I can’t make sense of the following code:
def ip_from_request_env
ip = request.env[‘REMOTE_ADDR’]
# check if someone is asking on behalf of another system (load balance
etc)
if request.env[‘HTTP_X_FORWARDED_FOR’].present? and (ip =~
Regexp.new(Setting[:remote_addr]))
ip = request.env[‘HTTP_X_FORWARDED_FOR’]
end
ip
end
In my environment, foreman is running behind passenger, and the
remote_addr setting is 127.0.0.1.
When a request comes from a smart-proxy, the Regexp.new check fails, and
’ip’ never gets set to the X-Forwarded-For IP, it retains the proxy’s
source IP, which fails to render.
If I change the code to:
if request.env['HTTP_X_FORWARDED_FOR'].present?
everything works as I expect it to.
Am I missing something here, or is the code not quite right?
Ok, this makes a little more sense. So in an environment with many
smart-proxies, the IP of each one would need to be included in this regexp?
I just assumed that foreman would take care of accepting X-Forwarded-For
from smart-proxy IPs which are registered, since it already knows about
them.
This setting could use a little more detail in the manual, glad you recall.
···
On Sunday, July 17, 2016 at 9:34:10 AM UTC-4, Greg Sutcliffe wrote:
>
> On 17 July 2016 at 06:42, adiran <adrian...@gmail.com > > wrote:
>
>> I've been working through troubleshooting template requests via a
>> smart-proxy without a token present.
>>
>> The request is from the client IP, which gets masked by the proxy on
>> forward, but when I reviewed the code I noticed that the proxy inserts an
>> X-Forwarded-For header, which foreman's unattended_controller looks at and
>> is supposed to honour.
>>
>> However, I can't make sense of the following code:
>>
>> def ip_from_request_env
>> ip = request.env['REMOTE_ADDR']
>>
>> # check if someone is asking on behalf of another system (load
>> balance etc)
>> if request.env['HTTP_X_FORWARDED_FOR'].present? and (ip =~
>> Regexp.new(Setting[:remote_addr]))
>> ip = request.env['HTTP_X_FORWARDED_FOR']
>> end
>>
>> ip
>> end
>>
>> In my environment, foreman is running behind passenger, and the
>> remote_addr setting is 127.0.0.1.
>>
>> When a request comes from a smart-proxy, the Regexp.new check fails, and
>> 'ip' never gets set to the X-Forwarded-For IP, it retains the proxy's
>> source IP, which fails to render.
>>
>> If I change the code to:
>>
>> if request.env['HTTP_X_FORWARDED_FOR'].present?
>>
>> everything works as I expect it to.
>>
>> Am I missing something here, or is the code not quite right?
>>
>
> If I recall correctly (disclaimer, it's been a while :P), the default of
> 127.0.0.1 is a security default which will prevent matching anything on the
> network spoofing hosts without a valid token. This is the only sane default
> when we (a priori) know little about the users network setup. I think you
> just need to set :remote_addr to a regular expression which will match the
> Smart Proxy's IP, so that the second half will succeed and use the header.
>
> Greg
>
> Ok, this makes a little more sense. So in an environment with many
> smart-proxies, the IP of each one would need to be included in this regexp?
>
> I just assumed that foreman would take care of accepting X-Forwarded-For
> from smart-proxy IPs which are registered, since it already knows about
> them.
>
I'm away from my desk, so I'm working from memory, but I think this
predates the smart-proxy-auth system that came in later for validating
things like ENC requests from valid proxies. The main issue there is that
the proxy-auth relies on validating the names in the SSL certificate -
templates usually aren't acquired over https, so this wouldn't work here.
It might be possible to adapt / re-use some of those ideas though - I do
agree that it's non-intuitive compared to how ENC/reports works.
> This setting could use a little more detail in the manual, glad you recall.
>
I cloned the repo, modified the doc section, and committed.
First time doing this on github, so if I've done something backwards, or
broken any code etiquette, I stand to be corrected.
···
On Sunday, July 17, 2016 at 11:38:23 AM UTC-4, Greg Sutcliffe wrote:
>
> On 17 July 2016 at 16:22, adiran <adrian...@gmail.com > > wrote:
>
>> Ok, this makes a little more sense. So in an environment with many
>> smart-proxies, the IP of each one would need to be included in this regexp?
>>
>> I just assumed that foreman would take care of accepting X-Forwarded-For
>> from smart-proxy IPs which are registered, since it already knows about
>> them.
>>
>
> I'm away from my desk, so I'm working from memory, but I think this
> predates the smart-proxy-auth system that came in later for validating
> things like ENC requests from valid proxies. The main issue there is that
> the proxy-auth relies on validating the names in the SSL certificate -
> templates usually aren't acquired over https, so this wouldn't work here.
> It might be possible to adapt / re-use some of those ideas though - I do
> agree that it's non-intuitive compared to how ENC/reports works.
>
>
>> This setting could use a little more detail in the manual, glad you
>> recall.
>>
>
> Sure, feel free -
> https://github.com/theforeman/theforeman.org/blob/gh-pages/_includes/manuals/1.12/3.5.2_configuration_options.md
> :)
>
> Greg
>
diff --git a/_includes/manuals/1.12/3.5.2_configuration_options.md
b/_includes/manuals/1.12/3.5.2_conf
index 6eafb9b…b1b26dd 100644
— a/_includes/manuals/1.12/3.5.2_configuration_options.md
+++ b/_includes/manuals/1.12/3.5.2_configuration_options.md
@@ -385,7 +385,13 @@ See also: dns_conflict_timeout
remote_addr
-If Foreman is running behind Passenger or a remote load balancer, the IP
of this load balance should
+When foreman receives client web requests via a smart proxy, proxy or load
balancer, the original client source IP address is lost, replaced by the
smart proxy, proxy, or load balancers IP instead. For template requests
without a token, this causes a failure, because foreman can't match the
request against a valid host.
···
+
+Smart proxies, and other devices if configured, can preserve the original
client IP within an HTTP X-Forwarded-For header, which foreman can evaluate
and use to match the request against a valid host.
+
+In order to prevent spoofing and provide some level of security, foreman
will only evaluate X-Forwarded-For headers from devices which match the
list of IPs configured here.
+
+This is a regular expression, so it can support several load balancers,
i.e: (10.0.0.1|127.0.0.1)
Default: 127.0.0.1
require_ssl_smart_proxies
On Sunday, July 17, 2016 at 1:29:16 PM UTC-4, adrian wrote:
I cloned the repo, modified the doc section, and committed.
First time doing this on github, so if I’ve done something backwards, or
broken any code etiquette, I stand to be corrected.
On Sunday, July 17, 2016 at 11:38:23 AM UTC-4, Greg Sutcliffe wrote:
Ok, this makes a little more sense. So in an environment with many
smart-proxies, the IP of each one would need to be included in this regexp?
I just assumed that foreman would take care of accepting X-Forwarded-For
from smart-proxy IPs which are registered, since it already knows about
them.
I’m away from my desk, so I’m working from memory, but I think this
predates the smart-proxy-auth system that came in later for validating
things like ENC requests from valid proxies. The main issue there is that
the proxy-auth relies on validating the names in the SSL certificate -
templates usually aren’t acquired over https, so this wouldn’t work here.
It might be possible to adapt / re-use some of those ideas though - I do
agree that it’s non-intuitive compared to how ENC/reports works.
This setting could use a little more detail in the manual, glad you
recall.
Thanks so much! I followed the article and created a pull request.
···
On Monday, July 18, 2016 at 8:59:25 AM UTC-4, Dominic Cleal wrote:
>
> On 17/07/16 18:33, adrian wrote:
> > Nevermind, I can't push, so here's the diff:
>
> If you push your branch to your GitHub fork, you can open up a pull
> request from the web UI against the original repo. See
> https://help.github.com/articles/using-pull-requests/ for details.
>
> --
> Dominic Cleal
> dom...@cleal.org
>