dash icon indicating copy to clipboard operation
dash copied to clipboard

HTTPS for local development

Open onnimonni opened this issue 9 years ago • 8 comments

(Moved from #24) I hate that so many use https in production but they don't in development. This causes multiple errors constantly. For example devs don't notice mixed content errors.

We could selfsign a wildcard certificate with something like *.dash.test or *.d.test and then use it for jwilder/nginx-proxy. Then if we use domains like my-application.dash.test for containers they would have https enabled by default. jwilder/nginx-proxy already supports this, we only need to mount the generated cert folder into the container. These certificates could be stored locally in ~/.dash/ for example. If stored locally we could add more domains later with a command something like $ dev ssl add *.site.test.

This would also allow testing the real certificates by changing production.address in /etc/hosts.

I checked and tested but it's not possible to use self-signed certificate for tld eg *.test. Safari will accept this without a question (if it's in keychain) but chrome is more clever and denies this.

You can trust self-generated keys in OS-X by:

system "sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' #{ssl_cert_path}/development.crt"

I can do PR for this in couple of days. I just want to hear your opinions about these as well.

onnimonni avatar Feb 18 '16 20:02 onnimonni

@silvamerica you mentioned in #24 that we could use same certificate which docker creates. Well we could that but then we can't make the development environment to think that the certificate is trusted. Or at least I don't know how to do it.

TL;DR If we use docker certificate we would get error like: non-trusted-https (because the certificate CN won't match the domain)

But if we create certificate with specific CN and add it into keychain it will look like this: trusted-https

Non trusted self-signed certs have caused some problems for me in some setups. So in order to have trusted self-signed certs we could do something like this:

For example Here's my docker-machine certificate. Note that it misses CN section.

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            16:83:1b:9b:a5:0e:ad:7d:97:82:3b:bf:63:52:c4:7a
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=onnimonni
        Validity
            Not Before: Feb 18 10:55:00 2016 GMT
            Not After : Feb  2 10:55:00 2019 GMT
        Subject: O=onnimonni.<bootstrap>
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:cb:fe:fe:c3:76:23:f4:0c:87:0f:6f:9d:26:b2:
                    21:97:0a:2f:8e:34:aa:d2:d0:47:1f:74:7b:6f:cc:
                    7a:f3:d7:a6:03:dc:ab:fd:f5:36:05:c3:37:3f:44:
                    63:ea:ce:68:00:b4:a4:8c:89:32:2d:23:de:75:fa:
                    26:1a:24:f8:b3:c7:21:3c:0e:f2:a9:64:b4:0b:1f:
                    00:62:07:7c:6e:01:ae:4c:6e:24:f6:ed:c6:3d:eb:
                    4c:72:04:57:f4:2e:8c:52:41:cb:f1:47:46:ce:87:
                    e9:17:50:3b:92:59:ee:d2:4a:30:c1:39:cc:68:55:
                    26:76:d1:ad:a0:63:8b:80:19:b8:3a:fe:81:0e:3e:
                    5b:06:04:4b:79:7b:f3:34:e9:dc:d5:97:d8:57:e0:
                    48:4d:91:a8:b6:08:4c:e4:41:26:dd:21:e9:45:b7:
                    08:a9:54:2c:1c:f4:92:6d:27:07:15:92:5f:31:10:
                    cf:60:8f:d2:a7:8f:07:8a:0c:c5:e1:a9:f0:14:d4:
                    2f:86:c5:d5:14:f7:67:69:23:46:2f:b0:ca:e1:a9:
                    b5:af:d4:bc:6e:f8:c2:dd:d9:97:98:b6:ce:c2:37:
                    b7:98:50:f0:c3:b6:e3:42:41:50:c1:12:a3:24:fb:
                    f6:84:22:d9:35:62:3e:36:82:c6:b1:f9:b1:26:9d:
                    d0:31
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
        ac:bf:e0:18:c7:05:18:5c:9c:87:73:75:3b:15:0a:4c:31:60:
        9f:9a:18:84:04:66:07:44:40:d9:9c:8b:d6:ad:e2:19:7f:c4:
        99:df:86:dc:98:0b:cc:9c:79:32:84:cc:f1:42:d1:fe:93:77:
        b6:9d:06:4b:42:61:4e:d6:62:70:31:d3:96:f6:52:bf:f9:7d:
        55:c0:e0:3a:63:4d:46:51:a6:ae:37:b4:a7:ed:33:c9:9a:71:
        db:f9:23:8d:cb:64:87:21:6b:27:14:dd:0c:bc:c7:d0:39:ad:
        63:3c:c3:52:b6:e3:4e:93:06:2f:f0:05:f0:60:a0:1f:24:d8:
        64:24:a1:17:b0:be:0c:20:aa:db:b5:9c:46:dc:18:6f:c6:60:
        ac:ae:99:74:de:63:eb:48:dc:b1:28:07:9f:cc:f7:cd:f9:8d:
        e7:3b:e2:2a:b2:a4:0b:0a:fa:bf:c7:f9:bb:60:ac:52:0e:30:
        6a:57:3e:05:54:28:13:b8:58:93:8e:d2:77:84:2b:19:10:17:
        03:56:ee:79:bf:5f:2d:bf:1e:a4:19:b0:01:32:d0:62:f8:75:
        96:c2:23:23:9c:f1:ab:75:45:39:41:65:bb:26:29:28:6c:93:
        f3:fa:d0:a0:5b:ab:4f:8c:d4:11:fa:48:c5:06:1a:2e:ac:67:
        d8:98:50:9e

And the certificate we would need looks like one below. This example is for *.g.dev. See the CN sections below.

$ openssl x509 -text -noout -in development.crt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            f5:78:28:0c:22:9e:5b:a7
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=*.g.dev
        Validity
            Not Before: Feb 16 12:53:06 2016 GMT
            Not After : Feb 13 12:53:06 2026 GMT
        Subject: CN=*.g.dev
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:d5:03:73:5d:46:89:04:f0:86:de:46:86:31:10:
                    b8:f6:7c:3b:0f:60:34:de:35:ed:80:08:a1:c7:17:
                    8a:00:8c:1b:02:47:7f:4d:ac:0c:80:7e:a7:5c:fd:
                    26:53:82:1d:fa:80:85:ac:e1:93:fe:21:a4:55:04:
                    05:45:fc:aa:a8:bf:34:31:d1:40:81:db:4b:6e:67:
                    df:0a:a9:c4:f7:73:97:78:91:2d:7f:cd:11:53:df:
                    29:0e:3e:ef:10:0c:3a:70:6d:aa:a8:b2:51:67:27:
                    c6:e0:c7:50:f3:cc:c7:06:92:df:ee:fc:63:a7:fd:
                    50:99:08:aa:88:33:c7:87:af:ca:c5:de:74:df:d2:
                    3f:91:e8:68:4c:58:d7:33:eb:25:95:02:c1:45:27:
                    88:d6:13:c0:7b:fe:9d:03:6c:dd:dd:e4:96:3b:0e:
                    84:cd:ff:e5:06:c3:11:b5:18:da:c7:cb:cd:e2:34:
                    f7:b6:bf:52:7b:c5:c9:7f:5f:9d:a0:47:7a:11:68:
                    7e:7b:57:88:6e:bf:16:40:34:1e:e6:a7:b5:bc:7e:
                    5c:57:25:e4:03:22:6d:9f:bc:f7:e5:ef:3b:eb:a9:
                    08:01:d2:65:21:59:df:15:04:df:56:9e:31:e2:1f:
                    40:d0:10:69:82:9a:3d:d4:fa:47:75:5d:d7:bd:e9:
                    6d:15
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Key Encipherment, Data Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Subject Alternative Name: 
                DNS:*.g.dev
    Signature Algorithm: sha1WithRSAEncryption
        8e:7d:6f:7b:d7:d2:ec:cd:71:45:fb:5d:dd:45:b7:32:61:ab:
        9c:dc:4f:75:4d:a3:5a:2b:3e:ad:c4:ce:25:10:d6:68:63:98:
        64:b8:2a:84:fc:a2:ff:e1:6d:ea:77:b9:e5:da:26:e2:bc:b0:
        ac:f8:64:34:52:63:0f:5f:08:61:85:cf:db:db:1f:63:65:36:
        0d:62:3e:88:b7:d6:8c:c7:ec:0d:c6:01:b2:11:ef:a0:31:07:
        0b:c7:9e:b0:54:3e:76:7b:dd:50:4e:cf:0d:c7:8d:fa:0c:ff:
        46:50:06:4d:86:18:82:86:94:35:73:5f:16:1f:0c:5d:a4:58:
        55:24:70:dc:5f:81:fc:ca:6d:13:bc:0f:36:f8:3e:d3:3b:16:
        7b:57:19:4f:d1:61:fc:03:41:08:81:df:4c:e0:00:49:fe:5e:
        6f:7c:81:f9:dc:99:82:14:9e:d3:40:58:2e:c5:5f:61:2d:88:
        99:21:58:e0:52:96:b5:c2:df:b8:09:58:e7:2a:5f:82:e0:03:
        1e:e5:ae:0d:86:a9:9f:30:78:35:9a:60:7a:bc:3a:b1:25:42:
        2d:c5:9d:e7:4e:5f:90:c3:44:72:57:08:e7:b9:60:1c:5d:e1:
        a8:55:23:0d:c2:10:47:ee:c3:17:dc:7b:36:51:6e:31:6c:7e:
        71:c8:59:a0

We can make certs with correct CN by:

$ openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ssl.key -out ssl.crt -config ./openssl.cnf -newkey rsa:2048

Example openssl.cnf

  [req]
  distinguished_name = req_distinguished_name
  x509_extensions = v3_req
  prompt = no
  [req_distinguished_name]
  CN = *.g.dev
  [v3_req]
  keyUsage = keyEncipherment, dataEncipherment
  extendedKeyUsage = serverAuth
  subjectAltName = @alt_names
  [alt_names]
  DNS.1 = *.g.dev
  DNS.2 = *.web.g.dev
  DNS.3 = other.dev

onnimonni avatar Feb 18 '16 20:02 onnimonni

I think it makes sense to not use the machine cert, but rather ask users to create their own, or have the bootstrap script handle this task. I'd rather not reuse an existing cert for convenience, as that may cause unexpected issues of some kind. Separating the certs will also give us more control over the Dash cert, rather than rely on what machine gives us.

benjamin-smith avatar Feb 18 '16 21:02 benjamin-smith

Or we could just parse the docker-compose.yml and create matching certs for the domain names in nginx-proxy mounted certs folder.

onnimonni avatar Feb 18 '16 21:02 onnimonni

I mean we could do this in: $ dev up

onnimonni avatar Feb 18 '16 21:02 onnimonni

Yeah, I'll backpeddle on using the machine cert, as all of your points against it are good ones.

@onnimonni would we be able to have matching certs in nginx-proxy without scanning all possible docker-compose.yml files? I'm not exactly sure what you're suggesting. Maybe the nginx-proxy module could create certs on the fly with a trusted CA that we create during bootstrapping?

silvamerica avatar Feb 23 '16 18:02 silvamerica

I think I could make a new container like this: JrCs/docker-letsencrypt-nginx-proxy-companion but only for local development and self-signed certs.

The container can listen docker.sock and could generate new certificates on the fly and our install script should only add the self-signed ca to trusted list. Then pass the ca for this container. And mount the same /certs/ folder inside this container and jwilder/nginx-proxy.

Should these certificates be stored in project directory or in user directory ~/.dash?

onnimonni avatar Feb 24 '16 07:02 onnimonni

~/.dash hasn't been something that we've used before, but I'm not opposed to it. For that matter, I mostly arbitrarily picked /usr/local/dev-env. Does it make more sense to put them in the project directory, but move the project directory to ~? (We could make another topic for that)

silvamerica avatar Feb 25 '16 06:02 silvamerica

I made this certificate generator container during weekend: https://github.com/onnimonni/signaler

If you add HTTPS_HOST: example.dev into docker-compose.yml this container will create example.dev certificate automatically.

I'm doing the HTTPS already in our fork: https://github.com/devgeniem/gdev/blob/master/docker/services.yml

I'm using user home folder for certs and mounting the folder in nginx and signaler containers.

I was in such a hurry so I didn't make a pull request (at least not yet), would something similiar work in dash?

onnimonni avatar Mar 08 '16 09:03 onnimonni