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..7956c29 --- /dev/null +++ b/.github/workflows/chart-release.yml @@ -0,0 +1,35 @@ +name: Release Charts + +on: + push: + branches: + - master + paths: + - 'charts/**' + +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 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..db1f281 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -1,39 +1,52 @@ -name: Build and publish tags to Docker Hub (tags only) +name: Build and publish tags to ghcr.io on: push: tags: - - '*' + - v* + branches: + - master + pull_request: + branches: + - master + +env: + WERF_STAGED_DOCKERFILE_VERSION: v2 + # WERF_BUILDAH_MODE: auto jobs: build: name: build images for tag runs-on: ubuntu-latest + 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 + + - 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 }} + + - name: Extract Docker metadata + uses: docker/metadata-action@v5.6.1 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - name: Push openvpn image to Docker Hub - uses: docker/build-push-action@v4 - with: - tags: flant/ovpn-admin:openvpn-${{ steps.get_version.outputs.VERSION }} - 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 + images: ghcr.io/${{ github.repository }}/${{ matrix.name }} + + - 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) + + 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 }} diff --git a/.gitignore b/.gitignore index 6f8f5aa..2f05a43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,11 @@ +bin/ + easyrsa easyrsa_master 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/Dockerfile b/Dockerfile.ovpn-admin similarity index 95% rename from Dockerfile rename to Dockerfile.ovpn-admin index aac416c..06ece2b 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 @@ -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 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 +########### diff --git a/charts/openvpn-admin/Chart.yaml b/charts/openvpn-admin/Chart.yaml new file mode 100644 index 0000000..614f6aa --- /dev/null +++ b/charts/openvpn-admin/Chart.yaml @@ -0,0 +1,15 @@ +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 diff --git a/charts/openvpn-admin/README.md b/charts/openvpn-admin/README.md new file mode 100644 index 0000000..f5bd9df --- /dev/null +++ b/charts/openvpn-admin/README.md @@ -0,0 +1,40 @@ +# 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` | | +| 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/helm/templates/configmap.yaml b/charts/openvpn-admin/templates/configmap.yaml similarity index 100% rename from helm/templates/configmap.yaml rename to charts/openvpn-admin/templates/configmap.yaml diff --git a/helm/templates/deployment.yaml b/charts/openvpn-admin/templates/deployment.yaml similarity index 93% rename from helm/templates/deployment.yaml rename to charts/openvpn-admin/templates/deployment.yaml index 1cc0538..4d40491 100644 --- a/helm/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/helm/templates/ingress.yaml b/charts/openvpn-admin/templates/ingress.yaml similarity index 71% rename from helm/templates/ingress.yaml rename to charts/openvpn-admin/templates/ingress.yaml index 8f227ef..98d12e5 100644 --- a/helm/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/helm/templates/rbac.yaml b/charts/openvpn-admin/templates/rbac.yaml similarity index 100% rename from helm/templates/rbac.yaml rename to charts/openvpn-admin/templates/rbac.yaml diff --git a/helm/templates/secret.yaml b/charts/openvpn-admin/templates/secret.yaml similarity index 100% rename from helm/templates/secret.yaml rename to charts/openvpn-admin/templates/secret.yaml diff --git a/helm/templates/service.yaml b/charts/openvpn-admin/templates/service.yaml similarity index 100% rename from helm/templates/service.yaml rename to charts/openvpn-admin/templates/service.yaml diff --git a/charts/openvpn-admin/values.yaml b/charts/openvpn-admin/values.yaml new file mode 100644 index 0000000..5d0b780 --- /dev/null +++ b/charts/openvpn-admin/values.yaml @@ -0,0 +1,39 @@ +domain: changeme +ovpnAdmin: + image: changeme + basicAuth: + user: admin + password: changeme +openvpn: + image: changeme + subnet: 172.16.200.0/255.255.255.0 + # 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 + +# -- [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" 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/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 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: .