MTLS with K6 does not work

Hi Team,

Trying to make call to one endpoint using MTLS (private key and certificate) in K6 by following the standard documentation but it does not work.

How to replicate:

/*
This is a test JS file where a test has been written to test
MTLS with K6.

K6 Reference: https://grafana.com/docs/k6/latest/using-k6/protocols/ssl-tls/ssl-tls-client-certificates/
*/
import http from 'k6/http';
import encoding from 'k6/encoding';
import { check } from 'k6';

const url = 'https://mydomain/resource';

const CERT = `-----BEGIN CERTIFICATE-----
some certificate value
-----END CERTIFICATE-----`;
const KEY = `-----BEGIN PRIVATE KEY-----
private key for the certificate
-----END PRIVATE KEY-----`;


export const options = {
  tlsAuth: [
    {
      domains: ['mydomain'],
      //cert: open('cert.crt'),   // Tried cert providing from file
      //key: open('key.pem'),  // Tried private key providing from file
      cert: CERT,
      key: KEY,
    },
  ],
};

export default function () {
  let httpOptions = { 
    headers: { 
      'Content-Type': 'application/x-www-form-urlencoded',
    } 
  };

  let res = http.get(url, httpOptions);
  console.log(res.json());
}

OS: Windows 11
K6: k6.exe v1.0.0 (commit/41b4984b75, go1.24.2, windows/amd64)

The same REST resource has been tested with other clients like cURL, postman, Jmeter etc. It works everywhere except k6.

Please guide me if there is something missing here or there is bug in k6 injector.

Thanks,

Hello @siddhivinayaksk can you share response error from k6 console for further investigation.

Hi @Elibarick

I get an error like `CERTIFICATE_MISSING: Missing SSL/TLS certificate`. However with same certificate, it works with Jmeter or curl.

Finally, I got why it was not working.

When TLS handshake happens, server responds with Acceptable client certificate CA names which is list of allowed CAs and only the certificate issued by these CAs can be used to connect.

When K6 gets this information, it tries to validate the private key and certificate (used to make k6 test) is issued by the acceptable CAs (received from server) or not. If not, then it drops the mTLS handshake and make normal connection.

Acceptable client certificate CA names can be seen by using command openssl s_client -connect <host> -prexit. This command will try to connect to server and print all details while handshake.

After removal of this at server-side, k6 started working.

Most of the clients (like Jmeter, Postman, cURL etc.) does not do allowed CA validation at their side but K6 does. Is there any switch or way to avoid this validation at K6?

Quick answer is appreciated.