--cap-add in Google Container Engine - docker

I am running into an issue with Google Container Engine where I am unable to add capabilities to the running of my Docker container.
I need to be able to alter the iptables so that I can forward traffic through my Docker VPN container.
The docker container runs fine when I am able to pass --cap-add=NET_ADMIN into the run command, but since GCE is (seemingly) only able to run images this does not seem possible. I get an insufficient permissions error when running my docker image and so it fails to deploy.
Is there anyway around this so I can alter theiptables? Or does GCE just not have this ability?
I have checked out this issue. Which references building an image with privileges but it doesn't seem to be close to resolved.
My iptables commands for reference:
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE

There was a pull request filed yesterday to add this feature to Kubernetes. Once it has been added to Kubernetes you should be able to test it by building from head and deploying your cluster to GCE.
This feature will show up in Google Container Engine shortly after the next release of Kubernetes.

Related

Docker: browsing to container on host computer not working

I am running a basic web application (PHP) inside Docker on a Debian VM, using Docker Compose.
When preforming sudo docker-compose up -d all containers start running just fine.
I have my ports setup as follows: 8007 for the application itself, 8008 for PHPMyAdmin, 9009 for Portainer.
The IP of the Debian VM is 192.168.56.102
When browsing using curl inside the VM to http://192.168.56.102:8007 the page loads without issues.
However, when browsing to the same URL on my Windows 10 host (Chrome) I get a connection timeout.
Pinging to 192.168.56.102 from host to VM and viceversa works fine, and so does SSH.
Does anyone know why I can't browse to these pages, eventhough everything works fine within the VM and the host and VM are clearly able to communicate?
Thanks.
I managed to fix the problem.
As suggested by #larsks some firewall rule inside Debian was blocking the connection. I had already tried /sbin/iptables -F which flushes the firewall rules, which I thought was enough, but it turns out that's not the case.
After running all these commands, the Debian firewall was completly reset and the issue was fixed:
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

Docker IP-TABLES Error

Hey i'm quite new to these docker stuff. I tried to start an docker container with bitbucket, but i get this output.
root#rv1175:~# docker run -v bitbucketVolume:/var/atlassian/application-data/bitbucket --name="bitbucket" -d -p 7990:7990 -p 7999:7999 atlassian/bitbucket-server
6da32052deeba204d5d08518c93e887ac9cc27ac10ffca60fa20581ff45f9959
docker: Error response from daemon: driver failed programming external connectivity on endpoint bitbucket (55d12e0e4d76ad7b7e8ae59d5275f6ee85c8690d9f803ec65fdc77a935a25110): (iptables failed: iptables --wait -t filter -A DOCKER ! -i docker0 -o docker0 -p tcp -d 172.17.0.2 --dport 7999 -j ACCEPT: iptables: No chain/target/match by that name.
(exit status 1)).
root#rv1175:~#
I got the same output every time i tried to activate any docker
container. Can someone help me?
P.S. one more question.
What does 172.1.0.2 mean? I can only say, that this is not my ip.
172.17.0.2 would be the IP assigned to the container within the default Docker bridge network (docker0 virtual interface). These are not reachable from the outside, though you are instructing the Docker engine to "publish" (in Docker terminology) two ports.
To do so, the engine creates port forwarding rules with iptables, which forward (in your case) all incoming traffic to ports tcp/7990 and tcp/7999 on all interfaces of the host to the same ports at 172.17.0.2 on the docker0 interface (where the process in the container is hopefully listening).
It looks like the DOCKER iptables chain where this happens is not present. Maybe you have other tools manipulating iptables that might be erasing what the Docker engine is doing. Try to identify them and restart the Docker engine (it should re-create everything on startup).
You can also instruct the engine not to manipulate iptables by configuring the Docker daemon appropriately. You would then need to set things up yourself if you want to use the network bridge driver (though you could also use the host driver). Here is a good example of doing so.

How ot map docker container ip to a host ip (NAT instead of NAPT)?

The main goal is to do a real NAT instead of NAPT. Note normal docker run -p ip:port2:port1 command actally is doing NAPT (address+port translation) instead of NAT(address translation). Is it possible to map address only, but keep all exposed ports the same as the container, like docker run -p=ip1:*:* ... , instead of one by one or a range?
ps.1. My port range is rather big (22-50070, ssh-hdfs) so port range approach won't work.
ps.2. Maybe I need a swarm of virtual machines and join the host into the swarm.
ps.3 I raised an feature request on github. Not sure if they will accept it but currently there are 2000+ open issues (it's so popular).
Solution
On linux, you can access any container by ip and port without any binding (no -p) ootb. Docker version: CE 17+
If your host is windows, and docker is running on a linux VM like me, to access the containers, the only thing need to do is adding the route on windows route add -p 172.16.0.0 mask 255.240.0.0 ip_of_your_vm. Now you can access all containers by IP:port without any port mapping from both windows host and linux VM.
There are few options you have. One is to decide which PORT range you want to map then use that in your docker run
docker run -p 192.168.33.101:80-200:80-200 <your image>
Above will map all ports from 80 to 200 on your container. Assuming your idle IP is 192.168.33.100. But unfortunately it is not possible to map a larger port range as docker creates multiple iptables forks to setup the tables and bombs the memory. It would raise an error like below
docker: Error response from daemon: driver failed programming external connectivity on endpoint zen_goodall (0ae6cec360831b46fe3668d6aad9f5f72b6dac5d26cc6c817452d1402d12f02c): (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8513 -j DNAT --to-destination 172.17.0.3:8513 ! -i docker0: (fork/exec /sbin/iptables: resource temporarily unavailable)).
This is not right way of docker mapping it. But this is not a use case that they would agree to, so may not fix the above issue. Next option is to run your docker container without any port publishing and use below iptables rules
DOCKER_IP=172.17.0.2
ACTION=A
IP=192.168.33.101
sudo iptables -t nat -$ACTION DOCKER -d $IP -j DNAT --to-destination $DOCKER_IP ! -i docker0
sudo iptables -t filter -$ACTION DOCKER ! -i docker0 -o docker0 -p tcp -d $DOCKER_IP -j ACCEPT
sudo iptables -t nat -$ACTION POSTROUTING -p tcp -s $DOCKER_IP -d $DOCKER_IP -j MASQUERADE
ACTION=A will add the rules and ACTION=D will delete the rules. This would setup complete traffic from your IP to the DOCKER_IP. This only good if you are doing it on a testing server. Not recommended on staging or production. Docker adds a lot more rules to prevent other containers poking into your container but this offers no protection whatsoever
I dont think there is a direct way to do what you are asking.
If you use "-P" option with "docker run", all ports that are exposed using "EXPOSE" in Dockerfile will automatically get exposed with random ports in the host. With "-p" option, the only way is to specify the option multiple times for multiple ports.

How can I access internet in docker build?

First of all, I start docker with the command:
docker --iptables=false -d
When I want to start my docker container, I start it like this
docker run --net=host myImageName
Use the host of net mode can make me access internet from the docker container.
But when I write dockerFile, I can't make it start in host mode.
So how can I access internet in the docker build.
In addition, I must run docker in the mode --iptables=false, because I don't have nat table in iptables. And I don't want it.(Reason link)
So in this mode, how can I access internet in the dockFile build.
Set DEFAULT_FORWARD_POLICY="ACCEPT" # /etc/default/ufw
Add the following lines JUST BEFORE “*filter” # /etc/ufw/before.rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
COMMIT
I, as many people, had to add --iptables=trueto make sure my UFW rules were respected by Docker. But all the articles seem leave out out an important thing that is... the time you reboot your machine, a series of configurations done when you enabled that setting on-the-fly and rebooted the Docker Engine will be lost. The problem? Your containers will no longer connect to the internetz.
Eventually I found out an article with a "full solution". You can find it here and it basically tells you what I wrote at the beginning of the answer.
Hope it helps

Limit Network access but allow a specific IP for a Running Docker Container

I try to use a docker container where only a specific IP address should be accessible out of the running container.
iptables are only working in priviliged docker container. But than the user can change the iptables themselves.
A nice idea would be to create a docker image with a dockerfile and with iptables. But there is no option for privileged right while creating an image.
Anyone have an idea how to solve this issue?
Best
Each docker container has a unique IP address, so if you want to permit a container with address 172.17.0.21 and you want it to be able to only access address 8.8.8.8, you could do something like:
iptables -A FORWARD -s 172.17.0.21 -d 8.8.8.8 -j ACCEPT
iptables -A FORWARD -s 172.17.0.21 -j REJECT --reject-with icmp-host-prohibited
It is also possible to modify the iptables rules inside an unprivileged container using the nsenter command. For example, if you start a Docker container:
docker run --name example -d myimage
You can get the PID of that container like this:
pid=$(docker inspect -f '{{.State.Pid}}' example)
And then use nsenter to run commands inside that container's network namespace:
nsenter -t $pid -n iptables ...
These commands will run without the capabilities restrictions of commands run inside the container.

Resources