[#1689] container: Make APE middleware form container system attributes
All checks were successful
Vulncheck / Vulncheck (push) Successful in 1m14s
Pre-commit hooks / Pre-commit (push) Successful in 1m39s
Build / Build Components (push) Successful in 1m50s
Tests and linters / Run gofumpt (push) Successful in 3m20s
Tests and linters / Staticcheck (push) Successful in 3m39s
Tests and linters / Lint (push) Successful in 3m46s
Tests and linters / Tests (push) Successful in 4m11s
Tests and linters / gopls check (push) Successful in 4m8s
Tests and linters / Tests with -race (push) Successful in 4m28s
OCI image / Build container images (push) Successful in 4m47s
All checks were successful
Vulncheck / Vulncheck (push) Successful in 1m14s
Pre-commit hooks / Pre-commit (push) Successful in 1m39s
Build / Build Components (push) Successful in 1m50s
Tests and linters / Run gofumpt (push) Successful in 3m20s
Tests and linters / Staticcheck (push) Successful in 3m39s
Tests and linters / Lint (push) Successful in 3m46s
Tests and linters / Tests (push) Successful in 4m11s
Tests and linters / gopls check (push) Successful in 4m8s
Tests and linters / Tests with -race (push) Successful in 4m28s
OCI image / Build container images (push) Successful in 4m47s
* Make `Put` handler extract container attributes from request body and form APE-resource properties; * Make `validateContainerBoundedOperation` used by `Get` and `Delete` handlers extracts attributes from read container. Change-Id: I005345575c3d25b505bae4108f60cd320a7489ba Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
c2a495814f
commit
86aec1ad6d
2 changed files with 206 additions and 4 deletions
|
@ -280,11 +280,16 @@ func (ac *apeChecker) Put(ctx context.Context, req *container.PutRequest) (*cont
|
|||
return nil, err
|
||||
}
|
||||
|
||||
cnrProps, err := getContainerPropsFromV2(req.GetBody().GetContainer())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get container properties: %w", err)
|
||||
}
|
||||
|
||||
request := aperequest.NewRequest(
|
||||
nativeschema.MethodPutContainer,
|
||||
aperequest.NewResource(
|
||||
resourceName(namespace, ""),
|
||||
make(map[string]string),
|
||||
cnrProps,
|
||||
),
|
||||
reqProps,
|
||||
)
|
||||
|
@ -395,7 +400,7 @@ func (ac *apeChecker) validateContainerBoundedOperation(ctx context.Context, con
|
|||
op,
|
||||
aperequest.NewResource(
|
||||
resourceName(namespace, id.EncodeToString()),
|
||||
ac.getContainerProps(cont),
|
||||
getContainerProps(cont),
|
||||
),
|
||||
reqProps,
|
||||
)
|
||||
|
@ -445,10 +450,26 @@ func resourceName(namespace string, container string) string {
|
|||
return fmt.Sprintf(nativeschema.ResourceFormatNamespaceContainer, namespace, container)
|
||||
}
|
||||
|
||||
func (ac *apeChecker) getContainerProps(c *containercore.Container) map[string]string {
|
||||
return map[string]string{
|
||||
func getContainerProps(c *containercore.Container) map[string]string {
|
||||
props := map[string]string{
|
||||
nativeschema.PropertyKeyContainerOwnerID: c.Value.Owner().EncodeToString(),
|
||||
}
|
||||
for attrName, attrVal := range c.Value.Attributes() {
|
||||
name := fmt.Sprintf(nativeschema.PropertyKeyFormatContainerAttribute, attrName)
|
||||
props[name] = attrVal
|
||||
}
|
||||
return props
|
||||
}
|
||||
|
||||
func getContainerPropsFromV2(cnrV2 *container.Container) (map[string]string, error) {
|
||||
if cnrV2 == nil {
|
||||
return nil, errors.New("container is not set")
|
||||
}
|
||||
c := cnrSDK.Container{}
|
||||
if err := c.ReadFromV2(*cnrV2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getContainerProps(&containercore.Container{Value: c}), nil
|
||||
}
|
||||
|
||||
func (ac *apeChecker) getRequestProps(ctx context.Context, mh *session.RequestMetaHeader, vh *session.RequestVerificationHeader,
|
||||
|
|
|
@ -54,6 +54,8 @@ func TestAPE(t *testing.T) {
|
|||
t.Run("deny put container with invlaid namespace", testDenyPutContainerInvalidNamespace)
|
||||
t.Run("deny list containers for owner with PK", testDenyListContainersForPK)
|
||||
t.Run("deny list containers by namespace invalidation", testDenyListContainersValidationNamespaceError)
|
||||
t.Run("deny get by container attribute rules", testDenyGetContainerSysZoneAttr)
|
||||
t.Run("deny put by container attribute rules", testDenyPutContainerSysZoneAttr)
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -564,6 +566,185 @@ func testDenyGetContainerByIP(t *testing.T) {
|
|||
require.Contains(t, errAccessDenied.Reason(), chain.AccessDenied.String())
|
||||
}
|
||||
|
||||
func testDenyGetContainerSysZoneAttr(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := &srvStub{
|
||||
calls: map[string]int{},
|
||||
}
|
||||
router := inmemory.NewInMemory()
|
||||
contRdr := &containerStub{
|
||||
c: map[cid.ID]*containercore.Container{},
|
||||
}
|
||||
ir := &irStub{
|
||||
keys: [][]byte{},
|
||||
}
|
||||
nm := &netmapStub{}
|
||||
pk, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
frostfsIDSubjectReader := &frostfsidStub{
|
||||
subjects: map[util.Uint160]*client.Subject{
|
||||
pk.PublicKey().GetScriptHash(): {
|
||||
KV: map[string]string{
|
||||
"tag-attr1": "value1",
|
||||
"tag-attr2": "value2",
|
||||
},
|
||||
},
|
||||
},
|
||||
subjectsExt: map[util.Uint160]*client.SubjectExtended{
|
||||
pk.PublicKey().GetScriptHash(): {
|
||||
KV: map[string]string{
|
||||
"tag-attr1": "value1",
|
||||
"tag-attr2": "value2",
|
||||
},
|
||||
Groups: []*client.Group{
|
||||
{
|
||||
ID: 19888,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
apeSrv := NewAPEServer(router, contRdr, ir, nm, frostfsIDSubjectReader, srv)
|
||||
|
||||
contID := cidtest.ID()
|
||||
testContainer := containertest.Container()
|
||||
pp := netmap.PlacementPolicy{}
|
||||
require.NoError(t, pp.DecodeString("REP 1"))
|
||||
testContainer.SetPlacementPolicy(pp)
|
||||
testContainer.SetAttribute(container.SysAttributeZone, "eggplant")
|
||||
contRdr.c[contID] = &containercore.Container{Value: testContainer}
|
||||
|
||||
nm.currentEpoch = 100
|
||||
nm.netmaps = map[uint64]*netmap.NetMap{}
|
||||
var testNetmap netmap.NetMap
|
||||
testNetmap.SetEpoch(nm.currentEpoch)
|
||||
testNetmap.SetNodes([]netmap.NodeInfo{{}})
|
||||
nm.netmaps[nm.currentEpoch] = &testNetmap
|
||||
nm.netmaps[nm.currentEpoch-1] = &testNetmap
|
||||
|
||||
_, _, err = router.MorphRuleChainStorage().AddMorphRuleChain(chain.Ingress, engine.ContainerTarget(contID.EncodeToString()), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.AccessDenied,
|
||||
Actions: chain.Actions{
|
||||
Names: []string{
|
||||
nativeschema.MethodGetContainer,
|
||||
},
|
||||
},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{
|
||||
fmt.Sprintf(nativeschema.ResourceFormatRootContainer, contID.EncodeToString()),
|
||||
},
|
||||
},
|
||||
Condition: []chain.Condition{
|
||||
{
|
||||
Kind: chain.KindResource,
|
||||
Key: fmt.Sprintf(nativeschema.PropertyKeyFormatContainerAttribute, container.SysAttributeZone),
|
||||
Value: "eggplant",
|
||||
Op: chain.CondStringEquals,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
req := &container.GetRequest{}
|
||||
req.SetBody(&container.GetRequestBody{})
|
||||
var refContID refs.ContainerID
|
||||
contID.WriteToV2(&refContID)
|
||||
req.GetBody().SetContainerID(&refContID)
|
||||
|
||||
require.NoError(t, signature.SignServiceMessage(&pk.PrivateKey, req))
|
||||
|
||||
resp, err := apeSrv.Get(ctxWithPeerInfo(), req)
|
||||
require.Nil(t, resp)
|
||||
var errAccessDenied *apistatus.ObjectAccessDenied
|
||||
require.ErrorAs(t, err, &errAccessDenied)
|
||||
require.Contains(t, errAccessDenied.Reason(), chain.AccessDenied.String())
|
||||
}
|
||||
|
||||
func testDenyPutContainerSysZoneAttr(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := &srvStub{
|
||||
calls: map[string]int{},
|
||||
}
|
||||
router := inmemory.NewInMemory()
|
||||
contRdr := &containerStub{
|
||||
c: map[cid.ID]*containercore.Container{},
|
||||
}
|
||||
ir := &irStub{
|
||||
keys: [][]byte{},
|
||||
}
|
||||
nm := &netmapStub{}
|
||||
|
||||
contID := cidtest.ID()
|
||||
testContainer := containertest.Container()
|
||||
pp := netmap.PlacementPolicy{}
|
||||
require.NoError(t, pp.DecodeString("REP 1"))
|
||||
testContainer.SetPlacementPolicy(pp)
|
||||
testContainer.SetAttribute(container.SysAttributeZone, "eggplant")
|
||||
contRdr.c[contID] = &containercore.Container{Value: testContainer}
|
||||
owner := testContainer.Owner()
|
||||
ownerAddr := owner.ScriptHash()
|
||||
|
||||
frostfsIDSubjectReader := &frostfsidStub{
|
||||
subjects: map[util.Uint160]*client.Subject{
|
||||
ownerAddr: {},
|
||||
},
|
||||
subjectsExt: map[util.Uint160]*client.SubjectExtended{
|
||||
ownerAddr: {},
|
||||
},
|
||||
}
|
||||
|
||||
apeSrv := NewAPEServer(router, contRdr, ir, nm, frostfsIDSubjectReader, srv)
|
||||
|
||||
nm.currentEpoch = 100
|
||||
nm.netmaps = map[uint64]*netmap.NetMap{}
|
||||
var testNetmap netmap.NetMap
|
||||
testNetmap.SetEpoch(nm.currentEpoch)
|
||||
testNetmap.SetNodes([]netmap.NodeInfo{{}})
|
||||
nm.netmaps[nm.currentEpoch] = &testNetmap
|
||||
nm.netmaps[nm.currentEpoch-1] = &testNetmap
|
||||
|
||||
_, _, err := router.MorphRuleChainStorage().AddMorphRuleChain(chain.Ingress, engine.NamespaceTarget(""), &chain.Chain{
|
||||
Rules: []chain.Rule{
|
||||
{
|
||||
Status: chain.AccessDenied,
|
||||
Actions: chain.Actions{
|
||||
Names: []string{
|
||||
nativeschema.MethodPutContainer,
|
||||
},
|
||||
},
|
||||
Resources: chain.Resources{
|
||||
Names: []string{
|
||||
nativeschema.ResourceFormatRootContainers,
|
||||
},
|
||||
},
|
||||
Condition: []chain.Condition{
|
||||
{
|
||||
Kind: chain.KindResource,
|
||||
Key: fmt.Sprintf(nativeschema.PropertyKeyFormatContainerAttribute, container.SysAttributeZone),
|
||||
Value: "eggplant",
|
||||
Op: chain.CondStringEquals,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
req := initPutRequest(t, testContainer)
|
||||
|
||||
resp, err := apeSrv.Put(ctxWithPeerInfo(), req)
|
||||
require.Nil(t, resp)
|
||||
var errAccessDenied *apistatus.ObjectAccessDenied
|
||||
require.ErrorAs(t, err, &errAccessDenied)
|
||||
require.Contains(t, errAccessDenied.Reason(), chain.AccessDenied.String())
|
||||
}
|
||||
|
||||
func testDenyGetContainerByGroupID(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := &srvStub{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue