Install with Docker
In this section, you will deploy the Securosys Key Manager as Docker container. This guide uses Docker Compose, which is useful for local test deployments.
To install the Key Manager UI on Kubernetes follow the Kubernetes guide.
Step 1: Define the Service with Docker Compose
Configure Secrets
Create a .env file in a clean directory to store the configuration variables for the
TSB REST API and its database.
This file will be automatically loaded by Docker Compose.
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password
DB_ROOT_PASSWORD=your_db_root_password
HSM_HOST=ch01-api.cloudshsm.com,ch02-api.cloudshsm.com
HSM_PORT=2300
HSM_USERNAME=your_hsm_username
HSM_SETUP_PASSWORD=your_hsm_setup_password
HSM_PROXY_USERNAME=your_hsm_proxy_username
HSM_PROXY_PASSWORD=your_hsm_proxy_password
HSM_ENCRYPTION_PASSWORD=your_encryption_password
Replace all placeholder values with your actual credentials.
The .env file configures the TSB REST API and its database - not the Key Manager UI itself.
The Key Manager UI is configured through secrets.toml (see Configuration).
Define the Containers
Create a docker-compose.yml file to define the containers that you will launch:
networks:
application-bridge:
driver: bridge
services:
kms_database:
container_name: kms_database
# uncomment mariadb:10.4 when working on Unix environment, uncomment mysql:8.0 when working with Windows Docker Desktop
image: mysql:8.0
#image: mariadb:11.8
restart: unless-stopped
ports:
- "3306:3306"
volumes:
- ./kms_database/mysql-lib:/var/lib/mysql
networks:
- application-bridge
environment:
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
- MYSQL_DATABASE=securosys_rest_api
- MYSQL_PORT=3306
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_LOWER_CASE_TABLE_NAMES=0
kms_rest_api:
hostname: tsb-rest-api
image: securosys.jfrog.io/external-tsb/securosys-tsb:latest
container_name: kms_rest_api
restart: unless-stopped
depends_on:
- kms_database
networks:
- application-bridge
ports:
- "8080:8080"
#volumes:
#- ./config-files:/etc/app/config
#- ./output:/etc/app/output
environment:
- logging.config=
- spring.datasource.url=jdbc:mariadb://kms_database:3306/securosys_rest_api?allowPublicKeyRetrieval=true&sslMode=false
- spring.datasource.username=${DB_USERNAME}
- spring.datasource.password=${DB_PASSWORD}
- hsm.host=${HSM_HOST}
- hsm.port=${HSM_PORT}
- hsm.user=${HSM_USERNAME}
- hsm.setupPassword=${HSM_SETUP_PASSWORD}
- hsm.encryptionPassword=${HSM_ENCRYPTION_PASSWORD}
- hsm.attestationKeyName=attestation-key
- hsm.timestampKeyName=timestamp-key
- hsm.proxyUser=${HSM_PROXY_USERNAME}
- hsm.proxyPassword=${HSM_PROXY_PASSWORD}
kms_ui:
container_name: kms_ui # Explicit container name
image: securosys.jfrog.io/kms/securosys-kms:latest # Pull the prebuilt image from the Securosys registry
ports:
- "8501:8501" # Map host port 8501 -> container port 8501 (default)
depends_on:
- kms_rest_api
restart: unless-stopped
networks:
- application-bridge
volumes:
- ./secrets.toml:/app/.streamlit/secrets.toml:ro
#- ./tls.crt:/app/.streamlit/tls.crt:ro
#- ./tls.key:/app/.streamlit/tls.key:ro
#- ./config.toml:/app/.streamlit/config.toml:ro
Configure Key Manager (UI) Secrets
Create a secrets.toml file to configure the Key Manager.
You will learn how to fill out this file in the next step.
secrets.toml
# ======================================================================
# Securosys KMS - Configuration Reference
# Copy this file to .streamlit/secrets.toml and adjust values.
# Sensitive values (tokens, client secrets) must be kept private.
# ======================================================================
# =====================================================================
# 1. AUTHENTICATION
# =====================================================================
# Controls how users log into the application.
#
# "" No authentication (open access - NOT recommended)
# "hsm_auth" Local users stored on the HSM partition (password + optional 2FA)
# "oauth" External OAuth providers (Microsoft Entra ID and/or GitHub)
#
# Combining providers: provider = "oauth" enables all configured
# [oauth.*] sections below. provider = "hsm_auth" ignores them.
# =====================================================================
[authentication]
provider = "hsm_auth" # REQUIRED - set to "hsm_auth" or "oauth"
# =====================================================================
# 2. HSM REST-API (Transaction Security Broker)
# =====================================================================
# Connection to the Securosys REST API (Primus HSM / CloudsHSM).
#
# WHEN IS THIS REQUIRED?
# • Always required when multi-tenancy is NOT configured
# • Always required when authentication.provider = "hsm_auth"
# (user objects are stored as HSM data objects on this partition)
# • Required when multi_tenancy.vault_type = "hsm"
# (partition credentials are read from this management partition)
# • NOT required when multi_tenancy.vault_type = "azure_key_vault"
# or "gcp_secret_manager" (credentials come from the external vault)
# =====================================================================
[tsb]
api_url = "http://tsb-rest-api:8080/" # Base URL, e.g. "https://sbx-rest-api.cloudshsm.com/v1"
access_token = "" # Bearer JWT token (leave empty if not required)
# --- Mutual TLS (optional) -------------------------------------------
# Configure if the REST-API is set to mTLS = "need".
# Both client_key_path and client_certificate_path must be provided together.
# -----------------------------------------------------------------------
[tsb.mtls]
#client_key_path = "./mtls/client.key" # Client private key
#client_certificate_path = "./mtls/client.crt" # Client certificate
#verify_ca_certificate = true # Verify server certificate (recommended)
#ca_certificate_path = "./mtls/server.crt" # CA / server cert path - omit if signed by a public CA
# =====================================================================
# 3. GENERAL
# =====================================================================
[general]
tsb_request_timeout = 10 # HTTP request timeout in seconds
logo = "" # Path to custom logo (e.g. "static/my_logo.png")
# =====================================================================
# 4. TWO-FACTOR AUTHENTICATION (TOTP)
# =====================================================================
# Application-level 2FA using TOTP (Google Authenticator, Authy, etc.).
# TOTP secrets are stored in the per-user HSM data object.
#
# NOTE: When using OAuth providers (Microsoft Entra / GitHub), the
# provider typically enforces its own MFA - this section is not needed.
# =====================================================================
[two_factor]
enabled = false # Enable 2FA globally
required = false # Force all users to enroll before accessing the app
# =====================================================================
# 5. MULTI-TENANCY (optional)
# =====================================================================
# Allows users to work with multiple HSM partitions / instances.
# Partition credentials are resolved at login from the configured vault.
#
# For OAuth: partitions are mapped from the token's "roles" claim.
# For hsm_auth: partitions are configured per-user in the Security tab.
#
# vault_type determines where partition credentials are stored:
#
# "hsm" - HSM Data Objects on the [tsb] management partition
# (objects named KMS-PARTITION-{role})
# "azure_key_vault" - Azure Key Vault secrets (one per role)
# "gcp_secret_manager" - Google Cloud Secret Manager secrets
#
# Each secret/object contains a JSON payload:
# {
# "api_url": "https://...",
# "access_token": "eyJ...",
# "display_name": "Production", ← shown in sidebar & top-bar
# "color": "#e30613" ← optional hex color for top-bar indicator
# }
# =====================================================================
# --- Option A: HSM-based partition store ------------------------------
# Requires [tsb] to be configured (management partition).
#[multi_tenancy]
#vault_type = "hsm"
# --- Option B: Azure Key Vault ----------------------------------------
# [tsb] section is NOT required with this vault type.
#[multi_tenancy]
#vault_type = "azure_key_vault"
#vault_url = "https://my-vault.vault.azure.net/"
#tenant_id = "00000000-0000-0000-0000-000000000000"
#client_id = "00000000-0000-0000-0000-000000000000"
#client_secret = ""
# --- Option C: Google Cloud Secret Manager ----------------------------
# [tsb] section is NOT required with this vault type.
#[multi_tenancy]
#vault_type = "gcp_secret_manager"
#project_id = "my-gcp-project"
#credentials_file = "" # Optional - uses Application Default Credentials if omitted
#secret_prefix = "" # Optional prefix prepended to role names
# =====================================================================
# 6. OAUTH PROVIDERS (when authentication.provider = "oauth")
# =====================================================================
# Configure one or both. Each configured section adds a login button.
# --- KeyCloak --------------------------------------------------------
#[oauth.keycloak]
#server_url = "https://dev-sso.securosys.com" # Base URL (no trailing slash)
#realm = "securosys"
#client_id = "kms-app"
#client_secret = "your-client-secret"
#redirect_uri = "http://localhost:8501" # Must match Keycloak exactly
#scope = "openid profile email"
#allowed_role = "" # Optional: restrict to a specific role
#button_text = "Login with Keycloak" # Optional: customize button label
# --- Microsoft Entra ID / Azure AD ------------------------------------
#[oauth.microsoft]
#client_id = "00000000-0000-0000-0000-000000000000"
#client_secret = ""
#redirect_uri = "http://localhost:8501"
#scope = "openid profile email"
#tenant_id = "00000000-0000-0000-0000-000000000000"
#allowed_group_id = "" # Optional - restrict to an Azure AD group
# --- GitHub -----------------------------------------------------------
#[oauth.github]
#client_id = ""
#client_secret = ""
#redirect_uri = "http://localhost:8501"
#scope = "read:user read:org"
#allowed_organization = "" # Optional - restrict to a GitHub organization
# =====================================================================
# 7. AI / MCP INTEGRATION (optional)
# =====================================================================
# Enables the "Chat" tab with an AI assistant connected to the HSM
# via the Model Context Protocol (MCP).
#
# [mcp] — General settings (MCP server URL)
# [mcp.<name>] — One sub-table per AI provider. Configure one or more.
# The user can switch between them at runtime in the Chat tab.
#
# Supported provider types:
# "anthropic" — Anthropic Claude (claude-sonnet-4-20250514, claude-opus-4-20250514, …)
# "openai" — OpenAI GPT (gpt-4o, gpt-4-turbo, o3, …)
# "gemini" — Google Gemini (gemini-2.5-pro, gemini-2.0-flash, …)
# "local" — Any OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, …)
#
# Each provider sub-table requires:
# provider — provider type (see above)
# model — model identifier
# api_key — API key (can be empty for "local")
# label — (optional) display name shown in the provider switcher
# base_url — (optional) custom endpoint URL (for "local" / custom "openai")
#
# The first configured provider is selected by default.
#[mcp]
#url = "https://mcp-hsm-server.securosys.com/sse" # MCP server endpoint URL
#[mcp.claude]
#provider = "anthropic"
#label = "Claude Opus"
#model = "claude-opus-4-20250514"
#api_key = "sk-..."
#[mcp.gpt]
#provider = "openai"
#label = "GPT-4o"
#model = "gpt-4o"
#api_key = "sk-..."
#[mcp.gemini]
#provider = "gemini"
#label = "Gemini 2.5 Pro"
#model = "gemini-2.5-pro"
#api_key = "AIza..."
#[mcp.ollama]
#provider = "local"
#label = "Ollama (local) - not setup"
#model = "llama3"
#api_key = ""
#base_url = "http://localhost:11434/v1"
# =====================================================================
# 8. AUDIT LOGGING (optional)
# =====================================================================
#[audit]
#log_dir = "logs" # Directory for audit JSONL logs (default: "logs")
# =====================================================================
# 9. DEMO MODE (optional — enable to restrict LLM chat usage)
# =====================================================================
# When enabled, each user is limited to a fixed number of LLM messages
# within a rolling time window. Remove or comment out to disable.
#[demo]
#max_llm_messages = 3 # Max messages per user per time window
#time_window_minutes = 60 # Rolling window in minutes (default: 60)
Step 2: Download the Docker image
Log in to the Securosys container registry:
docker login securosys.jfrog.io -u robot.reader
You will be prompted for a password. You can find the password in the Downloads section.
Then download the Docker images:
docker pull securosys.jfrog.io/kms/securosys-kms:latest
docker pull securosys.jfrog.io/external-tsb/securosys-tsb:latest
Step 3: Run the Docker container
Start the application by running:
docker compose up --detach
Open a browser and access the Key Manager UI: http://localhost:8501
First-Time Setup
On first launch, the Key Manager UI will prompt you to create your initial administrator account.
- Enter a username, email, and password (minimum 8 characters, must include uppercase, lowercase, and digits).
- This account will be assigned the admin role automatically.
- Additional users can be created later from the Security Settings page.
This bootstrap step only appears once - on the very first launch when no users exist. If you are using OAuth authentication (Microsoft Entra ID, GitHub, Keycloak), users are managed by the identity provider and this step does not apply.
Troubleshooting
If the container fails to start, check that it is running with docker ps -a
and inspect the logs to see what the root cause is:
docker logs kms_ui
docker logs kms_rest_api
Conclusion
Congratulations! You have finished the basic setup of the Securosys Key Manager. You can now start managing HSM Keys and their lifecycle or create a Certificate Authority directly in your browser.
Next Steps
- Customize the Key Manager UI
- Configure TLS (HTTPS)
- Configure User Authentication (Frontend)
- Configure Multi-Tenancy
- Configure mTLS with TSB (Backend)
- Configure AI Chat Assistant (MCP)
- Configure Audit Logging
- Setting a health checks for Key Manager UI.