Files
netbird/client/server/mdm.go
2026-06-08 14:37:10 +02:00

91 lines
2.7 KiB
Go

package server
import (
"fmt"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
gstatus "google.golang.org/grpc/status"
"github.com/netbirdio/netbird/client/mdm"
"github.com/netbirdio/netbird/client/proto"
)
// loadMDMPolicy is the indirection used by server handlers to read the
// active MDM policy. Tests override this to inject a fake policy.
var loadMDMPolicy = mdm.LoadPolicy
// requestedMDMManagedKeys returns the names of MDM-managed keys whose
// corresponding field is set in the SetConfigRequest. Only keys with an
// MDM mapping are considered; other fields are ignored.
func requestedMDMManagedKeys(msg *proto.SetConfigRequest) []string {
if msg == nil {
return nil
}
var keys []string
if msg.ManagementUrl != "" {
keys = append(keys, mdm.KeyManagementURL)
}
if msg.OptionalPreSharedKey != nil {
keys = append(keys, mdm.KeyPreSharedKey)
}
if msg.RosenpassEnabled != nil {
keys = append(keys, mdm.KeyRosenpassEnabled)
}
if msg.RosenpassPermissive != nil {
keys = append(keys, mdm.KeyRosenpassPermissive)
}
if msg.DisableAutoConnect != nil {
keys = append(keys, mdm.KeyDisableAutoConnect)
}
if msg.ServerSSHAllowed != nil {
keys = append(keys, mdm.KeyAllowServerSSH)
}
if msg.DisableClientRoutes != nil {
keys = append(keys, mdm.KeyDisableClientRoutes)
}
if msg.DisableServerRoutes != nil {
keys = append(keys, mdm.KeyDisableServerRoutes)
}
if msg.BlockInbound != nil {
keys = append(keys, mdm.KeyBlockInbound)
}
if msg.WireguardPort != nil {
keys = append(keys, mdm.KeyWireguardPort)
}
return keys
}
// rejectMDMManagedFieldConflicts returns a FailedPrecondition gRPC error
// with an MDMManagedFieldsViolation detail when any of the requested keys
// is MDM-enforced, and nil otherwise. The whole request is rejected on
// any conflict; non-conflicting fields in the same request are not
// applied either (no partial apply).
func rejectMDMManagedFieldConflicts(policy *mdm.Policy, requested []string) error {
if policy.IsEmpty() || len(requested) == 0 {
return nil
}
var conflicts []string
for _, k := range requested {
if policy.HasKey(k) {
conflicts = append(conflicts, k)
}
}
if len(conflicts) == 0 {
return nil
}
log.Warnf("MDM rejected request: tried to modify %d managed key(s): %v",
len(conflicts), conflicts)
st := gstatus.New(
codes.FailedPrecondition,
fmt.Sprintf("fields managed by MDM cannot be modified: %v", conflicts),
)
detailed, err := st.WithDetails(&proto.MDMManagedFieldsViolation{Fields: conflicts})
if err != nil {
// Detail attachment is best-effort; fall back to the plain status
// so the caller still gets a usable FailedPrecondition.
return st.Err()
}
return detailed.Err()
}