[#553] authmate: Don't use basic acl

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2024-11-18 15:31:09 +03:00
parent 368c7d2acd
commit 4fa45bdac2
8 changed files with 108 additions and 24 deletions

View file

@ -141,7 +141,6 @@ func (n *Layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
SessionToken: p.SessionContainerCreation, SessionToken: p.SessionContainerCreation,
CreationTime: bktInfo.Created, CreationTime: bktInfo.Created,
AdditionalAttributes: attributes, AdditionalAttributes: attributes,
BasicACL: 0, // means APE
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("create container: %w", err) return nil, fmt.Errorf("create container: %w", err)

View file

@ -9,13 +9,13 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
) )
// PrmContainerCreate groups parameters of FrostFS.CreateContainer operation. // PrmContainerCreate groups parameters of FrostFS.CreateContainer operation.
@ -38,13 +38,19 @@ type PrmContainerCreate struct {
// Token of the container's creation session. Nil means session absence. // Token of the container's creation session. Nil means session absence.
SessionToken *session.Container SessionToken *session.Container
// Basic ACL of the container.
BasicACL acl.Basic
// Attributes for optional parameters. // Attributes for optional parameters.
AdditionalAttributes [][2]string AdditionalAttributes [][2]string
} }
// PrmAddContainerPolicyChain groups parameter of FrostFS.AddContainerPolicyChain operation.
type PrmAddContainerPolicyChain struct {
// ContainerID is a container identifier.
ContainerID cid.ID
// Chain is Access Policy Engine chain that contains rules which provide access to specific actions in container.
Chain chain.Chain
}
// PrmContainer groups parameters of FrostFS.Container operation. // PrmContainer groups parameters of FrostFS.Container operation.
type PrmContainer struct { type PrmContainer struct {
// Container identifier. // Container identifier.
@ -239,6 +245,10 @@ type FrostFS interface {
// prevented the container from being created. // prevented the container from being created.
CreateContainer(context.Context, PrmContainerCreate) (*ContainerCreateResult, error) CreateContainer(context.Context, PrmContainerCreate) (*ContainerCreateResult, error)
// AddContainerPolicyChain create new policy chain for container.
// Can be invoked only by container owner.
AddContainerPolicyChain(context.Context, PrmAddContainerPolicyChain) error
// Container reads a container from FrostFS by ID. // Container reads a container from FrostFS by ID.
// //
// It returns exactly one non-nil value. It returns any error encountered which // It returns exactly one non-nil value. It returns any error encountered which

View file

@ -5,6 +5,7 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -25,6 +26,7 @@ import (
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
) )
@ -61,13 +63,14 @@ func (k *FeatureSettingsMock) FormContainerZone(ns string) string {
return ns + ".ns" return ns + ".ns"
} }
type TestFrostFS struct { var _ frostfs.FrostFS = (*TestFrostFS)(nil)
frostfs.FrostFS
type TestFrostFS struct {
objects map[string]*object.Object objects map[string]*object.Object
objectErrors map[string]error objectErrors map[string]error
objectPutErrors map[string]error objectPutErrors map[string]error
containers map[string]*container.Container containers map[string]*container.Container
chains map[string][]chain.Chain
currentEpoch uint64 currentEpoch uint64
key *keys.PrivateKey key *keys.PrivateKey
} }
@ -78,6 +81,7 @@ func NewTestFrostFS(key *keys.PrivateKey) *TestFrostFS {
objectErrors: make(map[string]error), objectErrors: make(map[string]error),
objectPutErrors: make(map[string]error), objectPutErrors: make(map[string]error),
containers: make(map[string]*container.Container), containers: make(map[string]*container.Container),
chains: make(map[string][]chain.Chain),
key: key, key: key,
} }
} }
@ -145,7 +149,6 @@ func (t *TestFrostFS) CreateContainer(_ context.Context, prm frostfs.PrmContaine
cnr.Init() cnr.Init()
cnr.SetOwner(prm.Creator) cnr.SetOwner(prm.Creator)
cnr.SetPlacementPolicy(prm.Policy) cnr.SetPlacementPolicy(prm.Policy)
cnr.SetBasicACL(prm.BasicACL)
creationTime := prm.CreationTime creationTime := prm.CreationTime
if creationTime.IsZero() { if creationTime.IsZero() {
@ -174,6 +177,7 @@ func (t *TestFrostFS) CreateContainer(_ context.Context, prm frostfs.PrmContaine
var id cid.ID var id cid.ID
id.SetSHA256(sha256.Sum256(b)) id.SetSHA256(sha256.Sum256(b))
t.containers[id.EncodeToString()] = &cnr t.containers[id.EncodeToString()] = &cnr
t.chains[id.EncodeToString()] = []chain.Chain{}
return &frostfs.ContainerCreateResult{ContainerID: id}, nil return &frostfs.ContainerCreateResult{ContainerID: id}, nil
} }
@ -455,6 +459,17 @@ func (t *TestFrostFS) PatchObject(ctx context.Context, prm frostfs.PrmObjectPatc
return newID, nil return newID, nil
} }
func (t *TestFrostFS) AddContainerPolicyChain(_ context.Context, prm frostfs.PrmAddContainerPolicyChain) error {
list, ok := t.chains[prm.ContainerID.EncodeToString()]
if !ok {
return errors.New("container not found")
}
t.chains[prm.ContainerID.EncodeToString()] = append(list, prm.Chain)
return nil
}
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID) bool { func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID) bool {
cnr, ok := t.containers[cnrID.EncodeToString()] cnr, ok := t.containers[cnrID.EncodeToString()]
if !ok { if !ok {

View file

@ -33,7 +33,7 @@ import (
// PrmContainerCreate groups parameters of containers created by authmate. // PrmContainerCreate groups parameters of containers created by authmate.
type PrmContainerCreate struct { type PrmContainerCreate struct {
// FrostFS identifier of the container creator. // FrostFS identifier of the container creator.
Owner user.ID Owner *keys.PublicKey
// Container placement policy. // Container placement policy.
Policy netmap.PlacementPolicy Policy netmap.PlacementPolicy

View file

@ -14,7 +14,6 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -227,10 +226,9 @@ func createAccessBox(ctx context.Context, frostFS *frostfs.AuthmateFrostFS, key
prm := authmate.PrmContainerCreate{ prm := authmate.PrmContainerCreate{
FriendlyName: friendlyName, FriendlyName: friendlyName,
Owner: key.PublicKey(),
} }
user.IDFromKey(&prm.Owner, key.PrivateKey.PublicKey)
if err := prm.Policy.DecodeString(placementPolicy); err != nil { if err := prm.Policy.DecodeString(placementPolicy); err != nil {
return cid.ID{}, fmt.Errorf("failed to build placement policy: %w", err) return cid.ID{}, fmt.Errorf("failed to build placement policy: %w", err)
} }

View file

@ -3,6 +3,7 @@ package frostfs
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/hex"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
@ -16,10 +17,12 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/crdt" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/crdt"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -55,21 +58,61 @@ func (x *AuthmateFrostFS) TimeToEpoch(ctx context.Context, futureTime time.Time)
// CreateContainer implements authmate.FrostFS interface method. // CreateContainer implements authmate.FrostFS interface method.
func (x *AuthmateFrostFS) CreateContainer(ctx context.Context, prm authmate.PrmContainerCreate) (cid.ID, error) { func (x *AuthmateFrostFS) CreateContainer(ctx context.Context, prm authmate.PrmContainerCreate) (cid.ID, error) {
basicACL := acl.Private var owner user.ID
// allow reading objects to OTHERS in order to provide read access to S3 gateways owner.SetScriptHash(prm.Owner.GetScriptHash())
basicACL.AllowOp(acl.OpObjectGet, acl.RoleOthers)
basicACL.AllowOp(acl.OpObjectHead, acl.RoleOthers)
basicACL.AllowOp(acl.OpObjectSearch, acl.RoleOthers)
res, err := x.frostFS.CreateContainer(ctx, frostfs.PrmContainerCreate{ res, err := x.frostFS.CreateContainer(ctx, frostfs.PrmContainerCreate{
Creator: prm.Owner, Creator: owner,
Policy: prm.Policy, Policy: prm.Policy,
Name: prm.FriendlyName, Name: prm.FriendlyName,
BasicACL: basicACL,
}) })
if err != nil { if err != nil {
return cid.ID{}, err return cid.ID{}, err
} }
ch := chain.Chain{
ID: chain.ID("authmate/" + owner.String()),
Rules: []chain.Rule{
{
Status: chain.Allow,
Actions: chain.Actions{Names: []string{"*"}},
Resources: chain.Resources{Names: []string{
fmt.Sprintf(native.ResourceFormatRootContainer, res.ContainerID),
fmt.Sprintf(native.ResourceFormatRootContainerObjects, res.ContainerID),
}},
Condition: []chain.Condition{{
Op: chain.CondStringEquals,
Kind: chain.KindRequest,
Key: native.PropertyKeyActorPublicKey,
Value: hex.EncodeToString(prm.Owner.Bytes()),
}},
},
{
Status: chain.Allow,
Actions: chain.Actions{Names: []string{
native.MethodGetContainer,
native.MethodGetObject,
native.MethodHeadObject,
native.MethodSearchObject,
native.MethodRangeObject,
native.MethodHashObject,
}},
Resources: chain.Resources{Names: []string{
fmt.Sprintf(native.ResourceFormatRootContainer, res.ContainerID),
fmt.Sprintf(native.ResourceFormatRootContainerObjects, res.ContainerID),
}},
},
},
}
err = x.frostFS.AddContainerPolicyChain(ctx, frostfs.PrmAddContainerPolicyChain{
ContainerID: res.ContainerID,
Chain: ch,
})
if err != nil {
return cid.ID{}, err
}
return res.ContainerID, nil return res.ContainerID, nil
} }

View file

@ -47,7 +47,7 @@ func TestCredsObject(t *testing.T) {
cnrID, err := frostfs.CreateContainer(ctx, authmate.PrmContainerCreate{ cnrID, err := frostfs.CreateContainer(ctx, authmate.PrmContainerCreate{
FriendlyName: bktName, FriendlyName: bktName,
Owner: userID, Owner: key.PublicKey(),
}) })
require.NoError(t, err) require.NoError(t, err)

View file

@ -12,6 +12,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors" frosterr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
@ -93,7 +94,6 @@ func (x *FrostFS) CreateContainer(ctx context.Context, prm frostfs.PrmContainerC
cnr.Init() cnr.Init()
cnr.SetPlacementPolicy(prm.Policy) cnr.SetPlacementPolicy(prm.Policy)
cnr.SetOwner(prm.Creator) cnr.SetOwner(prm.Creator)
cnr.SetBasicACL(prm.BasicACL)
creationTime := prm.CreationTime creationTime := prm.CreationTime
if creationTime.IsZero() { if creationTime.IsZero() {
@ -135,6 +135,25 @@ func (x *FrostFS) CreateContainer(ctx context.Context, prm frostfs.PrmContainerC
}, handleObjectError("save container via connection pool", err) }, handleObjectError("save container via connection pool", err)
} }
// AddContainerPolicyChain implements frostfs.FrostFS interface method.
func (x *FrostFS) AddContainerPolicyChain(ctx context.Context, prm frostfs.PrmAddContainerPolicyChain) error {
data, err := prm.Chain.MarshalBinary()
if err != nil {
return err
}
prmAddAPEChain := pool.PrmAddAPEChain{
Target: ape.ChainTarget{
TargetType: ape.TargetTypeContainer,
Name: prm.ContainerID.EncodeToString(),
},
Chain: ape.Chain{Raw: data},
}
err = x.pool.AddAPEChain(ctx, prmAddAPEChain)
return handleObjectError("add ape chain to container", err)
}
// UserContainers implements layer.FrostFS interface method. // UserContainers implements layer.FrostFS interface method.
func (x *FrostFS) UserContainers(ctx context.Context, layerPrm frostfs.PrmUserContainers) ([]cid.ID, error) { func (x *FrostFS) UserContainers(ctx context.Context, layerPrm frostfs.PrmUserContainers) ([]cid.ID, error) {
prm := pool.PrmContainerList{ prm := pool.PrmContainerList{