forked from TrueCloudLab/frostfs-s3-gw
[#81] Use impersonate bearer token
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
e487ee5b7d
commit
b366e75366
6 changed files with 39 additions and 11 deletions
|
@ -20,6 +20,7 @@ This document outlines major changes between releases.
|
|||
- Support string `Action` and `Resource` fields in `bucketPolicy.Statement` (TrueCloudLab#32)
|
||||
- Add new `kludge.use_default_xmlns_for_complete_multipart` config param (TrueCloudLab#40)
|
||||
- Support dump metrics descriptions (#80)
|
||||
- Support impersonate bearer token (#81)
|
||||
|
||||
### Changed
|
||||
- Update syncTree.sh due to recent renaming (#73)
|
||||
|
|
|
@ -329,7 +329,7 @@ func (n *layer) Owner(ctx context.Context) user.ID {
|
|||
|
||||
func (n *layer) prepareAuthParameters(ctx context.Context, prm *PrmAuth, bktOwner user.ID) {
|
||||
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil && bd.Gate.BearerToken != nil {
|
||||
if bktOwner.Equals(bearer.ResolveIssuer(*bd.Gate.BearerToken)) {
|
||||
if bd.Gate.BearerToken.Impersonate() || bktOwner.Equals(bearer.ResolveIssuer(*bd.Gate.BearerToken)) {
|
||||
prm.BearerToken = bd.Gate.BearerToken
|
||||
return
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ type (
|
|||
FrostFSKey *keys.PrivateKey
|
||||
GatesPublicKeys []*keys.PublicKey
|
||||
EACLRules []byte
|
||||
Impersonate bool
|
||||
SessionTokenRules []byte
|
||||
SkipSessionRules bool
|
||||
Lifetime time.Duration
|
||||
|
@ -344,16 +345,21 @@ func restrictedRecords() (records []*eacl.Record) {
|
|||
return
|
||||
}
|
||||
|
||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
||||
func buildBearerToken(key *keys.PrivateKey, impersonate bool, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
||||
var ownerID user.ID
|
||||
user.IDFromKey(&ownerID, (ecdsa.PublicKey)(*gateKey))
|
||||
|
||||
var bearerToken bearer.Token
|
||||
|
||||
if !impersonate {
|
||||
bearerToken.SetEACLTable(*table)
|
||||
}
|
||||
|
||||
bearerToken.ForUser(ownerID)
|
||||
bearerToken.SetExp(lifetime.Exp)
|
||||
bearerToken.SetIat(lifetime.Iat)
|
||||
bearerToken.SetNbf(lifetime.Iat)
|
||||
bearerToken.SetImpersonate(impersonate)
|
||||
|
||||
err := bearerToken.Sign(key.PrivateKey)
|
||||
if err != nil {
|
||||
|
@ -363,10 +369,10 @@ func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetime
|
|||
return &bearerToken, nil
|
||||
}
|
||||
|
||||
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*bearer.Token, error) {
|
||||
func buildBearerTokens(key *keys.PrivateKey, impersonate bool, table *eacl.Table, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*bearer.Token, error) {
|
||||
bearerTokens := make([]*bearer.Token, 0, len(gatesKeys))
|
||||
for _, gateKey := range gatesKeys {
|
||||
tkn, err := buildBearerToken(key, table, lifetime, gateKey)
|
||||
tkn, err := buildBearerToken(key, impersonate, table, lifetime, gateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build bearer token: %w", err)
|
||||
}
|
||||
|
@ -413,7 +419,8 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions) ([]*acc
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build eacl table: %w", err)
|
||||
}
|
||||
bearerTokens, err := buildBearerTokens(options.FrostFSKey, table, lifetime, options.GatesPublicKeys)
|
||||
|
||||
bearerTokens, err := buildBearerTokens(options.FrostFSKey, options.Impersonate, table, lifetime, options.GatesPublicKeys)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ var (
|
|||
accountAddressFlag string
|
||||
peerAddressFlag string
|
||||
eaclRulesFlag string
|
||||
disableImpersonateFlag bool
|
||||
gateWalletPathFlag string
|
||||
gateAccountAddressFlag string
|
||||
accessKeyIDFlag string
|
||||
|
@ -207,10 +208,16 @@ func issueSecret() *cli.Command {
|
|||
},
|
||||
&cli.StringFlag{
|
||||
Name: "bearer-rules",
|
||||
Usage: "rules for bearer token (filepath or a plain json string are allowed)",
|
||||
Usage: "rules for bearer token (filepath or a plain json string are allowed, can be used only with --disable-impersonate)",
|
||||
Required: false,
|
||||
Destination: &eaclRulesFlag,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "disable-impersonate",
|
||||
Usage: "mark token as not impersonate to don't consider token signer as request owner (must be provided to use --bearer-rules flag)",
|
||||
Required: false,
|
||||
Destination: &disableImpersonateFlag,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "gate-public-key",
|
||||
Usage: "public 256r1 key of a gate (use flags repeatedly for multiple gates)",
|
||||
|
@ -345,6 +352,10 @@ It will be ceil rounded to the nearest amount of epoch.`,
|
|||
return cli.Exit(fmt.Sprintf("couldn't parse container policy: %s", err.Error()), 6)
|
||||
}
|
||||
|
||||
if !disableImpersonateFlag && eaclRulesFlag != "" {
|
||||
return cli.Exit("--bearer-rules flag can be used only with --disable-impersonate", 6)
|
||||
}
|
||||
|
||||
bearerRules, err := getJSONRules(eaclRulesFlag)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("couldn't parse 'bearer-rules' flag: %s", err.Error()), 7)
|
||||
|
@ -364,6 +375,7 @@ It will be ceil rounded to the nearest amount of epoch.`,
|
|||
FrostFSKey: key,
|
||||
GatesPublicKeys: gatesPublicKeys,
|
||||
EACLRules: bearerRules,
|
||||
Impersonate: !disableImpersonateFlag,
|
||||
SessionTokenRules: sessionRules,
|
||||
SkipSessionRules: skipSessionRules,
|
||||
ContainerPolicies: policies,
|
||||
|
|
|
@ -139,12 +139,19 @@ the secret. Format of `access_key_id`: `%cid0%oid`, where 0(zero) is a delimiter
|
|||
|
||||
Creation of bearer tokens is mandatory.
|
||||
|
||||
Rules for a bearer token can be set via parameter `--bearer-rules` (json-string and file path allowed):
|
||||
By default, bearer token will be created with `impersonate` flag and won't have eACL table. It means that gate which will use such token
|
||||
to interact with node can have access to your private containers or to containers in which eACL grants access to you
|
||||
by public key.
|
||||
|
||||
Rules for a bearer token can be set via parameter `--bearer-rules` (json-string and file path allowed).
|
||||
But you must provide `--disable-impersonate` flag:
|
||||
|
||||
```shell
|
||||
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
||||
--peer 192.168.130.71:8080 \
|
||||
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
|
||||
--bearer-rules bearer-rules.json
|
||||
--bearer-rules bearer-rules.json \
|
||||
--disable-impersonate
|
||||
```
|
||||
where content of `bearer-rules.json`:
|
||||
```json
|
||||
|
|
|
@ -8,12 +8,13 @@ import (
|
|||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||
grpcService "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services/tree"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
|
@ -385,7 +386,7 @@ func metaToKV(meta map[string]string) []*grpcService.KeyValue {
|
|||
func getBearer(ctx context.Context, bktInfo *data.BucketInfo) []byte {
|
||||
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil {
|
||||
if bd.Gate.BearerToken != nil {
|
||||
if bktInfo.Owner.Equals(bearer.ResolveIssuer(*bd.Gate.BearerToken)) {
|
||||
if bd.Gate.BearerToken.Impersonate() || bktInfo.Owner.Equals(bearer.ResolveIssuer(*bd.Gate.BearerToken)) {
|
||||
return bd.Gate.BearerToken.Marshal()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue