Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creates a Docker container to run algo #331

Merged
merged 3 commits into from
Mar 16, 2018
Merged

Creates a Docker container to run algo #331

merged 3 commits into from
Mar 16, 2018

Conversation

mutemule
Copy link
Contributor

@mutemule mutemule commented Apr 1, 2017

This does not enable you to run your VPNs from within a container.

(I'm not even sure how that would be possible, given Docker networking.)

The current version of WSL (the Ubuntu layer) provided by Windows in the Anniversary Update is based on Ubuntu 14.04 (Trusty), whereas Creators Update (expected April 11) is based on Ubuntu 16.04 (Xenial). You can get early access to the WSL update by enabling Insider Preview builds.

I just underwent another re-image of a Windows workstation, and I can't enable Insider Preview builds, as it conflicts with some other settings I have. But I do want to be able to run algo on my machine, so I put together a quick Dockerfile so this can be run via Docker. Thus far, I've successfully provisioned an algo instance in EC2 using this container.

You can give this a shot right now:

  1. Create a config.cfg in your local filesystem: .e.g C:\Users\mutemule\VPNs\config.cfg
  2. Create an empty directory called configs: e.g. C:\Users\mutemule\VPNs\configs
  3. Run the container: docker run --cap-drop ALL -it -v C:\Users\mutemule\VPNs\configs:/algo/configs -v C:\Users\mutemule\VPNs\config.cfg:/algo/config.cfg mutemule/algo:latest docker run --cap-drop ALL -it -v C:\Users\mutemule\VPNs\configs:/algo/configs mutemule/algo:latest

Since I needed this for myself anyhow, I figured I would share this upstream. This PR probably shouldn't be merged as-is, but I'm happy to clean it up for merging if there's interest:

  1. The maintainer probably shouldn't be me. Resolved.
  2. It needs some documentation indicating how to run the container. Resolved.
  3. It may benefit from something in the image to ensure the container is invoked properly (configs/ is actually bind-mounted to the host; container is launched interactively with a TTY; etc.) -- I've already got something like this locally, but it's thoroughly untested. Resolved.
  4. Unfortunately, because of how bind-mounts work, algo needs to run as root -- this is probably okay, but it's not ideal, and may break when user namespacing is enabled (I haven't tested this). I don't know a way around this.

@dguido
Copy link
Member

dguido commented Apr 1, 2017

Neat! Glad to hear the Creator's Build will have WSL based on Ubuntu 16.04. I hope this resolves the many issues that Windows users seem to run into.

I'm happy to support this if others want to contribute the missing pieces.

@mutemule
Copy link
Contributor Author

mutemule commented Apr 1, 2017

I've just cleaned things up a bit, mostly to make the container smaller.

I'll put together the other missing pieces -- namely, the second and third points from the list -- and add them in over the weekend. It should probably also cover provisioning nodes in GCP as well; that should be reasonably simple, as it's just another bind-mount.

@mutemule
Copy link
Contributor Author

mutemule commented Apr 2, 2017

I've addressed the first of the three points above, so this should now be ready for review and testing. Right now this falls into the "works for me" category; I'm not sure how to go about writing automated tests for this.

Note that I've just marked trailofbits as the maintainer, and the documentation points people to a currently-nonexistent Docker Hub repository. For now, you can s/trailofbits/mutemule/ in the instructions, and those will work just fine. If this isn't something you folks want to tackle right now, I'm happy to point people at my own images, as I'll likely be keeping them up-to-date, or I can help get this up and going (which is probably strongly preferred, so people aren't running Docker images from some random stranger on the Internet).

EDIT: Alternatively, just don't provide pre-built images, and instruct folks on building their own. It's pretty simple: docker build -t algo:current . will get everything ready, and then it's just docker run ... algo:current.

@dguido
Copy link
Member

dguido commented Apr 2, 2017

Cool! I would drop the instructions from the main README. I think this is still kind of "experimental" and will need some time to fully bake. At that point, we can think about how best to put it in the main readme.

@mutemule
Copy link
Contributor Author

mutemule commented Apr 2, 2017

I wasn't sure about the main README update, hence it being a distinct commit; it's now dropped!

@jackivanov
Copy link
Collaborator

Need to make some tests in .travis.yml

@gsf
Copy link

gsf commented Apr 8, 2017

I nearly submitted a pull request for running the client in Docker last week as well! Very cool to see interest. My solution is simpler. Here's my Dockerfile:

FROM ubuntu:16.04                                                               
                                                                                
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install \       
  build-essential \                                                             
  libffi-dev \                                                                  
  libssl-dev \                                                                  
  openssh-client \                                                              
  python \                                                                      
  python-dev \                                                                  
  python-pip \                                                                  
  python-virtualenv \                                                           
  && apt-get clean && rm -rf /var/lib/apt/lists/* \                             
  && virtualenv /env                                                            
                                                                                
ENV PATH=/env/bin:$PATH                                                         
WORKDIR /algo                                                                   
                                                                                
COPY requirements.txt requirements.txt                                          
RUN pip install -r requirements.txt                                             
                                                                                
CMD ["./algo"]

I built the container and successfully created a VPN with the following commands:

docker build -t algo .
docker run -it -v $PWD:/algo algo

algo-docker.sh Outdated
fi

# Ensure that `config.cfg` has the appropriate line endings
tr -d '\r' < config.cfg > config.cfg.new
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One could do an in place edit using

sed -i -e 's/\r//' config.cfg

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.... oh dear, I'm not sure what I was thinking here. Thanks, I'd much rather use sed in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, turns out you can't, which is probably why I did it in this weird way in the first place:

When you do the in-place sed, it actually moves the file and tries to re-create it, which isn't possible because of the bind-mount of the single file. We can either put everything in a single directory and point algo at that, or go back to this weird way of doing things.

@dstroot
Copy link

dstroot commented Apr 15, 2017

I would LOVE to have Algo in a Docker container! But it seems Docker may not offer a working IPsec stack from the StrongSWAN docs: https://wiki.strongswan.org/projects/strongswan/wiki/Cloudplatforms

Container Virtualization

"Container virtualized environments often do not offer a working IPsec stack to software in the container. Therefore, kernel-libipsec has to be used instead. To use kernel-libipsec, tun devices have to be available. Keep in mind that using kernel-libipsec has drawbacks and is generally discouraged. Change to a hardware virtualized virtual machine, if possible."

I'd love to run this in a container on Kubernetes. Anyone try that and get it working?

@dguido
Copy link
Member

dguido commented Apr 15, 2017

Thanks, but that is not what this PR is about.

@MiWCryptAnalytics
Copy link
Contributor

This would make it much easier to set up ephemeral provisioning environments, especially from external things like web apps. :-) love it.

choice base container seems correct; use of a full ubuntu:16.04 image would not be needed for the algo client.

@jauderho
Copy link
Contributor

jauderho commented Apr 15, 2017 via email

@dguido
Copy link
Member

dguido commented Apr 15, 2017

Yes, this is getting off topic but the process is documented here:
https://wiki.strongswan.org/projects/strongswan/wiki/Cloudplatforms

@dguido
Copy link
Member

dguido commented Apr 18, 2017

Thanks @gsf! @mutemule: Do you want to update your PR with anything from #331 (comment)? I've never used docker before and try to avoid it where ever possible, so I have no idea how to judge the value of each possible solution here.

@jauderho
Copy link
Contributor

There's a lot of hype around containers in general but in all honesty, I think it's likely the way forward particularly since we can probably use Docker Compose to containerize the various pieces. For instance, we can chose to pull in ad-blocker, dnscrypt functionality etc. based on features selected.

But we'll have to work through figuring out how to get IPSec working in a container first.

@dguido
Copy link
Member

dguido commented Apr 18, 2017

@jauderho we won't be doing that, and that is not what this PR is about. This just makes it easier to install the dependencies and deploy new Algo servers for some users. You can't effectively run a strongswan inside a container. I don't trust kernel-libipsec enough.

@mister2d
Copy link

mister2d commented Apr 18, 2017

@dguido I don't think kernel-libipsec is needed in a Docker container when using the Macvlan network driver for the container networking. I haven't fully tested it for ipsec comms yet though.

Removing the bridge that traditionally resides in between the Docker host NIC and container interface leaves a very simple setup consisting of container interfaces, attached directly to the Docker host interface. This result is easy access for external facing services as there is no port mappings in these scenarios.

https://docs.docker.com/engine/userguide/networking/get-started-macvlan

@mutemule
Copy link
Contributor Author

@dguido: I need to update the docs as I found a bug in how I'm running the container, but I think what #331 (comment) is trying to do is somewhat distinct from what I'm proposing: I'm trying to get a good container image pushed to Docker Hub that anyone can use without needing to install Algo at all.

I also want to have a look, as I suspect basing this off Alpine -- which makes the Dockerfile somewhat more complex -- results in a considerably smaller image, which makes this easier for folks to consume arbitrarily.

@Thermi
Copy link

Thermi commented Apr 23, 2017

The article about cloud platforms and container virtualization does not pertain docker, but surely OpenVZ and Virtuozzo. The reason is that whatever the devs did broke something that breaks XFRM or the ABI to it (protocol over netlink socket). If the container virtualization you use didn't break it (so it doesn't inherit from OpenVZ) and your container has the privileges, it will work just fine. I wrote that article, so I know that .

Give the application in the container CAP_NET_ADMIN and it will work.
(Next!)

@dguido
Copy link
Member

dguido commented Apr 23, 2017

haha oh great, now I have to update the new documentation I wrote this weekend :-(

https://github.com/trailofbits/algo/blob/master/docs/deploy-to-unsupported-cloud.md

@Thermi
Copy link

Thermi commented Apr 23, 2017

Sorry. :(

@mutemule
Copy link
Contributor Author

mutemule commented Apr 27, 2017

Dockerfile has been updated to reflect the now-mandatory usage of virtualenv. The resulting container is a bit larger (~6MB) now, but I'm not worrying about that just yet.

I've also updated the docs to reflect the bug that I found: namely, when running under Linux, it needs -u $(id -u), or the loss of CAP_DAC_OVERRIDE means you'll be unable to write things to disk. Note that I haven't actually tested this yet.

Now that this part is done, I'm going to tackle tests. Not entirely certain how to do that just yet.

(New builds have been pushed to mutemule/algo:c9481de if anyone wants to give it a shot -- latest build is always mutemule/algo:latest.)

EDIT: Fixed a few more issues; the SHA in the build above is now outdated. But the image itself doesn't run, because of volume permissions that I'm trying to sort out. Windows makes this quite hard...

@mutemule
Copy link
Contributor Author

mutemule commented May 1, 2017

Okay, worked around the volume mounting permissions thing.

Docker on Windows actually runs from a Linux VM, so when you bind-mount a Windows directory, file system permissions can only every be 0755 as a result of the mount type (CIFS, I believe?). So we no longer use the configuration data directly, and simply copy it into and out of configs/ during startup and shutdown.

I've successfully used the container to provision three VMs in the last few hours, with varying configurations, from Windows. This means that mutemule/algo:latest and mutemule/algo:4403c2d should now be fully functional.

I've also made some headway with running tests, in that I have some ideas as to how to approach testing. I'll play a bit with this in the coming days.

@dguido
Copy link
Member

dguido commented May 1, 2017

Neat, keep at it!

@dguido
Copy link
Member

dguido commented May 1, 2017

Don't forget to resync with master now and again too btw

@mutemule
Copy link
Contributor Author

mutemule commented May 1, 2017

Yeah, I am. Pretty much anytime I do any work, I pull in latest master.

@mutemule
Copy link
Contributor Author

mutemule commented May 4, 2017

I've added simple instructions (71f01ad) to test building a Docker image. CI time doesn't seem to have increased significantly, which is good.

I'm still trying to figure out how to actually test the resulting container. Because we're not using an Ubuntu base, we can't just run a local provisioner. I'm going to start looking at creating a restricted IAM account to test things that way, while I poke around at some other options.

Even then, though, a driving force behind this container is to run it on Windows, which this wouldn't test, but at least there's some basic testing going now.

I misunderstood the way tests were being run, but I think this is going to work out reasonably straightforward, at least for rough tests. Just trying to sort out the appropriate invocation syntax now.

@mutemule
Copy link
Contributor Author

mutemule commented May 4, 2017

I've left the commits for two distinct approaches to testing in place. The latter is more thorough but more complex; the former is more straightforward but less thorough.

Also, it looks like Travis can actually push the Docker image up to a repository (or you can configure Docker to build images itself). Doing so will make building images considerably easier, but I don't think you can use Content Trust (signed images) in that case.

This simply uses the same LXC system that was just tested.
It's functional, but minimal.
This doubles the number of LXC containers in use,
but does provide a more thorough test of the Docker
image.
@mutemule
Copy link
Contributor Author

mutemule commented Mar 10, 2018

For a long while, I couldn't run Docker on Windows, so I hadn't touched this.

I've just rebased on latest master, built new images, and pushed them up to Docker
Hub (mutemule/algo:latest). I've successfully used the image to provision a new Algo instance on Digital Ocean, running the container from Windows.

@dguido dguido requested a review from jackivanov March 12, 2018 15:57
@dguido
Copy link
Member

dguido commented Mar 12, 2018

Thanks for picking this up again! We had a "needs tests" label on this before, but it looks like you updated the Travis testing scripts and it passes now. I'm ready to merge this but I want Jack to check it out quickly. I requested his review.

@jackivanov
Copy link
Collaborator

Yes, that's great. How about make a repository on the docker hub and push the image every build with tags by Travis?

@dguido dguido merged commit 62fc22a into trailofbits:master Mar 16, 2018
eyecat pushed a commit to eyecat/algo that referenced this pull request Oct 23, 2018
* Creates a Docker container to run algo

* Simplistic testing of the Docker image

This simply uses the same LXC system that was just tested.
It's functional, but minimal.

* More thorough tests against Docker

This doubles the number of LXC containers in use,
but does provide a more thorough test of the Docker
image.
faf0 pushed a commit to faf0/algo that referenced this pull request Dec 13, 2018
* Creates a Docker container to run algo

* Simplistic testing of the Docker image

This simply uses the same LXC system that was just tested.
It's functional, but minimal.

* More thorough tests against Docker

This doubles the number of LXC containers in use,
but does provide a more thorough test of the Docker
image.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants