mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
refactor: move IPsec certificate handling to network host
This commit is contained in:
@@ -1668,7 +1668,7 @@ func runAdminInit(cmd *cobra.Command, args []string) {
|
||||
if ipsecEnabled {
|
||||
caCertPath := filepath.Join(configDir, "ca.pem")
|
||||
caKeyPath := filepath.Join(configDir, "ca.key")
|
||||
if err := admin.GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, node, bindIP); err != nil {
|
||||
if err := host.GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, node, bindIP); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error generating IPsec peer certificate: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -2655,7 +2655,7 @@ func runAdminJoin(cmd *cobra.Command, args []string) {
|
||||
if ipsecEnabled {
|
||||
caCertPath := filepath.Join(configDir, "ca.pem")
|
||||
caKeyPath := filepath.Join(configDir, "ca.key")
|
||||
if err := admin.GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, node, bindIP); err != nil {
|
||||
if err := host.GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, node, bindIP); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error generating IPsec peer certificate: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -1297,7 +1297,7 @@ fi
|
||||
# explicitly given. Reasons to pin:
|
||||
# 1. IPsec identity: ovs-monitor-ipsec uses chassis-id as the IKEv2
|
||||
# `@<name>` peer identity. Our per-node IPsec peer cert
|
||||
# (admin.GenerateIPSecPeerCert) carries the cluster node name as CN
|
||||
# (host.GenerateIPSecPeerCert) carries the cluster node name as CN
|
||||
# + dnsName SAN — see spx admin init/join, which take --node NAME and
|
||||
# bake NAME into the cert. Leaving chassis-id as the package-generated
|
||||
# UUID would cause `received AUTHENTICATION_FAILED` because charon
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package admin
|
||||
package host
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
@@ -29,6 +29,10 @@ const (
|
||||
ipsecCACertSymlink = "ca.pem"
|
||||
)
|
||||
|
||||
// ipsecCertKeyBits is the RSA key size for IPsec peer certificates. It is a
|
||||
// seam so tests can lower it for faster key generation.
|
||||
var ipsecCertKeyBits = 4096
|
||||
|
||||
// id-kp-ipsecIKE per RFC 4945 §5.1.3.12. strongSwan accepts certs carrying
|
||||
// this EKU as IKEv2 peer credentials; ovs-monitor-ipsec's auto-generated
|
||||
// strongSwan config consumes them as-is.
|
||||
@@ -61,7 +65,7 @@ func GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, hostname, nodeIP st
|
||||
return err
|
||||
}
|
||||
|
||||
peerKey, err := rsa.GenerateKey(rand.Reader, certKeyBits)
|
||||
peerKey, err := rsa.GenerateKey(rand.Reader, ipsecCertKeyBits)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ipsec peer cert: generate key: %w", err)
|
||||
}
|
||||
@@ -1,19 +1,49 @@
|
||||
package admin
|
||||
package host
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestGenerateIPSecPeerCert shares a CA across subtests so the 4096-bit
|
||||
// CA-key generation runs once (~0.7s).
|
||||
func init() { ipsecCertKeyBits = 2048 }
|
||||
|
||||
// writeTestCA writes a throwaway self-signed RSA CA in the PEM/PKCS8 form the
|
||||
// IPsec issuer loads.
|
||||
func writeTestCA(t *testing.T, certPath, keyPath string) {
|
||||
t.Helper()
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err)
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "test CA"},
|
||||
NotBefore: time.Now().Add(-time.Hour),
|
||||
NotAfter: time.Now().Add(24 * time.Hour),
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
|
||||
require.NoError(t, err)
|
||||
keyDER, err := x509.MarshalPKCS8PrivateKey(key)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, os.WriteFile(certPath, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}), 0o644))
|
||||
require.NoError(t, os.WriteFile(keyPath, pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyDER}), 0o600))
|
||||
}
|
||||
|
||||
// TestGenerateIPSecPeerCert shares a CA across subtests so the CA-key
|
||||
// generation runs once.
|
||||
//
|
||||
//nolint:tparallel // the parent cannot be parallel: it overrides the charonCATrustDir/charonRereadCAs package vars for the duration of the test
|
||||
func TestGenerateIPSecPeerCert(t *testing.T) {
|
||||
@@ -33,7 +63,7 @@ func TestGenerateIPSecPeerCert(t *testing.T) {
|
||||
caDir := t.TempDir()
|
||||
caCertPath := filepath.Join(caDir, "ca.pem")
|
||||
caKeyPath := filepath.Join(caDir, "ca.key")
|
||||
require.NoError(t, GenerateCACert(caCertPath, caKeyPath))
|
||||
writeTestCA(t, caCertPath, caKeyPath)
|
||||
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mulgadc/spinifex/spinifex/admin"
|
||||
"github.com/mulgadc/spinifex/spinifex/bootstrap/config"
|
||||
"github.com/mulgadc/spinifex/spinifex/foundation/telemetry"
|
||||
hostcommand "github.com/mulgadc/spinifex/spinifex/runtime/host/command"
|
||||
@@ -274,7 +273,7 @@ func EnableOVNIPSec(ctx context.Context, configPath string, clusterConfig *confi
|
||||
// turn on encapsulation, once ovs-monitor-ipsec is up to act on both.
|
||||
func configureLocalIPSec(configPath string) error {
|
||||
configDir := filepath.Dir(configPath)
|
||||
certPath, keyPath := admin.IPSecCertPaths(configDir)
|
||||
certPath, keyPath := IPSecCertPaths(configDir)
|
||||
caCertPath := filepath.Join(configDir, "ca.pem")
|
||||
|
||||
for _, p := range []string{certPath, keyPath, caCertPath} {
|
||||
|
||||
Reference in New Issue
Block a user