forked from TrueCloudLab/frostfs-s3-gw
[#108] authmate: Add lifetime for tokens
Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
parent
ce65a47d1b
commit
f97739898a
2 changed files with 63 additions and 15 deletions
|
@ -53,6 +53,7 @@ type (
|
|||
EACLRules []byte
|
||||
ContextRules []byte
|
||||
SessionTkn bool
|
||||
Lifetime uint64
|
||||
}
|
||||
|
||||
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
|
||||
|
@ -62,6 +63,12 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
// lifetimeOptions holds NeoFS epochs, iat -- epoch, which a token was issued at, exp -- epoch, when the token expires.
|
||||
type lifetimeOptions struct {
|
||||
Iat uint64
|
||||
Exp uint64
|
||||
}
|
||||
|
||||
type (
|
||||
issuingResult struct {
|
||||
AccessKeyID string `json:"access_key_id"`
|
||||
|
@ -104,20 +111,42 @@ func (a *Agent) checkContainer(ctx context.Context, cid *cid.ID, friendlyName st
|
|||
return cid, nil
|
||||
}
|
||||
|
||||
func (a *Agent) getCurrentEpoch(ctx context.Context) (uint64, error) {
|
||||
if conn, _, err := a.pool.Connection(); err != nil {
|
||||
return 0, err
|
||||
} else if networkInfo, err := conn.NetworkInfo(ctx); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
return networkInfo.CurrentEpoch(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// IssueSecret creates an auth token, puts it in the NeoFS network and writes to io.Writer a new secret access key.
|
||||
func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecretOptions) error {
|
||||
var (
|
||||
err error
|
||||
cid *cid.ID
|
||||
box *accessbox.AccessBox
|
||||
lifetime lifetimeOptions
|
||||
)
|
||||
|
||||
lifetime.Iat, err = a.getCurrentEpoch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Lifetime >= math.MaxUint64-lifetime.Iat {
|
||||
lifetime.Exp = math.MaxUint64
|
||||
} else {
|
||||
lifetime.Exp = lifetime.Iat + options.Lifetime
|
||||
}
|
||||
|
||||
a.log.Info("check container", zap.Stringer("cid", options.ContainerID))
|
||||
if cid, err = a.checkContainer(ctx, options.ContainerID, options.ContainerFriendlyName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gatesData, err := createTokens(options, cid)
|
||||
gatesData, err := createTokens(options, lifetime, cid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build bearer token: %w", err)
|
||||
}
|
||||
|
@ -257,7 +286,7 @@ func buildContext(rules []byte) (*session.ContainerContext, error) {
|
|||
return sessionCtx, nil
|
||||
}
|
||||
|
||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, gateKey *keys.PublicKey) (*token.BearerToken, error) {
|
||||
func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*token.BearerToken, error) {
|
||||
oid, err := ownerIDFromNeoFSKey(gateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -266,15 +295,15 @@ func buildBearerToken(key *keys.PrivateKey, table *eacl.Table, gateKey *keys.Pub
|
|||
bearerToken := token.NewBearerToken()
|
||||
bearerToken.SetEACLTable(table)
|
||||
bearerToken.SetOwner(oid)
|
||||
bearerToken.SetLifetime(math.MaxUint64, 0, 0)
|
||||
bearerToken.SetLifetime(lifetime.Exp, lifetime.Iat, lifetime.Iat)
|
||||
|
||||
return bearerToken, bearerToken.SignToken(&key.PrivateKey)
|
||||
}
|
||||
|
||||
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, gatesKeys []*keys.PublicKey) ([]*token.BearerToken, error) {
|
||||
func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*token.BearerToken, error) {
|
||||
bearerTokens := make([]*token.BearerToken, 0, len(gatesKeys))
|
||||
for _, gateKey := range gatesKeys {
|
||||
tkn, err := buildBearerToken(key, table, gateKey)
|
||||
tkn, err := buildBearerToken(key, table, lifetime, gateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -283,7 +312,7 @@ func buildBearerTokens(key *keys.PrivateKey, table *eacl.Table, gatesKeys []*key
|
|||
return bearerTokens, nil
|
||||
}
|
||||
|
||||
func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
|
||||
func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, lifetime lifetimeOptions, ctx *session.ContainerContext, gateKey *keys.PublicKey) (*session.Token, error) {
|
||||
tok := session.NewToken()
|
||||
tok.SetContext(ctx)
|
||||
uid, err := uuid.New().MarshalBinary()
|
||||
|
@ -294,13 +323,17 @@ func buildSessionToken(key *keys.PrivateKey, oid *owner.ID, ctx *session.Contain
|
|||
tok.SetOwnerID(oid)
|
||||
tok.SetSessionKey(gateKey.Bytes())
|
||||
|
||||
tok.SetIat(lifetime.Iat)
|
||||
tok.SetNbf(lifetime.Iat)
|
||||
tok.SetExp(lifetime.Exp)
|
||||
|
||||
return tok, tok.Sign(&key.PrivateKey)
|
||||
}
|
||||
|
||||
func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, ctx *session.ContainerContext, gatesKeys []*keys.PublicKey) ([]*session.Token, error) {
|
||||
func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, lifetime lifetimeOptions, ctx *session.ContainerContext, gatesKeys []*keys.PublicKey) ([]*session.Token, error) {
|
||||
sessionTokens := make([]*session.Token, 0, len(gatesKeys))
|
||||
for _, gateKey := range gatesKeys {
|
||||
tkn, err := buildSessionToken(key, oid, ctx, gateKey)
|
||||
tkn, err := buildSessionToken(key, oid, lifetime, ctx, gateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -309,14 +342,14 @@ func buildSessionTokens(key *keys.PrivateKey, oid *owner.ID, ctx *session.Contai
|
|||
return sessionTokens, nil
|
||||
}
|
||||
|
||||
func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateData, error) {
|
||||
func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions, cid *cid.ID) ([]*accessbox.GateData, error) {
|
||||
gates := make([]*accessbox.GateData, len(options.GatesPublicKeys))
|
||||
|
||||
table, err := buildEACLTable(cid, options.EACLRules)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build eacl table: %w", err)
|
||||
}
|
||||
bearerTokens, err := buildBearerTokens(options.NeoFSKey, table, options.GatesPublicKeys)
|
||||
bearerTokens, err := buildBearerTokens(options.NeoFSKey, table, lifetime, options.GatesPublicKeys)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
||||
}
|
||||
|
@ -334,7 +367,7 @@ func createTokens(options *IssueSecretOptions, cid *cid.ID) ([]*accessbox.GateDa
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, sessionRules, options.GatesPublicKeys)
|
||||
sessionTokens, err := buildSessionTokens(options.NeoFSKey, oid, lifetime, sessionRules, options.GatesPublicKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import (
|
|||
const (
|
||||
poolConnectTimeout = 5 * time.Second
|
||||
poolRequestTimeout = 5 * time.Second
|
||||
// a number of 15-second blocks in a month.
|
||||
defaultLifetime = 172800
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -42,6 +44,7 @@ var (
|
|||
logEnabledFlag bool
|
||||
logDebugEnabledFlag bool
|
||||
sessionTokenFlag bool
|
||||
lifetimeFlag uint64
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -191,6 +194,13 @@ func issueSecret() *cli.Command {
|
|||
Destination: &sessionTokenFlag,
|
||||
Value: false,
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "lifetime",
|
||||
Usage: "Lifetime of tokens in NeoFS epoch (number of blocks in sidechain)",
|
||||
Required: false,
|
||||
Destination: &lifetimeFlag,
|
||||
Value: defaultLifetime,
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
ctx, log := prepare()
|
||||
|
@ -222,11 +232,15 @@ func issueSecret() *cli.Command {
|
|||
for _, key := range gatesPublicKeysFlag.Value() {
|
||||
gpk, err := keys.NewPublicKeyFromString(key)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 5)
|
||||
return cli.Exit(fmt.Sprintf("failed to load gate's public key: %s", err), 4)
|
||||
}
|
||||
gatesPublicKeys = append(gatesPublicKeys, gpk)
|
||||
}
|
||||
|
||||
if lifetimeFlag <= 0 {
|
||||
return cli.Exit(fmt.Sprintf("lifetime must be at least 1, current value: %d", lifetimeFlag), 5)
|
||||
}
|
||||
|
||||
issueSecretOptions := &authmate.IssueSecretOptions{
|
||||
ContainerID: containerID,
|
||||
ContainerFriendlyName: containerFriendlyName,
|
||||
|
@ -235,6 +249,7 @@ func issueSecret() *cli.Command {
|
|||
EACLRules: []byte(eaclRulesFlag),
|
||||
ContextRules: []byte(contextRulesFlag),
|
||||
SessionTkn: sessionTokenFlag,
|
||||
Lifetime: lifetimeFlag,
|
||||
}
|
||||
|
||||
if err = agent.IssueSecret(ctx, os.Stdout, issueSecretOptions); err != nil {
|
||||
|
|
Loading…
Reference in a new issue