Search code examples
spring-cloud-gateway

Spring Cloud Gateway Pass Client Certificate Information


I am trying to forward client certificate information from Spring Cloud Gateway to microservices behind it. I modified the Netty config and it is successfully requesting a client cert from the client, but I don't see it forwarding it to the microservice behind it. In Apache we used to use +ExportCertData which populated a handful of headers with the client certificate DN, validity time, etc. Does Spring Cloud Gateway have any out of the box functionality like this?

I found these 2 questions which seem similar, but neither had very explicit answers. spring cloud gateway forward client certificate and Does anyone have a simple example of implementing x509 mutual authentication in Spring Cloud Gateway/Spring WebFlux?


Solution

  • After playing with it for a while, changing something on the Netty HttpClient did not seem to be right because as far as I could tell it did not know anything about where the request came from. However I found that the filter chain had all the information I needed, so I put in a custom GlobalFilter which adds the certificate information to the header like what Apache does.

    public class ClientSSLToHeaderFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 
            ServerHttpRequest req = exchange.getRequest();
            SslInfo info = req.getSslInfo();
            if(info != null) {
                X509Certificate[] certs = info.getPeerCertificates();
                if(certs != null && certs.length > 0) {
    
                    ServerHttpRequest request = exchange.getRequest().mutate()
                            .headers(httpHeaders -> {
                                try {
                                    certs[0].checkValidity();
                                    String encodedCert = new String(Base64.getEncoder().encode(certs[0].getEncoded())); 
                                    httpHeaders.add("SSL_CLIENT_CERT", encodedCert); 
                                    httpHeaders.add("SSL_CLIENT_VERIFY", "success");
                                } catch(CertificateEncodingException | CertificateExpiredException
                                        | CertificateNotYetValidException e) {
                                    // TODO Auto-generated catch block
                                    log.log(Level.ERROR, e, e);
                                }
    
                            }).build();
                    return  chain.filter(exchange.mutate().request(request).build());
                }
    
            }
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return -1;
        }
    }