From 6f415b0fec4e60c9eb0bbb5471b49459171ab280 Mon Sep 17 00:00:00 2001 From: Robert Clark Date: Thu, 12 May 2016 18:01:11 +0100 Subject: [PATCH] Adding bootstrap to docker container This commit removes the key generation stage of building Anchor containers. When a container is started it will look for a key in a docker volume named '/key' if there is a correctly formatted key it will attempt to use it. If not it will generate one before starting normal operations. Change-Id: I569f0fe07171faeed0cffc7c87f3075a094ec811 --- Dockerfile | 10 +----- README.rst | 47 +++++++++++++++++++++++--- bin/container_bootstrap.py | 67 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 bin/container_bootstrap.py diff --git a/Dockerfile b/Dockerfile index 89302d5..96230d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,4 @@ RUN pip install pecan ADD . /code WORKDIR /code RUN pip install -e . -RUN openssl req -out CA/root-ca.crt \ - -keyout CA/root-ca-unwrapped.key \ - -newkey rsa:4096 \ - -subj "/CN=Anchor Test CA" \ - -nodes \ - -x509 \ - -days 365 -RUN chmod 0400 CA/root-ca-unwrapped.key -ENTRYPOINT ["pecan", "serve", "/code/config.py"] +ENTRYPOINT ["python","bin/container_bootstrap.py"] diff --git a/README.rst b/README.rst index 5f4a3be..c20d3d9 100644 --- a/README.rst +++ b/README.rst @@ -115,12 +115,49 @@ directory. Docker test environment ======================= -We have provided a Dockerfile that can be used to build a container that -will run anchor +We have published a docker image for anchor at +https://hub.docker.com/r/openstacksecurity/anchor/ These instructions expect +the reader to have a working Docker install already. Docker should *not* be +used to serve Anchor in any production environments. -These instructions expect the reader to have a working Docker install -already. Docker should *not* be used to serve Anchor in any production -environments. +The behaviour of the Anchor container is controlled through docker volumes. To +run a plain version of Anchor, with a default configuration and a dynamically +generated private key simply invoke the container without any volumes. Note +that Anchor exposes port 5016: + +docker run -p 5016:5016 openstacksecurity/anchor + +The recommended way to use the anchor container is to use a pre-compiled private +key and certificate. You can read more about generating these (if you do not +already have them) in this readme. + +Once a key and certificate have been created, they can be provided to Anchor +using docker volumes. In this example we've stored the sensitive data in +/var/keys (note, docker must be able to access the folder where you have stored +your keys). When the container starts it looks for a mounted volume in '/key' +and files called root-ca-unwrapped.key and root-ca.crt that it will use. + +docker run -p 5016:5016 -v /var/keys:/key anchor + +Anchor is highly configurable, you can read more about Anchor configuration in +the documentation here: +http://docs.openstack.org/developer/anchor/configuration.html the method for +exposing configuration to Anchor is very similar as for keys, simply provide +docker with the folder the config.json is within and create a volume called +/config In the below example, Anchor will start with a custom configuration but +as no key was provided it will generate one on the fly. + +docker run -p 5016:5016 -v /var/config:/config anchor + +Obviously it's possible to run Anchor with a custom configuration and a custom +key/certificate by running the following (note in this case we've used -d to +detach the container from our terminal) + +docker run -d -p 5016:5016 -v /var/config:/config -v /var/keys:/key anchor + +If you prefer to use locally built containers or want to modify the container +build you can do that, we provide a simple Dockerfile to make the process +easier. Assuming you are already in the anchor directory, build a container called 'anchor' that runs the anchor service, with any local changes diff --git a/bin/container_bootstrap.py b/bin/container_bootstrap.py new file mode 100644 index 0000000..11c3268 --- /dev/null +++ b/bin/container_bootstrap.py @@ -0,0 +1,67 @@ +import os +import shutil + +from subprocess import call + +import logging + +logging.basicConfig() +logger = logging.getLogger('Anchor_Bootstrap') +logger.setLevel(logging.DEBUG) + +# This script looks for two mounted volumes '/key' and '/config'. They can +# contain key material and configuration files respectively. If data is found +# in either of these volumes it will be used to over-write the defaults within +# the Anchor container. +# In the case that '/key' is empty. This script will generate a new private key +# and copy that over the one to be used by Anchor. +# In the case that '/config' is empty no action will be taken + +# It's worth noting that the default location for key material can be modified +# in the config.json. That's really up to the deployer. + +# The reason we have a separate /key volume is to trigger a new key to be +# created even if we want to use a default configuration. + +newkey_newcert = ["openssl", "req", "-out", "CA/root-ca.crt", "-keyout", + "CA/root-ca-unwrapped.key", "-newkey", "rsa:4096", "-subj", + "/CN=Anchor Test CA", "-nodes", "-x509", "-days", "365"] + +newcert_existkey = ["openssl", "req", "-new" "-out", "CA/root-ca.crt", "-key", + "/key/root-ca-unwrapped.key", "-subj", "/CN=Anchor Test CA", + "-nodes", "-x509", "-days", "365"] + +# Anchor containers no longer build with built in keys. See if a deployer has +# provided a key, if they have, use that. If not then build one now. The key +# built in this way will disappear along with the container. +if os.path.exists('/key/root-ca-unwrapped.key'): + if os.path.exists('/key/root-ca.crt'): + # Provided both a key and a certificate + logger.info("Private key and certificate provided") + shutil.copy2('/key/root-ca-unwrapped.key', 'CA/') + shutil.copy2('/key/root-ca.crt', 'CA/') + os.chmod('CA/root-ca-unwrapped.key', 0400) + else: + # Provided key but no certificate + logger.info("Key provided without certificate. Generating certificate") + call(newcert_existingkey) + shutil.copy2('/key/root-ca-unwrapped.key', 'CA/') + os.chmod('CA/root-ca-unwrapped.key', 0400) +else: + logger.info("No key provided, Anchor will generate a dynamic one") + logger.info("To use a persistent key, create one and provide it in a key volume") + logger.info("Generating new key and certificate") + call(newkey_newcert) #No key or cert provided. Possibly no /key volume at all + os.chmod('CA/root-ca-unwrapped.key', 0400) + + +# If the user has provdided a config file in a /config volume, use that +#/config +if os.path.exists('/config/config.json'): + shutil.copy2('/config/config.json','./') + +if os.path.exists('/config/config.py'): + shutil.copy2('/config/config.py','./') + +#Start the pecan service +call(['pecan','serve','config.py'])