Munki-Docker & SSL (proofing a concept)

Edit:

The ustwo docker munki git repo has been removed, thanks to Clayton Burlison you can see a forked version here https://github.com/clburlison/docker-munki-ssl

Intro

This is a stumbling journey of a layman and how he got a proof of concept munki repo secured with ssl in some way on a docker host. Before this I knew little about docker, less about ssl/certs and had barely touched Ubuntu let alone a server version.

enhanced-14836-1414320930-8

The end game: Have a Munki Repo that requires client side ssl certs for authentication (as a means to protect for un authorized access to a repo) and hosted in a docker environment (for easy maintenance and recreation of servers in multiple locations.

The Pieces

  • Server

    • Base OS: Ubuntu Server 14.04.3
    • Docker 1.9.1 (current release at the time)
    • Ubuntu was a VM via Virtual box on a Mac Mini
      • (Okay, Okay, emphasis on proof of concept)
    • Munki-Docker Container files
  • Client

    • OS X 10.10 VM (clean install)
  • Certs

    • Server Cert
    • Client Cert

The Setup

Server

I started with a VM of Ubuntu Server 14.04.3 standard install.

Update

apt-get update

Install ssh

apt-get install openssh-server

Install docker

apt-get install docker.io

Docker

I started originally vying for a Munki Repo hosted on Ubuntu. I followed the extremely well documented (and explanatory)  Munki on Ubuntu (pt I,II,III & Reposado) by Clayton Burlison. But I thought to myself, (and perhaps a couple other voices) “what about docker..?” The only experience I had was Connect the Dots with Docker at PSU Macadmins by Pepijn Bruienne

Munki Repo

I originally followed Running Munki in Docker by Nick McSpadden which did a rad job of step by step and explaining what the steps I was taking were doing. This was my first dip into Docker and Nick did an incredible job of making accessible.

From there I wanted the SSL layer, as in production I am looking to secure the repo from any access by a client without a client certificate. This process would essentially be a comparison of the client cert to the server cert to ensure that the client has access to the repo in which it is trying to access. This was more dictated by the nature of my professional life, not my choice, but you can’t be too secure right? Right!?

new

I am.

This is where I started cross pollinating the Nick’s instructions and Docker-Munki-SSL by Ustwo‘s Conf Files. I didn’t know exactly what I was looking at- I also have little web experience, so NGINX was all new to me as well. So this at first was a hit more miss trial and error session for me.

 

So looking at Ustwo’s docker-munki-ssl files…

Three main parts

  • Dockerfile
    • Instructions on building the Docker image. (More)
  • nginx.conf
    • Generic NGINX configuration file
  • munki-repo-ssl.conf
    • Specific configurations to munki-repo, also where SSL is defined.

And this is how I broke them down:

Dockerfile:

Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession. Docker Docs

# designates the base image, in this case it will prefer the latest nginx
FROM nginx
# makes the directory /munki_repo
RUN mkdir -p /munki_repo
# makes the directory /etc/nginx/sites-enabled/
RUN mkdir -p /etc/nginx/sites-enabled/
# Adds the nginx conf to proper location
ADD nginx.conf /etc/nginx/nginx.conf
# Adds the munki-repo conf to proper location
ADD munki-repo-ssl.conf /etc/nginx/sites-enabled/
# Adds the server cert into the image
ADD server.crt /etc/nginx/certs/server.crt
# Adds the server key into the image
ADD server.key /etc/nginx/certs/server.key
# Adds the ca cert into the image
ADD ca.crt /etc/nginx/certs/
# Create the volume /munki_repo
VOLUME /munki_repo
#Expose port 443 for SSL
EXPOSE 443

nginx.conf

# stay in the foreground so Docker has a process to track
worker_processes 1;
http {
include /etc/nginx/sites-enabled/*;
include       mime.types;
default_type  application/octet-stream;
sendfile        on;
keepalive_timeout  65;
}
events {
worker_connections 768;
}

This conf seemed pretty straightforward on the layout, the next conf determines ssl settings.

munki-repo-ssl.conf

# Munki Repo
server {
    listen 443;
    ssl on;
    server_name munki.domain.com;
    ssl_certificate      /etc/nginx/certs/server.crt;
    ssl_certificate_key  /etc/nginx/certs/server.key;
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 1;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;
    location /repo/ {
      alias /munki_repo/;
      autoindex off;
	    }
	}

For the nginx.conf I went to the nginx docs, this post on configuring HTTPS servers, and the ssl module page were extremely helpful in making sense of this conf file. But essentially it is pointing toward server.crt, server.key, & ca.crt. Telling it that the client must be verified, check client certs against server certs.

Make sure to change server_name to the fqdn of the server you’re setting up. Also don’t forget to modify the host file on the client machine for testing. 

The certs, my least favorite part… as seen above we need:

  • server.crt
    • To act as a security reference on the server.
  • client.crt
    • To distribute to the client to be verified against the server.
  • ca.crt
    • Oh huzzah! This is simple enough.

Lets Talk About Certificates by Ben Toms at JNUC 2015 helped my wrap my head around certs a bit better for this project.

Server.crt

  • Generated cert from our internal CA
    • You could setup a CA on the server itself if you don’t have one already.
  • Our CA outputs in non-ideal cert types for nginx and os x
  • So some conversion was required…
  • nginx and os x seemed to prefer pem, not der format.

Client.crt

  • Saw the same with the incompatible cert types
  • The Ustwo github breaks this down line by line…
  • Create the Client Key and CSR

    Organization & Common Name = munkiclient

    openssl genrsa -des3 -out client.key 4096
    openssl req -new -key client.key -out client.csr
    # self-signed
    openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
    

    Convert Client Key to PKCS

    So that it may be installed in most browsers.

    openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
    

    Convert Client Key to (combined) PEM

    Combines client.crt and client.key into a single PEM file for programs using openssl.

    openssl pkcs12 -in client.p12 -out client.pem -clcerts
    

    Install Client Key on client device (OS or browser)

    Use client.p12. Actual instructions vary.

    Create the Server Key and CRT

    Organization & Common Name = munki.example.com

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
    
    ustwo/docker-munki-ssl
    
  • So you actually end up with:
    • client-munki.crt.pem
    • client-munki.key.pem

Building the Image

Once we have all the parts as we want…

  • Dockerfile
  • nginx.conf
  • munki-repo-ssl.conf
  • server.crt
  • ca.crt
  • client certs

…we can get started. The docker file will act as the building instructions, it will insert the certs into the image, so the certs will be within the container, I have tinkered with the idea of exposing the certs location as a volume (as we will do with the repo) so they can be managed at the host level- but I haven’t gotten it to jive just yet.

Running the build command, I like to tag with version numbers to keep track of testing these servers(I am sure this isn’t proper form):

docker build -t lucas/munki-ssl:v1

Run munki-data(Data-only), this is the data only container that will hold all the files in the munki repo:

docker run -d --name munki-data -v /home/user/munki_repo:/munki_repo --entrypoint /bin/echo lucas/munki-ssl:v1 Data-only container for munki

What I did here was expose the munki_repo to the host at /home/user/ so that I could move files in and out via the host, without having to be inside the contianer. Nick McSpadden offers another option of making a SMB-munki container that allows temp access to repo when the container is running.
Run Munki:

docker run -d --name munki-test --volumes-from munki-data -v /home/usr/nginx_logs:/var/log/nginx/ -p 443:443 -h munki lucas/munki-ssl:v1

For the web server container I expose the location of the nginx logs to a place on the host for ease of access.

So now there should be two (or three if you chose to use the smb option) containers on your docker host. The data-only container will never ‘run’ it will just exist as a storage option. The munki server should be up on 443.

Client

For the client I followed the Ustwo github breakdown verbatim for the client enrollment and testing options.

Munki Client setup

First we need to convert into two pem files as Munki doesn’t liked the joined client.pem

openssl x509 -in client.crt -out client-munki.crt.pem -outform PEM
openssl rsa -in client.key -out client-munki.key.pem -outform PEM

Transfer the certs to your client in my example I used scp to put them in /tmp/.

sudo mkdir -p /Library/Managed\ Installs/certs
sudo chmod 0700 /Library/Managed\ Installs/certs
sudo cp /tmp/client-munki.crt.pem /Library/Managed\ Installs/certs/client-munki.crt.pem
sudo cp /tmp/client-munki.key.pem /Library/Managed\ Installs/certs/client-munki.key.pem
sudo chmod 0600 /Library/Managed\ Installs/certs/client-munki*
sudo chown root:wheel /Library/Managed\ Installs/certs/client-munki*

Change the ManagedInstalls.plist defaults:

sudo defaults write /Library/Preferences/ManagedInstalls SoftwareRepoURL "https://munki.example.com/repo"
sudo defaults write /Library/Preferences/ManagedInstalls ClientCertificatePath "/Library/Managed Installs/certs/client-munki.crt.pem"
sudo defaults write /Library/Preferences/ManagedInstalls ClientKeyPath "/Library/Managed Installs/certs/client-munki.key.pem"
sudo defaults write /Library/Preferences/ManagedInstalls UseClientCertificate -bool TRUE

ustwo/docker-munki-ssl

When I ran managedsoftwareupdate -vvv –checkonly it succeeded in pulling down info from the repo. I found that the real key is in the first part of the run where the cert verification takes place.

Next for me…

Here is where I am headed next for this project, as time allows. I am not claiming to be the first, not to be doing it the best. Just an average macadmin giving the docker world a ride.

  • More “depth” of this server
    • Logging (report to logging server)
    • SSL configs
    • Automated startup/duplication/multiple locations
    • Use network mounts for repos
  • Munki-report PHP
  • Munki-admin
  • Imaging
    • BSDpy
    • Imagr

Existing Projects Referenced

 

I am new here! Comments, pointers & resources are of course welcome. Just be kind!

4 thoughts on “Munki-Docker & SSL (proofing a concept)

  1. Pingback: Munkireport-PHP on Docker | Lucas J. Hall

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s