Skip to content

Commit

Permalink
ACL for mcs
Browse files Browse the repository at this point in the history
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users, currently mcsAdmin policy uses admin:* and s3:*, we
are assuming users have access to everything which is not good.

We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.

In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:

```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
    iampolicy.ListGroupsAdminAction,
    iampolicy.AddUserToGroupAdminAction,
    //iampolicy.GetGroupAdminAction,
    iampolicy.EnableGroupAdminAction,
    iampolicy.DisableGroupAdminAction,
)

// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
    iampolicy.GetPolicyAdminAction,
    iampolicy.DeletePolicyAdminAction,
    iampolicy.CreatePolicyAdminAction,
    iampolicy.AttachPolicyAdminAction,
    iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
  • Loading branch information
Alevsk committed May 15, 2020
1 parent acf480f commit afe5f04
Show file tree
Hide file tree
Showing 19 changed files with 937 additions and 367 deletions.
75 changes: 55 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,61 @@ $ set -o history
```
$ cat > mcsAdmin.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"admin:*"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
"Version": "2012-10-17",
"Statement": [{
"Action": [
"admin:ServerInfo",
"admin:CreatePolicy",
"admin:DeletePolicy",
"admin:GetPolicy",
"admin:AttachUserOrGroupPolicy",
"admin:ListUserPolicies",
"admin:ConfigUpdate",
"admin:ConsoleLog",
"admin:AddUserToGroup",
"admin:RemoveUserFromGroup",
"admin:ListGroups",
"admin:EnableGroup",
"admin:DisableGroup",
"admin:Profiling",
"admin:ServerTrace",
"admin:CreateUser",
"admin:DeleteUser",
"admin:ListUsers",
"admin:EnableUser",
"admin:DisableUser",
"admin:GetUser"
],
"Effect": "Allow",
"Sid": ""
},
{
"Action": [
"s3:ListenBucketNotification",
"s3:PutBucketNotification",
"s3:GetBucketNotification",
"s3:ListMultipartUploadParts",
"s3:ListBucketMultipartUploads",
"s3:ListBucket",
"s3:HeadBucket",
"s3:GetObject",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteBucket",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:GetBucketPolicy"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
],
"Sid": ""
}
]
}
EOF
$ mc admin policy add myminio mcsAdmin mcsAdmin.json
Expand Down
3 changes: 3 additions & 0 deletions models/session_response.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

199 changes: 199 additions & 0 deletions pkg/acl/endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package acl

import iampolicy "github.com/minio/minio/pkg/iam/policy"

// endpoints definition
var (
configuration = "/configurations-list"
users = "/users"
groups = "/groups"
iamPolicies = "/policies"
dashboard = "/dashboard"
profiling = "/profiling"
trace = "/trace"
logs = "/logs"
watch = "/watch"
notifications = "/notification-endpoints"
buckets = "/buckets"
)

// configurationActionSet contains the list of admin actions required for this endpoint to work
var configurationActionSet = iampolicy.NewActionSet(
iampolicy.ConfigUpdateAdminAction,
)

// logsActionSet contains the list of admin actions required for this endpoint to work
var logsActionSet = iampolicy.NewActionSet(
iampolicy.ConsoleLogAdminAction,
)

// dashboardActionSet contains the list of admin actions required for this endpoint to work
var dashboardActionSet = iampolicy.NewActionSet(
iampolicy.ServerInfoAdminAction,
)

// groupsActionSet contains the list of admin actions required for this endpoint to work
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)

// iamPoliciesActionSet contains the list of admin actions required for this endpoint to work
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)

// profilingActionSet contains the list of admin actions required for this endpoint to work
var profilingActionSet = iampolicy.NewActionSet(
iampolicy.ProfilingAdminAction,
)

// traceActionSet contains the list of admin actions required for this endpoint to work
var traceActionSet = iampolicy.NewActionSet(
iampolicy.TraceAdminAction,
)

// usersActionSet contains the list of admin actions required for this endpoint to work
var usersActionSet = iampolicy.NewActionSet(
iampolicy.ListUsersAdminAction,
iampolicy.CreateUserAdminAction,
iampolicy.DeleteUserAdminAction,
iampolicy.GetUserAdminAction,
iampolicy.EnableUserAdminAction,
iampolicy.DisableUserAdminAction,
)

// watchActionSet contains the list of admin actions required for this endpoint to work
var watchActionSet = iampolicy.NewActionSet(
iampolicy.ListenBucketNotificationAction,
)

// notificationsActionSet contains the list of admin actions required for this endpoint to work
var notificationsActionSet = iampolicy.NewActionSet(
iampolicy.ListenBucketNotificationAction,
iampolicy.PutBucketNotificationAction,
iampolicy.GetBucketNotificationAction,
)

// bucketsActionSet contains the list of admin actions required for this endpoint to work
var bucketsActionSet = iampolicy.NewActionSet(
// Read access to buckets
iampolicy.ListMultipartUploadPartsAction,
iampolicy.ListBucketMultipartUploadsAction,
iampolicy.ListBucketAction,
iampolicy.HeadBucketAction,
iampolicy.GetObjectAction,
iampolicy.GetBucketLocationAction,
// Write access to buckets
iampolicy.AbortMultipartUploadAction,
iampolicy.CreateBucketAction,
iampolicy.PutObjectAction,
iampolicy.DeleteObjectAction,
iampolicy.DeleteBucketAction,
// Assign bucket policies
iampolicy.PutBucketPolicyAction,
iampolicy.DeleteBucketPolicyAction,
iampolicy.GetBucketPolicyAction,
)

// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
var endpointRules = map[string]iampolicy.ActionSet{
configuration: configurationActionSet,
users: usersActionSet,
groups: groupsActionSet,
iamPolicies: iamPoliciesActionSet,
dashboard: dashboardActionSet,
profiling: profilingActionSet,
trace: traceActionSet,
logs: logsActionSet,
watch: watchActionSet,
notifications: notificationsActionSet,
buckets: bucketsActionSet,
}

// GetActionsStringFromPolicy extract the admin/s3 actions from a given policy and return them in []string format
//
// ie:
// {
// "Version": "2012-10-17",
// "Statement": [{
// "Action": [
// "admin:ServerInfo",
// "admin:CreatePolicy",
// "admin:GetUser"
// ],
// ...
// },
// {
// "Action": [
// "s3:ListenBucketNotification",
// "s3:PutBucketNotification"
// ],
// ...
// }
// ]
// }
// Will produce an array like: ["admin:ServerInfo", "admin:CreatePolicy", "admin:GetUser", "s3:ListenBucketNotification", "s3:PutBucketNotification"]\
func GetActionsStringFromPolicy(policy *iampolicy.Policy) []string {
var actions []string
for _, statement := range policy.Statements {
// We only care about allowed actions
if statement.Effect.IsAllowed(true) {
for _, action := range statement.Actions.ToSlice() {
actions = append(actions, string(action))
}
}
}
return actions
}

// actionsStringToActionSet convert a given string array to iampolicy.ActionSet structure
// this avoids ending with duplicate actions
func actionsStringToActionSet(actions []string) iampolicy.ActionSet {
actionsSet := iampolicy.ActionSet{}
for _, action := range actions {
actionsSet.Add(iampolicy.Action(action))
}
return actionsSet
}

// GetAuthorizedEndpoints return a list of allowed endpoint based on a provided *iampolicy.Policy
// ie: pages the user should have access based on his current privileges
func GetAuthorizedEndpoints(actions []string) []string {
if len(actions) == 0 {
return []string{}
}
// Prepare new ActionSet structure that will hold all the user actions
userAllActionSet := actionsStringToActionSet(actions)
var allowedEndpoints []string
for endpoint, rules := range endpointRules {
actions := rules.Intersection(userAllActionSet)
if len(actions) == len(rules.ToSlice()) {
allowedEndpoints = append(allowedEndpoints, endpoint)
}
}
return allowedEndpoints
}
Loading

0 comments on commit afe5f04

Please sign in to comment.