2021-05-19 09:28:17 +00:00
package authmate
2021-05-18 18:49:09 +00:00
import (
"context"
"crypto/ecdsa"
2021-05-25 16:52:29 +00:00
"encoding/hex"
2021-05-18 18:49:09 +00:00
"encoding/json"
2022-06-15 19:31:41 +00:00
"errors"
2021-05-20 10:14:17 +00:00
"fmt"
2021-05-18 18:49:09 +00:00
"io"
2021-09-01 11:30:15 +00:00
"os"
2021-05-18 18:49:09 +00:00
"time"
2023-06-23 13:06:59 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
sessionv2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
2023-03-07 14:38:08 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
2024-11-19 08:22:39 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
2023-03-07 14:38:08 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
2023-08-23 11:07:52 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
2024-11-19 08:22:39 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/retryer"
2023-03-07 14:38:08 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
2024-01-19 07:00:04 +00:00
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
2023-03-07 14:38:08 +00:00
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/user"
2024-11-19 08:22:39 +00:00
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/retry"
2021-06-16 20:09:51 +00:00
"github.com/google/uuid"
2021-06-24 15:21:34 +00:00
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
2021-05-18 18:49:09 +00:00
"go.uber.org/zap"
)
2022-03-01 19:02:24 +00:00
// PrmContainerCreate groups parameters of containers created by authmate.
type PrmContainerCreate struct {
2022-12-20 08:38:58 +00:00
// FrostFS identifier of the container creator.
2024-11-18 12:31:09 +00:00
Owner * keys . PublicKey
2022-03-01 19:02:24 +00:00
// Container placement policy.
Policy netmap . PlacementPolicy
// Friendly name for the container (optional).
FriendlyName string
}
2022-12-20 08:38:58 +00:00
// NetworkState represents FrostFS network state which is needed for authmate processing.
2022-03-01 19:02:24 +00:00
type NetworkState struct {
2022-12-20 08:38:58 +00:00
// Current FrostFS time.
2022-03-01 19:02:24 +00:00
Epoch uint64
// Duration of the Morph chain block in ms.
BlockDuration int64
2022-12-20 08:38:58 +00:00
// Duration of the FrostFS epoch in Morph chain blocks.
2022-03-01 19:02:24 +00:00
EpochDuration uint64
}
2022-12-20 08:38:58 +00:00
// FrostFS represents virtual connection to FrostFS network.
type FrostFS interface {
// FrostFS interface required by credential tool.
tokens . FrostFS
2022-03-01 19:02:24 +00:00
2022-12-20 08:38:58 +00:00
// ContainerExists checks container presence in FrostFS by identifier.
2022-04-13 16:56:58 +00:00
// Returns nil if container exists.
2022-03-01 19:02:24 +00:00
ContainerExists ( context . Context , cid . ID ) error
2022-12-20 08:38:58 +00:00
// CreateContainer creates and saves parameterized container in FrostFS.
2022-04-13 16:56:58 +00:00
// It sets 'Timestamp' attribute to the current time.
// It returns the ID of the saved container.
2022-03-01 19:02:24 +00:00
//
2022-04-13 16:56:58 +00:00
// The container must be private with GET access for OTHERS group.
2022-03-01 19:02:24 +00:00
// Creation time should also be stamped.
//
2022-04-13 16:56:58 +00:00
// It returns exactly one non-nil value. It returns any error encountered which
// prevented the container from being created.
2022-06-27 09:08:26 +00:00
CreateContainer ( context . Context , PrmContainerCreate ) ( cid . ID , error )
2022-03-01 19:02:24 +00:00
2022-04-13 16:56:58 +00:00
// TimeToEpoch computes the current epoch and the epoch that corresponds to the provided time.
2022-03-05 08:53:01 +00:00
// Note:
// * time must be in the future
// * time will be ceil rounded to match epoch
2022-03-01 19:02:24 +00:00
//
2022-04-13 16:56:58 +00:00
// It returns any error encountered which prevented computing epochs.
2022-03-05 08:53:01 +00:00
TimeToEpoch ( context . Context , time . Time ) ( uint64 , uint64 , error )
2022-03-01 19:02:24 +00:00
}
2021-05-18 18:49:09 +00:00
2022-12-20 08:38:58 +00:00
// Agent contains client communicating with FrostFS and logger.
2021-05-18 18:49:09 +00:00
type Agent struct {
2022-12-20 08:38:58 +00:00
frostFS FrostFS
log * zap . Logger
2024-11-19 08:22:39 +00:00
cfg * config
}
type config struct {
RetryMaxAttempts int
RetryMaxBackoff time . Duration
RetryStrategy handler . RetryStrategy
}
func defaultConfig ( ) * config {
return & config {
RetryMaxAttempts : 4 ,
RetryMaxBackoff : 30 * time . Second ,
RetryStrategy : handler . RetryStrategyExponential ,
}
}
type Option func ( cfg * config )
func WithRetryMaxAttempts ( attempts int ) func ( * config ) {
return func ( cfg * config ) {
cfg . RetryMaxAttempts = attempts
}
}
func WithRetryMaxBackoff ( backoff time . Duration ) func ( * config ) {
return func ( cfg * config ) {
cfg . RetryMaxBackoff = backoff
}
}
func WithRetryStrategy ( strategy handler . RetryStrategy ) func ( * config ) {
return func ( cfg * config ) {
cfg . RetryStrategy = strategy
}
2021-05-18 18:49:09 +00:00
}
2021-05-19 16:27:02 +00:00
// New creates an object of type Agent that consists of Client and logger.
2024-11-19 08:22:39 +00:00
func New ( log * zap . Logger , frostFS FrostFS , options ... Option ) * Agent {
cfg := defaultConfig ( )
for _ , opt := range options {
opt ( cfg )
}
return & Agent {
log : log ,
frostFS : frostFS ,
cfg : cfg ,
}
2021-05-18 18:49:09 +00:00
}
type (
2022-12-20 08:38:58 +00:00
// ContainerPolicies contains mapping of aws LocationConstraint to frostfs PlacementPolicy.
2021-07-16 12:35:07 +00:00
ContainerPolicies map [ string ] string
2021-05-19 16:27:02 +00:00
// IssueSecretOptions contains options for passing to Agent.IssueSecret method.
2021-05-18 18:49:09 +00:00
IssueSecretOptions struct {
2024-08-30 12:05:32 +00:00
Container cid . ID
AccessKeyID string
SecretAccessKey string
2022-12-20 08:38:58 +00:00
FrostFSKey * keys . PrivateKey
2021-06-24 15:21:34 +00:00
GatesPublicKeys [ ] * keys . PublicKey
2022-10-25 09:30:18 +00:00
Impersonate bool
2022-01-31 18:40:00 +00:00
SessionTokenRules [ ] byte
2022-03-30 12:23:00 +00:00
SkipSessionRules bool
2021-10-26 12:03:51 +00:00
Lifetime time . Duration
2021-09-01 11:30:15 +00:00
AwsCliCredentialsFile string
2021-07-16 12:35:07 +00:00
ContainerPolicies ContainerPolicies
2024-01-19 07:00:04 +00:00
CustomAttributes [ ] object . Attribute
2021-05-18 18:49:09 +00:00
}
2023-06-23 13:06:59 +00:00
// UpdateSecretOptions contains options for passing to Agent.UpdateSecret method.
UpdateSecretOptions struct {
2024-01-19 07:00:04 +00:00
FrostFSKey * keys . PrivateKey
GatesPublicKeys [ ] * keys . PublicKey
2024-08-30 12:05:32 +00:00
IsCustom bool
AccessKeyID string
ContainerID cid . ID
2024-01-19 07:00:04 +00:00
GatePrivateKey * keys . PrivateKey
CustomAttributes [ ] object . Attribute
2023-06-23 13:06:59 +00:00
}
tokenUpdateOptions struct {
frostFSKey * keys . PrivateKey
gatesPublicKeys [ ] * keys . PublicKey
lifetime lifetimeOptions
box * accessbox . Box
}
2022-03-03 12:43:56 +00:00
// ContainerOptions groups parameters of auth container to put the secret into.
ContainerOptions struct {
2022-06-27 09:08:26 +00:00
ID cid . ID
2022-03-03 12:43:56 +00:00
FriendlyName string
PlacementPolicy string
}
2023-06-13 09:35:40 +00:00
// UpdateOptions groups parameters to update existing the secret into.
UpdateOptions struct {
Address oid . Address
SecretAccessKey [ ] byte
}
2021-05-19 16:27:02 +00:00
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
2021-05-18 18:49:09 +00:00
ObtainSecretOptions struct {
2024-08-30 12:05:32 +00:00
Container cid . ID
AccessKeyID string
2021-06-24 15:21:34 +00:00
GatePrivateKey * keys . PrivateKey
2021-05-18 18:49:09 +00:00
}
)
2022-12-20 08:38:58 +00:00
// lifetimeOptions holds FrostFS epochs, iat -- epoch which the token was issued at, exp -- epoch when the token expires.
2021-06-28 13:20:11 +00:00
type lifetimeOptions struct {
Iat uint64
Exp uint64
}
2021-05-18 18:49:09 +00:00
type (
issuingResult struct {
2023-06-13 09:35:40 +00:00
InitialAccessKeyID string ` json:"initial_access_key_id" `
2023-06-23 13:06:59 +00:00
AccessKeyID string ` json:"access_key_id" `
2023-06-13 09:35:40 +00:00
SecretAccessKey string ` json:"secret_access_key" `
OwnerPrivateKey string ` json:"owner_private_key" `
WalletPublicKey string ` json:"wallet_public_key" `
ContainerID string ` json:"container_id" `
2021-05-18 18:49:09 +00:00
}
obtainingResult struct {
2023-06-09 11:31:31 +00:00
BearerToken * bearer . Token ` json:"bearer_token" `
2022-04-25 09:57:58 +00:00
SecretAccessKey string ` json:"secret_access_key" `
2021-05-18 18:49:09 +00:00
}
)
2024-08-30 12:05:32 +00:00
func ( a * Agent ) checkContainer ( ctx context . Context , cnrID cid . ID ) error {
a . log . Info ( logs . CheckContainer , zap . Stringer ( "cid" , cnrID ) )
return a . frostFS . ContainerExists ( ctx , cnrID )
2021-05-18 18:49:09 +00:00
}
2021-07-16 12:35:07 +00:00
func checkPolicy ( policyString string ) ( * netmap . PlacementPolicy , error ) {
2022-06-15 19:31:41 +00:00
var result netmap . PlacementPolicy
err := result . DecodeString ( policyString )
2021-07-16 12:35:07 +00:00
if err == nil {
2022-06-15 19:31:41 +00:00
return & result , nil
2021-07-16 12:35:07 +00:00
}
if err = result . UnmarshalJSON ( [ ] byte ( policyString ) ) ; err == nil {
2022-06-15 19:31:41 +00:00
return & result , nil
2021-07-16 12:35:07 +00:00
}
2022-06-15 19:31:41 +00:00
return nil , errors . New ( "can't parse placement policy" )
2021-07-16 12:35:07 +00:00
}
func preparePolicy ( policy ContainerPolicies ) ( [ ] * accessbox . AccessBox_ContainerPolicy , error ) {
if policy == nil {
return nil , nil
}
var result [ ] * accessbox . AccessBox_ContainerPolicy
for locationConstraint , placementPolicy := range policy {
parsedPolicy , err := checkPolicy ( placementPolicy )
if err != nil {
2022-06-22 19:40:52 +00:00
return nil , fmt . Errorf ( "check placement policy: %w" , err )
2021-07-16 12:35:07 +00:00
}
result = append ( result , & accessbox . AccessBox_ContainerPolicy {
LocationConstraint : locationConstraint ,
2022-06-15 19:31:41 +00:00
Policy : parsedPolicy . Marshal ( ) ,
2021-07-16 12:35:07 +00:00
} )
}
return result , nil
}
2022-12-20 08:38:58 +00:00
// IssueSecret creates an auth token, puts it in the FrostFS network and writes to io.Writer a new secret access key.
2021-05-18 18:49:09 +00:00
func ( a * Agent ) IssueSecret ( ctx context . Context , w io . Writer , options * IssueSecretOptions ) error {
var (
2021-06-28 13:20:11 +00:00
err error
box * accessbox . AccessBox
lifetime lifetimeOptions
2021-05-18 18:49:09 +00:00
)
2021-07-16 12:35:07 +00:00
policies , err := preparePolicy ( options . ContainerPolicies )
if err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "prepare policies: %w" , err )
2021-07-16 12:35:07 +00:00
}
2022-12-20 08:38:58 +00:00
lifetime . Iat , lifetime . Exp , err = a . frostFS . TimeToEpoch ( ctx , time . Now ( ) . Add ( options . Lifetime ) )
2021-06-28 13:20:11 +00:00
if err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "fetch time to epoch: %w" , err )
2021-06-28 13:20:11 +00:00
}
2022-03-11 09:59:52 +00:00
gatesData , err := createTokens ( options , lifetime )
2021-05-18 18:49:09 +00:00
if err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "create tokens: %w" , err )
2021-05-18 18:49:09 +00:00
}
2024-08-30 12:05:32 +00:00
var secret [ ] byte
isCustom := options . AccessKeyID != ""
if isCustom {
secret = [ ] byte ( options . SecretAccessKey )
}
box , secrets , err := accessbox . PackTokens ( gatesData , secret , isCustom )
2021-06-14 13:39:25 +00:00
if err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "pack tokens: %w" , err )
2021-06-14 13:39:25 +00:00
}
2021-06-16 20:09:51 +00:00
2021-07-16 12:35:07 +00:00
box . ContainerPolicy = policies
2024-08-30 12:05:32 +00:00
if err = a . checkContainer ( ctx , options . Container ) ; err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "check container: %w" , err )
2022-03-11 09:59:52 +00:00
}
2024-08-30 12:05:32 +00:00
var idOwner user . ID
user . IDFromKey ( & idOwner , options . FrostFSKey . PrivateKey . PublicKey )
2023-08-23 11:07:52 +00:00
a . log . Info ( logs . StoreBearerTokenIntoFrostFS ,
2022-02-08 16:54:04 +00:00
zap . Stringer ( "owner_tkn" , idOwner ) )
2021-06-16 14:07:31 +00:00
2024-02-06 13:44:49 +00:00
cfg := tokens . Config {
FrostFS : a . frostFS ,
Key : secrets . EphemeralKey ,
CacheConfig : cache . DefaultAccessBoxConfig ( a . log ) ,
}
creds := tokens . New ( cfg )
2023-06-13 09:35:40 +00:00
2024-01-19 07:00:04 +00:00
prm := tokens . CredentialsParam {
2024-08-30 12:05:32 +00:00
Container : options . Container ,
AccessKeyID : options . AccessKeyID ,
2024-01-19 07:00:04 +00:00
AccessBox : box ,
Expiration : lifetime . Exp ,
Keys : options . GatesPublicKeys ,
CustomAttributes : options . CustomAttributes ,
}
2024-11-19 08:22:39 +00:00
var addr oid . Address
err = retryer . MakeWithRetry ( ctx , func ( ) error {
var inErr error
addr , inErr = creds . Put ( ctx , prm )
return inErr
} , a . credsPutRetryer ( ) )
2021-05-18 18:49:09 +00:00
if err != nil {
2023-06-13 09:35:40 +00:00
return fmt . Errorf ( "failed to put creds: %w" , err )
2021-05-18 18:49:09 +00:00
}
2024-08-30 12:05:32 +00:00
accessKeyID := options . AccessKeyID
if accessKeyID == "" {
accessKeyID = accessKeyIDFromAddr ( addr )
}
2021-05-18 18:49:09 +00:00
ir := & issuingResult {
2023-06-23 13:06:59 +00:00
InitialAccessKeyID : accessKeyID ,
2023-06-13 09:35:40 +00:00
AccessKeyID : accessKeyID ,
2023-10-02 09:42:02 +00:00
SecretAccessKey : secrets . SecretKey ,
2023-06-13 09:35:40 +00:00
OwnerPrivateKey : hex . EncodeToString ( secrets . EphemeralKey . Bytes ( ) ) ,
WalletPublicKey : hex . EncodeToString ( options . FrostFSKey . PublicKey ( ) . Bytes ( ) ) ,
2024-08-30 12:05:32 +00:00
ContainerID : options . Container . EncodeToString ( ) ,
2021-05-18 18:49:09 +00:00
}
enc := json . NewEncoder ( w )
enc . SetIndent ( "" , " " )
2021-09-01 11:30:15 +00:00
if err = enc . Encode ( ir ) ; err != nil {
return err
}
if options . AwsCliCredentialsFile != "" {
2023-06-13 09:35:40 +00:00
profileName := "authmate_cred_" + addr . Object ( ) . EncodeToString ( )
2021-09-01 11:30:15 +00:00
if _ , err = os . Stat ( options . AwsCliCredentialsFile ) ; os . IsNotExist ( err ) {
profileName = "default"
}
file , err := os . OpenFile ( options . AwsCliCredentialsFile , os . O_APPEND | os . O_WRONLY | os . O_CREATE , 0600 )
if err != nil {
return fmt . Errorf ( "couldn't open aws cli credentials file: %w" , err )
}
defer file . Close ( )
if _ , err = file . WriteString ( fmt . Sprintf ( "\n[%s]\naws_access_key_id = %s\naws_secret_access_key = %s\n" ,
2023-10-02 09:42:02 +00:00
profileName , accessKeyID , secrets . SecretKey ) ) ; err != nil {
2022-06-22 19:40:52 +00:00
return fmt . Errorf ( "fails to write to file: %w" , err )
2021-09-01 11:30:15 +00:00
}
}
return nil
2021-05-18 18:49:09 +00:00
}
2023-06-23 13:06:59 +00:00
// UpdateSecret updates an auth token (change list of gates that can use credential), puts new cred version to the FrostFS network and writes to io.Writer a result.
func ( a * Agent ) UpdateSecret ( ctx context . Context , w io . Writer , options * UpdateSecretOptions ) error {
2024-02-06 13:44:49 +00:00
cfg := tokens . Config {
FrostFS : a . frostFS ,
Key : options . GatePrivateKey ,
CacheConfig : cache . DefaultAccessBoxConfig ( a . log ) ,
}
creds := tokens . New ( cfg )
2023-06-23 13:06:59 +00:00
2024-08-30 12:05:32 +00:00
box , _ , err := creds . GetBox ( ctx , options . ContainerID , options . AccessKeyID )
2023-06-23 13:06:59 +00:00
if err != nil {
return fmt . Errorf ( "get accessbox: %w" , err )
}
2024-08-30 12:05:32 +00:00
var secret [ ] byte
if options . IsCustom {
secret = [ ] byte ( box . Gate . SecretKey )
} else if secret , err = hex . DecodeString ( box . Gate . SecretKey ) ; err != nil {
2023-06-23 13:06:59 +00:00
return fmt . Errorf ( "failed to decode secret key access box: %w" , err )
}
lifetime := getLifetimeFromGateData ( box . Gate )
tokenOptions := tokenUpdateOptions {
frostFSKey : options . FrostFSKey ,
gatesPublicKeys : options . GatesPublicKeys ,
lifetime : lifetime ,
box : box ,
}
gatesData , err := formTokensToUpdate ( tokenOptions )
if err != nil {
return fmt . Errorf ( "create tokens: %w" , err )
}
2024-08-30 12:05:32 +00:00
updatedBox , secrets , err := accessbox . PackTokens ( gatesData , secret , options . IsCustom )
2023-06-23 13:06:59 +00:00
if err != nil {
return fmt . Errorf ( "pack tokens: %w" , err )
}
var idOwner user . ID
user . IDFromKey ( & idOwner , options . FrostFSKey . PrivateKey . PublicKey )
2023-08-23 11:07:52 +00:00
a . log . Info ( logs . UpdateAccessCredObjectIntoFrostFS ,
2023-06-23 13:06:59 +00:00
zap . Stringer ( "owner_tkn" , idOwner ) )
2024-01-19 07:00:04 +00:00
prm := tokens . CredentialsParam {
2024-08-30 12:05:32 +00:00
Container : options . ContainerID ,
2024-01-19 07:00:04 +00:00
AccessBox : updatedBox ,
Expiration : lifetime . Exp ,
Keys : options . GatesPublicKeys ,
CustomAttributes : options . CustomAttributes ,
}
2024-08-30 12:05:32 +00:00
addr , err := creds . Update ( ctx , prm )
2023-06-23 13:06:59 +00:00
if err != nil {
return fmt . Errorf ( "failed to update creds: %w" , err )
}
2024-08-30 12:05:32 +00:00
accessKeyID := options . AccessKeyID
if ! options . IsCustom {
accessKeyID = accessKeyIDFromAddr ( addr )
}
2023-06-23 13:06:59 +00:00
ir := & issuingResult {
2024-08-30 12:05:32 +00:00
AccessKeyID : accessKeyID ,
InitialAccessKeyID : options . AccessKeyID ,
2023-10-02 09:42:02 +00:00
SecretAccessKey : secrets . SecretKey ,
2023-06-23 13:06:59 +00:00
OwnerPrivateKey : hex . EncodeToString ( secrets . EphemeralKey . Bytes ( ) ) ,
WalletPublicKey : hex . EncodeToString ( options . FrostFSKey . PublicKey ( ) . Bytes ( ) ) ,
ContainerID : addr . Container ( ) . EncodeToString ( ) ,
}
enc := json . NewEncoder ( w )
enc . SetIndent ( "" , " " )
return enc . Encode ( ir )
}
func getLifetimeFromGateData ( gateData * accessbox . GateData ) lifetimeOptions {
var btokenv2 acl . BearerToken
gateData . BearerToken . WriteToV2 ( & btokenv2 )
return lifetimeOptions {
Iat : btokenv2 . GetBody ( ) . GetLifetime ( ) . GetIat ( ) ,
Exp : btokenv2 . GetBody ( ) . GetLifetime ( ) . GetExp ( ) ,
}
}
2022-12-20 08:38:58 +00:00
// ObtainSecret receives an existing secret access key from FrostFS and
2021-05-19 16:27:02 +00:00
// writes to io.Writer the secret access key.
2021-05-18 18:49:09 +00:00
func ( a * Agent ) ObtainSecret ( ctx context . Context , w io . Writer , options * ObtainSecretOptions ) error {
2024-02-06 13:44:49 +00:00
cfg := tokens . Config {
FrostFS : a . frostFS ,
Key : options . GatePrivateKey ,
CacheConfig : cache . DefaultAccessBoxConfig ( a . log ) ,
}
bearerCreds := tokens . New ( cfg )
2022-05-25 17:25:43 +00:00
2024-08-30 12:05:32 +00:00
box , _ , err := bearerCreds . GetBox ( ctx , options . Container , options . AccessKeyID )
2021-05-18 18:49:09 +00:00
if err != nil {
2021-06-17 16:45:50 +00:00
return fmt . Errorf ( "failed to get tokens: %w" , err )
2021-05-18 18:49:09 +00:00
}
or := & obtainingResult {
2021-07-16 12:35:07 +00:00
BearerToken : box . Gate . BearerToken ,
2023-10-02 09:42:02 +00:00
SecretAccessKey : box . Gate . SecretKey ,
2021-05-18 18:49:09 +00:00
}
enc := json . NewEncoder ( w )
enc . SetIndent ( "" , " " )
return enc . Encode ( or )
}
2024-11-19 08:22:39 +00:00
func ( a * Agent ) credsPutRetryer ( ) aws . RetryerV2 {
return retry . NewStandard ( func ( options * retry . StandardOptions ) {
options . MaxAttempts = a . cfg . RetryMaxAttempts
options . MaxBackoff = a . cfg . RetryMaxBackoff
if a . cfg . RetryStrategy == handler . RetryStrategyExponential {
options . Backoff = retry . NewExponentialJitterBackoff ( options . MaxBackoff )
} else {
options . Backoff = retry . BackoffDelayerFunc ( func ( int , error ) ( time . Duration , error ) {
return options . MaxBackoff , nil
} )
}
options . Retryables = [ ] retry . IsErrorRetryable { retry . IsErrorRetryableFunc ( func ( err error ) aws . Ternary {
if errors . Is ( err , frostfs . ErrAccessDenied ) {
return aws . TrueTernary
}
return aws . FalseTernary
} ) }
} )
}
2024-05-28 09:10:28 +00:00
func buildBearerToken ( key * keys . PrivateKey , impersonate bool , lifetime lifetimeOptions , gateKey * keys . PublicKey ) ( * bearer . Token , error ) {
2022-04-25 09:57:58 +00:00
var ownerID user . ID
user . IDFromKey ( & ownerID , ( ecdsa . PublicKey ) ( * gateKey ) )
2021-06-16 14:07:31 +00:00
2022-04-25 09:57:58 +00:00
var bearerToken bearer . Token
2022-06-01 14:00:30 +00:00
bearerToken . ForUser ( ownerID )
bearerToken . SetExp ( lifetime . Exp )
bearerToken . SetIat ( lifetime . Iat )
bearerToken . SetNbf ( lifetime . Iat )
2022-10-25 09:30:18 +00:00
bearerToken . SetImpersonate ( impersonate )
2021-05-18 18:49:09 +00:00
2022-06-01 14:00:30 +00:00
err := bearerToken . Sign ( key . PrivateKey )
if err != nil {
return nil , fmt . Errorf ( "sign bearer token: %w" , err )
}
return & bearerToken , nil
2021-05-18 18:49:09 +00:00
}
2021-05-25 16:52:29 +00:00
2024-05-28 09:10:28 +00:00
func buildBearerTokens ( key * keys . PrivateKey , impersonate bool , lifetime lifetimeOptions , gatesKeys [ ] * keys . PublicKey ) ( [ ] * bearer . Token , error ) {
2022-04-25 09:57:58 +00:00
bearerTokens := make ( [ ] * bearer . Token , 0 , len ( gatesKeys ) )
2021-06-18 15:15:58 +00:00
for _ , gateKey := range gatesKeys {
2024-05-28 09:10:28 +00:00
tkn , err := buildBearerToken ( key , impersonate , lifetime , gateKey )
2021-06-17 16:45:50 +00:00
if err != nil {
2022-06-22 19:40:52 +00:00
return nil , fmt . Errorf ( "build bearer token: %w" , err )
2021-06-17 16:45:50 +00:00
}
2021-06-18 15:15:58 +00:00
bearerTokens = append ( bearerTokens , tkn )
2021-06-17 16:45:50 +00:00
}
2021-06-18 15:15:58 +00:00
return bearerTokens , nil
2021-06-17 16:45:50 +00:00
}
2022-05-04 12:29:11 +00:00
func buildSessionToken ( key * keys . PrivateKey , lifetime lifetimeOptions , ctx sessionTokenContext , gateKey * keys . PublicKey ) ( * session . Container , error ) {
tok := new ( session . Container )
tok . ForVerb ( ctx . verb )
2023-06-23 08:20:05 +00:00
if ! ctx . containerID . Equals ( cid . ID { } ) {
tok . ApplyOnlyTo ( ctx . containerID )
}
2022-05-04 12:29:11 +00:00
tok . SetID ( uuid . New ( ) )
2022-12-20 08:38:58 +00:00
tok . SetAuthKey ( ( * frostfsecdsa . PublicKey ) ( gateKey ) )
2021-06-16 20:09:51 +00:00
2021-06-28 13:20:11 +00:00
tok . SetIat ( lifetime . Iat )
tok . SetNbf ( lifetime . Iat )
tok . SetExp ( lifetime . Exp )
2022-05-04 12:29:11 +00:00
return tok , tok . Sign ( key . PrivateKey )
2021-06-16 20:09:51 +00:00
}
2022-05-04 12:29:11 +00:00
func buildSessionTokens ( key * keys . PrivateKey , lifetime lifetimeOptions , ctxs [ ] sessionTokenContext , gatesKeys [ ] * keys . PublicKey ) ( [ ] [ ] * session . Container , error ) {
sessionTokens := make ( [ ] [ ] * session . Container , 0 , len ( gatesKeys ) )
2021-06-18 15:15:58 +00:00
for _ , gateKey := range gatesKeys {
2022-05-04 12:29:11 +00:00
tkns := make ( [ ] * session . Container , len ( ctxs ) )
2022-01-26 06:57:11 +00:00
for i , ctx := range ctxs {
2022-05-04 12:29:11 +00:00
tkn , err := buildSessionToken ( key , lifetime , ctx , gateKey )
2022-01-26 06:57:11 +00:00
if err != nil {
2022-06-22 19:40:52 +00:00
return nil , fmt . Errorf ( "build session token: %w" , err )
2022-01-26 06:57:11 +00:00
}
tkns [ i ] = tkn
2021-06-18 15:15:58 +00:00
}
2022-01-26 06:57:11 +00:00
sessionTokens = append ( sessionTokens , tkns )
2021-06-18 15:15:58 +00:00
}
return sessionTokens , nil
}
2022-03-11 09:59:52 +00:00
func createTokens ( options * IssueSecretOptions , lifetime lifetimeOptions ) ( [ ] * accessbox . GateData , error ) {
2021-06-18 15:15:58 +00:00
gates := make ( [ ] * accessbox . GateData , len ( options . GatesPublicKeys ) )
2024-05-28 09:10:28 +00:00
bearerTokens , err := buildBearerTokens ( options . FrostFSKey , options . Impersonate , lifetime , options . GatesPublicKeys )
2021-06-18 15:15:58 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to build bearer tokens: %w" , err )
}
for i , gateKey := range options . GatesPublicKeys {
gates [ i ] = accessbox . NewGateData ( gateKey , bearerTokens [ i ] )
}
2022-03-30 12:23:00 +00:00
if ! options . SkipSessionRules {
2022-01-31 18:40:00 +00:00
sessionRules , err := buildContext ( options . SessionTokenRules )
2021-06-16 14:07:31 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to build context for session token: %w" , err )
}
2021-06-18 15:15:58 +00:00
2022-12-20 08:38:58 +00:00
sessionTokens , err := buildSessionTokens ( options . FrostFSKey , lifetime , sessionRules , options . GatesPublicKeys )
2021-06-18 15:15:58 +00:00
if err != nil {
2022-02-16 19:26:51 +00:00
return nil , fmt . Errorf ( "failed to biuild session token: %w" , err )
2021-06-18 15:15:58 +00:00
}
2022-01-26 09:09:28 +00:00
for i , sessionTkns := range sessionTokens {
gates [ i ] . SessionTokens = sessionTkns
2021-06-18 15:15:58 +00:00
}
2021-06-16 14:07:31 +00:00
}
2021-06-18 15:15:58 +00:00
return gates , nil
2021-06-16 14:07:31 +00:00
}
2023-06-23 13:06:59 +00:00
func formTokensToUpdate ( options tokenUpdateOptions ) ( [ ] * accessbox . GateData , error ) {
btoken := options . box . Gate . BearerToken
2024-05-28 09:10:28 +00:00
btokenv2 := new ( acl . BearerToken )
btoken . WriteToV2 ( btokenv2 )
if btokenv2 . GetBody ( ) . GetEACL ( ) != nil {
return nil , errors . New ( "EACL table in bearer token isn't supported" )
}
bearerTokens , err := buildBearerTokens ( options . frostFSKey , btoken . Impersonate ( ) , options . lifetime , options . gatesPublicKeys )
2023-06-23 13:06:59 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to build bearer tokens: %w" , err )
}
gates := make ( [ ] * accessbox . GateData , len ( options . gatesPublicKeys ) )
for i , gateKey := range options . gatesPublicKeys {
gates [ i ] = accessbox . NewGateData ( gateKey , bearerTokens [ i ] )
}
sessionRules := make ( [ ] sessionTokenContext , len ( options . box . Gate . SessionTokens ) )
for i , token := range options . box . Gate . SessionTokens {
var stoken sessionv2 . Token
token . WriteToV2 ( & stoken )
sessionCtx , ok := stoken . GetBody ( ) . GetContext ( ) . ( * sessionv2 . ContainerSessionContext )
if ! ok {
return nil , fmt . Errorf ( "get context from session token: %w" , err )
}
var cnrID cid . ID
if cnrIDv2 := sessionCtx . ContainerID ( ) ; cnrIDv2 != nil {
if err = cnrID . ReadFromV2 ( * cnrIDv2 ) ; err != nil {
return nil , fmt . Errorf ( "read from v2 container id: %w" , err )
}
}
sessionRules [ i ] = sessionTokenContext {
verb : session . ContainerVerb ( sessionCtx . Verb ( ) ) ,
containerID : cnrID ,
}
}
sessionTokens , err := buildSessionTokens ( options . frostFSKey , options . lifetime , sessionRules , options . gatesPublicKeys )
if err != nil {
return nil , fmt . Errorf ( "failed to biuild session token: %w" , err )
}
for i , sessionTkns := range sessionTokens {
gates [ i ] . SessionTokens = sessionTkns
}
return gates , nil
}
func accessKeyIDFromAddr ( addr oid . Address ) string {
return addr . Container ( ) . EncodeToString ( ) + "0" + addr . Object ( ) . EncodeToString ( )
}