forked from TrueCloudLab/frostfs-s3-gw
[#372] authmate: Don't create creds with eacl table
Allow only impersonate flag. Don't allow SetEACL container session token. Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
77f8bdac58
commit
9241954496
5 changed files with 89 additions and 209 deletions
|
@ -20,7 +20,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
@ -102,7 +101,6 @@ type (
|
||||||
Container ContainerOptions
|
Container ContainerOptions
|
||||||
FrostFSKey *keys.PrivateKey
|
FrostFSKey *keys.PrivateKey
|
||||||
GatesPublicKeys []*keys.PublicKey
|
GatesPublicKeys []*keys.PublicKey
|
||||||
EACLRules []byte
|
|
||||||
Impersonate bool
|
Impersonate bool
|
||||||
SessionTokenRules []byte
|
SessionTokenRules []byte
|
||||||
SkipSessionRules bool
|
SkipSessionRules bool
|
||||||
|
@ -441,47 +439,11 @@ func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSe
|
||||||
return enc.Encode(or)
|
return enc.Encode(or)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildEACLTable(eaclTable []byte) (*eacl.Table, error) {
|
func buildBearerToken(key *keys.PrivateKey, impersonate bool, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
||||||
table := eacl.NewTable()
|
|
||||||
if len(eaclTable) != 0 {
|
|
||||||
return table, table.UnmarshalJSON(eaclTable)
|
|
||||||
}
|
|
||||||
|
|
||||||
record := eacl.NewRecord()
|
|
||||||
record.SetOperation(eacl.OperationGet)
|
|
||||||
record.SetAction(eacl.ActionAllow)
|
|
||||||
eacl.AddFormedTarget(record, eacl.RoleOthers)
|
|
||||||
table.AddRecord(record)
|
|
||||||
|
|
||||||
for _, rec := range restrictedRecords() {
|
|
||||||
table.AddRecord(rec)
|
|
||||||
}
|
|
||||||
|
|
||||||
return table, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func restrictedRecords() (records []*eacl.Record) {
|
|
||||||
for op := eacl.OperationGet; op <= eacl.OperationRangeHash; op++ {
|
|
||||||
record := eacl.NewRecord()
|
|
||||||
record.SetOperation(op)
|
|
||||||
record.SetAction(eacl.ActionDeny)
|
|
||||||
eacl.AddFormedTarget(record, eacl.RoleOthers)
|
|
||||||
records = append(records, record)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildBearerToken(key *keys.PrivateKey, impersonate bool, table *eacl.Table, lifetime lifetimeOptions, gateKey *keys.PublicKey) (*bearer.Token, error) {
|
|
||||||
var ownerID user.ID
|
var ownerID user.ID
|
||||||
user.IDFromKey(&ownerID, (ecdsa.PublicKey)(*gateKey))
|
user.IDFromKey(&ownerID, (ecdsa.PublicKey)(*gateKey))
|
||||||
|
|
||||||
var bearerToken bearer.Token
|
var bearerToken bearer.Token
|
||||||
|
|
||||||
if !impersonate {
|
|
||||||
bearerToken.SetEACLTable(*table)
|
|
||||||
}
|
|
||||||
|
|
||||||
bearerToken.ForUser(ownerID)
|
bearerToken.ForUser(ownerID)
|
||||||
bearerToken.SetExp(lifetime.Exp)
|
bearerToken.SetExp(lifetime.Exp)
|
||||||
bearerToken.SetIat(lifetime.Iat)
|
bearerToken.SetIat(lifetime.Iat)
|
||||||
|
@ -496,10 +458,10 @@ func buildBearerToken(key *keys.PrivateKey, impersonate bool, table *eacl.Table,
|
||||||
return &bearerToken, nil
|
return &bearerToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildBearerTokens(key *keys.PrivateKey, impersonate bool, table *eacl.Table, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*bearer.Token, error) {
|
func buildBearerTokens(key *keys.PrivateKey, impersonate bool, lifetime lifetimeOptions, gatesKeys []*keys.PublicKey) ([]*bearer.Token, error) {
|
||||||
bearerTokens := make([]*bearer.Token, 0, len(gatesKeys))
|
bearerTokens := make([]*bearer.Token, 0, len(gatesKeys))
|
||||||
for _, gateKey := range gatesKeys {
|
for _, gateKey := range gatesKeys {
|
||||||
tkn, err := buildBearerToken(key, impersonate, table, lifetime, gateKey)
|
tkn, err := buildBearerToken(key, impersonate, lifetime, gateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("build bearer token: %w", err)
|
return nil, fmt.Errorf("build bearer token: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -544,12 +506,7 @@ func buildSessionTokens(key *keys.PrivateKey, lifetime lifetimeOptions, ctxs []s
|
||||||
func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions) ([]*accessbox.GateData, error) {
|
func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions) ([]*accessbox.GateData, error) {
|
||||||
gates := make([]*accessbox.GateData, len(options.GatesPublicKeys))
|
gates := make([]*accessbox.GateData, len(options.GatesPublicKeys))
|
||||||
|
|
||||||
table, err := buildEACLTable(options.EACLRules)
|
bearerTokens, err := buildBearerTokens(options.FrostFSKey, options.Impersonate, lifetime, options.GatesPublicKeys)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to build eacl table: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bearerTokens, err := buildBearerTokens(options.FrostFSKey, options.Impersonate, table, lifetime, options.GatesPublicKeys)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -577,9 +534,14 @@ func createTokens(options *IssueSecretOptions, lifetime lifetimeOptions) ([]*acc
|
||||||
|
|
||||||
func formTokensToUpdate(options tokenUpdateOptions) ([]*accessbox.GateData, error) {
|
func formTokensToUpdate(options tokenUpdateOptions) ([]*accessbox.GateData, error) {
|
||||||
btoken := options.box.Gate.BearerToken
|
btoken := options.box.Gate.BearerToken
|
||||||
table := btoken.EACLTable()
|
|
||||||
|
|
||||||
bearerTokens, err := buildBearerTokens(options.frostFSKey, btoken.Impersonate(), &table, options.lifetime, options.gatesPublicKeys)
|
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
return nil, fmt.Errorf("failed to build bearer tokens: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package authmate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
apisession "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
apisession "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
||||||
|
@ -55,22 +56,11 @@ func buildContext(rules []byte) ([]sessionTokenContext, error) {
|
||||||
return nil, fmt.Errorf("failed to unmarshal rules for session token: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal rules for session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
containsPut = false
|
|
||||||
containsSetEACL = false
|
|
||||||
)
|
|
||||||
for _, d := range sessionCtxs {
|
for _, d := range sessionCtxs {
|
||||||
if d.verb == session.VerbContainerPut {
|
if d.verb == session.VerbContainerSetEACL {
|
||||||
containsPut = true
|
return nil, errors.New("verb container SetEACL isn't supported")
|
||||||
} else if d.verb == session.VerbContainerSetEACL {
|
|
||||||
containsSetEACL = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if containsPut && !containsSetEACL {
|
|
||||||
sessionCtxs = append(sessionCtxs, sessionTokenContext{
|
|
||||||
verb: session.VerbContainerSetEACL,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return sessionCtxs, nil
|
return sessionCtxs, nil
|
||||||
}
|
}
|
||||||
|
@ -78,6 +68,5 @@ func buildContext(rules []byte) ([]sessionTokenContext, error) {
|
||||||
return []sessionTokenContext{
|
return []sessionTokenContext{
|
||||||
{verb: session.VerbContainerPut},
|
{verb: session.VerbContainerPut},
|
||||||
{verb: session.VerbContainerDelete},
|
{verb: session.VerbContainerDelete},
|
||||||
{verb: session.VerbContainerSetEACL},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,15 @@ func TestContainerSessionRules(t *testing.T) {
|
||||||
{
|
{
|
||||||
"verb": "DELETE",
|
"verb": "DELETE",
|
||||||
"containerID": "6CcWg8LkcbfMUC8pt7wiy5zM1fyS3psNoxgfppcCgig1"
|
"containerID": "6CcWg8LkcbfMUC8pt7wiy5zM1fyS3psNoxgfppcCgig1"
|
||||||
},
|
|
||||||
{
|
|
||||||
"verb": "SETEACL"
|
|
||||||
}
|
}
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
sessionContext, err := buildContext(jsonRules)
|
sessionContext, err := buildContext(jsonRules)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Len(t, sessionContext, 3)
|
require.Len(t, sessionContext, 2)
|
||||||
require.Equal(t, sessionContext[0].verb, session.VerbContainerPut)
|
require.Equal(t, sessionContext[0].verb, session.VerbContainerPut)
|
||||||
require.Zero(t, sessionContext[0].containerID)
|
require.Zero(t, sessionContext[0].containerID)
|
||||||
require.Equal(t, sessionContext[1].verb, session.VerbContainerDelete)
|
require.Equal(t, sessionContext[1].verb, session.VerbContainerDelete)
|
||||||
require.NotNil(t, sessionContext[1].containerID)
|
require.NotNil(t, sessionContext[1].containerID)
|
||||||
require.Equal(t, sessionContext[2].verb, session.VerbContainerSetEACL)
|
|
||||||
require.Zero(t, sessionContext[2].containerID)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -29,8 +28,6 @@ const (
|
||||||
walletFlag = "wallet"
|
walletFlag = "wallet"
|
||||||
addressFlag = "address"
|
addressFlag = "address"
|
||||||
peerFlag = "peer"
|
peerFlag = "peer"
|
||||||
bearerRulesFlag = "bearer-rules"
|
|
||||||
disableImpersonateFlag = "disable-impersonate"
|
|
||||||
gatePublicKeyFlag = "gate-public-key"
|
gatePublicKeyFlag = "gate-public-key"
|
||||||
containerIDFlag = "container-id"
|
containerIDFlag = "container-id"
|
||||||
containerFriendlyNameFlag = "container-friendly-name"
|
containerFriendlyNameFlag = "container-friendly-name"
|
||||||
|
@ -70,8 +67,6 @@ func initIssueSecretCmd() {
|
||||||
issueSecretCmd.Flags().String(walletFlag, "", "Path to the wallet that will be owner of the credentials")
|
issueSecretCmd.Flags().String(walletFlag, "", "Path to the wallet that will be owner of the credentials")
|
||||||
issueSecretCmd.Flags().String(addressFlag, "", "Address of the wallet account")
|
issueSecretCmd.Flags().String(addressFlag, "", "Address of the wallet account")
|
||||||
issueSecretCmd.Flags().String(peerFlag, "", "Address of a frostfs peer to connect to")
|
issueSecretCmd.Flags().String(peerFlag, "", "Address of a frostfs peer to connect to")
|
||||||
issueSecretCmd.Flags().String(bearerRulesFlag, "", "Rules for bearer token (filepath or a plain json string are allowed, can be used only with --disable-impersonate)")
|
|
||||||
issueSecretCmd.Flags().Bool(disableImpersonateFlag, false, "Mark token as not impersonate to don't consider token signer as request owner (must be provided to use --bearer-rules flag)")
|
|
||||||
issueSecretCmd.Flags().StringSlice(gatePublicKeyFlag, nil, "Public 256r1 key of a gate (use flags repeatedly for multiple gates or separate them by comma)")
|
issueSecretCmd.Flags().StringSlice(gatePublicKeyFlag, nil, "Public 256r1 key of a gate (use flags repeatedly for multiple gates or separate them by comma)")
|
||||||
issueSecretCmd.Flags().String(containerIDFlag, "", "Auth container id to put the secret into (if not provided new container will be created)")
|
issueSecretCmd.Flags().String(containerIDFlag, "", "Auth container id to put the secret into (if not provided new container will be created)")
|
||||||
issueSecretCmd.Flags().String(containerFriendlyNameFlag, "", "Friendly name of auth container to put the secret into (flag value will be used only if --container-id is missed)")
|
issueSecretCmd.Flags().String(containerFriendlyNameFlag, "", "Friendly name of auth container to put the secret into (flag value will be used only if --container-id is missed)")
|
||||||
|
@ -134,17 +129,6 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't parse container policy: %s", err.Error()))
|
return wrapPreparationError(fmt.Errorf("couldn't parse container policy: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
disableImpersonate := viper.GetBool(disableImpersonateFlag)
|
|
||||||
eaclRules := viper.GetString(bearerRulesFlag)
|
|
||||||
if !disableImpersonate && eaclRules != "" {
|
|
||||||
return wrapPreparationError(errors.New("--bearer-rules flag can be used only with --disable-impersonate"))
|
|
||||||
}
|
|
||||||
|
|
||||||
bearerRules, err := getJSONRules(eaclRules)
|
|
||||||
if err != nil {
|
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't parse 'bearer-rules' flag: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionRules, skipSessionRules, err := getSessionRules(viper.GetString(sessionTokensFlag))
|
sessionRules, skipSessionRules, err := getSessionRules(viper.GetString(sessionTokensFlag))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't parse 'session-tokens' flag: %s", err.Error()))
|
return wrapPreparationError(fmt.Errorf("couldn't parse 'session-tokens' flag: %s", err.Error()))
|
||||||
|
@ -200,8 +184,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
},
|
},
|
||||||
FrostFSKey: key,
|
FrostFSKey: key,
|
||||||
GatesPublicKeys: gatesPublicKeys,
|
GatesPublicKeys: gatesPublicKeys,
|
||||||
EACLRules: bearerRules,
|
Impersonate: true,
|
||||||
Impersonate: !disableImpersonate,
|
|
||||||
SessionTokenRules: sessionRules,
|
SessionTokenRules: sessionRules,
|
||||||
SkipSessionRules: skipSessionRules,
|
SkipSessionRules: skipSessionRules,
|
||||||
ContainerPolicies: policies,
|
ContainerPolicies: policies,
|
||||||
|
|
145
docs/authmate.md
145
docs/authmate.md
|
@ -75,6 +75,7 @@ wallet is successfully created, the file location is wallet.json
|
||||||
```
|
```
|
||||||
|
|
||||||
To get the public key from the wallet:
|
To get the public key from the wallet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ ./bin/neo-go wallet dump-keys -w wallet.json
|
$ ./bin/neo-go wallet dump-keys -w wallet.json
|
||||||
|
|
||||||
|
@ -90,22 +91,25 @@ put them as an object into a container on the FrostFS network.
|
||||||
### CLI parameters
|
### CLI parameters
|
||||||
|
|
||||||
**Required parameters:**
|
**Required parameters:**
|
||||||
|
|
||||||
* `--wallet` is a path to a wallet `.json` file. You can provide a passphrase to decrypt
|
* `--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
|
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.
|
interactively. You can also specify an account address to use from a wallet using the `--address` parameter.
|
||||||
* `--peer` is an address of a FrostFS peer to connect to
|
* `--peer` is an address of a FrostFS peer to connect to
|
||||||
* `--gate-public-key` is a public `secp256r1` 33-byte short key of a gate (use flags repeatedly for multiple gates). The tokens are encrypted
|
* `--gate-public-key` is a public `secp256r1` 33-byte short key of a gate (use flags repeatedly for multiple gates). The
|
||||||
by a set of gateway keys, so you need to pass them as well.
|
tokens are encrypted by a set of gateway keys, so you need to pass them as well.
|
||||||
|
|
||||||
You can issue a secret using the parameters above only. The tool will
|
You can issue a secret using the parameters above only. The tool will
|
||||||
|
|
||||||
1. create a new container
|
1. create a new container
|
||||||
1. without a friendly name
|
1. without a friendly name
|
||||||
2. with ACL `0x3c8c8cce` -- all operations are forbidden for `OTHERS` and `BEARER` user groups, except for `GET`
|
2. with ACL `0x3c8c8cce` -- all operations are forbidden for `OTHERS` and `BEARER` user groups, except for `GET`
|
||||||
3. with policy `REP 2 IN X CBF 3 SELECT 2 FROM * AS X`
|
3. with policy `REP 2 IN X CBF 3 SELECT 2 FROM * AS X`
|
||||||
2. put bearer and session tokens with default rules (details in [Bearer tokens](#Bearer tokens) and
|
2. put bearer and session tokens with default rules (details in [Bearer tokens](#bearer-tokens) and
|
||||||
[Session tokens](#Session tokens))
|
[Session tokens](#session-tokens))
|
||||||
|
|
||||||
E.g.:
|
E.g.:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
||||||
--peer 192.168.130.71:8080 \
|
--peer 192.168.130.71:8080 \
|
||||||
|
@ -128,100 +132,48 @@ $ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
||||||
`initial_access_key_id` contains the first credentials in the chain of credentials versions
|
`initial_access_key_id` contains the first credentials in the chain of credentials versions
|
||||||
(can be useful when you update your credentials).
|
(can be useful when you update your credentials).
|
||||||
|
|
||||||
`access_key_id` consists of Base58 encoded containerID(cid) and objectID(oid) stored on the FrostFS network and containing
|
`access_key_id` consists of Base58 encoded containerID(cid) and objectID(oid) stored on the FrostFS network and
|
||||||
|
containing
|
||||||
the secret. Format of `access_key_id`: `%cid0%oid`, where 0(zero) is a delimiter.
|
the secret. Format of `access_key_id`: `%cid0%oid`, where 0(zero) is a delimiter.
|
||||||
|
|
||||||
**Optional parameters:**
|
**Optional parameters:**
|
||||||
|
|
||||||
* `--container-id` - you can put the tokens into an existing container, but this way is ***not recommended***.
|
* `--container-id` - you can put the tokens into an existing container, but this way is ***not recommended***.
|
||||||
* `--container-friendly-name` -- name of a container with tokens, by default container will not have a friendly name
|
* `--container-friendly-name` -- name of a container with tokens, by default container will not have a friendly name
|
||||||
* `--container-placement-policy` - placement policy of auth container to put the secret into. Default value is
|
* `--container-placement-policy` - placement policy of auth container to put the secret into. Default value is
|
||||||
`REP 2 IN X CBF 3 SELECT 2 FROM * AS X`
|
`REP 2 IN X CBF 3 SELECT 2 FROM * AS X`
|
||||||
* `--lifetime`-- lifetime of tokens. For example 50h30m (note: max time unit is an hour so to set a day you should use
|
* `--lifetime`-- lifetime of tokens. For example 50h30m (note: max time unit is an hour so to set a day you should use
|
||||||
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)
|
* `--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
|
* `--frostfsid` -- FrostfsID contract hash (LE) or name in NNS to register public key in contract
|
||||||
(`--rpc-endpoint` flag also must be provided).
|
(`--rpc-endpoint` flag also must be provided).
|
||||||
* `--rpc-endpoint` -- NEO node RPC address.
|
* `--rpc-endpoint` -- NEO node RPC address.
|
||||||
|
|
||||||
### Bearer tokens
|
### Bearer tokens
|
||||||
|
|
||||||
Creation of bearer tokens is mandatory.
|
Creation of bearer tokens is mandatory.
|
||||||
|
|
||||||
By default, bearer token will be created with `impersonate` flag and won't have eACL table. It means that gate which will use such token
|
Bearer token will be created with `impersonate` flag. It means that gate (which will use such token to interact with
|
||||||
to interact with node can have access to your private containers or to containers in which eACL grants access to you
|
node) can have access to your private containers or to containers in which eACL grants access to you by public key.
|
||||||
by public key.
|
|
||||||
|
|
||||||
Rules for a bearer token can be set via parameter `--bearer-rules` (json-string and file path allowed).
|
|
||||||
But you must provide `--disable-impersonate` flag:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
|
||||||
--peer 192.168.130.71:8080 \
|
|
||||||
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
|
|
||||||
--bearer-rules bearer-rules.json \
|
|
||||||
--disable-impersonate
|
|
||||||
```
|
|
||||||
where content of `bearer-rules.json`:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"records": [
|
|
||||||
{"operation": "PUT", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "GET", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "HEAD", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "DELETE", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "SEARCH", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "GETRANGE", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "GETRANGEHASH", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** such rules allow all operations for all users (the same behavior when records are empty).
|
|
||||||
To restrict access you MUST provide records with `DENY` action. That's why we recommend always place such records
|
|
||||||
at the end of records (see default rules below) to prevent undesirable access violation.
|
|
||||||
Since the rules are applied from top to bottom, they do not override what was previously allowed.
|
|
||||||
|
|
||||||
If bearer rules are not set, a token will be auto-generated with a value:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": {
|
|
||||||
"major": 2,
|
|
||||||
"minor": 11
|
|
||||||
},
|
|
||||||
"containerID": {
|
|
||||||
"value": null
|
|
||||||
},
|
|
||||||
"records": [
|
|
||||||
{"operation": "GET", "action": "ALLOW", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
|
|
||||||
{"operation": "GET", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "HEAD", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "PUT", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "DELETE", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "SEARCH", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "GETRANGE", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]},
|
|
||||||
{"operation": "GETRANGEHASH", "action": "DENY", "filters": [], "targets": [{"role": "OTHERS", "keys": []}]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Session tokens
|
### Session tokens
|
||||||
|
|
||||||
With a session token, there are 3 options:
|
With a session token, there are 3 options:
|
||||||
|
|
||||||
1. append `--session-tokens` parameter with your custom rules in json format (as a string or file path). E.g.:
|
1. append `--session-tokens` parameter with your custom rules in json format (as a string or file path). E.g.:
|
||||||
```shell
|
```shell
|
||||||
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
$ frostfs-s3-authmate issue-secret --wallet wallet.json \
|
||||||
--peer 192.168.130.71:8080 \
|
--peer 192.168.130.71:8080 \
|
||||||
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
|
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
|
||||||
--session-tokens session.json
|
--session-tokens session.json
|
||||||
```
|
```
|
||||||
where content of `session.json`:
|
where content of `session.json`:
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"verb": "PUT",
|
"verb": "PUT",
|
||||||
"containerID": null
|
"containerID": null
|
||||||
|
@ -229,33 +181,29 @@ where content of `session.json`:
|
||||||
{
|
{
|
||||||
"verb": "DELETE",
|
"verb": "DELETE",
|
||||||
"containerID": null
|
"containerID": null
|
||||||
},
|
|
||||||
{
|
|
||||||
"verb": "SETEACL",
|
|
||||||
"containerID": null
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Available `verb` values: `PUT`, `DELETE`, `SETEACL`.
|
Available `verb` values: `PUT`, `DELETE`.
|
||||||
|
|
||||||
If `containerID` is `null` or omitted, then session token rule will be applied
|
If `containerID` is `null` or omitted, then session token rule will be applied
|
||||||
to all containers. Otherwise, specify `containerID` value in human-redabale
|
to all containers. Otherwise, specify `containerID` value in human-readable
|
||||||
format (base58 encoded string).
|
format (base58 encoded string).
|
||||||
|
|
||||||
> **_NB!_** To create buckets in FrostFS it's necessary to have session tokens with `PUT` and `SETEACL` permissions, that's why
|
> **_NB!_** To create buckets in FrostFS it's necessary to have session tokens with `PUT` permissions.
|
||||||
the authmate creates a `SETEACL` session token automatically in case when a user specified the token rule with `PUT` and
|
|
||||||
forgot about the rule with `SETEACL`.
|
|
||||||
|
|
||||||
2. append `--session-tokens` parameter with the value `none` -- no session token will be created
|
2. append `--session-tokens` parameter with the value `none` -- no session token will be created
|
||||||
3. skip the parameter, and `authmate` will create session tokens with default rules (the same as in `session.json`
|
3. skip the parameter, and `authmate` will create session tokens with default rules (the same as in `session.json`
|
||||||
in example above)
|
in example above)
|
||||||
|
|
||||||
### Containers policy
|
### Containers policy
|
||||||
|
|
||||||
Rules for mapping of `LocationConstraint` ([aws spec](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html#API_CreateBucket_RequestBody))
|
Rules for mapping
|
||||||
|
of `LocationConstraint` ([aws spec](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html#API_CreateBucket_RequestBody))
|
||||||
to `PlacementPolicy`
|
to `PlacementPolicy`
|
||||||
can be set via parameter `--container-policy` (json-string and file path allowed):
|
can be set via parameter `--container-policy` (json-string and file path allowed):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"rep-3": "REP 3",
|
"rep-3": "REP 3",
|
||||||
|
@ -302,7 +250,6 @@ Enter password for gate-wallet.json >
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Generate presigned URL
|
## Generate presigned URL
|
||||||
|
|
||||||
You can generate [presigned url](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html)
|
You can generate [presigned url](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html)
|
||||||
|
@ -332,6 +279,7 @@ $ frostfs-s3-authmate generate-presigned-url --endpoint http://localhost:8084 \
|
||||||
```
|
```
|
||||||
|
|
||||||
### AWS CLI
|
### AWS CLI
|
||||||
|
|
||||||
You can also can get the presigned URL (only for GET) using aws cli v2:
|
You can also can get the presigned URL (only for GET) using aws cli v2:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -341,14 +289,17 @@ http://localhost:8084/pregigned/obj?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Crede
|
||||||
```
|
```
|
||||||
|
|
||||||
## Update secret
|
## Update secret
|
||||||
|
|
||||||
You can extend list of s3 gates that can accept already issued credentials.
|
You can extend list of s3 gates that can accept already issued credentials.
|
||||||
To do this use `frostfs-s3-authmate update-secret` command:
|
To do this use `frostfs-s3-authmate update-secret` command:
|
||||||
|
|
||||||
**Required parameters:**
|
**Required parameters:**
|
||||||
|
|
||||||
* `--wallet` is a path to a user wallet `.json` file. You can provide a passphrase to decrypt
|
* `--wallet` is a path to a user 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
|
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.
|
interactively. You can also specify an account address to use from a wallet using the `--address` parameter.
|
||||||
* `--gate-wallet` is a path to a gate wallet `.json` file (need to decrypt current access box version). You can provide a passphrase to decrypt
|
* `--gate-wallet` is a path to a gate wallet `.json` file (need to decrypt current access box version). You can provide
|
||||||
|
a passphrase to decrypt
|
||||||
a wallet via environment variable `AUTHMATE_WALLET_GATE_PASSPHRASE`, or you will be asked to enter a passphrase
|
a wallet via environment variable `AUTHMATE_WALLET_GATE_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 `--gate-address` parameter.
|
interactively. You can also specify an account address to use from a wallet using the `--gate-address` parameter.
|
||||||
* `--peer` is an address of a FrostFS peer to connect to
|
* `--peer` is an address of a FrostFS peer to connect to
|
||||||
|
@ -381,7 +332,7 @@ Enter password for s3-wallet.json >
|
||||||
There are several non-zero exit codes added at the moment.
|
There are several non-zero exit codes added at the moment.
|
||||||
|
|
||||||
| Code | Description |
|
| Code | Description |
|
||||||
|-------|--------------------------------------------------------------------------------------------|
|
|------|--------------------------------------------------------------------------------------------|
|
||||||
| 1 | Any unknown errors, or errors generated by the parser of command line parameters. |
|
| 1 | Any unknown errors, or errors generated by the parser of command line parameters. |
|
||||||
| 2 | Preparation errors: malformed configuration, issues with input data parsing. |
|
| 2 | Preparation errors: malformed configuration, issues with input data parsing. |
|
||||||
| 3 | FrostFS errors: connectivity problems, misconfiguration. |
|
| 3 | FrostFS errors: connectivity problems, misconfiguration. |
|
||||||
|
|
Loading…
Reference in a new issue