Skip to content

Commit be5cd7f

Browse files
authored
Added flag for operator only features (#144)
Added flag to only enable operator endpoints / links in mcs
1 parent fa068b6 commit be5cd7f

File tree

8 files changed

+239
-124
lines changed

8 files changed

+239
-124
lines changed

pkg/acl/config.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package acl
18+
19+
import (
20+
"strings"
21+
22+
"github.com/minio/minio/pkg/env"
23+
)
24+
25+
// GetOperatorOnly gets mcs operator mode status set on env variable
26+
//or default one
27+
func GetOperatorOnly() string {
28+
return strings.ToLower(env.Get(McsOperatorOnly, "off"))
29+
}

pkg/acl/const.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package acl
18+
19+
const (
20+
McsOperatorOnly = "MCS_OPERATOR_ONLY"
21+
)

pkg/acl/endpoints.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package acl
1818

19-
import iampolicy "github.com/minio/minio/pkg/iam/policy"
19+
import (
20+
iampolicy "github.com/minio/minio/pkg/iam/policy"
21+
)
2022

2123
// endpoints definition
2224
var (
@@ -221,11 +223,18 @@ var endpointRules = map[string]ConfigurationActionSet{
221223
buckets: bucketsActionSet,
222224
bucketsDetail: bucketsActionSet,
223225
serviceAccounts: serviceAccountsActionSet,
224-
clusters: clustersActionSet,
225-
clustersDetail: clustersActionSet,
226226
heal: healActionSet,
227227
}
228228

229+
// operatorRules contains the mapping between endpoints and ActionSets for operator only mode
230+
var operatorRules = map[string]ConfigurationActionSet{
231+
clusters: clustersActionSet,
232+
clustersDetail: clustersActionSet,
233+
}
234+
235+
// operatorOnly ENV variable
236+
var operatorOnly = GetOperatorOnly()
237+
229238
// GetActionsStringFromPolicy extract the admin/s3 actions from a given policy and return them in []string format
230239
//
231240
// ie:
@@ -275,13 +284,19 @@ func actionsStringToActionSet(actions []string) iampolicy.ActionSet {
275284
// GetAuthorizedEndpoints return a list of allowed endpoint based on a provided *iampolicy.Policy
276285
// ie: pages the user should have access based on his current privileges
277286
func GetAuthorizedEndpoints(actions []string) []string {
287+
rangeTake := endpointRules
288+
289+
if operatorOnly == "on" {
290+
rangeTake = operatorRules
291+
}
292+
278293
if len(actions) == 0 {
279294
return []string{}
280295
}
281296
// Prepare new ActionSet structure that will hold all the user actions
282297
userAllowedAction := actionsStringToActionSet(actions)
283298
allowedEndpoints := []string{}
284-
for endpoint, rules := range endpointRules {
299+
for endpoint, rules := range rangeTake {
285300
// check if user policy matches s3:* or admin:* typesIntersection
286301
endpointActionTypes := rules.actionTypes
287302
typesIntersection := endpointActionTypes.Intersection(userAllowedAction)

pkg/acl/endpoints_test.go

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,34 @@ import (
2323
iampolicy "github.com/minio/minio/pkg/iam/policy"
2424
)
2525

26-
func TestGetAuthorizedEndpoints(t *testing.T) {
27-
type args struct {
28-
actions []string
26+
type args struct {
27+
actions []string
28+
}
29+
30+
type endpoint struct {
31+
name string
32+
args args
33+
want int
34+
}
35+
36+
func validateEndpoints(t *testing.T, configs []endpoint) {
37+
for _, tt := range configs {
38+
t.Run(tt.name, func(t *testing.T) {
39+
if got := GetAuthorizedEndpoints(tt.args.actions); !reflect.DeepEqual(len(got), tt.want) {
40+
t.Errorf("GetAuthorizedEndpoints() = %v, want %v", len(got), tt.want)
41+
}
42+
})
2943
}
30-
tests := []struct {
31-
name string
32-
args args
33-
want int
34-
}{
44+
}
45+
46+
func TestGetAuthorizedEndpoints(t *testing.T) {
47+
tests := []endpoint{
3548
{
3649
name: "dashboard endpoint",
3750
args: args{
3851
[]string{"admin:ServerInfo"},
3952
},
40-
want: 4,
53+
want: 2,
4154
},
4255
{
4356
name: "policies endpoint",
@@ -50,7 +63,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
5063
"admin:ListUserPolicies",
5164
},
5265
},
53-
want: 4,
66+
want: 2,
5467
},
5568
{
5669
name: "all admin endpoints",
@@ -59,7 +72,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
5972
"admin:*",
6073
},
6174
},
62-
want: 13,
75+
want: 11,
6376
},
6477
{
6578
name: "all s3 endpoints",
@@ -68,7 +81,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
6881
"s3:*",
6982
},
7083
},
71-
want: 6,
84+
want: 4,
7285
},
7386
{
7487
name: "all admin and s3 endpoints",
@@ -78,7 +91,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
7891
"s3:*",
7992
},
8093
},
81-
want: 16,
94+
want: 14,
8295
},
8396
{
8497
name: "no endpoints",
@@ -88,13 +101,52 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
88101
want: 0,
89102
},
90103
}
91-
for _, tt := range tests {
92-
t.Run(tt.name, func(t *testing.T) {
93-
if got := GetAuthorizedEndpoints(tt.args.actions); !reflect.DeepEqual(len(got), tt.want) {
94-
t.Errorf("GetAuthorizedEndpoints() = %v, want %v", len(got), tt.want)
95-
}
96-
})
104+
105+
validateEndpoints(t, tests)
106+
}
107+
108+
func TestOperatorOnlyEndpoints(t *testing.T) {
109+
operatorOnly = "on"
110+
111+
tests := []endpoint{
112+
{
113+
name: "Operator Only - all admin endpoints",
114+
args: args{
115+
[]string{
116+
"admin:*",
117+
},
118+
},
119+
want: 2,
120+
},
121+
{
122+
name: "Operator Only - all s3 endpoints",
123+
args: args{
124+
[]string{
125+
"s3:*",
126+
},
127+
},
128+
want: 2,
129+
},
130+
{
131+
name: "Operator Only - all admin and s3 endpoints",
132+
args: args{
133+
[]string{
134+
"admin:*",
135+
"s3:*",
136+
},
137+
},
138+
want: 2,
139+
},
140+
{
141+
name: "Operator Only - no endpoints",
142+
args: args{
143+
[]string{},
144+
},
145+
want: 0,
146+
},
97147
}
148+
149+
validateEndpoints(t, tests)
98150
}
99151

100152
func TestGetActionsStringFromPolicy(t *testing.T) {

0 commit comments

Comments
 (0)