-
-
Save liejuntao001/266f2c5a5e85be70201eee9bcbd2b4a4 to your computer and use it in GitHub Desktop.
*filter | |
:INPUT ACCEPT [0:0] | |
:FORWARD DROP [0:0] | |
:OUTPUT ACCEPT [0:0] | |
:FILTERS - [0:0] | |
:DOCKER-USER - [0:0] | |
-F INPUT | |
-F DOCKER-USER | |
-F FILTERS | |
# BASIC Allow | |
-A INPUT -i lo -j ACCEPT | |
# Chain to FILTERS | |
-A INPUT -j FILTERS | |
-A DOCKER-USER -i eth0 -j FILTERS | |
# COMMON FIREWALL RULES | |
# ALLOW something | |
-A FILTERS -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT | |
# DENY something | |
-A FILTERS -p icmp --icmp-type echo-request -j REJECT | |
################################################################### | |
### special cases for servers | |
### please modify by the server | |
### end special cases | |
############################################################ | |
# FINAL REJECT | |
# Optional logging | |
-A FILTERS -m limit --limit 5/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7 | |
-A FILTERS -j REJECT | |
COMMIT |
Thanks for the quick reply. So just by binding it to the private ip, I don't see a different behaviour.
Didn't fully get your last sentence about the public ip. This machine only has one interface wlp3s0
with private ip 192.168.1.5
.
I did play with it a little more, but when I remove allow 80,44 in line 22 and use something like:
-A FILTERS -s 192.168.1.20/32 -p tcp -m multiport --dports 8080 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
Then 192.168.1.20 still can not connect to the nginx running on 8080. What makes it work is using the port inside the container like:
-A FILTERS -s 192.168.1.20/32 -p tcp -m multiport --dports 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
Then I can curl from 192.168.1.20
to http://192.168.1.5:8080
and it works.
However, this allows connections to any container that is using port 80 internally. I.e. if I start another container like sudo docker run --rm --name nginx2 -p 192.168.1.5:8181:80 nginx
Then I can curl from 192.168.1.20
to http://192.168.1.5:8181
and it works.
What I want to achieve is that only certain hosts on the 192.168.1.0 net can reach certain services on this machine provided by docker.
How would you go about only allowing 192.168.1.20
access to the nginx running like sudo docker run --rm --name some-nginx -p 192.168.1.5:8080:80 nginx
, without also allowing it access to another nginx that is running with 8181->80
?
You have a different use case.
Mine is for hosts with 2 interfaces. One is the public IP address serving 80/443, another is private IP serving other internal services. The rules in this example block the unexpected access from the private IP interface.
The official document could help your use case.
https://docs.docker.com/network/iptables/
You could instead allow connections from a source subnet. The following rule only allows access from the subnet 192.168.1.0/24:
$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP
As you have this line
-A DOCKER-USER -i wlp3s0 -j FILTERS
above rule is like
-A FILTERS -i wlp3s0 ! -s 192.168.1.0/24 -j DROP
After some study I found this line will allow access to container port 80 when jumped from DOCKER-USER to FILTERS
-A DOCKER-USER -i wlp3s0 -j FILTERS
-A FILTERS -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
Here the "80, 443" are not the port on the host side of the binding, but container side
e.g. 8080:80, 8080, the left side, host side port, and 80, the right side, container side.
If you modify the rule as
-A FILTERS -p tcp -m multiport --dports 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
then 8080 port is not accessible from external.
Thanks for looking into this, really appreciate the help. I think I will stick with my current setup and using double rules in INPUT+DOCKER-USER for the per host per service mapping.
Thanks for posting this and your medium post, I'm search for a smooth docker/iptables solution for quite some time and this looks promising.
Unfortunately I can't get it working correctly and I'm wondering if I do something wrong or if there is something missing.
Using your example above, I only changed the interface name to match the one from my machine, but when I apply it, my machine can not talk to anything on the network anymore.
I guess thats because something like
-A FILTERS -m state --state ESTABLISHED,RELATED -j ACCEPT
is missing that allows other machines talking back to mine when I ping or curl something for testing.The other thing I noticed is that the allow in https://gist.github.com/liejuntao001/266f2c5a5e85be70201eee9bcbd2b4a4#file-iptables-conf-template-L22 also seems to match when the target port in docker is one of those.
Example: if I run a container like
sudo docker run --rm --name nginx -p 8080:80 nginx
and use port8080
on the outside forwarded to port80
in the container, i can still do acurl http://192.168.1.5:8080
for another machine in the network and it is able to connect, even though I haven't opened port 8080.Am I missing something or does it not differentiate between exposed ports and ports in the container for the allow?
Also tried the original example form the https://unrouted.io/2017/08/15/docker-firewall/ post, but it behaves similar.
while docker is running, iptables -S looks like: