From 3276853427c071698eabb2bddc1aefb2e685fdf6 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 19 Jun 2025 02:12:08 +0800 Subject: [PATCH] misc: added helm support for auto bootstrap --- ...rt-tests-infisical-standalone-postgres.yml | 7 ++ .../guides/automated-bootstrapping.mdx | 81 +++++++++++++++++++ .../templates/bootstrap-job.yaml | 57 +++++++++++++ .../templates/jobs-rbac.yaml | 32 +++++++- .../infisical-standalone-postgres/values.yaml | 25 ++++++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 helm-charts/infisical-standalone-postgres/templates/bootstrap-job.yaml diff --git a/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml b/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml index fcf5197208..d8f6466c68 100644 --- a/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml +++ b/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml @@ -51,6 +51,13 @@ jobs: --from-literal=ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 \ --from-literal=SITE_URL=http://localhost:8080 + - name: Create bootstrap secret + run: | + kubectl create secret generic infisical-bootstrap-credentials \ + --namespace infisical-standalone-postgres \ + --from-literal=INFISICAL_ADMIN_EMAIL=admin@example.com \ + --from-literal=INFISICAL_ADMIN_PASSWORD=admin-password + - name: Run chart-testing (install) run: | ct install \ diff --git a/docs/self-hosting/guides/automated-bootstrapping.mdx b/docs/self-hosting/guides/automated-bootstrapping.mdx index ebc9c3c806..5266c933b7 100644 --- a/docs/self-hosting/guides/automated-bootstrapping.mdx +++ b/docs/self-hosting/guides/automated-bootstrapping.mdx @@ -8,6 +8,7 @@ Infisical's Automated Bootstrapping feature enables you to provision and configu ## Overview The Automated Bootstrapping workflow automates the following processes: + - Creating an admin user account - Initializing an organization for the entire instance - Establishing an **instance admin machine identity** with full administrative permissions @@ -51,6 +52,7 @@ You can bootstrap an Infisical instance using either the API or the CLI. -d '{"email":"admin@example.com","password":"your-secure-password","organization":"your-org-name"}' \ http://your-infisical-instance.com/api/v1/admin/bootstrap ``` + Use the [Infisical CLI](/cli/commands/bootstrap) to bootstrap the instance and extract the token for immediate use in automation: @@ -60,9 +62,88 @@ You can bootstrap an Infisical instance using either the API or the CLI. ``` This example command pipes the output through `jq` to extract only the machine identity token, making it easy to capture and use directly in automation scripts or export as an environment variable for tools like Terraform. + +## Helm Chart Auto Bootstrap + +When deploying Infisical using the official Helm chart, you can enable automatic bootstrapping that runs as part of the deployment process. This eliminates the need to manually bootstrap the instance after deployment. + +### Configuration + +Enable auto bootstrapping in your Helm values by setting `autoBootstrap.enabled: true` and providing the necessary configuration: + +```yaml +autoBootstrap: + enabled: true + organization: "My Organization" + secretTemplate: '{"data":{"token":"{{.Identity.Credentials.Token | b64enc}}"}}' + + secretDestination: + name: "infisical-bootstrap-secret" + namespace: "default" # defaults to release namespace if not specified + + credentialSecret: + name: "infisical-bootstrap-credentials" +``` + +You'll also need to create a secret containing the bootstrap credentials before deployment. The secret must contain `INFISICAL_ADMIN_EMAIL` and `INFISICAL_ADMIN_PASSWORD` keys: + +```bash +kubectl create secret generic infisical-bootstrap-credentials \ + --from-literal=INFISICAL_ADMIN_EMAIL="admin@example.com" \ + --from-literal=INFISICAL_ADMIN_PASSWORD="your-secure-password" \ + --namespace=release-namespace +``` + +### How It Works + +The Helm chart auto bootstrap feature: + +1. **Post-Install Hook**: Runs automatically after the main Infisical deployment is complete +2. **Readiness Check**: Uses an init container with curl to wait for Infisical to be ready by polling the `/api/status` endpoint +3. **Bootstrap Execution**: Uses the Infisical CLI to bootstrap the instance +4. **Kubernetes Secret Creation**: Creates a Kubernetes secret directly via the Kubernetes API using the rendered template +5. **RBAC**: Automatically configures the necessary permissions (`get`, `create`, `update` on secrets) for the bootstrap job + +### Template System + +The `secretTemplate` field allows you to customize the data section of the created Kubernetes secret. The template has access to the full bootstrap response and includes helper functions: + +- `{{ .Identity.Credentials.Token }}` - The admin machine identity token +- `{{ .Organization.Id }}` - The created organization ID +- `{{ .Organization.Slug }}` - The organization slug +- `{{ .User.Email }}` - The admin user email +- `b64enc` function for base64 encoding values + +Example template for storing multiple values: + +```yaml +secretTemplate: | + { + "data": { + "infisical_token": "{{ .Identity.Credentials.Token | b64enc }}", + "admin_email": "{{ .User.Email | b64enc }}", + "organization": "{{ .Organization.Name | b64enc }}" + } + } +``` + +### Benefits + +- **Zero-Touch Deployment**: Complete Infisical setup without manual intervention +- **Infrastructure as Code**: Bootstrap configuration is versioned with your Helm values +- **Secure Token Storage**: Admin identity credentials are immediately stored in Kubernetes secrets +- **Integration Ready**: The created secret can be referenced by other applications or automation tools + +### Security Considerations + +- The bootstrap job requires permissions to create secrets in the specified namespace +- Bootstrap credentials should be stored securely and rotated regularly +- The generated admin token has full instance privileges and should be protected accordingly +- Consider using Kubernetes RBAC to restrict access to the generated secret + ## API Response Structure The bootstrap process returns a JSON response with details about the created user, organization, and machine identity: diff --git a/helm-charts/infisical-standalone-postgres/templates/bootstrap-job.yaml b/helm-charts/infisical-standalone-postgres/templates/bootstrap-job.yaml new file mode 100644 index 0000000000..b8631a6819 --- /dev/null +++ b/helm-charts/infisical-standalone-postgres/templates/bootstrap-job.yaml @@ -0,0 +1,57 @@ +{{- $infisicalValues := .Values.infisical }} +{{- if $infisicalValues.autoBootstrap.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ .Release.Name }}-bootstrap-{{ .Release.Revision }}" + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": before-hook-creation + labels: + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + backoffLimit: 3 + template: + metadata: + name: "{{ .Release.Name }}-bootstrap" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + serviceAccountName: {{ include "infisical.serviceAccountName" . }} + {{- if $infisicalValues.image.imagePullSecrets }} + imagePullSecrets: + {{- toYaml $infisicalValues.image.imagePullSecrets | nindent 6 }} + {{- end }} + restartPolicy: OnFailure + initContainers: + - name: wait-for-infisical + image: curlimages/curl:8.14.1 + command: ['sh', '-c'] + args: + - | + echo "Waiting for Infisical to be ready..." + until curl -f http://{{ include "infisical.fullname" . }}:8080/api/status; do + echo "Infisical not ready yet, retrying in 10 seconds..." + sleep 10 + done + echo "Infisical is ready! Proceeding with bootstrap..." + containers: + - name: infisical-bootstrap + image: "infisical/cli:{{ $infisicalValues.image.tag }}" + imagePullPolicy: {{ $infisicalValues.image.pullPolicy | default "IfNotPresent" }} + args: + - bootstrap + - --domain=http://{{ include "infisical.fullname" . }}:8080 + - --output=k8-secret + - --k8-secret-name={{ $infisicalValues.autoBootstrap.secretDestination.name }} + - --k8-secret-namespace={{ $infisicalValues.autoBootstrap.secretDestination.namespace | default .Release.Namespace }} + - --organization={{ $infisicalValues.autoBootstrap.organization }} + - --k8-secret-template={{ $infisicalValues.autoBootstrap.secretTemplate }} + - --ignore-if-bootstrapped=true + envFrom: + - secretRef: + name: {{ $infisicalValues.autoBootstrap.credentialSecret.name }} +{{- end }} diff --git a/helm-charts/infisical-standalone-postgres/templates/jobs-rbac.yaml b/helm-charts/infisical-standalone-postgres/templates/jobs-rbac.yaml index 38230d9a12..3a229c7cf8 100644 --- a/helm-charts/infisical-standalone-postgres/templates/jobs-rbac.yaml +++ b/helm-charts/infisical-standalone-postgres/templates/jobs-rbac.yaml @@ -39,4 +39,34 @@ subjects: roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: {{ include "infisical.roleName" . }} \ No newline at end of file + name: {{ include "infisical.roleName" . }} +--- +{{- if .Values.infisical.autoBootstrap.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "infisical.roleName" . }}-bootstrap + namespace: {{ .Values.infisical.autoBootstrap.secretDestination.namespace | default .Release.Namespace }} + labels: + {{- include "infisical.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "infisical.roleBindingName" . }}-bootstrap + namespace: {{ .Values.infisical.autoBootstrap.secretDestination.namespace | default .Release.Namespace }} + labels: + {{- include "infisical.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "infisical.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "infisical.roleName" . }}-bootstrap +{{- end }} diff --git a/helm-charts/infisical-standalone-postgres/values.yaml b/helm-charts/infisical-standalone-postgres/values.yaml index d617a1389b..2d5f12abcc 100644 --- a/helm-charts/infisical-standalone-postgres/values.yaml +++ b/helm-charts/infisical-standalone-postgres/values.yaml @@ -13,6 +13,31 @@ infisical: # -- Automatically migrates new database schema when deploying autoDatabaseSchemaMigration: true + autoBootstrap: + # -- Enable auto-bootstrap of the Infisical instance + enabled: false + + image: + # -- Infisical Infisical CLI image tag version + tag: "0.41.86" + + # -- Template for the data/stringData section of the Kubernetes secret. Available functions: b64enc + secretTemplate: '{"data":{"token":"{{.Identity.Credentials.Token | b64enc}}"}}' + + secretDestination: + # -- Name of the bootstrap secret to create in the Kubernetes cluster which will store the formatted root identity credentials + name: "infisical-bootstrap-secret" + + # -- Namespace to create the bootstrap secret in. If not provided, the secret will be created in the same namespace as the release. + namespace: "default" + + # -- Infisical organization to create in the Infisical instance during auto-bootstrap + organization: "default-org" + + credentialSecret: + # -- Name of the Kubernetes secret containing the credentials for the auto-bootstrap workflow + name: "infisical-bootstrap-credentials" + databaseSchemaMigrationJob: image: # -- Image repository for migration wait job