forked from TrueCloudLab/frostfs-s3-gw
[#260] authmate: Support key registration in frostfsid contract
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
6304d7bfda
commit
a61ff3b8cb
8 changed files with 101 additions and 1 deletions
|
@ -81,6 +81,11 @@ type FrostFS interface {
|
||||||
TimeToEpoch(context.Context, time.Time) (uint64, uint64, error)
|
TimeToEpoch(context.Context, time.Time) (uint64, uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FrostFSID represents interface to interact with frostfsid contract.
|
||||||
|
type FrostFSID interface {
|
||||||
|
RegisterPublicKey(*keys.PublicKey) error
|
||||||
|
}
|
||||||
|
|
||||||
// Agent contains client communicating with FrostFS and logger.
|
// Agent contains client communicating with FrostFS and logger.
|
||||||
type Agent struct {
|
type Agent struct {
|
||||||
frostFS FrostFS
|
frostFS FrostFS
|
||||||
|
|
|
@ -12,6 +12,10 @@ type (
|
||||||
businessLogicError struct {
|
businessLogicError struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frostFSIDInitError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func wrapPreparationError(e error) error {
|
func wrapPreparationError(e error) error {
|
||||||
|
@ -38,6 +42,14 @@ func (e businessLogicError) Error() string {
|
||||||
return e.err.Error()
|
return e.err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapFrostFSIDInitError(e error) error {
|
||||||
|
return frostFSIDInitError{e}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e frostFSIDInitError) Error() string {
|
||||||
|
return e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
// ExitCode picks corresponding error code depending on the type of error provided.
|
// ExitCode picks corresponding error code depending on the type of error provided.
|
||||||
// Returns 1 if error type is unknown.
|
// Returns 1 if error type is unknown.
|
||||||
func ExitCode(e error) int {
|
func ExitCode(e error) int {
|
||||||
|
@ -48,6 +60,8 @@ func ExitCode(e error) int {
|
||||||
return 3
|
return 3
|
||||||
case businessLogicError:
|
case businessLogicError:
|
||||||
return 4
|
return 4
|
||||||
|
case frostFSIDInitError:
|
||||||
|
return 4
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
"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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -37,6 +38,8 @@ const (
|
||||||
lifetimeFlag = "lifetime"
|
lifetimeFlag = "lifetime"
|
||||||
containerPolicyFlag = "container-policy"
|
containerPolicyFlag = "container-policy"
|
||||||
awsCLICredentialFlag = "aws-cli-credentials"
|
awsCLICredentialFlag = "aws-cli-credentials"
|
||||||
|
frostfsIDFlag = "frostfsid"
|
||||||
|
rpcEndpointFlag = "rpc-endpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -77,6 +80,8 @@ func initIssueSecretCmd() {
|
||||||
issueSecretCmd.Flags().Duration(poolHealthcheckTimeoutFlag, defaultPoolHealthcheckTimeout, "Timeout for request to node to decide if it is alive")
|
issueSecretCmd.Flags().Duration(poolHealthcheckTimeoutFlag, defaultPoolHealthcheckTimeout, "Timeout for request to node to decide if it is alive")
|
||||||
issueSecretCmd.Flags().Duration(poolRebalanceIntervalFlag, defaultPoolRebalanceInterval, "Interval for updating nodes health status")
|
issueSecretCmd.Flags().Duration(poolRebalanceIntervalFlag, defaultPoolRebalanceInterval, "Interval for updating nodes health status")
|
||||||
issueSecretCmd.Flags().Duration(poolStreamTimeoutFlag, defaultPoolStreamTimeout, "Timeout for individual operation in streaming RPC")
|
issueSecretCmd.Flags().Duration(poolStreamTimeoutFlag, defaultPoolStreamTimeout, "Timeout for individual operation in streaming RPC")
|
||||||
|
issueSecretCmd.Flags().String(frostfsIDFlag, "", "FrostfsID contract hash (LE) or name in NNS to register public key in contract (rpc-endpoint flag also must be provided)")
|
||||||
|
issueSecretCmd.Flags().String(rpcEndpointFlag, "", "NEO node RPC address")
|
||||||
|
|
||||||
_ = issueSecretCmd.MarkFlagRequired(walletFlag)
|
_ = issueSecretCmd.MarkFlagRequired(walletFlag)
|
||||||
_ = issueSecretCmd.MarkFlagRequired(peerFlag)
|
_ = issueSecretCmd.MarkFlagRequired(peerFlag)
|
||||||
|
@ -152,6 +157,28 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frostFSID := viper.GetString(frostfsIDFlag)
|
||||||
|
if frostFSID != "" {
|
||||||
|
rpcAddress := viper.GetString(rpcEndpointFlag)
|
||||||
|
if rpcAddress == "" {
|
||||||
|
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
||||||
|
}
|
||||||
|
cfg := frostfsid.Config{
|
||||||
|
RPCAddress: rpcAddress,
|
||||||
|
Contract: frostFSID,
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
|
||||||
|
frostfsIDClient, err := createFrostFSID(ctx, log, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return wrapFrostFSIDInitError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = frostfsIDClient.RegisterPublicKey(key.PublicKey()); err != nil {
|
||||||
|
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
issueSecretOptions := &authmate.IssueSecretOptions{
|
issueSecretOptions := &authmate.IssueSecretOptions{
|
||||||
Container: authmate.ContainerOptions{
|
Container: authmate.ContainerOptions{
|
||||||
ID: cnrID,
|
ID: cnrID,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -39,6 +40,8 @@ func initUpdateSecretCmd() {
|
||||||
updateSecretCmd.Flags().Duration(poolHealthcheckTimeoutFlag, defaultPoolHealthcheckTimeout, "Timeout for request to node to decide if it is alive")
|
updateSecretCmd.Flags().Duration(poolHealthcheckTimeoutFlag, defaultPoolHealthcheckTimeout, "Timeout for request to node to decide if it is alive")
|
||||||
updateSecretCmd.Flags().Duration(poolRebalanceIntervalFlag, defaultPoolRebalanceInterval, "Interval for updating nodes health status")
|
updateSecretCmd.Flags().Duration(poolRebalanceIntervalFlag, defaultPoolRebalanceInterval, "Interval for updating nodes health status")
|
||||||
updateSecretCmd.Flags().Duration(poolStreamTimeoutFlag, defaultPoolStreamTimeout, "Timeout for individual operation in streaming RPC")
|
updateSecretCmd.Flags().Duration(poolStreamTimeoutFlag, defaultPoolStreamTimeout, "Timeout for individual operation in streaming RPC")
|
||||||
|
updateSecretCmd.Flags().String(frostfsIDFlag, "", "FrostfsID contract hash (LE) or name in NNS to register public key in contract (rpc-endpoint flag also must be provided)")
|
||||||
|
updateSecretCmd.Flags().String(rpcEndpointFlag, "", "NEO node RPC address")
|
||||||
|
|
||||||
_ = updateSecretCmd.MarkFlagRequired(walletFlag)
|
_ = updateSecretCmd.MarkFlagRequired(walletFlag)
|
||||||
_ = updateSecretCmd.MarkFlagRequired(peerFlag)
|
_ = updateSecretCmd.MarkFlagRequired(peerFlag)
|
||||||
|
@ -94,6 +97,28 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frostFSID := viper.GetString(frostfsIDFlag)
|
||||||
|
if frostFSID != "" {
|
||||||
|
rpcAddress := viper.GetString(rpcEndpointFlag)
|
||||||
|
if rpcAddress == "" {
|
||||||
|
return wrapPreparationError(fmt.Errorf("you can use '%s' flag only along with '%s'", frostfsIDFlag, rpcEndpointFlag))
|
||||||
|
}
|
||||||
|
cfg := frostfsid.Config{
|
||||||
|
RPCAddress: rpcAddress,
|
||||||
|
Contract: frostFSID,
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
|
||||||
|
frostfsIDClient, err := createFrostFSID(ctx, log, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return wrapFrostFSIDInitError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = frostfsIDClient.RegisterPublicKey(key.PublicKey()); err != nil {
|
||||||
|
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateSecretOptions := &authmate.UpdateSecretOptions{
|
updateSecretOptions := &authmate.UpdateSecretOptions{
|
||||||
Address: accessBoxAddress,
|
Address: accessBoxAddress,
|
||||||
FrostFSKey: key,
|
FrostFSKey: key,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
"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/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -141,3 +142,14 @@ func getLogger() *zap.Logger {
|
||||||
|
|
||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg frostfsid.Config) (authmate.FrostFSID, error) {
|
||||||
|
log.Debug(logs.PrepareFrostfsIDClient)
|
||||||
|
|
||||||
|
cli, err := frostfsid.New(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cli, nil
|
||||||
|
}
|
||||||
|
|
|
@ -143,6 +143,9 @@ the secret. Format of `access_key_id`: `%cid0%oid`, where 0(zero) is a delimiter
|
||||||
* `--access-key-id` -- credentials that you want to update (e.g. to add more gates that can use your creds)
|
* `--access-key-id` -- credentials that you want to update (e.g. to add more gates that can use your creds)
|
||||||
without changing values of `aws_access_key_id` and `aws_secret_access_key`. If you want to update credential you MUST
|
without changing values of `aws_access_key_id` and `aws_secret_access_key`. If you want to update credential you MUST
|
||||||
provide also secret key using `AUTHMATE_SECRET_ACCESS_KEY` env variable.
|
provide also secret key using `AUTHMATE_SECRET_ACCESS_KEY` env variable.
|
||||||
|
* `--frostfsid` -- FrostfsID contract hash (LE) or name in NNS to register public key in contract
|
||||||
|
(`--rpc-endpoint` flag also must be provided).
|
||||||
|
* `--rpc-endpoint` -- NEO node RPC address.
|
||||||
|
|
||||||
### Bearer tokens
|
### Bearer tokens
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -31,7 +32,10 @@ type Config struct {
|
||||||
Key *keys.PrivateKey
|
Key *keys.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ middleware.FrostFSID = (*FrostFSID)(nil)
|
var (
|
||||||
|
_ middleware.FrostFSID = (*FrostFSID)(nil)
|
||||||
|
_ authmate.FrostFSID = (*FrostFSID)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
||||||
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
|
@ -67,6 +71,15 @@ func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FrostFSID) RegisterPublicKey(key *keys.PublicKey) error {
|
||||||
|
_, err := f.cli.Wait(f.cli.CreateSubject(key))
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func fetchContractHash(cfg Config) (util.Uint160, error) {
|
func fetchContractHash(cfg Config) (util.Uint160, error) {
|
||||||
if hash, err := util.Uint160DecodeStringLE(cfg.Contract); err == nil {
|
if hash, err := util.Uint160DecodeStringLE(cfg.Contract); err == nil {
|
||||||
return hash, nil
|
return hash, nil
|
||||||
|
|
|
@ -45,6 +45,7 @@ const (
|
||||||
SkipEmptyAddress = "skip, empty address" // Warn in ../../cmd/s3-gw/app_settings.go
|
SkipEmptyAddress = "skip, empty address" // Warn in ../../cmd/s3-gw/app_settings.go
|
||||||
AddedStoragePeer = "added storage peer" // Info in ../../cmd/s3-gw/app_settings.go
|
AddedStoragePeer = "added storage peer" // Info in ../../cmd/s3-gw/app_settings.go
|
||||||
PrepareConnectionPool = "prepare connection pool" // Debug in ../../cmd/s3-authmate/modules/utils.go
|
PrepareConnectionPool = "prepare connection pool" // Debug in ../../cmd/s3-authmate/modules/utils.go
|
||||||
|
PrepareFrostfsIDClient = "prepare frostfsid client" // Debug in ../../cmd/s3-authmate/modules/utils.go
|
||||||
InvalidCacheEntryType = "invalid cache entry type" // Warn in ../../api/cache/*
|
InvalidCacheEntryType = "invalid cache entry type" // Warn in ../../api/cache/*
|
||||||
InvalidCacheKeyType = "invalid cache key type" // Warn in ../../api/cache/objectslist.go
|
InvalidCacheKeyType = "invalid cache key type" // Warn in ../../api/cache/objectslist.go
|
||||||
ObjectIsCopied = "object is copied" // Info in ../../api/handler/copy.go
|
ObjectIsCopied = "object is copied" // Info in ../../api/handler/copy.go
|
||||||
|
|
Loading…
Reference in a new issue