feat: implement optional mTLS and helper scripts
Signed-off-by: HeshamTB <hishaminv@gmail.com>
This commit is contained in:
parent
1f3eca1b1b
commit
da0b1c720e
7
cmd/hvpn-node/.gitignore
vendored
7
cmd/hvpn-node/.gitignore
vendored
@ -1,2 +1,7 @@
|
|||||||
hvpn-node
|
hvpn-node
|
||||||
|
tmp/
|
||||||
|
.air.toml
|
||||||
|
client_cert.pem
|
||||||
|
client_cert.key
|
||||||
|
cert.key
|
||||||
|
cert.pem
|
||||||
|
@ -2,6 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@ -32,6 +34,8 @@ var WgPort int
|
|||||||
var wgLink *hvpnnode3.WGLink
|
var wgLink *hvpnnode3.WGLink
|
||||||
|
|
||||||
var httpPort int
|
var httpPort int
|
||||||
|
var TLS_ENABLED bool
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
@ -76,10 +80,17 @@ func run(ctx *cli.Context) {
|
|||||||
IdleTimeout: 120 * time.Second,
|
IdleTimeout: 120 * time.Second,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
Addr: hostPort,
|
Addr: hostPort,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
defer wgLink.Close()
|
defer wgLink.Close()
|
||||||
|
if TLS_ENABLED {
|
||||||
|
slog.Debug("Running with TLS")
|
||||||
|
slog.Info("Running TLS or mTLS with a reverse proxy is recommended")
|
||||||
|
slog.Warn(srv.ListenAndServeTLS(ctx.Path("cert"), ctx.Path("cert-private-key")).Error())
|
||||||
|
} else {
|
||||||
slog.Warn(srv.ListenAndServe().Error())
|
slog.Warn(srv.ListenAndServe().Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCliApp() *cli.App {
|
func createCliApp() *cli.App {
|
||||||
@ -175,6 +186,48 @@ func createCliApp() *cli.App {
|
|||||||
app.Flags = append(app.Flags, &httpPort)
|
app.Flags = append(app.Flags, &httpPort)
|
||||||
|
|
||||||
|
|
||||||
|
/* TLS Flags */
|
||||||
|
|
||||||
|
TLS := cli.BoolFlag{
|
||||||
|
Name: "enable-tls",
|
||||||
|
Aliases: []string{ "tls" },
|
||||||
|
Value: false,
|
||||||
|
Category: "\rTLS:",
|
||||||
|
Destination: &TLS_ENABLED,
|
||||||
|
Action: func(ctx *cli.Context, b bool) error {
|
||||||
|
tlsConf, err := setupTLS(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tlsConfig = tlsConf
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Flags = append(app.Flags, &TLS)
|
||||||
|
|
||||||
|
mTLSClientCerts := cli.PathFlag{
|
||||||
|
Name: "client-certs",
|
||||||
|
Aliases: []string{"ca"},
|
||||||
|
Usage: "A path to PEM file with client certificates; Enables TLS",
|
||||||
|
Category: "\rTLS:",
|
||||||
|
}
|
||||||
|
app.Flags = append(app.Flags, &mTLSClientCerts)
|
||||||
|
|
||||||
|
TLSCert := cli.PathFlag{
|
||||||
|
Name: "cert",
|
||||||
|
Usage: "Server x509 certificate file",
|
||||||
|
Category: "\rTLS:",
|
||||||
|
}
|
||||||
|
app.Flags = append(app.Flags, &TLSCert)
|
||||||
|
|
||||||
|
TLSCertKey := cli.PathFlag{
|
||||||
|
Name: "cert-private-key",
|
||||||
|
Usage: "Server x509 certificate private key file",
|
||||||
|
Category: "\rTLS:",
|
||||||
|
}
|
||||||
|
app.Flags = append(app.Flags, &TLSCertKey)
|
||||||
|
|
||||||
|
|
||||||
app.Action = func(ctx *cli.Context) error {
|
app.Action = func(ctx *cli.Context) error {
|
||||||
err := setup(ctx)
|
err := setup(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -367,3 +420,46 @@ func handleStdin(c chan struct{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createMTLS(clinetCert, serverCert, serverKey string) (*x509.CertPool, error) {
|
||||||
|
clientCert, err := os.ReadFile(clinetCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
ok := certPool.AppendCertsFromPEM(clientCert)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("mTLS: Could read and parase a single cert from client cert")
|
||||||
|
}
|
||||||
|
return certPool, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTLS(ctx *cli.Context) (*tls.Config, error) {
|
||||||
|
ca := ctx.Path("client-certs")
|
||||||
|
if ca == "" {
|
||||||
|
return nil, errors.New("client-certs flag is not set to enable TLS")
|
||||||
|
}
|
||||||
|
|
||||||
|
serverCert := ctx.Path("ca")
|
||||||
|
if serverCert == "" {
|
||||||
|
return nil, errors.New("cert flag is not set to enable TLS")
|
||||||
|
}
|
||||||
|
|
||||||
|
serverKey := ctx.Path("cert-private-key")
|
||||||
|
if serverKey == "" {
|
||||||
|
return nil, errors.New("cert-private-key is not set to enable TLS")
|
||||||
|
}
|
||||||
|
|
||||||
|
certPool, err := createMTLS(ca, serverCert, serverKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := tls.Config{
|
||||||
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||||
|
ClientCAs: certPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
28
cmd/hvpn-node/init-certs.sh
Executable file
28
cmd/hvpn-node/init-certs.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
openssl req \
|
||||||
|
-x509 \
|
||||||
|
-new \
|
||||||
|
-noenc \
|
||||||
|
-sha256 \
|
||||||
|
-newkey rsa:4096 \
|
||||||
|
-outform PEM \
|
||||||
|
-keyout client_cert.key \
|
||||||
|
-out client_cert.pem \
|
||||||
|
-days 3600 \
|
||||||
|
-new \
|
||||||
|
-subj "/C=US/ST=Ohio/L=Columbus/O=HVPN/OU=HVPN Client"
|
||||||
|
|
||||||
|
openssl req \
|
||||||
|
-x509 \
|
||||||
|
-new \
|
||||||
|
-noenc \
|
||||||
|
-sha256 \
|
||||||
|
-newkey rsa:4096 \
|
||||||
|
-outform PEM \
|
||||||
|
-keyout cert.key \
|
||||||
|
-out cert.pem \
|
||||||
|
-days 3600 \
|
||||||
|
-new \
|
||||||
|
-subj "/C=US/ST=Ohio/L=Columbus/O=HVPN/OU=HVPN Server"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user