Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NET-1615: External Client Acls #3165

Merged
merged 8 commits into from
Oct 21, 2024
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
1 change: 1 addition & 0 deletions controllers/acls.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) {
},
SrcGroupTypes: []models.AclGroupType{
models.UserAclID,
models.UserRoleAclID,
models.UserGroupAclID,
models.DeviceAclID,
},
Expand Down
4 changes: 3 additions & 1 deletion controllers/ext_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,9 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
extclient.OwnerID = userName
extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
extclient.IngressGatewayID = nodeid

extclient.Tags = make(map[models.TagID]struct{})
extclient.Tags[models.TagID(fmt.Sprintf("%s.%s", extclient.Network,
models.RemoteAccessTagName))] = struct{}{}
// set extclient dns to ingressdns if extclient dns is not explicitly set
if (extclient.DNS == "") && (node.IngressDNS != "") {
extclient.DNS = node.IngressDNS
Expand Down
97 changes: 81 additions & 16 deletions logic/acls.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
ID: models.UserGroupAclID,
Value: "*",
},
{
ID: models.UserRoleAclID,
Value: "*",
},
},
Dst: []models.AclPolicyTag{{
ID: models.DeviceAclID,
Expand All @@ -79,7 +83,7 @@
Src: []models.AclPolicyTag{
{
ID: models.DeviceAclID,
Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"),
Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName),
},
},
Dst: []models.AclPolicyTag{
Expand All @@ -95,7 +99,7 @@
}
InsertAcl(defaultUserAcl)
}

CreateDefaultUserPolicies(netID)
}

// DeleteDefaultNetworkPolicies - deletes all default network acl policies
Expand Down Expand Up @@ -168,8 +172,11 @@
if srcI.ID == "" || srcI.Value == "" {
return false
}
if srcI.Value == "*" {
continue
}
if srcI.ID != models.UserAclID &&
srcI.ID != models.UserGroupAclID {
srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID {
return false
}
// check if user group is valid
Expand All @@ -178,10 +185,14 @@
if err != nil {
return false
}
} else if srcI.ID == models.UserGroupAclID {
if srcI.Value == "*" {
continue
} else if srcI.ID == models.UserRoleAclID {

_, err := GetRole(models.UserRoleID(srcI.Value))
if err != nil {
return false
}

} else if srcI.ID == models.UserGroupAclID {
err := IsGroupValid(models.UserGroupID(srcI.Value))
if err != nil {
return false
Expand All @@ -194,10 +205,6 @@
if dstI.ID == "" || dstI.Value == "" {
return false
}
if dstI.ID == models.UserAclID ||
dstI.ID == models.UserGroupAclID {
return false
}
if dstI.ID != models.DeviceAclID {
return false
}
Expand Down Expand Up @@ -281,9 +288,13 @@
return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String())
}

// GetDefaultNodesPolicy - fetches default policy in the network by ruleType
func GetDefaultNodesPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) {
acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes")))
// GetDefaultPolicy - fetches default policy in the network by ruleType
func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) {
aclID := "all-users"
if ruleType == models.DevicePolicy {
aclID = "all-nodes"
}
acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, aclID)))
if err != nil {
return models.Acl{}, errors.New("default rule not found")
}
Expand Down Expand Up @@ -323,8 +334,45 @@
return acls
}

// listPoliciesOfUser - lists all user acl policies applied to user in an network
func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl {
data, err := database.FetchRecords(database.ACLS_TABLE_NAME)
if err != nil && !database.IsEmptyRecord(err) {
return []models.Acl{}
}
acls := []models.Acl{}
for _, dataI := range data {
acl := models.Acl{}
err := json.Unmarshal([]byte(dataI), &acl)
if err != nil {
continue
}
if acl.NetworkID == netID && acl.RuleType == models.UserPolicy {
srcMap := convAclTagToValueMap(acl.Src)
if _, ok := srcMap[user.UserName]; ok {
acls = append(acls, acl)
continue
}
for netRole := range user.NetworkRoles {
if _, ok := srcMap[netRole.String()]; ok {
acls = append(acls, acl)
continue
}
}
for userG := range user.UserGroups {
if _, ok := srcMap[userG.String()]; ok {
acls = append(acls, acl)
continue
}
}

}
}
return acls
}

// listUserPoliciesByNetwork - lists all acl user policies in a network
func listUserPoliciesByNetwork(netID models.NetworkID) []models.Acl {

Check failure on line 375 in logic/acls.go

View workflow job for this annotation

GitHub Actions / staticcheck

func listUserPoliciesByNetwork is unused (U1000)
data, err := database.FetchRecords(database.ACLS_TABLE_NAME)
if err != nil && !database.IsEmptyRecord(err) {
return []models.Acl{}
Expand Down Expand Up @@ -391,15 +439,32 @@
return aclValueMap
}

// IsUserAllowedToCommunicate - check if user is allowed to communicate with peer
func IsUserAllowedToCommunicate(userName string, peer models.Node) bool {
listUserPoliciesByNetwork(models.NetworkID(peer.Network))
return true
user, err := GetUser(userName)
if err != nil {
return false
}
policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network))
for _, policy := range policies {
if !policy.Enabled {
continue
}
dstMap := convAclTagToValueMap(policy.Dst)
for tagID := range peer.Tags {
if _, ok := dstMap[tagID.String()]; ok {
return true
}
}

}
return false
}

// IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer
func IsNodeAllowedToCommunicate(node, peer models.Node) bool {
// check default policy if all allowed return true
defaultPolicy, err := GetDefaultNodesPolicy(models.NetworkID(node.Network), models.DevicePolicy)
defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
if err == nil {
if defaultPolicy.Enabled {
return true
Expand Down
1 change: 1 addition & 0 deletions logic/user_mgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var UpdateRole = func(r models.UserRolePermissionTemplate) error { return nil }
var InitialiseRoles = userRolesInit
var DeleteNetworkRoles = func(netID string) {}
var CreateDefaultNetworkRolesAndGroups = func(netID models.NetworkID) {}
var CreateDefaultUserPolicies = func(netID models.NetworkID) {}

// GetRole - fetches role template by id
func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) {
Expand Down
19 changes: 17 additions & 2 deletions migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
func Run() {
updateEnrollmentKeys()
assignSuperAdmin()
createDefaultTags()
createDefaultTagsAndPolicies()
removeOldUserGrps()
syncUsers()
updateHosts()
Expand Down Expand Up @@ -171,6 +171,9 @@ func updateNodes() {
if node.IsIngressGateway {
tagID := models.TagID(fmt.Sprintf("%s.%s", node.Network,
models.RemoteAccessTagName))
if node.Tags == nil {
node.Tags = make(map[models.TagID]struct{})
}
if _, ok := node.Tags[tagID]; !ok {
node.Tags[tagID] = struct{}{}
logic.UpsertNode(&node)
Expand All @@ -186,6 +189,18 @@ func updateNodes() {
}
}
}
extclients, _ := logic.GetAllExtClients()
for _, extclient := range extclients {
tagID := models.TagID(fmt.Sprintf("%s.%s", extclient.Network,
models.RemoteAccessTagName))
if extclient.Tags == nil {
extclient.Tags = make(map[models.TagID]struct{})
}
if _, ok := extclient.Tags[tagID]; !ok {
extclient.Tags[tagID] = struct{}{}
logic.SaveExtClient(&extclient)
}
}
}

func removeInterGw(egressRanges []string) ([]string, bool) {
Expand Down Expand Up @@ -444,7 +459,7 @@ func syncUsers() {
}
}

func createDefaultTags() {
func createDefaultTagsAndPolicies() {
networks, err := logic.GetNetworks()
if err != nil {
return
Expand Down
1 change: 1 addition & 0 deletions models/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type AclGroupType string
const (
UserAclID AclGroupType = "user"
UserGroupAclID AclGroupType = "user-group"
UserRoleAclID AclGroupType = "user-role"
DeviceAclID AclGroupType = "tag"
NetmakerIPAclID AclGroupType = "ip"
NetmakerSubNetRangeAClID AclGroupType = "ipset"
Expand Down
9 changes: 6 additions & 3 deletions pro/controllers/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) {
userGws := make(map[string][]models.UserRemoteGws)
networks := []models.Network{}
networkMap := make(map[string]struct{})
userGwNodes := proLogic.GetUserRAGNodes(*user)
userGwNodes := proLogic.GetUserRAGNodesV1(*user)
for _, node := range userGwNodes {
network, err := logic.GetNetwork(node.Network)
if err != nil {
Expand Down Expand Up @@ -876,7 +876,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request)
}
userGws := []models.UserRAGs{}

userGwNodes := proLogic.GetUserRAGNodes(*user)
userGwNodes := proLogic.GetUserRAGNodesV1(*user)
for _, node := range userGwNodes {
if node.Network != network {
continue
Expand Down Expand Up @@ -931,7 +931,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) {
return
}

userGwNodes := proLogic.GetUserRAGNodes(*user)
userGwNodes := proLogic.GetUserRAGNodesV1(*user)
if _, ok := userGwNodes[remoteGwID]; !ok {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden"))
return
Expand Down Expand Up @@ -995,6 +995,9 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) {
if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
userConf.Enabled = parentNetwork.DefaultACL == "yes"
}
userConf.Tags = make(map[models.TagID]struct{})
userConf.Tags[models.TagID(fmt.Sprintf("%s.%s", userConf.Network,
models.RemoteAccessTagName))] = struct{}{}
if err = logic.CreateExtClient(&userConf); err != nil {
slog.Error(
"failed to create extclient",
Expand Down
1 change: 1 addition & 0 deletions pro/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func InitPro() {
logic.IsNetworkRolesValid = proLogic.IsNetworkRolesValid
logic.InitialiseRoles = proLogic.UserRolesInit
logic.UpdateUserGwAccess = proLogic.UpdateUserGwAccess
logic.CreateDefaultUserPolicies = proLogic.CreateDefaultUserPolicies
}

func retrieveProLogo() string {
Expand Down
Loading
Loading