feat(operator): secure system server workloads
This commit is contained in:
10 files changed
+191
-59
No files matched your search
@@ -19,6 +19,7 @@ var (
|
||||
// reserved subdomains/server names that users may not claim: proxy/lobby and
|
||||
// the platform's own faces.
|
||||
var reserved = map[string]struct{}{
|
||||
"login": {},
|
||||
"lobby": {},
|
||||
"admin": {},
|
||||
"panel": {},
|
||||
@@ -56,6 +57,31 @@ const (
|
||||
ServiceTokenSecretKey = "token"
|
||||
)
|
||||
|
||||
// ForwardingSecretName / ForwardingSecretKey name the Velocity modern player-info
|
||||
// forwarding secret — the shared HMAC key the proxy signs each login handshake with
|
||||
// and every backend verifies. It is what makes a backend's idea of "who is this
|
||||
// player" trustworthy: with modern forwarding on, the UUID arrives inside the signed
|
||||
// forwarding payload rather than being derived offline from the username, which is
|
||||
// the whole basis of the Owner bind (the Owner IS a Minecraft account, claimed by
|
||||
// joining the login gate). Legacy/BungeeCord forwarding carries no secret at all and
|
||||
// fails OPEN — anyone who can reach a backend directly can assert any UUID — so Felis
|
||||
// mandates modern (spec §20).
|
||||
//
|
||||
// Unlike the service token this is NOT login-only: Velocity's forwarding mode is a
|
||||
// single proxy-wide setting, so once it is "modern" EVERY backend must speak it or it
|
||||
// rejects the proxy's logins outright. The secret authenticates the PROXY to the
|
||||
// backend; every backend verifies it before accepting the forwarded identity. The
|
||||
// NetworkPolicy narrows game-port reachability to declared Velocity CIDRs for non-node
|
||||
// traffic, but Kubernetes always permits traffic from a pod's resident node, so the
|
||||
// policy is defense in depth and never replaces HMAC verification.
|
||||
//
|
||||
// Provisioned out-of-band (deploy/bootstrap.sh, the same run that writes Velocity's
|
||||
// forwarding.secret) and replicated into the minecraft namespace by `felis setup`.
|
||||
const (
|
||||
ForwardingSecretName = "felis-forwarding-secret"
|
||||
ForwardingSecretKey = "secret"
|
||||
)
|
||||
|
||||
// ValidateServerName checks the §22 name rule and reservation list.
|
||||
func ValidateServerName(name string) error {
|
||||
if !serverNameRE.MatchString(name) {
|
||||
|
||||
@@ -22,6 +22,7 @@ func TestValidateServerName(t *testing.T) {
|
||||
{"has space", false}, // illegal char
|
||||
{"-leading", false}, // leading hyphen
|
||||
{"trailing-", false}, // trailing hyphen
|
||||
{"login", false}, // reserved system server
|
||||
{"lobby", false}, // reserved
|
||||
{"admin", false}, // reserved
|
||||
{"api", false}, // reserved
|
||||
@@ -45,9 +46,9 @@ func TestValidateSystemServerName(t *testing.T) {
|
||||
name string
|
||||
ok bool
|
||||
}{
|
||||
{"login", true}, // reserved, but a legal system service
|
||||
{"lobby", true}, // reserved, but a legal system service
|
||||
{"admin", true}, // reserved names are allowed on this path
|
||||
{"login", true}, // reserved, but a legal system service
|
||||
{"lobby", true}, // reserved, but a legal system service
|
||||
{"admin", true}, // reserved names are allowed on this path
|
||||
{"survival", true},
|
||||
{"ab", false}, // still too short
|
||||
{"Login", false}, // still case-sensitive
|
||||
@@ -64,13 +65,15 @@ func TestValidateSystemServerName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The two paths must genuinely differ on reserved names: user path refuses
|
||||
// "lobby", system path accepts it.
|
||||
if naming.ValidateServerName("lobby") == nil {
|
||||
t.Error("ValidateServerName(lobby) accepted; reserved name must be refused for users")
|
||||
}
|
||||
if naming.ValidateSystemServerName("lobby") != nil {
|
||||
t.Error("ValidateSystemServerName(lobby) refused; system path must accept it")
|
||||
// The two paths must genuinely differ on system names: the user path
|
||||
// refuses them while the system path accepts them.
|
||||
for _, name := range []string{"login", "lobby"} {
|
||||
if naming.ValidateServerName(name) == nil {
|
||||
t.Errorf("ValidateServerName(%s) accepted; reserved name must be refused for users", name)
|
||||
}
|
||||
if naming.ValidateSystemServerName(name) != nil {
|
||||
t.Errorf("ValidateSystemServerName(%s) refused; system path must accept it", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user