2022-06-28 18:12:39 +00:00
# NeoFS S3 AuthMate
2021-08-18 19:18:49 +00:00
Authmate is a tool to create gateway AWS credentials. AWS users
are authenticated with access key IDs and secrets, while NeoFS users are
2022-04-13 16:56:58 +00:00
authenticated with key pairs. To complicate things further, we have S3 gateway
that usually acts on behalf of some user, but the user doesn't necessarily want to
2021-08-19 12:46:41 +00:00
give their keys to the gateway.
2021-08-18 19:18:49 +00:00
2021-08-19 12:46:41 +00:00
To solve this, we use NeoFS bearer tokens that are signed by the owner (NeoFS
2021-08-18 19:18:49 +00:00
"user") and that can implement any kind of policy for NeoFS requests allowed
2022-04-13 16:56:58 +00:00
to use this token. However, tokens can't be used as AWS credentials directly. Thus,
they're stored on NeoFS as regular objects, and an access key ID is just an
address of this object while a secret is generated randomly.
2021-08-18 19:18:49 +00:00
Tokens are not stored on NeoFS in plaintext, they're encrypted with a set of
2022-04-13 16:56:58 +00:00
gateway keys. So, in order for a gateway to be able to successfully extract bearer
2021-08-19 12:46:41 +00:00
token, the object needs to be stored in a container available for the gateway
to read, and it needs to be encrypted with this gateway's key (among others
2021-08-18 19:18:49 +00:00
potentially).
2022-04-27 07:15:46 +00:00
1. [Generation of wallet ](#generation-of-wallet )
2. [Issuance of a secret ](#issuance-of-a-secret )
1. [CLI parameters ](#cli-parameters )
2. [Bearer tokens ](#bearer-tokens )
3. [Session tokens ](#session-tokens )
4. [Containers policy ](#containers-policy )
3. [Obtainment of a secret ](#obtainment-of-a-secret-access-key )
2022-06-15 08:48:58 +00:00
4. [Generate presigned url ](#generate-presigned-url )
2021-08-18 19:18:49 +00:00
## Generation of wallet
2022-04-06 14:31:32 +00:00
To generate a wallet for a gateway, run the following command:
2021-08-18 19:18:49 +00:00
2022-04-06 14:31:32 +00:00
```shell
2021-08-18 19:18:49 +00:00
$ ./neo-go wallet init -a -w wallet.json
Enter the name of the account > AccountTestName
Enter passphrase >
Confirm passphrase >
{
"version": "3.0",
"accounts": [
{
"address": "NhLQpDnerpviUWDF77j5qyjFgavCmasJ4p",
"key": "6PYUFyYpJ1JGyMrYV8NqeUFLKfpEVHsGGjCYtTDkjnKaSgYizRBZxVerte",
"label": "AccountTestName",
"contract": {
"script": "DCECXCsUZPwUyKHs6nAyyCvJ5s/vLwZkkVtWNC0zWzH8a9dBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
}
],
"scrypt": {
"n": 16384,
"r": 8,
"p": 8
},
"extra": {
"Tokens": null
}
}
2022-04-13 16:56:58 +00:00
wallet is successfully created, the file location is wallet.json
2021-08-18 19:18:49 +00:00
```
2022-04-13 16:56:58 +00:00
To get the public key from the wallet:
2022-04-06 14:31:32 +00:00
```shell
2021-08-18 19:18:49 +00:00
$ ./bin/neo-go wallet dump-keys -w wallet.json
NhLQpDnerpviUWDF77j5qyjFgavCmasJ4p (simple signature contract):
025c2b1464fc14c8a1ecea7032c82bc9e6cfef2f0664915b56342d335b31fc6bd7
```
## Issuance of a secret
2022-04-13 16:56:58 +00:00
To issue a secret means to create Bearer and, optionally, Session tokens and
2021-08-19 09:55:01 +00:00
put them as an object into a container on the NeoFS network.
2021-08-18 19:18:49 +00:00
2022-04-06 14:31:32 +00:00
### CLI parameters
**Required parameters:**
2022-04-13 16:56:58 +00:00
* `--wallet` is a path to a wallet `.json` file. You can provide a passphrase to decrypt
2022-04-06 14:31:32 +00:00
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.
2022-04-13 16:56:58 +00:00
* `--peer` is an address of a NeoFS 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
2022-04-06 14:31:32 +00:00
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
1. create a new container
1. without a friendly name
2022-04-13 16:56:58 +00:00
2. with ACL `0x3c8c8cce` -- all operations are forbidden for `OTHERS` and `BEARER` user groups, except for `GET`
2022-04-06 14:31:32 +00:00
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
[Session tokens ](#Session tokens ))
E.g.:
```shell
2022-06-28 18:12:39 +00:00
$ neofs-s3-authmate issue-secret --wallet wallet.json \
2022-04-06 14:31:32 +00:00
--peer 192.168.130.71:8080 \
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf\
--gate-public-key 0317585fa8274f7afdf1fc5f2a2e7bece549d5175c4e5182e37924f30229aef967
Enter password for wallet.json >
{
"access_key_id": "5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT0AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM",
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c",
"owner_private_key": "274fdd6e71fc6a6b8fe77bec500254115d66d6d17347d7db0880d2eb80afc72a",
"container_id":"5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT"
}
```
`access_key_id` and `secret_access_key` are AWS credentials that you can use with any S3 client.
2021-08-19 09:55:01 +00:00
2022-04-06 14:31:32 +00:00
`access_key_id` consists of Base58 encoded containerID(cid) and objectID(oid) stored on the NeoFS network and containing
the secret. Format of `access_key_id` : `%cid0%oid` , where 0(zero) is a delimiter.
2021-08-19 09:55:01 +00:00
2022-04-06 14:31:32 +00:00
**Optional parameters:**
* `--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-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`
* `--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
* `--aws-cli-credentials` - path to the aws cli credentials file, where authmate will write `access_key_id` and
`secret_access_key` to
2021-08-18 19:18:49 +00:00
2022-04-06 14:31:32 +00:00
### Bearer tokens
2021-08-18 19:18:49 +00:00
2022-04-13 16:56:58 +00:00
Creation of bearer tokens is mandatory.
2021-08-18 19:18:49 +00:00
2022-04-13 16:56:58 +00:00
Rules for a bearer token can be set via parameter `--bearer-rules` (json-string and file path allowed):
2022-04-06 14:31:32 +00:00
```shell
2022-06-28 18:12:39 +00:00
$ neofs-s3-authmate issue-secret --wallet wallet.json \
2022-04-06 14:31:32 +00:00
--peer 192.168.130.71:8080 \
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
--bearer-rules bearer-rules.json
2021-08-18 19:18:49 +00:00
```
2022-04-06 14:31:32 +00:00
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": []}]}
]
}
```
2022-04-27 07:52:03 +00:00
**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.
2022-04-06 14:31:32 +00:00
If bearer rules are not set, a token will be auto-generated with a value:
```json
2021-08-18 19:18:49 +00:00
{
"version": {
2022-04-27 07:52:03 +00:00
"major": 2,
"minor": 11
2021-08-18 19:18:49 +00:00
},
"containerID": {
2022-04-27 07:52:03 +00:00
"value": null
2021-08-18 19:18:49 +00:00
},
"records": [
2022-04-27 07:52:03 +00:00
{"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": []}]}
2021-08-18 19:18:49 +00:00
]
}
```
2022-04-06 14:31:32 +00:00
### Session tokens
2022-01-31 18:40:00 +00:00
2022-04-13 16:56:58 +00:00
With a session token, there are 3 options:
2022-04-14 15:09:57 +00:00
1. append `--session-tokens` parameter with your custom rules in json format (as a string or file path). E.g.:
2022-04-06 14:31:32 +00:00
```shell
2022-06-28 18:12:39 +00:00
$ neofs-s3-authmate issue-secret --wallet wallet.json \
2022-04-06 14:31:32 +00:00
--peer 192.168.130.71:8080 \
--gate-public-key 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf \
2022-04-14 15:09:57 +00:00
--session-tokens session.json
2021-08-18 19:18:49 +00:00
```
2022-04-06 14:31:32 +00:00
where content of `session.json` :
```json
2022-01-26 09:14:41 +00:00
[
{
2021-08-18 19:18:49 +00:00
"verb": "PUT",
"containerID": null
2022-01-31 10:50:41 +00:00
},
{
"verb": "DELETE",
"containerID": null
},
{
"verb": "SETEACL",
"containerID": null
2022-04-06 14:31:32 +00:00
}
2022-01-26 09:14:41 +00:00
]
2021-08-18 19:18:49 +00:00
```
2022-05-04 12:29:11 +00:00
Available `verb` values: `PUT` , `DELETE` , `SETEACL` .
If `containerID` is `null` or omitted, then session token rule will be applied
to all containers. Otherwise, specify `containerID` value in human-redabale
format (base58 encoded string).
2022-04-06 14:31:32 +00:00
> **_NB!_** To create buckets in NeoFS it's necessary to have session tokens with `PUT` and `SETEACL` permissions, that's why
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` .
2022-04-14 15:09:57 +00:00
2. append `--session-tokens` parameter with the value `none` -- no session token will be created
2022-04-06 14:31:32 +00:00
3. skip the parameter, and `authmate` will create session tokens with default rules (the same as in `session.json`
in example above)
### Containers policy
2021-08-18 19:18:49 +00:00
Rules for mapping of `LocationConstraint` ([aws spec](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html#API_CreateBucket_RequestBody))
to `PlacementPolicy` ([neofs spec](https://github.com/nspcc-dev/neofs-spec/blob/master/01-arch/02-policy.md))
2022-04-06 14:31:32 +00:00
can be set via parameter `--container-policy` (json-string and file path allowed):
```json
2021-08-18 19:18:49 +00:00
{
"rep-3": "REP 3",
"complex": "REP 1 IN X CBF 1 SELECT 1 FROM * AS X",
"example-json-policy": "{\"replicas\":[{\"count\":3,\"selector\":\"SelASD0\"}],\"container_backup_factor\":3,\"selectors\":[{\"name\":\"SelASD0\",\"count\":3,\"filter\":\"*\"}],\"filters\":[]}"
}
```
## Obtainment of a secret access key
2021-08-19 12:46:41 +00:00
You can get a secret access key associated with an access key ID by obtaining a
secret stored on the NeoFS network. Here is an example of providing one password (for `wallet.json` ) via env variable
and the other (for `gate-wallet.json` ) interactively:
2021-08-18 19:18:49 +00:00
2022-04-06 14:31:32 +00:00
```shell
$ AUTHMATE_WALLET_PASSPHRASE=some-pwd \
2022-06-28 18:12:39 +00:00
neofs-s3-authmate obtain-secret --wallet wallet.json \
2022-04-06 14:31:32 +00:00
--peer 192.168.130.71:8080 \
--gate-wallet gate-wallet.json \
--access-key-id 5g933dyLEkXbbAspouhPPTiyLZRg4axBW1axSPD87eVT0AiXsH4AjYy1iTJ4C1WExzjBrSobJsQFWEyKLREe5sQYM
2021-08-18 19:18:49 +00:00
Enter password for gate-wallet.json >
{
"secret_access_key": "438bbd8243060e1e1c9dd4821756914a6e872ce29bf203b68f81b140ac91231c"
}
```
2022-06-15 08:48:58 +00:00
## Generate presigned URL
You can generate [presigned url ](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html )
using AWS credentials from `~/.aws/credentials` (you can specify profile using the `--profile` flag)
with the following command:
```shell
2022-06-28 18:12:39 +00:00
$ neofs-s3-authmate generate-presigned-url --endpoint http://localhost:8084 \
2022-06-15 08:48:58 +00:00
--method get --bucket presigned --object obj --lifetime 30s
{
"URL": "http://localhost:8084/presigned/obj?X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=6UpmiuYspPLMWfyhEKYmZQSsTGkFLS5MhQVdsda3fhz908Hw9eo9urTmaJtfvHMHUpY8SWAptk61bns2Js8f1M5tZ%2F20220615%2Fus-east-2%2Fs3%2Faws4_request& X-Amz-Date=20220615T084203Z& X-Amz-Expires=30& X-Amz-SignedHeaders=host& X-Amz-Signature=47f74d4b84566708a17dded05cce732690745f141235215104ad051e265e3c59"
}
```
You can also provide credential explicitly:
```shell
2022-06-28 18:12:39 +00:00
$ neofs-s3-authmate generate-presigned-url --endpoint http://localhost:8084 \
2022-06-15 08:48:58 +00:00
--method put --bucket presigned --object obj --lifetime 12h \
--region ru --aws-secret-access-key c2d65ef2980f03f4f495bdebedeeae760496697880d61d106bb9a4e5cd2e0607 \
--aws-access-key-id ETaA2CadPcA7bAkLsML2PbTudXY8uRt2PDjCCwkvRv9s0FDCxWDXYc1SA1vKv8KbyCNsLY2AmAjJ92Vz5rgvsFCy
{
"URL": "http://localhost:8084/presigned/obj?X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=ETaA2CadPcA7bAkLsML2PbTudXY8uRt2PDjCCwkvRv9s0FDCxWDXYc1SA1vKv8KbyCNsLY2AmAjJ92Vz5rgvsFCy%2F20220615%2Fru%2Fs3%2Faws4_request& X-Amz-Date=20220615T084455Z& X-Amz-Expires=43200& X-Amz-SignedHeaders=host& X-Amz-Signature=ac92aecc3787eeed03922ea82af082091c806f1bb58a7101602ed21369815d04"
}
```
### AWS CLI
You can also can get the presigned URL (only for GET) using aws cli v2:
```shell
$ aws s3 --endpoint http://localhost:8084 presign s3://pregigned/obj
http://localhost:8084/pregigned/obj?X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=6UpmiuYspPLMWfyhEKYmZQSsTGkFLS5MhQVdsda3fhz908Hw9eo9urTmaJtfvHMHUpY8SWAptk61bns2Js8f1M5tZ%2F20220615%2Fus-east-2%2Fs3%2Faws4_request& X-Amz-Date=20220615T072348Z& X-Amz-Expires=3600& X-Amz-SignedHeaders=host& X-Amz-Signature=b82c13952534b1bba699a718f2d42d135c2833a1e64030d4ce0e198af46551d4
```