mirror of
https://github.com/minio/minio.git
synced 2025-11-09 05:34:56 -05:00
fix: check sub-policy properly when present (#21642)
This fixes a security issue where sub-policy attached to a service account or STS account is not properly validated under certain "own" account operations (like creating new service accounts). This allowed a service account to create new service accounts for the same user bypassing the inline policy restriction.
This commit is contained in:
committed by
GitHub
parent
334c313da4
commit
c1a49490c7
@@ -208,6 +208,8 @@ func TestIAMInternalIDPServerSuite(t *testing.T) {
|
||||
suite.TestGroupAddRemove(c)
|
||||
suite.TestServiceAccountOpsByAdmin(c)
|
||||
suite.TestServiceAccountPrivilegeEscalationBug(c)
|
||||
suite.TestServiceAccountPrivilegeEscalationBug2_2025_10_15(c, true)
|
||||
suite.TestServiceAccountPrivilegeEscalationBug2_2025_10_15(c, false)
|
||||
suite.TestServiceAccountOpsByUser(c)
|
||||
suite.TestServiceAccountDurationSecondsCondition(c)
|
||||
suite.TestAddServiceAccountPerms(c)
|
||||
@@ -1249,6 +1251,108 @@ func (s *TestSuiteIAM) TestServiceAccountPrivilegeEscalationBug(c *check) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TestSuiteIAM) TestServiceAccountPrivilegeEscalationBug2_2025_10_15(c *check, forRoot bool) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
for i := range 3 {
|
||||
err := s.client.MakeBucket(ctx, fmt.Sprintf("bucket%d", i+1), minio.MakeBucketOptions{})
|
||||
if err != nil {
|
||||
c.Fatalf("bucket create error: %v", err)
|
||||
}
|
||||
defer func(i int) {
|
||||
_ = s.client.RemoveBucket(ctx, fmt.Sprintf("bucket%d", i+1))
|
||||
}(i)
|
||||
}
|
||||
|
||||
allow2BucketsPolicyBytes := []byte(`{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "ListBucket1AndBucket2",
|
||||
"Effect": "Allow",
|
||||
"Action": ["s3:ListBucket"],
|
||||
"Resource": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2"]
|
||||
},
|
||||
{
|
||||
"Sid": "ReadWriteBucket1AndBucket2Objects",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:DeleteObject",
|
||||
"s3:DeleteObjectVersion",
|
||||
"s3:GetObject",
|
||||
"s3:GetObjectVersion",
|
||||
"s3:PutObject"
|
||||
],
|
||||
"Resource": ["arn:aws:s3:::bucket1/*", "arn:aws:s3:::bucket2/*"]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
if forRoot {
|
||||
// Create a service account for the root user.
|
||||
_, err := s.adm.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
|
||||
Policy: allow2BucketsPolicyBytes,
|
||||
AccessKey: "restricted",
|
||||
SecretKey: "restricted123",
|
||||
})
|
||||
if err != nil {
|
||||
c.Fatalf("could not create service account")
|
||||
}
|
||||
defer func() {
|
||||
_ = s.adm.DeleteServiceAccount(ctx, "restricted")
|
||||
}()
|
||||
} else {
|
||||
// Create a regular user and attach consoleAdmin policy
|
||||
err := s.adm.AddUser(ctx, "foobar", "foobar123")
|
||||
if err != nil {
|
||||
c.Fatalf("could not create user")
|
||||
}
|
||||
|
||||
_, err = s.adm.AttachPolicy(ctx, madmin.PolicyAssociationReq{
|
||||
Policies: []string{"consoleAdmin"},
|
||||
User: "foobar",
|
||||
})
|
||||
if err != nil {
|
||||
c.Fatalf("could not attach policy")
|
||||
}
|
||||
|
||||
// Create a service account for the regular user.
|
||||
_, err = s.adm.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
|
||||
Policy: allow2BucketsPolicyBytes,
|
||||
TargetUser: "foobar",
|
||||
AccessKey: "restricted",
|
||||
SecretKey: "restricted123",
|
||||
})
|
||||
if err != nil {
|
||||
c.Fatalf("could not create service account: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = s.adm.DeleteServiceAccount(ctx, "restricted")
|
||||
_ = s.adm.RemoveUser(ctx, "foobar")
|
||||
}()
|
||||
}
|
||||
restrictedClient := s.getUserClient(c, "restricted", "restricted123", "")
|
||||
|
||||
buckets, err := restrictedClient.ListBuckets(ctx)
|
||||
if err != nil {
|
||||
c.Fatalf("err fetching buckets %s", err)
|
||||
}
|
||||
if len(buckets) != 2 || buckets[0].Name != "bucket1" || buckets[1].Name != "bucket2" {
|
||||
c.Fatalf("restricted service account should only have access to bucket1 and bucket2")
|
||||
}
|
||||
|
||||
// Try to escalate privileges
|
||||
restrictedAdmClient := s.getAdminClient(c, "restricted", "restricted123", "")
|
||||
_, err = restrictedAdmClient.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
|
||||
AccessKey: "newroot",
|
||||
SecretKey: "newroot123",
|
||||
})
|
||||
if err == nil {
|
||||
c.Fatalf("restricted service account was able to create service account bypassing sub-policy!")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TestSuiteIAM) SetUpAccMgmtPlugin(c *check) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testDefaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
Reference in New Issue
Block a user