grafana/k6 · error

encrypted pkcs8 formatted key is not supported

Error message

encrypted pkcs8 formatted key is not supported

What it means

k6's encrypted-key decryption uses the legacy x509.DecryptPEMBlock API, which only understands traditional OpenSSL PEM encryption. Keys with block type 'ENCRYPTED PRIVATE KEY' (PKCS#8, e.g. PBES2 output of openssl pkcs8 -topk8 / genpkey with a passphrase) are explicitly rejected before decryption is attempted.

Source

Thrown at internal/js/modules/k6/grpc/client.go:133

	fdset := &descriptorpb.FileDescriptorSet{}
	if err = proto.Unmarshal(fdsetBytes, fdset); err != nil {
		return nil, fmt.Errorf("couldn't unmarshal protoset file %s: %w", protosetPath, err)
	}

	return c.convertToMethodInfo(fdset)
}

// Note: this function was lifted from `lib/options.go`
func decryptPrivateKey(key, password []byte) ([]byte, error) {
	block, _ := pem.Decode(key)
	if block == nil {
		return nil, errors.New("failed to decode PEM key")
	}

	blockType := block.Type
	if blockType == "ENCRYPTED PRIVATE KEY" {
		return nil, errors.New("encrypted pkcs8 formatted key is not supported")
	}
	/*
	   Even though `DecryptPEMBlock` has been deprecated since 1.16.x it is still
	   being used here because it is deprecated due to it not supporting *good* cryptography
	   ultimately though we want to support something so we will be using it for now.
	*/
	decryptedKey, err := x509.DecryptPEMBlock(block, password) //nolint:staticcheck
	if err != nil {
		return nil, err
	}
	key = pem.EncodeToMemory(&pem.Block{
		Type:  blockType,
		Bytes: decryptedKey,
	})
	return key, nil
}

func buildTLSConfig(parentConfig *tls.Config, certificate, key []byte, caCertificates [][]byte) (*tls.Config, error) {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Decrypt to an unencrypted key: openssl pkcs8 -in key.enc.pem -nodes -out key.pem
  2. Or convert to traditional RSA PEM encryption: openssl rsa -in key.enc.pem -aes256 -out key.trad.pem (then pass the new password)
  3. Long-term: track the upstream k6 issue for PKCS#8 support instead of working around per script

Example fix

# before: key has '-----BEGIN ENCRYPTED PRIVATE KEY-----'
# after: produce a supported format
openssl pkcs8 -in key.enc.pem -nodes -out key.pem
# then connect without a password for that cert pair:
client.connect(addr, { tls: { certs: [[certPem, keyPem]] } });
Defensive patterns

Strategy: validation

Validate before calling

function isEncryptedPkcs8(pem) {
  return pem.trim().startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----');
}

if (isEncryptedPkcs8(keyPem)) {
  throw new Error('k6 does not support encrypted PKCS#8 keys; convert with: openssl pkcs8 -in key.pem -nodes -out key-decrypted.pem');
}

Prevention

When it happens

Trigger: client.connect(addr, { tls: { certs: [[cert, key, password]] } }) where key is an encrypted PKCS#8 file (header -----BEGIN ENCRYPTED PRIVATE KEY-----).

Common situations: Keys provisioned by modern openssl defaults (genpkey + pkcs8 -topk8), cloud KMS exports, or company PKI tooling that standardizes on PKCS#8 encryption.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/d88664efcaa44fa4. Report an issue: GitHub.