-
-
Notifications
You must be signed in to change notification settings - Fork 137
Add helm chart #240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add helm chart #240
Changes from 10 commits
0f20530
028886f
327d798
4bbfde5
31d9992
79ef1f1
6be42ca
db33677
5c23f80
7641454
1c938d4
801f1de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| apiVersion: v2 | ||
| name: headplane | ||
| description: "The headplane Helm chart provides an easy way to deploy a Headscale UI with headplane, including an embedded Tailscale relay. This chart simplifies the setup of a private networking solution using Kubernetes." | ||
| type: application | ||
| version: 0.1.39 | ||
| appVersion: "0.6.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| # headplane | ||
|
|
||
|    | ||
|
|
||
| This helm chart deploys [Headplane](https://github.com/tale/headplane) + [Headscale](https://github.com/juanfont/headscale) and an embedded Tailscale relay in a kubernetes cluster. | ||
|
|
||
| ## Installation | ||
|
|
||
| ### Prerequisites | ||
| - Kubernetes cluster | ||
| - Helm installed | ||
|
|
||
| ### Install the Chart | ||
| ```sh | ||
| # Install with default values | ||
| helm install headplane oci://harbor.lag0.com.br/library/headplane | ||
|
|
||
| # Install with custom values | ||
| helm install headplane oci://harbor.lag0.com.br/library/headplane -f values.yaml | ||
|
|
||
| ``` | ||
|
|
||
| ### Upgrade the Chart | ||
| ```sh | ||
| helm upgrade headplane oci://harbor.lag0.com.br/library/headplane | ||
| ``` | ||
|
|
||
| * Some config changes may require manual pod restart to take place | ||
|
|
||
| ### Uninstall the Chart | ||
| ```sh | ||
| helm uninstall headplane | ||
| ``` | ||
|
|
||
| ## Values | ||
|
|
||
| | Key | Type | Default | Description | | ||
| |-----|------|---------|-------------| | ||
| | headplane.config.headscale.config_path | string | `"/etc/headscale/config.yaml"` | | | ||
| | headplane.config.headscale.config_strict | string | `"true"` | | | ||
| | headplane.config.headscale.url | string | `"https://vpn.example.com"` | | | ||
| | headplane.config.integration.kubernetes.enabled | bool | `true` | | | ||
| | headplane.config.integration.kubernetes.pod_name | string | `"headplane-0"` | | | ||
| | headplane.config.integration.kubernetes.validate_manifest | bool | `true` | | | ||
| | headplane.config.server.cookie_secure | bool | `true` | | | ||
| | headplane.config.server.host | string | `"0.0.0.0"` | | | ||
| | headplane.config.server.port | int | `3000` | | | ||
| | headplane.envFrom | list | `[]` | | | ||
| | headplane.image | string | `"ghcr.io/tale/headplane:0.6.0"` | | | ||
| | headplane.oidc.client_id | string | `"REPLACE_IT_WITH_YOUR_OIDC_CLIENT_ID_FOR_HEADPLANE"` | | | ||
| | headplane.oidc.disable_api_key_login | bool | `true` | | | ||
| | headplane.oidc.enabled | bool | `false` | | | ||
| | headplane.oidc.issuer | string | `"https://your-oidc-issuer-url.com"` | | | ||
| | headplane.oidc.redirect_uri | string | `"https://your-headplane-admin-domain.com/admin/oidc/callback"` | | | ||
| | headplane.oidc.secret_name | string | `"oidc-secrets"` | | | ||
| | headplane.oidc.token_endpoint_auth_method | string | `"client_secret_post"` | | | ||
| | headscale.acl | string | `""` | | | ||
| | headscale.config.database.debug | bool | `false` | | | ||
| | headscale.config.database.sqlite.path | string | `"/etc/headscale/db.sqlite"` | | | ||
| | headscale.config.database.type | string | `"sqlite"` | | | ||
| | headscale.config.derp.paths | list | `[]` | | | ||
| | headscale.config.derp.server.automatically_add_embedded_derp_region | bool | `true` | | | ||
| | headscale.config.derp.server.enabled | bool | `false` | | | ||
| | headscale.config.derp.server.ipv4 | string | `"1.2.3.4"` | | | ||
| | headscale.config.derp.server.ipv6 | string | `"2001:db8::1"` | | | ||
| | headscale.config.derp.server.private_key_path | string | `"/var/lib/headscale/derp_server_private.key"` | | | ||
| | headscale.config.derp.server.region_code | string | `"headscale"` | | | ||
| | headscale.config.derp.server.region_id | int | `999` | | | ||
| | headscale.config.derp.server.region_name | string | `"Headscale Embedded DERP"` | | | ||
| | headscale.config.derp.server.stun_listen_addr | string | `"0.0.0.0:3478"` | | | ||
| | headscale.config.derp.urls[0] | string | `"https://controlplane.tailscale.com/derpmap/default"` | | | ||
| | headscale.config.dns.base_domain | string | `"headscale.vpn"` | | | ||
| | headscale.config.dns.magic_dns | bool | `true` | | | ||
| | headscale.config.dns.nameservers.global[0] | string | `"1.1.1.1"` | | | ||
| | headscale.config.dns.nameservers.global[1] | string | `"8.8.8.8"` | | | ||
| | headscale.config.grpc_allow_insecure | bool | `false` | | | ||
| | headscale.config.grpc_listen_addr | string | `"0.0.0.0:50443"` | | | ||
| | headscale.config.listen_addr | string | `"0.0.0.0:8080"` | | | ||
| | headscale.config.metrics_listen_addr | string | `"0.0.0.0:9090"` | | | ||
| | headscale.config.noise.private_key_path | string | `"/etc/headscale/noise_private.key"` | | | ||
| | headscale.config.policy.mode | string | `"database"` | | | ||
| | headscale.config.policy.path | string | `"/etc/headscale/acl.hujson"` | | | ||
| | headscale.config.prefixes.allocation | string | `"sequential"` | | | ||
| | headscale.config.prefixes.v4 | string | `"100.64.0.0/10"` | | | ||
| | headscale.config.prefixes.v6 | string | `"fd7a:115c:a1e0::/48"` | | | ||
| | headscale.config.server_url | string | `"https://vpn.example.com"` | | | ||
| | headscale.envFrom | list | `[]` | | | ||
| | headscale.image | string | `"headscale/headscale:0.25.1"` | | | ||
| | headscale.oidc.client_id | string | `"YOUR_OIDC_CLIENT_ID_FOR_HEADSCALE"` | | | ||
| | headscale.oidc.enabled | bool | `false` | | | ||
| | headscale.oidc.issuer | string | `"https://your-oidc-issuer.com"` | | | ||
| | headscale.oidc.secret_name | string | `"oidc-secrets"` | | | ||
| | ingress.annotations | list | `[]` | | | ||
| | ingress.className | string | `"nginx"` | | | ||
| | ingress.enabled | bool | `false` | | | ||
| | ingress.headplaneDomain | string | `"headplane.example.com"` | | | ||
| | ingress.headscaleDomain | string | `"vpn.example.com"` | | | ||
| | ingress.labels | list | `[]` | | | ||
| | ingress.tlsSecretName | string | `"headplane-tls"` | | | ||
| | pvc.accessModes[0] | string | `"ReadWriteOnce"` | | | ||
| | pvc.annotations | object | `{}` | | | ||
| | pvc.enabled | bool | `true` | | | ||
| | pvc.labels | list | `[]` | | | ||
| | pvc.name | string | `"headscale-config"` | | | ||
| | pvc.storage | string | `"1Gi"` | | | ||
| | relay.config.advertise_exit_node | string | `"true"` | | | ||
| | relay.config.authKey | string | `""` | | | ||
| | relay.config.exit_node | string | `"example.com"` | | | ||
| | relay.config.firewall_debug | string | `"false"` | | | ||
| | relay.config.hostname | string | `"example.com"` | | | ||
| | relay.config.login_server | string | `"https://vpn.example.com"` | | | ||
| | relay.config.routes | string | `"10.0.0.0/8"` | | | ||
| | relay.enabled | bool | `false` | | | ||
| | relay.image | string | `"ghcr.io/tailscale/tailscale:v1.80.3"` | | | ||
| | relay.pvc.accessModes[0] | string | `"ReadWriteOnce"` | | | ||
| | relay.pvc.enabled | bool | `false` | | | ||
| | relay.pvc.name | string | `"tailscale-relay-data"` | | | ||
| | relay.pvc.storage | string | `"1Gi"` | | | ||
|
|
||
| ### OIDC Configuration | ||
|
|
||
| To use OIDC, you must provide the OIDC client secrets via Kubernetes secret: | ||
|
|
||
| ```sh | ||
| kubectl create secret generic oidc-secrets \ | ||
| --from-literal=HEADPLANE_OIDC__CLIENT_SECRET=your-headplane-oidc-client-secret \ | ||
| --from-literal=HEADPLANE_OIDC__CLIENT_ID=your-headplane-oidc-client-id \ | ||
| --from-literal=HEADSCALE_OIDC__CLIENT_SECRET=your-headscale-oidc-client-secret \ | ||
| --from-literal=HEADSCALE_OIDC__CLIENT_ID=your-headscale-oidc-client-id \ | ||
| -n <namespace> | ||
| ``` | ||
|
|
||
| Then enable OIDC in your `values.yaml`: | ||
| ```yaml | ||
| headplane: | ||
| oidc: | ||
| enabled: true | ||
| issuer: "https://your-oidc-issuer-url.com" | ||
| redirect_uri: "https://your-headplane-admin-domain.com/admin/oidc/callback" | ||
| secret_name: "oidc-secrets" # Name of your OIDC secret | ||
|
|
||
| headscale: | ||
| oidc: | ||
| enabled: true | ||
| issuer: "https://your-oidc-issuer.com" | ||
| secret_name: "oidc-secrets" # Same secret as Headplane | ||
| ``` | ||
|
|
||
| You can add any additional environment variables by creating more secrets or config-maps and adding them to the `envFrom` section. For example, to add custom configuration: | ||
|
|
||
| ```sh | ||
| kubectl create secret generic headplane-custom-config \ | ||
| --from-literal=CUSTOM_VAR=value \ | ||
| --from-literal=ANOTHER_VAR=another-value \ | ||
| -n <namespace> | ||
| ``` | ||
|
|
||
| Then add it to your values: | ||
| ```yaml | ||
| headplane: | ||
| envFrom: | ||
| - secretRef: | ||
| name: headplane-custom-config | ||
| ``` | ||
|
|
||
| Note: Make sure to keep your secrets secure and never commit them to version control. | ||
| Consider using a secrets management solution in production like external-secrets. | ||
|
|
||
| ## License | ||
| Copyright © 2025 antoniolago | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer if this isn't licensed, especially as Apache because its language doesn't necessarily fit well with MIT the best.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure we can remove Apache license since the code is forked from https://github.com/nbcloudio/headplane-chart unless all contributors agrees, or am I wrong?
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then in that case, we do need their permission yes, and I can't technically merge this in-tree until it's been addressed. |
||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: | ||
|
|
||
| ``` | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| ``` | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # headplane | ||
|
|
||
|    | ||
|
|
||
| This helm chart deploys [Headplane](https://github.com/tale/headplane) + [Headscale](https://github.com/juanfont/headscale) and an embedded Tailscale relay in a kubernetes cluster. | ||
|
|
||
| ## Installation | ||
|
|
||
| ### Prerequisites | ||
| - Kubernetes cluster | ||
| - Helm installed | ||
|
|
||
| ### Install the Chart | ||
| ```sh | ||
| # Install with default values | ||
| helm install headplane oci://harbor.lag0.com.br/library/headplane | ||
|
|
||
| # Install with custom values | ||
| helm install headplane oci://harbor.lag0.com.br/library/headplane -f values.yaml | ||
|
|
||
| ``` | ||
|
|
||
| ### Upgrade the Chart | ||
| ```sh | ||
| helm upgrade headplane oci://harbor.lag0.com.br/library/headplane | ||
| ``` | ||
|
|
||
| * Some config changes may require manual pod restart to take place | ||
|
|
||
| ### Uninstall the Chart | ||
| ```sh | ||
| helm uninstall headplane | ||
| ``` | ||
|
|
||
| ## Values | ||
|
|
||
| | Key | Type | Default | Description | | ||
| |-----|------|---------|-------------| | ||
| {{- range .Values }} | ||
| | {{ .Key }} | {{ .Type }} | {{ .Default }} | {{ .Description }} | | ||
| {{- end }} | ||
|
|
||
| ### OIDC Configuration | ||
|
|
||
| To use OIDC, you must provide the OIDC client secrets via Kubernetes secret: | ||
|
|
||
| ```sh | ||
| kubectl create secret generic oidc-secrets \ | ||
| --from-literal=HEADPLANE_OIDC__CLIENT_SECRET=your-headplane-oidc-client-secret \ | ||
| --from-literal=HEADPLANE_OIDC__CLIENT_ID=your-headplane-oidc-client-id \ | ||
| --from-literal=HEADSCALE_OIDC__CLIENT_SECRET=your-headscale-oidc-client-secret \ | ||
| --from-literal=HEADSCALE_OIDC__CLIENT_ID=your-headscale-oidc-client-id \ | ||
| -n <namespace> | ||
| ``` | ||
|
|
||
| Then enable OIDC in your `values.yaml`: | ||
| ```yaml | ||
| headplane: | ||
| oidc: | ||
| enabled: true | ||
| issuer: "https://your-oidc-issuer-url.com" | ||
| redirect_uri: "https://your-headplane-admin-domain.com/admin/oidc/callback" | ||
| secret_name: "oidc-secrets" # Name of your OIDC secret | ||
|
|
||
| headscale: | ||
| oidc: | ||
| enabled: true | ||
| issuer: "https://your-oidc-issuer.com" | ||
| secret_name: "oidc-secrets" # Same secret as Headplane | ||
| ``` | ||
|
|
||
| You can add any additional environment variables by creating more secrets or config-maps and adding them to the `envFrom` section. For example, to add custom configuration: | ||
|
|
||
| ```sh | ||
| kubectl create secret generic headplane-custom-config \ | ||
| --from-literal=CUSTOM_VAR=value \ | ||
| --from-literal=ANOTHER_VAR=another-value \ | ||
| -n <namespace> | ||
| ``` | ||
|
|
||
| Then add it to your values: | ||
| ```yaml | ||
| headplane: | ||
| envFrom: | ||
| - secretRef: | ||
| name: headplane-custom-config | ||
| ``` | ||
|
|
||
| Note: Make sure to keep your secrets secure and never commit them to version control. | ||
| Consider using a secrets management solution in production like external-secrets. | ||
|
|
||
| ## License | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same concerns as earlier |
||
| Copyright © 2025 antoniolago | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: | ||
|
|
||
| ``` | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| ``` | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| {{/* | ||
| Generate a random cookie secret if none is provided | ||
| */}} | ||
| {{- define "headplane.cookieSecret" -}} | ||
| {{- if and .Values.headplane.secret .Values.headplane.secret.server (hasKey .Values.headplane.secret.server "cookie_secret") .Values.headplane.secret.server.cookie_secret -}} | ||
| {{- .Values.headplane.secret.server.cookie_secret -}} | ||
| {{- else -}} | ||
| {{- randAlphaNum 32 -}} | ||
| {{- end -}} | ||
| {{- end -}} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| --- | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: headplane-config | ||
| data: | ||
| config.yaml: | | ||
| server: | ||
| {{- toYaml .Values.headplane.config.server | nindent 6 }} | ||
| cookie_secret: {{ include "headplane.cookieSecret" . | quote }} | ||
| headscale: | ||
| {{- toYaml .Values.headplane.config.headscale | nindent 6 }} | ||
| integration: | ||
| {{- toYaml .Values.headplane.config.integration | nindent 6 }} | ||
| # only add oidc if .Values.headplane.config.oidc is set | ||
| {{- if .Values.headplane.config.oidc.enabled }} | ||
| oidc: | ||
| issuer: {{ .Values.headplane.config.oidc.issuer | quote }} | ||
| disable_api_key_login: {{ .Values.headplane.config.oidc.disable_api_key_login | quote }} | ||
| token_endpoint_auth_method: {{ .Values.headplane.config.oidc.token_endpoint_auth_method | quote }} | ||
| redirect_uri: {{ .Values.headplane.config.oidc.redirect_uri | quote }} | ||
| client_id: {{ .Values.headplane.config.oidc.client_id | quote }} | ||
| {{- end }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| {{- if .Values.headscale.acl }} | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: headscale-acl | ||
| labels: | ||
| app: headplane | ||
| data: | ||
| acl.hujson: |- | ||
| {{- .Values.headscale.acl | nindent 4 }} | ||
| {{- end }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: headscale-default-config | ||
| data: | ||
| config.yaml: | | ||
| {{- toYaml .Values.headscale.config | nindent 4 }} | ||
| {{- if .Values.headscale.config.oidc.enabled }} | ||
| oidc: | ||
| issuer: {{ .Values.headscale.config.oidc.issuer | quote }} | ||
| client_id: {{ .Values.headscale.config.oidc.client_id | quote }} | ||
| {{- if .Values.headscale.config.oidc.allowed_groups }} | ||
| allowed_groups: | ||
| {{- toYaml .Values.headscale.config.oidc.allowed_groups | nindent 8 }} | ||
| {{- end }} | ||
| {{- if .Values.headscale.config.oidc.allowed_domains }} | ||
| allowed_domains: | ||
| {{- toYaml .Values.headscale.config.oidc.allowed_domains | nindent 8 }} | ||
| {{- end }} | ||
| {{- if .Values.headscale.config.oidc.allowed_users }} | ||
| allowed_users: | ||
| {{- toYaml .Values.headscale.config.oidc.allowed_users | nindent 8 }} | ||
| {{- end }} | ||
| {{- end }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise a good overall PR, wondering why we're defaulting to the Harbor hosted instance, is there not a way to just pull it directly from the GitHub repository or publish a chart repository using GitHub pages?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use Harbor just because I like self-hosting stuff lol, no objections for creating a workflow to push this to another chart repository, maybe you can setup a workflow based on this one: https://github.com/antoniolago/headplane-chart/blob/main/.github/workflows/publish-helm-chart.yml (tests are included in this PR already)