From 1cdb3e5a4abc178bc410c16eb0ee2dcf703b5343 Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Fri, 26 Jan 2024 15:43:48 +0300 Subject: [PATCH] [#46] iam: Support more s3 to native actions mapping Signed-off-by: Denis Kirillov --- iam/converter_native.go | 36 ++++++++++++----------- iam/converter_test.go | 64 +++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 57 deletions(-) diff --git a/iam/converter_native.go b/iam/converter_native.go index 74c2822..3ca0d89 100644 --- a/iam/converter_native.go +++ b/iam/converter_native.go @@ -10,15 +10,17 @@ import ( const PropertyKeyFilePath = "FilePath" -var actionToOpMap = map[string][]string{ - supportedS3ActionDeleteObject: {native.MethodDeleteObject}, - supportedS3ActionGetObject: {native.MethodGetObject, native.MethodHeadObject, native.MethodSearchObject, native.MethodRangeObject, native.MethodHashObject}, - supportedS3ActionHeadObject: {native.MethodHeadObject, native.MethodSearchObject, native.MethodRangeObject, native.MethodHashObject}, - supportedS3ActionPutObject: {native.MethodPutObject}, - supportedS3ActionListBucket: {native.MethodGetContainer, native.MethodGetObject, native.MethodHeadObject, native.MethodSearchObject, native.MethodRangeObject, native.MethodHashObject}, +var supportedActionToNativeOpMap = map[string][]string{ + supportedS3NativeActionDeleteObject: {native.MethodDeleteObject}, + supportedS3NativeActionGetObject: {native.MethodGetObject, native.MethodHeadObject, native.MethodSearchObject, native.MethodRangeObject, native.MethodHashObject}, + supportedS3NativeActionPutObject: {native.MethodPutObject}, + supportedS3NativeActionListBucket: {native.MethodGetContainer, native.MethodGetObject, native.MethodHeadObject, native.MethodSearchObject, native.MethodRangeObject, native.MethodHashObject}, - supportedS3ActionCreateBucket: {native.MethodPutContainer}, - supportedS3ActionDeleteBucket: {native.MethodDeleteContainer}, + supportedS3NativeActionCreateBucket: {native.MethodPutContainer}, + supportedS3NativeActionDeleteBucket: {native.MethodDeleteContainer}, + supportedS3NativeActionListAllMyBucket: {native.MethodListContainers}, + supportedS3NativeActionPutBucketACL: {native.MethodSetContainerEACL}, + supportedS3NativeActionGetBucketACL: {native.MethodGetContainerEACL}, } var containerNativeOperations = map[string]struct{}{ @@ -41,14 +43,16 @@ var objectNativeOperations = map[string]struct{}{ } const ( - supportedS3ActionDeleteObject = "s3:DeleteObject" - supportedS3ActionGetObject = "s3:GetObject" - supportedS3ActionHeadObject = "s3:HeadObject" - supportedS3ActionPutObject = "s3:PutObject" - supportedS3ActionListBucket = "s3:ListBucket" + supportedS3NativeActionDeleteObject = "s3:DeleteObject" + supportedS3NativeActionGetObject = "s3:GetObject" + supportedS3NativeActionPutObject = "s3:PutObject" + supportedS3NativeActionListBucket = "s3:ListBucket" - supportedS3ActionCreateBucket = "s3:CreateBucket" - supportedS3ActionDeleteBucket = "s3:DeleteBucket" + supportedS3NativeActionCreateBucket = "s3:CreateBucket" + supportedS3NativeActionDeleteBucket = "s3:DeleteBucket" + supportedS3NativeActionListAllMyBucket = "s3:ListAllMyBuckets" + supportedS3NativeActionPutBucketACL = "s3:PutBucketAcl" + supportedS3NativeActionGetBucketACL = "s3:GetBucketAcl" ) type NativeResolver interface { @@ -342,7 +346,7 @@ func formNativeActionNames(names []string) ([]string, error) { return []string{Wildcard}, nil } - res = append(res, actionToOpMap[action]...) + res = append(res, supportedActionToNativeOpMap[action]...) } return res, nil diff --git a/iam/converter_test.go b/iam/converter_test.go index e02109e..f5c5ef4 100644 --- a/iam/converter_test.go +++ b/iam/converter_test.go @@ -154,40 +154,6 @@ func TestConverters(t *testing.T) { require.Equal(t, expected, nativeChain) }) - t.Run("valid native policy with container resources", func(t *testing.T) { - p := Policy{ - Version: "2012-10-17", - Statement: []Statement{{ - Principal: map[PrincipalType][]string{ - AWSPrincipalType: {principal}, - }, - Effect: AllowEffect, - Action: []string{"s3:PutObject"}, - Resource: []string{resource}, - }}, - } - - expected := &chain.Chain{Rules: []chain.Rule{ - { - Status: chain.Allow, - Actions: chain.Actions{Names: []string{native.MethodPutObject}}, - Resources: chain.Resources{Names: []string{fmt.Sprintf(native.ResourceFormatNamespaceContainerObjects, namespace, mockResolver.containers[bktName])}}, - Condition: []chain.Condition{ - { - Op: chain.CondStringEquals, - Object: chain.ObjectRequest, - Key: native.PropertyKeyActorPublicKey, - Value: mockResolver.users[user], - }, - }, - }, - }} - - nativeChain, err := ConvertToNativeChain(p, mockResolver) - require.NoError(t, err) - require.Equal(t, expected, nativeChain) - }) - t.Run("valid inverted policy", func(t *testing.T) { p := Policy{ Version: "2012-10-17", @@ -222,24 +188,27 @@ func TestConverters(t *testing.T) { require.Equal(t, expected, s3Chain) }) - t.Run("valid policy map get action", func(t *testing.T) { + t.Run("valid native policy map action", func(t *testing.T) { p := Policy{ Version: "2012-10-17", Statement: []Statement{{ Principal: map[PrincipalType][]string{ AWSPrincipalType: {principal}, }, - Effect: DenyEffect, - NotAction: []string{"s3:GetObject"}, - NotResource: []string{fmt.Sprintf(s3.ResourceFormatS3BucketObject, bktName, objName)}, + Effect: DenyEffect, + Action: []string{"s3:DeleteObject", "s3:DeleteBucket"}, + Resource: []string{ + fmt.Sprintf(s3.ResourceFormatS3BucketObject, bktName, objName), + fmt.Sprintf(s3.ResourceFormatS3Bucket, bktName), + }, }}, } expected := &chain.Chain{Rules: []chain.Rule{ { Status: chain.AccessDenied, - Actions: chain.Actions{Inverted: true, Names: actionToOpMap["s3:GetObject"]}, - Resources: chain.Resources{Inverted: true, Names: []string{ + Actions: chain.Actions{Names: []string{native.MethodDeleteObject, native.MethodDeleteContainer}}, + Resources: chain.Resources{Names: []string{ fmt.Sprintf(native.ResourceFormatNamespaceContainerObjects, namespace, mockResolver.containers[bktName]), }}, Condition: []chain.Condition{ @@ -257,6 +226,19 @@ func TestConverters(t *testing.T) { }, }, }, + { + Status: chain.AccessDenied, + Actions: chain.Actions{Names: []string{native.MethodDeleteObject, native.MethodDeleteContainer}}, + Resources: chain.Resources{Names: []string{ + fmt.Sprintf(native.ResourceFormatNamespaceContainer, namespace, mockResolver.containers[bktName]), + }}, + Condition: []chain.Condition{{ + Op: chain.CondStringEquals, + Object: chain.ObjectRequest, + Key: native.PropertyKeyActorPublicKey, + Value: mockResolver.users[user], + }}, + }, }} nativeChain, err := ConvertToNativeChain(p, mockResolver) @@ -660,7 +642,7 @@ func TestComplexNativeConditions(t *testing.T) { } expectedStatus := chain.AccessDenied - expectedActions := chain.Actions{Names: actionToOpMap["s3:"+action]} + expectedActions := chain.Actions{Names: supportedActionToNativeOpMap["s3:"+action]} expectedResource1 := chain.Resources{Names: []string{nativeResource1}} expectedResource23 := chain.Resources{Names: []string{nativeResource2, nativeResource3}}