1
0
mirror of https://github.com/minio/minio.git synced 2025-04-03 19:30:29 -04:00

add explicit deny support for service accounts ()

creating service accounts is implicitly enabled
for all users, this PR however adds support to
reject creating service accounts, with an explicit
"Deny" policy.
This commit is contained in:
Harshavardhana 2021-11-15 06:57:52 -08:00 committed by GitHub
parent 5a36179c19
commit ac74237f01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 159 additions and 0 deletions

@ -564,6 +564,22 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque
// that targetUser is a real user (i.e. not derived // that targetUser is a real user (i.e. not derived
// credentials). // credentials).
if isSvcAccForRequestor { if isSvcAccForRequestor {
// Check if adding service account is explicitly denied.
//
// This allows turning off service accounts for request sender,
// if there is no deny statement this call is implicitly enabled.
if !globalIAMSys.IsAllowed(iampolicy.Args{
AccountName: requestorUser,
Action: iampolicy.CreateServiceAccountAdminAction,
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
IsOwner: owner,
Claims: claims,
DenyOnly: true,
}) {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
return
}
if requestorIsDerivedCredential { if requestorIsDerivedCredential {
if requestorParentUser == "" { if requestorParentUser == "" {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx,

@ -121,6 +121,18 @@ func (s *TestSuiteIAM) RestartIAMSuite(c *check) {
s.iamSetup(c) s.iamSetup(c)
} }
func (s *TestSuiteIAM) getAdminClient(c *check, accessKey, secretKey, sessionToken string) *madmin.AdminClient {
madmClnt, err := madmin.NewWithOptions(s.endpoint, &madmin.Options{
Creds: credentials.NewStaticV4(accessKey, secretKey, sessionToken),
Secure: s.secure,
})
if err != nil {
c.Fatalf("error creating user admin client: %s", err)
}
madmClnt.SetCustomTransport(s.TestSuiteCommon.client.Transport)
return madmClnt
}
func (s *TestSuiteIAM) getUserClient(c *check, accessKey, secretKey, sessionToken string) *minio.Client { func (s *TestSuiteIAM) getUserClient(c *check, accessKey, secretKey, sessionToken string) *minio.Client {
client, err := minio.New(s.endpoint, &minio.Options{ client, err := minio.New(s.endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKey, secretKey, sessionToken), Creds: credentials.NewStaticV4(accessKey, secretKey, sessionToken),
@ -140,6 +152,7 @@ func runAllIAMTests(suite *TestSuiteIAM, c *check) {
suite.TestCannedPolicies(c) suite.TestCannedPolicies(c)
suite.TestGroupAddRemove(c) suite.TestGroupAddRemove(c)
suite.TestServiceAccountOps(c) suite.TestServiceAccountOps(c)
suite.TestAddServiceAccountPerms(c)
suite.TearDownSuite(c) suite.TearDownSuite(c)
} }
@ -246,6 +259,118 @@ func (s *TestSuiteIAM) TestUserCreate(c *check) {
} }
} }
func (s *TestSuiteIAM) TestAddServiceAccountPerms(c *check) {
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
defer cancel()
// 1. Create a policy
policy1 := "deny-svc"
policy2 := "allow-svc"
policyBytes := []byte(`{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"admin:CreateServiceAccount"
]
}
]
}`)
newPolicyBytes := []byte(`{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::testbucket/*"
]
}
]
}`)
err := s.adm.AddCannedPolicy(ctx, policy1, policyBytes)
if err != nil {
c.Fatalf("policy add error: %v", err)
}
err = s.adm.AddCannedPolicy(ctx, policy2, newPolicyBytes)
if err != nil {
c.Fatalf("policy add error: %v", err)
}
// 2. Verify that policy json is validated by server
invalidPolicyBytes := policyBytes[:len(policyBytes)-1]
err = s.adm.AddCannedPolicy(ctx, policy1+"invalid", invalidPolicyBytes)
if err == nil {
c.Fatalf("invalid policy creation success")
}
// 3. Create a user, associate policy and verify access
accessKey, secretKey := mustGenerateCredentials(c)
err = s.adm.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
if err != nil {
c.Fatalf("Unable to set user: %v", err)
}
// 3.1 check that user does not have any access to the bucket
uClient := s.getUserClient(c, accessKey, secretKey, "")
c.mustNotListObjects(ctx, uClient, "testbucket")
// 3.2 associate policy to user
err = s.adm.SetPolicy(ctx, policy1, accessKey, false)
if err != nil {
c.Fatalf("Unable to set policy: %v", err)
}
admClnt := s.getAdminClient(c, accessKey, secretKey, "")
// 3.3 check user does not have explicit permissions to create service account.
c.mustNotCreateSvcAccount(ctx, accessKey, admClnt)
// 4. Verify the policy appears in listing
ps, err := s.adm.ListCannedPolicies(ctx)
if err != nil {
c.Fatalf("policy list err: %v", err)
}
_, ok := ps[policy1]
if !ok {
c.Fatalf("policy was missing!")
}
// 3.2 associate policy to user
err = s.adm.SetPolicy(ctx, policy2, accessKey, false)
if err != nil {
c.Fatalf("Unable to set policy: %v", err)
}
// 3.3 check user can create service account implicitly.
c.mustCreateSvcAccount(ctx, accessKey, admClnt)
_, ok = ps[policy2]
if !ok {
c.Fatalf("policy was missing!")
}
err = s.adm.RemoveUser(ctx, accessKey)
if err != nil {
c.Fatalf("user could not be deleted: %v", err)
}
err = s.adm.RemoveCannedPolicy(ctx, policy1)
if err != nil {
c.Fatalf("policy del err: %v", err)
}
err = s.adm.RemoveCannedPolicy(ctx, policy2)
if err != nil {
c.Fatalf("policy del err: %v", err)
}
}
func (s *TestSuiteIAM) TestPolicyCreate(c *check) { func (s *TestSuiteIAM) TestPolicyCreate(c *check) {
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout) ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
defer cancel() defer cancel()
@ -750,6 +875,24 @@ func (s *TestSuiteIAM) TestServiceAccountOps(c *check) {
} }
} }
func (c *check) mustCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) {
_, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
TargetUser: tgtUser,
})
if err != nil {
c.Fatalf("user should be able to create service accounts %s", err)
}
}
func (c *check) mustNotCreateSvcAccount(ctx context.Context, tgtUser string, admClnt *madmin.AdminClient) {
_, err := admClnt.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
TargetUser: tgtUser,
})
if err == nil {
c.Fatalf("user was able to add service accounts unexpectedly!")
}
}
func (c *check) mustNotListObjects(ctx context.Context, client *minio.Client, bucket string) { func (c *check) mustNotListObjects(ctx context.Context, client *minio.Client, bucket string) {
res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) res := client.ListObjects(ctx, bucket, minio.ListObjectsOptions{})
v, ok := <-res v, ok := <-res