All Projects → jonashackt → spring-boot-rest-clientcertificates-docker-compose

jonashackt / spring-boot-rest-clientcertificates-docker-compose

Licence: MIT License
Example project showing how to access REST endpoints from multiple servers that are secured by different client certificates, using Spring´s RestTemplate & Docker Compose

Programming Languages

java
68154 projects - #9 most used programming language
Dockerfile
14818 projects

Projects that are alternatives of or similar to spring-boot-rest-clientcertificates-docker-compose

spring-boot-rest-clientcertificate
Example project showing how to provide a Spring Boot App that serves a secured REST endpoint, that is called with Spring´s RestTemplate configured to use client authentification with a client certificate
Stars: ✭ 83 (+336.84%)
Mutual labels:  java-keystore, jks, client-certificate, truststore
BuildPhp
php and web env manager for mac,include apache nginx php mysql memcached redis node with mutable version, and SSL make, file info... extend tools
Stars: ✭ 111 (+484.21%)
Mutual labels:  ssl-certificates
spring-jooq-flyway-testcontainers-junit5
🚀 Example project with configured Spring Boot, JooQ, TestContainers, MySQL container and JUnit5
Stars: ✭ 29 (+52.63%)
Mutual labels:  testcontainers
private-tls-cert
A simple Terraform module to generate self-signed TLS certificates for private use
Stars: ✭ 36 (+89.47%)
Mutual labels:  ssl-certificates
spotifyApiSpring
Spring-boot MVC application consuming Spotify's REST API
Stars: ✭ 28 (+47.37%)
Mutual labels:  rest-template
cert human
SSL Certificates for Humans
Stars: ✭ 34 (+78.95%)
Mutual labels:  ssl-certificates
terraform-aws-acm-request-certificate
Terraform module to request an ACM certificate for a domain name and create a CNAME record in the DNS zone to complete certificate validation
Stars: ✭ 83 (+336.84%)
Mutual labels:  ssl-certificates
hivemq-testcontainer
Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. This enables testing MQTT client applications and integration testing of custom HiveMQ extensions.
Stars: ✭ 17 (-10.53%)
Mutual labels:  testcontainers
acmed
ACME (RFC 8555) client daemon
Stars: ✭ 121 (+536.84%)
Mutual labels:  ssl-certificates
ght-acme.sh
Shell script to sign certificate by the letsencrypt CA
Stars: ✭ 31 (+63.16%)
Mutual labels:  ssl-certificates
advanced-spring-scaffold
This project provides an advanced baseline to help you kick start a Spring project.
Stars: ✭ 21 (+10.53%)
Mutual labels:  testcontainers
google-managed-certs-gke
DEPRECATED: How to use Google Managed SSL Certificates on GKE
Stars: ✭ 16 (-15.79%)
Mutual labels:  ssl-certificates
kafka-connect-datagen
A Kafka Connect source connector that generates data for tests
Stars: ✭ 27 (+42.11%)
Mutual labels:  integration-test
testing-spring-boot-applications-masterclass
🍃 Everything You Need to Know About Testing Spring Boot Applications
Stars: ✭ 185 (+873.68%)
Mutual labels:  testcontainers
jota-cert-checker
Check SSL certificate expiration date of a list of sites.
Stars: ✭ 45 (+136.84%)
Mutual labels:  ssl-certificates
spring-r2dbc-sample
Code samples for demonstrating R2dbc, Spring R2dbc, and Spring Data R2dbc.
Stars: ✭ 105 (+452.63%)
Mutual labels:  testcontainers
docker-nginx-certbot
Automatically create and renew website certificates for free using the Let's Encrypt certificate authority.
Stars: ✭ 367 (+1831.58%)
Mutual labels:  ssl-certificates
ktor-hexagonal-multimodule
Template project to build ktor-based multi-module web service with Kotlin using Hexagonal architecture
Stars: ✭ 30 (+57.89%)
Mutual labels:  testcontainers
smart-cloud-examples
基于springcloud的脚手架(smart-cloud)示例,支持服务合并部署与拆分部署、接口加解密签名、日志数据脱敏、接口数据mock、接口文档自动生成、请求幂等校验、接口日志&&sql日志切面打印、分表分库分布式事务等
Stars: ✭ 23 (+21.05%)
Mutual labels:  integration-test
secure-oauth2-oidc-workshop
Hands-On Workshop for OAuth 2.0 and OpenID Connect 1.0
Stars: ✭ 58 (+205.26%)
Mutual labels:  testcontainers

Multiple Spring Boot servers that are secured with different client certificates - called by RestTemplate

Build Status renovateenabled

This repository basically forks all the ground work that was done in https://github.com/jonashackt/spring-boot-rest-clientcertificate. This is a basic example, where the client certificate secured server is a Spring Boot Application and the client is just a Testcase that uses Spring´s RestTemplate which is configured to use the client certificate.

In contrast the present project focusses on the configuration of more than one client certificates and how to access REST endpoints from multiple servers that are secured by different client certificates with Spring´s RestTemplate.

Therefore we use several Spring Boot based microservices that provide different client certificate secured REST endpoint and a separate microservice that accesses these services:

                  -------------------------------------------    
                 | Docker Network scope                 __   |  
                 |                         ============|o¬|  |  
                 |                         =            ¯¯=  |   
                 |                         = server-alice =  |
 ============    |   ==============   ssl  =              =  |
 =  docker- =    |   =            = -----> ================  |
 = network- = -----> = client-bob =                     __   |
 =  client  =    |   =   __   __  = -----> ============|o¬|  |
 ============    |   ===|o¬|=|o¬|==   ssl  =            ¯¯=  |
                 |       ¯¯   ¯¯           =  server-tom  =  |
                 |                         =              =  |
                 |                         ================  |
                  -------------------------------------------
                 

For a general approach on how to generate private keys and certificates and create Java Keystores, have a look into https://github.com/jonashackt/spring-boot-rest-clientcertificate#generate-the-usual-key-and-crt---and-import-them-into-needed-keystore-jks-files

HowTo Use

Everything you need to run a full build and complete test (incl. Integrationtest of docker-network-client firing up all three microservices that´ll call each other with client certificate support) is this:

mvn clean install

Only, if you want to check manually, you can do a docker-compose up -d and open your Browser with [http:localhost:8080/swagger-ui.html] and fire up a GET-Request to /secretservers with Swagger :)

Integrationtesting with testcontainers

As client-bob only has access to the DNS aliases server-alice and server-tom, if it itself is part of the Docker (Compose) network and these aliases are used to access both client certificate secured endpoints, we need another way to run an Integration test inside the Docker network scope.

Therefore we use the testcontainers and the docker-network-client that just calls client-bob inside the Docker network.

testcontainers could be []simply integrated by via Maven](https://www.testcontainers.org/usage.html#maven-dependencies):

		<dependency>
			<groupId>org.testcontainers</groupId>
			<artifactId>testcontainers</artifactId>
			<version>NewestTestcontainersVersionOnMavenCentral</version>
			<scope>test</scope>
		</dependency>

And the code you need, to fire up all Docker Compose services / Docker Containers is really simple:

package de.jonashackt;

import org.apache.http.HttpStatus;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.DockerComposeContainer;
import org.testcontainers.containers.wait.strategy.Wait;

import java.io.File;

import static io.restassured.RestAssured.when;
import static org.hamcrest.Matchers.containsString;

@RunWith(SpringRunner.class)
@ContextConfiguration()
public class ClientTest {

	@ClassRule
	public static DockerComposeContainer services =
			new DockerComposeContainer(new File("../docker-compose.yml"))
					.withExposedService("server-alice", 8443,Wait.forListeningPort())
					.withExposedService("server-tom", 8443, Wait.forListeningPort())
					.withExposedService("client-bob", 8080, Wait.forHttp("/swagger-ui.html").forStatusCode(200)).withLocalCompose(true);


	@Test
	public void is_client_bob_able_to_call_all_servers_with_client_certs() {

		when()
			.get("http://localhost:8080/secretservers")
		.then()
			.statusCode(HttpStatus.SC_OK)
			.assertThat()
				.body(containsString("Both Servers called - Alice said 'Alice answering!' & Tom replied 'Tom answering!'."));
	}
}

TlDR: How to create multiple keys & certificates for multiple servers - and add these into appropriate truststores / keystores

server-alice keys and client certificate, truststore & keystore (see /server-alice/src/main/resources)

1. Private Key: aliceprivate.key

openssl genrsa -des3 -out aliceprivate.key 1024
  • passphrase alicepassword

2. Certificate Signing Request (CSR): alice.csr

openssl req -new -key aliceprivate.key -out alice.csr -config alice-csr.conf

Common Name: server-alice, which will later be a DNS alias inside the Docker network

3. self-signed Certificate: alice.crt

openssl x509 -req -days 3650 -in alice.csr -signkey aliceprivate.key -out alice.crt -extfile alice-csr.conf -extensions v3_req

4. Java Truststore Keystore, that inherits the generated self-signed Certificate: alice-truststore.jks

keytool -import -file alice.crt -alias alicesCA -keystore alice-truststore.jks

the same password alicepassword

5. Java Keystore, that inherits Public and Private Keys (keypair): alice-keystore.jks

openssl pkcs12 -export -in alice.crt -inkey aliceprivate.key -certfile alice.crt -name "alicecert" -out alice-keystore.p12

the same password alicepassword

To read in KeyStore Explorer

keytool -importkeystore -srckeystore alice-keystore.p12 -srcstoretype pkcs12 -destkeystore alice-keystore.jks -deststoretype JKS

server-tom keys and client certificate, truststore & keystore (see /server-tom/src/main/resources)

1. Private Key: tomprivate.key

openssl genrsa -des3 -out tomprivate.key 1024
  • passphrase tompassword

2. Certificate Signing Request (CSR): tom.csr

openssl req -new -key tomprivate.key -out tom.csr -config tom-csr.conf

Common Name: server-tom, which will later be a DNS alias inside the Docker network

3. self-signed Certificate: tom.crt

openssl x509 -req -days 3650 -in tom.csr -signkey tomprivate.key -out tom.crt -extfile tom-csr.conf -extensions v3_req

4. Java Truststore Keystore, that inherits the generated self-signed Certificate: tom-truststore.jks

keytool -import -file tom.crt -alias tomsCA -keystore tom-truststore.jks

the same password tompassword

5. Java Keystore, that inherits Public and Private Keys (keypair): tom-keystore.p12

openssl pkcs12 -export -in tom.crt -inkey tomprivate.key -certfile tom.crt -name "tomcert" -out tom-keystore.p12

the same password tompassword

client-bob truststore & keystore (see /server-alice/src/main/resources)

1. Java Truststore Keystore, that inherits the generated self-signed Certificate: client-truststore.jks

keytool -import -file alice.crt -alias alicesCA -keystore client-truststore.jks
keytool -import -file tom.crt -alias tomsCA -keystore client-truststore.jks

password bobpassword

In KeyStore Explorer this should look like this:

client-truststore

2. Java Keystores, that inherit Public and Private Keys (keypair): copy alice-keystore.p12 & tom-keystore.p12

As Apache HttpClient isn´t able to handle more than one client certificate for the same SSLContext, we need to provide two of them. Therefore we don´t need to add two private keys and certificates to one Keystore - we can just use both Keystores we already assembled before. So we copy alice-keystore.p12 & tom-keystore.p12 to clien-bob/src/main/resources and use them in the RestClientCertConfiguration like this:

import org.apache.commons.io.FileUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;

@Configuration
public class RestClientCertConfiguration {

    private char[] bobPassword = "bobpassword".toCharArray();
    private char[] tomPassword = "tompassword".toCharArray();

    @Value("classpath:alice-keystore.p12")
    private Resource aliceKeystoreResource;

    @Value("classpath:tom-keystore.p12")
    private Resource tomKeystoreResource;

    @Value("classpath:client-truststore.jks")
    private Resource truststoreResource;
    private char[] alicePassword = "alicepassword".toCharArray();

    @Bean
    public HttpComponentsClientHttpRequestFactory serverTomClientHttpRequestFactory() throws Exception {
        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(inStream2File(tomKeystoreResource), tomPassword, tomPassword)
                .loadTrustMaterial(inStream2File(truststoreResource), bobPassword)
                .build();

        HttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        return new HttpComponentsClientHttpRequestFactory(client);
    }

    @Bean
    public HttpComponentsClientHttpRequestFactory serverAliceClientHttpRequestFactory() throws Exception {
        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(inStream2File(aliceKeystoreResource), alicePassword, alicePassword)
                .loadTrustMaterial(inStream2File(truststoreResource), bobPassword)
                .build();

        HttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        return new HttpComponentsClientHttpRequestFactory(client);
    }

    private File inStream2File(Resource resource) {
        try {
            File tempFile = File.createTempFile("file", ".tmp");
            FileUtils.copyInputStreamToFile(resource.getInputStream(), tempFile);
            return tempFile;
        } catch (IOException e) {
            throw new RuntimeException("Problems loading Keystores", e);
        }
    }
}

Now we´re able to insert individual SSLContexts into Spring´s RestTemplate. Therefore see ServerClientImpl:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class ServerClientImpl implements ServerClient {

    @Autowired
    private HttpComponentsClientHttpRequestFactory serverAliceClientHttpRequestFactory;

    @Autowired
    private HttpComponentsClientHttpRequestFactory serverTomClientHttpRequestFactory;

    private RestTemplate restTemplate = new RestTemplate();

    @Override
    public String callServerAlice() {
        restTemplate.setRequestFactory(serverAliceClientHttpRequestFactory);

        return restTemplate.getForObject("https://server-alice:8443/hello", String.class);
    }

    @Override
    public String callServerTom() {
        restTemplate.setRequestFactory(serverTomClientHttpRequestFactory);

        return restTemplate.getForObject("https://server-tom:8443/hello", String.class);
    }
}

Links

https://stackoverflow.com/questions/25869428/classpath-resource-not-found-when-running-as-jar

https://www.thomas-krenn.com/de/wiki/Openssl_Multi-Domain_CSR_erstellen

https://stackoverflow.com/questions/30977264/subject-alternative-name-not-present-in-certificate

https://stackoverflow.com/questions/21488845/how-can-i-generate-a-self-signed-certificate-with-subjectaltname-using-openssl

--> this is not the only solution, see -extfile and -extensions CLI paramters!

https://serverfault.com/questions/779475/openssl-add-subject-alternate-name-san-when-signing-with-ca

Multiple certificates handling in Java Keystores:

Look into the documentation of Tomcat in section keyAlias: http://tomcat.apache.org/tomcat-6.0-doc/config/http.html#SSL_Support

https://stackoverflow.com/questions/5292074/how-to-specify-outbound-certificate-alias-for-https-calls

https://stackoverflow.com/questions/6370745/can-we-load-multiple-certificates-keys-in-a-key-store

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].