mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
fix(ipsec): symlink cluster CA into charon's default cacerts dir
ovs-monitor-ipsec writes per-conn `cacert=/etc/spinifex/ca.pem` references in the strongSwan config, but strongSwan 6.0 only loads CAs declared in standalone `ca` sections or files placed in /etc/ipsec.d/cacerts at startup. Without this, charon authenticates the local side fine but rejects every inbound peer cert as `no trusted RSA public key found for '<peer>'`, AUTH_FAILED, and no xfrm SAs negotiate. Do the symlink in admin.GenerateIPSecPeerCert (right after writing the peer cert) — setup-ovn.sh runs before `spx admin init/join` creates /etc/spinifex/ca.pem, so the wiring can't live there. Use a stage-and- rename pattern so concurrent test invocations don't race on the symlink. /etc/ipsec.d/cacerts is on charon's default AppArmor allowlist so no profile change needed. Refs: mulga-siv-136
This commit is contained in:
@@ -136,6 +136,44 @@ func GenerateIPSecPeerCert(configDir, caCertPath, caKeyPath, hostname, nodeIP st
|
||||
return fmt.Errorf("ipsec peer cert: write key: %w", err)
|
||||
}
|
||||
|
||||
// Symlink the cluster CA into charon's default cacerts scan dir.
|
||||
// ovs-monitor-ipsec writes per-conn `cacert=` references, but
|
||||
// strongSwan 6.0 only loads CAs declared in standalone `ca` sections
|
||||
// or files placed in /etc/ipsec.d/cacerts at startup. Without this,
|
||||
// charon authenticates the local side OK but rejects every inbound
|
||||
// peer cert as `no trusted RSA public key found for '<peer>'` and
|
||||
// no SAs negotiate. The dir is on charon's default AppArmor allowlist
|
||||
// so no profile change is needed (unlike /etc/spinifex/).
|
||||
if err := installCAIntoCharonTrustStore(caCertPath); err != nil {
|
||||
return fmt.Errorf("ipsec peer cert: install CA into charon trust store: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// charonCATrustDir is the strongSwan default cacerts scan dir. Overridden
|
||||
// in tests so they don't pollute the real /etc/ipsec.d/cacerts.
|
||||
var charonCATrustDir = "/etc/ipsec.d/cacerts"
|
||||
|
||||
const charonCATrustLink = "spinifex-ca.pem"
|
||||
|
||||
func installCAIntoCharonTrustStore(caCertPath string) error {
|
||||
if err := os.MkdirAll(charonCATrustDir, 0750); err != nil {
|
||||
return fmt.Errorf("mkdir %s: %w", charonCATrustDir, err)
|
||||
}
|
||||
link := filepath.Join(charonCATrustDir, charonCATrustLink)
|
||||
tmp, err := os.MkdirTemp(charonCATrustDir, ".cainstall-")
|
||||
if err != nil {
|
||||
return fmt.Errorf("tmpdir: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
staging := filepath.Join(tmp, charonCATrustLink)
|
||||
if err := os.Symlink(caCertPath, staging); err != nil {
|
||||
return fmt.Errorf("symlink %s -> %s: %w", staging, caCertPath, err)
|
||||
}
|
||||
if err := os.Rename(staging, link); err != nil {
|
||||
return fmt.Errorf("rename %s -> %s: %w", staging, link, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,12 @@ import (
|
||||
// TestGenerateIPSecPeerCert shares a CA across subtests so the 4096-bit
|
||||
// CA-key generation runs once (~0.7s).
|
||||
func TestGenerateIPSecPeerCert(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Redirect the charon trust-store symlink at a temp dir so the test
|
||||
// doesn't try to write to /etc/ipsec.d/cacerts on the host. Restored
|
||||
// in cleanup. Cannot use t.Parallel() with this var override.
|
||||
origTrustDir := charonCATrustDir
|
||||
charonCATrustDir = t.TempDir()
|
||||
t.Cleanup(func() { charonCATrustDir = origTrustDir })
|
||||
|
||||
caDir := t.TempDir()
|
||||
caCertPath := filepath.Join(caDir, "ca.pem")
|
||||
@@ -110,7 +115,9 @@ func TestGenerateIPSecPeerCert(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateIPSecPeerCertIfEnabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
origTrustDir := charonCATrustDir
|
||||
charonCATrustDir = t.TempDir()
|
||||
t.Cleanup(func() { charonCATrustDir = origTrustDir })
|
||||
|
||||
caDir := t.TempDir()
|
||||
caCertPath := filepath.Join(caDir, "ca.pem")
|
||||
|
||||
Reference in New Issue
Block a user