[#360] Use 'c' prefix for bucket policies instead of 'n'

With 'c' prefix, acl chains become shorter, thus gateway
receives shorter results and avoids sessions to neo-go.

There is still issue with many IAM rules.

Signed-off-by: Alex Vanin <a.vanin@yadro.com>
This commit is contained in:
Alexey Vanin 2024-04-10 15:53:36 +03:00
parent 3ea3f971e1
commit 6da1acc554
8 changed files with 49 additions and 43 deletions

View file

@ -450,7 +450,7 @@ func (h *handler) putBucketACLAPEHandler(w http.ResponseWriter, r *http.Request,
} }
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID) chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
if err = h.ape.SaveACLChains(reqInfo.Namespace, chainRules); err != nil { if err = h.ape.SaveACLChains(bktInfo.CID.EncodeToString(), chainRules); err != nil {
h.logAndSendError(w, "failed to add morph rule chains", reqInfo, err) h.logAndSendError(w, "failed to add morph rule chains", reqInfo, err)
return return
} }

View file

@ -1325,7 +1325,7 @@ func TestPutBucketAPE(t *testing.T) {
_, err := hc.tp.ContainerEACL(hc.Context(), layer.PrmContainerEACL{ContainerID: info.BktInfo.CID}) _, err := hc.tp.ContainerEACL(hc.Context(), layer.PrmContainerEACL{ContainerID: info.BktInfo.CID})
require.ErrorContains(t, err, "not found") require.ErrorContains(t, err, "not found")
chains, err := hc.h.ape.(*apeMock).ListChains(engine.NamespaceTarget("")) chains, err := hc.h.ape.(*apeMock).ListChains(engine.ContainerTarget(info.BktInfo.CID.EncodeToString()))
require.NoError(t, err) require.NoError(t, err)
require.Len(t, chains, 2) require.Len(t, chains, 2)
} }
@ -1509,7 +1509,7 @@ func TestDeleteBucketWithPolicy(t *testing.T) {
hc := prepareHandlerContext(t) hc := prepareHandlerContext(t)
bktName := "bucket-for-policy" bktName := "bucket-for-policy"
createTestBucket(hc, bktName) bi := createTestBucket(hc, bktName)
newPolicy := engineiam.Policy{ newPolicy := engineiam.Policy{
Version: "2012-10-17", Version: "2012-10-17",
@ -1524,12 +1524,12 @@ func TestDeleteBucketWithPolicy(t *testing.T) {
putBucketPolicy(hc, bktName, newPolicy) putBucketPolicy(hc, bktName, newPolicy)
require.Len(t, hc.h.ape.(*apeMock).policyMap, 1) require.Len(t, hc.h.ape.(*apeMock).policyMap, 1)
require.Len(t, hc.h.ape.(*apeMock).chainMap[engine.NamespaceTarget("")], 4) require.Len(t, hc.h.ape.(*apeMock).chainMap[engine.ContainerTarget(bi.CID.EncodeToString())], 4)
deleteBucket(t, hc, bktName, http.StatusNoContent) deleteBucket(t, hc, bktName, http.StatusNoContent)
require.Empty(t, hc.h.ape.(*apeMock).policyMap) require.Empty(t, hc.h.ape.(*apeMock).policyMap)
chains, err := hc.h.ape.(*apeMock).ListChains(engine.NamespaceTarget("")) chains, err := hc.h.ape.(*apeMock).ListChains(engine.ContainerTarget(bi.CID.EncodeToString()))
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, chains) require.Empty(t, chains)
} }

View file

@ -59,7 +59,7 @@ type (
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error
DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
SaveACLChains(ns string, chains []*chain.Chain) error SaveACLChains(cid string, chains []*chain.Chain) error
} }
) )

View file

@ -270,7 +270,7 @@ func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chain
} }
for i := range chain { for i := range chain {
if err := a.AddChain(engine.NamespaceTarget(ns), chain[i]); err != nil { if err := a.AddChain(engine.ContainerTarget(cnrID.EncodeToString()), chain[i]); err != nil {
return err return err
} }
} }
@ -283,7 +283,7 @@ func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.I
return err return err
} }
for i := range chainIDs { for i := range chainIDs {
if err := a.RemoveChain(engine.NamespaceTarget(ns), chainIDs[i]); err != nil { if err := a.RemoveChain(engine.ContainerTarget(cnrID.EncodeToString()), chainIDs[i]); err != nil {
return err return err
} }
} }
@ -300,9 +300,9 @@ func (a *apeMock) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
return policy, nil return policy, nil
} }
func (a *apeMock) SaveACLChains(ns string, chains []*chain.Chain) error { func (a *apeMock) SaveACLChains(cid string, chains []*chain.Chain) error {
for i := range chains { for i := range chains {
if err := a.AddChain(engine.NamespaceTarget(ns), chains[i]); err != nil { if err := a.AddChain(engine.ContainerTarget(cid), chains[i]); err != nil {
return err return err
} }
} }

View file

@ -898,7 +898,7 @@ func (h *handler) createBucketHandlerPolicy(w http.ResponseWriter, r *http.Reque
h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID)) h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID))
chains := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID) chains := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
if err = h.ape.SaveACLChains(reqInfo.Namespace, chains); err != nil { if err = h.ape.SaveACLChains(bktInfo.CID.EncodeToString(), chains); err != nil {
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err) h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
return return
} }

View file

@ -72,15 +72,34 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
return err return err
} }
reqInfo := GetReqInfo(r.Context()) var bktInfo *data.BucketInfo
target := engine.NewRequestTargetWithNamespace(reqInfo.Namespace) if reqType != noneType && !strings.HasSuffix(req.Operation(), CreateBucketOperation) {
st, found, err := cfg.Storage.IsAllowed(chain.S3, target, req) bktInfo, err = cfg.BucketResolver(r.Context(), bktName)
if err != nil { if err != nil {
return err return err
} }
}
if !found { reqInfo := GetReqInfo(r.Context())
st = chain.NoRuleFound targets := []engine.RequestTarget{
engine.NewRequestTargetWithNamespace(reqInfo.Namespace),
}
if bktInfo != nil {
targets = append(targets, engine.NewRequestTargetWithContainer(bktInfo.CID.EncodeToString()))
}
st := chain.NoRuleFound
for _, target := range targets {
status, found, err := cfg.Storage.IsAllowed(chain.S3, target, req)
if err != nil {
return err
}
if found {
st = status
if status != chain.Allow {
break
}
}
} }
switch { switch {
@ -90,9 +109,9 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String())) return apiErr.GetAPIErrorWithError(apiErr.ErrAccessDenied, fmt.Errorf("policy check: %s", st.String()))
} }
isAPE, err := isAPEBehavior(r.Context(), req, cfg, reqType, bktName) isAPE := !cfg.Settings.ACLEnabled()
if err != nil { if bktInfo != nil {
return err isAPE = bktInfo.APEEnabled
} }
if isAPE && cfg.Settings.PolicyDenyByDefault() { if isAPE && cfg.Settings.PolicyDenyByDefault() {
@ -102,20 +121,6 @@ func policyCheck(r *http.Request, cfg PolicyConfig) error {
return nil return nil
} }
func isAPEBehavior(ctx context.Context, req *testutil.Request, cfg PolicyConfig, reqType ReqType, bktName string) (bool, error) {
if reqType == noneType ||
strings.HasSuffix(req.Operation(), CreateBucketOperation) {
return !cfg.Settings.ACLEnabled(), nil
}
bktInfo, err := cfg.BucketResolver(ctx, bktName) // we cannot use reqInfo.BucketName because it hasn't been set yet
if err != nil {
return false, err
}
return bktInfo.APEEnabled, nil
}
func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string, log *zap.Logger) (*testutil.Request, error) { func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string, log *zap.Logger) (*testutil.Request, error) {
var ( var (
owner string owner string

View file

@ -197,6 +197,7 @@ func TestPolicyChecker(t *testing.T) {
func TestPolicyCheckerReqTypeDetermination(t *testing.T) { func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
chiRouter := prepareRouter(t) chiRouter := prepareRouter(t)
bktName, objName := "bucket", "object" bktName, objName := "bucket", "object"
createBucket(chiRouter, "", bktName)
policy := engineiam.Policy{ policy := engineiam.Policy{
Version: "2012-10-17", Version: "2012-10-17",

View file

@ -76,24 +76,24 @@ func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engi
} }
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error { func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, chains []*chain.Chain) error {
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3}) c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3})
tx := c.contract.StartTx() tx := c.contract.StartTx()
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy) tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
for i := range chains { for i := range chains {
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes()) tx.AddChain(policycontract.Container, cnrID.EncodeToString(), chains[i].ID, chains[i].Bytes())
} }
return c.contract.SendTx(tx) return c.contract.SendTx(tx)
} }
func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error { func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainIDs []chain.ID) error {
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3}) c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cnrID.EncodeToString()), Name: chain.S3})
tx := c.contract.StartTx() tx := c.contract.StartTx()
for _, chainID := range chainIDs { for _, chainID := range chainIDs {
tx.RemoveChain(policycontract.Namespace, ns, chainID) tx.RemoveChain(policycontract.Container, cnrID.EncodeToString(), chainID)
} }
tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID)) tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
@ -104,13 +104,13 @@ func (c *MorphRuleChainStorage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte
return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID)) return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
} }
func (c *MorphRuleChainStorage) SaveACLChains(ns string, chains []*chain.Chain) error { func (c *MorphRuleChainStorage) SaveACLChains(cid string, chains []*chain.Chain) error {
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3}) c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.S3})
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.Ingress}) c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.ContainerTarget(cid), Name: chain.Ingress})
tx := c.contract.StartTx() tx := c.contract.StartTx()
for i := range chains { for i := range chains {
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes()) tx.AddChain(policycontract.Container, cid, chains[i].ID, chains[i].Bytes())
} }
return c.contract.SendTx(tx) return c.contract.SendTx(tx)