feat: encrypt with tls 1.3 (#522)

This commit is contained in:
naison
2025-04-12 12:30:05 +08:00
committed by GitHub
parent 7e4e9e1e0d
commit ca333fcdaf
20 changed files with 391 additions and 66 deletions

View File

@@ -31,6 +31,8 @@ const (
TLSCertKey = "tls_crt"
// TLSPrivateKeyKey is the key for the private key field in a TLS secret.
TLSPrivateKeyKey = "tls_key"
// TLSServerName for tls config server name
TLSServerName = "tls_server_name"
// container name
ContainerSidecarEnvoyProxy = "envoy-proxy"
@@ -170,10 +172,47 @@ var (
)
var (
// network layer ip needs 20 bytes
// transport layer UDP header needs 8 bytes
// UDP over TCP header needs 22 bytes
DefaultMTU = 1500 - 20 - 8 - 21
// DefaultMTU
/**
+--------------------------------------------------------------------+
| Original IP Packet from TUN |
+-------------------+------------------------------------------------+
| IP Header (20B) | Payload (MTU size) |
+-------------------+------------------------------------------------+
After adding custom 2-byte header:
+----+-------------------+-------------------------------------------+
| LH | IP Header (20B) | Payload |
+----+-------------------+-------------------------------------------+
| 2B | 20B | 1453 - 20 = 1433B |
+----+-------------------+-------------------------------------------+
TLS 1.3 Record Structure Breakdown:
+---------------------+--------------------------+-------------------+
| TLS Header (5B) | Encrypted Data (N) | Auth Tag (16B) |
+---------------------+--------------------------+-------------------+
| Content Type (1) | ↑ | AEAD Authentication
| Version (2) | Encrypted Payload | (e.g. AES-GCM) |
| Length (2) | (Original Data + LH2) | |
+---------------------+--------------------------+-------------------+
|←------- 5B --------→|←---- Length Field ------→|←----- 16B -------→|
Final Ethernet Frame:
+--------+----------------+----------------+-----------------------+--------+
| EthHdr | IP Header | TCP Header | TLS Components |
| (14B) | (20B) | (20B) +---------+-------------+--------+
| | | | Hdr(5B) | Data+LH2 | Tag(16)|
+--------+----------------+----------------+---------+-------------+--------+
|←------------------- Total 1500B Ethernet Frame --------------------------→|
ipv4: 20
ipv6: 40
mtu: 1417
*/
DefaultMTU = 1500 - max(20, 40) - 20 - 5 - 2 - 16
)
var (

View File

@@ -70,7 +70,7 @@ func (c *Forwarder) getConn(ctx context.Context) (net.Conn, error) {
if c.IsEmpty() {
return nil, ErrorEmptyForwarder
}
return c.Node().Client.Dial(ctx, c.resolve(c.Node().Addr))
return c.Node().Client.Dial(ctx, c.Node().Addr)
}
type Handler interface {

View File

@@ -2,6 +2,8 @@ package core
import (
"context"
"crypto/tls"
"errors"
"net"
"sync"
@@ -65,9 +67,19 @@ func GvisorTCPListener(addr string) (net.Listener, error) {
if err != nil {
return nil, err
}
ln, err := net.ListenTCP("tcp", laddr)
listener, err := net.ListenTCP("tcp", laddr)
if err != nil {
return nil, err
}
return &tcpKeepAliveListener{TCPListener: ln}, nil
serverConfig, err := util.GetTlsServerConfig(nil)
if err != nil {
if errors.Is(err, util.ErrNoTLSConfig) {
plog.G(context.Background()).Warn("tls config not found in config, use raw tcp mode")
return &tcpKeepAliveListener{TCPListener: listener}, nil
}
plog.G(context.Background()).Errorf("failed to get tls server config: %v", err)
_ = listener.Close()
return nil, err
}
return tls.NewListener(&tcpKeepAliveListener{TCPListener: listener}, serverConfig), nil
}

View File

@@ -42,7 +42,7 @@ func (r *Route) ParseForwarder() (*Forwarder, error) {
}
forwarder.Client = &Client{
Connector: NewUDPOverTCPConnector(),
Transporter: TCPTransporter(),
Transporter: TCPTransporter(nil),
}
return NewForwarder(r.Retries, forwarder), nil
}

View File

@@ -2,20 +2,44 @@ package core
import (
"context"
"crypto/tls"
"errors"
"net"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
"github.com/wencaiwulue/kubevpn/v2/pkg/util"
)
type tcpTransporter struct{}
type tcpTransporter struct {
tlsConfig *tls.Config
}
func TCPTransporter() Transporter {
return &tcpTransporter{}
func TCPTransporter(tlsInfo map[string][]byte) Transporter {
tlsConfig, err := util.GetTlsClientConfig(tlsInfo)
if err != nil {
if errors.Is(err, util.ErrNoTLSConfig) {
plog.G(context.Background()).Warn("tls config not found in config, use raw tcp mode")
return &tcpTransporter{}
}
plog.G(context.Background()).Errorf("failed to get tls client config: %v", err)
return &tcpTransporter{}
}
return &tcpTransporter{tlsConfig: tlsConfig}
}
func (tr *tcpTransporter) Dial(ctx context.Context, addr string) (net.Conn, error) {
dialer := &net.Dialer{Timeout: config.DialTimeout}
return dialer.DialContext(ctx, "tcp", addr)
conn, err := dialer.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
if tr.tlsConfig == nil {
plog.G(ctx).Debugf("tls config not found in config, use raw tcp mode")
return conn, nil
}
plog.G(ctx).Debugf("use tls mode")
return tls.Client(conn, tr.tlsConfig), nil
}
func TCPListener(addr string) (net.Listener, error) {
@@ -23,11 +47,20 @@ func TCPListener(addr string) (net.Listener, error) {
if err != nil {
return nil, err
}
ln, err := net.ListenTCP("tcp", laddr)
listener, err := net.ListenTCP("tcp", laddr)
if err != nil {
return nil, err
}
return &tcpKeepAliveListener{TCPListener: ln}, nil
serverConfig, err := util.GetTlsServerConfig(nil)
if err != nil {
if errors.Is(err, util.ErrNoTLSConfig) {
plog.G(context.Background()).Warn("tls config not found in config, use raw tcp mode")
return &tcpKeepAliveListener{TCPListener: listener}, nil
}
plog.G(context.Background()).Errorf("failed to get tls server config: %v", err)
return nil, err
}
return tls.NewListener(&tcpKeepAliveListener{TCPListener: listener}, serverConfig), nil
}
type tcpKeepAliveListener struct {

View File

@@ -21,6 +21,7 @@ import (
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/metadata"
admissionv1 "k8s.io/api/admissionregistration/v1"
v1 "k8s.io/api/core/v1"
apinetworkingv1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -155,6 +156,11 @@ func (c *ConnectOptions) CreateRemoteInboundPod(ctx context.Context, namespace s
c.proxyWorkloads = make(ProxyList, 0)
}
tlsSecret, err := c.clientset.CoreV1().Secrets(c.Namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if err != nil {
return err
}
for _, workload := range workloads {
plog.G(ctx).Infof("Injecting inbound sidecar for %s in namespace %s", workload, namespace)
configInfo := util.PodRouteConfig{
@@ -175,11 +181,11 @@ func (c *ConnectOptions) CreateRemoteInboundPod(ctx context.Context, namespace s
// https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/
// means mesh mode
if c.Engine == config.EngineGvisor {
err = inject.InjectEnvoySidecar(ctx, c.factory, c.clientset, c.Namespace, object, headers, portMap)
err = inject.InjectEnvoySidecar(ctx, c.factory, c.clientset, c.Namespace, object, headers, portMap, tlsSecret)
} else if len(headers) != 0 || len(portMap) != 0 {
err = inject.InjectVPNAndEnvoySidecar(ctx, c.factory, c.clientset.CoreV1().ConfigMaps(c.Namespace), c.Namespace, object, configInfo, headers, portMap)
err = inject.InjectVPNAndEnvoySidecar(ctx, c.factory, c.clientset.CoreV1().ConfigMaps(c.Namespace), c.Namespace, object, configInfo, headers, portMap, tlsSecret)
} else {
err = inject.InjectVPNSidecar(ctx, c.factory, c.Namespace, object, configInfo)
err = inject.InjectVPNSidecar(ctx, c.factory, c.Namespace, object, configInfo, tlsSecret)
}
if err != nil {
plog.G(ctx).Errorf("Injecting inbound sidecar for %s in namespace %s failed: %s", workload, namespace, err.Error())
@@ -370,6 +376,11 @@ func (c *ConnectOptions) portForward(ctx context.Context, portPair []string) err
func (c *ConnectOptions) startLocalTunServer(ctx context.Context, forwardAddress string, lite bool) (err error) {
plog.G(ctx).Debugf("IPv4: %s, IPv6: %s", c.localTunIPv4.IP.String(), c.localTunIPv6.IP.String())
tlsSecret, err := c.clientset.CoreV1().Secrets(c.Namespace).Get(ctx, config.ConfigMapPodTrafficManager, metav1.GetOptions{})
if err != nil {
return err
}
var cidrList []*net.IPNet
if !lite {
cidrList = append(cidrList, config.CIDR, config.CIDR6)
@@ -423,7 +434,7 @@ func (c *ConnectOptions) startLocalTunServer(ctx context.Context, forwardAddress
}
forward.Client = &core.Client{
Connector: core.NewUDPOverTCPConnector(),
Transporter: core.TCPTransporter(),
Transporter: core.TCPTransporter(tlsSecret.Data),
}
forwarder := core.NewForwarder(5, forward)
@@ -957,8 +968,14 @@ func (c *ConnectOptions) upgradeDeploy(ctx context.Context) error {
return err
}
plog.G(ctx).Infof("Set image %s --> %s...", serverImg, clientImg)
// 1) update secret
err = upgradeSecretSpec(ctx, c.factory, c.Namespace)
if err != nil {
return err
}
// 2) update deploy
plog.G(ctx).Infof("Set image %s --> %s...", serverImg, clientImg)
err = upgradeDeploySpec(ctx, c.factory, c.Namespace, deploy.Name, c.Engine == config.EngineGvisor)
if err != nil {
return err
@@ -1051,6 +1068,49 @@ func upgradeDeploySpec(ctx context.Context, f cmdutil.Factory, ns, name string,
return nil
}
func upgradeSecretSpec(ctx context.Context, f cmdutil.Factory, ns string) error {
crt, key, host, err := util.GenTLSCert(ctx, ns)
if err != nil {
return err
}
secret := genSecret(ns, crt, key, host)
clientset, err := f.KubernetesClientSet()
if err != nil {
return err
}
currentSecret, err := clientset.CoreV1().Secrets(ns).Get(ctx, secret.Name, metav1.GetOptions{})
if err != nil {
return err
}
// already have three keys
if currentSecret.Data[config.TLSServerName] != nil &&
currentSecret.Data[config.TLSPrivateKeyKey] != nil &&
currentSecret.Data[config.TLSCertKey] != nil {
return nil
}
_, err = clientset.CoreV1().Secrets(ns).Update(ctx, secret, metav1.UpdateOptions{})
if err != nil {
return err
}
mutatingWebhookConfig := genMutatingWebhookConfiguration(ns, crt)
var current *admissionv1.MutatingWebhookConfiguration
current, err = clientset.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(ctx, mutatingWebhookConfig.Name, metav1.GetOptions{})
if err != nil {
return err
}
mutatingWebhookConfig.ResourceVersion = current.ResourceVersion
_, err = clientset.AdmissionregistrationV1().MutatingWebhookConfigurations().Update(ctx, mutatingWebhookConfig, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}
func restartDeploy(ctx context.Context, f cmdutil.Factory, clientset *kubernetes.Clientset, ns, name string) error {
label := fields.OneTermEqualSelector("app", config.ConfigMapPodTrafficManager).String()
list, err := util.GetRunningPodList(ctx, clientset, ns, label)

View File

@@ -18,7 +18,6 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/util/cert"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/util/podutils"
"k8s.io/utils/pointer"
@@ -114,17 +113,14 @@ func createOutboundPod(ctx context.Context, clientset *kubernetes.Clientset, nam
return err
}
domain := util.GetTlsDomain(namespace)
var crt, key []byte
crt, key, err = cert.GenerateSelfSignedCertKey(domain, nil, nil)
crt, key, host, err := util.GenTLSCert(ctx, namespace)
if err != nil {
plog.G(ctx).Errorf("Generate self signed cert and key error: %s", err.Error())
return err
}
// reason why not use v1.SecretTypeTls is because it needs key called tls.crt and tls.key, but tls.key can not as env variable
// ➜ ~ export tls.key=a
//export: not valid in this context: tls.key
secret := genSecret(namespace, crt, key)
secret := genSecret(namespace, crt, key, host)
_, err = clientset.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{})
if err != nil {
plog.G(ctx).Errorf("Creating secret error: %s", err.Error())
@@ -282,7 +278,7 @@ func genService(namespace string, udp8422 string, tcp10800 string, tcp9002 strin
}
}
func genSecret(namespace string, crt []byte, key []byte) *v1.Secret {
func genSecret(namespace string, crt []byte, key []byte, host []byte) *v1.Secret {
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: config.ConfigMapPodTrafficManager,
@@ -291,6 +287,7 @@ func genSecret(namespace string, crt []byte, key []byte) *v1.Secret {
Data: map[string][]byte{
config.TLSCertKey: crt,
config.TLSPrivateKeyKey: key,
config.TLSServerName: host,
},
Type: v1.SecretTypeOpaque,
}

View File

@@ -38,7 +38,7 @@ func RemoveContainers(spec *v1.PodTemplateSpec) {
}
// AddMeshContainer todo envoy support ipv6
func AddMeshContainer(spec *v1.PodTemplateSpec, ns, nodeId string, c util.PodRouteConfig, ipv6 bool, connectNamespace string) {
func AddMeshContainer(spec *v1.PodTemplateSpec, ns, nodeId string, c util.PodRouteConfig, ipv6 bool, connectNamespace string, secret *v1.Secret) {
// remove envoy proxy containers if already exist
RemoveContainers(spec)
@@ -98,6 +98,18 @@ kubevpn server -l "tun:/localhost:8422?net=${TunIPv4}&net6=${TunIPv6}&route=${CI
},
},
},
{
Name: config.TLSServerName,
Value: string(secret.Data[config.TLSServerName]),
},
{
Name: config.TLSCertKey,
Value: string(secret.Data[config.TLSCertKey]),
},
{
Name: config.TLSPrivateKeyKey,
Value: string(secret.Data[config.TLSPrivateKeyKey]),
},
},
Resources: v1.ResourceRequirements{
Requests: map[v1.ResourceName]resource.Quantity{
@@ -159,7 +171,7 @@ kubevpn server -l "tun:/localhost:8422?net=${TunIPv4}&net6=${TunIPv6}&route=${CI
})
}
func AddEnvoyContainer(spec *v1.PodTemplateSpec, ns, nodeId string, ipv6 bool, connectNamespace string) {
func AddEnvoyContainer(spec *v1.PodTemplateSpec, ns, nodeId string, ipv6 bool, connectNamespace string, secret *v1.Secret) {
// remove envoy proxy containers if already exist
RemoveContainers(spec)

View File

@@ -20,7 +20,7 @@ func RemoveContainer(spec *corev1.PodSpec) {
}
}
func AddContainer(spec *corev1.PodSpec, c util.PodRouteConfig, connectNamespace string) {
func AddContainer(spec *corev1.PodSpec, c util.PodRouteConfig, connectNamespace string, secret *corev1.Secret) {
// remove vpn container if already exist
RemoveContainer(spec)
spec.Containers = append(spec.Containers, corev1.Container{
@@ -71,6 +71,18 @@ func AddContainer(spec *corev1.PodSpec, c util.PodRouteConfig, connectNamespace
},
},
},
{
Name: config.TLSServerName,
Value: string(secret.Data[config.TLSServerName]),
},
{
Name: config.TLSCertKey,
Value: string(secret.Data[config.TLSCertKey]),
},
{
Name: config.TLSPrivateKeyKey,
Value: string(secret.Data[config.TLSPrivateKeyKey]),
},
},
Command: []string{"/bin/sh", "-c"},
// https://www.netfilter.org/documentation/HOWTO/NAT-HOWTO-6.html#ss6.2

View File

@@ -28,7 +28,7 @@ import (
// InjectEnvoySidecar patch a sidecar, using iptables to do port-forward let this pod decide should go to 233.254.254.100 or request to 127.0.0.1
// https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio
func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kubernetes.Clientset, connectNamespace string, object *runtimeresource.Info, headers map[string]string, portMap []string) (err error) {
func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kubernetes.Clientset, connectNamespace string, object *runtimeresource.Info, headers map[string]string, portMap []string, secret *v1.Secret) (err error) {
u := object.Object.(*unstructured.Unstructured)
var templateSpec *v1.PodTemplateSpec
var path []string
@@ -66,7 +66,7 @@ func InjectEnvoySidecar(ctx context.Context, f cmdutil.Factory, clientset *kuber
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, connectNamespace)
// (1) add mesh container
AddEnvoyContainer(templateSpec, object.Namespace, nodeID, enableIPv6, connectNamespace)
AddEnvoyContainer(templateSpec, object.Namespace, nodeID, enableIPv6, connectNamespace, secret)
helper := pkgresource.NewHelper(object.Client, object.Mapping)
ps := []P{
{

View File

@@ -31,7 +31,7 @@ import (
// https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio
// InjectVPNAndEnvoySidecar patch a sidecar, using iptables to do port-forward let this pod decide should go to 233.254.254.100 or request to 127.0.0.1
func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, mapInterface v12.ConfigMapInterface, connectNamespace string, object *runtimeresource.Info, c util.PodRouteConfig, headers map[string]string, portMaps []string) (err error) {
func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, mapInterface v12.ConfigMapInterface, connectNamespace string, object *runtimeresource.Info, c util.PodRouteConfig, headers map[string]string, portMaps []string, secret *v1.Secret) (err error) {
u := object.Object.(*unstructured.Unstructured)
var templateSpec *v1.PodTemplateSpec
var path []string
@@ -90,7 +90,7 @@ func InjectVPNAndEnvoySidecar(ctx context.Context, f cmdutil.Factory, mapInterfa
enableIPv6, _ := util.DetectPodSupportIPv6(ctx, f, connectNamespace)
// (1) add mesh container
AddMeshContainer(templateSpec, object.Namespace, nodeID, c, enableIPv6, connectNamespace)
AddMeshContainer(templateSpec, object.Namespace, nodeID, c, enableIPv6, connectNamespace, secret)
helper := pkgresource.NewHelper(object.Client, object.Mapping)
ps := []P{
{

View File

@@ -24,7 +24,7 @@ import (
util2 "github.com/wencaiwulue/kubevpn/v2/pkg/util"
)
func InjectVPNSidecar(ctx context.Context, f util.Factory, connectNamespace string, object *resource.Info, c util2.PodRouteConfig) error {
func InjectVPNSidecar(ctx context.Context, f util.Factory, connectNamespace string, object *resource.Info, c util2.PodRouteConfig, secret *v1.Secret) error {
u := object.Object.(*unstructured.Unstructured)
podTempSpec, path, err := util2.GetPodTemplateSpecPath(u)
@@ -51,7 +51,7 @@ func InjectVPNSidecar(ctx context.Context, f util.Factory, connectNamespace stri
return err
}
AddContainer(&podTempSpec.Spec, c, connectNamespace)
AddContainer(&podTempSpec.Spec, c, connectNamespace, secret)
workload := fmt.Sprintf("%s/%s", object.Mapping.Resource.Resource, object.Name)
helper := resource.NewHelper(object.Client, object.Mapping)

112
pkg/util/tls.go Normal file
View File

@@ -0,0 +1,112 @@
package util
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net"
"os"
"strings"
"k8s.io/client-go/util/cert"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
"github.com/wencaiwulue/kubevpn/v2/pkg/log"
)
func GetTlsClientConfig(tlsSecret map[string][]byte) (*tls.Config, error) {
crtBytes, keyBytes, serverName, err := getTls(tlsSecret)
if err != nil {
return nil, err
}
pair, err := tls.X509KeyPair(crtBytes, keyBytes)
if err != nil {
return nil, err
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(crtBytes)
client := &tls.Config{
RootCAs: certPool,
Certificates: []tls.Certificate{pair},
ServerName: string(serverName),
MinVersion: tls.VersionTLS13,
MaxVersion: tls.VersionTLS13,
}
return client, nil
}
func GetTlsServerConfig(tlsInfo map[string][]byte) (*tls.Config, error) {
crtBytes, keyBytes, serverName, err := getTls(tlsInfo)
if err != nil {
return nil, err
}
pair, err := tls.X509KeyPair(crtBytes, keyBytes)
if err != nil {
return nil, err
}
client := &tls.Config{
Certificates: []tls.Certificate{pair},
ServerName: string(serverName),
MinVersion: tls.VersionTLS13,
MaxVersion: tls.VersionTLS13,
}
return client, nil
}
var ErrNoTLSConfig = errors.New("no TLS configuration found")
func getTls(tlsSecret map[string][]byte) (crtBytes []byte, keyBytes []byte, serverName []byte, err error) {
if tlsSecret != nil {
crtBytes = tlsSecret[config.TLSCertKey]
keyBytes = tlsSecret[config.TLSPrivateKeyKey]
serverName = tlsSecret[config.TLSServerName]
return
}
if os.Getenv(config.TLSCertKey) == "" ||
os.Getenv(config.TLSPrivateKeyKey) == "" ||
os.Getenv(config.TLSServerName) == "" {
return nil, nil, nil, ErrNoTLSConfig
}
crtBytes = []byte(os.Getenv(config.TLSCertKey))
keyBytes = []byte(os.Getenv(config.TLSPrivateKeyKey))
serverName = []byte(os.Getenv(config.TLSServerName))
return
}
func GetTLSHost(ns string) string {
return fmt.Sprintf("%s.%s", config.ConfigMapPodTrafficManager, ns)
}
func GenTLSCert(ctx context.Context, ns string) ([]byte, []byte, []byte, error) {
host := GetTLSHost(ns)
alternateIPs := []net.IP{net.IPv4(127, 0, 0, 1)}
alternateDNS := []string{"localhost"}
// for Mutatingwebhookconfigurations will use domain: kubevpn-traffic-manager.xxx.svc
alternateDNS = append(alternateDNS, fmt.Sprintf("%s.svc", host))
crt, key, err := cert.GenerateSelfSignedCertKeyWithFixtures(host, alternateIPs, alternateDNS, ".")
if err != nil {
log.G(ctx).Errorf("Generate self signed cert and key error: %s", err.Error())
return nil, nil, nil, err
}
// ref --start vendor/k8s.io/client-go/util/cert/cert.go:113
baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-"))
_ = os.Remove(baseName + ".crt")
_ = os.Remove(baseName + ".key")
// ref --end
return crt, key, []byte(host), nil
}
func ipsToStrings(ips []net.IP) []string {
ss := make([]string, 0, len(ips))
for _, ip := range ips {
ss = append(ss, ip.String())
}
return ss
}

68
pkg/util/tls_test.go Normal file
View File

@@ -0,0 +1,68 @@
package util
import (
"context"
"crypto/tls"
"io"
"net"
"testing"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
)
func TestTLS(t *testing.T) {
ns := "kubevpn"
crtBytes, keyBytes, alternateDNS, err := GenTLSCert(context.Background(), GetTLSHost(ns))
if err != nil {
t.Fatal(err)
}
t.Setenv(config.TLSCertKey, string(crtBytes))
t.Setenv(config.TLSPrivateKeyKey, string(keyBytes))
t.Setenv(config.TLSServerName, string(alternateDNS))
listen, err := net.Listen("tcp", ":9090")
if err != nil {
t.Fatal(err)
}
tlsServerConfig, err := GetTlsServerConfig(nil)
if err != nil {
t.Fatal(err)
}
listener := tls.NewListener(listen, tlsServerConfig)
go func() {
for {
conn, err := listener.Accept()
if err != nil {
t.Error(err)
return
}
go func(conn net.Conn) {
bytes := make([]byte, 1024)
all, err2 := conn.Read(bytes)
if err2 != nil {
t.Error(err2)
return
}
defer conn.Close()
t.Log(string(bytes[:all]))
io.WriteString(conn, "hello client")
}(conn)
}
}()
dial, err := net.Dial("tcp", ":9090")
if err != nil {
t.Fatal(err)
}
clientConfig, err := GetTlsClientConfig(nil)
if err != nil {
t.Fatal(err)
}
client := tls.Client(dial, clientConfig)
client.Write([]byte("hi server"))
all, err := io.ReadAll(client)
if err != nil {
t.Fatal(err)
}
t.Log(string(all))
}

View File

@@ -33,7 +33,6 @@ import (
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
"github.com/wencaiwulue/kubevpn/v2/pkg/driver"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
)
@@ -235,10 +234,6 @@ func CanI(clientset *kubernetes.Clientset, sa, ns string, resource *rbacv1.Polic
return false, nil
}
func GetTlsDomain(ns string) string {
return config.ConfigMapPodTrafficManager + "." + ns + "." + "svc"
}
func RemoveLargerOverlappingCIDRs(cidrNets []*net.IPNet) []*net.IPNet {
sort.Slice(cidrNets, func(i, j int) bool {
onesI, _ := cidrNets[i].Mask.Size()

View File

@@ -21,6 +21,7 @@ import (
"github.com/wencaiwulue/kubevpn/v2/pkg/dhcp"
"github.com/wencaiwulue/kubevpn/v2/pkg/dhcp/rpc"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
putil "github.com/wencaiwulue/kubevpn/v2/pkg/util"
)
func Main(f util.Factory) error {
@@ -38,10 +39,9 @@ func Main(f util.Factory) error {
_, _ = w.Write([]byte("ok"))
})
var pairs []tls.Certificate
pairs, err = getSSLKeyPairs()
tlsConfig, err := putil.GetTlsServerConfig(nil)
if err != nil {
return err
return fmt.Errorf("failed to load tls certificate: %v", err)
}
grpcServer := grpc.NewServer()
@@ -58,7 +58,7 @@ func Main(f util.Factory) error {
// With downgrading-capable gRPC server, which can also handle HTTP.
downgradingServer := &http.Server{
Addr: fmt.Sprintf(":%d", 80),
TLSConfig: &tls.Config{Certificates: pairs},
TLSConfig: &tls.Config{Certificates: tlsConfig.Certificates},
}
defer downgradingServer.Close()
var h2Server http2.Server
@@ -73,20 +73,3 @@ func Main(f util.Factory) error {
rpc.RegisterDHCPServer(grpcServer, dhcp.NewServer(clientset))
return downgradingServer.ListenAndServeTLS("", "")
}
func getSSLKeyPairs() ([]tls.Certificate, error) {
cert, ok := os.LookupEnv(config.TLSCertKey)
if !ok {
return nil, fmt.Errorf("can not get %s from env", config.TLSCertKey)
}
var key string
key, ok = os.LookupEnv(config.TLSPrivateKeyKey)
if !ok {
return nil, fmt.Errorf("can not get %s from env", config.TLSPrivateKeyKey)
}
pair, err := tls.X509KeyPair([]byte(cert), []byte(key))
if err != nil {
return nil, fmt.Errorf("failed to load certificate and key ,err: %v", err)
}
return []tls.Certificate{pair}, nil
}