From b6cf450e97f0dad2a645d1c4b01602348748fcc1 Mon Sep 17 00:00:00 2001 From: "ugo.bechameil" Date: Tue, 4 Aug 2026 22:35:49 +0200 Subject: [PATCH] feat(compose): add hardened compose example for read-only rootfs (HCK-17257) Keep compose.yml as the simple getting-started example and add compose.hardened.yml with read-only rootfs, dropped capabilities, /data volume, and /tmp tmpfs for Kubernetes Restricted parity. Co-authored-by: Cursor --- Studio/compose.hardened.yml | 93 +++++++++++++++++++++++++++++++++++++ Studio/compose.yml | 68 ++++++++------------------- 2 files changed, 113 insertions(+), 48 deletions(-) create mode 100644 Studio/compose.hardened.yml diff --git a/Studio/compose.hardened.yml b/Studio/compose.hardened.yml new file mode 100644 index 0000000..63f395d --- /dev/null +++ b/Studio/compose.hardened.yml @@ -0,0 +1,93 @@ +# +# Copyright © 2016-2026 by IntegrIT S.A. dba Hackolade. All rights reserved. +# +# The copyright to the computer software herein is the property of IntegrIT S.A. +# The software may be used and/or copied only with the written permission of +# IntegrIT S.A. or in accordance with the terms and conditions stipulated in +# the agreement/contract under which the software has been supplied. +# + +# Hardened Docker Compose example for hackolade/hck-cli. +# +# Matches how the image runs under the Kubernetes Restricted Pod Security Standard +# and OpenShift restricted-v2 SCC: +# +# - read-only root filesystem +# - all capabilities dropped, no privilege escalation +# - non-root user (1000:1001 by default) +# - exactly two writable mounts: +# /data persistent volume — license state, logs, models, output, settings +# /tmp tmpfs — sockets, caches, scratch (discarded when the container exits) +# +# Usage: +# docker compose -f compose.hardened.yml run --rm hck-cli version +# +# For local development without these constraints, use compose.yml instead. +# For Kubernetes manifests with a PVC, see k8s/hck-cli-job.yaml. +# Documentation: doc/getting-started-hck-cli.md + +services: + hck-cli: &hck-cli + init: true + image: hackolade/hck-cli:8.9.2 + command: ["version"] + restart: 'no' + read_only: true + user: "1000:1001" + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + volumes: + - hackolade-studio-data:/data + - ${PWD}/models:/data/models + tmpfs: + - /tmp:rw,size=1g,mode=1777 + + showComputerIdForOfflineValidation: + extends: hck-cli + command: ["getComputerId"] + + validateKeyOffline: + extends: hck-cli + network_mode: 'none' + command: ["validateKey"] + secrets: + - license_file + + validateKeyOnline: + extends: hck-cli + command: ["validateKey"] + network_mode: host + secrets: + - license_key + + # Smoke test: run a command that starts Electron and writes output, not just the CLI wrapper. + genDoc: + extends: hck-cli + command: ["genDoc", "--model=/data/models/smoke.hck.json", "--doc=/data/output/smoke.pdf"] + + # OpenShift restricted-v2 assigns an arbitrary UID in the root supplementary group. + # Proves nss_wrapper and group-0 ownership of /data work without a passwd entry. + hck-cli-arbitrary-uid: + <<: *hck-cli + user: "31337:0" + + # Trust a private CA with a read-only PEM mount — no root step required. + # See doc/custom-certificates.md. + # runWithCustomCertificates: + # extends: hck-cli + # environment: + # NODE_EXTRA_CA_CERTS: /certs/internal-ca.crt + # SSL_CERT_FILE: /certs/internal-ca.crt + # volumes: + # - ./certificates/internal-ca.crt:/certs/internal-ca.crt:ro + +volumes: + hackolade-studio-data: + +secrets: + license_key: + file: ${HOME}/Downloads/license-key.txt + license_file: + file: ${HOME}/Downloads/LicenseFile.xml diff --git a/Studio/compose.yml b/Studio/compose.yml index d307501..076a730 100644 --- a/Studio/compose.yml +++ b/Studio/compose.yml @@ -7,41 +7,36 @@ # the agreement/contract under which the software has been supplied. # -# This file is an example of how to orchestrate the Hackolade CLI from a docker compose file -# leveraging our hck-cli docker image from Docker Hub -# This image contains the Hackolade Studio Release and all of the plugins already installed -# It's ready to be used. +# Example Docker Compose file for the pre-built hackolade/hck-cli image from Docker Hub. +# The image includes Hackolade Studio and all plugins — ready to use without a build step. # -# This compose.yml file is specifically designed for the pre-built hackolade/hck-cli image. # For complete documentation and usage instructions, see: doc/getting-started-hck-cli.md # -# If you are building your own image using hackolade/studio, use docker-compose.yml instead, -# which is designed for custom-built images. See doc/getting-started.md for building instructions. +# If you are building your own image using hackolade/studio, use docker-compose.yml instead. +# See doc/getting-started.md for building instructions. +# +# For Kubernetes Restricted / OpenShift restricted-v2 parity (read-only root filesystem, +# dropped capabilities, /data volume + /tmp tmpfs), use compose.hardened.yml instead. services: - # Run a cli command (default to version) - # Pay attention to file paths as they must be paths inside the containers - # If a file needs to be made available from the host or another container, use the volumes section to mount the file or folders - # This compose exposes different manners to provide the License key or LicenseFile.xml for offline validation - - # Example using online License key validation and the key stored in a secret file (file path from host) defined in the secrets section: + # Run a CLI command (defaults to version). + # Paths below are inside the container. Mount host files or folders through volumes. # - # docker compose run -t --rm validateKeyOnline - # docker compose run -t --rm hck-cli gendoc --format=HTML --model '/data/models/MongoDB/Yelp Challenge dataset.hck.json' --doc /data/output/doc-test --jsonSchema + # Examples: + # docker compose run -t --rm validateKeyOnline + # docker compose run -t --rm hck-cli genDoc --format=HTML \ + # --model '/data/models/MongoDB/Yelp Challenge dataset.hck.json' \ + # --doc /data/output/doc-test --jsonSchema hck-cli: &hck-cli image: hackolade/hck-cli:8.9.2 command: ["version"] restart: 'no' # network_mode: 'none' volumes: - - hackolade-studio-app-data:/home/hackolade/.config - - hackolade-studio-logs:/data/logs + # Mandatory: license state, logs, output, settings, and options live under /data. + - hackolade-studio-data:/data + # Models from the host; remove this line to keep models on the named volume instead. - ${PWD}/models:/data/models - # - hackolade-studio-options:/data/options - - hackolade-studio-output:/data/output - secrets: - - license_file - - license_key showComputerIdForOfflineValidation: extends: hck-cli @@ -66,7 +61,6 @@ services: # volumes: # - $HOME/Downloads/license-key.txt:/data/license-key.txt - validateKeyOffline: extends: hck-cli network_mode: 'none' @@ -81,34 +75,12 @@ services: secrets: - license_key - installCustomCertificates: - image: hackolade/hck-cli:8.9.2 - entrypoint: [ "bash", "-c" ] - command: ['update-ca-certificates'] - restart: 'no' - # calling update-ca-certificates can only be done by root and will generate - # a new ca-certificates.crt file that will bundle all installed certificates - # in /etc/ssl/certs - user: root - volumes: - - installed-tls-certificates:/etc/ssl/certs - # - ./custom-certificate.crt:/etc/ssl/certs/custom-certificate.crt - # Bind or inject any other custom certificate into /etc/ssl/certs but without overriding everything! - volumes: - # This docker volume is mandatory if you want the licensing to work and be able to use the cli - hackolade-studio-app-data: - hackolade-studio-logs: - # This compose mounts the models folder from the host - # hackolade-studio-models: - # hackolade-studio-options: - hackolade-studio-output: - installed-tls-certificates: + # Required for licensing and persistent CLI state. + hackolade-studio-data: -secrets: # Don't change the name of the secrets as the cli is looking for them by name with these values by default +secrets: # Don't change the secret names — the CLI looks them up by these values. license_key: - # Expects the license key to be put as content of the file path defined in the file variable file: ${HOME}/Downloads/license-key.txt license_file: - # Expects the license file to be put as content of the file path defined in the file variable file: ${HOME}/Downloads/LicenseFile.xml