Compare commits

...

3 Commits

Author SHA1 Message Date
pascal
29c5184329 fix tag in openapi 2025-12-02 12:33:48 +01:00
pascal
afa1620e6d pass account manager 2025-12-01 18:14:01 +01:00
pascal
f4c4d37d4e add resource temporary peer support 2025-12-01 18:05:07 +01:00
4 changed files with 143 additions and 4 deletions

View File

@@ -35,7 +35,7 @@ type handler struct {
func AddEndpoints(networksManager networks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager groups.Manager, accountManager account.Manager, router *mux.Router) {
addRouterEndpoints(routerManager, router)
addResourceEndpoints(resourceManager, groupsManager, router)
addResourceEndpoints(resourceManager, groupsManager, accountManager, router)
networksHandler := newHandler(networksManager, resourceManager, routerManager, groupsManager, accountManager)
router.HandleFunc("/networks", networksHandler.getAllNetworks).Methods("GET", "OPTIONS")

View File

@@ -6,33 +6,40 @@ import (
"github.com/gorilla/mux"
"github.com/netbirdio/netbird/management/server/account"
nbcontext "github.com/netbirdio/netbird/management/server/context"
"github.com/netbirdio/netbird/management/server/groups"
"github.com/netbirdio/netbird/management/server/networks/resources"
"github.com/netbirdio/netbird/management/server/networks/resources/types"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
nbtypes "github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/shared/management/http/api"
"github.com/netbirdio/netbird/shared/management/http/util"
"github.com/netbirdio/netbird/shared/management/status"
)
type resourceHandler struct {
resourceManager resources.Manager
groupsManager groups.Manager
accountManager account.Manager
}
func addResourceEndpoints(resourcesManager resources.Manager, groupsManager groups.Manager, router *mux.Router) {
resourceHandler := newResourceHandler(resourcesManager, groupsManager)
func addResourceEndpoints(resourcesManager resources.Manager, groupsManager groups.Manager, accountManager account.Manager, router *mux.Router) {
resourceHandler := newResourceHandler(resourcesManager, groupsManager, accountManager)
router.HandleFunc("/networks/resources", resourceHandler.getAllResourcesInAccount).Methods("GET", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources", resourceHandler.getAllResourcesInNetwork).Methods("GET", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources", resourceHandler.createResource).Methods("POST", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources/{resourceId}", resourceHandler.getResource).Methods("GET", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources/{resourceId}", resourceHandler.updateResource).Methods("PUT", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources/{resourceId}", resourceHandler.deleteResource).Methods("DELETE", "OPTIONS")
router.HandleFunc("/networks/{networkId}/resources/{resourceId}/temporary-access", resourceHandler.CreateTemporaryAccess).Methods("POST", "OPTIONS")
}
func newResourceHandler(resourceManager resources.Manager, groupsManager groups.Manager) *resourceHandler {
func newResourceHandler(resourceManager resources.Manager, groupsManager groups.Manager, accountManager account.Manager) *resourceHandler {
return &resourceHandler{
resourceManager: resourceManager,
groupsManager: groupsManager,
accountManager: accountManager,
}
}
@@ -218,3 +225,90 @@ func (h *resourceHandler) deleteResource(w http.ResponseWriter, r *http.Request)
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
}
func (h *resourceHandler) CreateTemporaryAccess(w http.ResponseWriter, r *http.Request) {
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
vars := mux.Vars(r)
networkID := vars["networkId"]
if len(networkID) == 0 {
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "invalid network ID"), w)
return
}
resourceID := vars["resourceId"]
if len(resourceID) == 0 {
util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "invalid resource ID"), w)
return
}
var req api.PeerTemporaryAccessRequest
err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
return
}
newPeer := &nbpeer.Peer{}
newPeer.FromAPITemporaryAccessRequest(&req)
targetResource, err := h.resourceManager.GetResource(r.Context(), userAuth.AccountId, userAuth.UserId, networkID, resourceID)
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
peer, _, _, err := h.accountManager.AddPeer(r.Context(), userAuth.AccountId, "", userAuth.UserId, newPeer, true)
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
for _, rule := range req.Rules {
protocol, portRange, err := nbtypes.ParseRuleString(rule)
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
policy := &nbtypes.Policy{
AccountID: userAuth.AccountId,
Description: "Temporary access policy for peer " + peer.Name,
Name: "Temporary access policy for peer " + peer.Name,
Enabled: true,
Rules: []*nbtypes.PolicyRule{{
Name: "Temporary access rule",
Description: "Temporary access rule",
Enabled: true,
Action: nbtypes.PolicyTrafficActionAccept,
SourceResource: nbtypes.Resource{
Type: nbtypes.ResourceTypePeer,
ID: peer.ID,
},
DestinationResource: nbtypes.Resource{
Type: nbtypes.ResourceType(targetResource.Type.String()),
ID: targetResource.ID,
},
Bidirectional: false,
Protocol: protocol,
PortRanges: []nbtypes.RulePortRange{portRange},
}},
}
_, err = h.accountManager.SavePolicy(r.Context(), userAuth.AccountId, userAuth.UserId, policy, true)
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
}
resp := &api.PeerTemporaryAccessResponse{
Id: peer.ID,
Name: peer.Name,
Rules: req.Rules,
}
util.WriteJSONObject(r.Context(), w, resp)
}

View File

@@ -4108,6 +4108,48 @@ paths:
"$ref": "#/components/responses/forbidden"
'500':
"$ref": "#/components/responses/internal_error"
/api/networks/{networkId}/resources/{resourceId}/temporary-access:
post:
summary: Create a Temporary Access Peer
description: Creates a temporary access peer that can be used to access this resource and this resource only. The temporary access peer and its access policies will be automatically deleted after it disconnects.
tags: [ Networks ]
security:
- BearerAuth: [ ]
- TokenAuth: [ ]
parameters:
- in: path
name: networkId
required: true
schema:
type: string
description: The unique identifier of a network
- in: path
name: resourceId
required: true
schema:
type: string
description: The unique identifier of a network resource
requestBody:
description: Temporary Access Peer create request
content:
'application/json':
schema:
$ref: '#/components/schemas/PeerTemporaryAccessRequest'
responses:
'200':
description: Temporary Access Peer response
content:
application/json:
schema:
$ref: '#/components/schemas/PeerTemporaryAccessResponse'
'400':
"$ref": "#/components/responses/bad_request"
'401':
"$ref": "#/components/responses/requires_authentication"
'403':
"$ref": "#/components/responses/forbidden"
'500':
"$ref": "#/components/responses/internal_error"
/api/networks/{networkId}/routers:
get:
summary: List all Network Routers

View File

@@ -1971,6 +1971,9 @@ type PostApiNetworksNetworkIdResourcesJSONRequestBody = NetworkResourceRequest
// PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody defines body for PutApiNetworksNetworkIdResourcesResourceId for application/json ContentType.
type PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody = NetworkResourceRequest
// PostApiNetworksNetworkIdResourcesResourceIdTemporaryAccessJSONRequestBody defines body for PostApiNetworksNetworkIdResourcesResourceIdTemporaryAccess for application/json ContentType.
type PostApiNetworksNetworkIdResourcesResourceIdTemporaryAccessJSONRequestBody = PeerTemporaryAccessRequest
// PostApiNetworksNetworkIdRoutersJSONRequestBody defines body for PostApiNetworksNetworkIdRouters for application/json ContentType.
type PostApiNetworksNetworkIdRoutersJSONRequestBody = NetworkRouterRequest