[#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:
Denis Kirillov 2024-05-28 12:10:28 +03:00
parent 77f8bdac58
commit 9241954496
5 changed files with 89 additions and 209 deletions

View file

@ -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)
} }

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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,

View file

@ -20,10 +20,10 @@ potentially).
1. [Generation of wallet](#generation-of-wallet) 1. [Generation of wallet](#generation-of-wallet)
2. [Issuance of a secret](#issuance-of-a-secret) 2. [Issuance of a secret](#issuance-of-a-secret)
1. [CLI parameters](#cli-parameters) 1. [CLI parameters](#cli-parameters)
2. [Bearer tokens](#bearer-tokens) 2. [Bearer tokens](#bearer-tokens)
3. [Session tokens](#session-tokens) 3. [Session tokens](#session-tokens)
4. [Containers policy](#containers-policy) 4. [Containers policy](#containers-policy)
3. [Obtainment of a secret](#obtaining-credential-secrets) 3. [Obtainment of a secret](#obtaining-credential-secrets)
4. [Generate presigned url](#generate-presigned-url) 4. [Generate presigned url](#generate-presigned-url)
5. [Update secrets](#update-secret) 5. [Update secrets](#update-secret)
@ -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,134 +132,78 @@ $ 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
}, },
{ {
"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,18 +289,21 @@ 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
* `--gate-public-key` is a public `secp256r1` 33-byte short key of a gate (use flags repeatedly for multiple gates). * `--gate-public-key` is a public `secp256r1` 33-byte short key of a gate (use flags repeatedly for multiple gates).
* `--access-key-id` is a credential id to update. * `--access-key-id` is a credential id to update.
```shell ```shell
@ -380,9 +331,9 @@ 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. |
| 4 | Business logic errors: `authmate` could not execute its task because of some restrictions. | | 4 | Business logic errors: `authmate` could not execute its task because of some restrictions. |