Lab M02P03-Server
The communication over HTTP with TLS is standard nowadays. You can easily enable TLS in Spring boot application. To do so, you need X.509 SSL certificate which is signed by trusted authority like Comodo, or ZeroSSL. You can easily generate SSL certificate for testing purposes using Java or openssl tool. This lab helps you to understand required steps how to secure HTTP communication chanel for your application.
It consists of two parts: * Server side configuration * Example of client with certificate authentication with mutual TLS
Part I - The Server
Web server as Tomcat can be configured to accept HTTPS connections only. Spring Boot support embedded web servers, and also simplifies SSL configuration of a server using server.ssl.* properties. You need also server certificate. Following steps wil guide you through the process of adding TLS on top of HTTP.
-
For this lab or dev purposes, you can crete self-signed server certificate. You will need openssl tools. The openssl is part of every Linux distribution, or you can use
gitbashon Windows, which is part of git for Windows installation. -
Execute next commands to generate required artifacts. Note: the
winptycommand is used to fix openssl stuck issue for Windows version (gitbash) For simplicity usepasswordwhenever you are asked to provide password. For server certificate CN uselocalhost, and for key alias use alsolocalhost.a) Generate self-signed CA certificate:
winpty openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crtb) Certificate signing request (CSR) for server certificate:
and config file localhost.ext:winpty openssl req -new -newkey rsa:4096 -keyout localhost.key -out localhost.csrauthorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE subjectAltName = @alt_names [alt_names] DNS.1 = localhostc) Sign the request with rootCA.crt certificate and its private key:
and check the request:winpty openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.extwinpty openssl x509 -in localhost.crt -textd) Create PKCS12 keystore:
If you like to use Java JKS as keystore, convert keystore with this command:winpty openssl pkcs12 -export -out localhost.p12 -name "localhost" -inkey localhost.key -in localhost.crtkeytool -importkeystore -srckeystore localhost.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS -
Copy keystore file
localhost.p12into resource folder. -
Add following configuration into application.yaml
5. Now start the application, and test API with postman. The server is accessible on [https://localhost:8443]. The server certificate is not trusted as it is not signed by trusted authority. You can import Root CA certificate into browser to make server certificate to be trusted.server: port: 8443 ssl: keyAlias: "localhost" key-store: "classpath:localhost.p12" key-store-password: "password" key-store-type: "PKCS12" -
There is still Basic HTTP Authentication used in the application. So let's switch to X.509 client certificate authentication. With help of the Spring Security the implementation of x.509 authentication is matter of configuration of the SecurityFilterChain where required Authentication filter is added. So change httpBasic() to x509(). Modify the SecurityFilterChain bean in SecurityConfig as following:
7. Application uses trust store to read Root CA from for client certificate validation if mutual TLS is configured. Execute following Java@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz .requestMatchers("/library/**").authenticated() .anyRequest().permitAll() ) .x509(customize -> customize.subjectPrincipalRegex("CN=(.*?)(?:,|$)")); return http.build(); }keytoolcommands to create trust store for server. Trust store creation:keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip:127.0.0.1 -file rootCA.crt -keystore truststore.jksConverting JKS to PCKS12:
Copy thekeytool -importkeystore -srckeystore truststore.jks -destkeystore truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -deststorepass passwordtruststore.p12into resource folder. -
Add also following configuration into application.yaml under server:ssl section.
yaml server: ssl: trust-store: "classpath:truststore.jks" trust-store-password: "password" client-auth: "need" -
Restart application and try to access API. You can use web browser. What is the result?
Part II - The Client
Spring Boot provides the concept of SSL bundles for configuring and consuming custom SSL trust material, such as keystores, certificates, and private keys. Once configured, a bundle can be applied to one or more connections using configuration properties or APIs. The programmatic configuration of HTTP Client to add SSL Context is also not a big deal. Check m02p03-security-https-client-lab how to implement API client with mutual TLS using Spring Boot and RestTemplate.
Every client needs its own client certificate issued by CA (Certificate Authority).
-
Client certificate generation for username=user@email.com. Use
user@email.comas CN:winpty openssl req -new -newkey rsa:4096 -nodes -keyout clientUser.key -out clientUser.csrSign client certificate with root CA (created in Part I.):
winpty openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in clientUser.csr -out clientUser.crt -days 365 -CAcreateserialCreate client store with certificate and key:
winpty openssl pkcs12 -export -out clientUser.p12 -name "clientUser" -inkey clientUser.key -in clientUser.crt -
Postman as client. You can test API call with mutual TLS, if you set certificates in Postman tool configuration.
