Skip to content

Commit

Permalink
totp auth; refactoring; fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
pashcovich committed Dec 30, 2022
1 parent a973b88 commit 63d8501
Show file tree
Hide file tree
Showing 37 changed files with 8,248 additions and 5,396 deletions.
14 changes: 8 additions & 6 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ out
gen
.github

easyrsa
easyrsa_master
easyrsa_slave
ccd
ccd_master
ccd_slave
easyrsa/
easyrsa_master/
easyrsa_slave/
ccd/
ccd_master/
ccd_slave/
werf.yaml
frontend/node_modules
frontend/static/dist
Expand All @@ -24,3 +24,5 @@ docker-compose-slave.yaml
img
dashboard
.helm
.github

13 changes: 13 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
OVPN_SERVER_NET="192.168.100.0"
OVPN_SERVER_MASK="255.255.255.0"
OVPN_NETWORK="192.168.100.0/24"
OVPN_CCD="true"
OVPN_CCD_PATH="/mnt/ccd"
EASYRSA_PATH="/mnt/easyrsa"
OVPN_INDEX_PATH="/mnt/easyrsa/pki/index.txt"
OVPN_SERVER="127.0.0.1:7777:tcp"
OVPN_AUTH="true"
OVPN_AUTH_TFA="true"
OVPN_PASSWD_AUTH="true"
OVPN_AUTH_DB_PATH="/mnt/easyrsa/pki/users.db"
LOG_LEVEL="debug"
8 changes: 0 additions & 8 deletions .github/workflows/publish-latest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ jobs:
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Push openvpn image to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
repository: flant/ovpn-admin
tags: openvpn-latest
dockerfile: Dockerfile.openvpn
- name: Push ovpn-admin image to Docker Hub
uses: docker/build-push-action@v1
with:
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/publish-tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ jobs:
- name: Get the version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Push openvpn image to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
repository: flant/ovpn-admin
tags: openvpn-${{ steps.get_version.outputs.VERSION }}
dockerfile: Dockerfile.openvpn
- name: Push ovpn-admin image to Docker Hub
uses: docker/build-push-action@v1
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ packrd/
*.ntvs*
*.njsproj
*.sln

.env
11 changes: 6 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ COPY frontend/ /app
RUN 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
RUN cd /app && packr2 && env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin && packr2 clean
RUN cd /app && env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin

FROM alpine:3.16
WORKDIR /app
COPY --from=backend-builder /app/ovpn-admin /app
RUN apk add --update bash easy-rsa openssl openvpn coreutils && \
RUN apk add --update bash easy-rsa openssl openvpn coreutils iptables curl&& \
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-amd64.tar.gz -O - | tar xz -C /usr/local/bin && \
wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.9/openvpn-user-linux-amd64.tar.gz -O - | tar xz -C /usr/local/bin && \
rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/*
COPY --from=backend-builder /app/ovpn-admin /app
COPY setup/ /etc/openvpn/setup
RUN chmod +x /etc/openvpn/setup/configure.sh
7 changes: 0 additions & 7 deletions Dockerfile.openvpn

This file was deleted.

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ Ready docker images available on [Docker Hub](https://hub.docker.com/r/flant/ovp

Requirements. You need Linux with the following components installed:
- [golang](https://golang.org/doc/install)
- [packr2](https://github.com/gobuffalo/packr#installation)
- [nodejs/npm](https://nodejs.org/en/download/package-manager/)

before version 2.1.0 you need
- [packr2](https://github.com/gobuffalo/packr#installation)


Commands to execute:

```bash
Expand Down
31 changes: 15 additions & 16 deletions certificates.go → backend/certificates.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package backend

import (
"bytes"
Expand All @@ -12,8 +12,8 @@ import (
"time"
)

// decode certificate from PEM to x509
func decodeCert(certPEMBytes []byte) (cert *x509.Certificate, err error) {
// DecodeCert decode certificate from PEM to x509
func DecodeCert(certPEMBytes []byte) (cert *x509.Certificate, err error) {
certPem, _ := pem.Decode(certPEMBytes)
certPemBytes := certPem.Bytes

Expand All @@ -25,8 +25,8 @@ func decodeCert(certPEMBytes []byte) (cert *x509.Certificate, err error) {
return
}

// decode private key from PEM to RSA format
func decodePrivKey(privKey []byte) (key *rsa.PrivateKey, err error) {
// DecodePrivKey decode private key from PEM to RSA format
func DecodePrivKey(privKey []byte) (key *rsa.PrivateKey, err error) {
privKeyPem, _ := pem.Decode(privKey)
key, err = x509.ParsePKCS1PrivateKey(privKeyPem.Bytes)
if err == nil {
Expand All @@ -43,8 +43,8 @@ func decodePrivKey(privKey []byte) (key *rsa.PrivateKey, err error) {
return
}

// return PEM encoded private key
func genPrivKey() (privKeyPEM *bytes.Buffer, err error) {
// GenPrivKey return PEM encoded private key
func GenPrivKey() (privKeyPEM *bytes.Buffer, err error) {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)

//privKeyPKCS1 := x509.MarshalPKCS1PrivateKey(privKey)
Expand All @@ -60,12 +60,11 @@ func genPrivKey() (privKeyPEM *bytes.Buffer, err error) {
Bytes: privKeyPKCS8,
})


return
}

// return PEM encoded certificate
func genCA(privKey *rsa.PrivateKey) (issuerPEM *bytes.Buffer, err error) {
// GenCA return PEM encoded certificate
func GenCA(privKey *rsa.PrivateKey) (issuerPEM *bytes.Buffer, err error) {
serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128)

issuerSerial, err := rand.Int(rand.Reader, serialNumberRange)
Expand Down Expand Up @@ -96,8 +95,8 @@ func genCA(privKey *rsa.PrivateKey) (issuerPEM *bytes.Buffer, err error) {
return
}

// return PEM encoded certificate
func genServerCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn string) (issuerPEM *bytes.Buffer, err error) {
// GenServerCert return PEM encoded certificate
func GenServerCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn string) (issuerPEM *bytes.Buffer, err error) {
serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128)
serial, err := rand.Int(rand.Reader, serialNumberRange)

Expand Down Expand Up @@ -128,8 +127,8 @@ func genServerCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn
return
}

// return PEM encoded certificate
func genClientCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn string) (issuerPEM *bytes.Buffer, err error) {
// GenClientCert return PEM encoded certificate
func GenClientCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn string) (issuerPEM *bytes.Buffer, err error) {
serialNumberRange := new(big.Int).Lsh(big.NewInt(1), 128)
serial, err := rand.Int(rand.Reader, serialNumberRange)

Expand Down Expand Up @@ -160,8 +159,8 @@ func genClientCert(privKey, caPrivKey *rsa.PrivateKey, ca *x509.Certificate, cn
return
}

// return PEM encoded CRL
func genCRL(certs []*RevokedCert, ca *x509.Certificate, caKey *rsa.PrivateKey) (crlPEM *bytes.Buffer, err error) {
// GenCRL return PEM encoded CRL
func GenCRL(certs []*RevokedCert, ca *x509.Certificate, caKey *rsa.PrivateKey) (crlPEM *bytes.Buffer, err error) {
var revokedCertificates []pkix.RevokedCertificate

for _, cert := range certs {
Expand Down
14 changes: 14 additions & 0 deletions backend/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package backend

const (
usernameRegexp = `^([a-zA-Z0-9_.-@])+$`
passwordMinLength = 6
DownloadCertsApiUrl = "/api/data/certs/download"
DownloadCcdApiUrl = "/api/data/ccd/download"
certsArchiveFileName = "certs.tar.gz"
ccdArchiveFileName = "ccd.tar.gz"
indexTxtDateLayout = "060102150405Z"
stringDateFormat = "2006-01-02 15:04:05"

KubeNamespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
)
18 changes: 18 additions & 0 deletions backend/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package backend

import "errors"

var (
userSecretDoesNotExistError = errors.New("user secret does not exist")
userAlreadyExistError = errors.New("user already exist")
userDeletedError = errors.New("user marked as deleted")
userRestoreError = errors.New("failed to restore user")
userRevokeError = errors.New("failed to revoke user")
userDeleteError = errors.New("failed to delete user")
userIsNotActiveError = errors.New("user is not active")
passwordMismatchedError = errors.New("password mismatched")
tokenMismatchedError = errors.New("token mismatched")
checkAppError = errors.New("failed to check 2FA app")
registerAppError = errors.New("failed to register 2FA app")
authBackendDisabled = errors.New("auth backend not enabled yet")
)
47 changes: 47 additions & 0 deletions backend/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package backend

import "gopkg.in/alecthomas/kingpin.v2"

var (
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()
ServerRole = kingpin.Flag("role", "server role, master or slave").Default("master").Envar("OVPN_ROLE").HintOptions("master", "slave").String()

//PersonalAccess = kingpin.Flag("personalize", "personalize access for users").Default("false").Envar("OVPN_ADMIN_PERSONALIZE").Bool()
//AdminUserPassword = kingpin.Flag("admin.password", "password fom admin user").Default("admin").Envar("OVPN_ADMIN_PASSWORD").String()
//AdditionalAdminUsers = kingpin.Flag("admin.users", "comma separated users for additional admin grants").Default("").Envar("OVPN_ADMIN_USERS").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()
MasterBasicAuthPassword = kingpin.Flag("master.basic-auth.password", "password for master server's Basic Auth").Default("").Envar("OVPN_MASTER_PASSWORD").String()
masterSyncFrequency = kingpin.Flag("master.sync-frequency", "master host data sync frequency in seconds").Default("600").Envar("OVPN_MASTER_SYNC_FREQUENCY").Int()
MasterSyncToken = kingpin.Flag("master.sync-token", "master host data sync security token").Default("VerySecureToken").Envar("OVPN_MASTER_TOKEN").PlaceHolder("TOKEN").String()

openvpnNetwork = kingpin.Flag("ovpn.network", "NETWORK/MASK_PREFIX for OpenVPN server").Default("172.16.100.0/24").Envar("OVPN_NETWORK").String()
openvpnServer = kingpin.Flag("ovpn.server", "HOST:PORT:PROTOCOL for OpenVPN server; can have multiple values").Default("127.0.0.1:7777:tcp").Envar("OVPN_SERVER").PlaceHolder("HOST:PORT:PROTOCOL").Strings()
//openvpnServerCryptoMode = kingpin.Flag("ovpn.server.crypto-mode", "OpenVPN server crypto mode").Default("tls-auth").Envar("OVPN_SERVER_CRYPTO_MODE").HintOptions("none", "tls-auth", "tls-crypt", "tls-cryptv2").Strings()
//openvpnServerCryptoFile = kingpin.Flag("ovpn.server.crypto-file", "OpenVPN server file name with cert for crypto ").Default("ta.key").Envar("OVPN_SERVER_CRYPTO_FILE").Strings()
openvpnServerBehindLB = kingpin.Flag("ovpn.server.behindLB", "enable if your OpenVPN server is behind Kubernetes Service having the LoadBalancer type").Default("false").Envar("OVPN_LB").Bool()
openvpnServiceName = kingpin.Flag("ovpn.service", "the name of Kubernetes Service having the LoadBalancer type if your OpenVPN server is behind it").Default("openvpn-external").Envar("OVPN_LB_SERVICE").Strings()

MgmtAddress = kingpin.Flag("mgmt", "ALIAS=HOST:PORT for OpenVPN server mgmt interface; can have multiple values").Default("main=127.0.0.1:8989").Envar("OVPN_MGMT").Strings()
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()
IndexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file").Default("").Envar("OVPN_INDEX_PATH").String()

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()

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()

AuthByPassword = kingpin.Flag("auth.password", "enable additional password authentication").Default("false").Envar("OVPN_AUTH").Bool()
AuthTFA = kingpin.Flag("auth.2fa", "auth type").Default("false").Envar("OVPN_AUTH_TFA").Bool()
AuthDatabase = kingpin.Flag("auth.db", "database path for password authentication").Default("./easyrsa/pki/users.db").Envar("OVPN_AUTH_DB_PATH").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()

StorageBackend = kingpin.Flag("storage.backend", "storage backend for user certs)").Default("filesystem").HintOptions("kubernetes.secrets", "filesystem").Envar("STORAGE_BACKEND").String()
)
Loading

0 comments on commit 63d8501

Please sign in to comment.