Browse Source

added s3 iam DeleteBucket permission management (#5599)

pull/5601/head
Riccardo Bertossa 9 months ago
committed by GitHub
parent
commit
f6e8a9bf9c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      weed/iamapi/iamapi_management_handlers.go
  2. 4
      weed/s3api/auth_credentials.go
  3. 15
      weed/s3api/auth_credentials_test.go
  4. 15
      weed/s3api/s3_constants/s3_actions.go
  5. 2
      weed/s3api/s3_constants/s3_config.go
  6. 12
      weed/s3api/s3api_bucket_handlers.go
  7. 2
      weed/s3api/s3api_server.go

5
weed/iamapi/iamapi_management_handlers.go

@ -33,6 +33,7 @@ const (
StatementActionReadAcp = "GetBucketAcl" StatementActionReadAcp = "GetBucketAcl"
StatementActionList = "List*" StatementActionList = "List*"
StatementActionTagging = "Tagging*" StatementActionTagging = "Tagging*"
StatementActionDelete = "DeleteBucket*"
) )
var ( var (
@ -58,6 +59,8 @@ func MapToStatementAction(action string) string {
return s3_constants.ACTION_LIST return s3_constants.ACTION_LIST
case StatementActionTagging: case StatementActionTagging:
return s3_constants.ACTION_TAGGING return s3_constants.ACTION_TAGGING
case StatementActionDelete:
return s3_constants.ACTION_DELETE_BUCKET
default: default:
return "" return ""
} }
@ -79,6 +82,8 @@ func MapToIdentitiesAction(action string) string {
return StatementActionList return StatementActionList
case s3_constants.ACTION_TAGGING: case s3_constants.ACTION_TAGGING:
return StatementActionTagging return StatementActionTagging
case s3_constants.ACTION_DELETE_BUCKET:
return StatementActionDelete
default: default:
return "" return ""
} }

4
weed/s3api/auth_credentials.go

@ -317,6 +317,7 @@ func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) htt
} }
identity, errCode := iam.authRequest(r, action) identity, errCode := iam.authRequest(r, action)
glog.V(3).Infof("auth error: %v", errCode)
if errCode == s3err.ErrNone { if errCode == s3err.ErrNone {
if identity != nil && identity.Name != "" { if identity != nil && identity.Name != "" {
r.Header.Set(s3_constants.AmzIdentityId, identity.Name) r.Header.Set(s3_constants.AmzIdentityId, identity.Name)
@ -453,6 +454,7 @@ func (identity *Identity) canDo(action Action, bucket string, objectKey string)
} }
} }
if bucket == "" { if bucket == "" {
glog.V(3).Infof("identity %s is not allowed to perform action %s on %s -- bucket is empty", identity.Name, action, bucket+objectKey)
return false return false
} }
target := string(action) + ":" + bucket + objectKey target := string(action) + ":" + bucket + objectKey
@ -477,6 +479,8 @@ func (identity *Identity) canDo(action Action, bucket string, objectKey string)
} }
} }
} }
//log error
glog.V(3).Infof("identity %s is not allowed to perform action %s on %s", identity.Name, action, bucket+objectKey)
return false return false
} }

15
weed/s3api/auth_credentials_test.go

@ -1,11 +1,12 @@
package s3api package s3api
import ( import (
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/stretchr/testify/assert"
"reflect" "reflect"
"testing" "testing"
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/stretchr/testify/assert"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
jsonpb "google.golang.org/protobuf/encoding/protojson" jsonpb "google.golang.org/protobuf/encoding/protojson"
) )
@ -79,6 +80,7 @@ func TestCanDo(t *testing.T) {
} }
// object specific // object specific
assert.Equal(t, true, ident1.canDo(ACTION_WRITE, "bucket1", "/a/b/c/d.txt")) assert.Equal(t, true, ident1.canDo(ACTION_WRITE, "bucket1", "/a/b/c/d.txt"))
assert.Equal(t, false, ident1.canDo(ACTION_DELETE_BUCKET, "bucket1", ""))
assert.Equal(t, false, ident1.canDo(ACTION_WRITE, "bucket1", "/a/b/other/some"), "action without *") assert.Equal(t, false, ident1.canDo(ACTION_WRITE, "bucket1", "/a/b/other/some"), "action without *")
// bucket specific // bucket specific
@ -141,6 +143,15 @@ func TestCanDo(t *testing.T) {
}, },
} }
assert.Equal(t, true, ident6.canDo(ACTION_READ, "anything_bucket", "/a/b/c/d.txt")) assert.Equal(t, true, ident6.canDo(ACTION_READ, "anything_bucket", "/a/b/c/d.txt"))
//test deleteBucket operation
ident7 := &Identity{
Name: "anything",
Actions: []Action{
"DeleteBucket:bucket1",
},
}
assert.Equal(t, true, ident7.canDo(ACTION_DELETE_BUCKET, "bucket1", ""))
} }
type LoadS3ApiConfigurationTestCase struct { type LoadS3ApiConfigurationTestCase struct {

15
weed/s3api/s3_constants/s3_actions.go

@ -1,13 +1,14 @@
package s3_constants package s3_constants
const ( const (
ACTION_READ = "Read"
ACTION_READ_ACP = "ReadAcp"
ACTION_WRITE = "Write"
ACTION_WRITE_ACP = "WriteAcp"
ACTION_ADMIN = "Admin"
ACTION_TAGGING = "Tagging"
ACTION_LIST = "List"
ACTION_READ = "Read"
ACTION_READ_ACP = "ReadAcp"
ACTION_WRITE = "Write"
ACTION_WRITE_ACP = "WriteAcp"
ACTION_ADMIN = "Admin"
ACTION_TAGGING = "Tagging"
ACTION_LIST = "List"
ACTION_DELETE_BUCKET = "DeleteBucket"
SeaweedStorageDestinationHeader = "x-seaweedfs-destination" SeaweedStorageDestinationHeader = "x-seaweedfs-destination"
MultipartUploadsFolder = ".uploads" MultipartUploadsFolder = ".uploads"

2
weed/s3api/s3_constants/s3_config.go

@ -7,7 +7,7 @@ import (
var ( var (
CircuitBreakerConfigDir = "/etc/s3" CircuitBreakerConfigDir = "/etc/s3"
CircuitBreakerConfigFile = "circuit_breaker.json" CircuitBreakerConfigFile = "circuit_breaker.json"
AllowedActions = []string{ACTION_READ, ACTION_READ_ACP, ACTION_WRITE, ACTION_WRITE_ACP, ACTION_LIST, ACTION_TAGGING, ACTION_ADMIN}
AllowedActions = []string{ACTION_READ, ACTION_READ_ACP, ACTION_WRITE, ACTION_WRITE_ACP, ACTION_LIST, ACTION_TAGGING, ACTION_ADMIN, ACTION_DELETE_BUCKET}
LimitTypeCount = "Count" LimitTypeCount = "Count"
LimitTypeBytes = "MB" LimitTypeBytes = "MB"
Separator = ":" Separator = ":"

12
weed/s3api/s3api_bucket_handlers.go

@ -6,14 +6,15 @@ import (
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3bucket"
"github.com/seaweedfs/seaweedfs/weed/util"
"math" "math"
"net/http" "net/http"
"strings" "strings"
"time" "time"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3bucket"
"github.com/seaweedfs/seaweedfs/weed/util"
"github.com/seaweedfs/seaweedfs/weed/filer" "github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants" "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/storage/needle" "github.com/seaweedfs/seaweedfs/weed/storage/needle"
@ -218,6 +219,10 @@ func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorC
return s3err.ErrNoSuchBucket return s3err.ErrNoSuchBucket
} }
//if iam is enabled, the access was already checked before
if s3a.iam.isEnabled() {
return s3err.ErrNone
}
if !s3a.hasAccess(r, entry) { if !s3a.hasAccess(r, entry) {
return s3err.ErrAccessDenied return s3err.ErrAccessDenied
} }
@ -236,6 +241,7 @@ func (s3a *S3ApiServer) hasAccess(r *http.Request, entry *filer_pb.Entry) bool {
identityId := r.Header.Get(s3_constants.AmzIdentityId) identityId := r.Header.Get(s3_constants.AmzIdentityId)
if id, ok := entry.Extended[s3_constants.AmzIdentityId]; ok { if id, ok := entry.Extended[s3_constants.AmzIdentityId]; ok {
if identityId != string(id) { if identityId != string(id) {
glog.V(3).Infof("hasAccess: %s != %s (entry.Extended = %v)", identityId, id, entry.Extended)
return false return false
} }
} }

2
weed/s3api/s3api_server.go

@ -279,7 +279,7 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
bucket.Methods("PUT").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketHandler, ACTION_ADMIN)), "PUT")) bucket.Methods("PUT").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketHandler, ACTION_ADMIN)), "PUT"))
// DeleteBucket // DeleteBucket
bucket.Methods("DELETE").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.DeleteBucketHandler, ACTION_ADMIN)), "DELETE"))
bucket.Methods("DELETE").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.DeleteBucketHandler, ACTION_DELETE_BUCKET)), "DELETE"))
// ListObjectsV1 (Legacy) // ListObjectsV1 (Legacy)
bucket.Methods("GET").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.ListObjectsV1Handler, ACTION_LIST)), "LIST")) bucket.Methods("GET").HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.ListObjectsV1Handler, ACTION_LIST)), "LIST"))

Loading…
Cancel
Save