Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 102 additions & 97 deletions Studio/doc/custom-certificates.md
Original file line number Diff line number Diff line change
@@ -1,147 +1,152 @@
# Installing Custom TLS Certificates in Containers

When working with Hackolade CLI in Docker containers, you may need to install custom TLS certificates to establish secure connections to internal services or systems that use self-signed certificates or certificates from private Certificate Authorities (CAs).
When working with Hackolade CLI in Docker containers, you may need to trust custom TLS certificates to establish secure connections to internal services or systems that use self-signed certificates or certificates from private Certificate Authorities (CAs).

## Overview

The `compose.yml` file includes an `installCustomCertificates` service that bundles custom certificates into a Docker volume. Mount this volume (or extract the bundled `ca-certificates.crt` file) into any service where you want to run `hck-cli` commands that need to trust these certificates.
Trusting a private CA is a read-only operation: mount the certificate into the container and point the runtime at it with an environment variable. There is no installation step, nothing runs as root, and nothing is written to the container filesystem — which is what makes this work with `read_only: true` and with a Kubernetes `readOnlyRootFilesystem` security context.

## Quick Start
Two environment variables cover everything the CLI does:

### Step 1: Configure and Run Certificate Installation
| Variable | Used by | Notes |
| --- | --- | --- |
| `NODE_EXTRA_CA_CERTS` | Hackolade Studio and the CLI (Node/Electron) | Additive: your CA is trusted **in addition to** the public roots bundled with the image |
| `SSL_CERT_FILE` | Tools that link OpenSSL directly, such as `git` over HTTPS | Replacing: the file you point at becomes the complete trust store |

1. **Prepare your certificate files** in a directory (e.g., `./certificates/`)
Because `SSL_CERT_FILE` replaces rather than extends the trust store, point it at a bundle that contains both your CA and the public roots when the container also has to reach public endpoints — for example license validation against Hackolade's servers. Building that bundle is a one-liner and is covered below.

2. **Update `compose.yml`** to bind mount your certificates into the `installCustomCertificates` service:
> Earlier versions of this guide used an `installCustomCertificates` service that ran `update-ca-certificates` as root against a shared volume. That approach is no longer needed, and no longer works with a read-only root filesystem. Remove the service and the `installed-tls-certificates` volume when you migrate.

```yaml
installCustomCertificates:
image: hackolade/hck-cli:8.9.2
entrypoint: [ "bash", "-c" ]
command: ['update-ca-certificates']
restart: 'no'
user: root
volumes:
- installed-tls-certificates:/etc/ssl/certs
# Bind mount your custom certificate(s) into /etc/ssl/certs
- ./certificates/custom-certificate.crt:/etc/ssl/certs/custom-certificate.crt:ro
# Add more certificates as needed
```
## Quick start

**Important:** Mount individual certificate files (not the entire directory) with unique filenames.
### 1. Put your certificate somewhere the container can read

3. **Run the installation**:
Use PEM format — the file starts with `-----BEGIN CERTIFICATE-----`. A single file may contain a chain.

```bash
docker compose run --rm installCustomCertificates
```
./certificates/internal-ca.crt
```

### Step 2: Use Certificates in hck-cli Services

You have two options:

#### Option A: Mount the Volume (Recommended)

Mount the `installed-tls-certificates` volume in your service:
### 2. Mount it read-only and set the variable

```yaml
services:
hck-cli:
image: hackolade/hck-cli:8.9.2
command: ["version"]
read_only: true
user: "1000:1001"
environment:
NODE_EXTRA_CA_CERTS: /certs/internal-ca.crt
volumes:
- hackolade-studio-app-data:/home/hackolade/.config
- hackolade-studio-logs:/data/logs
- ${PWD}/models:/data/models
- hackolade-studio-output:/data/output
- installed-tls-certificates:/etc/ssl/certs:ro # Add this line
- hackolade-studio-data:/data
- ./certificates/internal-ca.crt:/certs/internal-ca.crt:ro
tmpfs:
- /tmp:rw,size=1g,mode=1777

volumes:
hackolade-studio-data:
```

That is the whole configuration. Run any command as usual:

```bash
docker compose run --rm hck-cli genDoc --format=HTML --model '/data/models/model.hck.json' --doc /data/output/doc
```

#### Option B: Bind Mount Only ca-certificates.crt
### 3. Add `SSL_CERT_FILE` only if you need it

Extract the bundled certificate file and bind mount it:
Reverse-engineering connectors and Git integration that use OpenSSL rather than Node's TLS stack read `SSL_CERT_FILE`. Since it replaces the trust store, build a bundle that also carries the public roots:

1. **Extract the file**:
```bash
docker run --rm \
-v installed-tls-certificates:/source:ro \
-v ${PWD}/certificates:/output \
--entrypoint cp \
hackolade/hck-cli:8.9.2 \
/source/ca-certificates.crt /output/ca-certificates.crt
mkdir -p certificates
docker run --rm --entrypoint cat hackolade/hck-cli:8.9.2 \
/etc/ssl/certs/ca-certificates.crt > certificates/ca-bundle.crt
cat certificates/internal-ca.crt >> certificates/ca-bundle.crt
```

2. **Bind mount it** in your service:
Then mount the bundle and point both variables at it:

```yaml
services:
hck-cli:
image: hackolade/hck-cli:8.9.2
environment:
NODE_EXTRA_CA_CERTS: /certs/ca-bundle.crt
SSL_CERT_FILE: /certs/ca-bundle.crt
volumes:
- hackolade-studio-app-data:/home/hackolade/.config
- hackolade-studio-logs:/data/logs
- ${PWD}/models:/data/models
- hackolade-studio-output:/data/output
- ./certificates/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro # Add this line
- ./certificates/ca-bundle.crt:/certs/ca-bundle.crt:ro
```

## Complete Example
Regenerate the bundle whenever you upgrade the image, so it keeps the public roots that version ships with.

```yaml
services:
installCustomCertificates:
image: hackolade/hck-cli:8.9.2
entrypoint: [ "bash", "-c" ]
command: ['update-ca-certificates']
restart: 'no'
user: root
volumes:
- installed-tls-certificates:/etc/ssl/certs
- ./certificates/internal-ca.crt:/etc/ssl/certs/internal-ca.crt:ro
## Kubernetes

hck-cli:
image: hackolade/hck-cli:8.9.2
command: ["version"]
restart: 'no'
volumes:
- hackolade-studio-app-data:/home/hackolade/.config
- hackolade-studio-logs:/data/logs
- ${PWD}/models:/data/models
- hackolade-studio-output:/data/output
- installed-tls-certificates:/etc/ssl/certs:ro
Mount the CA from a `ConfigMap` or `Secret` and set the variable. No init container and no privileged step:

volumes:
hackolade-studio-app-data:
hackolade-studio-logs:
hackolade-studio-output:
installed-tls-certificates:
```yaml
spec:
containers:
- name: hck-cli
image: hackolade/hck-cli:8.9.2
env:
- name: NODE_EXTRA_CA_CERTS
value: /certs/internal-ca.crt
volumeMounts:
- name: custom-ca
mountPath: /certs
readOnly: true
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities: { drop: ["ALL"] }
volumes:
- name: custom-ca
configMap:
name: internal-ca
```

**Usage:**
Create the ConfigMap from your PEM file:

```bash
# Install certificates (run once)
docker compose run --rm installCustomCertificates
kubectl create configmap internal-ca --from-file=internal-ca.crt=./certificates/internal-ca.crt
```

# Run hck-cli commands
docker compose run --rm hck-cli genDoc --format=HTML --model '/data/models/model.hck.json' --doc /data/output/doc
## Behind an intercepting proxy

When traffic is intercepted (a corporate proxy, mitmproxy, Zscaler), you need the proxy's CA in addition to the proxy variables:

```yaml
environment:
HTTPS_PROXY: http://proxy.internal:8080
HTTP_PROXY: http://proxy.internal:8080
NO_PROXY: localhost,127.0.0.1
NODE_EXTRA_CA_CERTS: /certs/proxy-ca.crt
volumes:
- ./certificates/proxy-ca.crt:/certs/proxy-ca.crt:ro
```

## Updating Certificates
Online license validation goes through the same stack, so `validateKey` is a good way to confirm the CA is being picked up.

1. Add or replace certificate files in your certificates directory
2. Update the `installCustomCertificates` service in `compose.yml` to include new certificate bind mounts
3. Re-run: `docker compose run --rm installCustomCertificates`
## Updating certificates

**If using Option B (bind mount):** After re-running, extract the updated `ca-certificates.crt` file again using the extraction command from Step 2.
Replace the PEM file on the host and restart the container. There is no cached copy inside the image and nothing to reinstall.

## Troubleshooting

**Certificates not trusted:**
- Verify the volume/file is mounted: `docker compose run --rm hck-cli ls -la /etc/ssl/certs/ca-certificates.crt`
- Re-run the installation: `docker compose run --rm installCustomCertificates`
**Certificate not trusted**

- Confirm the mount arrived and the path matches the variable:
```bash
docker compose run --rm --entrypoint sh hck-cli -c 'ls -l "$NODE_EXTRA_CA_CERTS"'
```
- Confirm the file is PEM, not DER. A DER file is binary; convert it with
`openssl x509 -inform der -in cert.cer -out cert.crt`.
- If only some operations fail, the failing one is likely using OpenSSL rather than Node. Add `SSL_CERT_FILE` as described above.

**Public endpoints stopped working after setting `SSL_CERT_FILE`**

**Certificate format:**
- Use PEM format (files should start with `-----BEGIN CERTIFICATE-----`)
- Each file should contain a single certificate (not a chain)
You pointed it at a file containing only your private CA, which replaced the public roots. Rebuild the bundle so it contains both.

## Related Documentation
## Related documentation

- [Getting Started with hck-cli](./getting-started-hck-cli.md) - Main guide for using the Hackolade CLI Docker image