diff --git a/deployment/.github/workflows/release.yml b/deployment/.github/workflows/release.yml new file mode 100644 index 0000000..5da777d --- /dev/null +++ b/deployment/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Release Charts + +on: + push: + branches: + - main + +jobs: + release: + runs-on: [self-hosted, Linux, X64] + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.14.0 + + # https://github.com/helm/chart-releaser-action/issues/74 + - name: Add repositories + run: | + for dir in $(ls -d charts/*/); do + helm dependency list $dir 2> /dev/null | tail +2 | head -n -1 | awk '{ print "helm repo add " $1 " " $3 }' | while read cmd; do $cmd; done + done + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + with: + charts_dir: charts + skip_existing: true diff --git a/deployment/.github/workflows/test.yml b/deployment/.github/workflows/test.yml new file mode 100644 index 0000000..65a0a9a --- /dev/null +++ b/deployment/.github/workflows/test.yml @@ -0,0 +1,46 @@ +name: Test setup script + +on: + push: + branches: + - main + paths: + - 'docker-compose/**' + - '.github/workflows/test.yml' + +jobs: + test: + name: Test setup script + runs-on: [self-hosted, Linux] + steps: + - name: Login to GitHub container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Create working directory + run: mkdir temp + - name: Run setup script + env: + DEFGUARD_DOMAIN: "id.localhost" + DEFGUARD_ENROLLMENT_DOMAIN: "enrollment.localhost" + DEFGUARD_VPN_NAME: "test_location" + DEFGUARD_VPN_IP: "10.0.60.1/24" + DEFGUARD_VPN_GATEWAY_IP: "10.20.20.40" + DEFGUARD_VPN_GATEWAY_PORT: "50050" + CORE_IMAGE_TAG: latest + PROXY_IMAGE_TAG: latest + GATEWAY_IMAGE_TAG: latest + working-directory: temp + run: curl --proto '=https' --tlsv1.2 -sSf -L https://raw.githubusercontent.com/DefGuard/deployment/main/docker-compose/setup.sh | bash -s - --non-interactive + - name: Sleep for 10 seconds + working-directory: temp + run: sleep 10s + - name: Test defguard is available + working-directory: temp + run: curl -f http://id.localhost/api/v1/health + - name: Stop compose stack + if: always() + working-directory: temp + run: docker-compose down diff --git a/deployment/.gitignore b/deployment/.gitignore new file mode 100644 index 0000000..e5c0d50 --- /dev/null +++ b/deployment/.gitignore @@ -0,0 +1,3 @@ +docker-compose/.env +docker-compose/.volumes +.idea diff --git a/deployment/LICENSE b/deployment/LICENSE new file mode 100644 index 0000000..8ddd140 --- /dev/null +++ b/deployment/LICENSE @@ -0,0 +1,13 @@ +Copyright 2023 teonite ventures sp. z o.o. (teonite) + +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. diff --git a/deployment/README.md b/deployment/README.md new file mode 100644 index 0000000..8e6b830 --- /dev/null +++ b/deployment/README.md @@ -0,0 +1,16 @@ +

+ defguard +

+ +# Defguard deployment + +Check our [documentation](https://defguard.gitbook.io/defguard/features/setting-up-your-instance) for deployment +instructions. + +## Community and Support + +Find us on Matrix: [#defguard:teonite.com](https://matrix.to/#/#defguard:teonite.com) + +## Contribution + +Please review the [Contributing guide](https://defguard.gitbook.io/defguard/for-developers/contributing) for information on how to get started contributing to the project. You might also find our [environment setup guide](https://defguard.gitbook.io/defguard/for-developers/dev-env-setup) handy. diff --git a/deployment/charts/defguard-proxy/.helmignore b/deployment/charts/defguard-proxy/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deployment/charts/defguard-proxy/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deployment/charts/defguard-proxy/Chart.yaml b/deployment/charts/defguard-proxy/Chart.yaml new file mode 100644 index 0000000..61a06d9 --- /dev/null +++ b/deployment/charts/defguard-proxy/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: defguard-proxy +description: Defguard proxy is a public-facing proxy for core defguard service + +type: application +version: 0.3.5 +appVersion: 0.5.0 diff --git a/deployment/charts/defguard-proxy/templates/NOTES.txt b/deployment/charts/defguard-proxy/templates/NOTES.txt new file mode 100644 index 0000000..d8d21a5 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}/ +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "defguard-proxy.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "defguard-proxy.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "defguard-proxy.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "defguard-proxy.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/deployment/charts/defguard-proxy/templates/_helpers.tpl b/deployment/charts/defguard-proxy/templates/_helpers.tpl new file mode 100644 index 0000000..b6b625e --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "defguard-proxy.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "defguard-proxy.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "defguard-proxy.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "defguard-proxy.labels" -}} +helm.sh/chart: {{ include "defguard-proxy.chart" . }} +{{ include "defguard-proxy.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "defguard-proxy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "defguard-proxy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "defguard-proxy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "defguard-proxy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deployment/charts/defguard-proxy/templates/config.yaml b/deployment/charts/defguard-proxy/templates/config.yaml new file mode 100644 index 0000000..5efcad2 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/config.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "defguard-proxy.fullname" . }}-config + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} +data: + DEFGUARD_PROXY_HTTP_PORT: {{ .Values.service.ports.http | quote }} + DEFGUARD_PROXY_GRPC_PORT: {{ .Values.service.ports.grpc | quote }} diff --git a/deployment/charts/defguard-proxy/templates/deployment.yaml b/deployment/charts/defguard-proxy/templates/deployment.yaml new file mode 100644 index 0000000..4e6da60 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "defguard-proxy.fullname" . }} + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "defguard-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "defguard-proxy.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "defguard-proxy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + envFrom: + - configMapRef: + name: {{ include "defguard-proxy.fullname" . }}-config + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.ports.http }} + protocol: TCP + - name: grpc + containerPort: {{ .Values.service.ports.grpc }} + protocol: TCP + livenessProbe: + httpGet: + path: /api/v1/health + port: http + readinessProbe: + httpGet: + path: /api/v1/health + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deployment/charts/defguard-proxy/templates/grpc-service.yaml b/deployment/charts/defguard-proxy/templates/grpc-service.yaml new file mode 100644 index 0000000..b698b07 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/grpc-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + traefik.ingress.kubernetes.io/service.serversscheme: h2c + name: {{ include "defguard-proxy.fullname" . }}-grpc + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.ports.grpc }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + {{- include "defguard-proxy.selectorLabels" . | nindent 4 }} diff --git a/deployment/charts/defguard-proxy/templates/ingress-grpc.yaml b/deployment/charts/defguard-proxy/templates/ingress-grpc.yaml new file mode 100644 index 0000000..30fdc66 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/ingress-grpc.yaml @@ -0,0 +1,52 @@ +{{- if .Values.ingress.grpc.enabled -}} +{{- $fullName := include "defguard-proxy.fullname" . -}} +{{- if and .Values.ingress.grpc.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.grpc.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.grpc.annotations "kubernetes.io/ingress.class" .Values.ingress.grpc.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-grpc + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} + {{- with .Values.ingress.grpc.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.grpc.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.grpc.className }} + {{- end }} + {{- if .Values.ingress.grpc.tls }} + tls: + - hosts: + - {{ .Values.ingress.grpc.host | quote }} + secretName: {{ printf "%s-grpc-tls" .Values.ingress.grpc.host }} + {{- end }} + rules: + - host: {{ .Values.ingress.grpc.host | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: ImplementationSpecific + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-grpc + port: + number: {{ .Values.service.ports.grpc }} + {{- else }} + serviceName: {{ $fullName }}-grpc + servicePort: {{ .Values.service.ports.grpc }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard-proxy/templates/ingress-web.yaml b/deployment/charts/defguard-proxy/templates/ingress-web.yaml new file mode 100644 index 0000000..e13c124 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/ingress-web.yaml @@ -0,0 +1,52 @@ +{{- if .Values.ingress.web.enabled -}} +{{- $fullName := include "defguard-proxy.fullname" . -}} +{{- if and .Values.ingress.web.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.web.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.web.annotations "kubernetes.io/ingress.class" .Values.ingress.web.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-web + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} + {{- with .Values.ingress.web.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.web.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.web.className }} + {{- end }} + {{- if .Values.ingress.web.tls }} + tls: + - hosts: + - {{ .Values.ingress.web.host | quote }} + secretName: {{ printf "%s-web-tls" .Values.ingress.web.host }} + {{- end }} + rules: + - host: {{ .Values.ingress.web.host | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: ImplementationSpecific + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-web + port: + number: {{ .Values.service.ports.http }} + {{- else }} + serviceName: {{ $fullName }}-web + servicePort: {{ .Values.service.ports.http }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard-proxy/templates/service.yaml b/deployment/charts/defguard-proxy/templates/service.yaml new file mode 100644 index 0000000..151f128 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "defguard-proxy.fullname" . }}-web + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.ports.http }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "defguard-proxy.selectorLabels" . | nindent 4 }} diff --git a/deployment/charts/defguard-proxy/templates/serviceaccount.yaml b/deployment/charts/defguard-proxy/templates/serviceaccount.yaml new file mode 100644 index 0000000..a77a067 --- /dev/null +++ b/deployment/charts/defguard-proxy/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "defguard-proxy.serviceAccountName" . }} + labels: + {{- include "defguard-proxy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard-proxy/values.yaml b/deployment/charts/defguard-proxy/values.yaml new file mode 100644 index 0000000..02d3491 --- /dev/null +++ b/deployment/charts/defguard-proxy/values.yaml @@ -0,0 +1,42 @@ +affinity: {} +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 +fullnameOverride: "" +image: + pullPolicy: IfNotPresent + repository: ghcr.io/defguard/defguard-proxy + tag: "" +imagePullSecrets: [] +ingress: + grpc: + annotations: {} + className: "" + enabled: true + host: enrollment-grpc.local + tls: false + web: + annotations: {} + className: "" + enabled: true + host: enrollment.local + tls: false +nameOverride: "" +nodeSelector: {} +podAnnotations: {} +podLabels: {} +podSecurityContext: {} +publicUrl: "http://enrollment.local" +replicaCount: 1 +resources: {} +securityContext: {} +service: + ports: + http: 8080 + grpc: 50051 + type: ClusterIP +serviceAccount: + annotations: {} + create: true +tolerations: [] diff --git a/deployment/charts/defguard/.helmignore b/deployment/charts/defguard/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deployment/charts/defguard/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deployment/charts/defguard/Chart.lock b/deployment/charts/defguard/Chart.lock new file mode 100644 index 0000000..6a57515 --- /dev/null +++ b/deployment/charts/defguard/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 12.12.10 +- name: defguard-proxy + repository: https://defguard.github.io/deployment + version: 0.3.5 +digest: sha256:de930b480616cfa369caf7b1447c5b3e729fce3e17994717ab0f64aa02c027e7 +generated: "2024-07-26T09:00:54.309522115+02:00" diff --git a/deployment/charts/defguard/Chart.yaml b/deployment/charts/defguard/Chart.yaml new file mode 100644 index 0000000..9444933 --- /dev/null +++ b/deployment/charts/defguard/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: defguard +description: Defguard is an open-source enterprise wireGuard VPN with MFA and SSO + +type: application +version: 0.7.6 +appVersion: 0.11.0 + +dependencies: + - name: postgresql + condition: postgresql.enabled + version: 12.12.10 + repository: https://charts.bitnami.com/bitnami + - name: defguard-proxy + condition: defguard-proxy.enabled + version: 0.3.5 + repository: https://defguard.github.io/deployment diff --git a/deployment/charts/defguard/charts/defguard-proxy-0.3.5.tgz b/deployment/charts/defguard/charts/defguard-proxy-0.3.5.tgz new file mode 100644 index 0000000..830a28c Binary files /dev/null and b/deployment/charts/defguard/charts/defguard-proxy-0.3.5.tgz differ diff --git a/deployment/charts/defguard/charts/postgresql-12.12.10.tgz b/deployment/charts/defguard/charts/postgresql-12.12.10.tgz new file mode 100644 index 0000000..89bcc97 Binary files /dev/null and b/deployment/charts/defguard/charts/postgresql-12.12.10.tgz differ diff --git a/deployment/charts/defguard/templates/NOTES.txt b/deployment/charts/defguard/templates/NOTES.txt new file mode 100644 index 0000000..4550aad --- /dev/null +++ b/deployment/charts/defguard/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}/ +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "defguard.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "defguard.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "defguard.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "defguard.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/deployment/charts/defguard/templates/_helpers.tpl b/deployment/charts/defguard/templates/_helpers.tpl new file mode 100644 index 0000000..b373720 --- /dev/null +++ b/deployment/charts/defguard/templates/_helpers.tpl @@ -0,0 +1,78 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "defguard.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "defguard.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "defguard.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "defguard.labels" -}} +helm.sh/chart: {{ include "defguard.chart" . }} +{{ include "defguard.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "defguard.selectorLabels" -}} +app.kubernetes.io/name: {{ include "defguard.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "defguard.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "defguard.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Define OpenID secret name +*/}} +{{- define "defguard.openidSecretName" -}} +{{- $name := "openid-key" }} +{{- $name }} +{{- end }} + +{{/* +Define JWT secret name +*/}} +{{- define "defguard.jwtSecretName" -}} +{{- $name := "jwt-secrets" }} +{{- $name }} +{{- end }} diff --git a/deployment/charts/defguard/templates/defguard-config.yaml b/deployment/charts/defguard/templates/defguard-config.yaml new file mode 100644 index 0000000..b645b48 --- /dev/null +++ b/deployment/charts/defguard/templates/defguard-config.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "defguard.fullname" . }}-config + labels: + {{- include "defguard.labels" . | nindent 4 }} +data: + {{- if .Values.cookie.domain }} + DEFGUARD_COOKIE_DOMAIN: {{ .Values.cookie.domain }} + {{- end }} + DEFGUARD_COOKIE_INSECURE: {{ .Values.cookie.insecure | quote }} + DEFGUARD_DB_HOST: {{ .Values.postgresql.host | default (printf "%s-postgresql" (include "defguard.fullname" .)) }} + DEFGUARD_DB_PORT: {{ .Values.postgresql.port | quote}} + DEFGUARD_DB_NAME: {{ .Values.postgresql.auth.database }} + DEFGUARD_DB_USER: {{ .Values.postgresql.auth.username }} + DEFGUARD_GRPC_PORT: {{ .Values.service.ports.grpc | quote }} + DEFGUARD_ENROLLMENT_URL: {{ index .Values "defguard-proxy" "publicUrl" }} + {{- if .Values.proxyUrl }} + DEFGUARD_PROXY_URL: {{ .Values.proxyUrl }} + {{- end }} + DEFGUARD_URL: {{ .Values.publicUrl }} + DEFGUARD_WEBAUTHN_RP_ID: {{ .Values.ingress.web.host }} + {{- if .Values.ldap.enabled }} + DEFGUARD_LDAP_ADMIN_GROUP: {{ .Values.ldap.admin_group | quote }} + DEFGUARD_LDAP_BIND_PASSWORD: {{ .Values.ldap.bind_password | quote }} + DEFGUARD_LDAP_BIND_USERNAME: {{ .Values.ldap.bind_username | quote }} + DEFGUARD_LDAP_GROUP_SEARCH_BASE: {{ .Values.ldap.group_search_base | quote }} + DEFGUARD_LDAP_USER_SEARCH_BASE: {{ .Values.ldap.user_search_base | quote }} + DEFGUARD_LDAP_URL: {{ .Values.ldap.url | quote }} + {{- end }} diff --git a/deployment/charts/defguard/templates/defguard-deployment.yaml b/deployment/charts/defguard/templates/defguard-deployment.yaml new file mode 100644 index 0000000..f1713a0 --- /dev/null +++ b/deployment/charts/defguard/templates/defguard-deployment.yaml @@ -0,0 +1,105 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "defguard.fullname" . }} + labels: + {{- include "defguard.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "defguard.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "defguard.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "defguard.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + env: + - name: DEFGUARD_DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.postgresql.auth.existingSecret }} + key: {{ .Values.postgresql.auth.existingSecretPasswordKey | default "password" }} + - name: DEFGUARD_AUTH_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.existingJwtSecret | default (include "defguard.jwtSecretName" .) }} + key: auth + - name: DEFGUARD_GATEWAY_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.existingJwtSecret | default (include "defguard.jwtSecretName" .) }} + key: gateway + - name: DEFGUARD_YUBIBRIDGE_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.existingJwtSecret | default (include "defguard.jwtSecretName" .) }} + key: yubi-bridge + - name: DEFGUARD_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.existingJwtSecret | default (include "defguard.jwtSecretName" .) }} + key: secret-key + - name: DEFGUARD_OPENID_KEY + value: "/etc/defguard-openid-key.pem" + envFrom: + - configMapRef: + name: {{ include "defguard.fullname" . }}-config + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8000 + protocol: TCP + - name: grpc + containerPort: 50055 + protocol: TCP + livenessProbe: + httpGet: + path: /api/v1/health + port: http + readinessProbe: + httpGet: + path: /api/v1/health + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: openid-key + mountPath: "/etc/defguard-openid-key.pem" + readOnly: true + subPath: openid-key + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: openid-key + secret: + secretName: {{ .Values.existingOpenIdSecret | default (include "defguard.openidSecretName" .) }} + optional: false diff --git a/deployment/charts/defguard/templates/defguard-secret.yaml b/deployment/charts/defguard/templates/defguard-secret.yaml new file mode 100644 index 0000000..b5758e1 --- /dev/null +++ b/deployment/charts/defguard/templates/defguard-secret.yaml @@ -0,0 +1,25 @@ +{{ if not .Values.existingJwtSecret }} +{{- $auth := (randAlpha 16) | b64enc | quote }} +{{- $gateway := (randAlpha 16) | b64enc | quote }} +{{- $yubiBridge := (randAlpha 16) | b64enc | quote }} +{{- $secretKey := (randAlpha 64) | b64enc | quote }} +{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "defguard.jwtSecretName" .)) }} +{{- if $secret }} +{{- $auth = index $secret.data "auth" }} +{{- $gateway = index $secret.data "gateway" }} +{{- $yubiBridge = index $secret.data "yubi-bridge" }} +{{- $secretKey = index $secret.data "secret-key" }} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "defguard.jwtSecretName" . }} + labels: + {{- include "defguard.labels" . | nindent 4 }} +type: Opaque +data: + auth: {{ $auth }} + gateway: {{ $gateway }} + yubi-bridge: {{ $yubiBridge }} + secret-key: {{ $secretKey }} +{{- end }} diff --git a/deployment/charts/defguard/templates/defguard-service.yaml b/deployment/charts/defguard/templates/defguard-service.yaml new file mode 100644 index 0000000..fa6f8cf --- /dev/null +++ b/deployment/charts/defguard/templates/defguard-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "defguard.fullname" . }}-web + labels: + {{- include "defguard.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.ports.http }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "defguard.selectorLabels" . | nindent 4 }} diff --git a/deployment/charts/defguard/templates/grpc-service.yaml b/deployment/charts/defguard/templates/grpc-service.yaml new file mode 100644 index 0000000..edfef6c --- /dev/null +++ b/deployment/charts/defguard/templates/grpc-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + traefik.ingress.kubernetes.io/service.serversscheme: h2c + name: {{ include "defguard.fullname" . }}-grpc + labels: + {{- include "defguard.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.ports.grpc }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + {{- include "defguard.selectorLabels" . | nindent 4 }} diff --git a/deployment/charts/defguard/templates/ingress-grpc.yaml b/deployment/charts/defguard/templates/ingress-grpc.yaml new file mode 100644 index 0000000..189ce8e --- /dev/null +++ b/deployment/charts/defguard/templates/ingress-grpc.yaml @@ -0,0 +1,52 @@ +{{- if .Values.ingress.grpc.enabled -}} +{{- $fullName := include "defguard.fullname" . -}} +{{- if and .Values.ingress.grpc.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.grpc.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.grpc.annotations "kubernetes.io/ingress.class" .Values.ingress.grpc.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-grpc + labels: + {{- include "defguard.labels" . | nindent 4 }} + {{- with .Values.ingress.grpc.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.grpc.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.grpc.className }} + {{- end }} + {{- if .Values.ingress.grpc.tls }} + tls: + - hosts: + - {{ .Values.ingress.grpc.host | quote }} + secretName: {{ printf "%s-grpc-tls" .Values.ingress.grpc.host }} + {{- end }} + rules: + - host: {{ .Values.ingress.grpc.host | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: ImplementationSpecific + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-grpc + port: + number: {{ .Values.service.ports.grpc }} + {{- else }} + serviceName: {{ $fullName }}-grpc + servicePort: {{ .Values.service.ports.grpc }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard/templates/ingress-web.yaml b/deployment/charts/defguard/templates/ingress-web.yaml new file mode 100644 index 0000000..c53c7c6 --- /dev/null +++ b/deployment/charts/defguard/templates/ingress-web.yaml @@ -0,0 +1,52 @@ +{{- if .Values.ingress.web.enabled -}} +{{- $fullName := include "defguard.fullname" . -}} +{{- if and .Values.ingress.web.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.web.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.web.annotations "kubernetes.io/ingress.class" .Values.ingress.web.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-web + labels: + {{- include "defguard.labels" . | nindent 4 }} + {{- with .Values.ingress.web.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.web.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.web.className }} + {{- end }} + {{- if .Values.ingress.web.tls }} + tls: + - hosts: + - {{ .Values.ingress.web.host | quote }} + secretName: {{ printf "%s-web-tls" .Values.ingress.web.host }} + {{- end }} + rules: + - host: {{ .Values.ingress.web.host | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: ImplementationSpecific + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }}-web + port: + number: {{ .Values.service.ports.http }} + {{- else }} + serviceName: {{ $fullName }}-web + servicePort: {{ .Values.service.ports.http }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard/templates/openid-secret.yaml b/deployment/charts/defguard/templates/openid-secret.yaml new file mode 100644 index 0000000..ba67053 --- /dev/null +++ b/deployment/charts/defguard/templates/openid-secret.yaml @@ -0,0 +1,16 @@ +{{ if not .Values.existingOpenIdSecret }} +{{- $openIdKey := (genPrivateKey "rsa") | b64enc | quote }} +{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "defguard.openidSecretName" .)) }} +{{- if $secret }} +{{- $openIdKey = index $secret.data "openid-key" }} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "defguard.openidSecretName" . }} + labels: + {{- include "defguard.labels" . | nindent 4 }} +type: Opaque +data: + openid-key: {{ $openIdKey }} +{{- end }} diff --git a/deployment/charts/defguard/templates/postgresql-secret.yaml b/deployment/charts/defguard/templates/postgresql-secret.yaml new file mode 100644 index 0000000..efdc2c4 --- /dev/null +++ b/deployment/charts/defguard/templates/postgresql-secret.yaml @@ -0,0 +1,19 @@ +{{ if .Values.postgresql.enabled }} +{{- $password := (randAlpha 16) | b64enc | quote }} +{{- $postgresPassword := (randAlpha 16) | b64enc | quote }} +{{- $secret := (lookup "v1" "Secret" .Release.Namespace .Values.postgresql.auth.existingSecret) }} +{{- if $secret }} +{{- $password = index $secret.data "password" }} +{{- $postgresPassword = index $secret.data "postgres-password" }} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.postgresql.auth.existingSecret }} + labels: + {{- include "defguard.labels" . | nindent 4 }} +type: Opaque +data: + password: {{ $password }} + postgres-password: {{ $postgresPassword }} +{{- end }} diff --git a/deployment/charts/defguard/templates/serviceaccount.yaml b/deployment/charts/defguard/templates/serviceaccount.yaml new file mode 100644 index 0000000..1efc1cc --- /dev/null +++ b/deployment/charts/defguard/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "defguard.serviceAccountName" . }} + labels: + {{- include "defguard.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deployment/charts/defguard/values.yaml b/deployment/charts/defguard/values.yaml new file mode 100644 index 0000000..408019d --- /dev/null +++ b/deployment/charts/defguard/values.yaml @@ -0,0 +1,75 @@ +affinity: {} +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 +cookie: + domain: "" + insecure: false +fullnameOverride: "" +image: + pullPolicy: IfNotPresent + repository: ghcr.io/defguard/defguard + tag: "" +imagePullSecrets: [] +ingress: + grpc: + annotations: {} + className: "" + enabled: true + host: defguard-grpc.local + tls: false + web: + annotations: {} + className: "" + enabled: true + host: defguard.local + tls: false +existingJwtSecret: "" +ldap: + admin_group: "" + bind_password: "" + bind_username: "" + enabled: false + group_search_base: "" + url: "" + user_search_base: "" +nameOverride: "" +nodeSelector: {} +existingOpenIdSecret: "" +podAnnotations: {} +podLabels: {} +podSecurityContext: {} +# sub-chart bitnami/postgresql +postgresql: + enabled: true + host: "" # set if using external postgresql ~ enabled: false + port: 5432 + auth: + database: defguard + existingSecret: postgres-password + existingSecretPasswordKey: "" # set if using external postgresql ~ enabled: false + username: defguard +proxyUrl: "" +publicUrl: "http://defguard.local" +replicaCount: 1 +resources: {} +securityContext: {} +service: + ports: + grpc: 50055 + http: 80 + type: ClusterIP +serviceAccount: + annotations: {} + create: true +tolerations: [] +# sub-chart defguard-proxy +defguard-proxy: + enabled: false + publicUrl: "http://enrollment.local" + ingress: + grpc: + host: defguard-proxy-grpc.local + web: + host: enrollment.local diff --git a/deployment/docker-compose/.env.template b/deployment/docker-compose/.env.template new file mode 100644 index 0000000..61c2e22 --- /dev/null +++ b/deployment/docker-compose/.env.template @@ -0,0 +1,31 @@ +# The best way to define each secret is to generate random strings with e.g.: +# +# openssl rand -base64 48 #this will generate a 48chars random string +# +# Please provide secret strings (do not share them) for: +# +# Secret used for JWT cryptography +DEFGUARD_AUTH_SECRET= +# Secret used for JWT cryptography in YubiBridge GRPC communication +DEFGUARD_YUBIBRIDGE_SECRET= +# Secret used for JWT cryptography in gateway GRPC communication +DEFGUARD_GATEWAY_SECRET= +# Secret used for private cookies cryptography; must be at least 64 characters long +DEFGUARD_SECRET_KEY= +# Database password +DEFGUARD_DB_PASSWORD= +# Public URL of your Defguard instance +# E.g.: https://defguard.mycompany.com +DEFGUARD_URL= +# Webauthn RP ID (https://w3c.github.io/webauthn/#rp-id) +# E.g.: defguard.mycompany.com (without http/https) +DEFGUARD_WEBAUTHN_RP_ID= +# Public URL of your defguard proxy gRPC server +# DEFGUARD_PROXY_URL= +# Public URL of your enrollment service +# E.g.: https://enrollment.mycompany.com +# DEFGUARD_ENROLLMENT_URL= # [ENROLLMENT] +# Token used for VPN gateway authorization +# DEFGUARD_TOKEN= # [VPN] +# Enable insecure cookies when not using HTTPS +# DEFGUARD_COOKIE_INSECURE=true # [HTTP] diff --git a/deployment/docker-compose/docker-compose.yaml b/deployment/docker-compose/docker-compose.yaml new file mode 100644 index 0000000..6edeb14 --- /dev/null +++ b/deployment/docker-compose/docker-compose.yaml @@ -0,0 +1,98 @@ +services: + db: + image: postgres:15-alpine + restart: unless-stopped + environment: + POSTGRES_DB: defguard + POSTGRES_USER: defguard + POSTGRES_PASSWORD: ${DEFGUARD_DB_PASSWORD} + volumes: + - ${VOLUME_DIR:-./.volumes}/db:/var/lib/postgresql/data + # ports: + # - "5432:5432" + + # caddy: # [PROXY] + # image: caddy:2.7-alpine # [PROXY] + # restart: unless-stopped # [PROXY] + # volumes: # [PROXY] + # - ${VOLUME_DIR:-./.volumes}/caddy/data:/data # [PROXY] + # - ${VOLUME_DIR:-./.volumes}/caddy/config:/config # [PROXY] + # - ${VOLUME_DIR:-./.volumes}/caddy/Caddyfile:/etc/caddy/Caddyfile # [PROXY] + # ports: # [PROXY] + # # http # [PROXY] + # - "80:80" # [PROXY] + # # https # [PROXY] + # - "443:443" # [PROXY] + + core: + image: ghcr.io/defguard/defguard:${CORE_IMAGE_TAG:-latest} + restart: unless-stopped + environment: + DEFGUARD_AUTH_SECRET: ${DEFGUARD_AUTH_SECRET} + DEFGUARD_GATEWAY_SECRET: ${DEFGUARD_GATEWAY_SECRET} + DEFGUARD_YUBIBRIDGE_SECRET: ${DEFGUARD_YUBIBRIDGE_SECRET} + DEFGUARD_SECRET_KEY: ${DEFGUARD_SECRET_KEY} + DEFGUARD_DEFAULT_ADMIN_PASSWORD: ${DEFGUARD_DEFAULT_ADMIN_PASSWORD} + DEFGUARD_DB_HOST: db + DEFGUARD_DB_PORT: 5432 + DEFGUARD_DB_USER: defguard + DEFGUARD_DB_PASSWORD: ${DEFGUARD_DB_PASSWORD} + DEFGUARD_DB_NAME: defguard + DEFGUARD_URL: ${DEFGUARD_URL} + DEFGUARD_LOG_LEVEL: info + # DEFGUARD_WEBAUTHN_RP_ID: ${DEFGUARD_WEBAUTHN_RP_ID} + DEFGUARD_COOKIE_INSECURE: ${DEFGUARD_COOKIE_INSECURE:-false} + DEFGUARD_ENROLLMENT_URL: ${DEFGUARD_ENROLLMENT_URL} # [ENROLLMENT] + # DEFGUARD_PROXY_URL: https://proxy:50052 # [ENROLLMENT] + # DEFGUARD_PROXY_GRPC_CA: /ssl/defguard-ca.pem # [ENROLLMENT] + #DEFGUARD_GRPC_CERT: /ssl/defguard-grpc.crt + #DEFGUARD_GRPC_KEY: /ssl/defguard-grpc.key + ## RSA setup guide: https://defguard.gitbook.io/defguard/community-features/setting-up-your-instance/docker-compose#openid-rsa-setup + DEFGUARD_OPENID_KEY: /keys/rsakey.pem + ## LDAP setup guide: https://defguard.gitbook.io/defguard/features/ldap-synchronization-setup + # DEFGUARD_LDAP_URL: ldap://localhost:389 # [LDAP] + # DEFGUARD_LDAP_BIND_USERNAME: cn=admin,dc=example,dc=org # [LDAP] + # DEFGUARD_LDAP_BIND_PASSWORD: password # [LDAP] + ports: + # web + - "8850:8000" + # grpc + - "50055:50055" + depends_on: + - db + volumes: + # SSL setup guide: https://defguard.gitbook.io/defguard/features/setting-up-your-instance/docker-compose#ssl-setup + - ${VOLUME_DIR:-./.volumes}/ssl:/ssl + ## RSA setup guide: https://defguard.gitbook.io/defguard/community-features/setting-up-your-instance/docker-compose#openid-rsa-setup + - ${VOLUME_DIR:-./.volumes}/core/rsakey.pem:/keys/rsakey.pem + + # proxy: # [ENROLLMENT] + # image: ghcr.io/defguard/defguard-proxy:${PROXY_IMAGE_TAG:-latest} # [ENROLLMENT] + # restart: unless-stopped # [ENROLLMENT] + # environment: # [ENROLLMENT] + # DEFGUARD_PROXY_GRPC_PORT: 50052 # [ENROLLMENT] + # DEFGUARD_PROXY_GRPC_CERT: /ssl/defguard-proxy-grpc.crt # [ENROLLMENT] + # DEFGUARD_PROXY_GRPC_KEY: /ssl/defguard-proxy-grpc.key # [ENROLLMENT] + # volumes: # [ENROLLMENT] + # SSL setup guide: https://defguard.gitbook.io/defguard/features/setting-up-your-instance/docker-compose#ssl-setup + # - ${VOLUME_DIR:-./.volumes}/ssl:/ssl # [ENROLLMENT] + # ports: + # # web + # - "8080:8080" + # depends_on: # [ENROLLMENT] + # - core # [ENROLLMENT] + + # gateway: # [VPN] + # image: ghcr.io/defguard/gateway:${GATEWAY_IMAGE_TAG:-latest} # [VPN] + # restart: unless-stopped # [VPN] + # network_mode: "host" # [VPN] + # environment: # [VPN] + # DEFGUARD_GRPC_URL: https://localhost:50055 # [VPN] + # DEFGUARD_GRPC_CA: /ssl/defguard-ca.pem # [VPN] + # DEFGUARD_STATS_PERIOD: 30 # [VPN] + # DEFGUARD_TOKEN: ${DEFGUARD_TOKEN} # [VPN] + # volumes: # [VPN] + # SSL setup guide: https://defguard.gitbook.io/defguard/features/setting-up-your-instance/docker-compose#ssl-setup + # - ${VOLUME_DIR:-./.volumes}/ssl:/ssl # [VPN] + # cap_add: # [VPN] + # - NET_ADMIN # [VPN] diff --git a/deployment/docker-compose/setup.sh b/deployment/docker-compose/setup.sh new file mode 100755 index 0000000..e99814b --- /dev/null +++ b/deployment/docker-compose/setup.sh @@ -0,0 +1,890 @@ +#!/usr/bin/env bash +# shellcheck shell=bash + +# This is a script that sets up an entire defguard instance (including core, +# gateway, enrollment proxy and reverse proxy). It's goal is to prepare +# a working instance by running a single command. + +set -o errexit # abort on nonzero exitstatus +set -o pipefail # don't hide errors within pipes + +# Global variables +VERSION="1.0.2" +SECRET_LENGTH=64 +PASSWORD_LENGTH=16 + +VOLUME_DIR=".volumes" +SSL_DIR="${VOLUME_DIR}/ssl" +RSA_DIR="${VOLUME_DIR}/core" + +COMPOSE_FILE="docker-compose.yaml" +ENV_FILE=".env" +LOG_FILE=$(mktemp setup.log.XXXXXX) + +BASE_COMPOSE_FILE_URL="https://raw.githubusercontent.com/DefGuard/deployment/main/docker-compose/docker-compose.yaml" +BASE_ENV_FILE_URL="https://raw.githubusercontent.com/DefGuard/deployment/main/docker-compose/.env.template" + +CORE_IMAGE_TAG="${CORE_IMAGE_TAG:-latest}" +GATEWAY_IMAGE_TAG="${GATEWAY_IMAGE_TAG:-latest}" +PROXY_IMAGE_TAG="${PROXY_IMAGE_TAG:-latest}" + + +##################### +### MAIN FUNCTION ### +##################### + +main() { + is_utf_term + is_term_color + tput reset + print_header + + # display help `--help` argument is found + for i in $*; do + test "$i" == "--help" && print_usage && exit 0 + + # run non interactive + if [[ "$i" == "--non-interactive" ]]; then + CFG_NON_INTERACTIVE=1 + # we need to remove this element from $* or getopt will return an error + set -- $(remove_element "$i" $*) + fi + + # configure https + if [[ "$i" == "--use-https" ]]; then + CFG_USE_HTTPS=1 + # we need to remove this element from $* or getopt will return an error + set -- $(remove_element "$i" $*) + fi + done + + # + # First let's gather the ENV/command line variables + # + + # load configuration from env variables + load_configuration_from_env + + # load configuration from CLI options + load_configuration_from_cli "$@" + + # load configuration from user inputs + if [ X$CFG_VOLUME_DIR != X ]; then + VOLUME_DIR=${CFG_VOLUME_DIR} + SSL_DIR="${VOLUME_DIR}/ssl" + RSA_DIR="${VOLUME_DIR}/core" + fi + + export VOLUME_DIR + + # We have enough to check the enviromnent + # so check if necessary tools are available + check_environment + + # load configuration from user inputs + if ! [ $CFG_NON_INTERACTIVE ]; then + load_configuration_from_input + fi + + # check that all required configuration options are set + validate_required_variables + + # generate external service URLs based on config + generate_external_urls + + # print out config + print_config + + # set current working directory + WORK_DIR_PATH=$(pwd) + + # setup RSA & SSL keys + setup_keys + + # generate caddyfile + create_caddyfile + + # generate `.env` file + generate_env_file + + # enable insecure cookies if not using HTTPS + if ! [ "$CFG_USE_HTTPS" ]; then + uncomment_feature "HTTP" "${PROD_ENV_FILE}" + fi + + # generate base docker-compose file + PROD_COMPOSE_FILE="${WORK_DIR_PATH}/${COMPOSE_FILE}" + if [ -f "$PROD_COMPOSE_FILE" ]; then + echo -n " ${TXT_BEGIN} Using existing docker-compose file at ${PROD_COMPOSE_FILE}... " + print_confirmation + else + fetch_base_compose_file + fi + + # enable reverse proxy in compose file + uncomment_feature "PROXY" "${PROD_COMPOSE_FILE}" + + # enable enrollment service in compose file + if [ "$CFG_ENABLE_ENROLLMENT" ]; then + enable_enrollment + fi + + # fetch latest images + echo " ${TXT_BEGIN} Fetching latest Docker images: " + $COMPOSE_CMD -f "${PROD_COMPOSE_FILE}" --env-file "${PROD_ENV_FILE}" pull + + # enable and setup VPN gateway + if [ "$CFG_ENABLE_VPN" ]; then + enable_vpn_gateway + fi + + # start docker-compose stack + echo " ${TXT_BEGIN} Starting docker-compose stack" + $COMPOSE_CMD -f "${PROD_COMPOSE_FILE}" --env-file "${PROD_ENV_FILE}" up -d + if [ $? -ne 0 ]; then + echo >&2 "ERROR: failed to start docker-compose stack" + exit 1 + fi + + print_instance_summary +} + +######################## +### HELPER FUNCTIONS ### +######################## + +check_character_support() { + local char="$1" + echo -e "$char" | grep -q "$char" +} + +is_utf_term() { + if check_character_support "√"; then + TXT_CHECK="✓" + TXT_BEGIN="▶" + TXT_SUB="▷" + TXT_STAR="★" + TXT_X="✗" + TXT_INPUT="✍" + else + TXT_CHECK="+" + TXT_BEGIN=">>" + TXT_SUB=">" + TXT_STAR="*" + TXT_X="x" + TXT_INPUT=" ::" + fi +} + +is_term_color() { + + if [[ $TERM == *"256"* ]]; then + C_RED="\033[31m" + C_GREEN="\033[32m" + C_YELLOW="\033[33m" + C_BLUE="\033[34m" + C_WHITE="\033[37m" + C_GREY="\033[90m" + + C_LRED="\033[91m" + C_LGREEN="\033[92m" + C_LYELLOW="\033[93m" + C_LBLUE="\033[94m" + + C_BOLD="\033[1m" + C_ITALICS="\033[3m" + C_BG_GREY="\033[100m" + C_END="\033[0m" + else + C_RED="" + C_GREEN="" + C_YELLOW="" + C_BLUE="" + C_WHITE="" + C_GREY="" + + C_LRED="" + C_LGREEN="" + C_LYELLOW="" + C_LBLUE="" + + C_BOLD="" + C_ITALICS="" + C_BG_GREY="" + C_END="" + fi +} + +# remove array element +remove_element() { + local remove=$1 + local result=() + for element in "$@"; do + if [[ "$element" != "$remove" ]]; then + result+=("$element") + fi + done + echo "${result[@]}" +} + +# Function to convert relative path to absolute path +to_absolute_path() { + local path="$1" + if [[ "${path:0:1}" != "/" ]]; then + path="$(cd "$(dirname "$path")" && pwd)/$(basename "$path")" + fi + echo ${path} +} + +print_header() { + echo -e "${C_LBLUE}" + cat << _EOF_ + # + ## # + ## ## # # ## # + ## ## # # # # + # ## # #### # #### ##### #### # # #### ### #### # + # ## ## # ## # ## # # # # # # # # # ## + ## ## # # ######## # # # # # # # # # + # ## ## # # # ## # ##### # # ###### # # # + # ## # # ## # # # # # # # # # # ## + ## ## #### # ##### # ####### #### # #### # # #### # + ## ## # # # + ## # ####### + # +_EOF_ + echo -e "${C_END}" + echo + echo "defguard docker-compose deployment setup script v${VERSION}" + echo -e "Copyright (C) 2023-2024 ${C_BOLD}teonite${C_END} <${C_BG_GREY}${C_YELLOW}https://teonite.com${C_END}>" + echo +} + +print_confirmation() { + echo -e " ${C_LGREEN}${TXT_CHECK}${C_END} " +} + +print_usage() { + + echo "Usage: ${BASENAME} [options]" + echo + echo 'Available options:' + echo + echo -e "\t--help this help message" + echo -e "\t--non-interactive run in non-interactive mode - !REQUIRES SETTING all options/env vars" + echo -e "\t--domain domain where defguard web UI will be available" + echo -e "\t--enrollment-domain domain where enrollment service will be available" + echo -e "\t--use-https configure reverse proxy to use HTTPS" + echo -e "\t--volume Docker volumes directory - default: ${VOLUME_DIR}" + echo -e "\t--vpn-name VPN location name" + echo -e "\t--vpn-ip
VPN server address & netmask (e.g. 10.0.50.1/24)" + echo -e "\t--vpn-gateway-ip VPN gateway external IP (! NOT DOMAIN - IP)" + echo -e "\t--vpn-gateway-port VPN gateway external port (your clients connect here)" + echo +} + +command_exists() { + local command="$1" + command -v "$command" >/dev/null 2>&1 +} + +command_exists_check() { + local command="$1" + if ! command_exists "$command"; then + echo >&2 "ERROR: $command command not found" + echo >&2 "ERROR: dependency failed, exiting..." + exit 2 + fi +} + +check_environment() { + echo -n " ${TXT_BEGIN} Checking if all required tools are available..." + # compose can be provided by newer docker versions or a separate docker-compose + docker compose version >/dev/null 2>&1 + if [ $? = 0 ]; then + COMPOSE_CMD="docker compose" + else + if command_exists docker-compose; then + COMPOSE_CMD="docker-compose" + else + echo + echo >&2 "ERROR: docker-compose or docker compose command not found" + echo >&2 "ERROR: dependency failed, exiting..." + exit 3 + fi + fi + + command_exists_check openssl + command_exists_check curl + command_exists_check grep + + # Check if the volume dir is an absolute path since docker requires it + VOLUME_DIR=$(to_absolute_path "${VOLUME_DIR}") + + if [ -d ${VOLUME_DIR} ]; then + echo + echo >&2 "ERROR: volume directory: ${VOLUME_DIR} exists." + echo >&2 "ERROR: this means, I would overwrite the configuration, database and certificates." + echo >&2 "ERROR: please backup or remove the volume directory." + exit 3 + fi + + # create all necessary directories + for dir in ${VOLUME_DIR} ${SSL_DIR} ${RSA_DIR}; do + mkdir ${dir} + if [ $? -ne 0 ]; then + echo >&2 "ERROR: cloud not create volume directory: ${dir}" + exit 3 + fi + done + + print_confirmation +} + +load_configuration_from_env() { + echo -n " ${TXT_BEGIN} Loading configuration from environment variables... " + # required variables + CFG_DOMAIN="$DEFGUARD_DOMAIN" + + # optional variables + CFG_VOLUME_DIR="$DEFGUARD_VOLUME_DIR" + CFG_VPN_NAME="$DEFGUARD_VPN_NAME" + CFG_VPN_IP="$DEFGUARD_VPN_IP" + CFG_VPN_GATEWAY_IP="$DEFGUARD_VPN_GATEWAY_IP" + CFG_VPN_GATEWAY_PORT="$DEFGUARD_VPN_GATEWAY_PORT" + CFG_ENROLLMENT_DOMAIN="$DEFGUARD_ENROLLMENT_DOMAIN" + if ! [ $CFG_USE_HTTPS ]; then + CFG_USE_HTTPS="$DEFGUARD_USE_HTTPS" + fi + + print_confirmation +} + +load_configuration_from_cli() { + echo -n " ${TXT_BEGIN} Loading configuration from CLI arguments... " + + ARGUMENT_LIST=( + "domain" + "enrollment-domain" + "volume" + "vpn-name" + "vpn-ip" + "vpn-gateway-ip" + "vpn-gateway-port" + ) + + # read arguments + opts=$( + getopt \ + --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \ + --name "$(basename "$0")" \ + --options "" \ + -- "$@" + ) + + eval set --$opts + + while [[ $# -gt 0 ]]; do + case "$1" in + --domain) + CFG_DOMAIN=$2 + shift 2 + ;; + + --enrollment-domain) + CFG_ENROLLMENT_DOMAIN=$2 + shift 2 + ;; + + --volume) + CFG_VOLUME_DIR=$2 + shift 2 + ;; + + --vpn-name) + CFG_VPN_NAME=$2 + shift 2 + ;; + + --vpn-ip) + CFG_VPN_IP=$2 + shift 2 + ;; + + --vpn-gateway-ip) + CFG_VPN_GATEWAY_IP=$2 + shift 2 + ;; + + --vpn-gateway-port) + CFG_VPN_GATEWAY_PORT=$2 + shift 2 + ;; + + *) + break + ;; + esac + done + + print_confirmation +} + +load_configuration_from_input() { + echo -ne "${C_ITALICS}${C_LBLUE}" + cat << _EOF_ + +Please provide the values to configure your defguard instance. If you've +already configured some options by setting environment variables or through +CLI options, those will be used as defaults. + +If you prefer to disable this user input section, please restart the script +with --non-interactive CLI flag. + +_EOF_ + +echo -ne "${C_GREY}" +cat << _EOF_ + +Choose domains that will be used to expose your instance through Caddy +reverse proxy. defguard uses a separate domain for the Web UI, and for +the optional enrollment/desktop client configuration/password reset +service. + +If you don't provide any domain for the enrollment service, the service +itself will not be deployed. + +You can also enable HTTPS here (highly recommended), which will configure +Caddy to automatically provision SSL certificates. +_EOF_ + +echo -ne "${C_BOLD}" +cat << _EOF_ + +Please note that this requires your server to have a public IP address +and public DNS records for your chosen domains to be configured +correctly (pointing to your server's IP address). + +_EOF_ + + echo -ne "${C_END}" + + echo -e " ${C_BOLD}${C_GREEN}${TXT_STAR} General config ${TXT_STAR}${C_END}\n" + + while [ X${domain} = "X" ]; do + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter defguard domain [default: ${CFG_DOMAIN}]: " domain + if [ "$domain" ]; then + CFG_DOMAIN="$domain" + fi + done + + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter enrollment domain [default: ${CFG_ENROLLMENT_DOMAIN}]: " enroll + if [ "$enroll" ]; then + CFG_ENROLLMENT_DOMAIN="$enroll" + fi + + use_https_bool_value="false" + if [ $CFG_USE_HTTPS ]; then use_https_bool_value="true"; fi + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Use HTTPS [default: ${use_https_bool_value}]: " https + if [ "$https" ]; then + CFG_USE_HTTPS=1 + fi + + echo + echo -e " ${C_BOLD}${C_GREEN}${TXT_STAR} WireGuard VPN${TXT_STAR}${C_END}\n" + + echo -ne "${C_ITALICS}${C_GREY}" + cat << _EOF_ + +If you wish to configure and deploy WireGuard VPN gateway, please +provide your VPN location name. To skip, just press enter and VPN will +not be configured. +_EOF_ + + echo -ne "${C_END}\n" + + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter VPN location name [default: ${CFG_VPN_NAME}]: " vpn_name + if [ "$vpn_name" ]; then + CFG_VPN_NAME="$vpn_name" + fi + + if [ "$CFG_VPN_NAME" ]; then + while [ X${vpn_ip} = "X" ]; do + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter VPN server address and subnet (e.g. 10.0.60.1/24) [default: ${CFG_VPN_IP}]: " vpn_ip + if [ "$vpn_ip" ]; then + CFG_VPN_IP="$vpn_ip" + fi + done + + echo -ne "${C_ITALICS}${C_GREY}" + cat << _EOF_ + +Now we'll configure a public endpoint (IP + port) that your WireGuard +client devices will use to safely connect to your gateway from the +public internet. + +Since we'll be starting the gateway on this server the IP address should +be the same as your server's public IP address. +_EOF_ + echo -ne "${C_BOLD}" + cat << _EOF_ +Please also remember that your firewall should be configured +to allow incoming UDP traffic on the chosen WireGuard port. +_EOF_ + + echo -ne "${C_END}" + + while [ X${public_ip} = "X" ]; do + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter VPN gateway public IP (no domains!) [default: ${CFG_VPN_GATEWAY_IP}]: " public_ip + if [ "$public_ip" ]; then + CFG_VPN_GATEWAY_IP="$public_ip" + fi + done + + while [ X${public_port} = "X" ]; do + echo -ne "${C_YELLOW}${TXT_INPUT}${C_END} " + read -p "Enter VPN gateway public port [default: ${CFG_VPN_GATEWAY_PORT}]: " public_port + if [ "$public_port" ]; then + CFG_VPN_GATEWAY_PORT="$public_port" + fi + done + + else + echo -e " ${C_BOLD}${C_RED}${TXT_X} ${C_GREY} WireGuard VPN skipped${C_END}\n" + fi + + echo + echo -e "${C_BOLD}${C_GREEN}Thank you. We'll now proceed with the deployment using provided values.${C_END}" +} + +check_required_variable() { + local var_name="$1" + if [ -z "${!var_name}" ]; then + echo >&2 "ERROR: ${var_name} configuration option not set" + exit 4 + fi +} + +validate_required_variables() { + echo -n " ${TXT_BEGIN} Validating configuration options..." + check_required_variable "CFG_DOMAIN" + + # if VPN name is given validate other VPN configurations are present + if [ "$CFG_VPN_NAME" ]; then + CFG_ENABLE_VPN=1 + check_required_variable "CFG_VPN_IP" + check_required_variable "CFG_VPN_GATEWAY_IP" + check_required_variable "CFG_VPN_GATEWAY_PORT" + fi + + print_confirmation +} + +generate_external_urls() { + # prepare full defguard URL + if [ $CFG_USE_HTTPS ]; then + CFG_DEFGUARD_URL="https://${CFG_DOMAIN}" + else + CFG_DEFGUARD_URL="http://${CFG_DOMAIN}" + fi + + # prepare full enrollment URL + if [ "$CFG_ENROLLMENT_DOMAIN" ]; then + CFG_ENABLE_ENROLLMENT=1 + if [ "$CFG_USE_HTTPS" ]; then + CFG_ENROLLMENT_URL="https://${CFG_ENROLLMENT_DOMAIN}" + else + CFG_ENROLLMENT_URL="http://${CFG_ENROLLMENT_DOMAIN}" + fi + fi +} + +print_config() { + echo + echo " ${TXT_BEGIN} Setting up your defguard instance with following config:" + echo + echo -e " ${TXT_SUB} data volume: ${C_BOLD}${VOLUME_DIR}${C_END}" + echo + echo -e " ${TXT_SUB} domain: ${C_BOLD}${CFG_DOMAIN}${C_END}" + echo -e " ${TXT_SUB} web UI URL: ${C_BOLD}${CFG_DEFGUARD_URL}${C_END}" + + if [ "$CFG_VPN_NAME" ]; then + echo -e " ${TXT_SUB} VPN location name: ${C_BOLD}${CFG_VPN_NAME}${C_END}" + echo -e " ${TXT_SUB} VPN address: ${C_BOLD}${CFG_VPN_IP}${C_END}" + echo -e " ${TXT_SUB} VPN gateway IP: ${C_BOLD}${CFG_VPN_GATEWAY_IP}${C_END}" + echo -e " ${TXT_SUB} VPN gateway port: ${C_BOLD}${CFG_VPN_GATEWAY_PORT}${C_END}" + fi + + if [ "$CFG_ENROLLMENT_DOMAIN" ]; then + echo -e " ${TXT_SUB} Enrollment service domain: ${C_BOLD}${CFG_ENROLLMENT_DOMAIN}${C_END}" + echo -e " ${TXT_SUB} Enrollment service URL: ${C_BOLD}${CFG_ENROLLMENT_URL}${C_END}" + fi + echo + echo -e " ${TXT_BEGIN} All executed command's results are in log file: ${C_BOLD}${LOG_FILE}${C_END}" + echo +} + +setup_keys() { + echo " ${TXT_BEGIN} Setting up SSL certificates and RSA keys..." + if [ -d ${SSL_DIR} -a "$(ls -A ${SSL_DIR})" ]; then + echo " ${TXT_SUB} Using existing SSL certificates from ${SSL_DIR}" + else + generate_certs + fi + + if [ -d ${RSA_DIR} -a "$(ls -A ${RSA_DIR})" ]; then + echo " ${TXT_SUB} Using existing RSA keys from ${RSA_DIR}." + else + generate_rsa + fi +} + +generate_certs() { + echo " ${TXT_BEGIN} Creating new SSL certificates in ${SSL_DIR}..." + mkdir -p ${SSL_DIR} + + PASSPHRASE=$(generate_secret) + + echo "PEM passphrase for SSL certificates set to '${PASSPHRASE}'." + + # generate private key for CA + openssl genrsa -des3 -out ${SSL_DIR}/defguard-ca.key -passout pass:"${PASSPHRASE}" 2048 2>&1 >> ${LOG_FILE} + # generate Root Certificate + # TODO: allow configuring CA parameters + openssl req -x509 -new -nodes -key ${SSL_DIR}/defguard-ca.key -sha256 -days 1825 -out ${SSL_DIR}/defguard-ca.pem -passin pass:"${PASSPHRASE}" -subj "/C=PL/ST=Zachodniopomorskie/L=Szczecin/O=Example/OU=IT Department/CN=${CFG_DOMAIN}" 2>&1 >> ${LOG_FILE} + + # generate CA-signed certificate for defguard gRPC + openssl genrsa -out ${SSL_DIR}/defguard-grpc.key 2048 2>&1 >> ${LOG_FILE} + + openssl req -new -key ${SSL_DIR}/defguard-grpc.key -out ${SSL_DIR}/defguard-grpc.csr -subj "/C=PL/ST=Zachodniopomorskie/L=Szczecin/O=Example/OU=IT Department/CN=${CFG_DOMAIN}" 2>&1 >> ${LOG_FILE} + cat >${SSL_DIR}/defguard-grpc.ext <&1 >> ${LOG_FILE} + + # generate CA-signed certificate for defguard proxy gRPC + openssl genrsa -out ${SSL_DIR}/defguard-proxy-grpc.key 2048 2>&1 >> ${LOG_FILE} + + openssl req -new -key ${SSL_DIR}/defguard-proxy-grpc.key -out ${SSL_DIR}/defguard-proxy-grpc.csr -subj "/C=PL/ST=Zachodniopomorskie/L=Szczecin/O=Example/OU=IT Department/CN=${CFG_DOMAIN}" 2>&1 >> ${LOG_FILE} + cat >${SSL_DIR}/defguard-proxy-grpc.ext <&1 >> ${LOG_FILE} +} + +generate_rsa() { + echo "Generating RSA keys in ${RSA_DIR}..." + mkdir -p ${RSA_DIR} + openssl genpkey -out ${RSA_DIR}/rsakey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048 2>&1 >> ${LOG_FILE} + +} + +generate_secret() { + generate_secret_inner "${SECRET_LENGTH}" +} + +generate_password() { + generate_secret_inner "${PASSWORD_LENGTH}" +} + +generate_secret_inner() { + local length="$1" + openssl rand -base64 ${length} | tr -d "=+/" | tr -d '\n' | cut -c1-${length-1} +} + +create_caddyfile() { + caddy_volume_path="${VOLUME_DIR}/caddy" + caddyfile_path="${caddy_volume_path}/Caddyfile" + mkdir -p ${caddy_volume_path} + + cat >${caddyfile_path} <>${caddyfile_path} <>${caddyfile_path} <&1 >> ${LOG_FILE} + + print_confirmation +} + +generate_env_file() { + PROD_ENV_FILE="${WORK_DIR_PATH}/${ENV_FILE}" + fetch_base_env_file + update_env_file + + print_confirmation +} + +fetch_base_env_file() { + echo -e " ${TXT_BEGIN} Fetching base ${ENV_FILE} file for compose stack..." + + curl --proto '=https' --tlsv1.2 -sSf "${BASE_ENV_FILE_URL}" -o "${PROD_ENV_FILE}" 2>&1 >> ${LOG_FILE} + print_confirmation +} + +update_env_file() { + echo -n " ${TXT_BEGIN} Setting environment variables in ${ENV_FILE} file for compose stack..." + + # set image versions + set_env_file_value "CORE_IMAGE_TAG" "${CORE_IMAGE_TAG}" + set_env_file_value "PROXY_IMAGE_TAG" "${PROXY_IMAGE_TAG}" + set_env_file_value "GATEWAY_IMAGE_TAG" "${GATEWAY_IMAGE_TAG}" + + # fill in values + set_env_file_secret "DEFGUARD_AUTH_SECRET" + set_env_file_secret "DEFGUARD_YUBIBRIDGE_SECRET" + set_env_file_secret "DEFGUARD_GATEWAY_SECRET" + set_env_file_secret "DEFGUARD_SECRET_KEY" + + # use existing password if set in env variable + if [ "$DEFGUARD_DB_PASSWORD" ]; then + set_env_file_value "DEFGUARD_DB_PASSWORD" "${DEFGUARD_DB_PASSWORD}" + else + set_env_file_password "DEFGUARD_DB_PASSWORD" + fi + + DEFGUARD_DEFAULT_ADMIN_PASSWORD="$(generate_password)" + set_env_file_value "DEFGUARD_DEFAULT_ADMIN_PASSWORD" "${DEFGUARD_DEFAULT_ADMIN_PASSWORD}" + + set_env_file_value "DEFGUARD_URL" "${CFG_DEFGUARD_URL}" + set_env_file_value "DEFGUARD_WEBAUTHN_RP_ID" "${CFG_DOMAIN}" + print_confirmation +} + +set_env_file_value() { + # make sure variable exists in file + grep -qF "${1}=" "${PROD_ENV_FILE}" || echo "${1}=" >>"${PROD_ENV_FILE}" + sed -i "s@\(${1}\)=.*@\1=${2}@" "${PROD_ENV_FILE}" +} + +set_env_file_secret() { + set_env_file_value "${1}" "$(generate_secret)" "${PROD_ENV_FILE}" +} + +set_env_file_password() { + set_env_file_value "${1}" "$(generate_password)" "${PROD_ENV_FILE}" +} + +uncomment_feature() { + sed -i "s@# \(.*\) # \[${1}\]@\1@" "${2}" +} + +enable_enrollment() { + echo -n " ${TXT_BEGIN} Enabling enrollment proxy service in compose file..." + + # update .env file + uncomment_feature "ENROLLMENT" "${PROD_ENV_FILE}" + set_env_file_value "DEFGUARD_ENROLLMENT_URL" "${CFG_ENROLLMENT_URL}" + + # update compose file + uncomment_feature "ENROLLMENT" "${PROD_COMPOSE_FILE}" + + print_confirmation +} + +enable_vpn_gateway() { + echo " ${TXT_BEGIN} Enabling VPN gateway service..." + + uncomment_feature "VPN" "${PROD_COMPOSE_FILE}" + uncomment_feature "VPN" "${PROD_ENV_FILE}" + + # fetch latest image + echo " ${TXT_SUB} Fetching latest gateway image..." + $COMPOSE_CMD -f "${PROD_COMPOSE_FILE}" --env-file "${PROD_ENV_FILE}" pull gateway + + # create VPN location + echo " ${TXT_BEGIN} Adding VPN to core & generating gateway token..." + VPN_NETWORK=`echo ${CFG_VPN_IP} | awk -F'[./]' '{print $1"."$2"."$3".0/"$5}'` + token=$($COMPOSE_CMD -f "${PROD_COMPOSE_FILE}" --env-file "${PROD_ENV_FILE}" run core init-vpn-location --name "${CFG_VPN_NAME}" --address "${CFG_VPN_IP}" --endpoint "${CFG_VPN_GATEWAY_IP}" --port "${CFG_VPN_GATEWAY_PORT}" --allowed-ips "${VPN_NETWORK}" | tail -n 1) + if [ $? -ne 0 ]; then + echo >&2 "ERROR: failed to create VPN network" + exit 1 + fi + + # add gateway token to .env file + set_env_file_value "DEFGUARD_TOKEN" "${token}" +} + +print_instance_summary() { + echo + echo -e "${C_LGREEN} ${TXT_CHECK} defguard setup finished successfully${C_END}" + echo + echo "If your DNS configuration is correct your defguard instance should be available at:" + echo + echo -e "\t${TXT_SUB} Web UI: ${C_BOLD}${CFG_DEFGUARD_URL}${C_END}" + if [ "$CFG_ENABLE_ENROLLMENT" ]; then + echo -e "\t${TXT_SUB} Enrollment service: ${C_BOLD}${CFG_ENROLLMENT_URL}${C_END}" + fi + echo + echo -e " ${TXT_BEGIN} You can log into the UI using the default admin user:" + echo + echo -e "\t${TXT_SUB} username: ${C_BOLD}admin${C_END}" + echo -e "\t${TXT_SUB} password: ${C_BOLD}${DEFGUARD_DEFAULT_ADMIN_PASSWORD}${C_END}" + echo + if [ "$CFG_ENABLE_VPN" ]; then + echo -e "\t\tVPN server public endpoint is ${C_BOLD}${CFG_VPN_GATEWAY_IP}:${CFG_VPN_GATEWAY_PORT}${C_END}" + echo -e "\t\tVPN network is ${C_BOLD}${VPN_NETWORK}${C_END}" + echo -e "\t\t! Make sure your firewall allows external UDP traffic to port ${C_BOLD}${CFG_VPN_GATEWAY_PORT}${C_END} !" + echo + echo -e "\t\tTo test if the VPN is working: ping ${CFG_VPN_IP} (after connecting to VPN)" + fi + echo + echo -e "Files used to deploy your instance are stored in:" + echo -e "\t docker compose file: ${C_BOLD}${PROD_COMPOSE_FILE}${C_END}" + echo -e "\t docker compose environment: ${C_BOLD}${PROD_ENV_FILE}${C_END}" + echo + echo -e "Persistent data (docker volumes) is stored in ${C_BOLD}${VOLUME_DIR}${C_END}" + echo + echo -e " ${C_YELLOW}${TXT_STAR} To support our work, please star us on GitHub! ${TXT_STAR}${C_END}" + echo -e " ${C_YELLOW}${TXT_STAR} https://github.com/defguard/defguard ${TXT_STAR}${C_END}" + echo +} + +# run main function +main "$@" || exit 1 diff --git a/deployment/docs/header.png b/deployment/docs/header.png new file mode 100644 index 0000000..3a02a4d Binary files /dev/null and b/deployment/docs/header.png differ diff --git a/deployment/gateway/.env b/deployment/gateway/.env new file mode 100644 index 0000000..26b58fe --- /dev/null +++ b/deployment/gateway/.env @@ -0,0 +1,10 @@ +# Use userspace wireguard implementation, useful on systems without native wireguard support + +# Set to 0/1 +DEFGUARD_USERSPACE=0 +# Defguard GRPC URL, e.g.: defguard-grpc.mycompany.com +DEFGUARD_GRPC_URL=http://192.168.1.197:50055/ +# Token from Defguard app to secure gRPC connection, available on network page. +DEFGUARD_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJEZWZHdWFyZCIsInN1YiI6IkRFRkdVQVJELU5FVFdPUkstMiIsImNsaWVudF9pZCI6IjIiLCJleHAiOjYwMTg2NjMyMjYsIm5iZiI6MTcyMzY5NTkzMX0.cmQTo1ZIflFAW-STanDi3rgb9lqE55Hf50yetX1BSUE +# Defines how often (in seconds) should interface statistics be sent to Defguard server +DEFGUARD_STATS_PERIOD=30 diff --git a/deployment/gateway/.env.template b/deployment/gateway/.env.template new file mode 100644 index 0000000..69a402e --- /dev/null +++ b/deployment/gateway/.env.template @@ -0,0 +1,9 @@ +# Use userspace wireguard implementation, useful on systems without native wireguard support +# Set to 0/1 +DEFGUARD_USERSPACE=0 +# Defguard GRPC URL, e.g.: defguard-grpc.mycompany.com +DEFGUARD_GRPC_URL= +# Token from Defguard app to secure gRPC connection, available on network page. +DEFGUARD_TOKEN= +# Defines how often (in seconds) should interface statistics be sent to Defguard server +DEFGUARD_STATS_PERIOD=30 diff --git a/deployment/gateway/.volumes/ssl/defguard-ca.key b/deployment/gateway/.volumes/ssl/defguard-ca.key new file mode 100644 index 0000000..6bc491c --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard-ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCbzBOckyI+yISZ +8+K+wkacfAR/NJsqJ1pyq7mKa+fbWMeINharP3G0qBmL56sromxl2zgC/9VU5lnR +UwSjvA5UtwOtfAxwhtRf9gmWYA6qUC8csSLev/nwTi/BiHzeJvEJFB5y4JCMPfs/ +grRVWIW79to3zIUY2PKLcY9xvQwGwn9w9nYasnESdv2931ZTWR0ibYkrhMfqt1eW +njB63ZISWWoIVirO/WfcoAMtihuGt1IK/tlARk1nT1SFAhNncG59tzMa7uz2jJIq +c3JEoAhMeClH08Yv0+rRIB3dXExEKg5/6wr8eE7hGBpBEfpaeMPQocQYwLBEH82f +vR9hioTNAgMBAAECggEABsjeWcU2ipFk5OdwCmqfdJUaBQgfcbiBAdlknRiR4kV9 +evsQBakfpIRliGgwVhgerFjdmZPWkHnvk2QQIalA3oORz25FhGj6uqsWQ8wvF0+i +nZdBM34cvlBJWB4/gdUkTgboRIxu/wx78ooYnFbcjBD189QeP7TC6zuoyYU4Dts8 +FaJ4FcGa+tKFWhCh2wqtGxisHOxUmgaMmkOljLcpLmEA7DpUfRew7dIHptkGylox +8ahyVVTPq8H5R1lsshvDw0MFLsS12hHtTn1yicTFQNOg8JGX9lV67fCyC3pFxLiR +ZtGcUe0MiiCVltHOqwPQEBsIcweN0SRk2JZA0FnAAQKBgQDPKveaqNuU9rY7R0QF +8mjVnbPbobrmi5k9XqvuoPOuDA/86e0BYlv7BDST8Y8hOyK9aBScg+4vCKvEptoR +AGDIjdd2GueGW/HjwZa2kjunXQk0Rn1C9OsQpwNLTR3XLwmPyWvMZLVMEx/bGuLg +lNgxj+qetmSq2jwpYLkpZqiYAQKBgQDAhUXsd5uXuDtzp8NToxaoO+juKFYIRNKF +EP6m/7Pmwb2PGAT+a7erI9wktKdpN/AL8uQjder0hOHmN/ik+nwEB04HHDQxyoXt +VzayzBuhjfEKg+QwWuRu79eTlFd2Ed4bYbsPod1XMfj9XSI64wFZZCNF2XqfRiuU +uuFkE2jMzQKBgQCVjdAnj0TNWfkd/AmIPYIey/T+VdfF/PsICaMW5oxjlgOosfrN +qAL8yAFo19ZayAUBNPTENJ2qyJivo0ADTAGSZosnkK6ZGSEbKTKy5Ag6fvhZC5X7 +0zEq2VaQcsBbCnLdoSu35u/WVmwF0Xf9ZpZX2SwnnUY47MjHmjKxR5HoAQKBgQCD +FjwWVxrKo9dXWNPXDyVOR/zCrRRnbPUrRfcfHt0QMrsvw9sioZXeIfyzwY58Rmpc +uHY+7vucox5t846KR0RKOe8XSE0B2jR29vt3oyLtTgjicAvgIQOJxiWzhz5GVsQ1 +QMZuTni39n7jhZbZIdi5VUXvObYU3WKvUtBFpDGnwQKBgA3GtNzxQ8vzUkciUfue +uHaStFZEASM8m+Fz6J5JDTVzeHzJA6vFQCm2YPFqWlYHZLTZsuXWknm0iCntPCMN +Bbn0J5Ap8IUg3mzm4IHVGUNkGKrLm3Go77E4ZZrYOq7O2dGdtJPQppMaJ10FXdUr +pHiQmASJ88fBasr1sQ12/2vQ +-----END PRIVATE KEY----- diff --git a/deployment/gateway/.volumes/ssl/defguard-ca.pem b/deployment/gateway/.volumes/ssl/defguard-ca.pem new file mode 100644 index 0000000..e201106 --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIUFAaYomt0LdhGk7d3r7/cojUSpYowDQYJKoZIhvcNAQEL +BQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQwwCgYDVQQHDANOWUMxITAf +BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA4MTUwNzA1MDRa +Fw0zNDA4MTMwNzA1MDRaMEsxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEMMAoG +A1UEBwwDTllDMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbzBOckyI+yISZ8+K+wkacfAR/ +NJsqJ1pyq7mKa+fbWMeINharP3G0qBmL56sromxl2zgC/9VU5lnRUwSjvA5UtwOt +fAxwhtRf9gmWYA6qUC8csSLev/nwTi/BiHzeJvEJFB5y4JCMPfs/grRVWIW79to3 +zIUY2PKLcY9xvQwGwn9w9nYasnESdv2931ZTWR0ibYkrhMfqt1eWnjB63ZISWWoI +VirO/WfcoAMtihuGt1IK/tlARk1nT1SFAhNncG59tzMa7uz2jJIqc3JEoAhMeClH +08Yv0+rRIB3dXExEKg5/6wr8eE7hGBpBEfpaeMPQocQYwLBEH82fvR9hioTNAgMB +AAGjUzBRMB0GA1UdDgQWBBSuVx6w1tDFOr/nxkhH5zUCoKQjnjAfBgNVHSMEGDAW +gBSuVx6w1tDFOr/nxkhH5zUCoKQjnjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQATnuDVzsiLdg1D7KIWvavEv4l0aj1TzMAnev7ASoCeDumVKxrv +1F8B8gKiYtA0r1GXInq0x9o4/u7nZK00hqyPBvHmTDCwimV0KMD+XEcg28rwTfn8 +0RbVcUIEMNVRs1eEV3wSUHoJMxhEf7kSGJ7X8C+zu0CEQ9loBqAAbO7unhJZuoT6 +TixM0nqV5ss3hkk8RFhe3902mRT8Fit5wotNHRYquvi8yku4EZyArudjkQoalCBV +CNnhWxTug+Sc1XY6jMWdfFnU4bVK+hjuSnYwIM6VRDXmYRGuxCFf8lEfQNIRUOdF +N9Xp6iJcj0Lg3lW4i9lLS2z/jW+ICgtPYTcK +-----END CERTIFICATE----- diff --git a/deployment/gateway/.volumes/ssl/defguard-ca.srl b/deployment/gateway/.volumes/ssl/defguard-ca.srl new file mode 100644 index 0000000..d1af3cc --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard-ca.srl @@ -0,0 +1 @@ +21E9338B4AD12CCAF2F29C30B8DA6E8C7D993090 diff --git a/deployment/gateway/.volumes/ssl/defguard.crt b/deployment/gateway/.volumes/ssl/defguard.crt new file mode 100644 index 0000000..faac8fd --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDHTCCAgUCFCHpM4tK0SzK8vKcMLjabox9mTCQMA0GCSqGSIb3DQEBCwUAMEsx +CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEMMAoGA1UEBwwDTllDMSEwHwYDVQQK +DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjQwODE1MDcwNTQ5WhcNMjUw +ODE1MDcwNTQ5WjBLMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxDDAKBgNVBAcM +A05ZQzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9RdFYdklQ94lioWaFDEOb/1KeQ8BQ1X +b0YjYvgJ+rWobMNRls7A12g+gJ8EAPVDP7p9YaC06ovievSfaueC9byo9lfWsUrW +mwNA4/lH82j+/qKl8Yi8doBnQ6UAlSmt/g0PYE+/PQvRahld1K0LvqOpZIVa5imv +NY0h9Bt9J9gYKSZPvTh4MapsWGdVurkLUvQglfU4DpHKGvRoGT1nMYKX7BlFgtkM +hzD4jRoyOFyXwyyL9UFqHFYUozscPmm5deX0nNcfOs0NUOBHp11u+MG8R9mThct2 +JzEmu9lXxshBVk1Yrf7kHpZuW0YrvqNCSRYu9MiBiPSTZGdt1TrsoQIDAQABMA0G +CSqGSIb3DQEBCwUAA4IBAQAW17f+yj2IJis7SmrKFho1+bQapQac0err61g7jGYS +5Jo7f0Qvk7K5FUwwAbqF6zr8C31+PZrZmou1n8ht6y4rf/mmZV3ujuSf8cRuX9Jr +RpBpwDhBQU51/iZaQm+eDwuw8KJDGnHRQE7EzP6CNO5G9M7YblI3nJdcbXIog1Y7 +JgOOf5UZmerVhQm9wUNvVJ19p4qWW5u1AGXSaXTu2tcj6NSMITT2lLL321AdL4Vs +Zl7vpUV6ZbyDd7rYwqXnWEFLIWWTi9CKk8nSe130oag8PPhNCOFUY39M/1u1ZfeC +LypC2FNYJseA+xZnZXxAXkDOBLt8rIxTykVxAR8idElN +-----END CERTIFICATE----- diff --git a/deployment/gateway/.volumes/ssl/defguard.csr b/deployment/gateway/.volumes/ssl/defguard.csr new file mode 100644 index 0000000..47dd702 --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICrzCCAZcCAQAwSzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQwwCgYDVQQH +DANOWUMxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALvUXRWHZJUPeJYqFmhQxDm/9SnkPAUN +V29GI2L4Cfq1qGzDUZbOwNdoPoCfBAD1Qz+6fWGgtOqL4nr0n2rngvW8qPZX1rFK +1psDQOP5R/No/v6ipfGIvHaAZ0OlAJUprf4ND2BPvz0L0WoZXdStC76jqWSFWuYp +rzWNIfQbfSfYGCkmT704eDGqbFhnVbq5C1L0IJX1OA6Ryhr0aBk9ZzGCl+wZRYLZ +DIcw+I0aMjhcl8Msi/VBahxWFKM7HD5puXXl9JzXHzrNDVDgR6ddbvjBvEfZk4XL +dicxJrvZV8bIQVZNWK3+5B6WbltGK76jQkkWLvTIgYj0k2RnbdU67KECAwEAAaAf +MB0GCSqGSIb3DQEJBzEQDA5aYWthcmlhMTk4NiEhITANBgkqhkiG9w0BAQsFAAOC +AQEAUae4G2/G01LzT4MyTRhXja8uU1AKbxx7KztIN9WxWsRgQJjLte9gcANcsku+ +e+yrMlfm+LjTRH6bG3yNyyxFWncS8IyG3a+N2rvXoEO4lMIwQfyanYPyOB0ONoR3 +fzB+Ssgw8txiXwOSIG7KsQkebJ30aSqUe6FuUd9kY02bx1NYGvctf9mtBv+d9Q5Y +xYv1S0S6TtjB9PnUMWdfLm0Xmj9X0XzPjKrtxwamJ/AF3uTsQseuqcKQpbLCd32r +w0mjeZHtVrDgrxVgqxt1c86eAHwnhmD4jy9Vl2tJLcPNIXvTQNxoi5h/tYi1TlD3 +Mj6K46g29ee1HiLaL7ZbJb7Geg== +-----END CERTIFICATE REQUEST----- diff --git a/deployment/gateway/.volumes/ssl/defguard.key b/deployment/gateway/.volumes/ssl/defguard.key new file mode 100644 index 0000000..c6eb4ad --- /dev/null +++ b/deployment/gateway/.volumes/ssl/defguard.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC71F0Vh2SVD3iW +KhZoUMQ5v/Up5DwFDVdvRiNi+An6tahsw1GWzsDXaD6AnwQA9UM/un1hoLTqi+J6 +9J9q54L1vKj2V9axStabA0Dj+UfzaP7+oqXxiLx2gGdDpQCVKa3+DQ9gT789C9Fq +GV3UrQu+o6lkhVrmKa81jSH0G30n2BgpJk+9OHgxqmxYZ1W6uQtS9CCV9TgOkcoa +9GgZPWcxgpfsGUWC2QyHMPiNGjI4XJfDLIv1QWocVhSjOxw+abl15fSc1x86zQ1Q +4EenXW74wbxH2ZOFy3YnMSa72VfGyEFWTVit/uQelm5bRiu+o0JJFi70yIGI9JNk +Z23VOuyhAgMBAAECggEAKwwkuUZqeu8sx92lfQrlrgacfZldWBsSquH8QjZusxLn +IuYw0MtZzwSJLplDJaUQYI6xJarbS9X7dgqSbsHYddFjN/IxtjhcrvIz8Qu0vciW +iG1mctDPwKj1Ab/TPlxrEAqWN5CPV8JZoGNn6dIvGuYPcIZPquhqy28pFPUn3fV3 +cSS2dR3D6OU6yxEImZGffDwrZdXTTM+N1QMLHl4ivPzIjzrbwlVMVVODKracNvUE +79wYcieiEgbAM3DzlHnaW4BINw2ugoWFTAKMtHiVV8U3wQhDKvwljgFMTjB9O6PQ +nXRzoVwW5KX9gwpo9CBNVWn8/D+S04KHObC4cIKeQQKBgQD3ugq2sU1zXnBh/n7P +4Ac0Fv8Xwd/Ai3gRraJ3fFHKdwWKIL0m5DWDvALhoM+I/joLgUy0SV05R+iQzSu3 +3hLrp9GqWn/drNOvUhnPeO1MwvHATpDRCEkza5I1uRn6wZf95eclvDgocqnutWGv +t43sccm38iivIzs2YYmPdgQ75QKBgQDCGjnxXwU/wHV+uOFNSs5R/LIpCpqGzoW7 +5PQguJQOQY2Gq3aoPwnSGycgkOfkg2cibv04lDuoCnooYAc6SZy0N0wy9FDAsuzB ++6RNHGrr3jsqKJkRPwDal4Hb9AIMkhcIt9RIzEjO4nMKb7GxkhKD5glFVxWlNmMT +CWmXuIo6DQKBgQDM1epx8d1m3dnzTWoyHL4YFkPLsyV+olQf2gES55sB3LSZ6EQ/ +Wkfdq6J+SmgQkJYSWVHBaUBKUuk8gkn5+QiQDu3Q/I/qDjPjLfHlmcotxKv9JXmd +Pkq41+PHxEx1CYrSCD2++Ak/eMCGfzhNAWu67MOs8/EsD+ewKaqDE0Sg+QKBgAVx +ktpwHceR8Dmjmb3/MRYfjieUgozxUdLZMveP9acIs51pRaSmT/IyjMBfEAHapZPT +pQpnLd0inhZvywQZeGmde2eaboFZA0bVdeArwdvnmaUvCkvvhmibAytWBpCvsDGw +ZiW8hPY4Z52NUGB4hkhotS3aqWK+ybyI8QsuQ8IpAoGBAIsY6ARakykXZueMGLQN +B7n5cyoWlQNr3iD0UCUMDHqjUe8IUIfw1ZMaHun+aI3UaY/chHBkaxfy+0IQatNd +1F9wmCNmHrjjoBLPEqPvh7TeAEfzexi4fnadLukXWb9KyZLA9YEdos4CK9EE0+Nx +6r076e6gFIRQr09qR7pGz9TQ +-----END PRIVATE KEY----- diff --git a/deployment/gateway/defguard-gateway-linux-x86_64-v0.7.0-x86_64-unknown-linux-gnu.tar.gz b/deployment/gateway/defguard-gateway-linux-x86_64-v0.7.0-x86_64-unknown-linux-gnu.tar.gz new file mode 100644 index 0000000..1d4f2f8 Binary files /dev/null and b/deployment/gateway/defguard-gateway-linux-x86_64-v0.7.0-x86_64-unknown-linux-gnu.tar.gz differ diff --git a/deployment/gateway/docker-compose.yaml b/deployment/gateway/docker-compose.yaml new file mode 100644 index 0000000..539bde2 --- /dev/null +++ b/deployment/gateway/docker-compose.yaml @@ -0,0 +1,22 @@ + +services: + gateway: + image: ghcr.io/defguard/gateway:latest + restart: unless-stopped + network_mode: "host" + environment: + # load variables from .env file + - DEFGUARD_GRPC_URL + - DEFGUARD_TOKEN + - DEFGUARD_STATS_PERIOD + - RUST_LOG=debug + # SSL setup guide: https://defguard.gitbook.io/defguard/features/setting-up-your-instance/docker-compose#ssl-setup + - DEFGUARD_GRPC_CA=/ssl/defguard-ca.pem + #ports: + # wireguard endpoint + #- "51820:50051/udp" + volumes: + # SSL setup guide: https://defguard.gitbook.io/defguard/features/setting-up-your-instance/docker-compose#ssl-setup + - ./.volumes/ssl:/ssl + cap_add: + - NET_ADMIN