Browse Source

Prefer IAM path when policies exist

pull/8388/head
Chris Lu 1 day ago
parent
commit
30b36f149e
  1. 99
      test/s3tables/table-buckets/s3tables_integration_test.go
  2. 9
      test/s3tables/table-buckets/setup.go
  3. 5
      weed/s3api/s3tables/handler_bucket_create.go
  4. 14
      weed/s3api/s3tables/iam.go

99
test/s3tables/table-buckets/s3tables_integration_test.go

@ -70,6 +70,92 @@ func TestS3TablesIntegration(t *testing.T) {
})
}
func TestS3TablesCreateBucketIAMPolicy(t *testing.T) {
if testing.Short() {
t.Skip("Skipping IAM integration test in short mode")
}
t.Setenv("AWS_ACCESS_KEY_ID", "env-admin")
t.Setenv("AWS_SECRET_ACCESS_KEY", "env-secret")
allowedBucket := "tables-allowed"
deniedBucket := "tables-denied"
iamConfigDir := t.TempDir()
iamConfigPath := filepath.Join(iamConfigDir, "iam_config.json")
iamConfig := fmt.Sprintf(`{
"sts": {
"tokenDuration": "1h",
"maxSessionLength": "12h",
"issuer": "seaweedfs-sts",
"signingKey": "%s"
},
"accounts": [
{
"id": "%s",
"displayName": "tables-integration"
}
],
"identities": [
{
"name": "admin",
"credentials": [
{
"accessKey": "%s",
"secretKey": "%s"
}
],
"account": {
"id": "%s",
"displayName": "tables-integration"
},
"policyNames": ["S3TablesBucketPolicy"]
}
],
"policy": {
"defaultEffect": "Deny",
"storeType": "memory"
},
"policies": [
{
"name": "S3TablesBucketPolicy",
"document": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3tables:CreateTableBucket"],
"Resource": [
"arn:aws:s3tables:%s:%s:bucket/%s",
"arn:aws:s3:::%s"
]
}
]
}
}
]
}`, testIAMSigningKey, testAccountID, testAccessKey, testSecretKey, testAccountID, testRegion, testAccountID, allowedBucket, allowedBucket)
require.NoError(t, os.WriteFile(iamConfigPath, []byte(iamConfig), 0644))
cluster, err := startMiniClusterWithExtraArgs(t, []string{
"-s3.config=" + iamConfigPath,
"-s3.iam.config=" + iamConfigPath,
})
require.NoError(t, err, "failed to start cluster with IAM config")
defer cluster.Stop()
client := NewS3TablesClient(cluster.s3Endpoint, testRegion, testAccessKey, testSecretKey)
_, err = client.CreateTableBucket(deniedBucket, nil)
require.Error(t, err, "denied bucket creation should fail")
assert.Contains(t, err.Error(), "AccessDenied")
allowedResp, err := client.CreateTableBucket(allowedBucket, nil)
require.NoError(t, err, "allowed bucket creation should succeed")
defer func() {
_ = client.DeleteTableBucket(allowedResp.ARN)
}()
}
func testTableBucketLifecycle(t *testing.T, client *S3TablesClient) {
bucketName := "test-bucket-" + randomString(8)
@ -509,7 +595,7 @@ func findAvailablePorts(n int) ([]int, error) {
}
// startMiniCluster starts a weed mini instance directly without exec
func startMiniCluster(t *testing.T) (*TestCluster, error) {
func startMiniClusterWithExtraArgs(t *testing.T, extraArgs []string) (*TestCluster, error) {
// Find available ports
// We need 8 unique ports: Master(2), Volume(2), Filer(2), S3(2)
ports, err := findAvailablePorts(8)
@ -585,8 +671,7 @@ func startMiniCluster(t *testing.T) (*TestCluster, error) {
os.Chdir(testDir)
// Configure args for mini command
os.Args = []string{
"weed",
baseArgs := []string{
"-dir=" + testDir,
"-master.port=" + strconv.Itoa(masterPort),
"-master.port.grpc=" + strconv.Itoa(masterGrpcPort),
@ -603,6 +688,10 @@ func startMiniCluster(t *testing.T) (*TestCluster, error) {
"-master.peers=none", // Faster startup
"-s3.iam.readOnly=false", // Enable IAM write operations for tests
}
if len(extraArgs) > 0 {
baseArgs = append(baseArgs, extraArgs...)
}
os.Args = append([]string{"weed"}, baseArgs...)
// Suppress most logging during tests
glog.MaxSize = 1024 * 1024
@ -633,6 +722,10 @@ func startMiniCluster(t *testing.T) (*TestCluster, error) {
return cluster, nil
}
func startMiniCluster(t *testing.T) (*TestCluster, error) {
return startMiniClusterWithExtraArgs(t, nil)
}
// Stop stops the test cluster
func (c *TestCluster) Stop() {
if c.cancel != nil {

9
test/s3tables/table-buckets/setup.go

@ -46,8 +46,9 @@ func NewS3TablesClient(endpoint, region, accessKey, secretKey string) *S3TablesC
// Test configuration constants
const (
testRegion = "us-west-2"
testAccessKey = "admin"
testSecretKey = "admin"
testAccountID = "111122223333"
testRegion = "us-west-2"
testAccessKey = "admin"
testSecretKey = "admin"
testAccountID = "111122223333"
testIAMSigningKey = "dGVzdC1zaWduaW5nLWtleS1mb3Itc3RzLWludGVncmF0aW9uLXRlc3Rz"
)

5
weed/s3api/s3tables/handler_bucket_create.go

@ -28,11 +28,12 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
principal := h.getAccountID(r)
identityActions := getIdentityActions(r)
if h.shouldUseIAM(r, identityActions) && !h.defaultAllow {
identityPolicyNames := getIdentityPolicyNames(r)
if h.shouldUseIAM(r, identityActions, identityPolicyNames) && !h.defaultAllow {
ownerAccountID := h.getAccountID(r)
tableBucketARN := h.generateTableBucketARN(ownerAccountID, req.Name)
s3BucketARN := fmt.Sprintf("arn:aws:s3:::%s", req.Name)
allowed, err := h.authorizeIAMAction(r, "s3tables:CreateTableBucket", tableBucketARN, s3BucketARN)
allowed, err := h.authorizeIAMAction(r, identityPolicyNames, "s3tables:CreateTableBucket", tableBucketARN, s3BucketARN)
if err != nil || !allowed {
h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to create table buckets")
return NewAuthError("CreateTableBucket", principal, "not authorized to create table buckets")

14
weed/s3api/s3tables/iam.go

@ -22,14 +22,17 @@ func (h *S3TablesHandler) SetIAMAuthorizer(authorizer IAMAuthorizer) {
h.iamAuthorizer = authorizer
}
func (h *S3TablesHandler) shouldUseIAM(r *http.Request, identityActions []string) bool {
func (h *S3TablesHandler) shouldUseIAM(r *http.Request, identityActions, identityPolicyNames []string) bool {
if h.iamAuthorizer == nil || r == nil {
return false
}
if hasSessionToken(r) {
return true
}
return len(identityActions) == 0
if len(identityActions) == 0 {
return true
}
return len(identityPolicyNames) > 0
}
func hasSessionToken(r *http.Request) bool {
@ -42,7 +45,7 @@ func hasSessionToken(r *http.Request) bool {
return r.URL.Query().Get("X-Amz-Security-Token") != ""
}
func (h *S3TablesHandler) authorizeIAMAction(r *http.Request, action string, resources ...string) (bool, error) {
func (h *S3TablesHandler) authorizeIAMAction(r *http.Request, identityPolicyNames []string, action string, resources ...string) (bool, error) {
if h.iamAuthorizer == nil {
return false, nil
}
@ -67,7 +70,10 @@ func (h *S3TablesHandler) authorizeIAMAction(r *http.Request, action string, res
}
requestContext := buildIAMRequestContext(r, getIdentityClaims(r))
policyNames := getIdentityPolicyNames(r)
policyNames := identityPolicyNames
if len(policyNames) == 0 {
policyNames = getIdentityPolicyNames(r)
}
var lastErr error
for _, resource := range resources {

Loading…
Cancel
Save