[#414] authmate: Add register-user command
All checks were successful
/ Builds (1.20) (pull_request) Successful in 14m30s
/ Builds (1.21) (pull_request) Successful in 14m25s
/ DCO (pull_request) Successful in 6m47s
/ Vulncheck (pull_request) Successful in 6m59s
/ Lint (pull_request) Successful in 11m52s
/ Tests (1.20) (pull_request) Successful in 8m24s
/ Tests (1.21) (pull_request) Successful in 8m19s

New command allows register user in frostfsid and
set allowed rules in policy contract

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2024-06-27 12:23:13 +03:00
parent f86b82351a
commit 70eedfc077
12 changed files with 284 additions and 93 deletions

View file

@ -16,6 +16,7 @@ This document outlines major changes between releases.
- Support tag checks in policies (#357, #365, #392) - Support tag checks in policies (#357, #365, #392)
- Support IAM-MFA checks (#367) - Support IAM-MFA checks (#367)
- More docs (#334, #353) - More docs (#334, #353)
- Add `register-user` command to `authmate` (#414)
### Changed ### Changed
- Update dependencies noted by govulncheck (#368) - Update dependencies noted by govulncheck (#368)

View file

@ -16,6 +16,10 @@ type (
frostFSIDInitError struct { frostFSIDInitError struct {
err error err error
} }
policyInitError struct {
err error
}
) )
func wrapPreparationError(e error) error { func wrapPreparationError(e error) error {
@ -50,6 +54,14 @@ func (e frostFSIDInitError) Error() string {
return e.err.Error() return e.err.Error()
} }
func wrapPolicyInitError(e error) error {
return policyInitError{e}
}
func (e policyInitError) 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 {
@ -62,6 +74,8 @@ func ExitCode(e error) int {
return 4 return 4
case frostFSIDInitError: case frostFSIDInitError:
return 4 return 4
case policyInitError:
return 5
} }
return 1 return 1
} }

View file

@ -7,7 +7,6 @@ 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/contract"
"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"
@ -36,16 +35,10 @@ const (
lifetimeFlag = "lifetime" lifetimeFlag = "lifetime"
containerPolicyFlag = "container-policy" containerPolicyFlag = "container-policy"
awsCLICredentialFlag = "aws-cli-credentials" awsCLICredentialFlag = "aws-cli-credentials"
frostfsIDFlag = "frostfsid"
frostfsIDProxyFlag = "frostfsid-proxy"
frostfsIDNamespaceFlag = "frostfsid-namespace"
rpcEndpointFlag = "rpc-endpoint"
attributesFlag = "attributes" attributesFlag = "attributes"
) )
const ( const walletPassphraseCfg = "wallet.passphrase"
walletPassphraseCfg = "wallet.passphrase"
)
const ( const (
defaultAccessBoxLifetime = 30 * 24 * time.Hour defaultAccessBoxLifetime = 30 * 24 * time.Hour
@ -79,10 +72,6 @@ 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(frostfsIDProxyFlag, "", "Proxy contract hash (LE) or name in NNS to use when interact with frostfsid contract")
issueSecretCmd.Flags().String(frostfsIDNamespaceFlag, "", "Namespace to register public key in frostfsid contract")
issueSecretCmd.Flags().String(rpcEndpointFlag, "", "NEO node RPC address")
issueSecretCmd.Flags().String(attributesFlag, "", "User attributes in form of Key1=Value1,Key2=Value2 (note: you cannot override system attributes)") issueSecretCmd.Flags().String(attributesFlag, "", "User attributes in form of Key1=Value1,Key2=Value2 (note: you cannot override system attributes)")
_ = issueSecretCmd.MarkFlagRequired(walletFlag) _ = issueSecretCmd.MarkFlagRequired(walletFlag)
@ -148,29 +137,6 @@ 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 := contract.Config{
RPCAddress: rpcAddress,
Contract: frostFSID,
ProxyContract: viper.GetString(frostfsIDProxyFlag),
Key: key,
}
frostfsIDClient, err := createFrostFSID(ctx, log, cfg)
if err != nil {
return wrapFrostFSIDInitError(err)
}
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
}
}
customAttrs, err := parseObjectAttrs(viper.GetString(attributesFlag)) customAttrs, err := parseObjectAttrs(viper.GetString(attributesFlag))
if err != nil { if err != nil {
return wrapPreparationError(fmt.Errorf("failed to parse attributes: %s", err)) return wrapPreparationError(fmt.Errorf("failed to parse attributes: %s", err))

View file

@ -0,0 +1,202 @@
package modules
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
ffsidContract "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
policyContact "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy/contract"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"
)
var registerUserCmd = &cobra.Command{
Use: "register-user",
Short: "Register user and add allowed policy to him",
Long: "Register user in FrostFSID contract and add allowed policies. This is need to get access to s3-gw operations.",
Example: `frostfs-s3-authmate register-user --wallet wallet.json --rpc-endpoint http://morph-chain.frostfs.devenv:30333
frostfs-s3-authmate register-user --wallet wallet.json --contract-wallet contract-wallet.json --rpc-endpoint http://morph-chain.frostfs.devenv:30333 --namespace namespace --frostfsid-name devenv --frostfsid-contract frostfsid.frostfs --proxy-contract proxy.frostfs --policy-contract policy.frostfs`,
RunE: runRegisterUserCmd,
}
const (
frostfsIDContractFlag = "frostfsid-contract"
proxyContractFlag = "proxy-contract"
usernameFlag = "username"
namespaceFlag = "namespace"
policyContractFlag = "policy-contract"
contractWalletFlag = "contract-wallet"
contractWalletAddressFlag = "contract-wallet-address"
rpcEndpointFlag = "rpc-endpoint"
)
const walletContractPassphraseCfg = "wallet.contract.passphrase"
func initRegisterUserCmd() {
registerUserCmd.Flags().String(walletFlag, "", "Path to the wallet with account of the user that will be registered in FrostFS ID contract")
registerUserCmd.Flags().String(addressFlag, "", "Address of the user wallet that will be registered in FrostFS ID contract")
registerUserCmd.Flags().String(frostfsIDContractFlag, "frostfsid.frostfs", "FrostfsID contract hash (LE) or name in NNS to register public key in contract")
registerUserCmd.Flags().String(proxyContractFlag, "proxy.frostfs", "Proxy contract hash (LE) or name in NNS to use when interact with frostfsid contract")
registerUserCmd.Flags().String(namespaceFlag, "", "Namespace to register public key in frostfsid contract and add policy chains")
registerUserCmd.Flags().String(usernameFlag, "", "Username to set for public key in frostfsid contract")
registerUserCmd.Flags().String(contractWalletFlag, "", "Path to wallet that will be used to interact with contracts (if missing key from wallet flag be used)")
registerUserCmd.Flags().String(contractWalletAddressFlag, "", "Address of the contract wallet account")
registerUserCmd.Flags().String(policyContractFlag, "policy.frostfs", "Policy contract hash (LE) or name in NNS to save allowed chains for key")
registerUserCmd.Flags().String(rpcEndpointFlag, "", "NEO node RPC address")
_ = registerUserCmd.MarkFlagRequired(walletFlag)
_ = registerUserCmd.MarkFlagRequired(rpcEndpointFlag)
}
func runRegisterUserCmd(cmd *cobra.Command, _ []string) error {
ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag))
defer cancel()
log := getLogger()
key, contractKey, err := parseKeys()
if err != nil {
return wrapPreparationError(err)
}
frostfsIDClient, err := initFrostFSIDContract(ctx, log, contractKey)
if err != nil {
return wrapFrostFSIDInitError(err)
}
if err = registerPublicKey(log, frostfsIDClient, key.PublicKey()); err != nil {
return wrapBusinessLogicError(err)
}
policyClient, err := initPolicyContract(ctx, log, contractKey)
if err != nil {
return wrapPolicyInitError(err)
}
if err = addAllowedPolicyChains(cmd, log, policyClient, key.PublicKey()); err != nil {
return wrapBusinessLogicError(err)
}
return nil
}
func parseKeys() (userKey *keys.PrivateKey, contractKey *keys.PrivateKey, err error) {
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
if err != nil {
return nil, nil, fmt.Errorf("failed to load frostfs private key: %s", err)
}
contractKey = key
if contractWallet := viper.GetString(contractWalletFlag); contractWallet != "" {
password = wallet.GetPassword(viper.GetViper(), walletContractPassphraseCfg)
contractKey, err = wallet.GetKeyFromPath(contractWallet, viper.GetString(contractWalletAddressFlag), password)
if err != nil {
return nil, nil, fmt.Errorf("failed to load contract private key: %s", err)
}
}
return key, contractKey, nil
}
func initFrostFSIDContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*ffsidContract.FrostFSID, error) {
log.Debug(logs.PrepareFrostfsIDClient)
cfg := ffsidContract.Config{
RPCAddress: viper.GetString(rpcEndpointFlag),
Contract: viper.GetString(frostfsIDContractFlag),
ProxyContract: viper.GetString(proxyContractFlag),
Key: key,
}
cli, err := ffsidContract.New(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("create frostfsid client: %w", err)
}
return cli, nil
}
func registerPublicKey(log *zap.Logger, cli *ffsidContract.FrostFSID, key *keys.PublicKey) error {
namespace := viper.GetString(namespaceFlag)
log.Debug(logs.CreateSubjectInFrostFSID)
err := cli.Wait(cli.CreateSubject(namespace, key))
if err != nil {
if strings.Contains(err.Error(), "subject already exists") {
log.Debug(logs.SubjectAlreadyExistsInFrostFSID, zap.String("address", key.Address()))
} else {
return fmt.Errorf("create subject in frostfsid: %w", err)
}
}
name := viper.GetString(usernameFlag)
if name == "" {
return nil
}
log.Debug(logs.SetSubjectNameInFrostFSID)
if err = cli.Wait(cli.SetSubjectName(key, name)); err != nil {
return fmt.Errorf("set subject name in frostfsid: %w", err)
}
return nil
}
func initPolicyContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*policyContact.Client, error) {
log.Debug(logs.PreparePolicyClient)
cfg := policyContact.Config{
RPCAddress: viper.GetString(rpcEndpointFlag),
Contract: viper.GetString(policyContractFlag),
ProxyContract: viper.GetString(proxyContractFlag),
Key: key,
}
cli, err := policyContact.New(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("create policy client: %w", err)
}
return cli, nil
}
func addAllowedPolicyChains(cmd *cobra.Command, log *zap.Logger, cli *policyContact.Client, key *keys.PublicKey) error {
log.Debug(logs.AddPolicyChainRules)
namespace := viper.GetString(namespaceFlag)
allowAllRule := chain.Rule{
Status: chain.Allow,
Actions: chain.Actions{Names: []string{"*"}},
Resources: chain.Resources{Names: []string{"*"}},
}
chains := []*chain.Chain{
{ID: chain.ID(chain.S3 + ":authmate"), Rules: []chain.Rule{allowAllRule}},
{ID: chain.ID(chain.Ingress + ":authmate"), Rules: []chain.Rule{allowAllRule}},
}
kind := policy.Kind(policy.User)
entity := namespace + ":" + key.Address()
tx := cli.StartTx()
for _, ch := range chains {
tx.AddChain(kind, entity, ch.ID, ch.Bytes())
}
if err := cli.SendTx(tx); err != nil {
return fmt.Errorf("add policy chain: %w", err)
}
cmd.Printf("Added policy rules:\nkind: '%c'\nentity: '%s'\nchains:\n", kind, entity)
enc := json.NewEncoder(os.Stdout)
return enc.Encode(chains)
}

View file

@ -65,4 +65,7 @@ GoVersion: {{ runtimeVersion }}
rootCmd.AddCommand(updateSecretCmd) rootCmd.AddCommand(updateSecretCmd)
initUpdateSecretCmd() initUpdateSecretCmd()
rootCmd.AddCommand(registerUserCmd)
initRegisterUserCmd()
} }

View file

@ -7,7 +7,6 @@ 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/contract"
"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"
@ -40,10 +39,6 @@ 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(frostfsIDProxyFlag, "", "Proxy contract hash (LE) or name in NNS to use when interact with frostfsid contract")
updateSecretCmd.Flags().String(frostfsIDNamespaceFlag, "", "Namespace to register public key in frostfsid contract")
updateSecretCmd.Flags().String(rpcEndpointFlag, "", "NEO node RPC address")
updateSecretCmd.Flags().String(attributesFlag, "", "User attributes in form of Key1=Value1,Key2=Value2 (note: you cannot override system attributes)") updateSecretCmd.Flags().String(attributesFlag, "", "User attributes in form of Key1=Value1,Key2=Value2 (note: you cannot override system attributes)")
_ = updateSecretCmd.MarkFlagRequired(walletFlag) _ = updateSecretCmd.MarkFlagRequired(walletFlag)
@ -100,29 +95,6 @@ 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 := contract.Config{
RPCAddress: rpcAddress,
Contract: frostFSID,
ProxyContract: viper.GetString(frostfsIDProxyFlag),
Key: key,
}
frostfsIDClient, err := createFrostFSID(ctx, log, cfg)
if err != nil {
return wrapFrostFSIDInitError(err)
}
if err = registerPublicKey(frostfsIDClient, viper.GetString(frostfsIDNamespaceFlag), key.PublicKey()); err != nil {
return wrapBusinessLogicError(fmt.Errorf("failed to register key in frostfsid: %w", err))
}
}
customAttrs, err := parseObjectAttrs(viper.GetString(attributesFlag)) customAttrs, err := parseObjectAttrs(viper.GetString(attributesFlag))
if err != nil { if err != nil {
return wrapPreparationError(fmt.Errorf("failed to parse attributes: %s", err)) return wrapPreparationError(fmt.Errorf("failed to parse attributes: %s", err))

View file

@ -11,7 +11,6 @@ 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/contract"
"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/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
@ -145,26 +144,6 @@ func getLogger() *zap.Logger {
return log return log
} }
func createFrostFSID(ctx context.Context, log *zap.Logger, cfg contract.Config) (*contract.FrostFSID, error) {
log.Debug(logs.PrepareFrostfsIDClient)
cli, err := contract.New(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("create frostfsid client: %w", err)
}
return cli, nil
}
func registerPublicKey(cli *contract.FrostFSID, namespace string, key *keys.PublicKey) error {
err := cli.Wait(cli.CreateSubject(namespace, key))
if err != nil && !strings.Contains(err.Error(), "subject already exists") {
return err
}
return nil
}
func parseObjectAttrs(attributes string) ([]object.Attribute, error) { func parseObjectAttrs(attributes string) ([]object.Attribute, error) {
if len(attributes) == 0 { if len(attributes) == 0 {
return nil, nil return nil, nil

View file

@ -146,12 +146,6 @@ the secret. Format of `access_key_id`: `%cid0%oid`, where 0(zero) is a delimiter
24h). Default value is `720h` (30 days). It will be ceil rounded to the nearest amount of epoch 24h). Default value is `720h` (30 days). It will be ceil rounded to the nearest amount of epoch
* `--aws-cli-credentials` - path to the aws cli credentials file, where authmate will write `access_key_id` and * `--aws-cli-credentials` - path to the aws cli credentials file, where authmate will write `access_key_id` and
`secret_access_key` to `secret_access_key` to
* `--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
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
@ -212,6 +206,57 @@ can be set via parameter `--container-policy` (json-string and file path allowed
} }
``` ```
## User registration
To be able to interact with FrostFS Storage using s3-gw the user (whose credential is used) must be registered in
`frostfsid` contract and also must have allowed chain rules in `policy` contract.
### CLI parameters
**Required parameters:**
* `--wallet` is a path to a wallet `.json` file. You can provide a passphrase to decrypt
a wallet via environment variable `AUTHMATE_WALLET_PASSPHRASE`, or you will be asked to enter a passphrase
interactively. You can also specify an account address to use from a wallet using the `--address` parameter. Key from
this wallet will be registered in `frostfsid` contract and for this key allowed rules will be added.
* `--rpc-endpoint` -- NEO node RPC address.
**Optional parameters:**
* `--frostfsid-contract` -- FrostfsID contract hash (LE) or name in NNS to register public key in contract (
default: `frostfsid.frostfs`).
* `--username` -- Username to set for public key in frostfsid contract.
* `--namespace` -- Namespace to register public key in frostfsid contract and add allowed rules (default: `""`).
* `--contract-wallet` -- is a path to a contract wallet `.json` file. This wallet will be used to sign transactions
(if missing key from wallet flag be used). You can provide a passphrase to decrypt
a wallet via environment variable `AUTHMATE_WALLET_CONTRACT_PASSPHRASE`, or you will be asked to enter a passphrase
interactively. You can also specify an account address to use from a wallet using the `--contract-wallet-address`
parameter.
* `--policy-contract` -- Policy contract hash (LE) or name in NNS to save allowed chains for key (
default: `policy.frostfs`).
* `--proxy-contract` -- Proxy contract hash (LE) or name in NNS to use when interact with frostfsid contract (
default: `proxy.frostfs`).
Example command that not only create access keys for key, but also register key in frostfsid contract and
create allowed rules in policy contract:
```shell
$ frostfs-s3-authmate register-user --wallet subject-wallet.json \
--contract-wallet wallet-registered-in-proxy-contract.json \
--frostfsid-contract frostfsid.frostfs \
--namespace "" \
--usrername devenv \
--proxy-contract proxy.frostfs \
--policy-contract policy.frostfs \
--rpc-endpoint http://morph-chain.frostfs.devenv:30333
Added policy rules:
kind: 'u'
entity: ':NbUgTSFvPmsRxmGeWpuuGeJUoRoi6PErcM'
chains:
[{"ID":"czM6YXV0aG1hdGU=","Rules":[{"Status":"Allow","Actions":{"Inverted":false,"Names":["*"]},"Resources":{"Inverted":false,"Names":["*"]},"Any":false,"Condition":null}],"MatchType":"DenyPriority"},{"ID":"aW5ncmVzczphdXRobWF0ZQ==","Rules":[{"Status":"Allow","Actions":{"Inverted":false,"Names":["*"]},"Resources":{"Inverted":false,"Names":["*"]},"Any":false,"Condition":null}],"MatchType":"DenyPriority"}]
```
## Obtaining credential secrets ## Obtaining credential secrets
You can get a secret access key and bearer token associated with an access key ID by obtaining a You can get a secret access key and bearer token associated with an access key ID by obtaining a

2
go.mod
View file

@ -4,7 +4,7 @@ go 1.20
require ( require (
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3 git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240417080107-db361318009c
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240531132048-ebd8fcd1685f git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240531132048-ebd8fcd1685f
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240611102930-ac965e8d176a

4
go.sum
View file

@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3 h1:H5GvrVlowIMWfzqQkhY0p0myooJxQ1sMRVSFfXawwWg= git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3 h1:H5GvrVlowIMWfzqQkhY0p0myooJxQ1sMRVSFfXawwWg=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o= git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240530152826-2f6d3209e1d3/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd h1:fujTUMMn0wnpEKNDWLejFL916EPuaYD1MdZpk1ZokU8= git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240417080107-db361318009c h1:V58j1eg12wxbl4fUbjWtBOexl3zFt4w0EGHpCPkWJhQ=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240409115729-6eb492025bdd/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc= git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240417080107-db361318009c/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo= git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=

View file

@ -78,6 +78,10 @@ func (f *FrostFSID) CreateSubject(namespace string, key *keys.PublicKey) (util.U
return f.cli.CreateSubject(namespace, key) return f.cli.CreateSubject(namespace, key)
} }
func (f *FrostFSID) SetSubjectName(key *keys.PublicKey, name string) (util.Uint256, uint32, error) {
return f.cli.SetSubjectName(key.GetScriptHash(), name)
}
func (f *FrostFSID) Wait(tx util.Uint256, vub uint32, err error) error { func (f *FrostFSID) Wait(tx util.Uint256, vub uint32, err error) error {
_, err = f.cli.Wait(tx, vub, err) _, err = f.cli.Wait(tx, vub, err)
return err return err

View file

@ -51,6 +51,11 @@ const (
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 PrepareFrostfsIDClient = "prepare frostfsid client" // Debug in ../../cmd/s3-authmate/modules/utils.go
PreparePolicyClient = "prepare policy client" // Debug in ../../cmd/s3-authmate/modules/utils.go
CreateSubjectInFrostFSID = "create subject in frostfsid" // Debug in ../../cmd/s3-authmate/modules/utils.go
SubjectAlreadyExistsInFrostFSID = "subject already exists in frostfsid" // Debug in ../../cmd/s3-authmate/modules/utils.go
SetSubjectNameInFrostFSID = "set subject name in frostfsid" // Debug in ../../cmd/s3-authmate/modules/utils.go
AddPolicyChainRules = "add policy chain rules" // 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