feat: TLS support for web (#301)

* Added TLS support for web

- Added optional configurations `cert_file` and `key_file` to run web server with https

Signed-off-by: Dmytro Bondar <git@bonddim.com>

* Helm chart update

- Refactored Ingress to use one host only (`config.web.external_url` is required)
- Added Certificate resource template (secret is mounted to container into `/app/certs/`)
- Added support for service with mixed protocols (exposes UI and Wireguard ports on same IP)
- Added helm-docs target to makefile
- Changed pod labels to use selectorLabels
- Removed default probes (app runs without healthy web)
- Removed sections from README

Signed-off-by: Dmytro Bondar <git@bonddim.com>

* Fix chart workflow path filter

* Fix chart lint issue

* Skip clean-up tested chart

* Try k3d cluster

---------

Signed-off-by: Dmytro Bondar <git@bonddim.com>
This commit is contained in:
Dmytro Bondar 2024-09-22 13:25:08 +02:00 committed by GitHub
parent e3d05a4678
commit 6ffe1a90ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 289 additions and 274 deletions

View File

@ -10,10 +10,10 @@ name: Chart
on: on:
pull_request: pull_request:
branches: [master] branches: [master]
paths: [deploy/helm] paths: ['deploy/helm/**']
push: push:
branches: [master] branches: [master]
paths: [deploy/helm] paths: ['deploy/helm/**']
jobs: jobs:
lint-test: lint-test:
@ -24,6 +24,14 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Check docs
run: |
make helm-docs
if ! git diff --exit-code; then
echo "error::Documentation is not up to date. Please run helm-docs and commit changes."
exit 1
fi
# ct lint requires Python 3.x to run following packages: # ct lint requires Python 3.x to run following packages:
# - yamale (https://github.com/23andMe/Yamale) # - yamale (https://github.com/23andMe/Yamale)
# - yamllint (https://github.com/adrienverge/yamllint) # - yamllint (https://github.com/adrienverge/yamllint)
@ -36,15 +44,9 @@ jobs:
- name: Run chart-testing (lint) - name: Run chart-testing (lint)
run: ct lint --config ct.yaml run: ct lint --config ct.yaml
- name: Check docs - uses: nolar/setup-k3d-k3s@v1
run: | with:
docker run --rm --volume "${PWD}/deploy:/helm-docs" -u "$(id -u)" jnorwood/helm-docs github-token: ${{ secrets.GITHUB_TOKEN }}
if ! git diff --exit-code; then
echo "error::Documentation is not up to date. Please run helm-docs and commit changes."
exit 1
fi
- uses: helm/kind-action@v1
- name: Run chart-testing (install) - name: Run chart-testing (install)
run: ct install --config ct.yaml run: ct install --config ct.yaml

View File

@ -127,4 +127,9 @@ build-docker:
docker build --progress=plain \ docker build --progress=plain \
--build-arg BUILD_IDENTIFIER=${ENV_BUILD_IDENTIFIER} --build-arg BUILD_VERSION=${ENV_BUILD_VERSION} \ --build-arg BUILD_IDENTIFIER=${ENV_BUILD_IDENTIFIER} --build-arg BUILD_VERSION=${ENV_BUILD_VERSION} \
--build-arg TARGETPLATFORM=unknown . \ --build-arg TARGETPLATFORM=unknown . \
-t h44z/wg-portal:local -t h44z/wg-portal:local
#< helm-docs: Generate the helm chart documentation
.PHONY: helm-docs
helm-docs:
docker run --rm --volume "${PWD}/deploy:/helm-docs" -u "$$(id -u)" jnorwood/helm-docs -s file

View File

@ -142,7 +142,8 @@ The following configuration options are available:
| csrf_secret | web | extremely_secret | The CSRF secret. | | csrf_secret | web | extremely_secret | The CSRF secret. |
| site_title | web | WireGuard Portal | The title that is shown in the web frontend. | | site_title | web | WireGuard Portal | The title that is shown in the web frontend. |
| site_company_name | web | WireGuard Portal | The company name that is shown at the bottom of the web frontend. | | site_company_name | web | WireGuard Portal | The company name that is shown at the bottom of the web frontend. |
| cert_file | web | | (Optional) Path to the TLS certificate file |
| key_file | web | | (Optional) Path to the TLS certificate key file |
## Upgrading from V1 ## Upgrading from V1

View File

@ -16,10 +16,10 @@ annotations:
# This is the chart version. This version number should be incremented each time you make changes # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0 version: 0.2.0
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: v2.0.0-alpha.2 appVersion: latest

View File

@ -1,6 +1,6 @@
# wg-portal # wg-portal
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.0.0-alpha.2](https://img.shields.io/badge/AppVersion-v2.0.0--alpha.2-informational?style=flat-square) ![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square)
WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication WireGuard Configuration Portal with LDAP, OAuth, OIDC authentication
@ -27,90 +27,80 @@ The [Values](#values) section lists the parameters that can be configured during
## Values ## Values
### Parameters
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | Affinity configuration |
| args | list | `[]` | Additional pod arguments |
| command | list | `[]` | Overwrite pod command |
| dnsPolicy | string | `"ClusterFirst"` | Set DNS policy for the pod. Valid values are `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. |
| env | tpl/list | `[]` | Additional environment variables |
| envFrom | tpl/list | `[]` | Additional environment variables from a secret or configMap |
| hostNetwork | string | `false`. | Use the host's network namespace. |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"ghcr.io/h44z/wg-portal"` | Image repository |
| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion |
| imagePullSecrets | list | `[]` | Image pull secrets |
| initContainers | tpl/list | `[]` | Pod init containers |
| nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node Selector configuration |
| podAnnotations | tpl/object | `{}` | Extra annotations to add to the pod |
| podLabels | object | `{}` | Extra labels to add to the pod |
| podSecurityContext | object | `{}` | Pod Security Context |
| resources | object | `{}` | Resources requests and limits |
| restartPolicy | string | `"Always"` | Restart policy for all containers within the pod. Valid values are `Always`, `OnFailure` or `Never`. |
| revisionHistoryLimit | string | `10` | The number of old ReplicaSets to retain to allow rollback. |
| securityContext.capabilities.add | list | `["NET_ADMIN"]` | Add capabilities to the container |
| sidecarContainers | tpl/list | `[]` | Pod sidecar containers |
| strategy | object | `{"type":"RollingUpdate"}` | Update strategy for the workload Valid values are: `RollingUpdate` or `Recreate` for Deployment, `RollingUpdate` or `OnDelete` for StatefulSet |
| tolerations | list | `[]` | Tolerations configuration |
| volumeMounts | tpl/list | `[]` | Additional volumeMounts |
| volumes | tpl/list | `[]` | Additional volumes |
| workloadType | string | `"Deployment"` | Workload type - `Deployment` or `StatefulSet` |
### Configuration
| Key | Type | Default | Description | | Key | Type | Default | Description |
|-----|------|---------|-------------| |-----|------|---------|-------------|
| nameOverride | string | `""` | Partially override resource names (adds suffix) |
| fullnameOverride | string | `""` | Fully override resource names |
| extraDeploy | list | `[]` | Array of extra objects to deploy with the release |
| config.advanced | tpl/object | `{}` | Advanced configuration options. | | config.advanced | tpl/object | `{}` | Advanced configuration options. |
| config.auth | tpl/object | `{}` | Auth configuration options. | | config.auth | tpl/object | `{}` | Auth configuration options. |
| config.core | tpl/object | `{}` | Core configuration options.<br> If external admins in `auth` are not defined and there are no `admin_user` and `admin_password` defined here, the default credentials will be generated. | | config.core | tpl/object | `{}` | Core configuration options.<br> If external admins in `auth` are not defined and there are no `admin_user` and `admin_password` defined here, the default credentials will be generated. |
| config.database | tpl/object | `{}` | Database configuration options | | config.database | tpl/object | `{}` | Database configuration options |
| config.mail | tpl/object | `{}` | Mail configuration options | | config.mail | tpl/object | `{}` | Mail configuration options |
| config.statistics | tpl/object | `{}` | Statistics configuration options | | config.statistics | tpl/object | `{}` | Statistics configuration options |
| config.web | tpl/object | `{}` | Web configuration options.<br> The chart will set `listening_address` automatically from `service.web.port`, and `external_url` from `ingress.host` if enabled. | | config.web | tpl/object | `{}` | Web configuration options.<br> `listening_address` will be set automatically from `service.web.port`. `external_url` is required to enable ingress and certificate resources. |
| revisionHistoryLimit | string | `10` | The number of old ReplicaSets to retain to allow rollback. |
### Common | workloadType | string | `"Deployment"` | Workload type - `Deployment` or `StatefulSet` |
| strategy | object | `{"type":"RollingUpdate"}` | Update strategy for the workload Valid values are: `RollingUpdate` or `Recreate` for Deployment, `RollingUpdate` or `OnDelete` for StatefulSet |
| Key | Type | Default | Description | | image.repository | string | `"ghcr.io/h44z/wg-portal"` | Image repository |
|-----|------|---------|-------------| | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| extraDeploy | list | `[]` | Array of extra objects to deploy with the release | | image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion |
| fullnameOverride | string | `""` | Fully override resource names | | imagePullSecrets | list | `[]` | Image pull secrets |
| nameOverride | string | `""` | Partially override resource names (adds suffix) | | podAnnotations | tpl/object | `{}` | Extra annotations to add to the pod |
| podLabels | object | `{}` | Extra labels to add to the pod |
### Traffic exposure | podSecurityContext | object | `{}` | Pod Security Context |
| securityContext.capabilities.add | list | `["NET_ADMIN"]` | Add capabilities to the container |
| Key | Type | Default | Description | | initContainers | tpl/list | `[]` | Pod init containers |
|-----|------|---------|-------------| | sidecarContainers | tpl/list | `[]` | Pod sidecar containers |
| ingress.annotations | object | `{}` | Ingress annotations | | dnsPolicy | string | `"ClusterFirst"` | Set DNS policy for the pod. Valid values are `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. |
| ingress.className | string | `""` | Ingress class name | | restartPolicy | string | `"Always"` | Restart policy for all containers within the pod. Valid values are `Always`, `OnFailure` or `Never`. |
| ingress.enabled | bool | `false` | Specifies whether an ingress resource should be created | | hostNetwork | string | `false`. | Use the host's network namespace. |
| ingress.host | string | `""` | Ingress host FQDN | | resources | object | `{}` | Resources requests and limits |
| ingress.path | string | `"/"` | Ingress path | | command | list | `[]` | Overwrite pod command |
| ingress.pathType | string | `"ImplementationSpecific"` | Ingress path type | | args | list | `[]` | Additional pod arguments |
| ingress.tls | list | `[]` | Ingress TLS configuration | | env | tpl/list | `[]` | Additional environment variables |
| envFrom | tpl/list | `[]` | Additional environment variables from a secret or configMap |
| livenessProbe | object | `{}` | Liveness probe configuration |
| readinessProbe | object | `{}` | Readiness probe configuration |
| startupProbe | object | `{}` | Startup probe configuration |
| volumes | tpl/list | `[]` | Additional volumes |
| volumeMounts | tpl/list | `[]` | Additional volumeMounts |
| nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node Selector configuration |
| tolerations | list | `[]` | Tolerations configuration |
| affinity | object | `{}` | Affinity configuration |
| service.mixed.enabled | bool | `false` | Whether to create a single service for the web and wireguard interfaces |
| service.mixed.type | string | `"LoadBalancer"` | Service type |
| service.web.annotations | object | `{}` | Annotations for the web service | | service.web.annotations | object | `{}` | Annotations for the web service |
| service.web.port | int | `8888` | Web service port Used for the web interface listener |
| service.web.type | string | `"ClusterIP"` | Web service type | | service.web.type | string | `"ClusterIP"` | Web service type |
| service.web.port | int | `8888` | Web service port Used for the web interface listener |
| service.wireguard.annotations | object | `{}` | Annotations for the WireGuard service | | service.wireguard.annotations | object | `{}` | Annotations for the WireGuard service |
| service.wireguard.ports | list | `[51820]` | Wireguard service ports. Exposes the WireGuard ports for created interfaces. Lowerest port is selected as start port for the first interface. Increment next port by 1 for each additional interface. |
| service.wireguard.type | string | `"LoadBalancer"` | Wireguard service type | | service.wireguard.type | string | `"LoadBalancer"` | Wireguard service type |
| service.wireguard.ports | list | `[51820]` | Wireguard service ports. Exposes the WireGuard ports for created interfaces. Lowerest port is selected as start port for the first interface. Increment next port by 1 for each additional interface. |
### Persistence | ingress.enabled | bool | `false` | Specifies whether an ingress resource should be created |
| ingress.className | string | `""` | Ingress class name |
| Key | Type | Default | Description | | ingress.annotations | object | `{}` | Ingress annotations |
|-----|------|---------|-------------| | ingress.tls | bool | `false` | Ingress TLS configuration. Enable certificate resource or add ingress annotation to create required secret |
| persistence.accessMode | string | `"ReadWriteOnce"` | Persistent Volume Access Mode | | certificate.enabled | bool | `false` | Specifies whether a certificate resource should be created |
| persistence.annotations | object | `{}` | Persistent Volume Claim annotations | | certificate.issuer.name | string | `""` | Certificate issuer name |
| certificate.issuer.kind | string | `""` | Certificate issuer kind (ClusterIssuer or Issuer) |
| certificate.issuer.group | string | `"cert-manager.io"` | Certificate issuer group |
| certificate.duration | string | `""` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.renewBefore | string | `""` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.commonName | string | `""` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.emailAddresses | list | `[]` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.ipAddresses | list | `[]` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.keystores | object | `{}` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.privateKey | object | `{}` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.secretTemplate | object | `{}` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.subject | object | `{}` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.uris | list | `[]` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| certificate.usages | list | `[]` | Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources) |
| persistence.enabled | bool | `false` | Specifies whether an persistent volume should be created | | persistence.enabled | bool | `false` | Specifies whether an persistent volume should be created |
| persistence.size | string | `"1Gi"` | Persistent Volume size | | persistence.annotations | object | `{}` | Persistent Volume Claim annotations |
| persistence.storageClass | string | `""` | Persistent Volume storage class. If undefined (the default) cluster's default provisioner will be used. | | persistence.storageClass | string | `""` | Persistent Volume storage class. If undefined (the default) cluster's default provisioner will be used. |
| persistence.accessMode | string | `"ReadWriteOnce"` | Persistent Volume Access Mode |
### RBAC | persistence.size | string | `"1Gi"` | Persistent Volume size |
| serviceAccount.create | bool | `true` | Specifies whether a service account should be created |
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| serviceAccount.annotations | object | `{}` | Service account annotations | | serviceAccount.annotations | object | `{}` | Service account annotations |
| serviceAccount.automount | bool | `false` | Automatically mount a ServiceAccount's API credentials | | serviceAccount.automount | bool | `false` | Automatically mount a ServiceAccount's API credentials |
| serviceAccount.create | bool | `true` | Specifies whether a service account should be created |
| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template |

View File

@ -98,3 +98,12 @@ resources:
requests: requests:
storage: {{ .Values.persistence.size | quote }} storage: {{ .Values.persistence.size | quote }}
{{- end -}} {{- end -}}
{{/*
Define hostname
*/}}
{{- define "wg-portal.hostname" -}}
{{- if .Values.config.web.external_url -}}
{{- (urlParse (tpl .Values.config.web.external_url .)).hostname -}}
{{- end -}}
{{- end -}}

View File

@ -7,7 +7,7 @@ metadata:
{{- tpl (toYaml .) $ | nindent 4 }} {{- tpl (toYaml .) $ | nindent 4 }}
{{- end }} {{- end }}
labels: labels:
{{- include "wg-portal.labels" . | nindent 4 }} {{- include "wg-portal.selectorLabels" . | nindent 4 }}
{{- with .Values.podLabels }} {{- with .Values.podLabels }}
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
@ -36,7 +36,7 @@ spec:
envFrom: {{- tpl (toYaml .) $ | nindent 8 }} envFrom: {{- tpl (toYaml .) $ | nindent 8 }}
{{- end }} {{- end }}
ports: ports:
- name: http - name: web
containerPort: {{ .Values.service.web.port }} containerPort: {{ .Values.service.web.port }}
protocol: TCP protocol: TCP
{{- range $index, $port := .Values.service.wireguard.ports }} {{- range $index, $port := .Values.service.wireguard.ports }}
@ -65,6 +65,10 @@ spec:
readOnly: true readOnly: true
- name: data - name: data
mountPath: /app/data mountPath: /app/data
{{- if and .Values.certificate.enabled (include "wg-portal.hostname" .) }}
- name: certs
mountPath: /app/certs
{{- end }}
{{- with .Values.volumeMounts }} {{- with .Values.volumeMounts }}
{{- tpl (toYaml .) $ | nindent 8 }} {{- tpl (toYaml .) $ | nindent 8 }}
{{- end }} {{- end }}
@ -97,6 +101,11 @@ spec:
- name: config - name: config
secret: secret:
secretName: {{ include "wg-portal.fullname" . }} secretName: {{ include "wg-portal.fullname" . }}
{{- if and .Values.certificate.enabled (include "wg-portal.hostname" .) }}
- name: certs
secret:
secretName: {{ include "wg-portal.fullname" . }}-tls
{{- end }}
{{- if not .Values.persistence.enabled }} {{- if not .Values.persistence.enabled }}
- name: data - name: data
emptyDir: {} emptyDir: {}

View File

@ -0,0 +1,53 @@
{{/*
Define the service template
{{- include "wg-portal.service" (dict "context" $ "scope" .Values.service.<name> "ports" list "name" "<name>") -}}
*/}}
{{- define "wg-portal.service.tpl" -}}
apiVersion: v1
kind: Service
metadata:
{{- with .scope.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
labels: {{- include "wg-portal.labels" .context | nindent 4 }}
name: {{ include "wg-portal.fullname" .context }}{{ ternary "" (printf "-%s" .name) (empty .name) }}
spec:
{{- with .scope.clusterIP }}
clusterIP: {{ . }}
{{- end }}
{{- with .scope.externalIPs }}
externalIPs: {{ toYaml . | nindent 4 }}
{{- end }}
{{- with .scope.externalName }}
externalName: {{ . }}
{{- end }}
{{- with .scope.externalTrafficPolicy }}
externalTrafficPolicy: {{ . }}
{{- end }}
{{- with .scope.healthCheckNodePort }}
healthCheckNodePort: {{ . }}
{{- end }}
{{- with .scope.loadBalancerIP }}
loadBalancerIP: {{ . }}
{{- end }}
{{- with .scope.loadBalancerSourceRanges }}
loadBalancerSourceRanges: {{ toYaml . | nindent 4 }}
{{- end }}
ports: {{- toYaml .ports | nindent 4 }}
{{- with .scope.publishNotReadyAddresses }}
publishNotReadyAddresses: {{ . }}
{{- end }}
{{- with .scope.sessionAffinity }}
sessionAffinity: {{ . }}
{{- end }}
{{- with .scope.sessionAffinityConfig }}
sessionAffinityConfig: {{ toYaml . | nindent 4 }}
{{- end }}
{{- with .scope.topologyKeys }}
topologyKeys: {{ toYaml . | nindent 4 }}
{{- end }}
{{- with .scope.type }}
type: {{ . }}
{{- end }}
selector: {{- include "wg-portal.selectorLabels" .context | nindent 4 }}
{{- end -}}

View File

@ -0,0 +1,54 @@
{{/* https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources */}}
{{- if and .Values.certificate.enabled (include "wg-portal.hostname" .) -}}
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
secretName: {{ include "wg-portal.fullname" . }}-tls
{{- with .Values.certificate.secretTemplate }}
secretTemplate: {{ toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.privateKey }}
privateKey: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.keystores }}
keystores: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.duration }}
duration: {{ . }}
{{- end }}
{{- with .Values.certificate.renewBefore }}
renewBefore: {{ . }}
{{- end }}
{{- with .Values.certificate.usages }}
usages: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.subject }}
subject: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.commonName }}
commonName: {{ . }}
{{- end }}
dnsNames:
- {{ include "wg-portal.hostname" . }}
{{- with .Values.certificate.uris }}
uris: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.emailAddresses }}
emailAddresses: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.ipAddresses }}
ipAddresses: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.otherNames }}
otherNames: {{- toYaml . | nindent 4 }}
{{- end }}
issuerRef:
{{- with .Values.certificate.issuer.group }}
group: {{ . }}
{{- end }}
kind: {{ .Values.certificate.issuer.kind }}
name: {{ .Values.certificate.issuer.name }}
{{- end -}}

View File

@ -1,4 +1,5 @@
{{- if .Values.ingress.enabled -}} {{- $hostname := include "wg-portal.hostname" . -}}
{{- if and .Values.ingress.enabled $hostname -}}
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
@ -10,38 +11,20 @@ metadata:
spec: spec:
ingressClassName: {{ .Values.ingress.className }} ingressClassName: {{ .Values.ingress.className }}
rules: rules:
- host: {{ .Values.ingress.host }} - host: {{ $hostname }}
http: http:
paths: paths:
- path: / - path: {{ default "/" (urlParse (tpl .Values.config.web.external_url .)).path }}
pathType: {{ default "ImplementationSpecific" .pathType }} pathType: {{ default "ImplementationSpecific" .pathType }}
backend: backend:
service: service:
name: {{ include "wg-portal.fullname" . }}-web name: {{ include "wg-portal.fullname" . }}
port: port:
name: http name: web
{{- range .Values.ingress.extraHosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ default "ImplementationSpecific" .pathType }}
backend:
service:
name: {{ include "wg-portal.fullname" . }}-web
port:
name: http
{{- end }}
{{- end }}
{{- if .Values.ingress.tls }} {{- if .Values.ingress.tls }}
tls: tls:
{{- range .Values.ingress.tls }}
- hosts: - hosts:
{{- range .hosts }} - {{ $hostname | quote }}
- {{ . | quote }} secretName: {{ include "wg-portal.fullname" . }}-tls
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}

View File

@ -32,10 +32,6 @@ stringData:
{{- end }} {{- end }}
web: web:
listening_address: :{{ .Values.service.web.port }} listening_address: :{{ .Values.service.web.port }}
{{- if and .Values.ingress.enabled (not (hasKey .Values.config.web "external_url")) }}
{{- $proto := ternary "http" "https" (empty .Values.ingress.tls) }}
external_url: {{ trimSuffix "/" (printf "%s://%s%s" $proto .Values.ingress.host .Values.ingress.path) }}
{{- end }}
{{- with .Values.config.web }} {{- with .Values.config.web }}
{{- tpl (toYaml (omit . "listening_address")) $ | nindent 6 }} {{- tpl (toYaml (omit . "listening_address")) $ | nindent 6 }}
{{- end }} {{- end }}

View File

@ -1,16 +0,0 @@
apiVersion: v1
kind: Service
metadata:
{{- with .Values.service.web.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "wg-portal.fullname" . }}-web
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
ports:
- port: {{ .Values.service.web.port }}
targetPort: http
protocol: TCP
name: http
selector: {{- include "wg-portal.selectorLabels" . | nindent 4 }}
type: {{ .Values.service.web.type }}

View File

@ -1,27 +0,0 @@
apiVersion: v1
kind: Service
metadata:
{{- with .Values.service.wireguard.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "wg-portal.fullname" . }}-wireguard
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
{{- with .Values.service.wireguard.externalTrafficPolicy }}
externalTrafficPolicy: {{ . }}
{{- end }}
{{- with .Values.service.wireguard.loadBalancerSourceRanges }}
loadBalancerSourceRanges: {{- toYaml . | nindent 4 }}
{{- end }}
ports:
{{- range $index, $port := .Values.service.wireguard.ports }}
- port: {{ $port }}
targetPort: wg{{ $index }}
protocol: UDP
name: wg{{ $index }}
{{- end }}
selector: {{- include "wg-portal.selectorLabels" . | nindent 4 }}
{{- with .Values.service.wireguard.sessionAffinity }}
sessionAffinity: {{ . }}
{{- end }}
type: {{ .Values.service.wireguard.type }}

View File

@ -0,0 +1,14 @@
{{- $portsWeb := list (dict "name" "web" "port" .Values.service.web.port "protocol" "TCP" "targetPort" "web") -}}
{{- $ports := list -}}
{{- range $idx, $port := .Values.service.wireguard.ports -}}
{{- $name := printf "wg%d" $idx -}}
{{- $ports = append $ports (dict "name" $name "port" $port "protocol" "UDP" "targetPort" $name) -}}
{{- end -}}
{{- if .Values.service.mixed.enabled -}}
{{ include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.mixed "ports" (concat $portsWeb $ports)) }}
{{- else }}
{{ include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.web "ports" $portsWeb) }}
---
{{ include "wg-portal.service.tpl" (dict "context" . "scope" .Values.service.wireguard "ports" $ports "name" "wireguard") }}
{{- end -}}

View File

@ -3,267 +3,202 @@
# Declare variables to be passed into your templates. # Declare variables to be passed into your templates.
# -- Partially override resource names (adds suffix) # -- Partially override resource names (adds suffix)
# @section -- Common
nameOverride: '' nameOverride: ''
# -- Fully override resource names # -- Fully override resource names
# @section -- Common
fullnameOverride: '' fullnameOverride: ''
# -- Array of extra objects to deploy with the release # -- Array of extra objects to deploy with the release
# @section -- Common
extraDeploy: [] extraDeploy: []
# https://github.com/h44z/wg-portal/blob/master/README.md#configuration-options # https://github.com/h44z/wg-portal/blob/master/README.md#configuration-options
config: config:
# -- (tpl/object) Advanced configuration options. # -- (tpl/object) Advanced configuration options.
# @section -- Configuration
advanced: {} advanced: {}
# -- (tpl/object) Auth configuration options. # -- (tpl/object) Auth configuration options.
# @section -- Configuration
auth: {} auth: {}
# -- (tpl/object) Core configuration options.<br> # -- (tpl/object) Core configuration options.<br>
# @section -- Configuration
# If external admins in `auth` are not defined and # If external admins in `auth` are not defined and
# there are no `admin_user` and `admin_password` defined here, # there are no `admin_user` and `admin_password` defined here,
# the default credentials will be generated. # the default credentials will be generated.
core: {} core: {}
# -- (tpl/object) Database configuration options # -- (tpl/object) Database configuration options
# @section -- Configuration
database: {} database: {}
# -- (tpl/object) Mail configuration options # -- (tpl/object) Mail configuration options
# @section -- Configuration
mail: {} mail: {}
# -- (tpl/object) Statistics configuration options # -- (tpl/object) Statistics configuration options
# @section -- Configuration
statistics: {} statistics: {}
# -- (tpl/object) Web configuration options.<br> # -- (tpl/object) Web configuration options.<br>
# @section -- Configuration # `listening_address` will be set automatically from `service.web.port`.
# The chart will set `listening_address` automatically from `service.web.port`, # `external_url` is required to enable ingress and certificate resources.
# and `external_url` from `ingress.host` if enabled.
web: {} web: {}
# -- The number of old ReplicaSets to retain to allow rollback. # -- The number of old ReplicaSets to retain to allow rollback.
# @section -- Parameters
# @default -- `10` # @default -- `10`
revisionHistoryLimit: '' revisionHistoryLimit: ''
# -- Workload type - `Deployment` or `StatefulSet` # -- Workload type - `Deployment` or `StatefulSet`
# @section -- Parameters
workloadType: Deployment workloadType: Deployment
# -- Update strategy for the workload # -- Update strategy for the workload
# Valid values are: # Valid values are:
# `RollingUpdate` or `Recreate` for Deployment, # `RollingUpdate` or `Recreate` for Deployment,
# `RollingUpdate` or `OnDelete` for StatefulSet # `RollingUpdate` or `OnDelete` for StatefulSet
# @section -- Parameters
strategy: strategy:
type: RollingUpdate type: RollingUpdate
image: image:
# -- Image repository # -- Image repository
# @section -- Parameters
repository: ghcr.io/h44z/wg-portal repository: ghcr.io/h44z/wg-portal
# -- Image pull policy # -- Image pull policy
# @section -- Parameters
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
# -- Overrides the image tag whose default is the chart appVersion # -- Overrides the image tag whose default is the chart appVersion
# @section -- Parameters
tag: '' tag: ''
# -- Image pull secrets # -- Image pull secrets
# @section -- Parameters
imagePullSecrets: [] imagePullSecrets: []
# -- (tpl/object) Extra annotations to add to the pod # -- (tpl/object) Extra annotations to add to the pod
# @section -- Parameters
podAnnotations: {} podAnnotations: {}
# -- Extra labels to add to the pod # -- Extra labels to add to the pod
# @section -- Parameters
podLabels: {} podLabels: {}
# -- Pod Security Context # -- Pod Security Context
# @section -- Parameters
podSecurityContext: {} podSecurityContext: {}
# Container Security Context # Container Security Context
securityContext: securityContext:
capabilities: capabilities:
# -- Add capabilities to the container # -- Add capabilities to the container
# @section -- Parameters
add: add:
- NET_ADMIN - NET_ADMIN
# -- (tpl/list) Pod init containers # -- (tpl/list) Pod init containers
# @section -- Parameters
initContainers: [] initContainers: []
# -- (tpl/list) Pod sidecar containers # -- (tpl/list) Pod sidecar containers
# @section -- Parameters
sidecarContainers: [] sidecarContainers: []
# -- Set DNS policy for the pod. # -- Set DNS policy for the pod.
# Valid values are `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. # Valid values are `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`.
# @default -- `"ClusterFirst"` # @default -- `"ClusterFirst"`
# @section -- Parameters
dnsPolicy: '' dnsPolicy: ''
# -- Restart policy for all containers within the pod. # -- Restart policy for all containers within the pod.
# Valid values are `Always`, `OnFailure` or `Never`. # Valid values are `Always`, `OnFailure` or `Never`.
# @default -- `"Always"` # @default -- `"Always"`
# @section -- Parameters
restartPolicy: '' restartPolicy: ''
# -- Use the host's network namespace. # -- Use the host's network namespace.
# @default -- `false`. # @default -- `false`.
# @section -- Parameters
hostNetwork: '' hostNetwork: ''
# -- Resources requests and limits # -- Resources requests and limits
# @section -- Parameters
resources: {} resources: {}
# -- Overwrite pod command # -- Overwrite pod command
# @section -- Parameters
command: [] command: []
# -- Additional pod arguments # -- Additional pod arguments
# @section -- Parameters
args: [] args: []
# -- (tpl/list) Additional environment variables # -- (tpl/list) Additional environment variables
# @section -- Parameters
env: [] env: []
# -- (tpl/list) Additional environment variables from a secret or configMap # -- (tpl/list) Additional environment variables from a secret or configMap
# @section -- Parameters
envFrom: [] envFrom: []
# -- Liveness probe configuration # -- Liveness probe configuration
# @ignore livenessProbe: {}
livenessProbe:
failureThreshold: 10
httpGet:
path: /
port: http
# -- Readiness probe configuration # -- Readiness probe configuration
# @ignore readinessProbe: {}
readinessProbe:
httpGet:
path: /
port: http
# -- Startup probe configuration # -- Startup probe configuration
# @ignore startupProbe: {}
startupProbe:
initialDelaySeconds: 5
failureThreshold: 10
httpGet:
path: /
port: http
scheme: HTTP
# -- (tpl/list) Additional volumes # -- (tpl/list) Additional volumes
# @section -- Parameters
volumes: [] volumes: []
# -- (tpl/list) Additional volumeMounts # -- (tpl/list) Additional volumeMounts
# @section -- Parameters
volumeMounts: [] volumeMounts: []
# -- Node Selector configuration # -- Node Selector configuration
# @section -- Parameters
nodeSelector: nodeSelector:
kubernetes.io/os: linux kubernetes.io/os: linux
# -- Tolerations configuration # -- Tolerations configuration
# @section -- Parameters
tolerations: [] tolerations: []
# -- Affinity configuration # -- Affinity configuration
# @section -- Parameters
affinity: {} affinity: {}
service: service:
mixed:
# -- Whether to create a single service for the web and wireguard interfaces
enabled: false
# -- Service type
type: LoadBalancer
web: web:
# -- Annotations for the web service # -- Annotations for the web service
# @section -- Traffic exposure
annotations: {} annotations: {}
# -- Web service type # -- Web service type
# @section -- Traffic exposure
type: ClusterIP type: ClusterIP
# -- Web service port # -- Web service port
# Used for the web interface listener # Used for the web interface listener
# @section -- Traffic exposure
port: 8888 port: 8888
wireguard: wireguard:
# -- Annotations for the WireGuard service # -- Annotations for the WireGuard service
# @section -- Traffic exposure
annotations: {} annotations: {}
# -- Wireguard service type # -- Wireguard service type
# @section -- Traffic exposure
type: LoadBalancer type: LoadBalancer
# -- Wireguard service ports. # -- Wireguard service ports.
# Exposes the WireGuard ports for created interfaces. # Exposes the WireGuard ports for created interfaces.
# Lowerest port is selected as start port for the first interface. # Lowerest port is selected as start port for the first interface.
# Increment next port by 1 for each additional interface. # Increment next port by 1 for each additional interface.
# @section -- Traffic exposure
ports: ports:
- 51820 - 51820
ingress: ingress:
# -- Specifies whether an ingress resource should be created # -- Specifies whether an ingress resource should be created
# @section -- Traffic exposure
enabled: false enabled: false
# -- Ingress class name # -- Ingress class name
# @section -- Traffic exposure
className: '' className: ''
# -- Ingress annotations # -- Ingress annotations
# @section -- Traffic exposure
# @section -- Traffic exposure
annotations: {} annotations: {}
# -- Ingress host FQDN # -- Ingress TLS configuration.
# @section -- Traffic exposure # Enable certificate resource or add ingress annotation to create required secret
host: '' tls: false
# -- Ingress path type
# @section -- Traffic exposure certificate:
pathType: ImplementationSpecific # -- Specifies whether a certificate resource should be created
# -- Ingress path enabled: false
# @section -- Traffic exposure issuer:
path: / # -- Certificate issuer name
# -- Ingress TLS configuration name: ''
# @section -- Traffic exposure # -- Certificate issuer kind (ClusterIssuer or Issuer)
tls: [] kind: ''
# - secretName: wg-portal-example-tls # -- Certificate issuer group
# hosts: group: cert-manager.io
# - wg-portal.example.local # -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
duration: ''
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
renewBefore: ''
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
commonName: ''
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
emailAddresses: []
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
ipAddresses: []
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
keystores: {}
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
privateKey: {}
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
secretTemplate: {}
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
subject: {}
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
uris: []
# -- Optional. [Documentation](https://cert-manager.io/docs/usage/certificate/#creating-certificate-resources)
usages: []
persistence: persistence:
# -- Specifies whether an persistent volume should be created # -- Specifies whether an persistent volume should be created
# @section -- Persistence
enabled: false enabled: false
# -- Persistent Volume Claim annotations # -- Persistent Volume Claim annotations
# @section -- Persistence
annotations: {} annotations: {}
# -- Persistent Volume storage class. # -- Persistent Volume storage class.
# If undefined (the default) cluster's default provisioner will be used. # If undefined (the default) cluster's default provisioner will be used.
# @section -- Persistence
storageClass: '' storageClass: ''
# -- Persistent Volume Access Mode # -- Persistent Volume Access Mode
# @section -- Persistence
accessMode: ReadWriteOnce accessMode: ReadWriteOnce
# -- Persistent Volume size # -- Persistent Volume size
# @section -- Persistence
size: 1Gi size: 1Gi
serviceAccount: serviceAccount:
# -- Specifies whether a service account should be created # -- Specifies whether a service account should be created
# @section -- RBAC
create: true create: true
# -- Service account annotations # -- Service account annotations
# @section -- RBAC
annotations: {} annotations: {}
# -- Automatically mount a ServiceAccount's API credentials # -- Automatically mount a ServiceAccount's API credentials
# @section -- RBAC
automount: false automount: false
# -- The name of the service account to use. # -- The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template # If not set and create is true, a name is generated using the fullname template
# @section -- RBAC
name: '' name: ''

View File

@ -68,8 +68,7 @@ func NewServer(cfg *config.Config, endpoints ...ApiEndpointSetupFunc) (*Server,
c.Writer.Header().Set("X-Served-By", hostname) c.Writer.Header().Set("X-Served-By", hostname)
c.Next() c.Next()
}).Use(func(c *gin.Context) { }).Use(func(c *gin.Context) {
var xRequestID string xRequestID := uuid(16)
xRequestID = uuid(16)
c.Request.Header.Set(RequestIDKey, xRequestID) c.Request.Header.Set(RequestIDKey, xRequestID)
c.Set(RequestIDKey, xRequestID) c.Set(RequestIDKey, xRequestID)
@ -106,7 +105,13 @@ func (s *Server) Run(ctx context.Context, listenAddress string) {
srvContext, cancelFn := context.WithCancel(ctx) srvContext, cancelFn := context.WithCancel(ctx)
go func() { go func() {
if err := srv.ListenAndServe(); err != nil { var err error
if s.cfg.Web.CertFile != "" && s.cfg.Web.KeyFile != "" {
err = srv.ListenAndServeTLS(s.cfg.Web.CertFile, s.cfg.Web.KeyFile)
} else {
err = srv.ListenAndServe()
}
if err != nil {
logrus.Infof("web service on %s exited: %v", listenAddress, err) logrus.Infof("web service on %s exited: %v", listenAddress, err)
cancelFn() cancelFn()
} }

View File

@ -9,4 +9,6 @@ type WebConfig struct {
CsrfSecret string `yaml:"csrf_secret"` CsrfSecret string `yaml:"csrf_secret"`
SiteTitle string `yaml:"site_title"` SiteTitle string `yaml:"site_title"`
SiteCompanyName string `yaml:"site_company_name"` SiteCompanyName string `yaml:"site_company_name"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
} }