|
| 1 | +# Configuring SSL Certificates |
| 2 | + |
| 3 | +This article provides examples that can be used as a starting point when configuring SSL certificates. |
| 4 | + |
| 5 | +## Requirements |
| 6 | + |
| 7 | +The examples that follow assume that you are using Docker v1.13+, Docker Compose v1.10+, and Docker Machine v0.9+. |
| 8 | + |
| 9 | +!!! info |
| 10 | + If you are a Windows user, please run all the examples from *Git Bash* (installed through *Docker Toolbox*). Also, make sure that your Git client is configured to check out the code *AS-IS*. Otherwise, Windows might change carriage returns to the Windows format. |
| 11 | + |
| 12 | +Please note that *Docker Flow Proxy* is not limited to *Docker Machine*. We're using it as an easy way to create a cluster. |
| 13 | + |
| 14 | +## Swarm Cluster Setup |
| 15 | + |
| 16 | +To setup an example Swarm cluster using Docker Machine, please run the commands that follow. |
| 17 | + |
| 18 | +!!! tip |
| 19 | + Feel free to skip this section if you already have a working Swarm cluster. |
| 20 | + |
| 21 | +```bash |
| 22 | +curl -o swarm-cluster.sh \ |
| 23 | + https://raw.githubusercontent.com/\ |
| 24 | +vfarcic/docker-flow-proxy/master/scripts/swarm-cluster.sh |
| 25 | + |
| 26 | +chmod +x swarm-cluster.sh |
| 27 | + |
| 28 | +./swarm-cluster.sh |
| 29 | + |
| 30 | +eval $(docker-machine env node-1) |
| 31 | +``` |
| 32 | + |
| 33 | +Now we're ready to deploy the services that form the proxy stack and the demo services. |
| 34 | + |
| 35 | +```bash |
| 36 | +docker network create --driver overlay proxy |
| 37 | + |
| 38 | +curl -o docker-compose-stack.yml \ |
| 39 | + https://raw.githubusercontent.com/\ |
| 40 | +vfarcic/docker-flow-proxy/master/docker-compose-stack.yml |
| 41 | + |
| 42 | +docker stack deploy -c docker-compose-stack.yml proxy |
| 43 | + |
| 44 | +curl -o docker-compose-go-demo.yml \ |
| 45 | + https://raw.githubusercontent.com/\ |
| 46 | +vfarcic/go-demo/master/docker-compose-stack.yml |
| 47 | + |
| 48 | +docker stack deploy -c docker-compose-go-demo.yml go-demo |
| 49 | +``` |
| 50 | + |
| 51 | +Please consult [Using Docker Stack To Run Docker Flow Proxy In Swarm Mode](/swarm-mode-stack/) for a more detailed set of examples of deployment with Docker stack. |
| 52 | + |
| 53 | +Before proceeding towards the SSL examples we should wait until all the services are running. |
| 54 | + |
| 55 | +```bash |
| 56 | +docker service ls |
| 57 | +``` |
| 58 | + |
| 59 | +## Creating a New Image With Certificates or Mounting a Volume |
| 60 | + |
| 61 | +Even though we published the proxy port `443` and it is configured to forward traffic to our services, `SSL` communication still does not work. We can confirm that by sending an HTTPS request to our demo service. |
| 62 | + |
| 63 | +```bash |
| 64 | +curl -i "https://$(docker-machine ip node-1)/demo/hello" |
| 65 | +``` |
| 66 | + |
| 67 | +The output is as follows. |
| 68 | + |
| 69 | +``` |
| 70 | +curl: (35) Unknown SSL protocol error in connection to 192.168.99.100:-9847 |
| 71 | +``` |
| 72 | + |
| 73 | +The error means that there is no certificate that should be used with HTTPS traffic. |
| 74 | + |
| 75 | +There are two ways we can add certificates to the proxy. One is to create your own Docker image based on `docker-flow-proxy`. `Dockerfile` could be as follows. |
| 76 | + |
| 77 | +``` |
| 78 | +FROM vfarcic/docker-flow-proxy |
| 79 | +COPY my-cert.pem /certs/my-cert.pem |
| 80 | +``` |
| 81 | + |
| 82 | +When the image is built, it will be based on `vfarcic/docker-flow-proxy` and include `my-cert.pem` file. The `my-cert.pem` would be your certificate. Docker Flow proxy will load all certificates located in the `/certs` directory. |
| 83 | + |
| 84 | +If your certificate is static (almost never changes) and you are willing to create your own `docker-flow-proxy` image, this might be a good option. An alternative would be to mount a network volume with certificates. |
| 85 | + |
| 86 | +## Adding Certificates Through HTTP Requests |
| 87 | + |
| 88 | +!!! info |
| 89 | + Certificates can be added to the proxy dynamically through an HTTP request. |
| 90 | + |
| 91 | +We'll start by creating a certificate we'll use throughout the examples. |
| 92 | + |
| 93 | +For production, you should create your certificate through one of the trusted services. For demo purposes, we'll create a self-signed certificate with `openssl`. Before proceeding, please make sure that `openssl` is installed on your host OS. |
| 94 | + |
| 95 | +We'll store a certificate in `tmp` directory, so let us create it. |
| 96 | + |
| 97 | +```bash |
| 98 | +mkdir -p certs |
| 99 | +``` |
| 100 | + |
| 101 | +The certificate will be tied to the `*.xip.io` domain, which is handy for demonstration purposes. It'll let us use the same certificate even if our server IP addresses might change while testing locally. With [xip.io](http://xip.io/) don't need to re-create the self-signed certificate when, for example, our Docker machine changes IP. |
| 102 | + |
| 103 | +!!! info |
| 104 | + I use the [xip.io](http://xip.io/) service as it allows me to use a hostname rather than directly accessing the servers via an IP address. It saves me from editing me computers' host file. |
| 105 | + |
| 106 | +To create a certificate, first we need a key. |
| 107 | + |
| 108 | +```bash |
| 109 | +openssl genrsa -out certs/xip.io.key 1024 |
| 110 | +``` |
| 111 | + |
| 112 | +With the newly created key, we can proceed and create a certificate signing request (CSR). The command is as follows. |
| 113 | + |
| 114 | +```bash |
| 115 | +openssl req -new \ |
| 116 | + -key certs/xip.io.key \ |
| 117 | + -out certs/xip.io.csr |
| 118 | +``` |
| 119 | + |
| 120 | +You will be asked quite a few question. It is important that when "Common Name (e.g. server FQDN or YOUR name)" comes, you answer it with `*.xip.io`. Feel free to answer the rest of the question as you like. |
| 121 | + |
| 122 | +Finally, with the key and the CSR, we can create the certificate. The command is as follows. |
| 123 | + |
| 124 | +```bash |
| 125 | +openssl x509 -req -days 365 \ |
| 126 | + -in certs/xip.io.csr \ |
| 127 | + -signkey certs/xip.io.key \ |
| 128 | + -out certs/xip.io.crt |
| 129 | +``` |
| 130 | + |
| 131 | +As a result, we have the `crt`, `csr`, and `key` files in the `tmp` directory. |
| 132 | + |
| 133 | +Next, after the certificates are created, we need to create a `pem` file. A pem file is essentially just the certificate, the key and optionally certificate authorities concatenated into one file. In our example, we'll simply concatenate the certificate and key files together (in that order) to create a `xip.io.pem` file. |
| 134 | + |
| 135 | +```bash |
| 136 | +cat certs/xip.io.crt certs/xip.io.key \ |
| 137 | + | tee certs/xip.io.pem |
| 138 | +``` |
| 139 | + |
| 140 | +To demonstrate how `xip.io` works, we can, for example, send the request that follows. |
| 141 | + |
| 142 | +```bash |
| 143 | +curl -i "http://$(docker-machine ip node-1).xip.io/demo/hello" |
| 144 | +``` |
| 145 | + |
| 146 | +Our laptop thinks that we are dealing with the domain `xip.io`. When your computer looks up the xip.io domain, the xip.io DNS server extracts the IP address from the domain and sends it back in the response. The [xip.io](http://xip.io/) service is useful for testing purposes. |
| 147 | + |
| 148 | +Now we have the PEM file and a domain we'll use to test it. The only thing missing is to add it to the proxy. |
| 149 | + |
| 150 | +We'll send the proxy service the PEM file we just created. Before we do that, we should publish the port `8080`. It is proxy's internal port we can use to send it commands. If you already have the port `8080` published, there is no need to run the command that follows. |
| 151 | + |
| 152 | +```bash |
| 153 | +docker service update \ |
| 154 | + --publish-add 8080:8080 proxy_proxy |
| 155 | +``` |
| 156 | + |
| 157 | +Please wait a few moments until the proxy is updated. You can check the status by executing the `docker service ps proxy` command. |
| 158 | + |
| 159 | +Now we can tell the proxy to use the certificate we created. The command is as follows. |
| 160 | + |
| 161 | +```bash |
| 162 | +curl -i -XPUT \ |
| 163 | + --data-binary @certs/xip.io.pem \ |
| 164 | + "$(docker-machine ip node-1):8080/v1/docker-flow-proxy/cert?certName=xip.io.pem&distribute=true" |
| 165 | +``` |
| 166 | + |
| 167 | +The `PUT` request to the proxy passed the certificate in its body (`--data-binary @tmp/xip.io.pem`). The request URL has the certification name (`certName`) as one of the parameters. The second parameter (`distribute`) sends the proxy the signal to distribute the certificate to all the replicas. The result of the request is that the certificate has been added to all the replicas of the proxy. We can confirm that by inspecting the proxy config. |
| 168 | + |
| 169 | +```bash |
| 170 | +curl "$(docker-machine ip node-1).xip.io:8080/v1/docker-flow-proxy/config" |
| 171 | +``` |
| 172 | + |
| 173 | +The relevant part of the output is as follows. |
| 174 | + |
| 175 | +``` |
| 176 | +frontend services |
| 177 | + bind *:80 |
| 178 | + bind *:443 ssl crt /certs/xip.io.pem |
| 179 | + mode http |
| 180 | +
|
| 181 | + acl url_go-demo path_beg /demo |
| 182 | + use_backend go-demo-be if url_go-demo |
| 183 | +
|
| 184 | +backend go-demo-be |
| 185 | + mode http |
| 186 | + server go-demo go-demo:8080 |
| 187 | +``` |
| 188 | + |
| 189 | +As you can see, the certificate `xip.io.pem` was added to the `*:443` binding and the proxy is ready to serve HTTPS requests. |
| 190 | + |
| 191 | +Let's confirm that HTTPS works. |
| 192 | + |
| 193 | +```bash |
| 194 | +curl -i -k "https://$(docker-machine ip node-1).xip.io/demo/hello" |
| 195 | +``` |
| 196 | + |
| 197 | +Please note that you are not limited to a single certificate. You can send multiple `PUT` requests with different certificates and they will all be added to the proxy. |
| 198 | + |
| 199 | +Now you can secure your proxy communication with SSL certificates. Unless you already have a certificate, purchase it or get it for free from [Let's Encrypt](https://letsencrypt.org/). The only thing left is for you to send a request to the proxy to include the certificate and try it out with your domain. |
| 200 | + |
| 201 | +Now that we have a way to add certificates to the proxy, we might explore a more secure way to accomplish the same result. |
| 202 | + |
| 203 | +## Adding Certificates As Docker Secrets |
| 204 | + |
| 205 | +Keeping certificates inside Docker images or mounted volumes is fairly insecure. To tighten the security, we can add a certificate as a Docker secret. |
| 206 | + |
| 207 | +```bash |
| 208 | +docker secret create cert-xip.io.pem certs/xip.io.pem |
| 209 | +``` |
| 210 | + |
| 211 | +Once a secret is safely stored inside Swarm managers, the only thing missing is to add it to the proxy. |
| 212 | + |
| 213 | +Normally, we would include certificates when creating the service. However, since the `proxy` service is already running, we'll update it instead. |
| 214 | + |
| 215 | +```bash |
| 216 | +docker service update --secret-add cert-xip.io.pem proxy_proxy |
| 217 | +``` |
| 218 | + |
| 219 | +Docker stored the secret certificate inside all the containers that form the `proxy` service. |
| 220 | + |
| 221 | +Let's confirm that the certificate indeed works. |
| 222 | + |
| 223 | +```bash |
| 224 | +curl -i -k "https://$(docker-machine ip node-1).xip.io/demo/hello" |
| 225 | +``` |
| 226 | + |
| 227 | +We got the `200` response confirming that the certificate is stored in the proxy as a Docker secret and that the configuration was updated accordingly. |
| 228 | + |
| 229 | +!!! info |
| 230 | + Since many other types of information can be stored as secrets, *Docker Flow Proxy* assumes that secrets that should be used as certificates are prefixed with `cert-` or `cert_`. Secrets with any other naming convention will not be loaded as certificates. |
| 231 | + |
| 232 | +## Summary |
| 233 | + |
| 234 | +We explored a few ways to store certificates inside the proxy. We can build a new image that already includes the certificates or we can mount a network volume. Certificates can be added after the service was created through the [PUT certificate](/usage/#put-certificate) request. Finally, we explored how we can leverage Docker secrets that provide a more secure way to transmit certificates to the proxy. |
| 235 | + |
| 236 | + |
| 237 | +!!! info |
| 238 | + The recommended way to manage proxy certificates is through Docker secrets. |
0 commit comments