Rename wild-cloud → wild-central for all managed config files and nftables table
Completes the naming separation: nftables table, rules file, dnsmasq config, resolved config, systemd unit, sudoers rule, and temp files now all use the wild-central name.
This commit is contained in:
44
dist/debian/DEBIAN/postinst
vendored
44
dist/debian/DEBIAN/postinst
vendored
@@ -28,16 +28,16 @@ case "$1" in
|
||||
chgrp wildcloud /etc/dnsmasq.d
|
||||
chmod 775 /etc/dnsmasq.d
|
||||
|
||||
# Create or fix ownership of wild-cloud.conf
|
||||
if [ ! -f /etc/dnsmasq.d/wild-cloud.conf ]; then
|
||||
touch /etc/dnsmasq.d/wild-cloud.conf
|
||||
echo "Created /etc/dnsmasq.d/wild-cloud.conf"
|
||||
# Create or fix ownership of wild-central.conf
|
||||
if [ ! -f /etc/dnsmasq.d/wild-central.conf ]; then
|
||||
touch /etc/dnsmasq.d/wild-central.conf
|
||||
echo "Created /etc/dnsmasq.d/wild-central.conf"
|
||||
else
|
||||
echo "Found existing /etc/dnsmasq.d/wild-cloud.conf - updating ownership"
|
||||
echo "Found existing /etc/dnsmasq.d/wild-central.conf - updating ownership"
|
||||
fi
|
||||
|
||||
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-cloud.conf
|
||||
chmod 644 /etc/dnsmasq.d/wild-cloud.conf
|
||||
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-central.conf
|
||||
chmod 644 /etc/dnsmasq.d/wild-central.conf
|
||||
|
||||
# Set ownership and permissions for instance configs directory
|
||||
chown wildcloud:wildcloud /etc/dnsmasq.d/wild-cloud-instances
|
||||
@@ -47,14 +47,14 @@ case "$1" in
|
||||
# Set up systemd-resolved configuration directory and file
|
||||
mkdir -p /etc/systemd/resolved.conf.d
|
||||
|
||||
if [ ! -f /etc/systemd/resolved.conf.d/wild-cloud.conf ]; then
|
||||
touch /etc/systemd/resolved.conf.d/wild-cloud.conf
|
||||
echo "Created /etc/systemd/resolved.conf.d/wild-cloud.conf"
|
||||
if [ ! -f /etc/systemd/resolved.conf.d/wild-central.conf ]; then
|
||||
touch /etc/systemd/resolved.conf.d/wild-central.conf
|
||||
echo "Created /etc/systemd/resolved.conf.d/wild-central.conf"
|
||||
else
|
||||
echo "Found existing /etc/systemd/resolved.conf.d/wild-cloud.conf"
|
||||
echo "Found existing /etc/systemd/resolved.conf.d/wild-central.conf"
|
||||
fi
|
||||
chown wildcloud:wildcloud /etc/systemd/resolved.conf.d/wild-cloud.conf
|
||||
chmod 644 /etc/systemd/resolved.conf.d/wild-cloud.conf
|
||||
chown wildcloud:wildcloud /etc/systemd/resolved.conf.d/wild-central.conf
|
||||
chmod 644 /etc/systemd/resolved.conf.d/wild-central.conf
|
||||
|
||||
# Ensure /etc/resolv.conf is a symlink to systemd-resolved stub
|
||||
# Skip in Docker/container environments where resolv.conf might be bind-mounted
|
||||
@@ -101,16 +101,16 @@ case "$1" in
|
||||
|
||||
# Set up nftables configuration directory
|
||||
mkdir -p /etc/nftables.d
|
||||
if [ ! -f /etc/nftables.d/wild-cloud.nft ]; then
|
||||
touch /etc/nftables.d/wild-cloud.nft
|
||||
echo "Created /etc/nftables.d/wild-cloud.nft"
|
||||
if [ ! -f /etc/nftables.d/wild-central.nft ]; then
|
||||
touch /etc/nftables.d/wild-central.nft
|
||||
echo "Created /etc/nftables.d/wild-central.nft"
|
||||
fi
|
||||
chown wildcloud:wildcloud /etc/nftables.d/wild-cloud.nft
|
||||
chmod 644 /etc/nftables.d/wild-cloud.nft
|
||||
chown wildcloud:wildcloud /etc/nftables.d/wild-central.nft
|
||||
chmod 644 /etc/nftables.d/wild-central.nft
|
||||
|
||||
# Ensure nftables.conf includes wild-cloud rules
|
||||
if [ -f /etc/nftables.conf ] && ! grep -q 'wild-cloud.nft' /etc/nftables.conf; then
|
||||
echo 'include "/etc/nftables.d/wild-cloud.nft"' >> /etc/nftables.conf
|
||||
# Ensure nftables.conf includes wild-central rules
|
||||
if [ -f /etc/nftables.conf ] && ! grep -q 'wild-central.nft' /etc/nftables.conf; then
|
||||
echo 'include "/etc/nftables.d/wild-central.nft"' >> /etc/nftables.conf
|
||||
echo "Added Wild Central nftables include to /etc/nftables.conf"
|
||||
fi
|
||||
echo "Configured nftables for Wild Central management"
|
||||
@@ -192,7 +192,7 @@ AUTHELIA_EOF
|
||||
|
||||
# Install sudoers rules for privileged operations
|
||||
cat > /etc/sudoers.d/wild-central << 'SUDOERS_EOF'
|
||||
wildcloud ALL=(ALL) NOPASSWD: /usr/sbin/nft -c -f *, /usr/sbin/nft list table inet wild-cloud, /usr/bin/cscli bouncers *, /usr/bin/cscli machines *, /usr/bin/cscli decisions *, /usr/bin/cscli alerts *, /usr/bin/cscli version, /usr/bin/wg-quick up wg0, /usr/bin/wg-quick down wg0, /usr/bin/wg show wg0, /usr/bin/certbot *, /usr/sbin/nginx -t, /usr/bin/systemctl reload nginx
|
||||
wildcloud ALL=(ALL) NOPASSWD: /usr/sbin/nft -c -f *, /usr/sbin/nft list table inet wild-central, /usr/bin/cscli bouncers *, /usr/bin/cscli machines *, /usr/bin/cscli decisions *, /usr/bin/cscli alerts *, /usr/bin/cscli version, /usr/bin/wg-quick up wg0, /usr/bin/wg-quick down wg0, /usr/bin/wg show wg0, /usr/bin/certbot *, /usr/sbin/nginx -t, /usr/bin/systemctl reload nginx
|
||||
SUDOERS_EOF
|
||||
chmod 440 /etc/sudoers.d/wild-central
|
||||
echo "Installed sudoers rules for Wild Central"
|
||||
|
||||
8
dist/debian/DEBIAN/postrm
vendored
8
dist/debian/DEBIAN/postrm
vendored
@@ -18,14 +18,14 @@ case "$1" in
|
||||
fi
|
||||
|
||||
# Remove dnsmasq configuration
|
||||
if [ -f /etc/dnsmasq.d/wild-cloud.conf ]; then
|
||||
rm -f /etc/dnsmasq.d/wild-cloud.conf
|
||||
if [ -f /etc/dnsmasq.d/wild-central.conf ]; then
|
||||
rm -f /etc/dnsmasq.d/wild-central.conf
|
||||
echo "Removed dnsmasq configuration"
|
||||
fi
|
||||
|
||||
# Remove systemd-resolved configuration
|
||||
if [ -f /etc/systemd/resolved.conf.d/wild-cloud.conf ]; then
|
||||
rm -f /etc/systemd/resolved.conf.d/wild-cloud.conf
|
||||
if [ -f /etc/systemd/resolved.conf.d/wild-central.conf ]; then
|
||||
rm -f /etc/systemd/resolved.conf.d/wild-central.conf
|
||||
echo "Removed systemd-resolved configuration"
|
||||
systemctl restart systemd-resolved 2>/dev/null || true
|
||||
fi
|
||||
|
||||
@@ -5,5 +5,5 @@ After=network.target nftables.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/sbin/nft -f /etc/nftables.d/wild-cloud.nft
|
||||
ExecStart=/usr/sbin/nft -f /etc/nftables.d/wild-central.nft
|
||||
RemainAfterExit=no
|
||||
|
||||
@@ -60,9 +60,9 @@ type API struct {
|
||||
// NewAPI creates a new Central API handler with all dependencies
|
||||
func NewAPI(dataDir, version string, allowedOrigins []string) (*API, error) {
|
||||
// Determine config paths from env or defaults
|
||||
dnsmasqConfigPath := envOrDefault("WILD_CENTRAL_DNSMASQ_CONFIG_PATH", "/etc/dnsmasq.d/wild-cloud.conf")
|
||||
dnsmasqConfigPath := envOrDefault("WILD_CENTRAL_DNSMASQ_CONFIG_PATH", "/etc/dnsmasq.d/wild-central.conf")
|
||||
haproxyConfigPath := envOrDefault("WILD_CENTRAL_HAPROXY_CONFIG_PATH", "/etc/haproxy/haproxy.cfg")
|
||||
nftablesRulesPath := envOrDefault("WILD_CENTRAL_NFTABLES_RULES_PATH", "/etc/nftables.d/wild-cloud.nft")
|
||||
nftablesRulesPath := envOrDefault("WILD_CENTRAL_NFTABLES_RULES_PATH", "/etc/nftables.d/wild-central.nft")
|
||||
vpnConfigPath := envOrDefault("WILD_CENTRAL_VPN_CONFIG_PATH", "/etc/wireguard/wg0.conf")
|
||||
|
||||
sseManager := sse.NewManager()
|
||||
@@ -540,8 +540,8 @@ func getDaemonStatus() map[string]map[string]any {
|
||||
result[name] = entry
|
||||
}
|
||||
|
||||
// nftables has no persistent service — check if the wild-cloud table exists
|
||||
nftErr := exec.Command("sudo", "nft", "list", "table", "inet", "wild-cloud").Run()
|
||||
// nftables has no persistent service — check if the wild-central table exists
|
||||
nftErr := exec.Command("sudo", "nft", "list", "table", "inet", "wild-central").Run()
|
||||
nftEntry := map[string]any{"active": nftErr == nil}
|
||||
if out, verErr := exec.Command("nft", "--version").Output(); verErr == nil {
|
||||
// "nftables v1.0.9 (Old Doc Yak #3)"
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/wild-cloud/wild-central/internal/haproxy"
|
||||
)
|
||||
|
||||
// NftablesStatus returns the current wild-cloud nftables table contents
|
||||
// NftablesStatus returns the current wild-central nftables table contents
|
||||
func (api *API) NftablesStatus(w http.ResponseWriter, r *http.Request) {
|
||||
rules, err := api.nftables.GetStatus()
|
||||
if err != nil {
|
||||
@@ -56,7 +56,7 @@ func (api *API) vpnAutoUDPPorts() []int {
|
||||
func (api *API) syncNftablesOnly(globalCfg *config.State) {
|
||||
nftCfg := globalCfg.Cloud.Nftables
|
||||
|
||||
// Explicitly disabled: flush the wild-cloud table
|
||||
// Explicitly disabled: flush the wild-central table
|
||||
if nftCfg.Enabled != nil && !*nftCfg.Enabled {
|
||||
if err := api.nftables.WriteDisabledRules(); err != nil {
|
||||
slog.Error("failed to write disabled nftables rules", "component", "nftables-sync", "error", err)
|
||||
|
||||
@@ -22,7 +22,7 @@ func setupTestNftables(t *testing.T) (*API, string) {
|
||||
}
|
||||
|
||||
// TestNftablesStatus_ReturnsOK verifies the status endpoint returns 200.
|
||||
// GetStatus() runs `nft list table inet wild-cloud` and silently returns an
|
||||
// GetStatus() runs `nft list table inet wild-central` and silently returns an
|
||||
// empty string if nft is not installed or the table doesn't exist, so this
|
||||
// endpoint always returns 200.
|
||||
func TestNftablesStatus_ReturnsOK(t *testing.T) {
|
||||
@@ -109,7 +109,7 @@ func TestNftablesApply_ServiceUnavailable(t *testing.T) {
|
||||
|
||||
api.NftablesApply(w, req)
|
||||
|
||||
// ApplyRules calls `systemctl start wild-cloud-nftables-reload.service`
|
||||
// ApplyRules calls `systemctl start wild-central-nftables-reload.service`
|
||||
// which requires polkit/root — always fails in test environments.
|
||||
if w.Code != http.StatusInternalServerError {
|
||||
// If it happened to succeed (running on the actual Wild Central device
|
||||
|
||||
@@ -34,7 +34,7 @@ type Manager struct {
|
||||
// NewManager creates a new dnsmasq config generator
|
||||
func NewManager(configPath string) *Manager {
|
||||
if configPath == "" {
|
||||
configPath = "/etc/dnsmasq.d/wild-cloud.conf"
|
||||
configPath = "/etc/dnsmasq.d/wild-central.conf"
|
||||
}
|
||||
return &Manager{
|
||||
configPath: configPath,
|
||||
@@ -388,7 +388,7 @@ func (g *Manager) ConfigureSystemDNS() error {
|
||||
|
||||
// Write systemd-resolved configuration to file owned by wildcloud user
|
||||
// (created during package installation in postinst)
|
||||
resolvedConfPath := "/etc/systemd/resolved.conf.d/wild-cloud.conf"
|
||||
resolvedConfPath := "/etc/systemd/resolved.conf.d/wild-central.conf"
|
||||
resolvedConf := fmt.Sprintf("[Resolve]\nDNS=%s\nDomains=~.\n", dnsIP)
|
||||
|
||||
if err := os.WriteFile(resolvedConfPath, []byte(resolvedConf), 0644); err != nil {
|
||||
|
||||
@@ -191,8 +191,8 @@ func TestNewManager_CustomPath(t *testing.T) {
|
||||
// Test: NewManager uses default path when empty
|
||||
func TestNewManager_DefaultPath(t *testing.T) {
|
||||
g := NewManager("")
|
||||
if g.GetConfigPath() != "/etc/dnsmasq.d/wild-cloud.conf" {
|
||||
t.Errorf("got %q, want /etc/dnsmasq.d/wild-cloud.conf", g.GetConfigPath())
|
||||
if g.GetConfigPath() != "/etc/dnsmasq.d/wild-central.conf" {
|
||||
t.Errorf("got %q, want /etc/dnsmasq.d/wild-central.conf", g.GetConfigPath())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/wild-cloud/wild-central/internal/storage"
|
||||
)
|
||||
|
||||
const defaultRulesPath = "/etc/nftables.d/wild-cloud.nft"
|
||||
const defaultRulesPath = "/etc/nftables.d/wild-central.nft"
|
||||
|
||||
// Manager handles nftables rule generation and application
|
||||
type Manager struct {
|
||||
@@ -68,15 +68,15 @@ func (m *Manager) Generate(haproxyPorts []int, extraTCPPorts []int, extraUDPPort
|
||||
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString("# Wild Cloud nftables rules\n")
|
||||
sb.WriteString("# Managed by Wild Cloud Central API — do not edit manually\n\n")
|
||||
sb.WriteString("# Wild Central nftables rules\n")
|
||||
sb.WriteString("# Managed by Wild Central — do not edit manually\n\n")
|
||||
|
||||
// Delete and recreate the table so re-applying never accumulates stale set elements.
|
||||
// The first line ensures the table exists (so delete never errors on first run).
|
||||
sb.WriteString("table inet wild-cloud {}\n")
|
||||
sb.WriteString("delete table inet wild-cloud\n\n")
|
||||
sb.WriteString("table inet wild-central {}\n")
|
||||
sb.WriteString("delete table inet wild-central\n\n")
|
||||
|
||||
sb.WriteString("table inet wild-cloud {\n")
|
||||
sb.WriteString("table inet wild-central {\n")
|
||||
sb.WriteString(" # TCP ports allowed through the firewall (HAProxy + extra TCP)\n")
|
||||
sb.WriteString(" set allowed_tcp_ports {\n")
|
||||
sb.WriteString(" type inet_service\n")
|
||||
@@ -148,7 +148,7 @@ func ValidateWANInterface(name string) error {
|
||||
// On apply failure, rolls back to the previous rules.
|
||||
func (m *Manager) SafeApply(content string) error {
|
||||
// Validate syntax
|
||||
tmpFile := "/tmp/wild-cloud-nft-safeapply.tmp"
|
||||
tmpFile := "/tmp/wild-central-nft-safeapply.tmp"
|
||||
if err := os.WriteFile(tmpFile, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("writing validation file: %w", err)
|
||||
}
|
||||
@@ -204,7 +204,7 @@ func (m *Manager) verify() error {
|
||||
// Validation uses a temp file in /tmp (world-writable) to avoid needing
|
||||
// write permission on the /etc/nftables.d/ directory itself.
|
||||
func (m *Manager) WriteRules(content string) error {
|
||||
tempFile := "/tmp/wild-cloud-nft-validate.tmp"
|
||||
tempFile := "/tmp/wild-central-nft-validate.tmp"
|
||||
|
||||
if err := os.WriteFile(tempFile, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("writing temp rules: %w", err)
|
||||
@@ -224,9 +224,9 @@ func (m *Manager) WriteRules(content string) error {
|
||||
}
|
||||
|
||||
// ApplyRules loads the rules file into the kernel via a systemd oneshot service.
|
||||
// The wildcloud user has polkit permission to start wild-cloud-nftables-reload.service.
|
||||
// The wildcloud user has polkit permission to start wild-central-nftables-reload.service.
|
||||
func (m *Manager) ApplyRules() error {
|
||||
cmd := exec.Command("systemctl", "start", "wild-cloud-nftables-reload.service")
|
||||
cmd := exec.Command("systemctl", "start", "wild-central-nftables-reload.service")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("applying nftables rules: %w (output: %s)", err, string(output))
|
||||
@@ -235,13 +235,13 @@ func (m *Manager) ApplyRules() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteDisabledRules writes a rules file that flushes the wild-cloud table,
|
||||
// removing all Wild Cloud firewall rules from the kernel when applied.
|
||||
// WriteDisabledRules writes a rules file that flushes the wild-central table,
|
||||
// removing all Wild Central firewall rules from the kernel when applied.
|
||||
func (m *Manager) WriteDisabledRules() error {
|
||||
content := "# Wild Cloud nftables rules — firewall disabled\n" +
|
||||
"# Managed by Wild Cloud Central API — do not edit manually\n\n" +
|
||||
"table inet wild-cloud {}\n" +
|
||||
"delete table inet wild-cloud\n"
|
||||
content := "# Wild Central nftables rules — firewall disabled\n" +
|
||||
"# Managed by Wild Central — do not edit manually\n\n" +
|
||||
"table inet wild-central {}\n" +
|
||||
"delete table inet wild-central\n"
|
||||
if err := storage.WriteFileAtomic(m.rulesPath, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("writing disabled rules file: %w", err)
|
||||
}
|
||||
@@ -249,10 +249,10 @@ func (m *Manager) WriteDisabledRules() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStatus returns the current wild-cloud nftables table as a string.
|
||||
// GetStatus returns the current wild-central nftables table as a string.
|
||||
// Uses sudo to allow the wildcloud user to read kernel state.
|
||||
func (m *Manager) GetStatus() (string, error) {
|
||||
cmd := exec.Command("sudo", "nft", "list", "table", "inet", "wild-cloud")
|
||||
cmd := exec.Command("sudo", "nft", "list", "table", "inet", "wild-central")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// Table may not exist yet — not an error
|
||||
|
||||
@@ -13,9 +13,9 @@ func TestNewManager_DefaultPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewManager_CustomPath(t *testing.T) {
|
||||
m := NewManager("/tmp/wild-cloud.nft")
|
||||
if m.GetRulesPath() != "/tmp/wild-cloud.nft" {
|
||||
t.Errorf("got %q, want /tmp/wild-cloud.nft", m.GetRulesPath())
|
||||
m := NewManager("/tmp/wild-central.nft")
|
||||
if m.GetRulesPath() != "/tmp/wild-central.nft" {
|
||||
t.Errorf("got %q, want /tmp/wild-central.nft", m.GetRulesPath())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestGenerate_AlwaysIncludesStructure(t *testing.T) {
|
||||
out := m.Generate([]int{80, 443}, nil, nil, "")
|
||||
|
||||
for _, want := range []string{
|
||||
"table inet wild-cloud",
|
||||
"table inet wild-central",
|
||||
"set allowed_tcp_ports",
|
||||
"chain input",
|
||||
"type filter hook input priority filter; policy accept;",
|
||||
|
||||
Reference in New Issue
Block a user