Add support for multiple admins (#8487)

Also define IAM policies for administering
MinIO server
This commit is contained in:
poornas
2019-11-19 02:03:18 -08:00
committed by kannappanr
parent 13a3d17321
commit 929951fd49
11 changed files with 401 additions and 54 deletions

View File

@@ -145,7 +145,7 @@ func (action Action) IsValid() bool {
// MarshalJSON - encodes Action to JSON data.
func (action Action) MarshalJSON() ([]byte, error) {
if action.IsValid() {
if action.IsValid() || AdminAction(action).IsValid() {
return json.Marshal(string(action))
}
@@ -171,6 +171,10 @@ func (action *Action) UnmarshalJSON(data []byte) error {
}
func parseAction(s string) (Action, error) {
adminAction, err := parseAdminAction(s)
if err == nil {
return Action(adminAction), nil
}
action := Action(s)
if action.IsValid() {

View File

@@ -0,0 +1,154 @@
/*
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package iampolicy
import (
"fmt"
"github.com/minio/minio/pkg/policy/condition"
)
// AdminAction - admin policy action.
type AdminAction string
const (
// HealAdminAction - allows heal command
HealAdminAction = "admin:Heal"
// Service Actions
// ListServerInfoAdminAction - allow listing server info
ListServerInfoAdminAction = "admin:ListServerInfo"
// ServerUpdateAdminAction - allow MinIO binary update
ServerUpdateAdminAction = "admin:ServerUpdate"
//Config Actions
// ConfigUpdateAdminAction - allow MinIO config management
ConfigUpdateAdminAction = "admin:ConfigUpdate"
// User Actions
// CreateUserAdminAction - allow creating MinIO user
CreateUserAdminAction = "admin:CreateUser"
// DeleteUserAdminAction - allow deleting MinIO user
DeleteUserAdminAction = "admin:DeleteUser"
// ListUsersAdminAction - allow list users permission
ListUsersAdminAction = "admin:ListUsers"
// EnableUserAdminAction - allow enable user permission
EnableUserAdminAction = "admin:EnableUser"
// DisableUserAdminAction - allow disable user permission
DisableUserAdminAction = "admin:DisableUser"
// GetUserAdminAction - allows GET permission on user info
GetUserAdminAction = "admin:GetUser"
// Group Actions
// AddUserToGroupAdminAction - allow adding user to group permission
AddUserToGroupAdminAction = "admin:AddUserToGroup"
// RemoveUserFromGroupAdminAction - allow removing user to group permission
RemoveUserFromGroupAdminAction = "admin:RemoveUserFromGroup"
// GetGroupAdminAction - allow getting group info
GetGroupAdminAction = "admin:GetGroup"
// ListGroupsAdminAction - allow list groups permission
ListGroupsAdminAction = "admin:ListGroups"
// EnableGroupAdminAction - allow enable group permission
EnableGroupAdminAction = "admin:EnableGroup"
// DisableGroupAdminAction - allow disable group permission
DisableGroupAdminAction = "admin:DisableGroup"
// Policy Actions
// CreatePolicyAdminAction - allow create policy permission
CreatePolicyAdminAction = "admin:CreatePolicy"
// DeletePolicyAdminAction - allow delete policy permission
DeletePolicyAdminAction = "admin:DeletePolicy"
// GetPolicyAdminAction - allow get policy permission
GetPolicyAdminAction = "admin:GetPolicy"
// AttachPolicyAdminAction - allows attaching a policy to a user/group
AttachPolicyAdminAction = "admin:AttachUserOrGroupPolicy"
// ListUserPoliciesAdminAction - allows listing user policies
ListUserPoliciesAdminAction = "admin:ListUserPolicies"
// AllAdminActions - provides all admin permissions
AllAdminActions = "admin:*"
)
// List of all supported admin actions.
var supportedAdminActions = map[AdminAction]struct{}{
AllAdminActions: {},
HealAdminAction: {},
ListServerInfoAdminAction: {},
ServerUpdateAdminAction: {},
ConfigUpdateAdminAction: {},
CreateUserAdminAction: {},
DeleteUserAdminAction: {},
ListUsersAdminAction: {},
EnableUserAdminAction: {},
DisableUserAdminAction: {},
GetUserAdminAction: {},
AddUserToGroupAdminAction: {},
RemoveUserFromGroupAdminAction: {},
ListGroupsAdminAction: {},
EnableGroupAdminAction: {},
DisableGroupAdminAction: {},
CreatePolicyAdminAction: {},
DeletePolicyAdminAction: {},
GetPolicyAdminAction: {},
AttachPolicyAdminAction: {},
ListUserPoliciesAdminAction: {},
}
func parseAdminAction(s string) (AdminAction, error) {
action := AdminAction(s)
if action.IsValid() {
return action, nil
}
return action, fmt.Errorf("unsupported action '%v'", s)
}
// IsValid - checks if action is valid or not.
func (action AdminAction) IsValid() bool {
_, ok := supportedAdminActions[action]
return ok
}
// adminActionConditionKeyMap - holds mapping of supported condition key for an action.
var adminActionConditionKeyMap = map[Action]condition.KeySet{
AllAdminActions: condition.NewKeySet(condition.AllSupportedAdminKeys...),
HealAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ListServerInfoAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ServerUpdateAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ConfigUpdateAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
CreateUserAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
DeleteUserAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ListUsersAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
EnableUserAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
DisableUserAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
GetUserAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
AddUserToGroupAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
RemoveUserFromGroupAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ListGroupsAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
EnableGroupAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
DisableGroupAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
CreatePolicyAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
DeletePolicyAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
GetPolicyAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
AttachPolicyAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
ListUserPoliciesAdminAction: condition.NewKeySet(condition.AllSupportedAdminKeys...),
}

View File

@@ -30,7 +30,7 @@ type Statement struct {
SID policy.ID `json:"Sid,omitempty"`
Effect policy.Effect `json:"Effect"`
Actions ActionSet `json:"Action"`
Resources ResourceSet `json:"Resource"`
Resources ResourceSet `json:"Resource,omitempty"`
Conditions condition.Functions `json:"Condition,omitempty"`
}
@@ -52,7 +52,8 @@ func (statement Statement) IsAllowed(args Args) bool {
resource += "/"
}
if !statement.Resources.Match(resource, args.ConditionValues) {
// For admin statements, resource match can be ignored.
if !statement.Resources.Match(resource, args.ConditionValues) && !statement.isAdmin() {
return false
}
@@ -61,6 +62,14 @@ func (statement Statement) IsAllowed(args Args) bool {
return statement.Effect.IsAllowed(check())
}
func (statement Statement) isAdmin() bool {
for action := range statement.Actions {
if !AdminAction(action).IsValid() {
return false
}
}
return true
}
// isValid - checks whether statement is valid or not.
func (statement Statement) isValid() error {
@@ -72,6 +81,17 @@ func (statement Statement) isValid() error {
return fmt.Errorf("Action must not be empty")
}
if statement.isAdmin() {
for action := range statement.Actions {
keys := statement.Conditions.Keys()
keyDiff := keys.Difference(adminActionConditionKeyMap[action])
if !keyDiff.IsEmpty() {
return fmt.Errorf("unsupported condition keys '%v' used for action '%v'", keyDiff, action)
}
}
return nil
}
if len(statement.Resources) == 0 {
return fmt.Errorf("Resource must not be empty")
}

View File

@@ -183,6 +183,14 @@ func TestStatementIsValid(t *testing.T) {
t.Fatalf("unexpected error. %v\n", err)
}
func3, err := condition.NewStringEqualsFunc(
condition.AWSUserAgent,
"NSPlayer",
)
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
testCases := []struct {
statement Statement
expectErr bool
@@ -233,6 +241,18 @@ func TestStatementIsValid(t *testing.T) {
NewResourceSet(NewResource("mybucket", "myobject*")),
condition.NewFunctions(func1),
), false},
{NewStatement(
policy.Allow,
NewActionSet(CreateUserAdminAction, DeleteUserAdminAction),
nil,
condition.NewFunctions(func2, func3),
), true},
{NewStatement(
policy.Allow,
NewActionSet(CreateUserAdminAction, DeleteUserAdminAction),
nil,
condition.NewFunctions(),
), false},
}
for i, testCase := range testCases {

View File

@@ -272,3 +272,14 @@ func NewKeySet(keys ...Key) KeySet {
return set
}
// AllSupportedAdminKeys - is list of all admin supported keys.
var AllSupportedAdminKeys = []Key{
AWSReferer,
AWSSourceIP,
AWSUserAgent,
AWSSecureTransport,
AWSCurrentTime,
AWSEpochTime,
// Add new supported condition keys.
}