package modules import ( "context" "fmt" "os" "strings" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/spf13/cobra" "github.com/spf13/viper" ) var updateSecretCmd = &cobra.Command{ Use: "update-secret", Short: "Update a secret in FrostFS network", Long: `Creates new access box that will be available for extend list of s3 gates, preserve all timeout from initial credentials. After using this command you can use initial access-key-id to interact with newly added gates`, Example: `To extend list of s3 gates that can use existing credentials run: frostfs-s3-authmate update-secret --wallet wallet.json --peer s01.neofs.devenv:8080 --gate-wallet s3-wallet.json \ --gate-public-key 031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a \ --gate-public-key 021dc56fc6d81d581ae7605a8e00e0e0bab6cbad566a924a527339475a97a8e38e \ --acces-key-id EC3tyWpTEKfGNS888PFBpwQzZTrnwDXReGjgAxa8Em1h037VoWktUZCAk1LVA5SvVbVd2NHHb2NQm9jhcd5WFU5VD`, RunE: runUpdateSecretCmd, } func initUpdateSecretCmd() { updateSecretCmd.Flags().String(walletFlag, "", "Path to the wallet that will be owner of the credentials") updateSecretCmd.Flags().String(addressFlag, "", "Address of the wallet account") updateSecretCmd.Flags().String(peerFlag, "", "Address of a frostfs peer to connect to") updateSecretCmd.Flags().String(gateWalletFlag, "", "Path to the s3 gateway wallet to decrypt accessbox") updateSecretCmd.Flags().String(gateAddressFlag, "", "Address of the s3 gateway wallet account") updateSecretCmd.Flags().String(accessKeyIDFlag, "", "Access key id of s3 credential for which secret must be obtained") updateSecretCmd.Flags().StringSlice(gatePublicKeyFlag, nil, "Public 256r1 key of a gate (use flags repeatedly for multiple gates or separate them by comma)") updateSecretCmd.Flags().Duration(poolDialTimeoutFlag, defaultPoolDialTimeout, "Timeout for connection to the node in pool to be established") 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(poolStreamTimeoutFlag, defaultPoolStreamTimeout, "Timeout for individual operation in streaming RPC") _ = updateSecretCmd.MarkFlagRequired(walletFlag) _ = updateSecretCmd.MarkFlagRequired(peerFlag) _ = updateSecretCmd.MarkFlagRequired(gateWalletFlag) _ = updateSecretCmd.MarkFlagRequired(accessKeyIDFlag) _ = updateSecretCmd.MarkFlagRequired(gatePublicKeyFlag) } func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error { ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag)) defer cancel() log := getLogger() password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg) key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password) if err != nil { return wrapPreparationError(fmt.Errorf("failed to load frostfs private key: %s", err)) } gatePassword := wallet.GetPassword(viper.GetViper(), walletGatePassphraseCfg) gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword) if err != nil { return wrapPreparationError(fmt.Errorf("failed to load s3 gate private key: %s", err)) } var accessBoxAddress oid.Address credAddr := strings.Replace(viper.GetString(accessKeyIDFlag), "0", "/", 1) if err = accessBoxAddress.DecodeString(credAddr); err != nil { return wrapPreparationError(fmt.Errorf("failed to parse creds address: %w", err)) } var gatesPublicKeys []*keys.PublicKey for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) { gpk, err := keys.NewPublicKeyFromString(keyStr) if err != nil { return wrapPreparationError(fmt.Errorf("failed to load gate's public key: %s", err)) } gatesPublicKeys = append(gatesPublicKeys, gpk) } poolCfg := PoolConfig{ Key: key, Address: viper.GetString(peerFlag), DialTimeout: viper.GetDuration(poolDialTimeoutFlag), HealthcheckTimeout: viper.GetDuration(poolHealthcheckTimeoutFlag), StreamTimeout: viper.GetDuration(poolStreamTimeoutFlag), RebalanceInterval: viper.GetDuration(poolRebalanceIntervalFlag), } frostFS, err := createFrostFS(ctx, log, poolCfg) if err != nil { return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err)) } updateSecretOptions := &authmate.UpdateSecretOptions{ Address: accessBoxAddress, FrostFSKey: key, GatesPublicKeys: gatesPublicKeys, GatePrivateKey: gateKey, } if err = authmate.New(log, frostFS).UpdateSecret(ctx, os.Stdout, updateSecretOptions); err != nil { return wrapBusinessLogicError(fmt.Errorf("failed to update secret: %s", err)) } return nil }