Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions hscontrol/auth.go
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In hscontrol/auth.go, auto-approval of routes was removed from handleRegisterInteractive but still exists in handleRegisterWithAuthKey (line 217). Should this also be moved to after the node is stored in the database for consistency with the other registration flows?

Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,6 @@ func (h *Headscale) handleRegisterWithAuthKey(
nodeToRegister.Expiry = &regReq.Expiry
}

// Ensure any auto approved routes are handled before saving.
policy.AutoApproveRoutes(h.polMan, &nodeToRegister)

ipv4, ipv6, err := h.ipAlloc.Next()
if err != nil {
return nil, fmt.Errorf("allocating IPs: %w", err)
Expand Down Expand Up @@ -248,7 +245,23 @@ func (h *Headscale) handleRegisterWithAuthKey(
return nil, fmt.Errorf("nodes changed hook: %w", err)
}

if !updateSent {
// This is a bit of a back and forth, but we have a bit of a chicken and egg
// dependency here.
// Because the way the policy manager works, we need to have the node
// in the database, then add it to the policy manager and then we can
// approve the route. This means we get this dance where the node is
// first added to the database, then we add it to the policy manager via
// nodesChangedHook and then we can auto approve the routes.
// As that only approves the struct object, we need to save it again and
// ensure we send an update.
// This works, but might be another good candidate for doing some sort of
// eventbus.
routesChanged := policy.AutoApproveRoutes(h.polMan, node)
if err := h.db.DB.Save(node).Error; err != nil {
return nil, fmt.Errorf("saving auto approved routes to node: %w", err)
}

if !updateSent || routesChanged {
ctx := types.NotifyCtx(context.Background(), "node updated", node.Hostname)
h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(node.ID))
}
Expand Down Expand Up @@ -285,9 +298,6 @@ func (h *Headscale) handleRegisterInteractive(
nodeToRegister.Node.Expiry = &regReq.Expiry
}

// Ensure any auto approved routes are handled before saving.
policy.AutoApproveRoutes(h.polMan, &nodeToRegister.Node)

h.registrationCache.Set(
registrationId,
nodeToRegister,
Expand Down
19 changes: 18 additions & 1 deletion hscontrol/grpcv1.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,24 @@ func (api headscaleV1APIServer) RegisterNode(
if err != nil {
return nil, fmt.Errorf("updating resources using node: %w", err)
}
if !updateSent {

// This is a bit of a back and forth, but we have a bit of a chicken and egg
// dependency here.
// Because the way the policy manager works, we need to have the node
// in the database, then add it to the policy manager and then we can
// approve the route. This means we get this dance where the node is
// first added to the database, then we add it to the policy manager via
// nodesChangedHook and then we can auto approve the routes.
// As that only approves the struct object, we need to save it again and
// ensure we send an update.
// This works, but might be another good candidate for doing some sort of
// eventbus.
routesChanged := policy.AutoApproveRoutes(api.h.polMan, node)
if err := api.h.db.DB.Save(node).Error; err != nil {
return nil, fmt.Errorf("saving auto approved routes to node: %w", err)
}

if !updateSent || routesChanged {
ctx = types.NotifyCtx(context.Background(), "web-node-login", node.Hostname)
api.h.nodeNotifier.NotifyAll(ctx, types.UpdatePeerChanged(node.ID))
}
Expand Down
18 changes: 17 additions & 1 deletion hscontrol/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,23 @@ func (a *AuthProviderOIDC) handleRegistration(
return false, fmt.Errorf("updating resources using node: %w", err)
}

if !updateSent {
// This is a bit of a back and forth, but we have a bit of a chicken and egg
// dependency here.
// Because the way the policy manager works, we need to have the node
// in the database, then add it to the policy manager and then we can
// approve the route. This means we get this dance where the node is
// first added to the database, then we add it to the policy manager via
// nodesChangedHook and then we can auto approve the routes.
// As that only approves the struct object, we need to save it again and
// ensure we send an update.
// This works, but might be another good candidate for doing some sort of
// eventbus.
routesChanged := policy.AutoApproveRoutes(a.polMan, node)
if err := a.db.DB.Save(node).Error; err != nil {
return false, fmt.Errorf("saving auto approved routes to node: %w", err)
}

if !updateSent || routesChanged {
ctx := types.NotifyCtx(context.Background(), "oidc-expiry-self", node.Hostname)
a.notifier.NotifyByNodeID(
ctx,
Expand Down
10 changes: 5 additions & 5 deletions integration/route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,11 @@ func TestAutoApproveMultiNetwork(t *testing.T) {
assertNoErrGetHeadscale(t, err)
assert.NotNil(t, headscale)

// Set the route of usernet1 to be autoapproved
tt.pol.AutoApprovers.Routes[route.String()] = []string{tt.approver}
err = headscale.SetPolicy(tt.pol)
require.NoError(t, err)

if advertiseDuringUp {
tsOpts = append(tsOpts,
tsic.WithExtraLoginArgs([]string{"--advertise-routes=" + route.String()}),
Expand Down Expand Up @@ -1691,11 +1696,6 @@ func TestAutoApproveMultiNetwork(t *testing.T) {
}
// extra creation end.

// Set the route of usernet1 to be autoapproved
tt.pol.AutoApprovers.Routes[route.String()] = []string{tt.approver}
err = headscale.SetPolicy(tt.pol)
require.NoError(t, err)

routerUsernet1ID := routerUsernet1.MustID()

web := services[0]
Expand Down
Loading