Postgres Enable TCP/IP Connection [closed] - ruby-on-rails

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 8 years ago.
Improve this question
I have installed postgres-9.4 database server on a CentOS 6.6 system. I am trying to connect to this server from my laptop (connected to the same network. Laptop's ip is 192.168.1.105. I am running psql -U postgres -h 192.168.1.52). The psql command fails with an error message:
psql -U postgres -h 192.168.1.52
could not connect to server: COnnection refused
Is the server running on host 192.168.1.52 and accepting TCP/IP connection on port 5432?
My configuration:
/var/lib/pgsql/9.4/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 192.168.0.0/16 trust
host all all 0.0.0.0/0 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local replication postgres peer
#host replication postgres 127.0.0.1/32 ident
#host replication postgres ::1/128 ident
/etc/sysconfig/iptables:
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A INPUT -m state --state NEW -m tcp -p tcp --dport 5432 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
COMMIT
I have restarted the iptables service.
/var/lib/pgsql/9.4/data/postgresql.conf
listen_addresses = '*'
port = 5432
I restart the server as below:
[root#cinch-database1 9.4]# service postgresql-9.4 restart
Stopping postgresql-9.4 service: [ OK ]
Starting postgresql-9.4 service: [ OK ]
ps aux and grep postgres returns following:
ps auxwww | grep postgres
postgres 11460 0.0 0.0 325096 14860 ? S 01:36 0:00 /usr/pgsql-9.4/bin/postmaster -D /var/lib/pgsql/9.4/data
postgres 11463 0.0 0.0 180244 1264 ? Ss 01:36 0:00 postgres: logger process
postgres 11465 0.0 0.0 325096 1564 ? Ss 01:36 0:00 postgres: checkpointer process
postgres 11466 0.0 0.0 325096 2544 ? Ss 01:36 0:00 postgres: writer process
postgres 11467 0.0 0.0 325096 1496 ? Ss 01:36 0:00 postgres: wal writer process
postgres 11468 0.0 0.0 325508 2340 ? Ss 01:36 0:00 postgres: autovacuum launcher process
postgres 11469 0.0 0.0 180376 1476 ? Ss 01:36 0:00 postgres: stats collector process
root 11516 0.0 0.0 103252 844 pts/0 S+ 01:41 0:00 grep postgres
When I do a netstat on the server and grep for 5432 I get nothing:
netstat | grep 5432
But netstat -tulnp returns this:
tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN 13227/postmaster
Output of 'netstat -l|grep postgres'
[root#cinch-database1 pg_log]# netstat -l|grep postgres
tcp 0 0 *:postgres *:* LISTEN
tcp 0 0 *:postgres *:* LISTEN
But as mentioned earlier psql from my laptop fails to connect to the server.
What am I missing?

It was a firewall issue. I had to move the following two lines in the iptables file earlier in the sequence:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 5432 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
New iptables:
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 5432 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
After this I restarted iptables service:
service iptables restart
Now I can connect to postgres from my laptop.

It seems that the firewall blocks your connections, so just try to disable the firewall with:
sudo service iptables stop
and then if is pass, setup it correctly.

Related

Cannot access Grafana (Docker image) using port 3000 from non-local server

I'm working on a Ubuntu server with Docker, in which I ran the Grafana Docker Image using the following commands (based on documentation: https://grafana.com/docs/grafana/latest/installation/docker):
docker volume create grafana-storage
docker run -d -p 3000:3000 --name=grafana -v grafana-storage:/var/lib/grafana grafana/grafana-oss
I can access to my Grafana instance successfully using localhost:3000, but the issue is that I cannot access from any external server x.x.x.x:3000. Not even locally unless I use localhost.
Nevertheless, I can access from an external server to x.x.x.x (port 80, which is being used by another process) from an external device.
I proceeded to check port configuration details:
netstat -an | grep "3000"
tcp 0 0 yy.yy.yy.yy:53596 yy.yy.yy.yy:3000 ESTABLISHED
tcp 0 0 yy.yy.yy.yy:53716 yy.yy.yy.yy:3000 ESTABLISHED
tcp 0 0 yy.yy.yy.yy:53700 yy.yy.yy.yy:3000 ESTABLISHED
tcp6 0 0 :::3000 :::* LISTEN
tcp6 0 0 ::1:3000 ::1:50602 ESTABLISHED
tcp6 0 0 ::1:50706 ::1:3000 ESTABLISHED
tcp6 0 0 ::1:3000 ::1:50706 ESTABLISHED
tcp6 0 0 ::1:50602 ::1:3000 ESTABLISHED
iptables -S | grep "3000"
-A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 3000 -j ACCEPT
-A DOCKER -d yy.yy.yy.yy/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3000 -j ACCEPT
iptables -L INPUT -nvx
Chain INPUT (policy ACCEPT 659 packets, 98721 bytes)
pkts bytes target prot opt in out source destination
136 8160 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3000
0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3000
And noted that firewall was inactive, then I enable it and put a rule:
sudo ufw enable
sudo ufw allow 3000/tcp comment 'grafana-port'
sudo ufw reload
sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 3000/tcp ALLOW IN Anywhere # grafana-port
[ 2] 3000/tcp (v6) ALLOW IN Anywhere (v6) # grafana-port
Applying this change did not make x.x.x.x:3000 work. However, port 80 is still working normally as I mentioned. Maybe I am missing something else.
More info: I tried using domain = x.x.x.x and serve_from_subpath = true in grafana.ini, defaults.ini and custom.ini files. It did not work.
Have you any advice or contribution in order to solve this issue? Thank you in advance!
Have you tried the following?
docker run -p x.x.x.x:3000:3000 ...
Issue was solved letting the firewall inactive, and connecting to the server's router at tplinkwifi.net. There I put this router configuration on advanced > NAT forwarding > Port forwarding:
Device IP Address: 192.168.x.x
External Port: 3000
Internal Port: 3000
Protocol: TCP
Then restarted the docker container and got access from non-local server.
Thank you for your suggestions.

Docker Swarm worker node not accessing the internet

I have init a swarm with 1 manager and 1 worker, each on a different hosts, following the official tutorial. I also use Traefik, following these instructions on dockerswarm.rocks, using simply overlay network created with:
docker network create --driver=overlay traefik-public
Now I deploy a service of mine, which has to access the Internet.
While this works well when the service is deployed on the manager node, it fails in the worker node.
docker-compose.yml
version: '3.5'
services:
export-phyc:
image: my.docker.registry/my/image
networks:
- traefik-public
deploy:
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- traefik.http.routers.myservice-http.rule=Host(`my.domain`)
- traefik.http.routers.myservice-http.entrypoints=http
- traefik.http.routers.myservice-http.middlewares=https-redirect
- traefik.http.routers.myservice-https.rule=Host(`my.domain`)
- traefik.http.routers.myservice-https.entrypoints=https
- traefik.http.routers.myservice-https.tls=true
- traefik.http.routers.myservice-https.tls.certresolver=le
- traefik.http.services.myservice.loadbalancer.server.port=80
networks:
traefik-public:
external: true
Both hosts have the same DNS conf:
# cat /etc/resolv.conf
domain openstacklocal
search openstacklocal
nameserver 213.186.xx.xx
Both tasks has the same DNS conf too (but not the same as the hosts):
# docker container exec <my-container-id> cat /etc/resolv.conf
search openstacklocal
nameserver 127.0.0.xx
options ndots:0
And yet, the task on the manager can reach the internet:
# docker container exec <my-container-id> wget google.com
Connecting to google.com (216.58.215.46:80)
Connecting to www.google.com (216.58.206.228:80)
saving to 'index.html'
index.html 100% |********************************| 13848 0:00:00 ETA
'index.html' saved
and the task on the worker cannot:
# docker container exec <my-container-id> wget google.com
wget: bad address 'google.com'
# docker container exec <my-container-id> wget 216.58.204.142
Connecting to 216.58.204.142 (216.58.204.142:80)
wget: can't connect to remote host (216.58.204.142): Operation timed out
I am most confused. How do I get the tasks on my worker node to access the internet?
So the problem was with my firewall (iptables) messing around with the rules set by Docker. I indeed need to implement my own rules (launched at reboots), and Docker has to set its internal communication rules (set everytime the docker daemon restarts).
I'm not a connoisseur of iptables, I just got one supposed to deal well with Docker Swarm, but one line was missing in it:
-A DOCKER-USER -j RETURN
Example iptables rules:
*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
-A INPUT -i lo -j ACCEPT
-A INPUT -j FILTERS
-A DOCKER-USER -i eno1 -j FILTERS
-A DOCKER-USER -j RETURN
-A FILTERS -m state --state ESTABLISHED,RELATED -j ACCEPT
#allow 80 and 443
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A FILTERS -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
###### System
# Allow SSH connections
-A FILTERS -p tcp --dport 22 -j ACCEPT
# Docker SWARM cluster connections
-A FILTERS -p tcp --dport 2377 -j ACCEPT
-A FILTERS -p tcp --dport 7946 -j ACCEPT
-A FILTERS -p udp --dport 7946 -j ACCEPT
-A FILTERS -p udp --dport 4789 -j ACCEPT
###### Rules home
# ...
###### end
-A FILTERS -j REJECT --reject-with icmp-host-prohibited
COMMIT

How to block a Docker registry?

I want to block access to the default docker.io registry. For security/IP protection, we need to block push/pull access to/from the public Docker hub.
There have been many attempts to make this a configuration option, but all PRs just keep getting rejected. Red Hat has implemented both '--block-registry' and '--add-registry', which are exactly what I need, but it only works with Red Hat's fork of docker v1.10, and I want to use docker v1.12+
I'm using RHEL/Centos 7
DNS spoofing doesn't seem to work via the following in /etc/hosts (anymore):
127.0.0.1 index.docker.io registry.docker.io registry-1.docker.io docker.io
And I can't seem to get the firewall to block access either with the following rules (where the IPs are currently those from the above hosts listed in /etc/hosts):
# firewall-cmd --direct --get-rules ipv4 filter OUTPUT
0 -p tcp -m tcp --dport 5000 -j REJECT
0 -p tcp -m tcp --dport 443 -j REJECT
0 -p tcp -m tcp -d 52.207.178.113 -j DROP
0 -p tcp -m tcp -d 52.73.159.23 -j DROP
0 -p tcp -m tcp -d 54.85.12.131 -j DROP
0 -p tcp -m tcp -d 52.6.119.223 -j DROP
0 -p tcp -m tcp -d 52.0.53.94 -j DROP
0 -p tcp -m tcp -d 34.192.123.224 -j DROP
0 -m state --state ESTABLISHED,RELATED -j ACCEPT
1 -p tcp -m tcp --dport 80 -j ACCEPT
1 -p tcp -m tcp --dport 53 -j ACCEPT
1 -p udp --dport 53 -j ACCEPT
1 -p tcp -m tcp --dport 2376 -j ACCEPT
2 -j REJECT
or
# firewall-cmd --direct --get-rules ipv4 filter FORWARD
0 -p tcp -m tcp --dport 5000 -j REJECT
0 -p tcp -m tcp --dport 443 -j REJECT
0 -p tcp -m tcp -d 52.207.178.113 -j DROP
0 -p tcp -m tcp -d 52.73.159.23 -j DROP
0 -p tcp -m tcp -d 54.85.12.131 -j DROP
0 -p tcp -m tcp -d 52.6.119.223 -j DROP
0 -p tcp -m tcp -d 52.0.53.94 -j DROP
0 -p tcp -m tcp -d 34.192.123.224 -j DROP
With all these in place, I can still search/pull from docker.io.
One of the PRs to resolve this got closed by a maintainer who said it looks like something that should be addressed by the firewall. Can someone please tell me how this can actually be done?
Adding this to /etc/hosts on Ubuntu worked for me:
0.0.0.0 index.docker.io auth.docker.io registry-1.docker.io dseasb33srnrn.cloudfront.net production.cloudflare.docker.com
I got the list of domains from here: https://support.sonatype.com/hc/en-us/articles/115015442847-Whitelisting-Docker-Hub-Hosts-for-Firewalls-and-HTTP-Proxy-Servers
On redhat/centos add
--block-registry docker.io
to wherever you start your docker engine from ( likely /etc/sysconfig/docker on redhat, or possibly /lib/systemd/system/docker.service )
don't forget to refresh systemd if you edited the service file ( systemctl daemon-reload ) and to restart the docker engine ( systemctl restart docker.service ) in either case
now if you do a ps auxwwf | grep docker the docker engine --block-register flag should appear in the process listing.
I came here because this does not work on debian/ubuntu, and am looking for a way to do this on debian. = / HTH

Why is this docker image allowed past the firewall?

I'm running a docker container that has the port 9000:9000 binding to the host, but I also have ufw enabled. The only ports I've allowed are 22, 80, 443.
So why is it that I'm able to connect to this container using the host's IP address? Shouldn't port 9000 be blocked by ufw?
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14417c4f71fb dockerui/dockerui "/dockerui" 2 seconds ago Up 2 seconds 0.0.0.0:9000->9000/tcp docker_ui
root#docker:~# ufw status
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
80 ALLOW Anywhere
443 ALLOW Anywhere
22 (v6) ALLOW Anywhere (v6)
80 (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
Aren't all ports blocked by default when you enable ufw?
Docker silently modifies iptables. You can start the Docker daemon with the --iptables=false option by editing DOCKER_OPTS in /etc/default/docker
Docker modifies iptables and UFW is not aware of this.
This answer describes what is happening and how to fix:
https://stackoverflow.com/a/46266757
Please follow it.
adding "--iptables=false" is not a good solution
as I said here https://stackoverflow.com/a/54486957/1712906
a better solution is to add these lines to /etc/ufw/after.rules
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
As mentioned by #kliew, Docker will add its own iptables chain, granting access to all exposed ports and pre-empting any rules that you define using ufw.
If you're not comfortable completely disabling Docker's control over iptables, though, there is another documented way to have your own rules respected. From the same docs:
If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER chain. These rules are applied before any rules Docker creates automatically.
Source: https://docs.docker.com/network/iptables/#add-iptables-policies-before-dockers-rules
This would preclude the use of ufw, though, because ufw only operates within its own iptables chains and doesn't give you control over the DOCKER-USER chain. You'll have to do this using iptables directly.

Docker ignores iptable rules when using "-p <port>:<port>"

Just realized a few days ago that Docker seems to bypass my iptable rules. I am not incredible experienced with Docker nor iptables. Tried a lot of different things the last days. Also saw that there was big change in recent docker versions with a special DOCKER-chain that should allow me to do that. However not sure what I am doing wrong but it never does what I expect it to do.
So what I want is quite simple. I want that it behaves like expected. That if I have an ACCEPT-Rule to go through and if not it gets blocked.
My iptable looked originally like that (so before my many unsuccessful attempts):
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -j DROP
COMMIT
Hoped that it does exactly what I want. Just allow access to ports 22 and 80 and also allow port 123 from the ip 1.2.3.4. However If I create a container with "-p 123:123" everybody can access it. Can anybody help me and tell me how I have to change the above file?
Thanks!
Docker-Version: 1.6.2
Edit:
Left initially my different tries out to not overcomplicate the question. However adding at least one of them could maybe be helpful.
*nat
:PREROUTING ACCEPT [319:17164]
:INPUT ACCEPT [8:436]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [16:960]
:DOCKER - [0:0]
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A DOCKER -j DROP
-A INPUT -j DROP
COMMIT
The above kind of works. However get then a lot of other problems. For example do I get problems with container linking, DNS does not work anymore, and so on. So then end up adding a lot of additional rules to fix that issues but I get never to a state where it runs properly. So I guess there most be better and easier solution out there.
Solution:
Ended up doing more or less exactly what larsks said. Just did not add it to the FORWARD chain, I added it to the DOCKER chain instead. The problem with the FORWARD chain is that Docker adds its stuff in there when it restarts in first position. Which results in having my rules getting pushed down and not having any effect. However for the DOCKER chain it seems Docker appends only additional rules so mine stay in effect. So when I save my rules and then restart the server everything still works fine.
So now it looks more or less like that:
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
# That I can access from IP 1.2.3.4
-A DOCKER -s 1.2.3.4/32 -p tcp -m tcp --dport 123 -j ACCEPT
# That I can access from other Docker containers
-A DOCKER -o docker0 -p tcp -m tcp --dport 123 -j ACCEPT
# Does not allow it for anything else
-A DOCKER -p tcp --dport 123 -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -j DROP
COMMIT
I'm not an expert on iptables but I know that if you run the container with -p 127.0.0.1:123:123 then the port won't be exposed on all interfaces, just on the loopback.
Your iptables configuration looks a little broken right now, as if you cleared it out at some point without restarting Docker. For example, you have a DOCKER chain available in both the filter and nat tables, but no rules that reference it, so rules placed in that chain will have no affect.
In general, if you want to implement iptables rules that affect your Docker containers they need to go in the FORWARD chain of the filter table. Each container has it's own ip address, which means that your host is simply accepting packets and then FORWARDing them to the container address.
Rules in the INPUT chain are only for packets with a final destination of an address on an interface in the host's global network namespace.
However, I'm not sure that iptables is actually your problem.
If you are trying to expose services in containers such that they are available to other systems, you need to publish those ports using the -p flag to docker run. You can read more about that
in this section of the documentation.
If you want to update your question with a specific example of what you are trying to accomplish I can provide a more targeted answer.
Update
It's true that when you publish a container port using -p it will generally be available to any source ip address. In order to restrict access to a published port you would need to add a new rule to your FORWARD chain. For example, if I start a web server:
docker run --name web -p 80:8080 larsks/mini-httpd
The web server in the container is now available on port 8080 on my host. If I want to block access to this port, I need to insert a rule into the FORWARD chain that blocks access to port 80 on the container ip. So first I need the container ip address:
$ web_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' web)
$ echo $web_ip
172.17.0.5
The rule I create in the FORWARD chain needs to come before the rules that docker creates, so I will need to specify an explicit position:
iptables -I FORWARD 1 -d $web_ip -p tcp --dport 80 \! -s 192.168.1.10 -j DROP
This would block all traffic from hosts other than 192.168.1.10.
If you want a rule to apply to all containers, rather than a specific container, you can bind it to the docker0 interface rather than a specific ip address:
-A FORWARD -o docker0 -p tcp --dport 80 \! -s 192.168.1.10 -j DROP
This would prohibit access to port 80 on any container.
Ended up doing more or less exactly what larsks said. Just did not add
it to the FORWARD chain, I added it to the DOCKER chain instead.
I've found the same in the docs: https://docs.docker.com/v1.5/articles/networking/#the-world
Docker will not delete or modify any pre-existing rules from the
DOCKER filter chain. This allows the user to create in advance any
rules required to further restrict access to the containers.
Docker's forward rules permit all external source IPs by default. To
allow only a specific IP or network to access the containers, insert a
negated rule at the top of the DOCKER filter chain. For example, to
restrict external access such that only source IP 8.8.8.8 can access
the containers, the following rule could be added:
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
To use iptables on published ports from docker containers, you need a combination of things:
DOCKER-USER table: docker uses this table for iptables rules that affect containers and is reserved specifically for user provided rules that won't be overwritten by the docker engine when it restarts.
conntrack: port forwarding can publish on one port and forward to another in the container. You can have multiple containers all listening on port 80 with different published ports on the host.
To use these, the resulting iptables rule looks like:
iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/24 -p tcp \
-m conntrack --ctorigdstport 8080 -j ACCEPT
iptables -I DOCKER-USER -i eth0 ! -s 10.0.0.0/24 -p tcp \
-m conntrack --ctorigdstport 8080 -j DROP
This handles requests to the published port 8080/tcp (that's on the host, the container could be listening on 80 or any other port), and only accepts the requests from the 10.0.0.0/24 subnet. Everything outside of that subnet is dropped.
Note that the DOCKER-USER table has a default rule to immediately return, so all changes should be inserted before that default rule in the table.
Given: Debian stretch, docker 18.06, and a docker process created via
docker run ... -p 5678:1234 ...
Required: Access to the docker container restricted to multiple external subnetworks.
Solution: (using some example subnetworks)
iptables -I DOCKER-USER -p tcp --dport 1234 -j REJECT
iptables -I DOCKER-USER -s 18.204.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 34.192.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 35.153.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 13.56.63.0/24 -p tcp --dport 1234 -j RETURN
Persist the changed rules using iptables-save:
iptables-save > /etc/iptables/rules.v4
Result:
iptables -L DOCKER-USER -n -v --line-numbers
Chain DOCKER-USER (1 references)
pkts bytes target prot opt in out source destination
0 0 RETURN tcp -- * * 13.56.63.0/24 0.0.0.0/0 tcp dpt:1234
0 0 RETURN tcp -- * * 35.153.0.0/16 0.0.0.0/0 tcp dpt:1234
0 0 RETURN tcp -- * * 34.192.0.0/16 0.0.0.0/0 tcp dpt:1234
0 0 RETURN tcp -- * * 18.204.0.0/16 0.0.0.0/0 tcp dpt:1234
0 0 REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:1234 reject-with icmp-port-unreachable
Background 1: Rules
All rules are added to the chain DOCKER-USER as recommended by the current docker documentation.
The first rule targets REJECT and will end up as the last rule, since the other rules are added on top (option -I without a position number corresponds to adding a rule at position 1). All packages with destination port 1234 reaching this rule will be rejected.
The other rules target RETURN, i.e. a package with destination port 1234 and source IP from one of the given subnetworks will be returned to the calling chain, which is the FORWARD chain.
iptables -L FORWARD -n -v
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
16471 4568K DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
16413 4565K DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
7173 2060K ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
45 2340 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
From the FORWARD chain, it will be processed by the DOCKER chain, where it is forwarded as desired to the docker container:
iptables -L DOCKER -n -v
Chain DOCKER (1 references)
pkts bytes target prot opt in out source destination
45 2340 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:1234
Background 2: Port value
We don't use the external port value 5678 in the forward rule, because the destination port is changed via a rule automatically created by docker and applied before the forward chain is executed. See top section of /etc/iptables/rules.v4:
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
...
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 5678 -j DNAT --to-destination 172.17.0.2:1234

Resources