From 39e5175addd15c0a9c9a6c96269ada31481e68f1 Mon Sep 17 00:00:00 2001 From: Yashwantha Gowd Date: Tue, 26 May 2026 11:32:53 +0530 Subject: [PATCH 1/2] worker documentation --- docs/documentation/1-overview.md | 67 +++ docs/documentation/3-worker/1-install.md | 202 +++++++ .../documentation/3-worker/2-configuration.md | 147 +++++ docs/documentation/3-worker/3-examples.md | 544 ++++++++++++++++++ 4 files changed, 960 insertions(+) create mode 100644 docs/documentation/1-overview.md create mode 100644 docs/documentation/3-worker/1-install.md create mode 100644 docs/documentation/3-worker/2-configuration.md create mode 100644 docs/documentation/3-worker/3-examples.md diff --git a/docs/documentation/1-overview.md b/docs/documentation/1-overview.md new file mode 100644 index 0000000..d9d6257 --- /dev/null +++ b/docs/documentation/1-overview.md @@ -0,0 +1,67 @@ +# Boundary Helm charts + +Important Note: These charts are not compatible with Helm 2. Use Helm 3.x. + +Boundary can run on Kubernetes with separate Helm charts for the two Boundary runtime roles: + +- The Boundary controller chart installs the Boundary control-plane components. +- The Boundary worker chart installs self-managed Boundary data-plane workers. + +The charts are separate because controllers and workers have different lifecycle, scaling, persistence, and exposure requirements. + +## Boundary architecture + +Boundary uses a distributed architecture: + +- Controllers manage authentication, authorization, session coordination, worker registration, and API/UI access. +- Workers proxy session traffic between clients, upstream workers, and target systems. + +A controller-backed Boundary deployment needs a PostgreSQL database and KMS configuration. A worker deployment needs valid worker HCL, a registration model, and persistent storage when the selected worker authentication or recording configuration requires it. + +## Chart responsibilities + +The charts package Kubernetes resources and Helm release workflows. They do not replace Boundary runtime configuration. + +| Chart | Role | Primary Kubernetes resources | State model | +| --- | --- | --- | --- | +| Boundary controller | Control plane | Deployment, Services, ConfigMap, ServiceAccount, PodDisruptionBudget, hook Jobs | Controller pods are stateless; controller state lives in PostgreSQL. | +| Boundary worker | Data plane | Deployment, Services, ConfigMap, PersistentVolumeClaims | Worker identity and optional session recordings can be persisted with PVCs. | + +## Controller chart summary + +The controller chart is intended for operator-managed Boundary control planes on Kubernetes. It can run multiple controller replicas and uses Helm hook Jobs for database initialization, optional database migration, optional database repair, and optional admin bootstrap. + +The controller chart expects you to provide required external dependencies such as PostgreSQL, KMS access, Boundary Enterprise license data, and TLS material when TLS is enabled. + +Controller installation documentation is intentionally separate from worker installation documentation. + +## Worker chart summary + +The worker chart installs one self-managed Boundary worker per Helm release. It is focused on egress and intermediate worker use cases, including workers used with HCP Boundary or self-managed Boundary deployments. + +The worker chart uses the official `hashicorp/boundary-enterprise` image by default. It mounts user-provided worker HCL from `worker.config`, exposes optional proxy and operations Services, and provisions optional PVCs for auth storage and session recording storage. + +## Shared configuration model + +Both charts separate configuration into two layers: + +1. Boundary runtime configuration supplied as HCL through a chart value. +2. Kubernetes infrastructure configuration supplied through Helm values. + +The charts do not infer all runtime settings from Kubernetes values. You must keep listener ports, addresses, storage paths, TLS settings, and registration settings aligned between Boundary HCL and the Kubernetes resources created by the chart. + +## Documentation organization + +The documentation is organized by chart role: + +1. This overview contains information that applies to both Boundary Helm charts. +2. [Controller chart documentation](2-controller/1-overview.md) contains controller-specific context. +3. [Worker chart documentation](3-worker/1-install.md) contains the current worker chart installation and operations documentation. + +Use the worker section for the current worker chart documentation: + +- [Install a Boundary worker](3-worker/1-install.md) +- [Configure the worker chart](3-worker/2-configuration.md) +- [Worker examples](3-worker/3-examples.md) +- [Operate a worker release](3-worker/4-operations.md) +- [Worker security considerations](3-worker/5-security.md) diff --git a/docs/documentation/3-worker/1-install.md b/docs/documentation/3-worker/1-install.md new file mode 100644 index 0000000..6dbc2a9 --- /dev/null +++ b/docs/documentation/3-worker/1-install.md @@ -0,0 +1,202 @@ +## Prerequisites + +Before installing the chart, make sure the following are available: + +- A Kubernetes cluster with a default StorageClass or pre-provisioned PersistentVolumes. +- Helm 3.x configured with access to the target Kubernetes cluster. +- Network connectivity from the worker pod to the HCP Boundary cluster or self-managed Boundary upstreams. +- A valid Boundary worker HCL configuration. +- A registration model selected before installation: + - Controller-led registration with a controller-generated activation token. + - Worker-led registration using the token emitted in pod logs during first startup. + - KMS-backed worker authentication for self-managed Boundary deployments configured for KMS worker auth. + +Intermediate workers may also require a reachable endpoint for the proxy listener and cluster support for the selected Service type, such as `LoadBalancer`. + +## Add the HashiCorp Helm repository + +Add the Helm repository and confirm the chart is visible: + +```shell +helm repo add hashicorp https://helm.releases.hashicorp.com +helm search repo hashicorp/boundary-worker +``` + +Example output: + +```text +NAME CHART VERSION APP VERSION DESCRIPTION +hashicorp/boundary-worker 0.1.0 0.21-ent Boundary worker Helm chart +``` + +## Prepare the worker configuration + +The chart reads raw Boundary HCL from `worker.config`. Embed the HCL in a values file and pass it with `-f`. + +Start from the worker configuration guidance in [Create worker config](https://developer.hashicorp.com/boundary/docs/workers/create) if you want a base worker configuration. + +At minimum, a usable worker configuration usually includes: + +- A proxy listener for session traffic. +- An operations listener for health and metrics. +- A worker registration mechanism. +- `hcp_boundary_cluster_id` for HCP Boundary or `initial_upstreams` for an upstream worker or controller. +- `auth_storage_path` when auth storage persistence is enabled. +- `recording_storage_path` when session recording persistence is enabled. +- `public_addr` when other clients or workers must connect to this worker. + +Example HCP Boundary worker configuration: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + + tags { + type = ["worker", "kled", "tests"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + description = "All events sent to stderr" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Note: This inline AEAD KMS example is mainly suitable for development or testing. The key is visible to anyone who can read the configuration file. For production use, prefer an external KMS as described in [Configure KMS](https://developer.hashicorp.com/boundary/docs/configuration/kms). + +## Create a namespace + +```shell +kubectl create namespace boundary +``` + +## List available chart versions + +To see available published versions: + +```shell +helm search repo hashicorp/boundary-worker -l +``` + +## Install a Boundary worker + +Create a values file that contains `worker.config` and any Kubernetes overrides: + +```yaml +worker: + config: | + disable_mlock = true + + listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" + } + + listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true + } + + worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + + tags { + type = ["worker", "kled", "tests"] + } + } + + kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" + } + + persistence: + authStorage: + storageClass: "" + recording: + enabled: true + storageClass: "" +``` + +Install the release: + +```shell +helm install boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --create-namespace \ + -f my-values.yaml +``` + + + + +## Verify the deployment + +Check the rendered resources after installation: + +```shell +kubectl get deployment,pods,svc,pvc -n boundary +kubectl logs -n boundary deployment/boundary-worker-deployment +``` + +Confirm that: + +- The pod becomes Ready. +- Enabled PVCs are Bound. +- The proxy and ops Services match your intended exposure model. +- Worker logs show successful registration or authentication. +- The worker appears as active in Boundary and is eligible for session assignment. + +## Update `public_addr` for LoadBalancer workers + +Kubernetes may assign the external hostname or IP after installation when `worker.service.proxy.type` is `LoadBalancer`. If `worker.service.proxy.type` is `ClusterIP`, use a cluster-reachable address when the worker is accessed internally. + +Watch the proxy Service: + +```shell +kubectl get svc boundary-worker-proxy -n boundary -w +``` + +If the worker HCL needs the final address, update the `public_addr` field in `worker.config` or in the HCL file with the `LoadBalancer` address or internal `ClusterIP` address, then upgrade the release: + +```shell +helm upgrade boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml +``` diff --git a/docs/documentation/3-worker/2-configuration.md b/docs/documentation/3-worker/2-configuration.md new file mode 100644 index 0000000..8042416 --- /dev/null +++ b/docs/documentation/3-worker/2-configuration.md @@ -0,0 +1,147 @@ +# Boundary worker Helm chart configuration + +The Boundary worker Helm chart is configured with Helm values and a user-provided Boundary HCL configuration. The chart source is the source of truth for supported values. + + +### Boundary runtime configuration + +`worker.config` contains the Boundary worker HCL. The chart writes this value into a ConfigMap and mounts it at `/etc/boundary/boundary-worker.hcl`. + +The chart renders `worker.config` with Helm's `tpl` function. Helm template expressions inside the HCL are evaluated during rendering. + +At container startup, the chart replaces `${POD_NAME_LOWER}` with the pod name converted to lowercase and starts Boundary with the processed configuration file. + +The chart does not validate Boundary HCL semantics. You are responsible for configuring valid listeners, registration settings, upstreams, storage paths, and worker tags. + +### Kubernetes infrastructure configuration + +Kubernetes-specific values control the Deployment, Services, PVCs, security contexts, and scheduling options. These values do not replace or generate the Boundary runtime HCL. + +For example, if you change `worker.service.proxy.targetPort` to `9222`, you must also update the proxy listener port in `worker.config`. + +The following sections describe all available Helm values, grouped by function. Each table lists the key, its default value, and a description of its effect. + +## Image values + +| Key | Default | Description | +| --- | --- | --- | +| `image.repository` | `hashicorp/boundary-enterprise` | Worker container image repository. | +| `image.tag` | `""` | Worker image tag. When empty, the chart uses `Chart.appVersion`, currently `0.21-ent`. | +| `image.pullPolicy` | `IfNotPresent` | Kubernetes image pull policy. | +| `imagePullSecrets` | `[]` | Optional image pull secrets for private registries. | + +## Worker runtime value + +| Key | Default | Description | +| --- | --- | --- | +| `worker.config` | Embedded sample HCL | Boundary worker HCL stored in a ConfigMap and mounted into the worker container. Replace placeholders before installing. | +| `worker.terminationGracePeriodSeconds` | `7200` | Pod termination grace period in seconds. Allows long-running sessions time to drain before forced termination. | + +The default `worker.config` includes `disable_mlock = true`. Keep this setting when running the chart with its default security model, which drops all Linux capabilities and disallows privilege escalation. Memory locking requires elevated privileges that the chart does not grant. If swap is enabled on your nodes, address any resulting data-at-rest exposure through platform controls. + +## Proxy Service values + +The proxy Service exposes the worker's session traffic listener. + +| Key | Default | Description | +| --- | --- | --- | +| `worker.service.proxy.enabled` | `true` | Creates the proxy Service when enabled. | +| `worker.service.proxy.type` | `LoadBalancer` | Kubernetes Service type for proxy traffic. | +| `worker.service.proxy.port` | `9202` | Service port for proxy traffic. | +| `worker.service.proxy.targetPort` | `9202` | Container port targeted by the proxy Service. Must match the proxy listener in `worker.config`. | +| `worker.service.proxy.annotations` | AWS NLB annotations | Annotations added to the proxy Service. AWS load balancer annotations are omitted automatically when the proxy Service type is not `LoadBalancer`. | + +## Operations Service values + +The operations Service exposes the worker operations listener for health and metrics. + +| Key | Default | Description | +| --- | --- | --- | +| `worker.service.ops.enabled` | `true` | Creates the operations Service when enabled. | +| `worker.service.ops.type` | `ClusterIP` | Kubernetes Service type for operations traffic. | +| `worker.service.ops.port` | `9203` | Service port for the operations endpoint. | +| `worker.service.ops.targetPort` | `9203` | Container port targeted by the operations Service. Must match the ops listener in `worker.config`. | +| `worker.service.ops.annotations` | `{}` | Annotations added to the operations Service. | + +Keep the operations Service internal unless a trusted monitoring path requires a different exposure model. + +## Resource values + +| Key | Default | Description | +| --- | --- | --- | +| `worker.resources.requests.cpu` | `100m` | CPU request for the worker container. | +| `worker.resources.requests.memory` | `512Mi` | Memory request for the worker container. | +| `worker.resources.limits.cpu` | `200m` | CPU limit for the worker container. | +| `worker.resources.limits.memory` | `1Gi` | Memory limit for the worker container. | + +Tune resource values for your expected connection volume, recording usage, and cluster sizing. + +## Auth storage values + +Auth storage stores worker identity and authentication material for registration models that require local persistence. + +| Key | Default | Description | +| --- | --- | --- | +| `worker.persistence.authStorage.enabled` | `false` | Creates and mounts an auth storage PVC when enabled. When disabled, the chart mounts an `emptyDir` at the auth storage path. | +| `worker.persistence.authStorage.size` | `1Gi` | Size of the auth storage PVC. | +| `worker.persistence.authStorage.accessMode` | `ReadWriteOnce` | Access mode for the auth storage PVC. | +| `worker.persistence.authStorage.storageClass` | `""` | StorageClass for the auth storage PVC. Empty uses the cluster default. | +| `worker.persistence.authStorage.path` | `/var/lib/boundary` | Mount path for auth storage. Must match `auth_storage_path` in `worker.config`. | + +Disable auth storage only when your worker authentication model does not require persistent local auth material, such as KMS-backed worker authentication. + +## Recording storage values + +Recording storage stores session recordings when recording is configured in Boundary. + +| Key | Default | Description | +| --- | --- | --- | +| `worker.persistence.recording.enabled` | `false` | Creates and mounts a recording PVC when enabled. | +| `worker.persistence.recording.size` | `10Gi` | Size of the recording PVC. | +| `worker.persistence.recording.accessMode` | `ReadWriteOnce` | Access mode for the recording PVC. | +| `worker.persistence.recording.storageClass` | `""` | StorageClass for the recording PVC. Empty uses the cluster default. | +| `worker.persistence.recording.path` | `/boundary/recording` | Mount path for recording storage. Must match `recording_storage_path` in `worker.config` when recording is enabled. | + +If you disable recording storage, remove `recording_storage_path` from the HCL or ensure recording data does not need to persist. + +## Security context values + +The default security settings run the worker without elevated privileges. + +| Key | Default | +| --- | --- | +| `podSecurityContext.runAsNonRoot` | `true` | +| `podSecurityContext.runAsUser` | `100` | +| `podSecurityContext.runAsGroup` | `1000` | +| `podSecurityContext.fsGroup` | `1000` | +| `podSecurityContext.fsGroupChangePolicy` | `OnRootMismatch` | +| `podSecurityContext.seccompProfile.type` | `RuntimeDefault` | +| `containerSecurityContext.runAsNonRoot` | `true` | +| `containerSecurityContext.runAsUser` | `100` | +| `containerSecurityContext.runAsGroup` | `1000` | +| `containerSecurityContext.allowPrivilegeEscalation` | `false` | +| `containerSecurityContext.readOnlyRootFilesystem` | `true` | +| `containerSecurityContext.capabilities.drop` | `ALL` | +| `containerSecurityContext.seccompProfile.type` | `RuntimeDefault` | + +The Deployment also sets `SKIP_SETCAP=1`, which prevents the container startup path from attempting Linux capability modification. + +## Scheduling values + +| Key | Default | Description | +| --- | --- | --- | +| `podAnnotations` | `{}` | Additional pod annotations. | +| `nodeSelector` | `{}` | Node selector constraints. | +| `tolerations` | `[]` | Pod tolerations. | +| `affinity` | `{}` | Pod affinity rules. | + +## Configuration alignment checklist + +Before installing or upgrading, confirm that: + +- The proxy listener port in `worker.config` matches `worker.service.proxy.targetPort`. +- The ops listener port in `worker.config` matches `worker.service.ops.targetPort`. +- `auth_storage_path` matches `worker.persistence.authStorage.path` when auth storage is enabled. +- `recording_storage_path` matches `worker.persistence.recording.path` when recording storage is enabled. +- `public_addr` matches the endpoint other Boundary clients or workers can actually reach. +- Placeholder activation tokens, cluster IDs, and upstream addresses have been replaced. diff --git a/docs/documentation/3-worker/3-examples.md b/docs/documentation/3-worker/3-examples.md new file mode 100644 index 0000000..b318974 --- /dev/null +++ b/docs/documentation/3-worker/3-examples.md @@ -0,0 +1,544 @@ +# Boundary worker Helm chart examples + +These examples show common worker configurations. They focus on the worker chart only and assume the Boundary controller or HCP Boundary cluster already exists. + +## Worker with ingress capabilities + +An ingress worker accepts connections from downstream workers and clients. It commonly uses the controller cluster as its upstream and exposes the proxy listener publicly through a `LoadBalancer` Service. + +Example HCL for a worker with ingress capabilities: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "boundary-worker.example.com:9202" + initial_upstreams = ["boundary-controller-cluster:9201"] + + tags { + type = ["worker", "ingress"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Example values for a worker with ingress capabilities and a public LoadBalancer: + +```yaml +worker: + service: + proxy: + enabled: true + type: LoadBalancer + port: 9202 + targetPort: 9202 + ops: + enabled: true + type: ClusterIP + port: 9203 + targetPort: 9203 + persistence: + authStorage: + enabled: false + recording: + enabled: false +``` + +Install the chart: + +```shell +helm install boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --create-namespace \ + -f ingress-values.yaml +``` + +If `public_addr` is not known until the load balancer is created, wait for the external address: + +```shell +kubectl get svc boundary-worker-proxy -n boundary -w +``` + +Update `public_addr` in `ingress-worker.hcl`, then upgrade: + +```shell +helm upgrade boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --reuse-values \ + -f ingress-values.yaml +``` + +## Worker with intermediate capabilities + +A worker with intermediate capabilities relays traffic between upstream and downstream workers. It requires both `initial_upstreams` and `public_addr`. + +Example HCL for a worker with intermediate capabilities: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["ingress-worker-address:9202"] + + tags { + type = ["worker", "intermediate"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Example values for a worker with intermediate capabilities and a LoadBalancer: + +```yaml +worker: + service: + proxy: + enabled: true + type: LoadBalancer + port: 9202 + targetPort: 9202 + ops: + enabled: true + type: ClusterIP + port: 9203 + targetPort: 9203 + persistence: + authStorage: + enabled: false + recording: + enabled: false +``` + +Install the chart: + +```shell +helm install boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --create-namespace \ + -f intermediate-values.yaml +``` + +If `public_addr` is not known until the load balancer is created, wait for the external address: + +```shell +kubectl get svc boundary-worker-proxy -n boundary -w +``` + +Update `public_addr` in `intermediate-worker.hcl`, then upgrade: + +```shell +helm upgrade boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --reuse-values \ + -f intermediate-values.yaml +``` + +## Worker with egress capabilities + +A worker with egress capabilities connects to target systems and is usually the final hop before a target. It often does not need a public `public_addr`. + +Example HCL for a worker with egress capabilities: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = [":9202"] + + tags { + type = ["worker", "egress"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Example values for a worker with egress capabilities: + +```yaml +worker: + service: + proxy: + enabled: false + ops: + enabled: true + type: ClusterIP + persistence: + authStorage: + enabled: false + recording: + enabled: false +``` + +Install with a values file that includes the worker configuration: + +```shell +helm install boundary-worker hashicorp/boundary-worker \ + --version 0.1.0 \ + --namespace boundary \ + --create-namespace \ + -f egress-values.yaml +``` + +## Worker with a pre-configured DNS address + +If you already control the DNS name for the worker, set `public_addr` during installation: + +```hcl +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + + tags { + type = ["worker", "ingress"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} +``` + +After the Service receives an external address, point the DNS record to that address. This avoids changing the worker HCL after installation, but you remain responsible for ensuring DNS resolves to the reachable worker endpoint. + +## Worker-led registration + +For worker-led registration, install the worker without a controller-generated activation token. The worker generates identity material at startup and writes registration information to the pod logs. For additional details, see [Worker-led authorization](https://developer.hashicorp.com/boundary/docs/workers/registration#worker-led-authorization). + +Example HCL for worker-led registration: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + auth_storage_path = "/var/lib/boundary" + + tags { + type = ["worker", "worker-led"] + } +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Example values for worker-led registration with auth storage persistence: + +```yaml +worker: + persistence: + authStorage: + enabled: true + size: 1Gi +``` + +Typical workflow: + +1. Install the worker chart with worker-led registration settings in `worker.config`. +2. Read the worker pod logs. +3. Register or authorize the emitted worker registration information with Boundary. +4. Confirm the worker becomes active. + +View logs: + +```shell +kubectl logs -n boundary deployment/boundary-worker-deployment +``` + +Auth storage should remain enabled for worker-led registration so generated worker identity persists across restarts. + +## Controller-led registration + +For controller-led registration, see [Controller-led authorization](https://developer.hashicorp.com/boundary/docs/workers/registration#controller-led-authorization): + +1. Create the worker resource in Boundary or HCP Boundary. +2. Obtain the controller-generated activation token. +3. Add the token to `worker.config`. +4. Install the chart. +5. Confirm the worker registers and persists its credentials to auth storage. + +The activation token is used during initial bootstrap. After successful registration, the worker uses persisted credentials from auth storage. + +Example HCL for controller-led registration: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + auth_storage_path = "/var/lib/boundary" + controller_generated_activation_token = "" + + tags { + type = ["worker", "controller-led"] + } +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +Example values for controller-led registration with auth storage persistence: + +```yaml +worker: + persistence: + authStorage: + enabled: true + size: 1Gi +``` + +## KMS-backed worker authentication + +KMS-backed worker authentication is supported only in self-managed Boundary deployments. For additional details, see [KMS-led authorization and authentication](https://developer.hashicorp.com/boundary/docs/workers/registration#kms-led-authorization-and-authentication). It is not available for HCP Boundary workers. + +For self-managed deployments, configure the worker HCL with the required KMS worker-auth stanza. KMS authentication does not require persistent local auth material, so disable the auth storage PVC: + +Example HCL for KMS-backed worker authentication: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9202" + purpose = "proxy" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + + tags { + type = ["worker", "kms"] + } +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ=" + key_id = "global_worker-auth" +} + +events { + audit_enabled = true + sysevents_enabled = true + observations_enable = true + sink "stderr" { + name = "all-events" + event_types = ["*"] + format = "cloudevents-json" + } +} +``` + +```yaml +worker: + persistence: + authStorage: + enabled: false +``` + +When `worker.persistence.authStorage.enabled` is `false`, the chart mounts an `emptyDir` at the auth storage path instead of creating a PVC. + +## Enable session recording storage + +If this worker will store session recordings, enable recording persistence and set `recording_storage_path` in `worker.config`. + +Example values: + +```yaml +worker: + persistence: + recording: + enabled: true + size: 10Gi + path: /boundary/recording +``` + +Matching HCL: + +```hcl +worker { + name = "boundary-worker" + public_addr = "" + initial_upstreams = ["boundary-controller-cluster:9201"] + recording_storage_path = "/boundary/recording" + + tags { + type = ["worker", "recording"] + } +} +``` + +Ensure the recording storage path in `worker.config` matches `worker.persistence.recording.path`. + +## Change service ports + +If you change listener ports, update both the HCL and chart values. + +Example values: + +```yaml +worker: + service: + proxy: + port: 9222 + targetPort: 9222 +``` + +Matching HCL: + +```hcl +listener "tcp" { + address = "0.0.0.0:9222" + purpose = "proxy" +} +``` + +The chart does not synchronize these settings automatically. From 45a87a435f5e3d6fcf06b0b48ff32a22af774e8e Mon Sep 17 00:00:00 2001 From: Yashwantha Gowd Date: Mon, 1 Jun 2026 15:22:57 +0530 Subject: [PATCH 2/2] controller helm documentation --- docs/documentation/1-overview.md | 12 +- docs/documentation/2-controller/1-install.md | 273 ++++++++++++++++++ .../2-controller/2-configuration.md | 229 +++++++++++++++ docs/documentation/2-controller/3-examples.md | 210 ++++++++++++++ 4 files changed, 720 insertions(+), 4 deletions(-) create mode 100644 docs/documentation/2-controller/1-install.md create mode 100644 docs/documentation/2-controller/2-configuration.md create mode 100644 docs/documentation/2-controller/3-examples.md diff --git a/docs/documentation/1-overview.md b/docs/documentation/1-overview.md index d9d6257..590b0a5 100644 --- a/docs/documentation/1-overview.md +++ b/docs/documentation/1-overview.md @@ -55,13 +55,17 @@ The charts do not infer all runtime settings from Kubernetes values. You must ke The documentation is organized by chart role: 1. This overview contains information that applies to both Boundary Helm charts. -2. [Controller chart documentation](2-controller/1-overview.md) contains controller-specific context. -3. [Worker chart documentation](3-worker/1-install.md) contains the current worker chart installation and operations documentation. +2. [Controller chart documentation](2-controller/1-install.md) contains the current controller chart installation, configuration, and examples. +3. [Worker chart documentation](3-worker/1-install.md) contains the current worker chart installation, configuration, and examples. + +Use the controller section for the current controller chart documentation: + +- [Install a Boundary controller](2-controller/1-install.md) +- [Configure the controller chart](2-controller/2-configuration.md) +- [Controller examples](2-controller/3-examples.md) Use the worker section for the current worker chart documentation: - [Install a Boundary worker](3-worker/1-install.md) - [Configure the worker chart](3-worker/2-configuration.md) - [Worker examples](3-worker/3-examples.md) -- [Operate a worker release](3-worker/4-operations.md) -- [Worker security considerations](3-worker/5-security.md) diff --git a/docs/documentation/2-controller/1-install.md b/docs/documentation/2-controller/1-install.md new file mode 100644 index 0000000..ea25df5 --- /dev/null +++ b/docs/documentation/2-controller/1-install.md @@ -0,0 +1,273 @@ +# Boundary controller Helm chart installation + +## Prerequisites + +Before installing the chart, make sure the following are available: + +- A Kubernetes cluster supported by the chart. +- Helm 3.x configured with access to the target Kubernetes cluster. +- A reachable PostgreSQL database for Boundary controller state. +- A valid Boundary controller HCL configuration. +- KMS configuration for the `root`, `recovery`, and `worker-auth` purposes. +- An existing Kubernetes Secret containing the database URL and Boundary Enterprise license. +- An existing Kubernetes Secret containing `admin-username` and `admin-password` when `bootstrapAdmin.enabled=true`. +- A Kubernetes TLS Secret containing `tls.crt` and `tls.key` when `tls.disabled=false`. +- A ServiceAccount that the controller Deployment and hook Jobs can use. + +The controller chart deploys a stateless Boundary control plane. Persistent controller state is stored in PostgreSQL, not on the controller pods. + +## Add the HashiCorp Helm repository + +Add the Helm repository and confirm the chart is visible: + +```shell +helm repo add hashicorp https://helm.releases.hashicorp.com +helm repo update +helm search repo hashicorp/boundary-controller +``` + +Example output: + +```text +NAME CHART VERSION APP VERSION DESCRIPTION +hashicorp/boundary-controller 0.1.0 0.21-ent Boundary controller Helm chart +``` + +## Create the controller Secret + +The chart reads sensitive values from an existing Kubernetes Secret referenced by `secretRefs.secretName`. At minimum, create a Secret with the database URL and Boundary Enterprise license. Include bootstrap admin credentials when bootstrap admin creation is enabled. + +```shell +kubectl create secret generic boundary-controller-secrets \ + --namespace boundary \ + --from-literal=database-url='postgres://boundary:password@postgres:5432/boundary?sslmode=require' \ + --from-literal=license='' \ + --from-literal=admin-username='admin' \ + --from-literal=admin-password='' +``` + +If your `controller.config` uses `migration_url = "env://BOUNDARY_PG_MIGRATION_URL"`, also add the migration URL key expected by `secretRefs.keys.migrationUrl`. + +## Create the TLS Secret when TLS is enabled + +If `tls.disabled=false`, create the Kubernetes TLS Secret before installation: + +```shell +kubectl create secret tls boundary-controller-tls \ + --namespace boundary \ + --cert=tls.crt \ + --key=tls.key +``` + +When TLS is disabled, the chart does not mount this Secret. + +## Prepare the controller configuration + +The chart reads raw Boundary HCL from `controller.config`. Embed the HCL in a values file and pass it with `-f`. + +Start from the controller configuration guidance in [Configure controllers](https://developer.hashicorp.com/boundary/docs/configuration/controller) if you need a base controller configuration. + +At minimum, a usable controller configuration usually includes: + +- An API listener. +- A cluster listener. +- An operations listener. +- A `controller` block with `license` and `database.url`. +- `public_cluster_addr` so workers can reach the cluster listener. +- KMS stanzas for `root`, `recovery`, and `worker-auth`. + +Example controller configuration using AWS KMS: + +```hcl +disable_mlock = true + +listener "tcp" { + address = "0.0.0.0:9200" + purpose = "api" + tls_disable = true +} + +listener "tcp" { + address = "0.0.0.0:9201" + purpose = "cluster" +} + +listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true +} + +controller { + name = "boundary-controller" + description = "Boundary controller running in Kubernetes" + public_cluster_addr = "boundary-controller-cluster.boundary.svc.cluster.local:9201" + license = "env://BOUNDARY_LICENSE" + + database { + url = "env://BOUNDARY_PG_URL" + } +} + +kms "awskms" { + purpose = "root" + region = "us-east-1" + kms_key_id = "alias/boundary-root" +} + +kms "awskms" { + purpose = "recovery" + region = "us-east-1" + kms_key_id = "alias/boundary-recovery" +} + +kms "awskms" { + purpose = "worker-auth" + region = "us-east-1" + kms_key_id = "alias/boundary-worker-auth" +} +``` + +Note: Keep `disable_mlock = true` with the chart's default security model. The containers run without the elevated privileges required for memory locking. + +## Create a namespace + +```shell +kubectl create namespace boundary +``` + +## List available chart versions + +To see available published versions: + +```shell +helm search repo hashicorp/boundary-controller -l +``` + +## Install a Boundary controller + +Create a values file that contains `controller.config` and the Kubernetes overrides you need: + +```yaml +secretRefs: + secretName: boundary-controller-secrets + +serviceAccount: + name: default + +tls: + disabled: true + +controller: + config: | + disable_mlock = true + + listener "tcp" { + address = "0.0.0.0:9200" + purpose = "api" + tls_disable = true + } + + listener "tcp" { + address = "0.0.0.0:9201" + purpose = "cluster" + } + + listener "tcp" { + address = "0.0.0.0:9203" + purpose = "ops" + tls_disable = true + } + + 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" + } + } + + kms "awskms" { + purpose = "root" + region = "us-east-1" + kms_key_id = "" + } + + kms "awskms" { + purpose = "recovery" + region = "us-east-1" + kms_key_id = "" + } + + kms "awskms" { + purpose = "worker-auth" + region = "us-east-1" + kms_key_id = "" + } + + service: + api: + type: LoadBalancer + cluster: + type: LoadBalancer + ops: + type: ClusterIP +``` + +Install the release: + +```shell +helm install boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + --create-namespace \ + -f my-values.yaml +``` + +## Verify the deployment + +Check the rendered resources after installation: + +```shell +kubectl get deployment,pods,svc,jobs,pdb -n boundary +kubectl logs -n boundary deployment/boundary-controller +``` + +Confirm that: + +- The database initialization Job completes successfully when `database.init.enabled=true`. +- The bootstrap admin Job completes successfully when `bootstrapAdmin.enabled=true`. +- The controller pods become Ready. +- The API, cluster, and ops Services match your intended exposure model. +- Boundary API requests succeed against the controller API listener. +- Workers can reach `public_cluster_addr` and register successfully. + +## Upgrade with database migration + +When the Boundary version requires a database migration, run the upgrade in a controlled sequence: + +1. Scale controller replicas to zero. +2. Take a PostgreSQL backup. +3. Run the upgrade with `database.migrate.enabled=true`. + +Example: + +```shell +helm upgrade boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml \ + --set controller.replicas=0 +``` + +```shell +helm upgrade boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml \ + --set database.migrate.enabled=true +``` + +If you need to run a repair migration, also set `database.repair.version` to the Boundary migration version you need to repair. \ No newline at end of file diff --git a/docs/documentation/2-controller/2-configuration.md b/docs/documentation/2-controller/2-configuration.md new file mode 100644 index 0000000..6336792 --- /dev/null +++ b/docs/documentation/2-controller/2-configuration.md @@ -0,0 +1,229 @@ +# Boundary controller Helm chart configuration + +The Boundary controller Helm chart is configured with Helm values and a user-provided Boundary HCL configuration. The chart source is the source of truth for supported values. + +## Boundary runtime configuration + +`controller.config` contains the Boundary controller HCL. The chart writes this value into a ConfigMap and mounts it at `/etc/boundary/controller.hcl`. + +The chart renders `controller.config` with Helm's `tpl` function. Helm template expressions inside the HCL are evaluated during rendering. + +The chart does not validate Boundary controller semantics beyond a few chart-level alignment checks. You are responsible for configuring valid listeners, database settings, cluster addresses, KMS stanzas, rate limits, and event sinks. + +The chart validates the following: + +- `tls_cert_file` and `tls_key_file` remain aligned with `tls.mountPath` when `tls.disabled=false`. +- AEAD KMS keys are not referenced through `env://BOUNDARY_KMS_*` inside `kms` blocks. +- Required Secret keys exist when `secretRefs.validateExisting=true`. + +## Kubernetes infrastructure configuration + +Kubernetes-specific values control the Deployment, Services, ConfigMap, Job hooks, security contexts, ServiceAccount, and scheduling options. These values do not replace or generate the Boundary runtime HCL. + +For example, if you change `controller.service.api.targetPort` to `9220`, you must also update the API listener port in `controller.config`. + +The following sections describe the available Helm values grouped by function. Each table lists the key, its default value, and a description of its effect. + +## Naming and namespace values + +| Key | Default | Description | +| --- | --- | --- | +| `nameOverride` | `""` | Overrides the chart-generated resource base name. | +| `namespace` | `""` | Overrides the namespace the chart renders namespaced resources into. Empty uses the Helm release namespace. | + +## Image values + +| Key | Default | Description | +| --- | --- | --- | +| `image.repository` | `hashicorp/boundary-enterprise` | Controller image repository. | +| `image.tag` | `0.21-ent` | Controller image tag. | +| `image.pullPolicy` | `IfNotPresent` | Kubernetes image pull policy. | +| `imagePullSecrets` | `[]` | Optional image pull secrets for private registries. | + +## TLS values + +| Key | Default | Description | +| --- | --- | --- | +| `tls.disabled` | `true` | Disables TLS on the API and ops listeners when true. | +| `tls.secretName` | `boundary-controller-tls` | Name of the Kubernetes TLS Secret mounted when TLS is enabled. | +| `tls.mountPath` | `/etc/boundary/tls` | Container path where the TLS Secret is mounted. | + +When TLS is enabled, keep the listener `tls_cert_file` and `tls_key_file` paths in `controller.config` aligned with `tls.mountPath`, and set `controller.livenessProbe.scheme` and `controller.readinessProbe.scheme` to `HTTPS`. + +## Secret reference values + +| Key | Default | Description | +| --- | --- | --- | +| `secretRefs.secretName` | `boundary-controller-secrets` | Existing Secret that contains database, license, and bootstrap admin values. | +| `secretRefs.validateExisting` | `false` | Validates the referenced Secret and required keys during rendering when true. | +| `secretRefs.keys.databaseUrl` | `database-url` | Secret key used for `BOUNDARY_PG_URL`. | +| `secretRefs.keys.migrationUrl` | not set | Optional Secret key used for `BOUNDARY_PG_MIGRATION_URL` when referenced in `controller.config`. | +| `secretRefs.keys.license` | `license` | Secret key used for `BOUNDARY_LICENSE`. | +| `secretRefs.keys.adminUsername` | `admin-username` | Secret key used by the bootstrap admin Job. | +| `secretRefs.keys.adminPassword` | `admin-password` | Secret key used by the bootstrap admin Job. | + +If `controller.config` references `migration_url = "env://BOUNDARY_PG_MIGRATION_URL"`, the chart injects that environment variable into the controller pods and database Jobs. + +## Controller runtime values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.replicas` | `2` | Number of controller replicas in the Deployment. | +| `controller.rollingUpdate.maxUnavailable` | `1` | Maximum unavailable pods during a rolling update. | +| `controller.rollingUpdate.maxSurge` | `1` | Maximum extra pods during a rolling update. | +| `controller.config` | Embedded sample HCL | Boundary controller HCL stored in a ConfigMap and mounted into the controller container and hook Jobs. | + +The default `controller.config` includes `disable_mlock = true`. Keep this setting with the chart's default security model, which drops all Linux capabilities and disallows privilege escalation. + +The default embedded configuration uses `awskms` stanzas. Replace the default KMS regions, key IDs, and any placeholder addresses before installing. + +## Listener Service values + +The chart creates separate Services for the API, cluster, and ops listeners. + +### API Service values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.service.api.type` | `LoadBalancer` | Kubernetes Service type for Boundary API traffic. | +| `controller.service.api.port` | `9200` | Service port for API traffic. | +| `controller.service.api.targetPort` | `9200` | Container port targeted by the API Service. Must match the API listener in `controller.config`. | +| `controller.service.api.annotations` | `{}` | Annotations added to the API Service. | + +### Cluster Service values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.service.cluster.type` | `LoadBalancer` | Kubernetes Service type for worker registration and controller cluster traffic. | +| `controller.service.cluster.port` | `9201` | Service port for cluster traffic. | +| `controller.service.cluster.targetPort` | `9201` | Container port targeted by the cluster Service. Must match the cluster listener in `controller.config`. | +| `controller.service.cluster.annotations` | `{}` | Annotations added to the cluster Service. | + +### Ops Service values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.service.ops.type` | `ClusterIP` | Kubernetes Service type for health and metrics traffic. | +| `controller.service.ops.port` | `9203` | Service port for the operations endpoint. | +| `controller.service.ops.targetPort` | `9203` | Container port targeted by the ops Service. Must match the ops listener in `controller.config`. | +| `controller.service.ops.annotations` | `{}` | Annotations added to the ops Service. | + +Keep the ops Service internal unless a trusted monitoring path requires a different exposure model. + +## Probe values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.livenessProbe.scheme` | `HTTP` | Probe scheme for `/health` on the ops listener. Use `HTTPS` when TLS is enabled for ops. | +| `controller.livenessProbe.initialDelaySeconds` | `60` | Initial liveness probe delay. | +| `controller.livenessProbe.periodSeconds` | `10` | Liveness probe period. | +| `controller.livenessProbe.failureThreshold` | `3` | Liveness probe failure threshold. | +| `controller.livenessProbe.timeoutSeconds` | `5` | Liveness probe timeout. | +| `controller.readinessProbe.scheme` | `HTTP` | Readiness probe scheme for `/health` on the ops listener. Use `HTTPS` when TLS is enabled for ops. | +| `controller.readinessProbe.initialDelaySeconds` | `15` | Initial readiness probe delay. | +| `controller.readinessProbe.periodSeconds` | `10` | Readiness probe period. | +| `controller.readinessProbe.failureThreshold` | `3` | Readiness probe failure threshold. | +| `controller.readinessProbe.timeoutSeconds` | `5` | Readiness probe timeout. | + +## Resource values + +| Key | Default | Description | +| --- | --- | --- | +| `controller.resources.requests.cpu` | `250m` | CPU request for the controller container. | +| `controller.resources.requests.memory` | `512Mi` | Memory request for the controller container. | +| `controller.resources.limits.cpu` | `500m` | CPU limit for the controller container. | +| `controller.resources.limits.memory` | `1Gi` | Memory limit for the controller container. | + +Tune resource values for your expected API load, worker volume, session coordination, and audit event volume. + +## Database job values + +The chart uses hook Jobs for database initialization, migration, and optional repair. + +| Key | Default | Description | +| --- | --- | --- | +| `database.init.enabled` | `true` | Runs the pre-install database initialization Job. | +| `database.migrate.enabled` | `false` | Runs the pre-upgrade database migration Job. | +| `database.repair.version` | `""` | When set with `database.migrate.enabled=true`, also runs a pre-upgrade repair migration Job for the specified version. | +| `database.resources.requests.cpu` | `100m` | CPU request for database Jobs. | +| `database.resources.requests.memory` | `128Mi` | Memory request for database Jobs. | +| `database.resources.limits.cpu` | `500m` | CPU limit for database Jobs. | +| `database.resources.limits.memory` | `512Mi` | Memory limit for database Jobs. | + +The initialization Job is idempotent. If the database is already initialized, the Job exits successfully. + +## Bootstrap admin values + +The bootstrap admin Job creates or updates a global password auth method, user, account, and role using Boundary recovery privileges. + +| Key | Default | Description | +| --- | --- | --- | +| `bootstrapAdmin.enabled` | `true` | Runs the bootstrap admin Job after install. | +| `bootstrapAdmin.runOnUpgrade` | `false` | Also runs the bootstrap admin Job after upgrades when true. | +| `bootstrapAdmin.waitTimeoutSeconds` | `120` | Maximum time the bootstrap Job waits for the controller API to become reachable. | +| `bootstrapAdmin.authMethodName` | `bootstrap-password` | Name of the password auth method created or reused by the Job. | +| `bootstrapAdmin.userResourceName` | `bootstrap-admin` | Boundary user resource name created or reused by the Job. | +| `bootstrapAdmin.accountResourceName` | `bootstrap-admin` | Boundary account resource name created or reused by the Job. | +| `bootstrapAdmin.roleName` | `bootstrap-global-admin` | Boundary role name created or reused by the Job. | +| `bootstrapAdmin.resources.requests.cpu` | `100m` | CPU request for the bootstrap Job. | +| `bootstrapAdmin.resources.requests.memory` | `128Mi` | Memory request for the bootstrap Job. | +| `bootstrapAdmin.resources.limits.cpu` | `500m` | CPU limit for the bootstrap Job. | +| `bootstrapAdmin.resources.limits.memory` | `512Mi` | Memory limit for the bootstrap Job. | + +Disable this Job if you already manage Boundary auth methods and admin principals outside the chart. + +## Security context values + +The default security settings run the controller without elevated privileges. + +| Key | Default | +| --- | --- | +| `podSecurityContext.runAsUser` | `100` | +| `podSecurityContext.runAsGroup` | `1000` | +| `podSecurityContext.runAsNonRoot` | `true` | +| `podSecurityContext.fsGroup` | `1000` | +| `containerSecurityContext.runAsNonRoot` | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | `false` | +| `containerSecurityContext.readOnlyRootFilesystem` | `true` | +| `containerSecurityContext.capabilities.drop` | `ALL` | +| `containerSecurityContext.seccompProfile.type` | `RuntimeDefault` | + +The Deployment and Jobs also set `SKIP_SETCAP=1`, which prevents the container startup path from attempting Linux capability modification. + +## ServiceAccount values + +| Key | Default | Description | +| --- | --- | --- | +| `serviceAccount.name` | `default` | Existing ServiceAccount used by the Deployment and hook Jobs. The chart does not create a ServiceAccount. | +| `serviceAccount.automountServiceAccountToken` | `false` | Controls whether the pod service account token is mounted. | + +## Availability and shutdown values + +| Key | Default | Description | +| --- | --- | --- | +| `podDisruptionBudget.enabled` | `true` | Creates a PodDisruptionBudget for controller pods. | +| `podDisruptionBudget.minAvailable` | `1` | Minimum available controller pods during voluntary disruptions. | +| `podDisruptionBudget.maxUnavailable` | not set | Optional alternative to `minAvailable`. Use only one of the two. | +| `terminationGracePeriodSeconds` | `15` | Kubernetes termination grace period before SIGKILL. Should exceed `graceful_shutdown_wait_duration` in `controller.config`. | + +## Scheduling values + +| Key | Default | Description | +| --- | --- | --- | +| `podAnnotations` | `{}` | Additional pod annotations. | +| `nodeSelector` | `{}` | Node selector constraints. | +| `tolerations` | `[]` | Pod tolerations. | +| `affinity` | `{}` | Pod affinity rules. | + +## Configuration alignment checklist + +Before installing or upgrading, confirm that: + +- The API listener port in `controller.config` matches `controller.service.api.targetPort`. +- The cluster listener port in `controller.config` matches `controller.service.cluster.targetPort`. +- The ops listener port in `controller.config` matches `controller.service.ops.targetPort`. +- `public_cluster_addr` matches the endpoint workers can actually reach. +- `tls_cert_file` and `tls_key_file` match `tls.mountPath` when TLS is enabled. +- Probe schemes are set to `HTTPS` when TLS is enabled on the ops listener. +- The referenced Secret contains every key required by the current `controller.config` and bootstrap settings. +- `terminationGracePeriodSeconds` exceeds `graceful_shutdown_wait_duration` in the controller HCL. \ No newline at end of file diff --git a/docs/documentation/2-controller/3-examples.md b/docs/documentation/2-controller/3-examples.md new file mode 100644 index 0000000..99dc4e2 --- /dev/null +++ b/docs/documentation/2-controller/3-examples.md @@ -0,0 +1,210 @@ +# Boundary Controller Helm Chart Examples + +These examples show common controller variations that build on the baseline installation flow in the install page. They focus on the controller chart only and assume PostgreSQL, KMS access, and any required Secrets already exist. + +## Disable Database Initialization + +If the PostgreSQL database was already initialized by an earlier controller release or by an external workflow, disable the pre-install initialization Job. + +Example values: + +```yaml +database: + init: + enabled: false +``` + +Use this pattern when: + +- The Boundary database schema already exists. +- You are reinstalling the chart against an existing Boundary database. +- Database initialization is handled outside Helm. + +With `database.init.enabled=false`, Helm skips the `pre-install` init Job and goes straight to creating the ConfigMap, Services, Deployment, and any other enabled resources. + +## Disable Bootstrap Admin Creation + +If your organization manages auth methods and administrative accounts outside Helm, disable the bootstrap Job after the initial installation. + +Example values: + +```yaml +bootstrapAdmin: + enabled: false +``` + +Use this pattern when Boundary identity bootstrap is handled 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: + +```yaml +tls: + disabled: false + secretName: boundary-controller-tls + mountPath: /etc/boundary/tls + +controller: + livenessProbe: + scheme: HTTPS + readinessProbe: + scheme: HTTPS + config: | + disable_mlock = true + + 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:9201" + purpose = "cluster" + } + + 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 { + name = "boundary-controller" + public_cluster_addr = "boundary-controller-cluster.example.com:9201" + license = "env://BOUNDARY_LICENSE" + + database { + url = "env://BOUNDARY_PG_URL" + } + } + + kms "awskms" { + purpose = "root" + region = "us-east-1" + kms_key_id = "alias/boundary-root" + } + + kms "awskms" { + purpose = "recovery" + region = "us-east-1" + kms_key_id = "alias/boundary-recovery" + } + + kms "awskms" { + purpose = "worker-auth" + region = "us-east-1" + kms_key_id = "alias/boundary-worker-auth" + } +``` + +## 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: + +```yaml +controller: + service: + api: + type: LoadBalancer + cluster: + type: ClusterIP + ops: + type: ClusterIP +``` + +Matching HCL: + +```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" + } +} +``` + +Use this pattern when worker registration and controller clustering do not need internet-facing endpoints. + +## Configure Migration URL + +If you use a different PostgreSQL credential or connection string for schema migrations, reference `env://BOUNDARY_PG_MIGRATION_URL` in the controller HCL and provide the matching Secret key. + +Matching HCL: + +```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" + migration_url = "env://BOUNDARY_PG_MIGRATION_URL" + } +} +``` + +Matching values: + +```yaml +secretRefs: + secretName: boundary-controller-secrets + keys: + databaseUrl: database-url + migrationUrl: migration-url + license: license + adminUsername: admin-username + adminPassword: admin-password +``` + +The chart automatically injects `BOUNDARY_PG_MIGRATION_URL` into the controller pods and migration Jobs when the HCL references it. + +## 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: + +```shell +helm upgrade boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml \ + --set controller.replicas=0 +``` + +Run the migration: + +```shell +helm upgrade boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml \ + --set database.migrate.enabled=true +``` + +Run a repair migration for a specific version: + +```shell +helm upgrade boundary-controller hashicorp/boundary-controller \ + --version 0.1.0 \ + --namespace boundary \ + -f my-values.yaml \ + --set database.migrate.enabled=true \ + --set database.repair.version= +``` + +Take a PostgreSQL backup before running migrations or repairs. \ No newline at end of file