Docker expose a port only to localhost - docker

I want to restrict my database access to 127.0.0.1, so I executed the following command:
docker run -it mysql:5.5 -p 127.0.0.1:3306:3306 -name db.mysql
But I have some confusion...
You can see here that only the port of 127.0.0.1 will be forwarded:
; docker ps
mysql:5.5 127.0.0.1:3306->3306/tcp db.mysql
Interestingly, I cannot find this restriction in iptables:
; iptables -L
Chain FORWARD (policy DROP)
DOCKER all -- anywhere anywhere
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 192.168.112.2 tcp dpt:mysql
The source of this rule is anywhere.

The incoming traffic will go as next:
Incoming package to host's network -> use ip tables to forward to container
And, your restrict was not in iptables, it was in host's network, you just open 3306 bind on 127.0.0.1, not 0.0.0.0, so you of course not see anything in iptables. 127.0.0.1:3306:3306 means hostIp:hostPort:containerPort.
You could confirm it with netstat -oanltp | grep 3306 to see no 0.0.0.0 was there, so no foreign host could visit your host machine, thus also could not visit your container.

Related

Inside a container, how to resolve DNS on the host, on a specific port

I've an instance running a consul agent & docker. Consul agent can be used to resolve DNS queries on 0.0.0.0:8600. I'ld like to use this from inside a container.
A manual test works, running dig #172.17.0.1 -p 8600 rabbitmq.service.consul inside a container resolve properly.
A first solution is to run --network-mode host. It works. I'll do this until better. But I don't like it, security-wise.
Another idea, use docker's --dns and associated options. Even if I can script grabbing the IP, I can't get how to specify port=8600. Maybe in --dns-opts, but how ?
Along this line, writing the container's resolv.conf could do. But again, how to specify the port, I saw no hints in man resolv.conf, I believe it's not possible.
Last, I can set up a dnsmasq inside the container or in a sidecar container, along the line of this Q/A. But it's a bit heavy.
Anyone can help on this one ?
You can achieve this with the following configuration.
Configure each Consul container with a static IP address.
Use Docker's --dns option to provide these IPs as resolvers to other containers.
Create an iptables rule on the host system which redirects traffic destined to port 53 of the Consul server to port 8600.
For example:
$ sudo iptables --table nat --append PREROUTING --in-interface docker0 --proto udp \
--dst 1920.2.4 --dport 53 --jump DNAT --to-destination 192.0.2.4:8600
# Repeat for TCP
$ sudo iptables --table nat --append PREROUTING --in-interface docker0 --proto tcp \
--dst 192.0.2.4 --dport 53 --jump DNAT --to-destination 192.0.2.4:8600

Deny incoming traffic with docker and ansible iptables

In a standalone server, I have a docker container running jenkins. I want to write a playbook that allows me (some public ip, let's say it is 107.33.11.111), to connect via 22 and 8080 to the jenkins server on my standalone server, but nobody else. Public traffic is coming on eth0 on my standalone server. I am using this guide to try and make this work.
Here is an example of how I run jenkins:
# privileged is needed to allow browser based testing via chrome
- name: Run jenkins container
command: docker run --privileged -d -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk11
I then set this firewall rule:
- name: Firewall rule - allow port 22/SSH traffic only for me
iptables:
chain: INPUT
in_interface: eth0
destination_port: 22
jump: ACCEPT
protocol: tcp
source: 107.33.11.111
- name: Firewall rule - allow port 8080 traffic only for me
iptables:
chain: INPUT
in_interface: eth0
destination_port: 8080
jump: ACCEPT
protocol: tcp
source: 107.33.11.111
- name: Firewall rule - drop any traffic without rule
iptables:
chain: INPUT
jump: DROP
in_interface: eth0
When I execute the above playbook, and run iptables -L, my output trims to only:
Chain INPUT (policy ACCEPT)
target prot opt source destination
When I remove the last rule to drop all traffic, I can observe the entire output, and the ip tables show my ip being permitted for ports 22 and 8080. However, all other traffic coming to eth0 is able to reach those ports as well.
What do I need to do to allow 22 and 8080 only for a specific public address in my ansible playbook?
For your specific use case, you do not need to jump to another chain, but you can set the default policy to DROP after allowing 8080 and 22.
Replace the last stanza in your playbook with
- name: Firewall rule - drop any traffic without rule
iptables:
chain: INPUT
policy: DROP

Can't delete docker container's default iptables rule

If I type iptables -L there is this line in the output :
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.17.0.2 tcp dpt:http-alt
My container is exposed publicly and I can request a dummy http server from everywhere (tested). I try to remove that rule so only 80 is only exposed inside my server (localhost:80). I tried :
root#ns25252:~# iptables -D DOCKER --destination 172.17.0.2 -p tcp --dport 80 -j ACCEPT
iptables: Bad rule (does a matching rule exist in that chain?).
As the error implies, it can't find the matching rule.. How should I type to remove the line ?
It's usually easier to delete by number, unless there is a chance that the number could change between the time you listed the rules and the time you delete the rule.
Here's how to delete by line number:
# iptables -L --line-numbers
(snip)
Chain DOCKER (2 references)
num target prot opt source destination
1 ACCEPT tcp -- anywhere 172.17.0.2 tcp dpt:http
(snip)
# iptables -D DOCKER 1
Alternatively, you can get the full specification by doing iptables -S. Example:
# iptables -S
(snip)
-A DOCKER -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j ACCEPT
(snip)
Turn the -A into a -D and use this as the args to iptables to delete the rule:
# iptables -D DOCKER -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j ACCEPT
NOTE: This answer perplexingly still gets upvotes from time to time. I have no idea what everyone is trying to actually accomplish, I just blindly answered an iptables-related question. If you want to start a Docker container that is not accessible to the outside world, that's an entirely different topic, and this is not an appropriate answer in your case. (Maybe start by not exposing/publishing the port.)
This is a bit old but in case someone else is looking for how to remove docker completely from your iptables rules here's how I did it, also keep in mind this is on debian so your files/paths may differ.
edit your /etc/iptables.up.rules file, back up file then remove everything with docker in it - there may also be a few additional lines with the local docker subnet (mine was 172.17.x and 172.19.x) - remove them all
flush iptables: iptables -P INPUT ACCEPT && iptables -P OUTPUT ACCEPT && iptables -P FORWARD ACCEPT && iptables -F
reload iptables rules: iptables-restore < /etc/iptables.up.rules
verify/check your rules: iptables -L -n (should no longer have any docker chains or rules)
If you have deleted the docker package than just restart iptables service and it will deleted default docker iptables-
systemctl restart iptables.service

Logspout can't connect to papertrail

I can't get logspout to connect to papertrail. I get the following error:
!! lookup logs5.papertrailapp.com on 127.0.0.11:53: read udp 127.0.0.1:46185->127.0.0.11:53: i/o timeout
where 46185 changes every time I run the container. It seems like a DNS error, but nslookup logs5.papertrailapp.com gives the expected output, as does docker run busybox nslookup logs5.papertrailapp.com.
Beyond that, I don't even know how to interpret that error message, let alone address it. Any help debugging this would be hugely appreciated.
My Docker Compose file:
version: '2'
services:
logspout:
image: gliderlabs/logspout
command: "syslog://logs5.papertrailapp.com:12345"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
sleep:
image: benwhitehead/env-loop
Where 12345 is the actual papertrail port. Result is the same whether using syslog:// or syslog-tls://.
From https://docs.docker.com/engine/userguide/networking/configure-dns/:
the docker daemon implements an embedded DNS server which provides built-in service discovery for any container
It looks like your container is unable to connect to this DNS server. If your container is on the default bridge network, it won't reach the embedded DNS server. You can either set --dns to be an outside source or update /etc/resolv.conf. It doesn't sound like a Papertrail issue, at all.
(source)
Docker and iptables got in a fight. So I spun up a new machine, failed to set up iptables, and the problem was solved: no firewall at all to get in the way of Docker's connections!
Just kidding, don't do that. I got a toy database hacked that way.
Fortunately, it's now relatively easy to get iptables and Docker to live in harmony, using the DOCKER_USER iptables chain.
The solution, excerpted from my blog:
Configure Docker with iptables=true, and append to iptables configuration:
iptables -A DOCKER-USER -i eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -p tcp -m tcp --dport 443 -j ACCEPT
iptables -A DOCKER-USER -i eth0 -j DROP

Docker container can not ping the outside world - iptables

exploring Docker 17.06.
I've installed docker on Centos 7 and created a container. Started the container with the default bridge. I can ping both host adapters, but not the outside world e.g. www.google.com
All advise out there is based on older versions of Docker and it's iptables settings.
I would like to understand how to ping to the outside world, what is required please?
TIA!
If you able to ping www.google.com from host machine try following these steps :
run on host machine:
sudo ip addr show docker0
You will get output which includes :
inet 172.17.2.1/16 scope global docker0
The docker host has the IP address 172.17.2.1 on the docker0 network interface.
Then start the container :
docker run --rm -it ubuntu:trusty bash
and run
ip addr show eth0
output will include :
inet 172.17.1.29/16 scope global eth0
Your container has the IP address 172.17.1.29. Now look at the routing table:
run:
route
output will include:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.17.2.1 0.0.0.0 UG 0 0 0 eth0
It Means the IP Address of the docker host 172.17.2.1 is set as the default route and is accessible from your container.
try ping now to your host machine ip :
root#e21b5c211a0c:/# ping 172.17.2.1
PING 172.17.2.1 (172.17.2.1) 56(84) bytes of data.
64 bytes from 172.17.2.1: icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 172.17.2.1: icmp_seq=2 ttl=64 time=0.211 ms
64 bytes from 172.17.2.1: icmp_seq=3 ttl=64 time=0.166 ms
If this works most probably you'll be able to ping www.google.com
Hope it will help!
In my case restarting docker daemon helped
sudo systemctl restart docker
If iptables is not a reason and if you have no some limitation for change containers network mode - set it to "host" mode. This should solve this issue.
Please verify your existing iptables:
iptables --list
It should show you list of iptables with source and destination details.
target prot opt source destination
DOCKER-USER all -- anywhere anywhere
If it is anywhere for both source and destination it should ping outside IPs.(By Default its anywhere)
If not use this command to set your iptable(DOCKER-USER)
iptables -I DOCKER-USER -i eth0 -s 0.0.0.0/0 -j ACCEPT
Hope this will help!
I had a similar problem, an api docker container needed connection to outside, but the others containers not. So my option was add the flag --dns 8.8.8.8 to the docker run command , and with that the container can ping to outside. I consider this a solution for one container, if you need for more containers, maybe other responses are better. Here the documentation. And full line example:
docker run -d --rm -p 8080:8080 --dns 8.8.8.8 <docker-image-name>
where:
-d, detach mode for run containers in background
--rm, remove containers if is stop (careful if you are testing and maybe you need to inspect logs, with docker logs , don't use it)
-p, specify the port ( <host-port> : <container-port> )
--dns, the container can resolve internet domains

Resources