diff --git a/cmd/incusd/api.go b/cmd/incusd/api.go index 55f5ef650f0..6bf2e438e4e 100644 --- a/cmd/incusd/api.go +++ b/cmd/incusd/api.go @@ -422,6 +422,10 @@ func isClusterNotification(r *http.Request) bool { return r.Header.Get("User-Agent") == clusterRequest.UserAgentNotifier } +func isClusterInternal(r *http.Request) bool { + return r.Header.Get("User-Agent") == clusterRequest.UserAgentClient +} + type uiHttpDir struct { http.FileSystem } diff --git a/cmd/incusd/daemon.go b/cmd/incusd/daemon.go index 08c5c0a036f..44da19811f1 100644 --- a/cmd/incusd/daemon.go +++ b/cmd/incusd/daemon.go @@ -482,6 +482,11 @@ func (d *Daemon) Authenticate(w http.ResponseWriter, r *http.Request) (bool, str return false, "", "", fmt.Errorf("Cluster notification isn't using trusted server certificate") } + // Cluster internal client with wrong certificate. + if isClusterInternal(r) { + return false, "", "", fmt.Errorf("Cluster internal client isn't using trusted server certificate") + } + // Bad query, no TLS found. if r.TLS == nil { return false, "", "", fmt.Errorf("Bad/missing TLS on network query") diff --git a/cmd/incusd/instance_post.go b/cmd/incusd/instance_post.go index 2e74d2d4b28..d50b2cb4a1a 100644 --- a/cmd/incusd/instance_post.go +++ b/cmd/incusd/instance_post.go @@ -14,6 +14,7 @@ import ( internalInstance "github.com/lxc/incus/v6/internal/instance" "github.com/lxc/incus/v6/internal/server/auth" "github.com/lxc/incus/v6/internal/server/cluster" + clusterRequest "github.com/lxc/incus/v6/internal/server/cluster/request" "github.com/lxc/incus/v6/internal/server/db" dbCluster "github.com/lxc/incus/v6/internal/server/db/cluster" "github.com/lxc/incus/v6/internal/server/db/operationtype" @@ -336,7 +337,7 @@ func instancePost(d *Daemon, r *http.Request) response.Response { Devices: inst.ExpandedDevices().CloneNative(), }, }, - Project: projectName, + Project: instProject, Reason: apiScriptlet.InstancePlacementReasonRelocation, } @@ -595,7 +596,12 @@ func migrateInstance(ctx context.Context, s *state.State, inst instance.Instance // Handle pool and project moves. if req.Project != "" || req.Pool != "" { // Get a local client. - target, err := incus.ConnectIncusUnix(s.OS.GetUnixSocket(), nil) + args := &incus.ConnectionArgs{ + SkipGetServer: true, + UserAgent: clusterRequest.UserAgentClient, + } + + target, err := incus.ConnectIncusUnix(s.OS.GetUnixSocket(), args) if err != nil { return err } diff --git a/cmd/incusd/instances_post.go b/cmd/incusd/instances_post.go index 1de9fc0135c..ea0e95b037a 100644 --- a/cmd/incusd/instances_post.go +++ b/cmd/incusd/instances_post.go @@ -832,6 +832,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { targetProjectName := request.ProjectParam(r) clusterNotification := isClusterNotification(r) + clusterInternal := isClusterInternal(r) logger.Debug("Responding to instance create") @@ -1102,7 +1103,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { return response.BadRequest(err) } - if s.ServerClustered && !clusterNotification { + if s.ServerClustered && !clusterNotification && !clusterInternal { // If a target was specified, limit the list of candidates to that target. if targetMemberInfo != nil { candidateMembers = []db.NodeInfo{*targetMemberInfo} @@ -1142,7 +1143,7 @@ func instancesPost(d *Daemon, r *http.Request) response.Response { } // Record the cluster group as a volatile config key if present. - if !clusterNotification && targetGroupName != "" { + if !clusterNotification && !clusterInternal && targetGroupName != "" { req.Config["volatile.cluster.group"] = targetGroupName } diff --git a/internal/server/cluster/request/clienttype.go b/internal/server/cluster/request/clienttype.go index 8f1a3c0c7ae..f4699bc74ef 100644 --- a/internal/server/cluster/request/clienttype.go +++ b/internal/server/cluster/request/clienttype.go @@ -4,6 +4,10 @@ package request // notifying other nodes of a cluster change. const UserAgentNotifier = "incus-cluster-notifier" +// UserAgentClient used to distinguish between a regular client request and an internal cluster request when +// performing a regular API interaction as an internal client. +const UserAgentClient = "incus-cluster-client" + // UserAgentJoiner used to distinguish between a regular client request and an internal cluster request when // joining a node to a cluster. const UserAgentJoiner = "incus-cluster-joiner" @@ -20,6 +24,9 @@ const ClientTypeJoiner ClientType = "joiner" // ClientTypeNormal normal client. const ClientTypeNormal ClientType = "normal" +// ClientTypeInternal cluster internal client. +const ClientTypeInternal ClientType = "internal" + // UserAgentClientType converts user agent to client type. func UserAgentClientType(userAgent string) ClientType { switch userAgent { @@ -27,6 +34,8 @@ func UserAgentClientType(userAgent string) ClientType { return ClientTypeNotifier case UserAgentJoiner: return ClientTypeJoiner + case UserAgentClient: + return ClientTypeInternal } return ClientTypeNormal