Skip to content

Editing Manager Settings After Install

QHx Manager reads its configuration from a Kubernetes ConfigMap at startup and watches it for changes at runtime. Most settings take effect immediately without restarting the manager pod. Sensitive settings such as database credentials are stored separately in a Kubernetes Secret and overlaid onto the ConfigMap configuration.

Target audience: Platform operators, cluster administrators.


The manager reads two Kubernetes objects:

ObjectNamePurpose
ConfigMapqhx-manager (in qhx-system)All non-sensitive settings
SecretConfigured via --secret-name flag (optional)Sensitive overrides (e.g. database DSN)

Both objects are watched via the Kubernetes watch API. When either changes, the manager reloads configuration without restarting. The active configuration is logged at reload time.

The ConfigMap stores a single key qhx-manager.yaml whose value is a YAML document. The Secret (if configured) stores a key qhx-manager-secret.yaml with the same YAML format — only non-zero values in the Secret take effect as overrides.


Terminal window
kubectl get configmap qhx-manager -n qhx-system -o yaml

To see just the parsed settings:

Terminal window
kubectl get configmap qhx-manager -n qhx-system \
-o jsonpath='{.data.qhx-manager\.yaml}'

To see whether a Secret overlay is configured, check the manager’s flags:

Terminal window
kubectl get deployment manager -n qhx-system \
-o jsonpath='{.spec.template.spec.containers[0].args}'

Look for --secret-name and --secret-namespace in the output.


Edit the ConfigMap directly:

Terminal window
kubectl edit configmap qhx-manager -n qhx-system

The manager detects the change and reloads within a few seconds. You can confirm the reload in the manager logs:

Terminal window
kubectl logs -n qhx-system deploy/manager --since=1m | grep "Configuration loaded"

Alternatively, apply a patch:

Terminal window
kubectl patch configmap qhx-manager -n qhx-system --type merge \
-p '{"data":{"qhx-manager.yaml":"<full yaml content>"}}'

Because the value is a multi-line YAML string embedded in JSON, it is usually easier to edit the file locally and kubectl apply it:

Terminal window
kubectl get configmap qhx-manager -n qhx-system -o yaml > qhx-manager-cm.yaml
# edit qhx-manager-cm.yaml
kubectl apply -f qhx-manager-cm.yaml

All settings live under the qhx-manager.yaml key in the ConfigMap.

FieldDefaultDescription
qhxProxyImageset at installOCI image reference for the QHx proxy sidecar
pkiServerImageset at installOCI image reference for the SPIRE server (qhx-upki-server)
pkiAgentImageset at installOCI image reference for the SPIRE agent (qhx-upki-agent)
pkiControllerManagerImageset at installOCI image reference for the SPIRE controller manager
spiffeCSIDriverImageset at installOCI image reference for the SPIFFE CSI driver
initImageset at installOCI image reference for the init container
imagePullPolicyIfNotPresentKubernetes image pull policy (Always, IfNotPresent, Never)
FieldDefaultDescription
trustDomainset at installSPIFFE trust domain for this cluster (e.g. example.org)
clusterNameset at installLogical name for this cluster, used in federation
FieldDefaultDescription
pkiServerReplicas1Number of SPIRE server replicas. Set to 2 or more to enable HA. Requires pkiDatastoreConnectionString (see Sensitive Settings)
pkiStorageClassName""StorageClass for per-replica PKI data PVCs. Empty string uses the cluster default
pkiStorageSize1GiStorage capacity for each PKI data PVC
FieldDefaultDescription
proxyPortset at installPort the QHx proxy listens on
proxyConfigMapNamespaceset at installNamespace of the ConfigMap that holds proxy configuration
proxyConfigMapNameset at installName of the ConfigMap that holds proxy configuration
FieldDefaultDescription
policyRateLimit.qps5Maximum policy evaluation requests per second
policyRateLimit.burst20Maximum burst size for policy evaluations
policyRateLimit.backoffMax30sMaximum backoff duration when the rate limit is exceeded
FieldDefaultDescription
spireInstanceCooldownset at installMinimum time to wait before deleting an unused SPIRE instance after all its namespaces are removed
spireNamespaceMapConfigMapset at installName of the ConfigMap that maps namespaces to SPIRE instance hashes
spireSocketBaseDirset at installBase directory on nodes where SPIRE agent sockets are created
FieldDefaultDescription
agentMetricsPortBase39000First port in the range reserved for SPIRE agent Prometheus metrics endpoints
agentMetricsPortCount1024Number of ports in the agent metrics port range
FieldDefaultDescription
bundleExchangeInterval5mHow often the manager reconciles federation trust bundle exchanges between clusters
FieldDefaultDescription
tpmSupportEnabledfalseEnable TPM-backed node attestation. Requires TPM hardware on all nodes

Settings that contain credentials or connection strings must not be stored in the ConfigMap, as ConfigMaps are not encrypted at rest by default. Instead, store them in a Kubernetes Secret whose key is qhx-manager-secret.yaml.

The Secret is only used when the manager is started with the --secret-name and --secret-namespace flags (configured at install time via Helm values). The Secret is also watched at runtime — updating it reloads the manager configuration without a restart.

Currently the only sensitive setting is:

FieldDescription
pkiDatastoreConnectionStringPostgreSQL DSN for the shared SPIRE datastore. Required when pkiServerReplicas > 1
Terminal window
kubectl create secret generic qhx-manager-secret \
-n qhx-system \
--from-literal=qhx-manager-secret.yaml='pkiDatastoreConnectionString: "postgresql://spire:password@db.example.com:5432/spire?sslmode=require"' \
--dry-run=client -o yaml | kubectl apply -f -

The --dry-run=client -o yaml | kubectl apply pattern is safe to use for both initial creation and updates.

To verify the Secret is being picked up:

Terminal window
kubectl logs -n qhx-system deploy/manager --since=1m | grep -E "Configuration loaded|overlay"

The following steps enable multi-replica PKI servers on a cluster that was initially installed in single-replica mode.

1. Create the Secret with the PostgreSQL DSN (if not already configured at install):

Terminal window
kubectl create secret generic qhx-manager-secret \
-n qhx-system \
--from-literal=qhx-manager-secret.yaml='pkiDatastoreConnectionString: "postgresql://spire:password@db.example.com:5432/spire?sslmode=require"' \
--dry-run=client -o yaml | kubectl apply -f -

If the --secret-name flag is not already set on the manager deployment, add it via Helm upgrade:

Terminal window
helm upgrade qhx-core ./qhx-core-chart \
--namespace qhx-system \
--reuse-values \
--set secretName=qhx-manager-secret \
--set secretNamespace=qhx-system

2. Update the ConfigMap to set the replica count:

Terminal window
kubectl get configmap qhx-manager -n qhx-system -o yaml > qhx-manager-cm.yaml

Edit qhx-manager-cm.yaml and add/update these fields inside qhx-manager.yaml:

pkiServerReplicas: 2
pkiStorageClassName: "" # uses cluster default StorageClass
pkiStorageSize: "1Gi"

Apply the change:

Terminal window
kubectl apply -f qhx-manager-cm.yaml

The manager reloads immediately. It reconciles the SPIRE StatefulSet to the new replica count and provisions per-replica PVCs from the configured StorageClass.


  • ConfigMap changes: Detected within a few seconds via the Kubernetes watch API. All settings are reloaded atomically.
  • Secret changes: Detected on the same watch loop as the ConfigMap. The Secret overlay is re-applied on every reload.
  • No restart required: The manager pod does not need to be restarted for any ConfigMap or Secret change to take effect.
  • Reconciliation: After a reload, the manager re-reconciles all QHxClusterPolicy and QHxPolicy resources. Changes to SPIRE server configuration (replica count, storage, image) cause the affected StatefulSet to be updated, which Kubernetes applies as a rolling update.