Xk6 browser in docker with organization certificate

Hi,

I am attempting to run a very simple test which is having issues due to err:net::ERR_CERT_AUTHORITY_INVALID while trying to load the page.

Background:
I am trying to open a webpage of a company’s webapp hosted on a remote machine. The app is behind and NGINX which is used for SSL termination and provides the certificates (fully chained), with the organization root certificate inside the trusted root store of the windows machines. When you go to the URI, for example: https://mywebapp.company.local , it does a redirect to a login page but uses the company’s fully chained certificate. I am then trying to output results to Prometheus and Grafana. I’ve been trying everything for several days to get it to work but unfortunately it’s always getting the certificate error. On the side of the app server with the nginx, the nginx error log prints out:

[info] 6440#2356: *17 SSL_do_handshake() failed (SSL: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:SSL alert number 42) while SSL handshaking, client: 192.1.1.1, server: 0.0.0.0:443

Note: the following docker files work for API testing against this remote machine (correct certificate), but the issue happens when trying to use the browser. Also note, the code runs just fine when using xk6-browser.exe instead of docker.

Here are my dockerfile, dockercompose, and test code:
dockerfile:


FROM golang:1.19-bullseye as builder

RUN go install -trimpath go.k6.io/xk6/cmd/xk6@latest
RUN  xk6 build --output "/tmp/k6" --with github.com/grafana/xk6-browser@main 

FROM debian:bullseye

RUN apt-get update && \
    apt-get install -y chromium &&\
    apt install -y libnss3-tools curl &&\
    apt-get install -y ca-certificates

COPY ./certs/fullychained.crt /usr/local/share/ca-certificates/fullychained.crt
COPY ./certs/rootca.crt /usr/local/share/ca-certificates/rootca.crt
RUN chmod 644 /usr/local/share/ca-certificates/fullychained.crt && \
    chmod 644 /usr/local/share/ca-certificates/rootca.crt && \
    update-ca-certificates

COPY --from=builder /tmp/k6 /usr/bin/k6

ENV XK6_HEADLESS=true

ENTRYPOINT ["k6"]

And here is the docker compose:


version: '3.8'

networks:
  k6:
  grafana:
  prometheus:

services:
  prometheus:
    image: prom/prometheus:v2.40.7
    command:
      - --web.enable-remote-write-receiver
      - --enable-feature=native-histograms
      - --config.file=/etc/prometheus/prometheus.yml
    networks:
      - k6
      - grafana
      - prometheus
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana:9.3.2
    networks:
      - grafana
      - prometheus
    ports:
      - "3000:3000"
    environment:
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_BASIC_ENABLED=false
     # - IGNORE_HTTPS_ERRORS=true
    volumes:
      - ./grafana:/etc/grafana/provisioning/

  k6-browser:
    build: .
    networks:
      - k6
    ports:
      - "6565:6565"
      - "443:443"
      - "80:80"
    environment:
      - K6_PROMETHEUS_RW_SERVER_URL=http://prometheus:9090/api/v1/write
      - K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true
      - K6_OUT=experimental-prometheus-rw
    depends_on:
      - prometheus
    volumes:
      - ./samples/Login.js:/Login.js
      - ./samples/users.json:/users.json
      - ./screenshots/:/screenshots/
      - ./certs/fullychained.crt:/fullychained.crt
      - ./certs/rootca.crt:/rootca.crt
    command: run /Login.js --tag testid=logintest


And the code:


import { check, sleep } from 'k6';
import { chromium } from 'k6/x/browser';
import { SharedArray } from 'k6/data';
import { vu } from 'k6/execution';

const usersData = new SharedArray('users', function () {
  return JSON.parse(open('./users.json')).users;
});

export const options = {  
  httpDebug: 'full',
  scenarios: {
    login: {
      executor: 'per-vu-iterations',
      vus: 1,
      iterations: 1,
      maxDuration: '1h30m',
    },
  },  
};

export default function () {

  const browser = chromium.launch({ headless: true, debug: true  });
  const context = browser.newContext();

	const page = context.newPage();

 page.goto('https://mywebapp.company.local ', { waitUntil: 'networkidle' });
 page.screenshot({path: '/screenshots/01_screenshot.jpg'});

}

When I open up the docker terminal and CURL to the URI, it does a successful certificate handshake

If anyone has any pointers or solutions, I would be most grateful. Thanks!

Hi,

Managed to get it working. For anyone else that has this issue, make your dockerfile look like this so as to add the certificate to chromium cert storage:

FROM golang:1.19-bullseye as builder

RUN go install -trimpath go.k6.io/xk6/cmd/xk6@latest

RUN  xk6 build --output "/tmp/k6" --with github.com/grafana/xk6-browser@main 

FROM debian:bullseye

RUN apt-get update && \
    apt-get install -y chromium &&\
    apt install -y libnss3-tools curl &&\
    apt-get install -y ca-certificates

COPY ./certs/myroot.crt /usr/local/share/ca-certificates/myroot.crt
COPY ./certs/myroot.crt /usr/local/share/ca-certificates/myroot.pem
RUN chmod 644 /usr/local/share/ca-certificates/myroot.crt && \
    update-ca-certificates

RUN mkdir -p $HOME/.pki/nssdb
RUN certutil -d $HOME/.pki/nssdb -N --empty-password
RUN certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n myroot -i /usr/local/share/ca-certificates/myroot.pem

COPY --from=builder /tmp/k6 /usr/bin/k6

ENV XK6_HEADLESS=true

ENTRYPOINT ["k6"]

Many thanks for the amazing tool your guys are working on here!

1 Like

Hi @ArielK ,

Apologies I get a bit late, but I’m glad you got it working! It’s useful for us too!
Thank you very much for the compliments! And don’t hesitate to reach back to us if you encounter any problems.

Regards.

1 Like