diff --git a/api/middleware/policy.go b/api/middleware/policy.go index 615e32354..44fc5b21e 100644 --- a/api/middleware/policy.go +++ b/api/middleware/policy.go @@ -415,6 +415,7 @@ func determineProperties(r *http.Request, decoder XMLDecoder, resolver BucketRes res := map[string]string{ s3.PropertyKeyOwner: owner, common.PropertyKeyFrostFSIDGroupID: chain.FormCondSliceContainsValue(groups), + common.PropertyKeyFrostFSSourceIP: GetReqInfo(r.Context()).RemoteHost, } queries := GetReqInfo(r.Context()).URL.Query() diff --git a/api/router_mock_test.go b/api/router_mock_test.go index 6b410020d..bd67f271b 100644 --- a/api/router_mock_test.go +++ b/api/router_mock_test.go @@ -60,12 +60,13 @@ func (c *centerMock) Authenticate(*http.Request) (*middleware.Box, error) { } type middlewareSettingsMock struct { - denyByDefault bool - aclEnabled bool + denyByDefault bool + aclEnabled bool + sourceIPHeader string } func (r *middlewareSettingsMock) SourceIPHeader() string { - return "" + return r.sourceIPHeader } func (r *middlewareSettingsMock) NamespaceHeader() string { diff --git a/api/router_test.go b/api/router_test.go index ed895a81c..c181c535e 100644 --- a/api/router_test.go +++ b/api/router_test.go @@ -254,7 +254,7 @@ func TestDefaultBehaviorPolicyChecker(t *testing.T) { // check we cannot access if rules not found when settings is enabled chiRouter.middlewareSettings.denyByDefault = true - createBucketErr(chiRouter, ns, bktName, apiErrors.ErrAccessDenied) + createBucketErr(chiRouter, ns, bktName, nil, apiErrors.ErrAccessDenied) } func TestDefaultPolicyCheckerWithUserTags(t *testing.T) { @@ -265,7 +265,7 @@ func TestDefaultPolicyCheckerWithUserTags(t *testing.T) { allowOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{ engineiam.CondStringEquals: engineiam.Condition{fmt.Sprintf(common.PropertyKeyFormatFrostFSIDUserClaim, "tag-test"): []string{"test"}}, }) - createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied) + createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied) tags := make(map[string]string) tags["tag-test"] = "test" @@ -291,7 +291,7 @@ func TestACLAPE(t *testing.T) { putObjectErr(router, ns, bktNameNew, objName, nil, apiErrors.ErrAccessDenied) // Deny because of deny by default - createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied) + createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied) listBucketsErr(router, ns, apiErrors.ErrAccessDenied) // Allow operations and check @@ -322,7 +322,7 @@ func TestACLAPE(t *testing.T) { // Deny operations and check denyOperations(router, ns, []string{"s3:CreateBucket", "s3:ListAllMyBuckets"}, nil) - createBucketErr(router, ns, bktName, apiErrors.ErrAccessDenied) + createBucketErr(router, ns, bktName, nil, apiErrors.ErrAccessDenied) listBucketsErr(router, ns, apiErrors.ErrAccessDenied) }) @@ -617,6 +617,25 @@ func TestAccessBoxAttributesCheck(t *testing.T) { listObjectsV1(router, ns, bktName, "", "", "") } +func TestSourceIPCheck(t *testing.T) { + router := prepareRouter(t) + + ns, bktName, hdr := "", "bucket", "Source-Ip" + router.middlewareSettings.denyByDefault = true + + // Add policy and check + allowOperations(router, ns, []string{"s3:CreateBucket"}, engineiam.Conditions{ + engineiam.CondIPAddress: engineiam.Condition{"aws:SourceIp": []string{"192.0.2.0/24"}}, + }) + + router.middlewareSettings.sourceIPHeader = hdr + header := map[string][]string{hdr: {"192.0.3.0"}} + createBucketErr(router, ns, bktName, header, apiErrors.ErrAccessDenied) + + router.middlewareSettings.sourceIPHeader = "" + createBucket(router, ns, bktName) +} + func allowOperations(router *routerMock, ns string, operations []string, conditions engineiam.Conditions) { addPolicy(router, ns, "allow", engineiam.AllowEffect, operations, conditions) } @@ -661,19 +680,23 @@ func createSpecificBucket(router *routerMock, bktName string, old bool) { } func createBucket(router *routerMock, namespace, bktName string) { - w := createBucketBase(router, namespace, bktName) + w := createBucketBase(router, namespace, bktName, nil) resp := readResponse(router.t, w) require.Equal(router.t, s3middleware.CreateBucketOperation, resp.Method) } -func createBucketErr(router *routerMock, namespace, bktName string, errCode apiErrors.ErrorCode) { - w := createBucketBase(router, namespace, bktName) +func createBucketErr(router *routerMock, namespace, bktName string, header http.Header, errCode apiErrors.ErrorCode) { + w := createBucketBase(router, namespace, bktName, header) assertAPIError(router.t, w, errCode) } -func createBucketBase(router *routerMock, namespace, bktName string) *httptest.ResponseRecorder { +func createBucketBase(router *routerMock, namespace, bktName string, header http.Header) *httptest.ResponseRecorder { w, r := httptest.NewRecorder(), httptest.NewRequest(http.MethodPut, "/"+bktName, nil) r.Header.Set(FrostfsNamespaceHeader, namespace) + for key := range header { + r.Header.Set(key, header.Get(key)) + } + router.ServeHTTP(w, r) return w }