Skip to content
This repository has been archived by the owner on Sep 26, 2021. It is now read-only.

Add firewall rule for Ubuntu Provisioner #1156

Closed

Conversation

clnperez
Copy link
Contributor

If the image used has a locked-down OS, docker's port
may not be accessible. This patch simply adds an ssh
command that uses Ubuntu's Uncomplicated Firewall (ufw) to
allow the docker port.

I verified that if the firewall rule already exists, an error
is not returned, and the rc is 0. This may not be the case with
all CLIs, but it is for ufw. This means that just running the
command every time won't be a problem

Also note that this should not interfere the existing
Google Compute Engine firewall capabilities because it is at
the OS-level, whereas the 'Firewalls' API handles traffic
at the network level.

Tested against Ubuntu 14.04 on Digital Ocean and Bluemix
(using the openstack driver).

Signed-off-by: Christy Perez christy@linux.vnet.ibm.com

If the image used has a locked-down OS, docker's port
may not be accessible. This patch simply adds an ssh
command that uses Ubuntu's Uncomplicated Firewall (ufw) to
allow the docker port.

I verified that if the firewall rule already exists, an error
is not returned, and the rc is 0. This may not be the case with
all CLIs, but it is for ufw. This means that just running the
command every time won't be a problem

Also note that this should not interfere the existing
Google Compute Engine firewall capabilities because it is at
the OS-level, whereas the 'Firewalls' API handles traffic
at the network level.

Tested against Ubuntu 14.04 on Digital Ocean and Bluemix
(using the openstack driver).

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com>
@hairyhenderson
Copy link
Contributor

Very cool! Thanks for submitting this.

I'm guessing the reason this is Ubuntu-specific is due to the use of ufw? When #1090 and #1096 get merged, Ubuntu won't be the only show in town, so maybe it'd be a good idea to write this a little more generically.

Seems to me it wouldn't be too difficult to modify this to use iptables directly instead so that more distros are supported.

There are also bound to be questions about whether this is the sort of thing that docker-machine should be responsible for (want to avoid scope-creep). For my part I think it probably should, since it's not terribly useful if machine completes and ends up with an unreachable Docker engine.

/cc @nathanleclaire @ehazlett

@nathanleclaire
Copy link
Contributor

Yes, very interesting and thanks for submitting -- Like @hairyhenderson mentioned, I think it digs up some deeper questions around how we want to handle this.

There are also bound to be questions about whether this is the sort of thing that docker-machine should be responsible for (want to avoid scope-creep).

Well, and where should the responsibility lie. After all, the drivers have AuthorizePort etc. methods that seem to imply this is how you should do it if you need to use provider-specific methods such as security groups.

In general I really want to account for these sorts of things, but it has to be designed carefully.

@ehazlett
Copy link
Contributor

Thanks for the submission and bringing up the topic. As @nathanleclaire mentioned we have the AuthorizePort method just for this. However, as he also mentioned, it brings up some other questions around how we want to handle this. I agree with @hairyhenderson that we should probably use iptables as it is more prevalent especially now that we have multiple base OS provisioners.

@clnperez
Copy link
Contributor Author

Yah, all things I thought about. I wasn't too clear on why there's an AuthorizePort method in the driver itself. It makes sense in the case of a network within the provider -- but not as much when it comes to the OS. It seems like something that should be left to the provisioner.

As far as editing the iptables themselves, that would be great from a generic standpoint, so maybe a compelling reason to go with it. In my experience, though, people using the OS itself will expect to use the neat little tools the distros are adding to manage their firewalls, though, and we could run into problems.

@hairyhenderson
Copy link
Contributor

In my experience, though, people using the OS itself will expect to use the neat little tools the distros are adding to manage their firewalls, though, and we could run into problems.

True, but Machine isn't really about provisioning a host intended for general purpose use, so IMO it's OK if it does things in a more low-level way.

Also, it'd be nice if this were an optional thing. Most of the time there's no need to add firewall rules, so it'd be good to expose this functionality with a flag I think...

@clnperez
Copy link
Contributor Author

I've been thinking more about this over the past few days, and now am wondering if this could be something we ask for from Docker instead. Docker already handles firewall rules for ports needed by containers (IIUC), and is now (thanks to @jpopelka) working together with firewalld (since there were issues with Docker's rules being unloaded). Since machine changes the docker config to run on a TCP socket, too, wouldn't it be simpler to have Docker deal with keeping itself accessible on that port?

Thinking about other other alternatives (us adding iptables rules, or us using whatever provider's firewall tool was) seemed to run into a lot of "what ifs" that are going to add more complexity to machine than it needs, IMO.

@nathanleclaire
Copy link
Contributor

Thinking about other other alternatives (us adding iptables rules, or us using whatever provider's firewall tool was) seemed to run into a lot of "what ifs" that are going to add more complexity to machine than it needs, IMO.

Yeah, this is my main concern, too much magic / over-extended scope / possibly clashing with existing manipulation of firewall rules etc. from other sources.

cc @mavenugal @mrjana @dave-tucker what do you think about this? Happy to catch you up on the background if you're confused about it as well.

@clnperez
Copy link
Contributor Author

I also should have probably said "implement" instead of "ask for," since I'm willing to add it myself.

@clnperez
Copy link
Contributor Author

clnperez commented Jun 9, 2015

@mrjana @dave-tucker @nathanleclaire Has anyone discussed this? I've kind of let it go stale, but would like to know you guys' opinions on getting it into docker itself vs. adding firewall bits to machine.

@duglin
Copy link

duglin commented Jun 9, 2015

@crosbymichael do you have any thoughts on whether the logic to open up the firewall should be done by Docker or Machine?

@dave-tucker
Copy link
Contributor

FWIW, I would rather it were done by Machine than Docker itself. The way I think about it, Machine is a tool for provisioning a Docker host. Things in scope could be compared to what I might have done using a similar tool (e.g Chef/Puppet) - which includes things like firewall rules.
Daemons injecting rules in to iptables is already a practice that is frowned upon. It's better handled by a sysadmin or CM system that has a global view of things running on a server.

@duglin
Copy link

duglin commented Jun 10, 2015

yep - that's the way I tend to look at it too.

@ehazlett
Copy link
Contributor

+1 for not handling this in Docker. We already have AuthorizePort in the driver interface. We need to figure out how to handle it. This is also a significant change as it's in the driver. I think it will come in parts: 1) get each driver (assuming that it supports it) to implement AuthorizePort and then 2) allow the setting on provision.

@nathanleclaire
Copy link
Contributor

Here's my take based on @ehazlett @dave-tucker's good points:

  1. AuthorizePort / DeauthorizePort should take care of opening and closing ports at the "provider firewall" level. For instance, it would be useful to be able to forward ports over NAT from a Virtualbox VM to localhost, or open ports using AWS security groups, although as you may note those two examples are completely different so we'd have to think carefully about what level of inconsistency we would be willing to tolerate.
  2. Managing iptables (or another firewall) rules should be handled by another provisioning system which Machine has "hooks" to enable. That is, we would allow you to do something like run a shell script before Docker provisioning starts, . I'd like to start minimal on this at first and only expand outwards to first-class support for CM tools etc. if there is big demand for it.

@clnperez
Copy link
Contributor Author

Thanks @ehazlett, @nathanleclaire, @dave-tucker.

@nathanleclaire, can you expand a bit on what kind of provisioning system you mean (where it would live, which drivers would rely on it/them, etc.)? What kind of thing would be in this shell script?

@nathanleclaire
Copy link
Contributor

@nathanleclaire, can you expand a bit on what kind of provisioning system you mean (where it would live, which drivers would rely on it/them, etc.)? What kind of thing would be in this shell script?

It's just a crude mental sketch right now, but the basic idea would be various configurable "stages" of provisioning that Machine would expose to the user. One could be the running of a shell script before any of Machine's "official" provisioning begins, so that the user could do things like mount an external cloud volume instance, or, in this case, run things like sudo ufw enable, sudo ufw default deny incoming, sudo ufw allow ssh, etc.

To be clear, I'm not saying definitively that this is a feature we'll implement, but it's a model to consider.

@clnperez
Copy link
Contributor Author

Hm. So, in this particular case I, the user, had no idea this ubuntu image I picked had a firewall. machine provisioning just hung and eventually failed. I'm not convinced about user intervention. That would also require the user to know which port docker needs. I could see it for the other things you mentioned, but they wouldn't keep a machine from provisioning.

@nathanleclaire
Copy link
Contributor

Hm. So, in this particular case I, the user, had no idea this ubuntu image I picked had a firewall. machine provisioning just hung and eventually failed. I'm not convinced about user intervention. That would also require the user to know which port docker needs. I could see it for the other things you mentioned, but they wouldn't keep a machine from provisioning.

Hm, I'm not sure I understand. Generally to me things like changing the base image start to get into "voiding the warranty" turf, where the user is assuming greater responsibility for the provisioning process. If your chosen image has firewall rules already, ideally you should know about it and act accordingly.

EDIT: I misunderstood a bit. I think I understand now why we might want to set iptables rules automatically. It is a bit of a tricky problem. To do so we would have to implement everything in a uniform way across all provisioners. I'm hesitant to merge this in its current form but maybe it's something we could tackle in the future if we can come to a consensus about what's appropriate for Machine to handle and where.

@dave-tucker
Copy link
Contributor

Perhaps the best thing in the interim would be to run a set of tests after the machine is provisioned before returning an exit code. That way you can catch any issues and send a useful error message to the user. E.g in the case of the base image blocking the Docker API port, you would get an error that says "Unable to reach Docker on tcp/2376. Please check your firewall rules"

@clnperez
Copy link
Contributor Author

@dave-tucker, check out PR #1348 and see if that will do.

@nathanleclaire
Copy link
Contributor

As noted in #1446, let's please move to a discussion of scoping this in the issues.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants