Customizing your Testkube On-Prem Installation
A variety of advanced topics to further customize your Testkube On Prem deployment.
See Components for a list of all included components and links to their corresponding Helm Charts with a list of their available properties.
Master Password for Encryption
Testkube requires a master password to enable encrypted Credential storage and to sign the tokens that allow runners to securely retrieve credentials during workflow execution.
Without a master password configured:
- Only plaintext Variable credentials can be created — encrypted Secret credentials will be rejected.
- Workflow executions that use credentials will fail because the runner cannot obtain a valid execution token.
The master password cannot be recovered. If it is lost, all previously encrypted secrets will become unreadable and will need to be recreated. Store it securely.
What the master password protects
In on-premise setups, the master password became a hard requirement for credentials and runner execution flows starting with v1.13.0, when execution-token based runner authentication was introduced.
It is used in multiple control-plane paths, not just secret storage:
- Deriving encryption keys for Secret credential values
- Creating and validating Agent secret keys for Runner and GitOps agent authentication
- Signing execution tokens that runners use during workflow execution
All of these use the same runtime secret value:
- Environment variable:
CREDENTIALS_MASTER_PASSWORD - Helm values:
global.credentials.masterPassword.secretKeyRef(recommended)global.credentials.masterPassword.value(not recommended for production)
If you see the following log message:
cannot fetch agent ... error="missing master password for secret keys"
the control plane attempted to create or read agent secret-key crypto state without the password being set.
Configuring the Master Password
The recommended approach is to store the master password in a Kubernetes Secret and reference it in your Helm values.
First, create the secret (the password must be at least 32 characters):
kubectl create secret generic testkube-master-password \
--from-literal=password=$(openssl rand -base64 48) \
-n testkube
Then reference it in your values.yaml:
global:
credentials:
masterPassword:
secretKeyRef:
name: testkube-master-password
key: password
Alternatively, you can set the password directly in your Helm values using global.credentials.masterPassword.value,
but this is not recommended for production environments.
global:
credentials:
masterPassword:
value: "<your-strong-password>"
Storage and recovery considerations
masterPassword is not stored in a database as a plain field that can be inspected. It is a runtime secret used to
derive crypto material, and without it existing encrypted records cannot be decrypted.
For on-prem, this is a critical operational dependency:
- Never rotate it casually
- If it is lost, encrypted secrets must be recreated and agent secrets reissued
POST /organizations/<organizationId>/agents/<agentIdOrName>/regenerate regenerates an agent secret key for
affected agents.
Disabling Credentials
You can turn off the built-in credentials feature entirely, or disable just the encrypted (Secret) backend if you manage secrets through an external tool such as HashiCorp Vault.
Disable All Credentials
Turns off all credential operations. The Dashboard will not allow creating or editing credentials, and workflows
will not be able to resolve them. All credential endpoints return 403 Forbidden.
testkube-cloud-api:
credentials:
enabled: false
Environment variable: CREDENTIALS_ENABLED=false
The master password is still required at startup even when credentials are disabled — it is used to sign execution tokens that runners need to communicate with the control plane.
Disable Encrypted Credentials Only
Keeps plaintext Variable credentials and Vault references working, but blocks encrypted Secret credentials.
testkube-cloud-api:
credentials:
backends:
encrypted:
enabled: false
Environment variable: CREDENTIALS_BACKEND_ENCRYPTED_ENABLED=false
Artifact storage & cleanup
Testkube uses MinIO or any S3-compatible storage to store test artifacts by default. Over time, as the number of test executions increases, storage space may become filled with artifacts that are no longer required.
To manage storage efficiently, Testkube provides an automatic cleanup feature. You can configure the cleanup policy using the following Helm parameters:
testkube-cloud-api:
api:
storage:
cleanup:
retentionDays: 90
maxStorageSizeGb: 10
retentionDays: Defines the number of days to retain artifacts. Artifacts older than this period will be automatically deleted.maxStorageSizeGb: Sets the maximum allowable storage size in gigabytes. When the storage exceeds this limit, the oldest artifacts will be removed until the storage size is within the specified limit.
TLS
Self-signed certificates
If the Testkube On-Prem Control Plane components are behind a Load Balancer utilizing self-signed certificates, additional configuration must be provided to the Agent Helm chart during installation. Use one of the following methods to configure the Agent Helm chart to trust the self-signed certificates:
- Inject the custom CA certificate
# testkube chart
global:
tls:
caCertPath: /etc/testkube/certs
volumes:
additionalVolumes:
- name: custom-ca
secret:
secretName: custom-cert
additionalVolumeMounts:
- name: custom-ca
mountPath: /etc/testkube/certs
readOnly: true
- Skip TLS verification (not recommended in a production setup)
# testkube chart
global:
tls:
skipVerify: true
Security Headers
Security headers are an essential component of web security, providing protection against various types of attacks and enhancing the overall security posture of the web application. If you are exposing the Testkube On-Prem Control Plane components using the default Nginx Ingress Controller, inject the recommended security headers using the following snippet:
It requires the ingress controller configuration allow-snippet-annotations set as true, by default from version v1.9.0 it's set as false by default. Check here for more information.
testkube-cloud-api:
ingress:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Content-Type-Options: nosniff"
more_set_headers "X-Frame-Options: DENY"
more_set_headers "X-XSS-Protection: 1; mode=block"
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin"
more_set_headers "Permissions-Policy: "
more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload"
testkube-cloud-ui:
ingress:
annotations: &securityHeaders
nginx.ingress.kubernetes.io/configuration-snippet: &securityHeaders |
more_set_headers "X-Content-Type-Options: nosniff"
more_set_headers "X-Frame-Options: SAMEORIGIN"
more_set_headers "X-XSS-Protection: 1; mode=block"
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin"
more_set_headers "Permissions-Policy: fullscreen=(self)"
more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains; preload"
more_set_headers "Content-Security-Policy: default-src 'self' https: wss:; style-src 'self' 'unsafe-inline' https:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; worker-src https: wss: blob:; connect-src 'self' https: wss:"
testkube-ai-service:
ingress:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: *securityHeaders
It's possible to implement same headers with other ingress controllers or traffic managers, check the annotations or CRDs of the solution selected to expose Testkube On-Prem Control Plane components in your setup.
Organization Management
Bootstrap Member Mapping
By default, Testkube will automatically add new users as members to the default Organizations when they get invited. You can change the bootstrap configuration to change this behavior programmatically.
The simplified configuration is as follows. It creates a default org and environment and new users will automatically join as admin members:
testkube-cloud-api:
api:
features:
bootstrapOrg: <your-org>
bootstrapEnv: "Your first environment"
bootstrapAdmin: <you@example.com>
Alternatively, you can use the full advanced configuration for more options. The following example creates an organization with two environments. New users will automatically join as members of the default organizations and be added to specified environments and teams. Note that this will only happen on the first sign in. Afterwards, you can manage users through Testkube's dashboard, unless you use SCIM to manage your SSO integration - Read More.
testkube-cloud-api:
api:
features:
bootstrapConfig:
enabled: true
config:
# New users will automatically be added to these organizations
default_organizations:
- prod_organization
# These organizations will be created when Testkube boots.
organizations:
- name: prod_organization
# New users added will automatically receive this organization role
default_role: member
# New users will automatically be added to these environments
default_environments:
- production_1
# These environments will be created when Testkube boots.
environments:
- name: production_1
# New users added will automatically receive this environment role
default_role: run
- name: production_2
# These teams will be created when Testkube boots.
teams:
- name: Frontend
# New users will conditionally join teams based on a groups claim found within the JWT
# You will be added if the claim contains at least one of the groups you configure here.
# IMPORTANT: You must opt-in for groups by setting the OAUTH_GROUPS_SCOPE env to "true" in the testkube-cloud-api chart.
groups_claim: ["my-org:group-1", "my-org:group-2"]
The teams' groups claim works well with Dex. Dex includes a non-standard groups claim which is widely supported by its upstream providers.
Check out Dex's connector documentation to learn how to configure it for your identity provider.
For advanced automated User onboarding you can use the REST API to assign Users to Teams, Environments, Resource-Groups, etc.
Disabling personal organizations
Testkube creates an organization for every new user which acts as a personal workspace. When using the default organization and environment configuration, it makes sense to turn off personal organizations using the following config:
testkube-cloud-api:
api:
features:
disablePersonalOrgs: true