diff --git a/Makefile b/Makefile
index 982287e9ec12c53dcaf62252d6957cbe3638d15a..093ecf62bd6959c6493bc48ec46be85c650829e2 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@ Q=$(if $V,,@)
 PREFIX?=
 SRC=$(shell find . -type f -name '*.go' -not -path "./vendor/*")
 GOOS_OVERRIDE ?=
+OUTPUT_ROOT=output/
 
 # Set shell to bash for `echo -e`
 SHELL := /bin/bash
@@ -152,6 +153,70 @@ uninstall:
 
 .PHONY: install uninstall
 
+#########################################
+# Building Docker Image
+#
+# Builds a dockerfile for step by building a linux version of the step-cli and
+# then copying the specific binary when building the container.
+#
+# This ensures the container is as small as possible without having to deal
+# with getting access to private repositories inside the container during build
+# time.
+#########################################
+
+# XXX We put the output for the build in 'output' so we don't mess with how we
+# do rule overriding from the base Makefile (if you name it 'build' it messes up
+# the wildcarding).
+DOCKER_OUTPUT=$(OUTPUT_ROOT)docker/
+
+DOCKER_MAKE=V=$V GOOS_OVERRIDE='GOOS=linux GOARCH=amd64' PREFIX=$(1) make $(1)bin/$(2)
+DOCKER_BUILD=$Q docker build -t smallstep/$(1):latest -f docker/$(2) --build-arg BINPATH=$(DOCKER_OUTPUT)bin/$(1) .
+
+docker: docker-make docker/Dockerfile.step-ca
+	$(call DOCKER_BUILD,step-ca,Dockerfile.step-ca)
+
+docker-make:
+	mkdir -p $(DOCKER_OUTPUT)
+	$(call DOCKER_MAKE,$(DOCKER_OUTPUT),step-ca)
+
+.PHONY: docker docker-make
+
+#################################################
+# Releasing Docker Images
+#
+# Using the docker build infrastructure, this section is responsible for
+# logging into docker hub and pushing the built docker containers up with the
+# appropriate tags.
+#################################################
+
+DOCKER_TAG=docker tag smallstep/$(1):latest smallstep/$(1):$(2)
+DOCKER_PUSH=docker push smallstep/$(1):$(2)
+
+docker-tag:
+	$(call DOCKER_TAG,step-ca,$(VERSION))
+
+docker-push-tag: docker-tag
+	$(call DOCKER_PUSH,step-ca,$(VERSION))
+
+# Rely on DOCKER_USERNAME and DOCKER_PASSWORD being set inside the CI or
+# equivalent environment
+docker-login:
+	$Q docker login -u="$(DOCKER_USERNAME)" -p="$(DOCKER_PASSWORD)"
+
+.PHONY: docker-login docker-tag docker-push-tag
+
+#################################################
+# Targets for pushing the docker images
+#################################################
+
+# For all builds on the master branch, we actually build the container
+docker-master: docker
+
+# For all builds on the master branch with an rc tag
+docker-release: docker-master docker-login docker-push-tag
+
+.PHONY: docker-master docker-release
+
 #########################################
 # Debian
 #########################################
@@ -177,7 +242,6 @@ distclean: clean
 # Build statically compiled step binary for various operating systems
 #################################################
 
-OUTPUT_ROOT=output/
 BINARY_OUTPUT=$(OUTPUT_ROOT)binary/
 BUNDLE_MAKE=v=$v GOOS_OVERRIDE='GOOS=$(1) GOARCH=$(2)' PREFIX=$(3) make $(3)bin/$(BINNAME)
 RELEASE=./.travis-releases
@@ -234,7 +298,7 @@ artifacts-master:
 artifacts-release: artifacts-tag
 
 # This command is called by travis directly *after* a successful build
-artifacts: artifacts-$(PUSHTYPE)
+artifacts: artifacts-$(PUSHTYPE) docker-$(PUSHTYPE)
 
 .PHONY: artifacts-master artifacts-release artifacts
 
diff --git a/docker/Dockerfile.step-ca b/docker/Dockerfile.step-ca
new file mode 100644
index 0000000000000000000000000000000000000000..a5cddf2e54ea182153e13cc4faecf407129b3dd1
--- /dev/null
+++ b/docker/Dockerfile.step-ca
@@ -0,0 +1,17 @@
+FROM smallstep/step-cli:0.0.2-rc.17
+
+ARG BINPATH="bin/step-ca"
+
+ENV PORT=9000
+ENV CONFIGPATH="/home/step/.step/config/ca.json"
+ENV PWDPATH="/home/step/secrets/password"
+
+COPY $BINPATH "/usr/local/bin/step-ca"
+
+EXPOSE $PORT
+VOLUME ["/home/step/.step/secrets"]
+VOLUME ["/home/step/.step/config"]
+VOLUME ["/home/step/secrets"]
+STOPSIGNAL SIGTERM
+
+CMD exec /bin/sh -c "/usr/local/bin/step-ca --password-file $PWDPATH $CONFIGPATH"
diff --git a/docker/ca.json b/docker/ca.json
new file mode 100644
index 0000000000000000000000000000000000000000..e049d216ec3ca28b63de4ee61c66607011bb001f
--- /dev/null
+++ b/docker/ca.json
@@ -0,0 +1,39 @@
+{
+    "root": "/home/step/.step/secrets/root_ca.crt",
+    "crt": "/home/step/.step/secrets/intermediate_ca.crt",
+    "key": "/home/step/.step/secrets/intermediate_ca_key",
+    "address": ":9000",
+    "dnsNames": [
+        "ca.smallstep.com"
+    ],
+    "logger": {
+        "format": "text"
+    },
+    "authority": {
+        "provisioners": [
+            {
+                "name": "mariano@smallstep.com",
+                "type": "jwk",
+                "key": {
+                    "use": "sig",
+                    "kty": "EC",
+                    "kid": "DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk",
+                    "crv": "P-256",
+                    "alg": "ES256",
+                    "x": "jXoO1j4CXxoTC32pNzkVC8l6k2LfP0k5ndhJZmcdVbk",
+                    "y": "c3JDL4GTFxJWHa8EaHdMh4QgwMh64P2_AGWrD0ADXcI"
+                },
+                "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiOTFVWjdzRGw3RlNXcldfX1I1NUh3USJ9.FcWtrBDNgrkA33G9Ll9sXh1cPF-3jVXeYe1FLmSDc_Q2PmfLOPvJOA.0ZoN32ayaRWnufJb.WrkffMmDLWiq1-2kn-w7-kVBGW12gjNCBHNHB1hyEdED0rWH1YWpKd8FjoOACdJyLhSn4kAS3Lw5AH7fvO27A48zzvoxZU5EgSm5HG9IjkIH-LBJ-v79ShkpmPylchgjkFhxa5epD11OIK4rFmI7s-0BCjmJokLR_DZBhDMw2khGnsr_MEOfAz9UnqXaQ4MIy8eT52xUpx68gpWFlz2YP3EqiYyNEv0PpjMtyP5lO2i8-p8BqvuJdus9H3fO5Dg-1KVto1wuqh4BQ2JKTauv60QAnM_4sdxRHku3F_nV64SCrZfDvnN2ve21raFROtyXaqHZhN6lyoPxDncy8v4.biaOblEe0N-gMpJyFZ-3-A"
+            }
+        ]
+    },
+    "tls": {
+        "cipherSuites": [
+            "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
+            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
+        ],
+        "minVersion": 1.2,
+        "maxVersion": 1.2,
+        "renegotiation": false
+    }
+}
diff --git a/docker/k8s b/docker/k8s
new file mode 100755
index 0000000000000000000000000000000000000000..d9702fee761e019d06c52d782277f3235c2a555d
--- /dev/null
+++ b/docker/k8s
@@ -0,0 +1,210 @@
+#!/bin/sh
+
+CA_NAME="ca"
+CA_NAMESPACE="step"
+DEMO_NAMESPACE="step-demo"
+DEMO_ENVIRONMENT="staging"
+
+
+# The name of an image pull secret (e.g., for private docker hub images)
+# Set to "none" for no pull secret.
+IMAGE_PULL_SECRET="none"
+
+while getopts "c:d:n:e:h:t:p:i:" opt; do
+    case "$opt" in
+    h)
+        show_help
+        exit 0
+        ;;
+    c)
+        CA_NAMESPACE=$OPTARG
+        ;;
+    n)
+        CA_NAME=$OPTARG
+        ;;
+    e)
+        DEMO_ENVIRONMENT=$OPTARG
+        ;;
+    d)
+        DEMO_NAMESPACE=$OPTARG
+        ;;
+    t)
+        INSTALL_TYPE=$OPTARG
+        ;;
+    p)
+        PROVISIONER_TYPE=$OPTARG
+        ;;
+    i)
+        IMAGE_PULL_SECRET=$OPTARG
+        ;;
+    esac
+done
+
+shift $((OPTIND-1))
+
+
+# Various container images used throughout the script.
+STEP_CA_IMAGE="localhost:5000/smallstep/step-ca:latest"
+
+DIR=`pwd`
+PKI="$(dirname "$DIR")/pki"
+SECRETS="$PKI/secrets"
+
+##
+# Certificate Authority installation (prints yaml to stdout).
+##
+install_ca()
+{
+  read -p "CA Private Key Password: " -s password
+  (>&2 echo "")
+
+  tmp=$(mktemp -d /tmp/step.XXXXXX)
+  (
+    cd "$tmp"
+
+    # Bundle up certificates and private key into ConfigMap
+    mkdir $tmp/certificates
+    cp $SECRETS/root_ca.crt $tmp/certificates
+    cp $SECRETS/intermediate_ca.crt $tmp/certificates/
+    cp $SECRETS/intermediate_ca_key $tmp/certificates/
+
+    # ConfigMap for CA configuration
+    mkdir $tmp/config
+    cp $DIR/ca.json $tmp/config/ca.json
+
+    # Create the namespace
+    echo "---" > $tmp/step-ca.yml
+    echo "apiVersion: v1" >> $tmp/step-ca.yml
+    echo "kind: Namespace" >> $tmp/step-ca.yml
+    echo "metadata:" >> $tmp/step-ca.yml
+    echo "  name: $CA_NAMESPACE" >> $tmp/step-ca.yml
+    echo "---" >> $tmp/step-ca.yml
+
+    # Create certificates configmap
+    echo "apiVersion: v1" >> $tmp/step-ca.yml
+    echo "kind: ConfigMap" >> $tmp/step-ca.yml
+    kubectl create configmap ca-certificates -n $CA_NAMESPACE --from-file `pwd`/certificates --dry-run -o yaml >> $tmp/step-ca.yml
+    echo "" >> $tmp/step-ca.yml
+    echo "---" >> $tmp/step-ca.yml
+
+    # Create a CA configuration configmap
+    echo "" >> $tmp/step-ca.yml
+    echo "apiVersion: v1" >> $tmp/step-ca.yml
+    echo "kind: ConfigMap" >> $tmp/step-ca.yml
+    kubectl create configmap ca-config -n $CA_NAMESPACE --from-file `pwd`/config --dry-run -o yaml >> $tmp/step-ca.yml
+    echo "" >> $tmp/step-ca.yml
+    echo "---" >> $tmp/step-ca.yml
+
+    # Create a secret with the CA password in it
+    echo "" >> $tmp/step-ca.yml
+    echo "apiVersion: v1" >> $tmp/step-ca.yml
+    echo "kind: Secret" >> $tmp/step-ca.yml
+    kubectl create secret generic ca-certificate-password -n $CA_NAMESPACE --from-literal=password="$password" --dry-run -o yaml >> $tmp/step-ca.yml
+)
+
+  echo "" >> $tmp/step-ca.yml
+  echo "---" >> $tmp/step-ca.yml
+  echo "" >> $tmp/step-ca.yml
+
+  cat <<EOF >> $tmp/step-ca.yml
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    service: $CA_NAME
+  name: $CA_NAME
+  namespace: $CA_NAMESPACE
+spec:
+  type: ClusterIP
+  ports:
+  - name: headless
+    port: 443
+    targetPort: 9000
+  selector:
+    service: $CA_NAME
+
+---
+
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: $CA_NAME
+spec:
+  minAvailable: 1
+  selector:
+    matchLabels:
+      service: $CA_NAME
+
+---
+
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: $CA_NAME
+  namespace: $CA_NAMESPACE
+spec:
+  replicas: 1
+  strategy:
+    rollingUpdate:
+      maxSurge: 25%
+      maxUnavailable: 25%
+    type: RollingUpdate
+  template:
+    metadata:
+      creationTimestamp: null
+      labels:
+        service: $CA_NAME
+    spec:
+      containers:
+        - name: $CA_NAME
+          image: $STEP_CA_IMAGE
+          resources:
+            requests:
+              cpu: 100m
+              memory: 20Mi
+          readinessProbe:
+            httpGet:
+              path: /health
+              port: 443
+              scheme: HTTPS
+            initialDelaySeconds: 3
+            periodSeconds: 3
+          livenessProbe:
+            httpGet:
+              path: /health
+              port: 443
+              scheme: HTTPS
+            initialDelaySeconds: 5
+            periodSeconds: 3
+          volumeMounts:
+            - name: certificates
+              mountPath: /home/step/.step/secrets
+              readOnly: true
+            - name: config
+              mountPath: /home/step/.step/config
+              readOnly: true
+            - name: secrets
+              mountPath: /home/step/secrets
+              readOnly: true
+          securityContext:
+            runAsUser: 1000
+            allowPrivilegeEscalation: false
+      volumes:
+        - name: certificates
+          configMap:
+            name: ca-certificates
+        - name: config
+          configMap:
+            name: ca-config
+        - name: secrets
+          secret:
+            secretName: ca-certificate-password
+EOF
+
+  cat $tmp/step-ca.yml
+
+  rm -rf "$tmp"
+
+}
+
+install_ca