include internal pki
This commit is contained in:
parent
f7c5a66992
commit
6d96f1f927
7 changed files with 1589 additions and 604 deletions
|
@ -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"
|
||||
)
|
|
@ -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"
|
||||
)
|
||||
|
@ -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 {
|
||||
|
@ -365,33 +364,28 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if *StorageBackend == "kubernetes.secrets" {
|
||||
err := oAdmin.KubeClient.EasyrsaBuildClient(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err.Error(), err
|
||||
}
|
||||
if oAdmin.ExtraAuth {
|
||||
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 && %s build-client-full %s nopass 1>/dev/null", *EasyrsaDirPath, *EasyrsaBinPath, username))
|
||||
log.Debug(o)
|
||||
if oAdmin.ExtraAuth {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -409,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
|
||||
|
@ -630,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 %[1]s && echo yes | %[2]s revoke %[3]s 1>/dev/null && %[2]s gen-crl 1>/dev/null", *EasyrsaDirPath, *EasyrsaBinPath, username))
|
||||
log.Debugln(o)
|
||||
err := oAdmin.PKI.CertificateRevoke(username)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if oAdmin.ExtraAuth {
|
||||
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)
|
||||
|
@ -652,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 {
|
||||
|
@ -671,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 && %s gen-crl 1>/dev/null", *EasyrsaDirPath, *EasyrsaBinPath))
|
||||
|
||||
if oAdmin.ExtraAuth {
|
||||
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)
|
||||
}
|
||||
|
@ -740,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 oAdmin.ExtraAuth {
|
||||
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 && %s gen-crl 1>/dev/null", *EasyrsaDirPath, *EasyrsaBinPath))
|
||||
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 oAdmin.ExtraAuth {
|
||||
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 && %s gen-crl 1>/dev/null ", *EasyrsaDirPath, *EasyrsaBinPath))
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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,12 +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
|
||||
ExtraAuth bool
|
||||
}
|
||||
|
||||
type OpenvpnServer struct {
|
||||
|
@ -86,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"`
|
||||
}
|
1083
backend/pki.go
Normal file
1083
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"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -209,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())
|
||||
}
|
||||
|
@ -278,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 {
|
||||
|
@ -301,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)
|
||||
}
|
||||
|
@ -395,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
|
||||
}
|
||||
|
@ -572,4 +594,18 @@ func IsModuleEnabled(desiredModule string, listModules []string) bool {
|
|||
}
|
||||
}
|
||||
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
|
||||
}
|
9
main.go
9
main.go
|
@ -50,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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue