Controller Helm chart examples
- Create the controller Secret
- Create the TLS Secret
- Enable database initialization
- Enable bootstrap admin creation
- Controller with TLS enabled
- Controller with TLS disabled
- Internal-only cluster service
- Externally accessible cluster service
- Configure migration URL
- Controlled database migration
- Change service ports
The following examples show common controller variations that build on the baseline installation in Deploy controllers. They focus on the controller chart and assume PostgreSQL and KMS access already exist.
Create the controller Secret
Create a Kubernetes Secret containing the values the chart reads at install time. At a minimum, include the database URL and Boundary Enterprise license. Include bootstrap admin credentials when bootstrapAdmin.enabled=true, and a migration URL when migration_url is referenced via env://BOUNDARY_PG_MIGRATION_URL in your HCL.
$ kubectl create secret generic boundary-controller-secrets \
--namespace boundary \
--from-literal=database-url="postgres://<user>:<password>@<host>:5432/<dbname>?sslmode=require" \
--from-literal=migration-url="postgres://<migration-user>:<password>@<host>:5432/<dbname>?sslmode=require" \
--from-literal=license="<your-license-here>" \
--from-literal=admin-username="<admin-username>" \
--from-literal=admin-password="<admin-password>"
The key names (database-url, migration-url, license, admin-username, admin-password) must match the values set in secretRefs.keys.* in your Helm values file. These commands are provided as examples — use any Secret management method that fits your workflow.
Create the TLS Secret
If tls.disabled=false (the default), create a Kubernetes TLS Secret before installing the chart. The Secret must use the standard kubernetes.io/tls type with tls.crt and tls.key data keys.
$ kubectl create secret tls boundary-controller-tls \
--namespace boundary \
--cert=tls.crt \
--key=tls.key
The Secret name must match tls.secretName (default: boundary-controller-tls). These commands are provided as examples — use any Secret management method that fits your workflow.
Enable database initialization
Enable the pre-install database initialization Job on first install to let the chart create the Boundary schema.
Example values:
database:
init:
enabled: true
Use this pattern when:
- You are installing the chart for the first time against an empty PostgreSQL database.
- You want Helm to manage the initial schema creation.
With database.init.enabled=true, Helm runs a pre-install Job that initializes the Boundary schema before creating the ConfigMap, Services, Deployment, and any other enabled resources. Disable this Job on subsequent installs or when reinitializing against an existing Boundary database.
Enable bootstrap admin creation
Enable the post-install bootstrap Job on first install to let the chart create a global password auth method, user, account, and role.
Example values:
bootstrapAdmin:
enabled: true
Use this pattern when you want Helm to create the initial Boundary admin credentials. Disable this Job after the first install or if you manage Boundary auth methods and admin principals through another workflow.
Controller with TLS enabled
Enable TLS when you want encrypted API and ops traffic from the controller listeners. Provide a Kubernetes TLS Secret and keep the probe schemes aligned with HTTPS.
Example values:
tls:
disabled: false
secretName: boundary-controller-tls
mountPath: /etc/boundary/tls
Matching HCL — set tls_disable = false and add tls_cert_file and tls_key_file on the API and ops listeners:
listener "tcp" {
address = "0.0.0.0:9200"
purpose = "api"
tls_disable = false
tls_cert_file = "/etc/boundary/tls/tls.crt"
tls_key_file = "/etc/boundary/tls/tls.key"
}
listener "tcp" {
address = "0.0.0.0:9203"
purpose = "ops"
tls_disable = false
tls_cert_file = "/etc/boundary/tls/tls.crt"
tls_key_file = "/etc/boundary/tls/tls.key"
}
Controller with TLS disabled
Disable TLS when the controller listeners are protected by an upstream proxy or load balancer that terminates TLS, or in non-production environments where encryption is not required.
Example values:
tls:
disabled: true
Matching HCL — set tls_disable = true on each listener that had TLS enabled and remove the tls_cert_file and tls_key_file settings:
listener "tcp" {
address = "0.0.0.0:9200"
purpose = "api"
tls_disable = true
}
listener "tcp" {
address = "0.0.0.0:9203"
purpose = "ops"
tls_disable = true
}
When tls.disabled=true, the chart does not mount the TLS Secret and probe schemes default to HTTP.
Internal-only cluster service
If all workers run inside the cluster or connect through private networking, keep the cluster listener internal and set public_cluster_addr to a private DNS name or internal load balancer address reachable by workers.
Example values:
controller:
service:
api:
type: LoadBalancer
cluster:
type: ClusterIP
ops:
type: ClusterIP
Matching HCL:
controller {
name = "boundary-controller"
public_cluster_addr = "boundary-controller-cluster.boundary.svc.cluster.local:9201"
license = "env://BOUNDARY_LICENSE"
database {
url = "env://BOUNDARY_PG_URL"
}
}
Externally accessible cluster service
When workers run in a different namespace or outside the cluster, the default ClusterIP cluster service may not be reachable. Configure the cluster service as a LoadBalancer so workers can connect to public_cluster_addr from outside the namespace.
Example values:
controller:
service:
cluster:
type: LoadBalancer
port: 9201
targetPort: 9201
Matching HCL — update public_cluster_addr after the load balancer is provisioned:
controller {
name = "boundary-controller"
public_cluster_addr = "<LOAD_BALANCER_ADDRESS>:9201"
license = "env://BOUNDARY_LICENSE"
database {
url = "env://BOUNDARY_PG_URL"
}
}
Watch the cluster Service until the external address is assigned:
$ kubectl get svc boundary-controller-cluster --namespace boundary --watch
Update public_cluster_addr in controller.config with the assigned address, then upgrade:
$ helm upgrade boundary-controller hashicorp/boundary-controller \
--version 0.1.0 \
--namespace boundary \
--values my-values.yaml \
--rollback-on-failure \
--wait
Use this pattern when worker registration and controller clustering do not need internet-facing endpoints.
Configure migration URL
If you use a different PostgreSQL connection string for schema migrations, set migration_url directly in the controller HCL as a plain text value.
Matching HCL:
controller {
name = "boundary-controller"
public_cluster_addr = "boundary-controller-cluster.boundary.svc.cluster.local:9201"
license = "<your-license-here>"
database {
url = "postgres://<user>:<password>@<host>:5432/<dbname>?sslmode=require"
migration_url = "postgres://<migration-user>:<password>@<host>:5432/<dbname>?sslmode=require"
}
}
If the migration URL contains credentials that must not be stored in plaintext, you can instead reference it as env://BOUNDARY_PG_MIGRATION_URL and store the value in the same Kubernetes Secret as databaseUrl, using secretRefs.keys.migrationUrl to point to the correct key.
Controlled database migration
When upgrading to a Boundary version that requires a schema change, stop the controller pods first, then run the migration Job during the Helm upgrade.
Scale controllers to zero:
$ helm upgrade boundary-controller hashicorp/boundary-controller \
--version 0.1.0 \
--namespace boundary \
--values my-values.yaml \
--set controller.replicas=0 \
--rollback-on-failure \
--wait
Run the migration:
$ helm upgrade boundary-controller hashicorp/boundary-controller \
--version 0.1.0 \
--namespace boundary \
--values my-values.yaml \
--set controller.replicas=0 \
--set database.migrate.enabled=true \
--rollback-on-failure \
--wait
Or, to also run a repair migration for a specific version:
$ helm upgrade boundary-controller hashicorp/boundary-controller \
--version 0.1.0 \
--namespace boundary \
--values my-values.yaml \
--set controller.replicas=0 \
--set database.migrate.enabled=true \
--set database.repair.version=<version_id> \
--rollback-on-failure \
--wait
After the migration completes, reset all migration flags and restore the controller replica count:
$ helm upgrade boundary-controller hashicorp/boundary-controller \
--version 0.1.0 \
--namespace boundary \
--values my-values.yaml \
--set database.migrate.enabled=false \
--set database.repair.version="" \
--set controller.replicas=2 \
--rollback-on-failure \
--wait
Change service ports
If you change listener ports, update both the HCL and chart values.
Example values:
controller:
service:
api:
port: 9210
targetPort: 9210
Matching HCL:
listener "tcp" {
address = "0.0.0.0:9210"
purpose = "api"
tls_disable = false
tls_cert_file = "/etc/boundary/tls/tls.crt"
tls_key_file = "/etc/boundary/tls/tls.key"
}
The chart does not synchronize these settings automatically. Apply the same pattern for the cluster and ops listeners if those ports change.
More information
To view supported Helm values so that you can configure or update controllers, refer to Controller values.