forked from TrueCloudLab/frostfs-s3-gw
[#553] authmate: Don't use basic acl
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
368c7d2acd
commit
4fa45bdac2
8 changed files with 108 additions and 24 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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{
|
||||||
|
|
Loading…
Reference in a new issue