Search code examples
springsslgrails-3.1embedded-tomcat-8

How to configure SSL in Grails 3.1.6+?


We recently changed from using standalone Tomcat 8 containers to using the embedded Tomcat 8 container. We are having some trouble getting SSL to work on Grails 3.1.6 with the embedded container. We had been using the certificateFile approach with APR Native Libraries with the standalone container. We would like to keep this approach with the embedded Tomcat instead of changing to the keystore approach. I tried the Grails documentation, went deep into the Spring Boot embedded container documentation, but haven't found a working solution yet.

I tried many different configuration approaches in the application.yml. Based on several different pieces of documentation, sources, etc. my latest attempt was:

environments:
  test:
    grails:
        server:
            port: 8443
            ssl:
                enabled: true
            certificateKeyFile: '/usr/share/app/my_domain_net.key'
            certificateFile: '/usr/share/app/my_domain_net.crt'
            certificateChainFile: '/usr/share/app/myCA.crt'
        serverURL: "https://test.mydomain.net:8443"
        tomcat:
            port: 8443
            ssl:
                enabled: true
            certificateKeyFile: '/usr/share/app/my_domain_net.key'
            certificateFile: '/usr/share/app/my_domain_net.crt'
            certificateChainFile: '/usr/share/app/myCA.crt'

I also tried adding this to the end of the application.yml:

server:
    port: 8443
    ssl:
        enabled: true
    certificateKeyFile: '/usr/share/app/my_domain_net.key'
    certificateFile: '/usr/share/app/my_domain_net.crt'
    certificateChainFile: '/usr/share/app/myCA.crt'

but this gave me a 'resource location may not be null' error. Most examples and questions I see are quite dated at this point. Time to ask a fresh question on stackoverflow. Thanks in advance!


Solution

  • It was not possible to use the openssl certificateKeyFile approach, even with the APR native libraries loaded on LD_LIBRARY_PATH. (I think it may be possible if you edit grails-app/init/myapp/Application.groovy and follow the Spring documentation for adding an additional connector (at paragraph 70.9 of http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html), but this is difficult and you need to read the org.springframework sources to figure out how to make this work with openssl certificates and APR Native.) For me, it wasn't worth it, so here is how you do it using the keystore approach.

    I had to re-key the certificate using the Tomcat keytool method.

    Then, the application.yml was updated to look like this:

    ---
    ---
    environments:
        development:
            server:
                port: 8080
                ssl:
                    enabled: false
            grails:
                serverURL: "http://localhost:8080"
    
    ---
    ---
    environments:
        test:
            server:
                port: 8443
                ssl:
                    enabled: true
                key-store: classpath:my_domain_net.jks
                key-store-password: mypassword
                key-password: mypassword
            grails:
                serverURL: "https://test.mydomain.net:8443"
    

    My process for preparing the certificate was:

    1) create a directory for ssl_certificates
    2) pick a Certificate Authority (I chose DigiCert)
    3) use the CA's instructions for generating a csr for Tomcat:keytool
    4) the CA's keytool command asks for a keystore password and key password
    5) submit the csr and wait ~10 minutes for the cert to be issued
    6) download the issued certificate as my_domain_net.p7b into the
       ssl_certificates folder created above
    7) keytool -import -trustcacerts -alias server -file my_domain_net.p7b \
           -keystore my_domain_net
    8) copy my_domain_net.jks into src/main/resources/ of your web project.