Skip to content

Introduce Mutual TLS capabilities for secure endpoints #3

@rinshadka

Description

@rinshadka
  • Set up TechBD Hub Spring Boot application to accept Mutual TLS (mTLS) certificates for specific incoming FHIR and other REST endpoints while allowing others to be accessed without mTLS (like UI/UX endpoints).

First, set up your Spring Boot application to support SSL/TLS by configuring the application.properties file:

server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=your_keystore_password
server.ssl.key-password=your_key_password
server.ssl.key-store-type=JKS
server.ssl.client-auth=need

Create a custom security configuration to enable or disable mTLS based on the endpoint:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.cert.X509Certificate;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .addFilterBefore(new MTLSFilter(), BasicAuthenticationFilter.class);
        return http.build();
    }

    static class MTLSFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            if (requiresMTLS(request.getRequestURI())) {
                X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
                if (certs == null || certs.length == 0) {
                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Client certificate required.");
                    return;
                }
                // Perform any additional certificate checks here if needed
            }
            filterChain.doFilter(request, response);
        }

        private boolean requiresMTLS(String uri) {
            // Define your mTLS protected endpoints
            return uri.startsWith("/secure/");
        }
    }
}

Generate a keystore and truststore for your server and clients using keytool:

# Generate server keystore
keytool -genkeypair -alias server -keyalg RSA -keystore server.keystore.jks -keysize 2048 -validity 365

# Export server certificate
keytool -exportcert -alias server -keystore server.keystore.jks -file server.cer

# Generate client keystore
keytool -genkeypair -alias client -keyalg RSA -keystore client.keystore.jks -keysize 2048 -validity 365

# Export client certificate
keytool -exportcert -alias client -keystore client.keystore.jks -file client.cer

# Import client certificate into server truststore
keytool -importcert -alias client -file client.cer -keystore server.truststore.jks

# Import server certificate into client truststore
keytool -importcert -alias server -file server.cer -keystore client.truststore.jks

Ensure you place your server.keystore.jks in the src/main/resources directory and configure the paths and passwords in your application.properties.

Managing Certificates with AWS Services

  • We need to figure out whether to use ACM or other services to manage certificates. AWS Certificate Manager simplifies the process of provisioning, managing, and deploying SSL/TLS certificates. While ACM does not directly support mTLS, it can manage the certificates you need for your application.

Retrieving a Certificate from ACM

import software.amazon.awssdk.services.acm.AcmClient;
import software.amazon.awssdk.services.acm.model.GetCertificateRequest;
import software.amazon.awssdk.services.acm.model.GetCertificateResponse;

public class ACMCertificateManager {
    private final AcmClient acmClient;

    public ACMCertificateManager(AcmClient acmClient) {
        this.acmClient = acmClient;
    }

    public String getCertificate(String certificateArn) {
        GetCertificateRequest request = GetCertificateRequest.builder()
                .certificateArn(certificateArn)
                .build();
        GetCertificateResponse response = acmClient.getCertificate(request);
        return response.certificate();
    }
}

AWS Secrets Manager

In case ACM does not work, use AWS Secrets Manager by securely storing certificates and private keys. You can retrieve these secrets programmatically from your application.

Retrieving a Secret from AWS Secrets Manager

import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;

public class SecretsManagerService {
    private final SecretsManagerClient secretsManagerClient;

    public SecretsManagerService(SecretsManagerClient secretsManagerClient) {
        this.secretsManagerClient = secretsManagerClient;
    }

    public String getSecret(String secretName) {
        GetSecretValueRequest getSecretValueRequest = GetSecretValueRequest.builder()
                .secretId(secretName)
                .build();
        GetSecretValueResponse getSecretValueResponse = secretsManagerClient.getSecretValue(getSecretValueRequest);
        return getSecretValueResponse.secretString();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions