HAProxy ACL whitelist IPs CIDR notation - load-balancing

I have an HAProxy load balancer and I would like to allow access only to certain IPs. I know how to do this using the regular notation:
acl is_ip_allowed src 173.245.48.1
http-request deny if !is_ip_allowed
But when I use CIDR notation is not working
acl is_ip_allowed src 173.245.48.0/20
http-request deny if !is_ip_allowed
This should be possible if I got the HAProxy documentation correctly
IPv4 addresses values can be specified either as plain addresses or
with a netmask appended, in which case the IPv4 address matches
whenever it is within the network. Plain addresses may also be
replaced with a resolvable host name, but this practice is generally
discouraged as it makes it more difficult to read and debug
configurations. If hostnames are used, you should at least ensure that
they are present in /etc/hosts so that the configuration does not
depend on any random DNS match at the moment the configuration is
parsed.
But unfortunately, it's not working. Am I missing something?

After consulting with a colleague I found an answer.
http-request deny if !{ src 173.245.48.0/20 }
So, removing the ACL and adding the CIDR range in an IF condition works.

Related

ModSecurity: Block all IPs except for a list of defined IPs

I have an apache server with ModSecurity. I need to block all IPs except for a few ones.
The list of IPs is like this:
194.83.128.0/21
191.143.32.0/19
145.126.72.0/21
101.28.248.0/22
40.64.64.0/22
180.11.124.0/22
190.230.64.0/18
109.154.0.0/16
42.60.0.0/16
43.223.0.0/16
2a03:e980::/29
Right now I applied this rule:
SecRule REMOTE_ADDR "#ipMatch 194.83.128.0/21,191.145.32.0/19,145.126.72.0/21,101.28.248.0/22,40.64.64.0/22,180.11.124.0/22,190.230.64.0/18,109.154.0.0/16,42.60.0.0/16,43.223.0.0/16,2a03:e980::/29" "id:162"
But the rule above seems to be doing a whitelist rather than blocking all IPs except for the ones defined in the rule.
I'm not sure how to achieve blocking all IPs except the ones on my list. Most of the documentation I have found is related to blocking or adding IPs to a deny list, when some action happens, like constantly accessing 404 pages.
Is there a way to block by default all the IPs, except the ones defined in my list?
There are a couple options that you can use here.
Just use Apache core. I'm assuming you have Apache 2.4. You can use the Require Directive:
<RequireAny>
#IPv4 ranges to allow
Require ip 194.83.128.0/21
Require ip 191.143.32.0/19
...
</RequireAny>
This will allow only the IPs you add to that list.
Use modsecurity in Apache.
The rule you want is to do something similar to:
SecRule REMOTE_ADDR "#ipMatch 194.83.128.0/21,191.143.32.0/19,..." "id:50000,phase:1,nolog,allow,ctl:ruleEngine=Off"
Adding all your IP CIDR ranges on that list.
Optionally you can use store that list in a file (in this example, ips.txt) with one cidr range per line and use the #ipMatchFromFile operator:
SecRule REMOTE_ADDR "#ipMatchFromFile ips.txt" "id:50001,phase:1,nolog,allow,ctl:ruleEngine=Off"
In the modsecurity rule I added the nolog action so you won't see any matches from those IPs. If you want to take a peek and see that they are being recognized, use log instead.
Warning Note: please be 100% sure that no attacks are coming from your networks. Pay special attention to SSRF. Because this will disable modsecurity entirely from anything coming from your listed IP ranges.

Apache2 virtualhost "allow from" dynamic DNS hostname?

I have a cloud-based apache2 web server, which serves multiple sites using various virtualhost conf files.
One of the websites is for my development only, and is currently configured to only allow my current IP address.
Order deny,allow
Deny from all
Allow from 1.2.4.5
However my IP changes once a week or so - so I'd prefer to use my dynamic DNS hostname. Alas this...
Allow from abc.ddns.net
... does not work. Can it be done?
It can work, but it requires your DNS to be setup perfectly. If you use allow from {hostname} then for each relevant URI path, Apache requests a reverse DNS lookup of the IP for the connection, and then if that returns the correct host name from your allow directive Apache then rechecks that that name resolves to the IP of the original connection.
This is all a relatively expensive set of operations and is normally not recommended. Allow from {ip address} would normally be preferred.

Cant access my website through its IP address

I have hosting with godaddy with a private IP address. I am able to access my websites and others via the domain name, but not via IP Address.
I am now trying to access the HTTP via port 80 but it gives an error that the website is not setup.
Are there any workarounds on turning allowing accessing the website and other folders through the IP address over http?
This sounds to me like you were on a managed webpack that grants you access to the to-be-served content but not to the webserver or its config itself.
What you are experiencing there is an effect of a technique called virtual-hosts in which multiple sites are tied to one IP address. For this to work in the realm of HTTP, the Host header got introduced in HTTP/1.1. It allows clients to send a domain name for which they want to receive content.
If you request a raw IP, though, the Host header won't look like Host: example.com but rather like Host: 123.45.67.89. The server will not be able to associate a domainname with this as it is unlikely to be found elsewhere in the request. Therefore, it will be forced to serve content out of its default document directory which usually contains further documentations regarding the further configuration of the webserver in question. Linux distributions like to add additional informations specific to them. Check if you see any mentioning of e.g. Debian, RedHat, or Centos.
I am not sure if this is fixable. Usually webservers like Apache support IP-based virtual hosts. If a masshoster like godaddy is really going to address this is uncertain. Try to contact their support and see.
1]If you are using host headers, make sure you have a DNS entry pointing your URL to your IP
2]Telnet port 80 from a machine outside your network.If it fails then check with your ISP that port 80 should not block in firewall.

Apache - multiple sites on one IP, domain and port with SSL

Is it possible to run multiple apache sites on the same IP, domain and port (meaning the <VirtualHost> tags are exactly identical and no ServerName is given) while using SSL (not sure whether SSL makes a difference here)?
I would like to separate my web services into files in etc/apache2/sites-available to be able to activate or deactivate them on demand. Basically Apache should just take all files and string them together internally, but leave me the possibility to a2dissite certain parts.
Further clarification:
By "sites", I mean files in the etc/apache2/sites-available directory. "Web services" in this context are certain application like phpMyAdmin or an Etherpad which run on the Apache and whose configuration (e.g. Alias or ProxyPass) I want to write into its own configuration file ("site"),
The short answer is no.
SSL operates at a level between TCP and HTTP. But the virtual host name is sent via HTTP. So how does SSL know which certificate to use for a virtual host?
There is a way to do it - basically start up the HTTP over TCP then switch to SSL after the virtual host name (in the Host header) is sent. However this is complex, error prone and generally considered a bad idea.
Best practice is to have one IP per SSL. One machine can have multitple IP addresses, even a single network port can have mulitple IP addresses.

Set REMOTE_ADDR to X-Forwarded-For in apache

In a situation where Apache is sitting behind a reverse proxy (such as Squid), the cgi environment variable REMOTE_ADDR gets the address of the proxy rather than the client.
However, the proxy will set a header called X-Forwarded-For to contain the original IP address of the client so that Apache can see it.
The question is, how do we get Apache to replace REMOTE_ADDR with the value in the X-Forwarded-For header so that all of the web applications will transparently see the correct address?
You can use mod_rpaf for that. http://stderr.net/apache/rpaf/
Currently apache module mod_remoteip is the recommended way to do this; rpaf hasn't been reliably maintained, and can cause problems.
Note that the X-Forwarded-For header may contain a list of IP addresses if the request has traversed more than one proxy. In this case, you usually want the leftmost IP. You can extract this with a SetEnvIf:
SetEnvIf X-Forwarded-For "^(\d{1,3}+\.\d{1,3}+\.\d{1,3}+\.\d{1,3}+).*" XFFCLIENTIP=$1
Note the use of $1 to set the XFFCLIENTIP environment variable to hold the contents of the first group in the regex (in the parentheses).
Then you can use the value of the environment variable to set headers (or use it in Apache log formats so that the logs contain the actual client IP).
In addition to mod_rpaf as mentioned before, it appears that mod_extract_forwarded will perform this function as well.
One advantage to mod_extract_forwarded is that it is available from EPEL for RHEL/CentOS servers whereas mod_rpaf is not.
It appears that neither of these two modules allow you to whitelist an entire subnet of proxy servers, which is why the CloudFlare folks created their own plugin: mod_cloudflare which, it should be noted, is not a general-purpose tool like the other two; it contains a hardcoded list of CloudFlare subnets.
Yes, we can do this.
Just add a auto_prepend_file in your PHP.ini like auto_prepend_file = "c:/prepend.php"
and in this file add this:
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
You need the MOD_REMOTEIP in apache width RemoteIPHeader X-Real-IP.
Cheers,
Guiremach
Since Apache 2.4 there is mod_remoteip built-in module that does this.
Enable mod_remoteip
(e.g. a2enmod remoteip)
Create a list of trusted IP ranges (the IPs from which you accept the remote IP header). You can put them in a file like conf/trusted-ranges.txt
Add this line to the Apache config:
RemoteIPTrustedProxyList conf/trusted-ranges.txt
Change your log file formats to use %a instead of %h for logging the client IP.
For Cloudflare you need to trust all their IP ranges and use a custom header CF-Connecting-IP:
RemoteIPHeader CF-Connecting-IP
You can get Cloudflare ranges like this:
curl https://www.cloudflare.com/ips-v4 > trusted-ranges.txt
curl https://www.cloudflare.com/ips-v6 >> trusted-ranges.txt
Unfortunately,
at the time of this writing, none of the backports and forks at freshports.org, people.apache.org or gist.github.com worked. They were all based on an early alpha version of apache httpd 2.3 which was neither compatible with current versions of 2.2 nor 2.4.
So after hours of wasting time while trying to adjust the backports to create a real working one for httpd 2.2, I decided to move to httpd 2.4. Within httpd 2.4, mod_remoteip works smoothly, even if a load balancer has permanent keepalive connections which it uses to proxy requests from different actual client ip addresses to the backend. I'm not sure if the other modules can handle this situation (changing client ip addresses on each request within the same connection).
Remember that this value can be spoofed. See http://blog.c22.cc/2011/04/22/surveymonkey-ip-spoofing/ for a real-life example with Cross-site Scripting consequences.
You can install the module mod_extract_forwarded and set MEFaccept parameter to all.