Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
bde25f690e
Bump gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0
Bumps gopkg.in/yaml.v3 from 3.0.0-20210107192922-496545a6307b to 3.0.0.

---
updated-dependencies:
- dependency-name: gopkg.in/yaml.v3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 06:19:26 +00:00
31 changed files with 177 additions and 483 deletions

View File

@ -1,25 +0,0 @@
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"

17
.github/release.yml vendored
View File

@ -1,17 +0,0 @@
changelog:
exclude:
labels:
- ignore
categories:
- title: Enhancements 🚀
labels:
- enhancement
- title: Bug Fixes 🐛
labels:
- bug
- title: Dependency Updates ⬆️
labels:
- dependencies
- title: Other Changes
labels:
- "*"

View File

@ -1,35 +0,0 @@
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 }}"

View File

@ -1,107 +0,0 @@
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.25", "1.29", "1.31"]
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.25)
NODE_IMAGE=kindest/node:v1.25.3@sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1 ;;
1.29)
NODE_IMAGE=kindest/node:v1.29.12@sha256:62c0672ba99a4afd7396512848d6fc382906b8f33349ae68fb1dbfe549f70dec ;;
1.31)
NODE_IMAGE=kindest/node:v1.31.2@sha256:0526eb5cd8d892ed79b56feb48d17eeee1f719f55d5c35cef468f053caffad32 ;;
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

35
.github/workflows/publish-latest.yaml vendored Normal file
View File

@ -0,0 +1,35 @@
name: Build and publish latest tag to Docker Hub (releases only)
on:
release:
types: [created]
jobs:
build:
name: build latest images for release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
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-latest
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:latest
platforms: linux/amd64,linux/arm64,linux/arm
file: Dockerfile
push: true

View File

@ -1,52 +1,39 @@
name: Build and publish tags to ghcr.io name: Build and publish tags to Docker Hub (tags only)
on: on:
push: push:
tags: tags:
- v* - '*'
branches:
- master
pull_request:
branches:
- master
env:
WERF_STAGED_DOCKERFILE_VERSION: v2
# WERF_BUILDAH_MODE: auto
jobs: jobs:
build: build:
name: build images for tag name: build images for tag
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Get the version
- uses: werf/actions/install@v1.2 id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Login into ghcr.io - name: Set up Docker Buildx
shell: bash uses: docker/setup-buildx-action@v2
run: werf cr login -u ${{ github.actor }} -p ${{ github.token }} ghcr.io/${{ github.repository }} - name: Login to Docker Hub
uses: docker/login-action@v2
- name: Extract Docker metadata
uses: docker/metadata-action@v5.6.1
with: with:
images: ghcr.io/${{ github.repository }}/${{ matrix.name }} username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
- name: Build Image - name: Push openvpn image to Docker Hub
if: ${{ github.event_name == 'pull_request' }} uses: docker/build-push-action@v4
run: | with:
source "$(werf ci-env github --as-file)" tags: flant/ovpn-admin:openvpn-${{ steps.get_version.outputs.VERSION }}
source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) platforms: linux/amd64,linux/arm64,linux/arm
file: Dockerfile.openvpn
werf build --repo='' --final-repo='' push: true
- name: Push ovpn-admin image to Docker Hub
- name: Build and Push Image uses: docker/build-push-action@v4
if: ${{ github.event_name != 'pull_request' }} with:
run: | tags: flant/ovpn-admin:${{ steps.get_version.outputs.VERSION }}
source "$(werf ci-env github --as-file)" platforms: linux/amd64,linux/arm64,linux/arm
source <(jq -r '.labels | to_entries | to_entries[] | "export WERF_EXPORT_ADD_LABEL_\(.key)=\"\(.value.key)=\(.value.value)\""' <<< $DOCKER_METADATA_OUTPUT_JSON) file: Dockerfile
push: true
werf export --tag ghcr.io/${{ github.repository }}/%image%:${{ github.ref_name }}

View File

@ -17,7 +17,7 @@ jobs:
- name: checkout code - name: checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: build binaries - name: build binaries
uses: wangyoucao577/go-release-action@v1.53 uses: wangyoucao577/go-release-action@v1.40
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
goversion: 1.17 goversion: 1.17

View File

@ -17,7 +17,7 @@ jobs:
- name: checkout code - name: checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: build binaries - name: build binaries
uses: wangyoucao577/go-release-action@v1.53 uses: wangyoucao577/go-release-action@v1.40
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
goversion: 1.17 goversion: 1.17

6
.gitignore vendored
View File

@ -1,11 +1,13 @@
bin/
easyrsa easyrsa
easyrsa_master easyrsa_master
easyrsa_slave easyrsa_slave
ccd ccd
ccd_master ccd_master
ccd_slave ccd_slave
openvpn-web-ui*
openvpn-ui*
openvpn-admin*
ovpn-admin*
frontend/node_modules frontend/node_modules
main-packr.go main-packr.go

View File

@ -1,15 +1,15 @@
FROM node:16-alpine3.15 AS frontend-builder 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 RUN apk add --update python3 make g++ && cd /app && npm install && npm run build
FROM golang:1.17.3-buster AS backend-builder FROM golang:1.17.3-buster AS backend-builder
RUN go install github.com/gobuffalo/packr/v2/packr2@latest RUN go install github.com/gobuffalo/packr/v2/packr2@latest
COPY --from=frontend-builder /app/static /app/frontend/static COPY --from=frontend-builder /app/static /app/frontend/static
COPY .. /app COPY . /app
ARG TARGETARCH 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 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
FROM alpine:3.21 FROM alpine:3.16
WORKDIR /app WORKDIR /app
COPY --from=backend-builder /app/ovpn-admin /app COPY --from=backend-builder /app/ovpn-admin /app
ARG TARGETARCH ARG TARGETARCH
@ -17,4 +17,4 @@ RUN apk add --update bash easy-rsa openssl openvpn coreutils && \
ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ 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 && \ 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/* 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 RUN if [ -f "/usr/local/bin/openvpn-user-${TARGETARCH}" ]; then ln -s /usr/local/bin/openvpn-user-${TARGETARCH} /usr/local/bin/openvpn-user; fi

View File

@ -1,4 +1,4 @@
FROM alpine:3.21 FROM alpine:3.16
ARG TARGETARCH ARG TARGETARCH
RUN apk add --update bash openvpn easy-rsa iptables && \ RUN apk add --update bash openvpn easy-rsa iptables && \
ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \

View File

@ -1,54 +0,0 @@
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
###########

View File

@ -2,6 +2,8 @@
Simple web UI to manage OpenVPN users, their certificates & routes in Linux. While backend is written in Go, frontend is based on Vue.js. Simple web UI to manage OpenVPN users, their certificates & routes in Linux. While backend is written in Go, frontend is based on Vue.js.
Originally created in [Flant](https://flant.com/) for internal needs & used for years, then updated to be more modern and [publicly released](https://blog.flant.com/introducing-ovpn-admin-web-interface-for-openvpn/) in March'21. Your contributions are welcome!
***DISCLAIMER!** This project was created for experienced users (system administrators) and private (e.g., protected by network policies) environments only. Thus, it is not implemented with security in mind (e.g., it doesn't strictly check all parameters passed by users, etc.). It also relies heavily on files and fails if required files aren't available.* ***DISCLAIMER!** This project was created for experienced users (system administrators) and private (e.g., protected by network policies) environments only. Thus, it is not implemented with security in mind (e.g., it doesn't strictly check all parameters passed by users, etc.). It also relies heavily on files and fails if required files aren't available.*
## Features ## Features
@ -19,16 +21,16 @@ Simple web UI to manage OpenVPN users, their certificates & routes in Linux. Whi
### Screenshots ### Screenshots
Managing users in ovpn-admin: Managing users in ovpn-admin:
![ovpn-admin UI](https://raw.githubusercontent.com/palark/ovpn-admin/master/img/ovpn-admin-users.png) ![ovpn-admin UI](https://raw.githubusercontent.com/flant/ovpn-admin/master/img/ovpn-admin-users.png)
An example of dashboard made using ovpn-admin metrics: An example of dashboard made using ovpn-admin metrics:
![ovpn-admin metrics](https://raw.githubusercontent.com/palark/ovpn-admin/master/img/ovpn-admin-metrics.png) ![ovpn-admin metrics](https://raw.githubusercontent.com/flant/ovpn-admin/master/img/ovpn-admin-metrics.png)
## Installation ## Installation
### 1. Docker ### 1. Docker
There is a ready-to-use [docker-compose.yaml](https://github.com/palark/ovpn-admin/blob/master/docker-compose.yaml), so you can just change/add values you need and start it with [start.sh](https://github.com/palark/ovpn-admin/blob/master/start.sh). There is a ready-to-use [docker-compose.yaml](https://github.com/flant/ovpn-admin/blob/master/docker-compose.yaml), so you can just change/add values you need and start it with [start.sh](https://github.com/flant/ovpn-admin/blob/master/start.sh).
Requirements: Requirements:
You need [Docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/) installed. You need [Docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/) installed.
@ -36,7 +38,7 @@ You need [Docker](https://docs.docker.com/get-docker/) and [docker-compose](http
Commands to execute: Commands to execute:
```bash ```bash
git clone https://github.com/palark/ovpn-admin.git git clone https://github.com/flant/ovpn-admin.git
cd ovpn-admin cd ovpn-admin
./start.sh ./start.sh
``` ```
@ -54,7 +56,7 @@ Requirements. You need Linux with the following components installed:
Commands to execute: Commands to execute:
```bash ```bash
git clone https://github.com/palark/ovpn-admin.git git clone https://github.com/flant/ovpn-admin.git
cd ovpn-admin cd ovpn-admin
./bootstrap.sh ./bootstrap.sh
./build.sh ./build.sh
@ -65,18 +67,18 @@ cd ovpn-admin
### 3. Prebuilt binary ### 3. Prebuilt binary
You can also download and use prebuilt binaries from the [releases](https://github.com/palark/ovpn-admin/releases/latest) page — just choose a relevant tar.gz file. You can also download and use prebuilt binaries from the [releases](https://github.com/flant/ovpn-admin/releases/latest) page — just choose a relevant tar.gz file.
## Notes ## Notes
* This tool uses external calls for `bash`, `coreutils` and `easy-rsa`, thus **Linux systems only are supported** at the moment. * this tool uses external calls for `bash`, `coreutils` and `easy-rsa`, thus **Linux systems only are supported** at the moment.
* To enable additional password authentication, provide `--auth` and `--auth.db="/etc/easyrsa/pki/users.db`" flags and install [openvpn-user](https://github.com/pashcovich/openvpn-user/releases/latest). This tool should be available in your `$PATH` and its binary should be executable (`+x`). * to enable additional password authentication provide `--auth` and `--auth.db="/etc/easyrsa/pki/users.db`" flags and install [openvpn-user](https://github.com/pashcovich/openvpn-user/releases/latest). This tool should be available in your `$PATH` and its binary should be executable (`+x`).
* If you use `--ccd` and `--ccd.path="/etc/openvpn/ccd"` and plan to use static address setup for users, do not forget to provide `--ovpn.network="172.16.100.0/24"` with valid openvpn-server network. * master-replica synchronization does not work with `--storage.backend=kubernetes.secrets` - **WIP**
* If you want to pass all the traffic generated by the user, you need to edit `ovpn-admin/templates/client.conf.tpl` and uncomment `redirect-gateway def1`. * additional password authentication does not work with `--storage.backend=kubernetes.secrets` - **WIP**
* Tested with openvpn-server versions 2.4 and 2.5 and with tls-auth mode only. * if you use `--ccd` and `--ccd.path="/etc/openvpn/ccd"` abd plan to use static address setup for users do not forget to provide `--ovpn.network="172.16.100.0/24"` with valid openvpn-server network
* Not tested with Easy-RSA version > 3.0.8. * tested only with Openvpn-server versions 2.4 and 2.5 with only tls-auth mode
* Status of user connections update every 28 seconds. * not tested with EasyRsa version > 3.0.8
* Master-replica synchronization and additional password authentication do not work with `--storage.backend=kubernetes.secrets` - **WIP** * status of users connections update every 28 second(*no need to ask why =)*)
## Usage ## Usage
@ -157,10 +159,7 @@ Flags:
--auth.db="./easyrsa/pki/users.db" --auth.db="./easyrsa/pki/users.db"
(or OVPN_AUTH_DB_PATH) database path for password authorization (or OVPN_AUTH_DB_PATH) database path for password authorization
--auth.db-init
(or OVPN_AUTH_DB_INIT) enable database init if user db not exists or size is 0
--log.level set log level: trace, debug, info, warn, error (default info) --log.level set log level: trace, debug, info, warn, error (default info)
(or LOG_LEVEL) (or LOG_LEVEL)
@ -173,11 +172,6 @@ Flags:
--version show application version --version show application version
``` ```
## Authors ## Further information
ovpn-admin was originally created in [Flant](https://github.com/flant/) and used internally for years. Please feel free to use [issues](https://github.com/flant/ovpn-admin/issues) and [discussions](https://github.com/flant/ovpn-admin/discussions) to get help from maintainers & community.
In March 2021, it [went public](https://medium.com/flant-com/introducing-ovpn-admin-a-web-interface-to-manage-openvpn-users-d81705ad8f23) and was still developed in Flant.
Namely, [@vitaliy-sn](https://github.com/vitaliy-sn) created its first version in Python, and [@pashcovich](https://github.com/pashcovich) rewrote it in Go.
In November 2024, this project was moved to [Palark](https://github.com/palark/), which is currently responsible for its maintenance and development.

View File

@ -8,9 +8,7 @@ import (
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt"
"math/big" "math/big"
"strconv"
"time" "time"
) )
@ -62,6 +60,7 @@ func genPrivKey() (privKeyPEM *bytes.Buffer, err error) {
Bytes: privKeyPKCS8, Bytes: privKeyPKCS8,
}) })
return return
} }
@ -134,17 +133,6 @@ func genClientCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn
serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128) serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128)
serial, err := rand.Int(rand.Reader, serialNumberRange) serial, err := rand.Int(rand.Reader, serialNumberRange)
certLifetimeDays, err := strconv.Atoi(*clientCertExpirationDays)
if err != nil {
return nil, fmt.Errorf("can't get client certificate expiration value: %w", err)
}
notBefore := time.Now()
notAfter := notBefore.Add(time.Duration(certLifetimeDays) * 24 * time.Hour)
if notAfter.After(ca.NotAfter) {
notAfter = ca.NotAfter
}
template := x509.Certificate{ template := x509.Certificate{
BasicConstraintsValid: true, BasicConstraintsValid: true,
DNSNames: []string{cn}, DNSNames: []string{cn},
@ -154,8 +142,8 @@ func genClientCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn
}, },
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
NotBefore: notBefore, NotBefore: time.Now(),
NotAfter: notAfter, NotAfter: ca.NotAfter,
} }
issuerBytes, err := x509.CreateCertificate(rand.Reader, &template, ca, &privKey.PublicKey, caPrivKey) issuerBytes, err := x509.CreateCertificate(rand.Reader, &template, ca, &privKey.PublicKey, caPrivKey)

View File

@ -1,2 +0,0 @@
owner: palark
git-base-url: https://api.github.com/

View File

@ -1,15 +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.2"
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

View File

@ -1,40 +0,0 @@
# openvpn-admin
![Version: 0.0.2](https://img.shields.io/badge/Version-0.0.2-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 | <max.nabokih@gmail.com> | <github.com/nabokihms> |
## Source Code
* <https://github.com/palark/openvpn-admin>
## Requirements
Kubernetes: `>=1.14.0-0`
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| domain | string | `"changeme"` | |
| ovpnAdmin.repo | string | `"ghcr.io/palark/ovpn-admin/ovpn-admin"` | |
| ovpnAdmin.basicAuth.user | string | `"admin"` | |
| ovpnAdmin.basicAuth.password | string | `"changeme"` | |
| openvpn.repo | string | `"ghcr.io/palark/ovpn-admin/openvpn"` | |
| 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)

View File

@ -1,39 +0,0 @@
domain: changeme
ovpnAdmin:
repo: ghcr.io/palark/ovpn-admin/ovpn-admin
basicAuth:
user: admin
password: changeme
openvpn:
repo: ghcr.io/palark/ovpn-admin/openvpn
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"

2
helm/Chart.yaml Normal file
View File

@ -0,0 +1,2 @@
name: ovpn-admin
version: 1.0.0

1
helm/README.md Normal file
View File

@ -0,0 +1 @@
helm chart example

View File

@ -12,19 +12,19 @@ spec:
labels: labels:
app: openvpn app: openvpn
spec: spec:
{{- if .Values.nodeSelector }} {{- if .Values.openvpn.nodeSelector }}
nodeSelector: nodeSelector:
{{- .Values.nodeSelector | toYaml | indent 8 | printf "\n%s" }} {{- .Values.openvpn.nodeSelector | toYaml | indent 8 | printf "\n%s" }}
{{- end }} {{- end }}
{{- if .Values.tolerations }} {{- if .Values.openvpn.tolerations }}
tolerations: tolerations:
{{- .Values.tolerations | toYaml | indent 8 | printf "\n%s" }} {{- .Values.openvpn.tolerations | toYaml | indent 8 | printf "\n%s" }}
{{- end }} {{- end }}
terminationGracePeriodSeconds: 0 terminationGracePeriodSeconds: 0
serviceAccountName: openvpn serviceAccountName: openvpn
containers: containers:
- name: ovpn-admin - name: ovpn-admin
image: {{ .Values.ovpnAdmin.repo }}:master image: {{ .Values.ovpnAdmin.image }}
command: command:
- /bin/sh - /bin/sh
- -c - -c
@ -60,7 +60,7 @@ spec:
- name: ccd - name: ccd
mountPath: /mnt/ccd mountPath: /mnt/ccd
- name: openvpn - name: openvpn
image: {{ .Values.ovpnAdmin.repo }}:master image: {{ .Values.openvpn.image }}
command: [ '/entrypoint.sh' ] command: [ '/entrypoint.sh' ]
# imagePullPolicy: Always # imagePullPolicy: Always
securityContext: securityContext:

View File

@ -4,17 +4,12 @@ kind: Ingress
metadata: metadata:
name: ovpn-admin name: ovpn-admin
annotations: annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTP nginx.ingress.kubernetes.io/backend-protocol: HTTP
nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
nginx.ingress.kubernetes.io/auth-secret: basic-auth nginx.ingress.kubernetes.io/auth-secret: basic-auth
{{- with .Values.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec: spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . | quote }}
{{- end }}
tls: tls:
- hosts: - hosts:
- {{ .Values.domain }} - {{ .Values.domain }}
@ -30,3 +25,15 @@ spec:
name: ovpn-admin name: ovpn-admin
port: port:
name: http 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

26
helm/values.yaml Normal file
View File

@ -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

76
main.go
View File

@ -9,7 +9,11 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"github.com/google/uuid"
"io/ioutil" "io/ioutil"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -21,11 +25,6 @@ import (
"time" "time"
"unicode/utf8" "unicode/utf8"
"github.com/google/uuid"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"github.com/gobuffalo/packr/v2" "github.com/gobuffalo/packr/v2"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
@ -35,7 +34,7 @@ import (
) )
const ( const (
usernameRegexp = `^([a-zA-Z0-9_.\-@])+$` usernameRegexp = `^([a-zA-Z0-9_.-@])+$`
passwordMinLength = 6 passwordMinLength = 6
certsArchiveFileName = "certs.tar.gz" certsArchiveFileName = "certs.tar.gz"
ccdArchiveFileName = "ccd.tar.gz" ccdArchiveFileName = "ccd.tar.gz"
@ -50,7 +49,7 @@ const (
var ( var (
listenHost = kingpin.Flag("listen.host", "host for ovpn-admin").Default("0.0.0.0").Envar("OVPN_LISTEN_HOST").String() listenHost = kingpin.Flag("listen.host", "host for ovpn-admin").Default("0.0.0.0").Envar("OVPN_LISTEN_HOST").String()
listenPort = kingpin.Flag("listen.port", "port for ovpn-admin").Default("8080").Envar("OVPN_LISTEN_PORT").String() listenPort = kingpin.Flag("listen.port", "port for ovpn-admin").Default("8080").Envar("OVPN_LISTEN_PORT").String()
listenBaseUrl = kingpin.Flag("listen.base-url", "base url for ovpn-admin").Default("/").Envar("OVPN_LISTEN_BASE_URL").String() listenBaseUrl = kingpin.Flag("listen.base-url", "base url for ovpn-admin").Default("/").Envar("OVPN_LISTEN_BASE_URL").String()
serverRole = kingpin.Flag("role", "server role, master or slave").Default("master").Envar("OVPN_ROLE").HintOptions("master", "slave").String() serverRole = kingpin.Flag("role", "server role, master or slave").Default("master").Envar("OVPN_ROLE").HintOptions("master", "slave").String()
masterHost = kingpin.Flag("master.host", "URL for the master server").Default("http://127.0.0.1").Envar("OVPN_MASTER_HOST").String() masterHost = kingpin.Flag("master.host", "URL for the master server").Default("http://127.0.0.1").Envar("OVPN_MASTER_HOST").String()
masterBasicAuthUser = kingpin.Flag("master.basic-auth.user", "user for master server's Basic Auth").Default("").Envar("OVPN_MASTER_USER").String() masterBasicAuthUser = kingpin.Flag("master.basic-auth.user", "user for master server's Basic Auth").Default("").Envar("OVPN_MASTER_USER").String()
@ -65,18 +64,16 @@ var (
metricsPath = kingpin.Flag("metrics.path", "URL path for exposing collected metrics").Default("/metrics").Envar("OVPN_METRICS_PATH").String() metricsPath = kingpin.Flag("metrics.path", "URL path for exposing collected metrics").Default("/metrics").Envar("OVPN_METRICS_PATH").String()
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa").Envar("EASYRSA_PATH").String() easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa").Envar("EASYRSA_PATH").String()
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file").Default("").Envar("OVPN_INDEX_PATH").String() indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file").Default("").Envar("OVPN_INDEX_PATH").String()
easyrsaBinPath = kingpin.Flag("easyrsa.bin-path", "path to easyrsa script").Default("easyrsa").Envar("EASYRSA_BIN_PATH").String() easyrsaBinPath = kingpin.Flag("easyrsa.bin-path", "path to easyrsa script").Default("easyrsa").Envar("EASYRSA_BIN_PATH").String()
ccdEnabled = kingpin.Flag("ccd", "enable client-config-dir").Default("false").Envar("OVPN_CCD").Bool() ccdEnabled = kingpin.Flag("ccd", "enable client-config-dir").Default("false").Envar("OVPN_CCD").Bool()
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").Envar("OVPN_CCD_PATH").String() ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").Envar("OVPN_CCD_PATH").String()
clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").Envar("OVPN_TEMPLATES_CC_PATH").String() clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").Envar("OVPN_TEMPLATES_CC_PATH").String()
ccdTemplatePath = kingpin.Flag("templates.ccd-path", "path to custom ccd.tpl").Default("").Envar("OVPN_TEMPLATES_CCD_PATH").String() ccdTemplatePath = kingpin.Flag("templates.ccd-path", "path to custom ccd.tpl").Default("").Envar("OVPN_TEMPLATES_CCD_PATH").String()
authByPassword = kingpin.Flag("auth.password", "enable additional password authentication").Default("false").Envar("OVPN_AUTH").Bool() authByPassword = kingpin.Flag("auth.password", "enable additional password authentication").Default("false").Envar("OVPN_AUTH").Bool()
authDatabase = kingpin.Flag("auth.db", "database path for password authentication").Default("./easyrsa/pki/users.db").Envar("OVPN_AUTH_DB_PATH").String() authDatabase = kingpin.Flag("auth.db", "database path for password authentication").Default("./easyrsa/pki/users.db").Envar("OVPN_AUTH_DB_PATH").String()
authDataBaseInit = kingpin.Flag("auth.db-init", "enable database initialization if db user not exists or size is 0").Default("false").Envar("OVPN_AUTH_DB_INIT").Bool()
logLevel = kingpin.Flag("log.level", "set log level: trace, debug, info, warn, error (default info)").Default("info").Envar("LOG_LEVEL").String() logLevel = kingpin.Flag("log.level", "set log level: trace, debug, info, warn, error (default info)").Default("info").Envar("LOG_LEVEL").String()
logFormat = kingpin.Flag("log.format", "set log format: text, json (default text)").Default("text").Envar("LOG_FORMAT").String() logFormat = kingpin.Flag("log.format", "set log format: text, json (default text)").Default("text").Envar("LOG_FORMAT").String()
storageBackend = kingpin.Flag("storage.backend", "storage backend: filesystem, kubernetes.secrets (default filesystem)").Default("filesystem").Envar("STORAGE_BACKEND").String() storageBackend = kingpin.Flag("storage.backend", "storage backend: filesystem, kubernetes.secrets (default filesystem)").Default("filesystem").Envar("STORAGE_BACKEND").String()
clientCertExpirationDays = kingpin.Flag("client-cert.expiration-days", "Expiration period of OpenVPN client certificates in days, the period will shrink automatically to the CA expiration period").Default("3650").Envar("CLIENT_CERT_EXPIRATION_DAYS").String()
certsArchivePath = "/tmp/" + certsArchiveFileName certsArchivePath = "/tmp/" + certsArchiveFileName
ccdArchivePath = "/tmp/" + ccdArchiveFileName ccdArchivePath = "/tmp/" + ccdArchiveFileName
@ -507,10 +504,6 @@ func main() {
*indexTxtPath = *easyrsaDirPath + "/pki/index.txt" *indexTxtPath = *easyrsaDirPath + "/pki/index.txt"
} }
if *authDataBaseInit {
ovpnUserInitDb()
}
ovpnAdmin := new(OvpnAdmin) ovpnAdmin := new(OvpnAdmin)
ovpnAdmin.lastSyncTime = "unknown" ovpnAdmin.lastSyncTime = "unknown"
@ -565,27 +558,27 @@ func main() {
static := CacheControlWrapper(http.FileServer(staticBox)) static := CacheControlWrapper(http.FileServer(staticBox))
http.Handle(*listenBaseUrl, http.StripPrefix(strings.TrimRight(*listenBaseUrl, "/"), static)) http.Handle(*listenBaseUrl, http.StripPrefix(strings.TrimRight(*listenBaseUrl, "/"), static))
http.HandleFunc(*listenBaseUrl+"api/server/settings", ovpnAdmin.serverSettingsHandler) http.HandleFunc(*listenBaseUrl + "api/server/settings", ovpnAdmin.serverSettingsHandler)
http.HandleFunc(*listenBaseUrl+"api/users/list", ovpnAdmin.userListHandler) http.HandleFunc(*listenBaseUrl + "api/users/list", ovpnAdmin.userListHandler)
http.HandleFunc(*listenBaseUrl+"api/user/create", ovpnAdmin.userCreateHandler) http.HandleFunc(*listenBaseUrl + "api/user/create", ovpnAdmin.userCreateHandler)
http.HandleFunc(*listenBaseUrl+"api/user/change-password", ovpnAdmin.userChangePasswordHandler) http.HandleFunc(*listenBaseUrl + "api/user/change-password", ovpnAdmin.userChangePasswordHandler)
http.HandleFunc(*listenBaseUrl+"api/user/rotate", ovpnAdmin.userRotateHandler) http.HandleFunc(*listenBaseUrl + "api/user/rotate", ovpnAdmin.userRotateHandler)
http.HandleFunc(*listenBaseUrl+"api/user/delete", ovpnAdmin.userDeleteHandler) http.HandleFunc(*listenBaseUrl + "api/user/delete", ovpnAdmin.userDeleteHandler)
http.HandleFunc(*listenBaseUrl+"api/user/revoke", ovpnAdmin.userRevokeHandler) http.HandleFunc(*listenBaseUrl + "api/user/revoke", ovpnAdmin.userRevokeHandler)
http.HandleFunc(*listenBaseUrl+"api/user/unrevoke", ovpnAdmin.userUnrevokeHandler) http.HandleFunc(*listenBaseUrl + "api/user/unrevoke", ovpnAdmin.userUnrevokeHandler)
http.HandleFunc(*listenBaseUrl+"api/user/config/show", ovpnAdmin.userShowConfigHandler) http.HandleFunc(*listenBaseUrl + "api/user/config/show", ovpnAdmin.userShowConfigHandler)
http.HandleFunc(*listenBaseUrl+"api/user/disconnect", ovpnAdmin.userDisconnectHandler) http.HandleFunc(*listenBaseUrl + "api/user/disconnect", ovpnAdmin.userDisconnectHandler)
http.HandleFunc(*listenBaseUrl+"api/user/statistic", ovpnAdmin.userStatisticHandler) http.HandleFunc(*listenBaseUrl + "api/user/statistic", ovpnAdmin.userStatisticHandler)
http.HandleFunc(*listenBaseUrl+"api/user/ccd", ovpnAdmin.userShowCcdHandler) http.HandleFunc(*listenBaseUrl + "api/user/ccd", ovpnAdmin.userShowCcdHandler)
http.HandleFunc(*listenBaseUrl+"api/user/ccd/apply", ovpnAdmin.userApplyCcdHandler) http.HandleFunc(*listenBaseUrl + "api/user/ccd/apply", ovpnAdmin.userApplyCcdHandler)
http.HandleFunc(*listenBaseUrl+"api/sync/last/try", ovpnAdmin.lastSyncTimeHandler) http.HandleFunc(*listenBaseUrl + "api/sync/last/try", ovpnAdmin.lastSyncTimeHandler)
http.HandleFunc(*listenBaseUrl+"api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler) http.HandleFunc(*listenBaseUrl + "api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler)
http.HandleFunc(*listenBaseUrl+downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler) http.HandleFunc(*listenBaseUrl + downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler)
http.HandleFunc(*listenBaseUrl+downloadCcdApiUrl, ovpnAdmin.downloadCcdHandler) http.HandleFunc(*listenBaseUrl + downloadCcdApiUrl, ovpnAdmin.downloadCcdHandler)
http.Handle(*metricsPath, promhttp.HandlerFor(ovpnAdmin.promRegistry, promhttp.HandlerOpts{})) http.Handle(*metricsPath, promhttp.HandlerFor(ovpnAdmin.promRegistry, promhttp.HandlerOpts{}))
http.HandleFunc(*listenBaseUrl+"ping", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc(*listenBaseUrl + "ping", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "pong") fmt.Fprintf(w, "pong")
}) })
@ -861,7 +854,7 @@ func (oAdmin *OvpnAdmin) getCcd(username string) Ccd {
} }
func checkStaticAddressIsFree(staticAddress string, username string) bool { func checkStaticAddressIsFree(staticAddress string, username string) bool {
o := runBash(fmt.Sprintf("grep -rl ' %[1]s ' %[2]s | grep -vx %[2]s/%[3]s | wc -l", staticAddress, *ccdDir, username)) o := runBash(fmt.Sprintf("grep -rl ' %s ' %s | grep -vx %s/%s | wc -l", staticAddress, *ccdDir, *ccdDir, username))
if strings.TrimSpace(o) == "0" { if strings.TrimSpace(o) == "0" {
return true return true
@ -1011,7 +1004,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) {
func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (error, string) { func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (error, string) {
if checkUserExist(username) { if checkUserExist(username) {
o := runBash(fmt.Sprintf("openvpn-user check --db.path %[1]s --user %[2]s | grep %[2]s | wc -l", *authDatabase, username)) o := runBash(fmt.Sprintf("openvpn-user check --db.path %s --user %s | grep %s | wc -l", *authDatabase, username, username))
log.Debug(o) log.Debug(o)
if err := validatePassword(password); err != nil { if err := validatePassword(password); err != nil {
@ -1055,12 +1048,12 @@ func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) {
log.Error(err) log.Error(err)
} }
} else { } else {
o := runBash(fmt.Sprintf("cd %[1]s && echo yes | %[2]s revoke %[3]s 1>/dev/null && %[2]s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath, username)) o := runBash(fmt.Sprintf("cd %s && echo yes | easyrsa revoke %s 1>/dev/null && %s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath, username))
log.Debugln(o) log.Debugln(o)
} }
if *authByPassword { if *authByPassword {
o := runBash(fmt.Sprintf("openvpn-user revoke --db.path %s --user %s", *authDatabase, username)) o := runBash(fmt.Sprintf("openvpn-user revoke --db-path %s --user %s", *authDatabase, username))
log.Debug(o) log.Debug(o)
} }
@ -1122,7 +1115,7 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) (error, string) {
_ = runBash(fmt.Sprintf("cd %s && %s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath)) _ = runBash(fmt.Sprintf("cd %s && %s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath))
if *authByPassword { if *authByPassword {
o := runBash(fmt.Sprintf("openvpn-user restore --db.path %s --user %s", *authDatabase, username)) o := runBash(fmt.Sprintf("openvpn-user restore --db-path %s --user %s", *authDatabase, username))
log.Debug(o) log.Debug(o)
} }
@ -1347,7 +1340,7 @@ func (oAdmin *OvpnAdmin) mgmtGetActiveClients() []clientStatus {
break break
} }
oAdmin.mgmtRead(conn) // read welcome message oAdmin.mgmtRead(conn) // read welcome message
conn.Write([]byte("status 1\n")) conn.Write([]byte("status\n"))
activeClients = append(activeClients, oAdmin.mgmtConnectedUsersParser(oAdmin.mgmtRead(conn), srv)...) activeClients = append(activeClients, oAdmin.mgmtConnectedUsersParser(oAdmin.mgmtRead(conn), srv)...)
conn.Close() conn.Close()
} }
@ -1508,13 +1501,6 @@ func unArchiveCcd() {
} }
} }
func ovpnUserInitDb() {
if fi, err := os.Stat(*authDatabase); errors.Is(err, os.ErrNotExist) || fi.Size() == 0 {
i := runBash(fmt.Sprintf("openvpn-user --db.path %[1]s db-init && openvpn-user --db.path %[1]s db-migrate", *authDatabase))
log.Debug(i)
}
}
func (oAdmin *OvpnAdmin) syncDataFromMaster() { func (oAdmin *OvpnAdmin) syncDataFromMaster() {
retryCountMax := 3 retryCountMax := 3
certsDownloadFailed := true certsDownloadFailed := true

View File

@ -48,7 +48,7 @@ if [ ${OVPN_PASSWD_AUTH} = "true" ]; then
echo "auth-user-pass-verify /etc/openvpn/scripts/auth.sh via-file" | tee -a /etc/openvpn/openvpn.conf echo "auth-user-pass-verify /etc/openvpn/scripts/auth.sh via-file" | tee -a /etc/openvpn/openvpn.conf
echo "script-security 2" | tee -a /etc/openvpn/openvpn.conf echo "script-security 2" | tee -a /etc/openvpn/openvpn.conf
echo "verify-client-cert require" | tee -a /etc/openvpn/openvpn.conf echo "verify-client-cert require" | tee -a /etc/openvpn/openvpn.conf
openvpn-user db-init --db.path=$EASY_RSA_LOC/pki/users.db && openvpn-user db-migrate --db.path=$EASY_RSA_LOC/pki/users.db openvpn-user db-init --db.path=$EASY_RSA_LOC/pki/users.db
fi fi
[ -d $EASY_RSA_LOC/pki ] && chmod 755 $EASY_RSA_LOC/pki [ -d $EASY_RSA_LOC/pki ] && chmod 755 $EASY_RSA_LOC/pki

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/usr/bin/env bash
docker compose -p openvpn-master up -d --build docker-compose -p openvpn-master up -d --build

View File

@ -1,10 +1,10 @@
project: ovpn-admin project: ovpn-admin
configVersion: 1 configVersion: 1
--- ---
image: ovpn-admin image: ovpn-admin
dockerfile: Dockerfile.ovpn-admin dockerfile: Dockerfile
context: .
--- ---
image: openvpn image: openvpn
dockerfile: Dockerfile.openvpn dockerfile: Dockerfile.openvpn
context: .