From 366bb56596bee065616a5d9c31af9020d17888f5 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 12:38:16 +0100 Subject: [PATCH 01/21] Add workflows for the chart to CI Signed-off-by: maksim.nabokikh --- .github/dependabot.yml | 25 +++++++ .github/release.yml | 17 +++++ .github/workflows/chart-release.yml | 35 +++++++++ .github/workflows/chart-test.yaml | 107 ++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/release.yml create mode 100644 .github/workflows/chart-release.yml create mode 100644 .github/workflows/chart-test.yaml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..94c3ffb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + # Dependencies listed in go.mod + - package-ecosystem: "gomod" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + # Dependencies listed in .github/workflows/*.yml + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + + # Dependencies listed in Dockerfile + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + + # Dependencies listed in frontend/package.json + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..582f625 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,17 @@ +changelog: + exclude: + labels: + - ignore + categories: + - title: Enhancements 🚀 + labels: + - enhancement + - title: Bug Fixes 🐛 + labels: + - bug + - title: Dependency Updates ⬆️ + labels: + - dependencies + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml new file mode 100644 index 0000000..12b076d --- /dev/null +++ b/.github/workflows/chart-release.yml @@ -0,0 +1,35 @@ +name: Release Charts + +on: + push: + branches: + - master + paths: + - 'helm/**' + +jobs: + chart-release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + 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@v4 + with: + version: v3.7.1 + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + with: + charts_dir: charts + config: charts/cr.yaml + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/chart-test.yaml b/.github/workflows/chart-test.yaml new file mode 100644 index 0000000..1dcab4e --- /dev/null +++ b/.github/workflows/chart-test.yaml @@ -0,0 +1,107 @@ +name: Chart Test +on: + push: + tags: + - v* + branches: + - master + pull_request: + branches: + - master + +jobs: + chart: + name: Chart + + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.changes.outputs.changed }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.10.3 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + - name: Lint + run: ct lint + + - name: Check generated docs + run: | + make docs + test "$(git diff --name-only)" == "" \ + || ( printf >&2 "\nREADME files are not up to date (run 'make docs'), differences:\n\n%s\n\n" "$(git diff)" ; exit 1 ; ) + + - name: Detect changes + id: changes + run: | + changed=$(ct list-changed) + if [[ -n "$changed" ]]; then + echo "changed=true" >> $GITHUB_OUTPUT + fi + + chart-test: + name: Chart Test + runs-on: ubuntu-latest + needs: chart + if: needs.chart.outputs.changed == 'true' + strategy: + fail-fast: false + matrix: + kube: ["1.24", "1.25", "1.26"] + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.10.3 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.6.1 + + # See https://github.com/kubernetes-sigs/kind/releases/tag/v0.17.0 + - name: Determine KinD node image version + id: node_image + run: | + case ${{ matrix.kube }} in + 1.24) + NODE_IMAGE=kindest/node:v1.24.7@sha256:577c630ce8e509131eab1aea12c022190978dd2f745aac5eb1fe65c0807eb315 ;; + 1.25) + NODE_IMAGE=kindest/node:v1.25.3@sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1 ;; + 1.26) + NODE_IMAGE=kindest/node:v1.26.0@sha256:691e24bd2417609db7e589e1a479b902d2e209892a10ce375fab60a8407c7352 ;; + esac + + echo "image=$NODE_IMAGE" >> $GITHUB_OUTPUT + + - name: Create KinD cluster + uses: helm/kind-action@v1.12.0 + with: + version: v0.17.0 + node_image: ${{ steps.node_image.outputs.image }} + + - name: Test + run: ct install From 5d6a032cc496846718e2c1be15aff14db4830672 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 12:57:06 +0100 Subject: [PATCH 02/21] Move chart to a dedicated folder Signed-off-by: maksim.nabokikh --- .github/workflows/chart-release.yml | 2 +- helm/Chart.yaml | 2 - helm/README.md | 1 - helm/templates/configmap.yaml | 88 --------------------- helm/templates/deployment.yaml | 117 ---------------------------- helm/templates/ingress.yaml | 39 ---------- helm/templates/rbac.yaml | 36 --------- helm/templates/secret.yaml | 8 -- helm/templates/service.yaml | 57 -------------- helm/values.yaml | 26 ------- 10 files changed, 1 insertion(+), 375 deletions(-) delete mode 100644 helm/Chart.yaml delete mode 100644 helm/README.md delete mode 100644 helm/templates/configmap.yaml delete mode 100644 helm/templates/deployment.yaml delete mode 100644 helm/templates/ingress.yaml delete mode 100644 helm/templates/rbac.yaml delete mode 100644 helm/templates/secret.yaml delete mode 100644 helm/templates/service.yaml delete mode 100644 helm/values.yaml diff --git a/.github/workflows/chart-release.yml b/.github/workflows/chart-release.yml index 12b076d..7956c29 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/chart-release.yml @@ -5,7 +5,7 @@ on: branches: - master paths: - - 'helm/**' + - 'charts/**' jobs: chart-release: diff --git a/helm/Chart.yaml b/helm/Chart.yaml deleted file mode 100644 index 71838aa..0000000 --- a/helm/Chart.yaml +++ /dev/null @@ -1,2 +0,0 @@ -name: ovpn-admin -version: 1.0.0 diff --git a/helm/README.md b/helm/README.md deleted file mode 100644 index eabf182..0000000 --- a/helm/README.md +++ /dev/null @@ -1 +0,0 @@ -helm chart example diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml deleted file mode 100644 index 076e72d..0000000 --- a/helm/templates/configmap.yaml +++ /dev/null @@ -1,88 +0,0 @@ -{{ $openvpnNetwork := required "A valid .Values.openvpn.subnet entry required!" .Values.openvpn.subnet }} -{{ $openvpnNetworkAddress := index (splitList "/" $openvpnNetwork) 0 }} -{{ $openvpnNetworkNetmask := index (splitList "/" $openvpnNetwork) 1 }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: openvpn -data: - openvpn.conf: |- - user nobody - group nogroup - - mode server - tls-server - # dev-type tun - dev tun - proto tcp-server - port 1194 - # local 127.0.0.1 - management 127.0.0.1 8989 - - tun-mtu 1500 - mssfix - # only udp - #fragment 1300 - - keepalive 10 60 - client-to-client - persist-key - persist-tun - - cipher AES-128-CBC - duplicate-cn - - server {{ $openvpnNetworkAddress }} {{ $openvpnNetworkNetmask }} - - topology subnet - push "topology subnet" - push "route-metric 9999" - - verb 4 - - ifconfig-pool-persist /tmp/openvpn.ipp - status /tmp/openvpn.status - - key-direction 0 - - ca /etc/openvpn/certs/pki/ca.crt - key /etc/openvpn/certs/pki/private/server.key - cert /etc/openvpn/certs/pki/issued/server.crt - dh /etc/openvpn/certs/pki/dh.pem - crl-verify /etc/openvpn/certs/pki/crl.pem - tls-auth /etc/openvpn/certs/pki/ta.key - client-config-dir /etc/openvpn/ccd - - entrypoint.sh: |- - #!/bin/sh - set -x - - iptables -t nat -A POSTROUTING -s {{ $openvpnNetworkAddress }}/{{ $openvpnNetworkNetmask }} ! -d {{ $openvpnNetworkAddress }}/{{ $openvpnNetworkNetmask }} -j MASQUERADE - - mkdir -p /dev/net - if [ ! -c /dev/net/tun ]; then - mknod /dev/net/tun c 10 200 - fi - - wait_file() { - file_path="$1" - while true; do - if [ -f $file_path ]; then - break - fi - echo "wait $file_path" - sleep 2 - done - } - - easyrsa_path="/etc/openvpn/certs" - - wait_file "$easyrsa_path/pki/ca.crt" - wait_file "$easyrsa_path/pki/private/server.key" - wait_file "$easyrsa_path/pki/issued/server.crt" - wait_file "$easyrsa_path/pki/ta.key" - wait_file "$easyrsa_path/pki/dh.pem" - wait_file "$easyrsa_path/pki/crl.pem" - - openvpn --config /etc/openvpn/openvpn.conf diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml deleted file mode 100644 index 1cc0538..0000000 --- a/helm/templates/deployment.yaml +++ /dev/null @@ -1,117 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: openvpn -spec: - selector: - matchLabels: - app: openvpn - template: - metadata: - labels: - app: openvpn - spec: - {{- if .Values.openvpn.nodeSelector }} - nodeSelector: - {{- .Values.openvpn.nodeSelector | toYaml | indent 8 | printf "\n%s" }} - {{- end }} - {{- if .Values.openvpn.tolerations }} - tolerations: - {{- .Values.openvpn.tolerations | toYaml | indent 8 | printf "\n%s" }} - {{- end }} - terminationGracePeriodSeconds: 0 - serviceAccountName: openvpn - containers: - - name: ovpn-admin - image: {{ .Values.ovpnAdmin.image }} - command: - - /bin/sh - - -c - - /app/ovpn-admin - --storage.backend="kubernetes.secrets" - --listen.host="0.0.0.0" - --listen.port="8000" - --role="master" - {{- if hasKey .Values.openvpn "inlet" }} - {{- if eq .Values.openvpn.inlet "LoadBalancer" }} - --ovpn.server.behindLB - --ovpn.service="openvpn-external" - {{- end }} - {{- end }} - --mgmt=main="127.0.0.1:8989" - --ccd --ccd.path="/mnt/ccd" - --easyrsa.path="/mnt/certs" - {{- $externalHost := "" }} - {{- if hasKey .Values.openvpn "inlet" }} - {{- if eq .Values.openvpn.inlet "ExternalIP" }}{{ $externalHost = .Values.openvpn.externalIP }}{{- end }} - {{- end }} - {{- if hasKey .Values.openvpn "externalHost" }}{{ $externalHost = .Values.openvpn.externalHost }}{{- end }} - {{- if ne $externalHost "" }} - --ovpn.server="{{ $externalHost }}:{{ .Values.openvpn.externalPort | default 5416 | quote }}:tcp" - {{- end }} - ports: - - name: ovpn-admin - protocol: TCP - containerPort: 8000 - volumeMounts: - - name: certs - mountPath: /mnt/certs - - name: ccd - mountPath: /mnt/ccd - - name: openvpn - image: {{ .Values.openvpn.image }} - command: [ '/entrypoint.sh' ] - # imagePullPolicy: Always - securityContext: - allowPrivilegeEscalation: false - capabilities: - add: - - NET_ADMIN - - NET_RAW - - MKNOD - - SETGID - - SETUID - drop: - - ALL - ports: - - name: openvpn-tcp - protocol: TCP - containerPort: 1194 - {{- if eq .Values.openvpn.inlet "HostPort" }} - hostPort: {{ .Values.openvpn.hostPort }} - {{- end }} - volumeMounts: - - name: tmp - mountPath: /tmp - - name: dev-net - mountPath: /dev/net - - name: certs - mountPath: /etc/openvpn/certs - - name: ccd - mountPath: /etc/openvpn/ccd - - name: config - mountPath: /etc/openvpn/openvpn.conf - subPath: openvpn.conf - readOnly: true - - name: entrypoint - mountPath: /entrypoint.sh - subPath: entrypoint.sh - readOnly: true - volumes: - - name: tmp - emptyDir: {} - - name: dev-net - emptyDir: {} - - name: certs - emptyDir: {} - - name: ccd - emptyDir: {} - - name: config - configMap: - name: openvpn - defaultMode: 0644 - - name: entrypoint - configMap: - name: openvpn - defaultMode: 0755 diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml deleted file mode 100644 index 8f227ef..0000000 --- a/helm/templates/ingress.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: ovpn-admin - annotations: - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/backend-protocol: HTTP - nginx.ingress.kubernetes.io/auth-type: basic - nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" - nginx.ingress.kubernetes.io/auth-secret: basic-auth -spec: - tls: - - hosts: - - {{ .Values.domain }} - secretName: ingress-tls - rules: - - host: {{ .Values.domain }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: ovpn-admin - port: - name: http ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: ovpn-admin -spec: - secretName: ingress-tls - dnsNames: - - {{ .Values.domain }} - issuerRef: - name: letsencrypt - kind: ClusterIssuer diff --git a/helm/templates/rbac.yaml b/helm/templates/rbac.yaml deleted file mode 100644 index 4693d83..0000000 --- a/helm/templates/rbac.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: openvpn ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: openvpn -rules: -- apiGroups: - - "" - resources: - - services - verbs: - - get - - list -- apiGroups: - - "" - resources: - - secrets - verbs: - - "*" ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: openvpn -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: openvpn -subjects: -- kind: ServiceAccount - name: openvpn diff --git a/helm/templates/secret.yaml b/helm/templates/secret.yaml deleted file mode 100644 index b2dd27d..0000000 --- a/helm/templates/secret.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: basic-auth -type: Opaque -data: - auth: {{ print .Values.ovpnAdmin.basicAuth.user ":{PLAIN}" .Values.ovpnAdmin.basicAuth.password | b64enc | quote }} diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml deleted file mode 100644 index e04e626..0000000 --- a/helm/templates/service.yaml +++ /dev/null @@ -1,57 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: ovpn-admin -spec: - clusterIP: None - ports: - - name: http - port: 8000 - protocol: TCP - targetPort: 8000 - selector: - app: openvpn ---- -{{- if hasKey .Values.openvpn "inlet" }} - - {{- if eq .Values.openvpn.inlet "LoadBalancer" }} ---- -apiVersion: v1 -kind: Service -metadata: - name: openvpn-external -spec: - externalTrafficPolicy: Local - type: LoadBalancer - ports: - - name: openvpn-tcp - protocol: TCP - port: {{ .Values.openvpn.externalPort | default 1194 }} - targetPort: openvpn-tcp - selector: - app: openvpn - {{- else if eq .Values.openvpn.inlet "ExternalIP" }} ---- -apiVersion: v1 -kind: Service -metadata: - name: openvpn-external -spec: - type: ClusterIP - externalIPs: - - {{ .Values.openvpn.externalIP }} - ports: - - name: openvpn-tcp - port: {{ .Values.openvpn.externalPort | default 1194 }} - protocol: TCP - targetPort: openvpn-tcp - selector: - app: openvpn - {{- else if eq .Values.openvpn.inlet "HostPort" }} ---- - {{- else }} - {{- cat "Unsupported inlet type" .inlet | fail }} - {{- end }} - -{{- end }} diff --git a/helm/values.yaml b/helm/values.yaml deleted file mode 100644 index 544e3dd..0000000 --- a/helm/values.yaml +++ /dev/null @@ -1,26 +0,0 @@ -domain: changeme -ovpnAdmin: - image: changeme - basicAuth: - user: admin - password: changeme -openvpn: - image: changeme - subnet: 172.16.200.0/255.255.255.0 - # nodeSelector: - # node-role.kubernetes.io/master: "" - # tolerations: - # - effect: NoSchedule - # key: node-role.kubernetes.io/master - # - # // LoadBalancer or ExternalIP or HostPort - inlet: HostPort - # - # If inlet: ExternalIP - # externalIP: 1.2.3.4 - # externalPort: 1194 - # - # If inlet: HostPort - hostPort: 1194 - # Domain or ip for connect to OpenVPN server - # externalHost: 1.2.3.4 From 4ae8648be41731619691d500a4db823d77f777bd Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 12:58:17 +0100 Subject: [PATCH 03/21] Add Makefile Signed-off-by: maksim.nabokikh --- Makefile | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..535660b --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +export PATH := $(abspath bin/protoc/bin/):$(abspath bin/):${PATH} +export SHELL := env PATH=$(PATH) /bin/sh + +GOOS?=$(shell go env GOOS) +GOARCH?=$(shell go env GOARCH) +GOLANGCI_VERSION = 1.55.2 +HELM_DOCS_VERSION = 1.11.0 + +ifeq ($(GOARCH),arm) + ARCH=armv7 +else + ARCH=$(GOARCH) +endif + +COMMIT=$(shell git rev-parse --verify HEAD) + +########### +# BUILDING +########### + +########### +# LINTING +########### +bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION} + @ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint + +bin/golangci-lint-${GOLANGCI_VERSION}: + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | BINARY=golangci-lint bash -s -- v${GOLANGCI_VERSION} + @mv bin/golangci-lint $@ + +########### +# HELM +########### + +bin/helm-docs: bin/helm-docs-${HELM_DOCS_VERSION} + @ln -sf helm-docs-${HELM_DOCS_VERSION} bin/helm-docs +bin/helm-docs-${HELM_DOCS_VERSION}: + @mkdir -p bin + curl -L https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS_VERSION}/helm-docs_${HELM_DOCS_VERSION}_$(shell uname)_x86_64.tar.gz | tar -zOxf - helm-docs > ./bin/helm-docs-${HELM_DOCS_VERSION} && chmod +x ./bin/helm-docs-${HELM_DOCS_VERSION} + +.PHONY: lint fix +lint: bin/golangci-lint + bin/golangci-lint run + +fix: bin/golangci-lint + bin/golangci-lint run --fix + +.PHONY: docs +docs: bin/helm-docs + bin/helm-docs -s file -c charts/ -t README.md.gotmpl + +########### +# TESTING +########### From 3202758735b690b497e53cc1773737e3b8d21feb Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 13:09:31 +0100 Subject: [PATCH 04/21] Fix gitignore Signed-off-by: maksim.nabokikh --- .gitignore | 4 - charts/openvpn-admin/Chart.yaml | 2 + charts/openvpn-admin/README.md | 1 + charts/openvpn-admin/templates/configmap.yaml | 88 +++++++++++++ .../openvpn-admin/templates/deployment.yaml | 117 ++++++++++++++++++ charts/openvpn-admin/templates/ingress.yaml | 39 ++++++ charts/openvpn-admin/templates/rbac.yaml | 36 ++++++ charts/openvpn-admin/templates/secret.yaml | 8 ++ charts/openvpn-admin/templates/service.yaml | 57 +++++++++ charts/openvpn-admin/values.yaml | 26 ++++ 10 files changed, 374 insertions(+), 4 deletions(-) create mode 100644 charts/openvpn-admin/Chart.yaml create mode 100644 charts/openvpn-admin/README.md create mode 100644 charts/openvpn-admin/templates/configmap.yaml create mode 100644 charts/openvpn-admin/templates/deployment.yaml create mode 100644 charts/openvpn-admin/templates/ingress.yaml create mode 100644 charts/openvpn-admin/templates/rbac.yaml create mode 100644 charts/openvpn-admin/templates/secret.yaml create mode 100644 charts/openvpn-admin/templates/service.yaml create mode 100644 charts/openvpn-admin/values.yaml diff --git a/.gitignore b/.gitignore index 6f8f5aa..f2ff5c7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,6 @@ easyrsa_slave ccd ccd_master ccd_slave -openvpn-web-ui* -openvpn-ui* -openvpn-admin* -ovpn-admin* frontend/node_modules main-packr.go diff --git a/charts/openvpn-admin/Chart.yaml b/charts/openvpn-admin/Chart.yaml new file mode 100644 index 0000000..71838aa --- /dev/null +++ b/charts/openvpn-admin/Chart.yaml @@ -0,0 +1,2 @@ +name: ovpn-admin +version: 1.0.0 diff --git a/charts/openvpn-admin/README.md b/charts/openvpn-admin/README.md new file mode 100644 index 0000000..eabf182 --- /dev/null +++ b/charts/openvpn-admin/README.md @@ -0,0 +1 @@ +helm chart example diff --git a/charts/openvpn-admin/templates/configmap.yaml b/charts/openvpn-admin/templates/configmap.yaml new file mode 100644 index 0000000..076e72d --- /dev/null +++ b/charts/openvpn-admin/templates/configmap.yaml @@ -0,0 +1,88 @@ +{{ $openvpnNetwork := required "A valid .Values.openvpn.subnet entry required!" .Values.openvpn.subnet }} +{{ $openvpnNetworkAddress := index (splitList "/" $openvpnNetwork) 0 }} +{{ $openvpnNetworkNetmask := index (splitList "/" $openvpnNetwork) 1 }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: openvpn +data: + openvpn.conf: |- + user nobody + group nogroup + + mode server + tls-server + # dev-type tun + dev tun + proto tcp-server + port 1194 + # local 127.0.0.1 + management 127.0.0.1 8989 + + tun-mtu 1500 + mssfix + # only udp + #fragment 1300 + + keepalive 10 60 + client-to-client + persist-key + persist-tun + + cipher AES-128-CBC + duplicate-cn + + server {{ $openvpnNetworkAddress }} {{ $openvpnNetworkNetmask }} + + topology subnet + push "topology subnet" + push "route-metric 9999" + + verb 4 + + ifconfig-pool-persist /tmp/openvpn.ipp + status /tmp/openvpn.status + + key-direction 0 + + ca /etc/openvpn/certs/pki/ca.crt + key /etc/openvpn/certs/pki/private/server.key + cert /etc/openvpn/certs/pki/issued/server.crt + dh /etc/openvpn/certs/pki/dh.pem + crl-verify /etc/openvpn/certs/pki/crl.pem + tls-auth /etc/openvpn/certs/pki/ta.key + client-config-dir /etc/openvpn/ccd + + entrypoint.sh: |- + #!/bin/sh + set -x + + iptables -t nat -A POSTROUTING -s {{ $openvpnNetworkAddress }}/{{ $openvpnNetworkNetmask }} ! -d {{ $openvpnNetworkAddress }}/{{ $openvpnNetworkNetmask }} -j MASQUERADE + + mkdir -p /dev/net + if [ ! -c /dev/net/tun ]; then + mknod /dev/net/tun c 10 200 + fi + + wait_file() { + file_path="$1" + while true; do + if [ -f $file_path ]; then + break + fi + echo "wait $file_path" + sleep 2 + done + } + + easyrsa_path="/etc/openvpn/certs" + + wait_file "$easyrsa_path/pki/ca.crt" + wait_file "$easyrsa_path/pki/private/server.key" + wait_file "$easyrsa_path/pki/issued/server.crt" + wait_file "$easyrsa_path/pki/ta.key" + wait_file "$easyrsa_path/pki/dh.pem" + wait_file "$easyrsa_path/pki/crl.pem" + + openvpn --config /etc/openvpn/openvpn.conf diff --git a/charts/openvpn-admin/templates/deployment.yaml b/charts/openvpn-admin/templates/deployment.yaml new file mode 100644 index 0000000..1cc0538 --- /dev/null +++ b/charts/openvpn-admin/templates/deployment.yaml @@ -0,0 +1,117 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openvpn +spec: + selector: + matchLabels: + app: openvpn + template: + metadata: + labels: + app: openvpn + spec: + {{- if .Values.openvpn.nodeSelector }} + nodeSelector: + {{- .Values.openvpn.nodeSelector | toYaml | indent 8 | printf "\n%s" }} + {{- end }} + {{- if .Values.openvpn.tolerations }} + tolerations: + {{- .Values.openvpn.tolerations | toYaml | indent 8 | printf "\n%s" }} + {{- end }} + terminationGracePeriodSeconds: 0 + serviceAccountName: openvpn + containers: + - name: ovpn-admin + image: {{ .Values.ovpnAdmin.image }} + command: + - /bin/sh + - -c + - /app/ovpn-admin + --storage.backend="kubernetes.secrets" + --listen.host="0.0.0.0" + --listen.port="8000" + --role="master" + {{- if hasKey .Values.openvpn "inlet" }} + {{- if eq .Values.openvpn.inlet "LoadBalancer" }} + --ovpn.server.behindLB + --ovpn.service="openvpn-external" + {{- end }} + {{- end }} + --mgmt=main="127.0.0.1:8989" + --ccd --ccd.path="/mnt/ccd" + --easyrsa.path="/mnt/certs" + {{- $externalHost := "" }} + {{- if hasKey .Values.openvpn "inlet" }} + {{- if eq .Values.openvpn.inlet "ExternalIP" }}{{ $externalHost = .Values.openvpn.externalIP }}{{- end }} + {{- end }} + {{- if hasKey .Values.openvpn "externalHost" }}{{ $externalHost = .Values.openvpn.externalHost }}{{- end }} + {{- if ne $externalHost "" }} + --ovpn.server="{{ $externalHost }}:{{ .Values.openvpn.externalPort | default 5416 | quote }}:tcp" + {{- end }} + ports: + - name: ovpn-admin + protocol: TCP + containerPort: 8000 + volumeMounts: + - name: certs + mountPath: /mnt/certs + - name: ccd + mountPath: /mnt/ccd + - name: openvpn + image: {{ .Values.openvpn.image }} + command: [ '/entrypoint.sh' ] + # imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + - MKNOD + - SETGID + - SETUID + drop: + - ALL + ports: + - name: openvpn-tcp + protocol: TCP + containerPort: 1194 + {{- if eq .Values.openvpn.inlet "HostPort" }} + hostPort: {{ .Values.openvpn.hostPort }} + {{- end }} + volumeMounts: + - name: tmp + mountPath: /tmp + - name: dev-net + mountPath: /dev/net + - name: certs + mountPath: /etc/openvpn/certs + - name: ccd + mountPath: /etc/openvpn/ccd + - name: config + mountPath: /etc/openvpn/openvpn.conf + subPath: openvpn.conf + readOnly: true + - name: entrypoint + mountPath: /entrypoint.sh + subPath: entrypoint.sh + readOnly: true + volumes: + - name: tmp + emptyDir: {} + - name: dev-net + emptyDir: {} + - name: certs + emptyDir: {} + - name: ccd + emptyDir: {} + - name: config + configMap: + name: openvpn + defaultMode: 0644 + - name: entrypoint + configMap: + name: openvpn + defaultMode: 0755 diff --git a/charts/openvpn-admin/templates/ingress.yaml b/charts/openvpn-admin/templates/ingress.yaml new file mode 100644 index 0000000..8f227ef --- /dev/null +++ b/charts/openvpn-admin/templates/ingress.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ovpn-admin + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/backend-protocol: HTTP + nginx.ingress.kubernetes.io/auth-type: basic + nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" + nginx.ingress.kubernetes.io/auth-secret: basic-auth +spec: + tls: + - hosts: + - {{ .Values.domain }} + secretName: ingress-tls + rules: + - host: {{ .Values.domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: ovpn-admin + port: + name: http +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ovpn-admin +spec: + secretName: ingress-tls + dnsNames: + - {{ .Values.domain }} + issuerRef: + name: letsencrypt + kind: ClusterIssuer diff --git a/charts/openvpn-admin/templates/rbac.yaml b/charts/openvpn-admin/templates/rbac.yaml new file mode 100644 index 0000000..4693d83 --- /dev/null +++ b/charts/openvpn-admin/templates/rbac.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: openvpn +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: openvpn +rules: +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: openvpn +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: openvpn +subjects: +- kind: ServiceAccount + name: openvpn diff --git a/charts/openvpn-admin/templates/secret.yaml b/charts/openvpn-admin/templates/secret.yaml new file mode 100644 index 0000000..b2dd27d --- /dev/null +++ b/charts/openvpn-admin/templates/secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: basic-auth +type: Opaque +data: + auth: {{ print .Values.ovpnAdmin.basicAuth.user ":{PLAIN}" .Values.ovpnAdmin.basicAuth.password | b64enc | quote }} diff --git a/charts/openvpn-admin/templates/service.yaml b/charts/openvpn-admin/templates/service.yaml new file mode 100644 index 0000000..e04e626 --- /dev/null +++ b/charts/openvpn-admin/templates/service.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: ovpn-admin +spec: + clusterIP: None + ports: + - name: http + port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app: openvpn +--- +{{- if hasKey .Values.openvpn "inlet" }} + + {{- if eq .Values.openvpn.inlet "LoadBalancer" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: openvpn-external +spec: + externalTrafficPolicy: Local + type: LoadBalancer + ports: + - name: openvpn-tcp + protocol: TCP + port: {{ .Values.openvpn.externalPort | default 1194 }} + targetPort: openvpn-tcp + selector: + app: openvpn + {{- else if eq .Values.openvpn.inlet "ExternalIP" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: openvpn-external +spec: + type: ClusterIP + externalIPs: + - {{ .Values.openvpn.externalIP }} + ports: + - name: openvpn-tcp + port: {{ .Values.openvpn.externalPort | default 1194 }} + protocol: TCP + targetPort: openvpn-tcp + selector: + app: openvpn + {{- else if eq .Values.openvpn.inlet "HostPort" }} +--- + {{- else }} + {{- cat "Unsupported inlet type" .inlet | fail }} + {{- end }} + +{{- end }} diff --git a/charts/openvpn-admin/values.yaml b/charts/openvpn-admin/values.yaml new file mode 100644 index 0000000..544e3dd --- /dev/null +++ b/charts/openvpn-admin/values.yaml @@ -0,0 +1,26 @@ +domain: changeme +ovpnAdmin: + image: changeme + basicAuth: + user: admin + password: changeme +openvpn: + image: changeme + subnet: 172.16.200.0/255.255.255.0 + # nodeSelector: + # node-role.kubernetes.io/master: "" + # tolerations: + # - effect: NoSchedule + # key: node-role.kubernetes.io/master + # + # // LoadBalancer or ExternalIP or HostPort + inlet: HostPort + # + # If inlet: ExternalIP + # externalIP: 1.2.3.4 + # externalPort: 1194 + # + # If inlet: HostPort + hostPort: 1194 + # Domain or ip for connect to OpenVPN server + # externalHost: 1.2.3.4 From 9e88cc5b467ba89236002d79777481e46b73fb03 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 13:15:39 +0100 Subject: [PATCH 05/21] Fix CHart.yaml Signed-off-by: maksim.nabokikh --- charts/openvpn-admin/Chart.yaml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/charts/openvpn-admin/Chart.yaml b/charts/openvpn-admin/Chart.yaml index 71838aa..614f6aa 100644 --- a/charts/openvpn-admin/Chart.yaml +++ b/charts/openvpn-admin/Chart.yaml @@ -1,2 +1,15 @@ -name: ovpn-admin -version: 1.0.0 +apiVersion: v1 +appVersion: "2.0.2" +description: Simple web UI to manage OpenVPN users, their certificates & routes in Linux. While backend is written in Go, frontend is based on Vue.js. +name: openvpn-admin +version: "0.0.1" +kubeVersion: ">=1.14.0-0" +maintainers: +- name: nabokihms + email: max.nabokih@gmail.com + url: github.com/nabokihms +sources: + - https://github.com/palark/openvpn-admin +keywords: + - kubernetes + - openvpn From 2eb30014ad2859efc5113e3b56ccd8ec6909c979 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 13:19:57 +0100 Subject: [PATCH 06/21] Commit chart README.md Signed-off-by: maksim.nabokikh --- .gitignore | 2 ++ charts/openvpn-admin/README.md | 36 +++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f2ff5c7..2f05a43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +bin/ + easyrsa easyrsa_master easyrsa_slave diff --git a/charts/openvpn-admin/README.md b/charts/openvpn-admin/README.md index eabf182..e802c5f 100644 --- a/charts/openvpn-admin/README.md +++ b/charts/openvpn-admin/README.md @@ -1 +1,35 @@ -helm chart example +# openvpn-admin + +![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![AppVersion: 2.0.2](https://img.shields.io/badge/AppVersion-2.0.2-informational?style=flat-square) + +Simple web UI to manage OpenVPN users, their certificates & routes in Linux. While backend is written in Go, frontend is based on Vue.js. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| nabokihms | | | + +## Source Code + +* + +## Requirements + +Kubernetes: `>=1.14.0-0` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| domain | string | `"changeme"` | | +| ovpnAdmin.image | string | `"changeme"` | | +| ovpnAdmin.basicAuth.user | string | `"admin"` | | +| ovpnAdmin.basicAuth.password | string | `"changeme"` | | +| openvpn.image | string | `"changeme"` | | +| openvpn.subnet | string | `"172.16.200.0/255.255.255.0"` | | +| openvpn.inlet | string | `"HostPort"` | | +| openvpn.hostPort | int | `1194` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) From 696bf332c6d351458b082928f95eecccdb56e920 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 13:44:14 +0100 Subject: [PATCH 07/21] Fix chart Signed-off-by: maksim.nabokikh --- charts/openvpn-admin/README.md | 5 ++++ .../openvpn-admin/templates/deployment.yaml | 8 +++--- charts/openvpn-admin/templates/ingress.yaml | 19 +++++-------- charts/openvpn-admin/values.yaml | 27 ++++++++++++++----- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/charts/openvpn-admin/README.md b/charts/openvpn-admin/README.md index e802c5f..f5bd9df 100644 --- a/charts/openvpn-admin/README.md +++ b/charts/openvpn-admin/README.md @@ -30,6 +30,11 @@ Kubernetes: `>=1.14.0-0` | openvpn.subnet | string | `"172.16.200.0/255.255.255.0"` | | | openvpn.inlet | string | `"HostPort"` | | | openvpn.hostPort | int | `1194` | | +| nodeSelector | object | `{}` | [Node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) configuration. | +| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for node taints. See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. | +| ingress.enabled | bool | `false` | Enable [ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/). | +| ingress.className | string | `""` | Ingress [class name](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class). | +| ingress.annotations | object | `{}` | Annotations to be added to the ingress. | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/charts/openvpn-admin/templates/deployment.yaml b/charts/openvpn-admin/templates/deployment.yaml index 1cc0538..4d40491 100644 --- a/charts/openvpn-admin/templates/deployment.yaml +++ b/charts/openvpn-admin/templates/deployment.yaml @@ -12,13 +12,13 @@ spec: labels: app: openvpn spec: - {{- if .Values.openvpn.nodeSelector }} + {{- if .Values.nodeSelector }} nodeSelector: - {{- .Values.openvpn.nodeSelector | toYaml | indent 8 | printf "\n%s" }} + {{- .Values.nodeSelector | toYaml | indent 8 | printf "\n%s" }} {{- end }} - {{- if .Values.openvpn.tolerations }} + {{- if .Values.tolerations }} tolerations: - {{- .Values.openvpn.tolerations | toYaml | indent 8 | printf "\n%s" }} + {{- .Values.tolerations | toYaml | indent 8 | printf "\n%s" }} {{- end }} terminationGracePeriodSeconds: 0 serviceAccountName: openvpn diff --git a/charts/openvpn-admin/templates/ingress.yaml b/charts/openvpn-admin/templates/ingress.yaml index 8f227ef..98d12e5 100644 --- a/charts/openvpn-admin/templates/ingress.yaml +++ b/charts/openvpn-admin/templates/ingress.yaml @@ -4,12 +4,17 @@ kind: Ingress metadata: name: ovpn-admin annotations: - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/backend-protocol: HTTP nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" nginx.ingress.kubernetes.io/auth-secret: basic-auth + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . | quote }} + {{- end }} tls: - hosts: - {{ .Values.domain }} @@ -25,15 +30,3 @@ spec: name: ovpn-admin port: name: http ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: ovpn-admin -spec: - secretName: ingress-tls - dnsNames: - - {{ .Values.domain }} - issuerRef: - name: letsencrypt - kind: ClusterIssuer diff --git a/charts/openvpn-admin/values.yaml b/charts/openvpn-admin/values.yaml index 544e3dd..5d0b780 100644 --- a/charts/openvpn-admin/values.yaml +++ b/charts/openvpn-admin/values.yaml @@ -7,13 +7,7 @@ ovpnAdmin: openvpn: image: changeme subnet: 172.16.200.0/255.255.255.0 - # nodeSelector: - # node-role.kubernetes.io/master: "" - # tolerations: - # - effect: NoSchedule - # key: node-role.kubernetes.io/master - # - # // LoadBalancer or ExternalIP or HostPort + # LoadBalancer or ExternalIP or HostPort inlet: HostPort # # If inlet: ExternalIP @@ -24,3 +18,22 @@ openvpn: hostPort: 1194 # Domain or ip for connect to OpenVPN server # externalHost: 1.2.3.4 + +# -- [Node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) configuration. +nodeSelector: {} + +# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for node taints. +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. +tolerations: [] + +ingress: + # -- Enable [ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/). + enabled: false + + # -- Ingress [class name](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class). + className: "" + + # -- Annotations to be added to the ingress. + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" From 2dcdfc395bd0ed34c56c33b738de5a1408e7623d Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 14:58:34 +0100 Subject: [PATCH 08/21] Fix build Signed-off-by: maksim.nabokikh --- .github/dependabot.yml | 2 +- .github/workflows/publish-latest.yaml | 6 +-- .github/workflows/publish-tag.yaml | 65 ++++++++++++++++++++------- Dockerfile => Dockerfile.ovpn-admin | 4 +- werf.yaml | 6 +-- 5 files changed, 58 insertions(+), 25 deletions(-) rename Dockerfile => Dockerfile.ovpn-admin (96%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 94c3ffb..b1d88d3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,7 +12,7 @@ updates: schedule: interval: "weekly" - # Dependencies listed in Dockerfile + # Dependencies listed in Dockerfile.ovpn-admin - package-ecosystem: "docker" directory: "/" schedule: diff --git a/.github/workflows/publish-latest.yaml b/.github/workflows/publish-latest.yaml index ad1f8e4..2596741 100644 --- a/.github/workflows/publish-latest.yaml +++ b/.github/workflows/publish-latest.yaml @@ -24,12 +24,12 @@ jobs: with: tags: flant/ovpn-admin:openvpn-latest platforms: linux/amd64,linux/arm64,linux/arm - file: Dockerfile.openvpn + file: Dockerfile.ovpn-admin push: true - name: Push ovpn-admin image to Docker Hub uses: docker/build-push-action@v4 with: tags: flant/ovpn-admin:latest platforms: linux/amd64,linux/arm64,linux/arm - file: Dockerfile - push: true \ No newline at end of file + file: Dockerfile.openvpn + push: true diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 06bdaef..f02f0f4 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -1,4 +1,4 @@ -name: Build and publish tags to Docker Hub (tags only) +name: Build and publish tags to ghcr.io on: push: tags: @@ -8,32 +8,65 @@ jobs: build: name: build images for tag runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - dockerfile: ./Dockerfile.ovpn-admin + image: ovpn-admin + - dockerfile: ./Dockerfile.openvpn + image: openvpn steps: - name: Checkout code uses: actions/checkout@v2 with: fetch-depth: 0 + - name: Get the version id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Login to Docker Hub - uses: docker/login-action@v2 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v3.3.0 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - name: Push openvpn image to Docker Hub + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DECKHOUSE_REGISTRY_USER }} + password: ${{ secrets.DECKHOUSE_REGISTRY_PASSWORD }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5.6.1 + with: + images: ghcr.io/${{ github.repository }}/${{ matrix.image }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@v6.10.0 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + TAG=${{ github.ref_name }} + + - name: Push Image uses: docker/build-push-action@v4 with: - tags: flant/ovpn-admin:openvpn-${{ steps.get_version.outputs.VERSION }} + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + TAG=${{ github.ref_name }} platforms: linux/amd64,linux/arm64,linux/arm - file: Dockerfile.openvpn - push: true - - name: Push ovpn-admin image to Docker Hub - uses: docker/build-push-action@v4 - with: - tags: flant/ovpn-admin:${{ steps.get_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm64,linux/arm - file: Dockerfile - push: true \ No newline at end of file + file: ${{ matrix.dockerfile }} diff --git a/Dockerfile b/Dockerfile.ovpn-admin similarity index 96% rename from Dockerfile rename to Dockerfile.ovpn-admin index aac416c..87ddf27 100644 --- a/Dockerfile +++ b/Dockerfile.ovpn-admin @@ -1,11 +1,11 @@ FROM node:16-alpine3.15 AS frontend-builder -COPY frontend/ /app +COPY ../frontend /app RUN apk add --update python3 make g++ && cd /app && npm install && npm run build FROM golang:1.17.3-buster AS backend-builder RUN go install github.com/gobuffalo/packr/v2/packr2@latest COPY --from=frontend-builder /app/static /app/frontend/static -COPY . /app +COPY .. /app ARG TARGETARCH RUN cd /app && packr2 && env CGO_ENABLED=1 GOOS=linux GOARCH=${TARGETARCH} go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin && packr2 clean diff --git a/werf.yaml b/werf.yaml index 0ce7199..1a051b6 100644 --- a/werf.yaml +++ b/werf.yaml @@ -1,10 +1,10 @@ project: ovpn-admin configVersion: 1 - --- image: ovpn-admin -dockerfile: Dockerfile - +dockerfile: Dockerfile.ovpn-admin +context: . --- image: openvpn dockerfile: Dockerfile.openvpn +context: . From 010c4d4e7a220f84ad8e39f35013d3697c743c54 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 15:02:43 +0100 Subject: [PATCH 09/21] Fix build condition Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index f02f0f4..1b4aff5 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -2,7 +2,12 @@ name: Build and publish tags to ghcr.io on: push: tags: - - '*' + - v* + branches: + - master + pull_request: + branches: + - master jobs: build: From 0e871696346df8195177736e7a894915aeb02bbb Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 15:07:44 +0100 Subject: [PATCH 10/21] Fix matrix Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 1b4aff5..5162339 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -17,10 +17,9 @@ jobs: fail-fast: false matrix: include: - - dockerfile: ./Dockerfile.ovpn-admin - image: ovpn-admin - - dockerfile: ./Dockerfile.openvpn - image: openvpn + - name: ovpn-admin + - name: openvpn + steps: - name: Checkout code uses: actions/checkout@v2 @@ -50,7 +49,7 @@ jobs: id: meta uses: docker/metadata-action@v5.6.1 with: - images: ghcr.io/${{ github.repository }}/${{ matrix.image }} + images: ghcr.io/${{ github.repository }}/${{ matrix.name }} # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action @@ -74,4 +73,4 @@ jobs: build-args: | TAG=${{ github.ref_name }} platforms: linux/amd64,linux/arm64,linux/arm - file: ${{ matrix.dockerfile }} + file: ./Dockerfile.${{ matrix.name }} From d17cfd7ee9a2e47cada69f9819377d908808b171 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 15:09:50 +0100 Subject: [PATCH 11/21] Fix context Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 5162339..71a56bb 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -56,7 +56,6 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v6.10.0 with: - context: . push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} @@ -66,7 +65,6 @@ jobs: - name: Push Image uses: docker/build-push-action@v4 with: - context: . push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 31ba1607abb0f5bebd2ebdce7d614b874cd8294a Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 15:13:33 +0100 Subject: [PATCH 12/21] Delete unneeded build Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 71a56bb..3aeaa9a 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -53,15 +53,6 @@ jobs: # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - - name: Build and push Docker image - uses: docker/build-push-action@v6.10.0 - with: - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - TAG=${{ github.ref_name }} - - name: Push Image uses: docker/build-push-action@v4 with: From 1fae52e85c2ca6f393f661021f0f4c4be7c8d723 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 20:33:57 +0100 Subject: [PATCH 13/21] Try using werf Signed-off-by: maksim.nabokikh --- .github/dependabot.yml | 2 +- .github/workflows/publish-tag.yaml | 32 +++++++++++------------------- Dockerfile.ovpn-admin | 2 +- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b1d88d3..94c3ffb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,7 +12,7 @@ updates: schedule: interval: "weekly" - # Dependencies listed in Dockerfile.ovpn-admin + # Dependencies listed in Dockerfile - package-ecosystem: "docker" directory: "/" schedule: diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 3aeaa9a..11bd96f 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -9,16 +9,13 @@ on: branches: - master +env: + WERF_STAGED_DOCKERFILE_VERSION: v2 + jobs: build: name: build images for tag runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - name: ovpn-admin - - name: openvpn steps: - name: Checkout code @@ -30,18 +27,11 @@ jobs: id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + - uses: werf/actions/install@v1.2 - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.3.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DECKHOUSE_REGISTRY_USER }} - password: ${{ secrets.DECKHOUSE_REGISTRY_PASSWORD }} + - name: Login into ghcr.io + shell: bash + run: werf cr login -u ${{ github.actor }} -p ${{ github.token }} ghcr.io/${{ github.repository }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action @@ -53,10 +43,12 @@ jobs: # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - - name: Push Image - uses: docker/build-push-action@v4 + - name: Build Image + run: | + . <(echo "$DOCKER_METADATA_OUTPUT_LABELS" | awk '{print "export WERF_EXPORT_ADD_LABEL_" NR "=" $0}') + werf build with: - push: ${{ github.event_name != 'pull_request' }} + push: ${{ github.event_name == 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | diff --git a/Dockerfile.ovpn-admin b/Dockerfile.ovpn-admin index 87ddf27..06ece2b 100644 --- a/Dockerfile.ovpn-admin +++ b/Dockerfile.ovpn-admin @@ -17,4 +17,4 @@ RUN apk add --update bash easy-rsa openssl openvpn coreutils && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.4/openvpn-user-linux-${TARGETARCH}.tar.gz -O - | tar xz -C /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* -RUN if [ -f "/usr/local/bin/openvpn-user-${TARGETARCH}" ]; then ln -s /usr/local/bin/openvpn-user-${TARGETARCH} /usr/local/bin/openvpn-user; fi \ No newline at end of file +RUN if [ -f "/usr/local/bin/openvpn-user-${TARGETARCH}" ]; then ln -s /usr/local/bin/openvpn-user-${TARGETARCH} /usr/local/bin/openvpn-user; fi From 5722b2aec8d1a59a3c5662a3fa48921a5689e8b4 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 20:36:57 +0100 Subject: [PATCH 14/21] Fix actions file Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 11bd96f..888e055 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -44,14 +44,16 @@ jobs: # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - name: Build Image + if: ${{ github.event_name == 'pull_request' }} run: | . <(echo "$DOCKER_METADATA_OUTPUT_LABELS" | awk '{print "export WERF_EXPORT_ADD_LABEL_" NR "=" $0}') werf build - with: - push: ${{ github.event_name == 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - TAG=${{ github.ref_name }} - platforms: linux/amd64,linux/arm64,linux/arm - file: ./Dockerfile.${{ matrix.name }} + + # with: + # push: ${{ github.event_name == 'pull_request' }} + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} + # build-args: | + # TAG=${{ github.ref_name }} + # platforms: linux/amd64,linux/arm64,linux/arm + # file: ./Dockerfile.${{ matrix.name }} From 79ae6270d24a20d81faa1dd37702c0865797b3a8 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 20:39:01 +0100 Subject: [PATCH 15/21] Fix env variables Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 888e055..0eaedab 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -46,7 +46,8 @@ jobs: - name: Build Image if: ${{ github.event_name == 'pull_request' }} run: | - . <(echo "$DOCKER_METADATA_OUTPUT_LABELS" | awk '{print "export WERF_EXPORT_ADD_LABEL_" NR "=" $0}') + source "$(werf ci-env github --as-file)" + source <(echo "$DOCKER_METADATA_OUTPUT_LABELS" | awk '{print "export WERF_EXPORT_ADD_LABEL_" NR "=" $0}') werf build # with: From 0ba9eba9ba242e1e805d019972310629e3b3fa08 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 21:00:46 +0100 Subject: [PATCH 16/21] Migrate to jq Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 0eaedab..c38e461 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -36,7 +36,6 @@ jobs: # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action - name: Extract Docker metadata - id: meta uses: docker/metadata-action@v5.6.1 with: images: ghcr.io/${{ github.repository }}/${{ matrix.name }} @@ -47,7 +46,7 @@ jobs: if: ${{ github.event_name == 'pull_request' }} run: | source "$(werf ci-env github --as-file)" - source <(echo "$DOCKER_METADATA_OUTPUT_LABELS" | awk '{print "export WERF_EXPORT_ADD_LABEL_" NR "=" $0}') + source <(jq -r '.labels | to_entries | to_entries[] | "WERF_EXPORT_ADD_LABEL_\(.key)=\(.value.key)=\(.value.value)"' <<< $DOCKER_METADATA_OUTPUT_JSON) werf build # with: From a6baacd57f79cb81fdb8e636e4fbbf5286e59396 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 21:02:04 +0100 Subject: [PATCH 17/21] Migrate to jq Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index c38e461..51cf0fa 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -46,7 +46,12 @@ jobs: if: ${{ github.event_name == 'pull_request' }} run: | source "$(werf ci-env github --as-file)" - source <(jq -r '.labels | to_entries | to_entries[] | "WERF_EXPORT_ADD_LABEL_\(.key)=\(.value.key)=\(.value.value)"' <<< $DOCKER_METADATA_OUTPUT_JSON) + for l in $(jq -r '.labels | to_entries | to_entries[] | "WERF_EXPORT_ADD_LABEL_\(.key)=\(.value.key)=\(.value.value)"' <<< $DOCKER_METADATA_OUTPUT_JSON); do + echo "export $l" + export $l + done + + env werf build # with: From 38ed4afcb4de17b0db76728af3e6c9aae553ec0c Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 21:13:47 +0100 Subject: [PATCH 18/21] Migrate to jq Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 51cf0fa..de2a25d 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -46,12 +46,7 @@ jobs: if: ${{ github.event_name == 'pull_request' }} run: | source "$(werf ci-env github --as-file)" - for l in $(jq -r '.labels | to_entries | to_entries[] | "WERF_EXPORT_ADD_LABEL_\(.key)=\(.value.key)=\(.value.value)"' <<< $DOCKER_METADATA_OUTPUT_JSON); do - echo "export $l" - export $l - done - - env + source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) werf build # with: From 2e526b75705c02902ab3876af66f5af8e0fcca86 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 22:06:02 +0100 Subject: [PATCH 19/21] Make workflow prettier Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index de2a25d..dee10ef 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -11,6 +11,7 @@ on: env: WERF_STAGED_DOCKERFILE_VERSION: v2 + WERF_BUILDAH_MODE: auto jobs: build: @@ -23,37 +24,28 @@ jobs: with: fetch-depth: 0 - - name: Get the version - id: get_version - run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - - uses: werf/actions/install@v1.2 - name: Login into ghcr.io shell: bash run: werf cr login -u ${{ github.actor }} -p ${{ github.token }} ghcr.io/${{ github.repository }} - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - name: Extract Docker metadata uses: docker/metadata-action@v5.6.1 with: images: ghcr.io/${{ github.repository }}/${{ matrix.name }} - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build Image - if: ${{ github.event_name == 'pull_request' }} + - name: Export werf variables run: | source "$(werf ci-env github --as-file)" source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) + + - name: Build Image + if: ${{ github.event_name == 'pull_request' }} + run: | werf build - # with: - # push: ${{ github.event_name == 'pull_request' }} - # tags: ${{ steps.meta.outputs.tags }} - # labels: ${{ steps.meta.outputs.labels }} - # build-args: | - # TAG=${{ github.ref_name }} - # platforms: linux/amd64,linux/arm64,linux/arm - # file: ./Dockerfile.${{ matrix.name }} + - name: Build and Push Image + if: ${{ github.event_name != 'pull_request' }} + run: | + werf export --tag ghcr.io/${{ github.repository }}/%image%:${{ github.ref_name }} From da82b6e9b2e0de0c319b5384fc16851df471e7bd Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 22:08:18 +0100 Subject: [PATCH 20/21] Disable buildah Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index dee10ef..66ee35d 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -11,7 +11,7 @@ on: env: WERF_STAGED_DOCKERFILE_VERSION: v2 - WERF_BUILDAH_MODE: auto + # WERF_BUILDAH_MODE: auto jobs: build: From cedc2a94ecb3d2066eb6d72c353a02ee9b682917 Mon Sep 17 00:00:00 2001 From: "maksim.nabokikh" Date: Mon, 3 Mar 2025 22:11:41 +0100 Subject: [PATCH 21/21] Fix env variables Signed-off-by: maksim.nabokikh --- .github/workflows/publish-tag.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 66ee35d..db1f281 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -35,17 +35,18 @@ jobs: with: images: ghcr.io/${{ github.repository }}/${{ matrix.name }} - - name: Export werf variables + - name: Build Image + if: ${{ github.event_name == 'pull_request' }} run: | source "$(werf ci-env github --as-file)" source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) - - name: Build Image - if: ${{ github.event_name == 'pull_request' }} - run: | werf build - name: Build and Push Image if: ${{ github.event_name != 'pull_request' }} run: | + source "$(werf ci-env github --as-file)" + source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) + werf export --tag ghcr.io/${{ github.repository }}/%image%:${{ github.ref_name }}