[#70] iam: Support aws:MultiFactorAuthPresent key
DCO action / DCO (pull_request) Successful in 1m7s Details
Tests and linters / Tests (1.20) (pull_request) Successful in 1m23s Details
Tests and linters / Tests (1.21) (pull_request) Successful in 1m27s Details
Tests and linters / Tests with -race (pull_request) Successful in 1m38s Details
Tests and linters / Staticcheck (pull_request) Successful in 1m41s Details
Tests and linters / Lint (pull_request) Successful in 2m29s Details

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
Marina Biryukova 2024-04-12 13:56:26 +03:00
parent 0e69e48511
commit b4b2325716
4 changed files with 63 additions and 0 deletions

View File

@ -1,11 +1,13 @@
package iam
import (
"errors"
"fmt"
"strings"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"golang.org/x/exp/slices"
)
const PropertyKeyFilePath = "FilePath"
@ -80,6 +82,8 @@ var objectNativeOperations = map[string]struct{}{
native.MethodHashObject: {},
}
var errConditionKeyNotApplicable = errors.New("condition key is not applicable")
type NativeResolver interface {
GetUserKey(account, name string) (string, error)
GetBucketInfo(bucket string) (*BucketInfo, error)
@ -123,6 +127,9 @@ func ConvertToNativeChain(p Policy, resolver NativeResolver) (*chain.Chain, erro
groupedConditions, err := convertToNativeChainCondition(statement.Conditions, resolver)
if err != nil {
if errors.Is(err, errConditionKeyNotApplicable) {
continue
}
return nil, err
}
splitConditions := splitGroupedConditions(groupedConditions)
@ -218,6 +225,12 @@ func getNativePrincipalsAndConditionFunc(statement Statement, resolver NativeRes
func convertToNativeChainCondition(c Conditions, resolver NativeResolver) ([]GroupedConditions, error) {
return convertToChainConditions(c, func(gr GroupedConditions) (GroupedConditions, error) {
if slices.ContainsFunc(gr.Conditions, func(c chain.Condition) bool {
return c.Key == condKeyAWSMFAPresent
}) {
return GroupedConditions{}, errConditionKeyNotApplicable
}
for i := range gr.Conditions {
if gr.Conditions[i].Key == condKeyAWSPrincipalARN {
gr.Conditions[i].Key = native.PropertyKeyActorPublicKey

View File

@ -7,6 +7,8 @@ import (
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
)
const condKeyAWSMFAPresent = "aws:MultiFactorAuthPresent"
var actionToS3OpMap = map[string][]string{
s3ActionAbortMultipartUpload: {s3ActionAbortMultipartUpload},
s3ActionCreateBucket: {s3ActionCreateBucket},
@ -175,6 +177,9 @@ func convertToS3ChainCondition(c Conditions, resolver S3Resolver) ([]GroupedCond
}
gr.Conditions[i].Value = val
}
if gr.Conditions[i].Key == condKeyAWSMFAPresent {
gr.Conditions[i].Key = s3.PropertyKeyAccessBoxAttrMFA
}
}
return gr, nil

View File

@ -1642,6 +1642,48 @@ func TestTagsConditions(t *testing.T) {
require.ElementsMatch(t, expectedConditions, nativeChain.Rules[0].Condition)
}
func TestMFACondition(t *testing.T) {
policy := `
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
`
expectedConditions := []chain.Condition{
{
Op: chain.CondStringEqualsIgnoreCase,
Object: chain.ObjectRequest,
Key: s3.PropertyKeyAccessBoxAttrMFA,
Value: "true",
},
}
var p Policy
err := json.Unmarshal([]byte(policy), &p)
require.NoError(t, err)
s3Chain, err := ConvertToS3Chain(p, newMockUserResolver(nil, nil, ""))
require.NoError(t, err)
require.Len(t, s3Chain.Rules, 1)
require.ElementsMatch(t, expectedConditions, s3Chain.Rules[0].Condition)
_, err = ConvertToNativeChain(p, newMockUserResolver(nil, nil, ""))
require.ErrorIs(t, err, ErrActionsNotApplicable)
}
func requireChainRulesMatch(t *testing.T, expected, actual []chain.Rule) {
require.Equal(t, len(expected), len(actual), "length of chain rules differ")

View File

@ -11,6 +11,9 @@ const (
PropertyKeyFormatResourceTag = "aws:ResourceTag/%s"
PropertyKeyFormatRequestTag = "aws:RequestTag/%s"
PropertyKeyAccessBoxAttrMFA = "AccessBox-Attribute/IAM-MFA"
PropertyKeyFormatAccessBoxAttr = "AccessBox-Attribute/%s"
ResourceFormatS3All = "arn:aws:s3:::*"
ResourceFormatS3Bucket = "arn:aws:s3:::%s"
ResourceFormatS3BucketObjects = "arn:aws:s3:::%s/*"