Merge fd2169946a
into 84741d46ad
This commit is contained in:
commit
847c33c814
27 changed files with 8397 additions and 875 deletions
5
.env
5
.env
|
@ -1,3 +1,4 @@
|
|||
OVPN_LISTEN_BASE_URL="/"
|
||||
OVPN_SERVER_NET="192.168.100.0"
|
||||
OVPN_SERVER_MASK="255.255.255.0"
|
||||
OVPN_NETWORK="192.168.100.0/24"
|
||||
|
@ -6,8 +7,6 @@ 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="TOTP"
|
||||
OVPN_AUTH_DB_PATH="/mnt/easyrsa/pki/users.db"
|
||||
LOG_LEVEL="debug"
|
||||
|
|
23
.github/workflows/publish-latest.yaml
vendored
23
.github/workflows/publish-latest.yaml
vendored
|
@ -12,11 +12,24 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Push ovpn-admin image to Docker Hub
|
||||
uses: docker/build-push-action@v1
|
||||
- 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 }}
|
||||
repository: flant/ovpn-admin
|
||||
tags: latest
|
||||
dockerfile: Dockerfile
|
||||
- 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
|
23
.github/workflows/publish-tag.yaml
vendored
23
.github/workflows/publish-tag.yaml
vendored
|
@ -16,11 +16,24 @@ jobs:
|
|||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Push ovpn-admin image to Docker Hub
|
||||
uses: docker/build-push-action@v1
|
||||
- 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 }}
|
||||
repository: flant/ovpn-admin
|
||||
tags: ${{ steps.get_version.outputs.VERSION }}
|
||||
dockerfile: Dockerfile
|
||||
- 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
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
- name: checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: build binaries
|
||||
uses: wangyoucao577/go-release-action@v1.28
|
||||
uses: wangyoucao577/go-release-action@v1.40
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goversion: 1.17
|
||||
|
|
2
.github/workflows/release_arm.yaml
vendored
2
.github/workflows/release_arm.yaml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
- name: checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: build binaries
|
||||
uses: wangyoucao577/go-release-action@v1.28
|
||||
uses: wangyoucao577/go-release-action@v1.40
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
goversion: 1.17
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
FROM node:16-alpine3.15 AS frontend-builder
|
||||
COPY frontend/ /app
|
||||
RUN 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
|
||||
COPY --from=frontend-builder /app/static /app/frontend/static
|
||||
COPY . /app
|
||||
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
|
||||
ARG TARGETARCH
|
||||
RUN cd /app && env CGO_ENABLED=1 GOOS=linux GOARCH=${TARGETARCH} go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin
|
||||
|
||||
FROM alpine:3.16
|
||||
WORKDIR /app
|
||||
ARG TARGETARCH
|
||||
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.9/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-${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
|
||||
COPY --from=backend-builder /app/ovpn-admin /app
|
||||
COPY setup/ /etc/openvpn/setup
|
||||
RUN chmod +x /etc/openvpn/setup/configure.sh
|
||||
|
|
|
@ -97,6 +97,9 @@ Flags:
|
|||
--listen.port="8080" port for ovpn-admin
|
||||
(or OVPN_LISTEN_PORT)
|
||||
|
||||
--listen.base-url="/" base URL for ovpn-admin web files
|
||||
(or $OVPN_LISTEN_BASE_URL)
|
||||
|
||||
--role="master" server role, master or slave
|
||||
(or OVPN_ROLE)
|
||||
|
||||
|
|
|
@ -11,4 +11,16 @@ const (
|
|||
stringDateFormat = "2006-01-02 15:04:05"
|
||||
|
||||
KubeNamespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
|
||||
)
|
||||
|
||||
secretCA = "openvpn-pki-ca"
|
||||
secretServer = "openvpn-pki-server"
|
||||
secretClientTmpl = "openvpn-pki-%d"
|
||||
secretCRL = "openvpn-pki-crl"
|
||||
secretIndexTxt = "openvpn-pki-index-txt"
|
||||
secretDHandTA = "openvpn-pki-dh-and-ta"
|
||||
certFileName = "tls.crt"
|
||||
privKeyFileName = "tls.key"
|
||||
|
||||
//<year><month><day><hour><minute><second>Z
|
||||
indexTxtDateFormat = "060102150405Z"
|
||||
)
|
|
@ -12,7 +12,7 @@ var (
|
|||
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")
|
||||
checkAppError = errors.New("failed to check 2FA TOTP app")
|
||||
registerAppError = errors.New("failed to register 2FA TOTP app")
|
||||
authBackendDisabled = errors.New("auth backend not enabled yet")
|
||||
)
|
||||
|
|
|
@ -3,9 +3,10 @@ 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()
|
||||
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()
|
||||
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()
|
||||
|
||||
//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()
|
||||
|
@ -29,6 +30,7 @@ var (
|
|||
|
||||
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()
|
||||
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()
|
||||
CcdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").Envar("OVPN_CCD_PATH").String()
|
||||
|
@ -36,8 +38,7 @@ var (
|
|||
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()
|
||||
AuthType = kingpin.Flag("auth.type", "auth type").Default("").Envar("OVPN_AUTH").HintOptions("TOTP", "PASSWORD", "").String()
|
||||
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()
|
||||
|
|
|
@ -17,7 +17,7 @@ func (oAdmin *OvpnAdmin) UserListHandler(w http.ResponseWriter, r *http.Request)
|
|||
}
|
||||
oAdmin.clients = oAdmin.usersList()
|
||||
}
|
||||
|
||||
|
||||
usersList, _ := json.Marshal(oAdmin.clients)
|
||||
fmt.Fprintf(w, "%s", usersList)
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func (oAdmin *OvpnAdmin) UserResetTFAHandler(w http.ResponseWriter, r *http.Requ
|
|||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, "2FA reseted")
|
||||
fmt.Fprintf(w, "TOTP reseted")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ func (oAdmin *OvpnAdmin) UserUnrevokeHandler(w http.ResponseWriter, r *http.Requ
|
|||
func (oAdmin *OvpnAdmin) UserChangePasswordHandler(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info(r.RemoteAddr, " ", r.RequestURI)
|
||||
_ = r.ParseForm()
|
||||
if *AuthByPassword {
|
||||
if oAdmin.ExtraAuth {
|
||||
err, msg := oAdmin.userChangePassword(r.FormValue("username"), r.FormValue("password"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
|
@ -3,18 +3,13 @@ package backend
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dgryski/dgoogauth"
|
||||
"github.com/google/uuid"
|
||||
// "github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
@ -23,52 +18,11 @@ import (
|
|||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
secretCA = "openvpn-pki-ca"
|
||||
secretServer = "openvpn-pki-server"
|
||||
secretClientTmpl = "openvpn-pki-%d"
|
||||
secretCRL = "openvpn-pki-crl"
|
||||
secretIndexTxt = "openvpn-pki-index-txt"
|
||||
secretDHandTA = "openvpn-pki-dh-and-ta"
|
||||
certFileName = "tls.crt"
|
||||
privKeyFileName = "tls.key"
|
||||
)
|
||||
|
||||
//<year><month><day><hour><minute><second>Z
|
||||
const indexTxtDateFormat = "060102150405Z"
|
||||
|
||||
var namespace = "default"
|
||||
|
||||
type OpenVPNPKI struct {
|
||||
CAPrivKeyRSA *rsa.PrivateKey
|
||||
CAPrivKeyPEM *bytes.Buffer
|
||||
CACert *x509.Certificate
|
||||
CACertPEM *bytes.Buffer
|
||||
ServerPrivKeyRSA *rsa.PrivateKey
|
||||
ServerPrivKeyPEM *bytes.Buffer
|
||||
ServerCert *x509.Certificate
|
||||
ServerCertPEM *bytes.Buffer
|
||||
ClientCerts []ClientCert
|
||||
RevokedCerts []RevokedCert
|
||||
KubeClient *kubernetes.Clientset
|
||||
}
|
||||
|
||||
type ClientCert struct {
|
||||
PrivKeyRSA *rsa.PrivateKey
|
||||
PrivKeyPEM *bytes.Buffer
|
||||
Cert *x509.Certificate
|
||||
CertPEM *bytes.Buffer
|
||||
}
|
||||
|
||||
type RevokedCert struct {
|
||||
RevokedTime time.Time `json:"revokedTime"`
|
||||
CommonName string `json:"commonName"`
|
||||
Cert *x509.Certificate `json:"cert"`
|
||||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) Run() (err error) {
|
||||
func (openVPNPKI *OpenVPNPKI) KubeRun() (err error) {
|
||||
if _, err := os.Stat(KubeNamespaceFilePath); err == nil {
|
||||
file, err := ioutil.ReadFile(KubeNamespaceFilePath)
|
||||
file, err := os.ReadFile(KubeNamespaceFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -80,7 +34,7 @@ func (openVPNPKI *OpenVPNPKI) Run() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
err = openVPNPKI.initPKI()
|
||||
err = openVPNPKI.InitPKI()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -90,18 +44,6 @@ func (openVPNPKI *OpenVPNPKI) Run() (err error) {
|
|||
log.Error(err)
|
||||
}
|
||||
|
||||
err = openVPNPKI.easyrsaGenCRL()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if res, _ := openVPNPKI.secretCheckExists(secretDHandTA); !res {
|
||||
err := openVPNPKI.secretGenTaKeyAndDHParam()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = openVPNPKI.updateFilesFromSecrets()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
@ -131,243 +73,243 @@ func (openVPNPKI *OpenVPNPKI) initKubeClient() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) initPKI() (err error) {
|
||||
if res, _ := openVPNPKI.secretCheckExists(secretCA); res {
|
||||
cert, err := openVPNPKI.secretGetClientCert(secretCA)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) initPKI() (err error) {
|
||||
// if res, _ := openVPNPKI.secretCheckExists(secretCA); res {
|
||||
// cert, err := openVPNPKI.secretGetClientCert(secretCA)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
openVPNPKI.CAPrivKeyPEM = cert.PrivKeyPEM
|
||||
openVPNPKI.CAPrivKeyRSA = cert.PrivKeyRSA
|
||||
openVPNPKI.CACertPEM = cert.CertPEM
|
||||
openVPNPKI.CACert = cert.Cert
|
||||
} else {
|
||||
openVPNPKI.CAPrivKeyPEM, err = GenPrivKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
openVPNPKI.CAPrivKeyRSA, err = DecodePrivKey(openVPNPKI.CAPrivKeyPEM.Bytes())
|
||||
// openVPNPKI.CAPrivKeyPEM = cert.PrivKeyPEM
|
||||
// openVPNPKI.CAPrivKeyRSA = cert.PrivKeyRSA
|
||||
// openVPNPKI.CACertPEM = cert.CertPEM
|
||||
// openVPNPKI.CACert = cert.Cert
|
||||
// } else {
|
||||
// openVPNPKI.CAPrivKeyPEM, err = GenPrivKey()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// openVPNPKI.CAPrivKeyRSA, err = DecodePrivKey(openVPNPKI.CAPrivKeyPEM.Bytes())
|
||||
|
||||
openVPNPKI.CACertPEM, _ = GenCA(openVPNPKI.CAPrivKeyRSA)
|
||||
openVPNPKI.CACert, err = DecodeCert(openVPNPKI.CACertPEM.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// openVPNPKI.CACertPEM, _ = GenCA(openVPNPKI.CAPrivKeyRSA)
|
||||
// openVPNPKI.CACert, err = DecodeCert(openVPNPKI.CACertPEM.Bytes())
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{Name: secretCA}
|
||||
// secretMetaData := metav1.ObjectMeta{Name: secretCA}
|
||||
|
||||
secretData := map[string][]byte{
|
||||
certFileName: openVPNPKI.CACertPEM.Bytes(),
|
||||
privKeyFileName: openVPNPKI.CAPrivKeyPEM.Bytes(),
|
||||
}
|
||||
// secretData := map[string][]byte{
|
||||
// certFileName: openVPNPKI.CACertPEM.Bytes(),
|
||||
// privKeyFileName: openVPNPKI.CAPrivKeyPEM.Bytes(),
|
||||
// }
|
||||
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
if res, _ := openVPNPKI.secretCheckExists(secretServer); res {
|
||||
cert, err := openVPNPKI.secretGetClientCert(secretServer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if res, _ := openVPNPKI.secretCheckExists(secretServer); res {
|
||||
// cert, err := openVPNPKI.secretGetClientCert(secretServer)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
openVPNPKI.ServerPrivKeyPEM = cert.PrivKeyPEM
|
||||
openVPNPKI.ServerPrivKeyRSA = cert.PrivKeyRSA
|
||||
openVPNPKI.ServerCertPEM = cert.CertPEM
|
||||
openVPNPKI.ServerCert = cert.Cert
|
||||
} else {
|
||||
openVPNPKI.ServerPrivKeyPEM, err = GenPrivKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// openVPNPKI.ServerPrivKeyPEM = cert.PrivKeyPEM
|
||||
// openVPNPKI.ServerPrivKeyRSA = cert.PrivKeyRSA
|
||||
// openVPNPKI.ServerCertPEM = cert.CertPEM
|
||||
// openVPNPKI.ServerCert = cert.Cert
|
||||
// } else {
|
||||
// openVPNPKI.ServerPrivKeyPEM, err = GenPrivKey()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
openVPNPKI.ServerPrivKeyRSA, err = DecodePrivKey(openVPNPKI.ServerPrivKeyPEM.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// openVPNPKI.ServerPrivKeyRSA, err = DecodePrivKey(openVPNPKI.ServerPrivKeyPEM.Bytes())
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
openVPNPKI.ServerCertPEM, _ = GenServerCert(openVPNPKI.ServerPrivKeyRSA, openVPNPKI.CAPrivKeyRSA, openVPNPKI.CACert, "server")
|
||||
openVPNPKI.ServerCert, err = DecodeCert(openVPNPKI.ServerCertPEM.Bytes())
|
||||
// openVPNPKI.ServerCertPEM, _ = GenServerCert(openVPNPKI.ServerPrivKeyRSA, openVPNPKI.CAPrivKeyRSA, openVPNPKI.CACert, "server")
|
||||
// openVPNPKI.ServerCert, err = DecodeCert(openVPNPKI.ServerCertPEM.Bytes())
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{
|
||||
Name: secretServer,
|
||||
Labels: map[string]string{
|
||||
"index.txt": "",
|
||||
"name": "server",
|
||||
"type": "serverAuth",
|
||||
},
|
||||
}
|
||||
// secretMetaData := metav1.ObjectMeta{
|
||||
// Name: secretServer,
|
||||
// Labels: map[string]string{
|
||||
// "index.txt": "",
|
||||
// "name": "server",
|
||||
// "type": "serverAuth",
|
||||
// },
|
||||
// }
|
||||
|
||||
secretData := map[string][]byte{
|
||||
certFileName: openVPNPKI.ServerCertPEM.Bytes(),
|
||||
privKeyFileName: openVPNPKI.ServerPrivKeyPEM.Bytes(),
|
||||
}
|
||||
// secretData := map[string][]byte{
|
||||
// certFileName: openVPNPKI.ServerCertPEM.Bytes(),
|
||||
// privKeyFileName: openVPNPKI.ServerPrivKeyPEM.Bytes(),
|
||||
// }
|
||||
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) indexTxtUpdate() (err error) {
|
||||
secrets, err := openVPNPKI.secretsGetByLabels("index.txt=")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) indexTxtUpdate() (err error) {
|
||||
// secrets, err := openVPNPKI.secretsGetByLabels("index.txt=")
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
var indexTxt string
|
||||
for _, secret := range secrets.Items {
|
||||
certPEM := bytes.NewBuffer(secret.Data[certFileName])
|
||||
log.Trace("indexTxtUpdate:" + secret.Name)
|
||||
cert, err := DecodeCert(certPEM.Bytes())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// var indexTxt string
|
||||
// for _, secret := range secrets.Items {
|
||||
// certPEM := bytes.NewBuffer(secret.Data[certFileName])
|
||||
// log.Trace("indexTxtUpdate:" + secret.Name)
|
||||
// cert, err := DecodeCert(certPEM.Bytes())
|
||||
// if err != nil {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
log.Trace(cert.Subject.CommonName)
|
||||
// log.Trace(cert.Subject.CommonName)
|
||||
|
||||
if secret.Annotations["revokedAt"] == "" {
|
||||
indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", "V", cert.NotAfter.Format(indexTxtDateFormat), fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
} else if cert.NotAfter.Before(time.Now()) {
|
||||
indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", "E", cert.NotAfter.Format(indexTxtDateFormat), fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
} else {
|
||||
indexTxt += fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\n", "R", cert.NotAfter.Format(indexTxtDateFormat), secret.Annotations["revokedAt"], fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
}
|
||||
// if secret.Annotations["revokedAt"] == "" {
|
||||
// indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", "V", cert.NotAfter.Format(indexTxtDateFormat), fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
// } else if cert.NotAfter.Before(time.Now()) {
|
||||
// indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", "E", cert.NotAfter.Format(indexTxtDateFormat), fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
// } else {
|
||||
// indexTxt += fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\n", "R", cert.NotAfter.Format(indexTxtDateFormat), secret.Annotations["revokedAt"], fmt.Sprintf("%d", cert.SerialNumber), "unknown", "/CN="+secret.Labels["name"])
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{Name: secretIndexTxt}
|
||||
// secretMetaData := metav1.ObjectMeta{Name: secretIndexTxt}
|
||||
|
||||
secretData := map[string][]byte{"index.txt": []byte(indexTxt)}
|
||||
// secretData := map[string][]byte{"index.txt": []byte(indexTxt)}
|
||||
|
||||
if res, _ := openVPNPKI.secretCheckExists(secretIndexTxt); !res {
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
} else {
|
||||
err = openVPNPKI.secretUpdate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
}
|
||||
// if res, _ := openVPNPKI.secretCheckExists(secretIndexTxt); !res {
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
// } else {
|
||||
// err = openVPNPKI.secretUpdate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) updateIndexTxtOnDisk() (err error) {
|
||||
secret, err := openVPNPKI.secretGetByName(secretIndexTxt)
|
||||
indexTxt := secret.Data["index.txt"]
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/index.txt", *EasyrsaDirPath), indexTxt, 0600)
|
||||
err = fWriteRaw(fmt.Sprintf("%s/pki/index.txt", *EasyrsaDirPath), indexTxt, 0600)
|
||||
return
|
||||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) easyrsaGenCRL() (err error) {
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) easyrsaGenCRL() (err error) {
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
secrets, err := openVPNPKI.secretsGetByLabels("index.txt=,type=clientAuth")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// secrets, err := openVPNPKI.secretsGetByLabels("index.txt=,type=clientAuth")
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
var revoked []*RevokedCert
|
||||
// var revoked []*RevokedCert
|
||||
|
||||
for _, secret := range secrets.Items {
|
||||
if secret.Annotations["revokedAt"] != "" {
|
||||
revokedAt, err := time.Parse(indexTxtDateFormat, secret.Annotations["revokedAt"])
|
||||
if err != nil {
|
||||
log.Warning(err)
|
||||
}
|
||||
cert, err := DecodeCert(secret.Data[certFileName])
|
||||
revoked = append(revoked, &RevokedCert{RevokedTime: revokedAt, Cert: cert})
|
||||
}
|
||||
}
|
||||
// for _, secret := range secrets.Items {
|
||||
// if secret.Annotations["revokedAt"] != "" {
|
||||
// revokedAt, err := time.Parse(indexTxtDateFormat, secret.Annotations["revokedAt"])
|
||||
// if err != nil {
|
||||
// log.Warning(err)
|
||||
// }
|
||||
// cert, err := DecodeCert(secret.Data[certFileName])
|
||||
// revoked = append(revoked, &RevokedCert{RevokedTime: revokedAt, Cert: cert})
|
||||
// }
|
||||
// }
|
||||
|
||||
crl, err := GenCRL(revoked, openVPNPKI.CACert, openVPNPKI.CAPrivKeyRSA)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// crl, err := GenCRL(revoked, openVPNPKI.CACert, openVPNPKI.CAPrivKeyRSA)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{Name: secretCRL}
|
||||
// secretMetaData := metav1.ObjectMeta{Name: secretCRL}
|
||||
|
||||
secretData := map[string][]byte{
|
||||
"crl.pem": crl.Bytes(),
|
||||
}
|
||||
// secretData := map[string][]byte{
|
||||
// "crl.pem": crl.Bytes(),
|
||||
// }
|
||||
|
||||
//err = openVPNPKI.secretCreate(secretMetaData, secretData)
|
||||
// //err = openVPNPKI.secretCreate(secretMetaData, secretData)
|
||||
|
||||
if res, _ := openVPNPKI.secretCheckExists(secretCRL); !res {
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
} else {
|
||||
err = openVPNPKI.secretUpdate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
}
|
||||
// if res, _ := openVPNPKI.secretCheckExists(secretCRL); !res {
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
// } else {
|
||||
// err = openVPNPKI.secretUpdate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaBuildClient(commonName string) (err error) {
|
||||
// check certificate exists
|
||||
_, err = openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
if err == nil {
|
||||
return errors.New(fmt.Sprintf("certificate for user (%s) already exists", commonName))
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) EasyrsaBuildClient(commonName string) (err error) {
|
||||
// // check certificate exists
|
||||
// _, err = openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
// if err == nil {
|
||||
// return errors.New(fmt.Sprintf("certificate for user (%s) already exists", commonName))
|
||||
// }
|
||||
|
||||
clientPrivKeyPEM, err := GenPrivKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// clientPrivKeyPEM, err := GenPrivKey()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
clientPrivKeyRSA, err := DecodePrivKey(clientPrivKeyPEM.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// clientPrivKeyRSA, err := DecodePrivKey(clientPrivKeyPEM.Bytes())
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
clientCertPEM, _ := GenClientCert(clientPrivKeyRSA, openVPNPKI.CAPrivKeyRSA, openVPNPKI.CACert, commonName)
|
||||
clientCert, err := DecodeCert(clientCertPEM.Bytes())
|
||||
// clientCertPEM, _ := GenClientCert(clientPrivKeyRSA, openVPNPKI.CAPrivKeyRSA, openVPNPKI.CACert, commonName)
|
||||
// clientCert, err := DecodeCert(clientCertPEM.Bytes())
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf(secretClientTmpl, clientCert.SerialNumber),
|
||||
Labels: map[string]string{
|
||||
"index.txt": "",
|
||||
"type": "clientAuth",
|
||||
"name": commonName,
|
||||
"app.kubernetes.io/managed-by": "ovpn-admin",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"commonName": commonName,
|
||||
"notBefore": clientCert.NotBefore.Format(indexTxtDateFormat),
|
||||
"notAfter": clientCert.NotAfter.Format(indexTxtDateFormat),
|
||||
"revokedAt": "",
|
||||
"serialNumber": fmt.Sprintf("%d", clientCert.SerialNumber),
|
||||
},
|
||||
}
|
||||
// secretMetaData := metav1.ObjectMeta{
|
||||
// Name: fmt.Sprintf(secretClientTmpl, clientCert.SerialNumber),
|
||||
// Labels: map[string]string{
|
||||
// "index.txt": "",
|
||||
// "type": "clientAuth",
|
||||
// "name": commonName,
|
||||
// "app.kubernetes.io/managed-by": "ovpn-admin",
|
||||
// },
|
||||
// Annotations: map[string]string{
|
||||
// "commonName": commonName,
|
||||
// "notBefore": clientCert.NotBefore.Format(indexTxtDateFormat),
|
||||
// "notAfter": clientCert.NotAfter.Format(indexTxtDateFormat),
|
||||
// "revokedAt": "",
|
||||
// "serialNumber": fmt.Sprintf("%d", clientCert.SerialNumber),
|
||||
// },
|
||||
// }
|
||||
|
||||
secretData := map[string][]byte{
|
||||
certFileName: clientCertPEM.Bytes(),
|
||||
privKeyFileName: clientPrivKeyPEM.Bytes(),
|
||||
}
|
||||
// secretData := map[string][]byte{
|
||||
// certFileName: clientCertPEM.Bytes(),
|
||||
// privKeyFileName: clientPrivKeyPEM.Bytes(),
|
||||
// }
|
||||
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeTLS)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
// err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) easyrsaGetCACert() string {
|
||||
return openVPNPKI.CACertPEM.String()
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) easyrsaGetCACert() string {
|
||||
// return openVPNPKI.CACertPEM.String()
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaGetClientCert(commonName string) (cert, key string) {
|
||||
secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
|
@ -381,148 +323,148 @@ func (openVPNPKI *OpenVPNPKI) EasyrsaGetClientCert(commonName string) (cert, key
|
|||
return
|
||||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaRevoke(commonName string) (err error) {
|
||||
secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) EasyrsaRevoke(commonName string) (err error) {
|
||||
// secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
if secret.Annotations["revokedAt"] != "" {
|
||||
log.Warnf("user (%s) already revoked", commonName)
|
||||
return
|
||||
}
|
||||
// if secret.Annotations["revokedAt"] != "" {
|
||||
// log.Warnf("user (%s) already revoked", commonName)
|
||||
// return
|
||||
// }
|
||||
|
||||
secret.Annotations["revokedAt"] = time.Now().Format(indexTxtDateFormat)
|
||||
// secret.Annotations["revokedAt"] = time.Now().Format(indexTxtDateFormat)
|
||||
|
||||
_, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// _, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.easyrsaGenCRL()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// err = openVPNPKI.easyrsaGenCRL()
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateCRLOnDisk()
|
||||
// err = openVPNPKI.updateCRLOnDisk()
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaUnrevoke(commonName string) (err error) {
|
||||
secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// func (openVPNPKI *OpenVPNPKI) EasyrsaUnrevoke(commonName string) (err error) {
|
||||
// secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
secret.Annotations["revokedAt"] = ""
|
||||
// secret.Annotations["revokedAt"] = ""
|
||||
|
||||
_, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// _, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.easyrsaGenCRL()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// err = openVPNPKI.easyrsaGenCRL()
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateCRLOnDisk()
|
||||
// err = openVPNPKI.updateCRLOnDisk()
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaRotate(commonName string) (err error) {
|
||||
secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
secret.Annotations["commonName"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
secret.Labels["name"] = "REVOKED" + commonName
|
||||
secret.Labels["revokedForever"] = "true"
|
||||
// func (openVPNPKI *OpenVPNPKI) EasyrsaRotate(commonName string) (err error) {
|
||||
// secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
// uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
// secret.Annotations["commonName"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
// secret.Labels["name"] = "REVOKED" + commonName
|
||||
// secret.Labels["revokedForever"] = "true"
|
||||
|
||||
_, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// _, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.EasyrsaBuildClient(commonName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.EasyrsaBuildClient(commonName)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.easyrsaGenCRL()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// err = openVPNPKI.easyrsaGenCRL()
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateCRLOnDisk()
|
||||
return
|
||||
}
|
||||
func (openVPNPKI *OpenVPNPKI) EasyrsaDelete(commonName string) (err error) {
|
||||
secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
secret.Annotations["commonName"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
secret.Labels["name"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
secret.Labels["revokedForever"] = "true"
|
||||
// err = openVPNPKI.updateCRLOnDisk()
|
||||
// return
|
||||
// }
|
||||
// func (openVPNPKI *OpenVPNPKI) EasyrsaDelete(commonName string) (err error) {
|
||||
// secret, err := openVPNPKI.secretGetByLabels("name=" + commonName)
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
// uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
// secret.Annotations["commonName"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
// secret.Labels["name"] = "REVOKED-" + commonName + "-" + uniqHash
|
||||
// secret.Labels["revokedForever"] = "true"
|
||||
|
||||
_, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// _, err = openVPNPKI.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.indexTxtUpdate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.indexTxtUpdate()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.updateIndexTxtOnDisk()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
err = openVPNPKI.easyrsaGenCRL()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
// err = openVPNPKI.easyrsaGenCRL()
|
||||
// if err != nil {
|
||||
// log.Error(err)
|
||||
// }
|
||||
|
||||
err = openVPNPKI.updateCRLOnDisk()
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.updateCRLOnDisk()
|
||||
// return
|
||||
// }
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) secretGetClientCert(name string) (cert ClientCert, err error) {
|
||||
secret, err := openVPNPKI.secretGetByName(name)
|
||||
|
@ -546,12 +488,12 @@ func (openVPNPKI *OpenVPNPKI) secretGetClientCert(name string) (cert ClientCert,
|
|||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) updateFilesFromSecrets() (err error) {
|
||||
ca, err := openVPNPKI.secretGetClientCert(secretCA)
|
||||
ca, err := openVPNPKI.getExistCert(secretCA)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
server, err := openVPNPKI.secretGetClientCert(secretServer)
|
||||
server, err := openVPNPKI.getExistCert(secretServer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -568,27 +510,27 @@ func (openVPNPKI *OpenVPNPKI) updateFilesFromSecrets() (err error) {
|
|||
err = os.MkdirAll(fmt.Sprintf("%s/pki/private", *EasyrsaDirPath), 0755)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/ca.crt", *EasyrsaDirPath), ca.CertPEM.Bytes(), 0600)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/ca.crt", *EasyrsaDirPath), ca.CertPEM.Bytes(), 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/issued/server.crt", *EasyrsaDirPath), server.CertPEM.Bytes(), 0600)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/issued/server.crt", *EasyrsaDirPath), server.CertPEM.Bytes(), 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/private/server.key", *EasyrsaDirPath), server.PrivKeyPEM.Bytes(), 0600)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/private/server.key", *EasyrsaDirPath), server.PrivKeyPEM.Bytes(), 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/ta.key", *EasyrsaDirPath), takey, 0600)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/ta.key", *EasyrsaDirPath), takey, 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/dh.pem", *EasyrsaDirPath), dhparam, 0600)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/dh.pem", *EasyrsaDirPath), dhparam, 0600)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -600,45 +542,45 @@ func (openVPNPKI *OpenVPNPKI) updateFilesFromSecrets() (err error) {
|
|||
func (openVPNPKI *OpenVPNPKI) updateCRLOnDisk() (err error) {
|
||||
secret, err := openVPNPKI.secretGetByName(secretCRL)
|
||||
crl := secret.Data["crl.pem"]
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/pki/crl.pem", *EasyrsaDirPath), crl, 0644)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/pki/crl.pem", *EasyrsaDirPath), crl, 0644)
|
||||
if err != nil {
|
||||
log.Errorf("error write crl.pem:%s", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (openVPNPKI *OpenVPNPKI) secretGenTaKeyAndDHParam() (err error) {
|
||||
taKeyPath := "/tmp/ta.key"
|
||||
cmd := exec.Command("bash", "-c", fmt.Sprintf("/usr/sbin/openvpn --genkey --secret %s", taKeyPath))
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
log.Info(fmt.Sprintf("/usr/sbin/openvpn --genkey --secret %s: %s", taKeyPath, string(stdout)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
taKey, err := ioutil.ReadFile(taKeyPath)
|
||||
// func (openVPNPKI *OpenVPNPKI) secretGenTaKeyAndDHParam() (err error) {
|
||||
// taKeyPath := "/tmp/ta.key"
|
||||
// cmd := exec.Command("bash", "-c", fmt.Sprintf("/usr/sbin/openvpn --genkey --secret %s", taKeyPath))
|
||||
// stdout, err := cmd.CombinedOutput()
|
||||
// log.Info(fmt.Sprintf("/usr/sbin/openvpn --genkey --secret %s: %s", taKeyPath, string(stdout)))
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// taKey, err := os.ReadFile(taKeyPath)
|
||||
|
||||
dhparamPath := "/tmp/dh.pem"
|
||||
cmd = exec.Command("bash", "-c", fmt.Sprintf("openssl dhparam -out %s 2048", dhparamPath))
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dhparam, err := ioutil.ReadFile(dhparamPath)
|
||||
// dhparamPath := "/tmp/dh.pem"
|
||||
// cmd = exec.Command("bash", "-c", fmt.Sprintf("openssl dhparam -out %s 2048", dhparamPath))
|
||||
// _, err = cmd.CombinedOutput()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// dhparam, err := os.ReadFile(dhparamPath)
|
||||
|
||||
secretMetaData := metav1.ObjectMeta{Name: secretDHandTA}
|
||||
// secretMetaData := metav1.ObjectMeta{Name: secretDHandTA}
|
||||
|
||||
secretData := map[string][]byte{
|
||||
"ta.key": taKey,
|
||||
"dh.pem": dhparam,
|
||||
}
|
||||
// secretData := map[string][]byte{
|
||||
// "ta.key": taKey,
|
||||
// "dh.pem": dhparam,
|
||||
// }
|
||||
|
||||
err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// err = openVPNPKI.secretCreate(secretMetaData, secretData, v1.SecretTypeOpaque)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
// return
|
||||
// }
|
||||
|
||||
// ccd
|
||||
|
||||
|
@ -690,7 +632,7 @@ func (openVPNPKI *OpenVPNPKI) updateCcdOnDisk() error {
|
|||
for _, secret := range secrets.Items {
|
||||
ccd := secret.Data["ccd"]
|
||||
if len(ccd) > 0 {
|
||||
err = ioutil.WriteFile(fmt.Sprintf("%s/%s", *CcdDir, secret.Labels["name"]), ccd, 0644)
|
||||
err = os.WriteFile(fmt.Sprintf("%s/%s", *CcdDir, secret.Labels["name"]), ccd, 0644)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
ou "github.com/pashcovich/openvpn-user/src"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -152,7 +151,7 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
|||
conf.Key = fRead(*EasyrsaDirPath + "/pki/private/" + username + ".key")
|
||||
}
|
||||
|
||||
conf.PasswdAuth = *AuthByPassword
|
||||
conf.PasswdAuth = oAdmin.ExtraAuth
|
||||
|
||||
t := oAdmin.getTemplate("client.conf.tpl", "client-config", *clientConfigTemplatePath)
|
||||
|
||||
|
@ -280,7 +279,7 @@ func (oAdmin *OvpnAdmin) usersList() []OpenvpnClient {
|
|||
apochNow := time.Now().Unix()
|
||||
|
||||
for _, line := range IndexTxtParser(fRead(*IndexTxtPath)) {
|
||||
if line.Identity != "server" && !strings.Contains(line.Identity, "REVOKED") {
|
||||
if line.Identity != "server" && line.Identity != "ca" && !strings.Contains(line.Identity, "REVOKED") {
|
||||
totalCerts += 1
|
||||
ovpnClient := OpenvpnClient{Identity: line.Identity, ExpirationDate: parseDateToString(indexTxtDateLayout, line.ExpirationDate, stringDateFormat)}
|
||||
switch {
|
||||
|
@ -313,8 +312,12 @@ func (oAdmin *OvpnAdmin) usersList() []OpenvpnClient {
|
|||
connectedUniqUsers += 1
|
||||
}
|
||||
|
||||
if oAdmin.isSecondFactorConfigured(ovpnClient.Identity) {
|
||||
ovpnClient.SecondFactor = true
|
||||
if oAdmin.ExtraAuth{
|
||||
if oAdmin.isSecondFactorConfigured(ovpnClient.Identity) {
|
||||
ovpnClient.SecondFactor = "enabled"
|
||||
} else {
|
||||
ovpnClient.SecondFactor = "disabled"
|
||||
}
|
||||
}
|
||||
|
||||
users = append(users, ovpnClient)
|
||||
|
@ -354,40 +357,35 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (string, error) {
|
|||
return err.Error(), err
|
||||
}
|
||||
|
||||
if *AuthByPassword {
|
||||
if oAdmin.ExtraAuth {
|
||||
if err := validatePassword(password); err != nil {
|
||||
log.Debugf("userCreate: authByPassword(): %s", err.Error())
|
||||
return err.Error(), err
|
||||
}
|
||||
}
|
||||
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaBuildClient(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err.Error(), err
|
||||
}
|
||||
if *AuthByPassword {
|
||||
err := oAdmin.PKI.BuildKeyPairClient(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err.Error(), err
|
||||
}
|
||||
|
||||
if oAdmin.ExtraAuth {
|
||||
switch *StorageBackend {
|
||||
case "kubernetes.secrets":
|
||||
err = oAdmin.KubeClient.updatePasswordSecret(username, []byte(password))
|
||||
if err != nil {
|
||||
return err.Error(), err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
o := runBash(fmt.Sprintf("cd %s && easyrsa build-client-full %s nopass 1>/dev/null", *EasyrsaDirPath, username))
|
||||
log.Debug(o)
|
||||
if *AuthByPassword {
|
||||
case "filesystems":
|
||||
_, err := oAdmin.OUser.CreateUser(username, password)
|
||||
if err != nil {
|
||||
return err.Error(), err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Certificate for user %s issued", username)
|
||||
|
||||
//oAdmin.clients = oAdmin.usersList()
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
|
@ -405,13 +403,13 @@ func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (error, s
|
|||
log.Warningf("userChangePassword: %s", err.Error())
|
||||
return err, err.Error()
|
||||
}
|
||||
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
switch *StorageBackend {
|
||||
case "kubernetes.secrets":
|
||||
err := oAdmin.KubeClient.updatePasswordSecret(username, []byte(password))
|
||||
if err != nil {
|
||||
return err, err.Error()
|
||||
}
|
||||
} else {
|
||||
case "filesystem":
|
||||
msg, err := oAdmin.OUser.ChangeUserPassword(username, password)
|
||||
if err != nil {
|
||||
return err, msg
|
||||
|
@ -435,14 +433,21 @@ func (oAdmin *OvpnAdmin) isSecondFactorConfigured(username string) bool {
|
|||
}
|
||||
return sfe
|
||||
case "filesystem":
|
||||
sfe, err := oAdmin.OUser.IsSecondFactorEnabled(username)
|
||||
if err != nil {
|
||||
return false
|
||||
switch *AuthType {
|
||||
case "TOTP":
|
||||
sfe, err := oAdmin.OUser.IsSecondFactorEnabled(username)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return sfe
|
||||
case "PASSWORD":
|
||||
return true
|
||||
//TODO: check if password is exist in db
|
||||
}
|
||||
return sfe
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) getUserSecret(username string) (string, error) {
|
||||
|
@ -538,11 +543,11 @@ func (oAdmin *OvpnAdmin) registerUserAuthApp(username, totp string) error {
|
|||
|
||||
for i, u := range oAdmin.clients {
|
||||
if u.Identity == username {
|
||||
oAdmin.clients[i].SecondFactor = true
|
||||
oAdmin.clients[i].SecondFactor = "enabled"
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("2FA configured for user %s", username)
|
||||
log.Infof("TOTP configured for user %s", username)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("user \"%s\" not found", username)
|
||||
|
@ -567,7 +572,7 @@ func (oAdmin *OvpnAdmin) resetUserAuthApp(username string) error {
|
|||
|
||||
for i, u := range oAdmin.clients {
|
||||
if u.Identity == username {
|
||||
oAdmin.clients[i].SecondFactor = false
|
||||
oAdmin.clients[i].SecondFactor = "disabled"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -587,7 +592,12 @@ func (oAdmin *OvpnAdmin) checkAuth(username, token string) error {
|
|||
return authErr
|
||||
}
|
||||
} else {
|
||||
auth, authErr = oAdmin.OUser.AuthUser(username, "", token)
|
||||
switch *AuthType {
|
||||
case "TOTP":
|
||||
auth, authErr = oAdmin.OUser.AuthUser(username, "", token)
|
||||
case "PASSWORD":
|
||||
auth, authErr = oAdmin.OUser.AuthUser(username, token, "")
|
||||
}
|
||||
if authErr != nil {
|
||||
return authErr
|
||||
}
|
||||
|
@ -614,19 +624,13 @@ func (oAdmin *OvpnAdmin) getUserStatistic(username string) []ClientStatus {
|
|||
func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) {
|
||||
log.Infof("Revoke certificate for user %s", username)
|
||||
if checkUserExist(username) {
|
||||
// check certificate valid flag 'V'
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaRevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
} else {
|
||||
o := runBash(fmt.Sprintf("cd %s && echo yes | easyrsa revoke %s 1>/dev/null && easyrsa gen-crl 1>/dev/null", *EasyrsaDirPath, username))
|
||||
log.Debugln(o)
|
||||
err := oAdmin.PKI.CertificateRevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if *AuthByPassword {
|
||||
if oAdmin.OUser.CheckUserExistent(username) {
|
||||
if *StorageBackend == "filesystem" {
|
||||
if oAdmin.ExtraAuth && oAdmin.OUser.CheckUserExistent(username) {
|
||||
revokeMsg, revokeErr := oAdmin.OUser.RevokedUser(username)
|
||||
log.Debug(revokeMsg)
|
||||
log.Debug(revokeErr)
|
||||
|
@ -636,7 +640,6 @@ func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) {
|
|||
}
|
||||
}
|
||||
|
||||
crlFix()
|
||||
userConnected, userConnectedTo := isUserConnected(username, oAdmin.activeClients)
|
||||
log.Tracef("User %s connected: %t", username, userConnected)
|
||||
if userConnected {
|
||||
|
@ -655,67 +658,23 @@ func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) {
|
|||
|
||||
func (oAdmin *OvpnAdmin) userUnrevoke(username string) (error, string) {
|
||||
if checkUserExist(username) {
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaUnrevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
} else {
|
||||
// check certificate revoked flag 'R'
|
||||
usersFromIndexTxt := IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].DistinguishedName == "/CN="+username {
|
||||
if usersFromIndexTxt[i].Flag == "R" {
|
||||
|
||||
usersFromIndexTxt[i].Flag = "V"
|
||||
usersFromIndexTxt[i].RevocationDate = ""
|
||||
err := oAdmin.PKI.CertificateUnRevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
err := fMove(fmt.Sprintf("%s/pki/revoked/certs_by_serial/%s.crt", *EasyrsaDirPath, usersFromIndexTxt[i].SerialNumber), fmt.Sprintf("%s/pki/issued/%s.crt", *EasyrsaDirPath, username))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
err = fMove(fmt.Sprintf("%s/pki/revoked/certs_by_serial/%s.crt", *EasyrsaDirPath, usersFromIndexTxt[i].SerialNumber), fmt.Sprintf("%s/pki/certs_by_serial/%s.pem", *EasyrsaDirPath, usersFromIndexTxt[i].SerialNumber))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
err = fMove(fmt.Sprintf("%s/pki/revoked/private_by_serial/%s.key", *EasyrsaDirPath, usersFromIndexTxt[i].SerialNumber), fmt.Sprintf("%s/pki/private/%s.key", *EasyrsaDirPath, username))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
err = fMove(fmt.Sprintf("%s/pki/revoked/reqs_by_serial/%s.req", *EasyrsaDirPath, usersFromIndexTxt[i].SerialNumber), fmt.Sprintf("%s/pki/reqs/%s.req", *EasyrsaDirPath, username))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
err = fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
_ = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl 1>/dev/null", *EasyrsaDirPath))
|
||||
|
||||
if *AuthByPassword {
|
||||
if oAdmin.OUser.CheckUserExistent(username) {
|
||||
restoreMsg, restoreErr := oAdmin.OUser.RestoreUser(username)
|
||||
log.Debug(restoreMsg)
|
||||
log.Debug(restoreErr)
|
||||
if restoreErr != nil {
|
||||
return restoreErr, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crlFix()
|
||||
|
||||
break
|
||||
}
|
||||
if *StorageBackend == "filesystem" {
|
||||
if oAdmin.ExtraAuth && oAdmin.OUser.CheckUserExistent(username) {
|
||||
restoreMsg, restoreErr := oAdmin.OUser.RestoreUser(username)
|
||||
log.Debug(restoreMsg)
|
||||
log.Debug(restoreErr)
|
||||
if restoreErr != nil {
|
||||
return restoreErr, ""
|
||||
}
|
||||
}
|
||||
err := fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
crlFix()
|
||||
|
||||
oAdmin.clients = oAdmin.usersList()
|
||||
return nil, fmt.Sprintf("{\"msg\":\"User %s successfully unrevoked\"}", username)
|
||||
}
|
||||
|
@ -724,119 +683,46 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) (error, string) {
|
|||
|
||||
func (oAdmin *OvpnAdmin) userRotate(username, newPassword string) (error, string) {
|
||||
if checkUserExist(username) {
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaRotate(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
} else {
|
||||
|
||||
var oldUserIndex, newUserIndex int
|
||||
var oldUserSerial string
|
||||
|
||||
uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
|
||||
usersFromIndexTxt := IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].DistinguishedName == "/CN="+username {
|
||||
oldUserSerial = usersFromIndexTxt[i].SerialNumber
|
||||
usersFromIndexTxt[i].DistinguishedName = "/CN=REVOKED-" + username + "-" + uniqHash
|
||||
oldUserIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
err := fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if *AuthByPassword {
|
||||
if oAdmin.OUser.CheckUserExistent(username) {
|
||||
deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true)
|
||||
log.Debug(deleteMsg)
|
||||
log.Debug(deleteErr)
|
||||
if deleteErr != nil {
|
||||
return deleteErr, ""
|
||||
}
|
||||
log.Debug(deleteMsg)
|
||||
}
|
||||
}
|
||||
|
||||
userCreateMessage, userCreateError := oAdmin.userCreate(username, newPassword)
|
||||
if userCreateError != nil {
|
||||
usersFromIndexTxt = IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].SerialNumber == oldUserSerial {
|
||||
usersFromIndexTxt[i].DistinguishedName = "/CN=" + username
|
||||
break
|
||||
}
|
||||
}
|
||||
err = fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
return fmt.Errorf("error rotaing user due: %s", userCreateMessage), userCreateMessage
|
||||
}
|
||||
|
||||
usersFromIndexTxt = IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].DistinguishedName == "/CN="+username {
|
||||
newUserIndex = i
|
||||
}
|
||||
if usersFromIndexTxt[i].SerialNumber == oldUserSerial {
|
||||
oldUserIndex = i
|
||||
}
|
||||
}
|
||||
usersFromIndexTxt[oldUserIndex], usersFromIndexTxt[newUserIndex] = usersFromIndexTxt[newUserIndex], usersFromIndexTxt[oldUserIndex]
|
||||
|
||||
err = fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
_ = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl 1>/dev/null", *EasyrsaDirPath))
|
||||
err := oAdmin.PKI.CertificateRotate(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if *StorageBackend == "filesystem" {
|
||||
if oAdmin.ExtraAuth && oAdmin.OUser.CheckUserExistent(username) {
|
||||
deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true)
|
||||
log.Debug(deleteMsg)
|
||||
log.Debug(deleteErr)
|
||||
if deleteErr != nil {
|
||||
return deleteErr, ""
|
||||
}
|
||||
log.Debug(deleteMsg)
|
||||
}
|
||||
}
|
||||
crlFix()
|
||||
oAdmin.clients = oAdmin.usersList()
|
||||
return nil, fmt.Sprintf("{\"msg\":\"User %s successfully rotated\"}", username)
|
||||
}
|
||||
return fmt.Errorf("user \"%s\" not found", username), fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
||||
}
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) userDelete(username string) (error, string) {
|
||||
if checkUserExist(username) {
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaDelete(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
} else {
|
||||
uniqHash := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||
usersFromIndexTxt := IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].DistinguishedName == "/CN="+username {
|
||||
usersFromIndexTxt[i].DistinguishedName = "/CN=REVOKED-" + username + "-" + uniqHash
|
||||
break
|
||||
}
|
||||
}
|
||||
if *AuthByPassword {
|
||||
if oAdmin.OUser.CheckUserExistent(username) {
|
||||
deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true)
|
||||
log.Debug(deleteMsg)
|
||||
log.Debug(deleteErr)
|
||||
if deleteErr != nil {
|
||||
log.Debug(deleteErr)
|
||||
return deleteErr, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
err := fWrite(*IndexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
_ = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl 1>/dev/null ", *EasyrsaDirPath))
|
||||
err := oAdmin.PKI.CertificateDelAfterRevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if *StorageBackend == "filesystem" {
|
||||
if oAdmin.ExtraAuth && oAdmin.OUser.CheckUserExistent(username) {
|
||||
deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true)
|
||||
log.Debug(deleteMsg)
|
||||
log.Debug(deleteErr)
|
||||
if deleteErr != nil {
|
||||
return deleteErr, ""
|
||||
}
|
||||
log.Debug(deleteMsg)
|
||||
}
|
||||
}
|
||||
crlFix()
|
||||
oAdmin.clients = oAdmin.usersList()
|
||||
return nil, fmt.Sprintf("{\"msg\":\"User %s successfully deleted\"}", username)
|
||||
}
|
||||
|
@ -1095,3 +981,17 @@ func (oAdmin *OvpnAdmin) SyncWithMaster() {
|
|||
oAdmin.SyncDataFromMaster()
|
||||
}
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) IsTotpAuth() bool {
|
||||
if IsModuleEnabled("totpAuth", oAdmin.Modules) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (oAdmin *OvpnAdmin) IsPasswdAuth() bool {
|
||||
if IsModuleEnabled("passwdAuth", oAdmin.Modules) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -3,7 +3,12 @@ package backend
|
|||
import (
|
||||
"io/fs"
|
||||
"sync"
|
||||
|
||||
"bytes"
|
||||
"time"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"github.com/pashcovich/openvpn-user/src"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
@ -19,11 +24,13 @@ type OvpnAdmin struct {
|
|||
PromRegistry *prometheus.Registry
|
||||
OUser *src.OpenvpnUser
|
||||
KubeClient *OpenVPNPKI
|
||||
PKI *OpenVPNPKI
|
||||
MgmtInterfaces map[string]string
|
||||
Templates fs.FS
|
||||
Modules []string
|
||||
mgmtStatusTimeFormat string
|
||||
CreateUserMutex *sync.Mutex
|
||||
ExtraAuth bool
|
||||
}
|
||||
|
||||
type OpenvpnServer struct {
|
||||
|
@ -48,7 +55,7 @@ type OpenvpnClient struct {
|
|||
RevocationDate string `json:"RevocationDate"`
|
||||
ConnectionStatus string `json:"ConnectionStatus"`
|
||||
Connections int `json:"Connections"`
|
||||
SecondFactor bool `json:"SecondFactor"`
|
||||
SecondFactor string `json:"SecondFactor,omitempty"`
|
||||
}
|
||||
|
||||
type ccdRoute struct {
|
||||
|
@ -85,3 +92,32 @@ type ClientStatus struct {
|
|||
LastRefFormatted string
|
||||
ConnectedTo string
|
||||
}
|
||||
|
||||
type OpenVPNPKI struct {
|
||||
CAPrivKeyRSA *rsa.PrivateKey
|
||||
CAPrivKeyPEM *bytes.Buffer
|
||||
CACert *x509.Certificate
|
||||
CACertPEM *bytes.Buffer
|
||||
ServerPrivKeyRSA *rsa.PrivateKey
|
||||
ServerPrivKeyPEM *bytes.Buffer
|
||||
ServerCert *x509.Certificate
|
||||
ServerCertPEM *bytes.Buffer
|
||||
TaKey *bytes.Buffer
|
||||
DhParam *bytes.Buffer
|
||||
ClientCerts []ClientCert
|
||||
RevokedCerts []RevokedCert
|
||||
KubeClient *kubernetes.Clientset
|
||||
}
|
||||
|
||||
type ClientCert struct {
|
||||
PrivKeyRSA *rsa.PrivateKey
|
||||
PrivKeyPEM *bytes.Buffer
|
||||
Cert *x509.Certificate
|
||||
CertPEM *bytes.Buffer
|
||||
}
|
||||
|
||||
type RevokedCert struct {
|
||||
RevokedTime time.Time `json:"revokedTime"`
|
||||
CommonName string `json:"commonName"`
|
||||
Cert *x509.Certificate `json:"cert"`
|
||||
}
|
1089
backend/pki.go
Normal file
1089
backend/pki.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,12 +5,13 @@ import (
|
|||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
@ -208,7 +209,7 @@ func getOvpnServerHostsFromKubeApi() ([]OpenvpnServer, error) {
|
|||
|
||||
func getOvpnCaCertExpireDate() time.Time {
|
||||
caCertPath := *EasyrsaDirPath + "/pki/ca.crt"
|
||||
caCert, err := ioutil.ReadFile(caCertPath)
|
||||
caCert, err := os.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
log.Errorf("error read file %s: %s", caCertPath, err.Error())
|
||||
}
|
||||
|
@ -277,13 +278,27 @@ func fExist(path string) bool {
|
|||
}
|
||||
|
||||
func fRead(path string) string {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
content := fReadRaw(path)
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func fReadRaw(path string) []byte {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Warning(err)
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
return string(content)
|
||||
return content
|
||||
}
|
||||
|
||||
func fReadDir(path string) []fs.DirEntry {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
log.Warning(err)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
func fCreate(path string) error {
|
||||
|
@ -300,7 +315,15 @@ func fCreate(path string) error {
|
|||
}
|
||||
|
||||
func fWrite(path, content string) error {
|
||||
err := ioutil.WriteFile(path, []byte(content), 0644)
|
||||
err := fWriteRaw(path, []byte(content), 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fWriteRaw(path string, rawContent []byte, perm fs.FileMode) error {
|
||||
err := os.WriteFile(path, []byte(rawContent), perm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -394,7 +417,7 @@ func fDownload(path, url string, basicAuth bool) error {
|
|||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -555,3 +578,34 @@ func randStr(strSize int, randType string) string {
|
|||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func OpenDB(path string) *sql.DB {
|
||||
db, err := sql.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func IsModuleEnabled(desiredModule string, listModules []string) bool {
|
||||
for _, module := range listModules {
|
||||
if module == desiredModule {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetSerialNumberByUser(username string) string {
|
||||
var serialNumberInTxt string
|
||||
usersFromIndexTxt := IndexTxtParser(fRead(*IndexTxtPath))
|
||||
for i := range usersFromIndexTxt {
|
||||
if usersFromIndexTxt[i].DistinguishedName == "/CN="+username {
|
||||
if usersFromIndexTxt[i].Flag == "R" {
|
||||
serialNumberInTxt = usersFromIndexTxt[i].SerialNumber
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialNumberInTxt
|
||||
}
|
|
@ -31,7 +31,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -90,7 +90,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -149,7 +149,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -206,7 +206,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -263,7 +263,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -305,7 +305,7 @@
|
|||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "8.5.2",
|
||||
"pluginVersion": "8.5.13",
|
||||
"targets": [
|
||||
{
|
||||
"expr": "ovpn_clients_expired",
|
||||
|
@ -320,7 +320,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -381,7 +381,7 @@
|
|||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -469,7 +469,7 @@
|
|||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -557,7 +557,7 @@
|
|||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -647,7 +647,7 @@
|
|||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -733,7 +733,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"description": "value show last connection check time",
|
||||
"fieldConfig": {
|
||||
|
@ -794,7 +794,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"description": "value shows when connection was started",
|
||||
"fieldConfig": {
|
||||
|
@ -855,7 +855,7 @@
|
|||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "P0D6E4079E36703EB"
|
||||
"uid": "$ds_prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
|
@ -928,7 +928,26 @@
|
|||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"selected": false,
|
||||
"text": "default",
|
||||
"value": "default"
|
||||
},
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
"multi": false,
|
||||
"label": "Prometheus",
|
||||
"name": "ds_prometheus",
|
||||
"options": [],
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"type": "datasource"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-15m",
|
||||
|
@ -952,4 +971,4 @@
|
|||
"uid": "Z7qmFI0Gk",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
|
@ -9,7 +9,8 @@ services:
|
|||
environment:
|
||||
OVPN_SERVER_NET: ${OVPN_SERVER_NET}
|
||||
OVPN_SERVER_MASK: ${OVPN_SERVER_MASK}
|
||||
OVPN_PASSWD_AUTH: ${OVPN_PASSWD_AUTH}
|
||||
OVPN_LISTEN_BASE_URL: ${OVPN_LISTEN_BASE_URL}
|
||||
OVPN_AUTH: ${OVPN_AUTH}
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
ports:
|
||||
|
@ -26,12 +27,12 @@ services:
|
|||
environment:
|
||||
OVPN_NETWORK: ${OVPN_NETWORK}
|
||||
OVPN_CCD: ${OVPN_CCD}
|
||||
OVPN_CCD_PATH: ${OVPN_CCD_PATH
|
||||
OVPN_CCD_PATH: ${OVPN_CCD_PATH}
|
||||
EASYRSA_PATH: ${EASYRSA_PATH}
|
||||
OVPN_SERVER: ${OVPN_SERVER}
|
||||
OVPN_INDEX_PATH: ${OVPN_INDEX_PATH}
|
||||
OVPN_LISTEN_BASE_URL: ${OVPN_LISTEN_BASE_URL}
|
||||
OVPN_AUTH: ${OVPN_AUTH}
|
||||
OVPN_AUTH_TFA: ${OVPN_AUTH_TFA}
|
||||
OVPN_AUTH_DB_PATH: ${OVPN_AUTH_DB_PATH}
|
||||
LOG_LEVEL: ${LOG_LEVEL}
|
||||
network_mode: service:openvpn
|
||||
|
|
6696
frontend/package-lock.json
generated
6696
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -42,7 +42,7 @@
|
|||
"terser-webpack-plugin": "^5.3.0",
|
||||
"vue-loader": "^17.0.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "^4.7.2"
|
||||
}
|
||||
|
|
|
@ -160,6 +160,7 @@ new Vue({
|
|||
label: 'Download config',
|
||||
class: 'btn-info',
|
||||
showWhenStatus: 'Active',
|
||||
Require2FA: "true",
|
||||
showForServerRole: ['master', 'slave'],
|
||||
showForModule: ["core"],
|
||||
},
|
||||
|
@ -353,7 +354,7 @@ new Vue({
|
|||
|
||||
getUserTFAData: function(data) {
|
||||
let _this = this;
|
||||
if (!_this.secondfactor) {
|
||||
if (_this.secondfactor == 'disabled' ) {
|
||||
axios.request(axios_cfg('api/user/2fa/secret', data, 'form'))
|
||||
.then(function (response) {
|
||||
_this.u.secret = response.data;
|
||||
|
@ -374,15 +375,15 @@ new Vue({
|
|||
_this.u.modalActionStatus = 200;
|
||||
_this.u.modalRegister2faVisible = false;
|
||||
_this.getUserData();
|
||||
_this.secondfactor = true;
|
||||
_this.secondfactor = "enabled";
|
||||
_this.u.token = "";
|
||||
_this.u.secret = "";
|
||||
_this.$notify({title: '2FA application registered for user ' + username, type: 'success'});
|
||||
_this.$notify({title: 'TOTP application registered for user ' + username, type: 'success'});
|
||||
})
|
||||
.catch(function(error) {
|
||||
_this.u.modalActionStatus = error.response.status;
|
||||
_this.u.modalActionMessage = error.response.data.message;
|
||||
_this.$notify({title: 'Register 2FA application for user ' + username + ' failed!', type: 'error'});
|
||||
_this.$notify({title: 'Register TOTP application for user ' + username + ' failed!', type: 'error'});
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -396,15 +397,15 @@ new Vue({
|
|||
axios.request(axios_cfg('api/user/2fa/reset', data, 'form'))
|
||||
.then(function(response) {
|
||||
_this.u.modalActionStatus = 200;
|
||||
_this.secondfactor = false;
|
||||
_this.secondfactor = "disabled";
|
||||
_this.getUserTFAData(data);
|
||||
_this.getUserData();
|
||||
_this.$notify({title: '2FA application reset for user ' + username, type: 'success'});
|
||||
_this.$notify({title: 'TOTP application reset for user ' + username, type: 'success'});
|
||||
})
|
||||
.catch(function(error) {
|
||||
_this.u.modalActionStatus = error.response.status;
|
||||
_this.u.modalActionMessage = error.response.data.message;
|
||||
_this.$notify({title: 'Reset 2FA application for user ' + username + ' failed!', type: 'error'});
|
||||
_this.$notify({title: 'Reset TOTP application for user ' + username + ' failed!', type: 'error'});
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
@ -36,7 +36,10 @@
|
|||
@click.left.stop="rowActionFn"
|
||||
v-for="action in actions"
|
||||
v-bind:class="action.class"
|
||||
v-if="action.showWhenStatus == props.row.AccountStatus && action.showForServerRole.includes(serverRole) && action.showForModule.some(p=> modulesEnabled.includes(p))">
|
||||
v-if="action.showWhenStatus == props.row.AccountStatus &&
|
||||
( props.row.SecondFactor != 'disabled' || !(action.Require2FA) ) &&
|
||||
action.showForServerRole.includes(serverRole) &&
|
||||
action.showForModule.some(p=> modulesEnabled.includes(p))">
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</span>
|
||||
|
@ -51,7 +54,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="text" class="form-control el-square modal-el-margin" placeholder="Username [_a-zA-Z0-9\.-]" v-model="u.newUserName">
|
||||
<input type="password" class="form-control el-square modal-el-margin" minlength="6" autocomplete="off" placeholder="Password [_a-zA-Z0-9\.-]" v-model="u.newUserPassword" v-if="modulesEnabled.includes('passwdAuth')">
|
||||
<input type="password" class="form-control el-square modal-el-margin" minlength="6" autocomplete="off" placeholder="Password [_a-zA-Z0-9\.-]" v-model="u.newUserPassword" v-if="modulesEnabled.includes('passwdAuth')||modulesEnabled.includes('totpAuth')">
|
||||
</div>
|
||||
|
||||
<div class="modal-footer justify-content-center" v-if="u.modalActionMessage.length > 0">
|
||||
|
@ -232,10 +235,10 @@
|
|||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header justify-content-center">
|
||||
<h4>2FA</h4>
|
||||
<h4>2FA TOTP</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body justify-content-center" v-if="!secondfactor">
|
||||
<div class="modal-body justify-content-center" v-if="secondfactor == 'disabled' ">
|
||||
<div style="text-align: center">
|
||||
<vue-qr
|
||||
:text=u.twofaurl
|
||||
|
@ -262,8 +265,8 @@
|
|||
<input type="text" class="form-control el-square modal-el-margin" minlength="6" autocomplete="off" placeholder="Pin Code" v-model="u.token">
|
||||
</div>
|
||||
|
||||
<div class="modal-body justify-content-center" v-if="secondfactor">
|
||||
<h4>2FA already configured for user: <strong>{{ username }}</strong></h4>
|
||||
<div class="modal-body justify-content-center" v-if="secondfactor == 'enabled' ">
|
||||
<h4>2FA with TOTP already configured for user: <strong>{{ username }}</strong></h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer justify-content-center" v-if="u.modalActionMessage.length > 0">
|
||||
|
@ -273,8 +276,8 @@
|
|||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success el-square modal-el-margin" v-if="!secondfactor" v-on:click.stop="registerUser2faApp(username)">Register 2FA</button>
|
||||
<button type="button" class="btn btn-danger el-square modal-el-margin" v-if="secondfactor" v-on:click.stop="resetUser2faApp(username)">Reset 2FA</button>
|
||||
<button type="button" class="btn btn-success el-square modal-el-margin" v-if="secondfactor == 'disabled' " v-on:click.stop="registerUser2faApp(username)">Register 2FA TOTP</button>
|
||||
<button type="button" class="btn btn-danger el-square modal-el-margin" v-if="secondfactor == 'enabled' " v-on:click.stop="resetUser2faApp(username)">Reset 2FA TOTP</button>
|
||||
<button type="button" class="btn btn-primary el-square d-flex justify-content-sm-end modal-el-margin" v-on:click.stop="u.modalActionMessage='';u.modalRegister2faVisible=false;u.token=''">Close</button>
|
||||
</div>
|
||||
|
||||
|
|
10
go.mod
10
go.mod
|
@ -35,17 +35,17 @@ require (
|
|||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/term v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||
k8s.io/klog/v2 v2.40.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220114203427-a0453230fd26 // indirect
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect
|
||||
|
|
15
go.sum
15
go.sum
|
@ -404,8 +404,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -489,13 +490,15 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -505,8 +508,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -693,8 +697,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
92
main.go
92
main.go
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
|
@ -51,9 +50,16 @@ func main() {
|
|||
ovpnAdmin := new(backend.OvpnAdmin)
|
||||
ovpnAdmin.OUser = new(ou.OpenvpnUser)
|
||||
|
||||
ovpnAdmin.PKI = new(backend.OpenVPNPKI)
|
||||
err := ovpnAdmin.PKI.InitPKI()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if *backend.StorageBackend == "kubernetes.secrets" {
|
||||
// TODO: Check
|
||||
ovpnAdmin.KubeClient = new(backend.OpenVPNPKI)
|
||||
err := ovpnAdmin.KubeClient.Run()
|
||||
err := ovpnAdmin.KubeClient.KubeRun()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
@ -85,24 +91,17 @@ func main() {
|
|||
|
||||
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "core")
|
||||
|
||||
if *backend.AuthByPassword {
|
||||
db, err := sql.Open("sqlite3", *backend.AuthDatabase)
|
||||
if err != nil {
|
||||
kingpin.Fatalf(err.Error())
|
||||
}
|
||||
defer func(db *sql.DB) {
|
||||
err = db.Close()
|
||||
if err != nil {
|
||||
kingpin.Fatalf(err.Error())
|
||||
}
|
||||
}(db)
|
||||
ovpnAdmin.OUser.Database = db
|
||||
|
||||
switch *backend.AuthType {
|
||||
case "TOTP":
|
||||
ovpnAdmin.ExtraAuth = true
|
||||
ovpnAdmin.OUser.Database = backend.OpenDB(*backend.AuthDatabase)
|
||||
defer ovpnAdmin.OUser.Database.Close()
|
||||
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "totpAuth")
|
||||
case "PASSWORD":
|
||||
ovpnAdmin.ExtraAuth = true
|
||||
ovpnAdmin.OUser.Database = backend.OpenDB(*backend.AuthDatabase)
|
||||
defer ovpnAdmin.OUser.Database.Close()
|
||||
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "passwdAuth")
|
||||
|
||||
if *backend.AuthTFA {
|
||||
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "totpAuth")
|
||||
}
|
||||
}
|
||||
|
||||
if *backend.CcdEnabled {
|
||||
|
@ -134,46 +133,47 @@ func main() {
|
|||
|
||||
go ovpnAdmin.UpdateState()
|
||||
|
||||
http.Handle("/", static)
|
||||
http.HandleFunc("/api/server/settings", ovpnAdmin.ServerSettingsHandler)
|
||||
http.HandleFunc("/api/users/list", ovpnAdmin.UserListHandler)
|
||||
http.HandleFunc("/api/user/create", ovpnAdmin.UserCreateHandler)
|
||||
http.HandleFunc("/api/user/rotate", ovpnAdmin.UserRotateHandler)
|
||||
http.HandleFunc("/api/user/delete", ovpnAdmin.UserDeleteHandler)
|
||||
http.HandleFunc("/api/user/revoke", ovpnAdmin.UserRevokeHandler)
|
||||
http.HandleFunc("/api/user/unrevoke", ovpnAdmin.UserUnrevokeHandler)
|
||||
http.HandleFunc("/api/user/config/show", ovpnAdmin.UserShowConfigHandler)
|
||||
listenBaseUrl := *backend.ListenBaseUrl
|
||||
|
||||
http.HandleFunc("/api/user/disconnect", ovpnAdmin.UserDisconnectHandler)
|
||||
http.HandleFunc("/api/user/statistic", ovpnAdmin.UserStatisticHandler)
|
||||
http.Handle(listenBaseUrl, http.StripPrefix(strings.TrimRight(listenBaseUrl, "/"), static))
|
||||
http.HandleFunc(listenBaseUrl + "api/server/settings", ovpnAdmin.ServerSettingsHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/users/list", ovpnAdmin.UserListHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/create", ovpnAdmin.UserCreateHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/rotate", ovpnAdmin.UserRotateHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/delete", ovpnAdmin.UserDeleteHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/revoke", ovpnAdmin.UserRevokeHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/unrevoke", ovpnAdmin.UserUnrevokeHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/config/show", ovpnAdmin.UserShowConfigHandler)
|
||||
|
||||
http.HandleFunc(listenBaseUrl + "api/user/disconnect", ovpnAdmin.UserDisconnectHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/statistic", ovpnAdmin.UserStatisticHandler)
|
||||
|
||||
if *backend.CcdEnabled {
|
||||
http.HandleFunc("/api/user/ccd", ovpnAdmin.UserShowCcdHandler)
|
||||
http.HandleFunc("/api/user/ccd/apply", ovpnAdmin.UserApplyCcdHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/ccd", ovpnAdmin.UserShowCcdHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/ccd/apply", ovpnAdmin.UserApplyCcdHandler)
|
||||
}
|
||||
|
||||
if *backend.AuthByPassword {
|
||||
http.HandleFunc("/api/user/change-password", ovpnAdmin.UserChangePasswordHandler)
|
||||
http.HandleFunc("/api/auth/check", ovpnAdmin.AuthCheckHandler)
|
||||
|
||||
if *backend.AuthTFA {
|
||||
http.HandleFunc("/api/user/2fa/secret", ovpnAdmin.UserGetSecretHandler)
|
||||
http.HandleFunc("/api/user/2fa/register", ovpnAdmin.UserSetupTFAHandler)
|
||||
http.HandleFunc("/api/user/2fa/reset", ovpnAdmin.UserResetTFAHandler)
|
||||
if ovpnAdmin.ExtraAuth {
|
||||
http.HandleFunc(listenBaseUrl + "api/user/change-password", ovpnAdmin.UserChangePasswordHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/auth/check", ovpnAdmin.AuthCheckHandler)
|
||||
if *backend.AuthType == "TOTP" {
|
||||
http.HandleFunc(listenBaseUrl + "api/user/2fa/secret", ovpnAdmin.UserGetSecretHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/2fa/register", ovpnAdmin.UserSetupTFAHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/user/2fa/reset", ovpnAdmin.UserResetTFAHandler)
|
||||
}
|
||||
}
|
||||
|
||||
http.HandleFunc("/api/sync/last/try", ovpnAdmin.LastSyncTimeHandler)
|
||||
http.HandleFunc("/api/sync/last/successful", ovpnAdmin.LastSuccessfulSyncTimeHandler)
|
||||
http.HandleFunc(backend.DownloadCertsApiUrl, ovpnAdmin.DownloadCertsHandler)
|
||||
http.HandleFunc(backend.DownloadCcdApiUrl, ovpnAdmin.DownloadCcdHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/sync/last/try", ovpnAdmin.LastSyncTimeHandler)
|
||||
http.HandleFunc(listenBaseUrl + "api/sync/last/successful", ovpnAdmin.LastSuccessfulSyncTimeHandler)
|
||||
http.HandleFunc(listenBaseUrl + backend.DownloadCertsApiUrl, ovpnAdmin.DownloadCertsHandler)
|
||||
http.HandleFunc(listenBaseUrl + backend.DownloadCcdApiUrl, ovpnAdmin.DownloadCcdHandler)
|
||||
|
||||
http.Handle(*backend.MetricsPath, promhttp.HandlerFor(ovpnAdmin.PromRegistry, promhttp.HandlerOpts{}))
|
||||
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.HandleFunc(listenBaseUrl + "ping", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "pong")
|
||||
})
|
||||
|
||||
log.Printf("Bind: http://%s:%s", *backend.ListenHost, *backend.ListenPort)
|
||||
log.Printf("Bind: http://%s:%s%s", *backend.ListenHost, *backend.ListenPort, listenBaseUrl)
|
||||
log.Fatal(http.ListenAndServe(*backend.ListenHost+":"+*backend.ListenPort, nil))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
source /etc/openvpn/scripts/.env
|
||||
PATH=$PATH:/usr/local/bin
|
||||
set -e
|
||||
|
||||
|
@ -7,7 +7,7 @@ auth_usr=$(head -1 $1)
|
|||
auth_secret=$(tail -1 $1)
|
||||
|
||||
if [ $common_name = $auth_usr ]; then
|
||||
curl -s --fail --data-raw 'username='${auth_usr} --data-raw 'secret='${auth_secret} localhost:8080/api/auth/check
|
||||
curl -s --fail --data-raw 'username='${auth_usr} --data-raw 'token='${auth_secret} localhost:8080${OVPN_LISTEN_BASE_URL}api/auth/check
|
||||
else
|
||||
echo "$(date) Authorization for user $common_name failed"
|
||||
exit 1
|
||||
|
|
|
@ -19,17 +19,8 @@ else
|
|||
do
|
||||
sleep 5
|
||||
done
|
||||
else
|
||||
echo "Generating new certs"
|
||||
easyrsa init-pki
|
||||
cp -R /usr/share/easy-rsa/* $EASY_RSA_LOC/pki
|
||||
echo "ca" | easyrsa build-ca nopass
|
||||
easyrsa build-server-full server nopass
|
||||
easyrsa gen-dh
|
||||
openvpn --genkey --secret ./pki/ta.key
|
||||
fi
|
||||
fi
|
||||
easyrsa gen-crl
|
||||
|
||||
iptables -t nat -D POSTROUTING -s ${OVPN_SRV_NET}/${OVPN_SRV_MASK} ! -d ${OVPN_SRV_NET}/${OVPN_SRV_MASK} -j MASQUERADE || true
|
||||
iptables -t nat -A POSTROUTING -s ${OVPN_SRV_NET}/${OVPN_SRV_MASK} ! -d ${OVPN_SRV_NET}/${OVPN_SRV_MASK} -j MASQUERADE
|
||||
|
@ -41,8 +32,9 @@ fi
|
|||
|
||||
cp -f /etc/openvpn/setup/openvpn.conf /etc/openvpn/openvpn.conf
|
||||
|
||||
if [ ${OVPN_PASSWD_AUTH} = "true" ]; then
|
||||
if [ ${OVPN_AUTH} == "TOTP" ] || [ ${OVPN_AUTH} == "PASSWORD" ]; then
|
||||
mkdir -p /etc/openvpn/scripts/
|
||||
echo OVPN_LISTEN_BASE_URL=${OVPN_LISTEN_BASE_URL} > /etc/openvpn/scripts/.env
|
||||
cp -f /etc/openvpn/setup/auth.sh /etc/openvpn/scripts/auth.sh
|
||||
chmod +x /etc/openvpn/scripts/auth.sh
|
||||
echo "auth-user-pass-verify /etc/openvpn/scripts/auth.sh via-file" | tee -a /etc/openvpn/openvpn.conf
|
||||
|
|
Loading…
Reference in a new issue