|

Spring Boot : Enabling HTTPS (SSL) Using Cloudflare Certificate

In this blog post, I will explain how to enable HTTPS (SSL) in Spring Boot applications using Cloudflare SSL certificate.

For enabling SSL in Spring Boot applications we can use self signed certificate if you are running application in local development machine but in production you have to use certificate issued by Certificate Authority. In this tutorial I am going to use free SSL certificate provided by Cloudflare.

In my previous blog post, I have deployed Spring Boot application on Oracle cloud. In this blog post I am going to enable HTTPS (SSL) on same application.

Prerequisite

  1. Own a domain address ( You can get free domain from Freenom)
  2. Adding domain to Cloudflare

In my previous blog post, I have mapped the server IP address to “ap.fullstackdev.tk” address.

For same domain address we will enable the https (SSL).

Getting SSL Certificate from Cloudflare

  1. Log into your Cloudflare account. From the home page click on the domain for which you want to download the certificate.

2.From the left side menu, click on the SSL/TLS -> Origin Server

3.Click on the “Create Certificate” button.

4. We can go with default options on “Origin Certification Installation” screen and click on the “Create” button.

The certificate will work for domain and all sub domains ( as *.domain option is used).

5. Copy the generated certificate and private key into a file separately and save them as .pem and .key files.

Now we have the Cloudflare certificate. Copy these file to Oracle server. You can use software like WinSCP to copy files to server.

7. Click on SSL/TLS link on the left side menu and enable “Full” or “Full (Strict)” option

Converting Certificate to PKCS12 Format

The certificate we copied to oracle server are in .pem format. Java applications requires SSL certificate in PKCS12 format. We use package called openssl to convert certificate from pem to pkcs12 format.

Ubuntu distribution installed on Oracle server come with OpenSSL pre installed.

From your terminal enter following command and enter password when asked.

openssl pkcs12 -export -in fullstackdev.tk.pem -out keystore.p12 -inkey fullstackdev.tk.key --name fullstackdevCode language: Java (java)

Enabling SSL in Spring Boot

Now let’s enable SSL in spring boot application.

We can use following properties in application.properties and enable https (SSL) in spring appplication.

server.port=8443
security.require-ssl=true
server.ssl.key-store=/home/sbuser/certs/keystore.p12
server.ssl.key-store-password=certificatepassword
server.ssl.keyStoreType=PKCS12Code language: Java (java)

In Spring Boot applications, SSL is generally enabled on port 8443.

In general SSL is enabled when deployed to dev,test and production servers. So we make use of Spring Boot profile feature and create application-prod.properties and place SSL related properties and enable prod profile while running application.

Making Certificate Available

As we are running application with docker.

We make Spring Boot application access certificate in 2 ways.

  • Place certificate in resources folder in project
  • Copy certs using docker volume

In this blog, I am going to show you, how to make certificate available to application using docker volumes.

We need to make some changes to Dockerfile to access certificates using docker volume as we are running application with non root user.

Following is the docker file we were using to build image

FROM adoptopenjdk/openjdk11:x86_64-alpine-jdk-11.0.14.1_1-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
RUN addgroup -S springboot && adduser -S sbuser -G springboot
USER sbuser
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]Code language: Java (java)

As it is bad practice to run the docker container with root user, we were creating user called “sbuser” and adding him to group called “springboot

As we are running with non root user, when files/folders are mapped using docker volumes application will not able to access the files/folders as the mapped folders have different owner permission.

for example, in oracle server “ubuntu” is the user name we are using to log into server so files placed in the server will have “ubuntu” as the owner “ubuntu” as group owner

-rw-------  1 ubuntu ubuntu 3020 Jan  6 05:45 keystore.p12Code language: Java (java)

As we are running container with user “sbuser“, application will not be able to access the file we will get “Permission Denied ” error with docker volumes.

To over come above problem we will assign uid and gid to user and group while creating the user and group and also create folder under home folder of user while building docker image.

FROM adoptopenjdk/openjdk11:x86_64-alpine-jdk-11.0.14.1_1-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
RUN addgroup -S --g 1024 springboot && adduser -u 1024 -S sbuser -G springboot
USER sbuser
RUN mkdir /home/sbuser/certs
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]Code language: Java (java)

In above docker file we are creating “certs ” folder under “sbuser” home . We will map certificates from host machine to this directory.

In server I have copied the certificates to “certs” folder.

Using below command I will set group ownership and of certs directory and files inside it to 1024. 1024 is the group id we have used in the docker file

sudo chown -R :1024Code language: Java (java)

Note

When you change ownership to groupid , Ubuntu does not check whether that groupid exists in the system.

File permissions looks like below

$ ls -la
total 28
drwxrwxr-x  2 ubuntu   1024 4096 Jan  6 05:57 .
drwxr-x--- 13 ubuntu ubuntu 4096 Jan  4 11:28 ..
-rw------x  1 ubuntu   1024 3020 Jan  2 11:44 keystore.p12Code language: Java (java)

If the group does not have read permission to certificate file, provide read permission

chmod 641 keystore.p12Code language: Java (java)

File permissions should look like below

-rw-r----x  1 ubuntu   1024 3020 Jan  2 11:44 keystore.p12Code language: Java (java)

Now we will map certs folder from host to docker container and enable “prod” profile while running spring boot application.

As we are running application on port 8443, we need to open the port in Oracle cloud VNIC and allow the traffic on port using IP tables of server .You can refer to the my previous blog post for instructions.

We use following docker compose file

version: '3.3'


services:
  springboot-app:
    container_name: 'springboot-app'
    image: 'sureshgkhyd/springboot-flyway-dbmigration'
    restart: always
    ports:
      - 8443:8443
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    volumes:      
      - /home/ubuntu/certs:/home/sbuser/certs
    depends_on:
      - "postgres"

  postgres:
    container_name: 'postgresdb'
    image: 'postgres:13.2'
    volumes:  # volume
      - ./postgres/postgres-data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: admin
      POSTGRES_DB: TestCode language: Java (java)

Now start the application

docker-compose upCode language: Java (java)

Spring boot application should start on the port 8443.

[           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
 [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
 [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
springboot-app  |   WARN 1 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
 [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8443 (https) with context path ''
 [           main] e.SpringbootFlywayDbmigrationApplication : Started SpringbootFlywayDbmigrationApplication in 36.379 seconds (JVM running for 39.786)Code language: Java (java)

Now let’s test the application with Rest client.

Trouble Shooting

Most probably you might face issues with “Permission Denied” error due to permission issues with docker volumes while running Spring boot application with SSL certificate.

Follow the instruction as outlined in the blog post. If you are still facing the problem,

Run the application without SSL, and log into docker container.

docker exec -it springboot-app shCode language: Java (java)

Navigate to the /home/sbuser/certs folder check permissions on the files.

The group should point to “springboot” which was created as part of docker file.

In host machine we assigned gid 1024 as group owner, as gid matching with springboot (1024) docker container displays the group name.

$ ls -la
-rw-r----x    1 1001     springbo      3020 Jan  2 11:44 keystore.p12Code language: Java (java)

References

https://medium.com/@nielssj/docker-volumes-and-file-system-permissions-772c1aee23ca

Similar Posts