Possible to dynamically change options during a test?

I am trying to test a list of ciphers on a server. I’d like to go through the entire list of ciphers that k6 supports, and try to establish a TLS connection using every cipher. Here’s what I have to accomplish this:

This does not work, since exec.test.options are read-only. Is there any way I can accomplish this in a single script? I realize I could make a bunch of nearly identical scripts with global options set at the top, but I was hoping to accomplish this in a single file.

export default function () {
    // array of ciphers to test
    let ciphers = [
        "TLS_RSA_WITH_RC4_128_SHA",
        "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
        "TLS_RSA_WITH_AES_128_CBC_SHA",
        "TLS_RSA_WITH_AES_256_CBC_SHA",
        "TLS_RSA_WITH_AES_128_GCM_SHA256",
        "TLS_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
        "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
    ]
    
    // loop through ciphers
    for (let i = 0; i < ciphers.length; i++) {
        let cipher = ciphers[i];
        exec.test.options.tlsCipherSuites = [cipher];
        let res = http.get("https://badssl.com");

        check(res, {
            "is TLSv1.2": (r) => r.tls_version === http.TLS_1_2,
            [cipher]: (r) => r.tls_cipher_suite === cipher
        });
        console.log('Used ' + res.tls_cipher_suite + ' cipher suite');
    }
};

Hi @fstanley

Welcome to the community forum :wave:

One thing you could do is execute the same script, passing the tlsCipherSuites via, e.g., an environment variable. For example, with the script:

import http from 'k6/http';
import { check } from 'k6';

// read cipher from environment variable
const cipher = __ENV.cipher;
const tlsCiphers = [];
tlsCiphers.push(__ENV.cipher);

export const options = {
    tlsCipherSuites: tlsCiphers,
};

export default function () {
    let res = http.get("https://badssl.com");
    check(res, {
        "is TLSv1.2": (r) => r.tls_version === http.TLS_1_2,
        [cipher]: (r) => r.tls_cipher_suite === cipher
    });
    console.log('Used ' + res.tls_cipher_suite + ' cipher suite');
};

You could execute the following, using one of the ciphers you want to test in the variable cipher:

k6 run possible-to-dynamically-change-options-during-a-test.js --env cipher="TLS_RSA_WITH_3DES_EDE_CBC_SHA"

And in this case the checks work:

INFO[0000] Used TLS_RSA_WITH_3DES_EDE_CBC_SHA cipher suite  source=console

running (00m00.5s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  00m00.5s/10m0s  1/1 iters, 1 per VU

     ✓ is TLSv1.2
     ✓ TLS_RSA_WITH_3DES_EDE_CBC_SHA

     checks.........................: 100.00% ✓ 2        ✗ 0

Otherwise with another cipher:

k6 run possible-to-dynamically-change-options-during-a-test.js --env cipher="TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"

You’d get the failure:

WARN[0000] Request Failed                                error="Get \"https://badssl.com\": remote error: tls: handshake failure"
INFO[0000] Used  cipher suite                            source=console

running (00m00.3s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  00m00.3s/10m0s  1/1 iters, 1 per VU

     ✗ is TLSv1.2
      ↳  0% — ✓ 0 / ✗ 1
     ✗ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
      ↳  0% — ✓ 0 / ✗ 1

     checks.....................: 0.00%   ✓ 0        ✗ 2

Could you provide a bit more context so we can try to figure out alternatives?

  • What is the aim of your test, find out what ciphers a URL accepts from the list?
  • How will you execute it (command line, CI/CD pipelines, …)?

If you can describe a bit more about your requirements we might be able to figure a better way for this case.

Cheers!

This is actually the exact method I wound up implementing. A second script loops through the array and sets the environment variables to send to the k6 script. This achieved was I was hoping for. In my case, I am testing throughput of an embedded device while using different ciphers. This is a called by a CI system.

1 Like