nspcc-dev / neofs-api

NeoFS API documentation and proto files declaration
Apache License 2.0
11 stars 15 forks source link

getrangehash doesn't work with a bearer token created via cli #273

Open evgeniiz321 opened 1 year ago

evgeniiz321 commented 1 year ago

Related to https://github.com/nspcc-dev/neofs-testcases/pull/621

Current Behavior

  1. Create bearer token via cli with acl for all possible operations (including getrange and getrangehash)
  2. Try to issue getrangehash:
COMMAND: neofs-cli --config /home/runner/work/neofs-node/neofs-node/neofs-testcases/wallet_config.yml object hash --rpc-endpoint 's01.neofs.devenv:8080' --wallet '/home/runner/work/neofs-node/neofs-node/neofs-testcases/TemporaryDir/e768c827-812f-4a8c-9090-c52a3b7047ed.json' --cid 'HMVBh53JLaPF38Ztca3TQKfgjPwvFhBto1bSeREjfyiy' --oid '27wMEkckZ2VUAEtu3bLWymTabDn7Rw6BANvKss5jwt2r' --bearer '/home/runner/work/neofs-node/neofs-node/neofs-testcases/TemporaryDir/TestFilesDir/bearer_token_e95282b4-3ab9-4db3-8f86-1dd8a64694d6' --range '0:10'
RETCODE: 1

STDOUT:
rpc error: read payload hashes via client: status: code = 2049 message = object not found

STDERR:

Start / End / Elapsed    20:52:08.234392 / 20:52:08.751591 / 0:00:00.517199

In logs there are the following entries at the time of the failure:

2023-08-30T20:51:54.306Z    debug   get/get.go:87   serving request...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.306Z    debug   get/local.go:25 local get failed    {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "status: code = 2049 message = object not found"}
2023-08-30T20:51:54.306Z    debug   get/get.go:108  operation finished with error   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "status: code = 2049 message = object not found"}
2023-08-30T20:51:54.306Z    debug   get/container.go:18 trying to execute in container...   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "netmap lookup depth": 0}
2023-08-30T20:51:54.306Z    debug   get/container.go:46 process epoch   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "number": 7}
2023-08-30T20:51:54.306Z    debug   get/remote.go:13    processing node...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.311Z    debug   get/container.go:87 completing the operation    {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.311Z    debug   get/get.go:99   operation finished successfully {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.787Z    debug   get/get.go:87   serving request...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.787Z    debug   get/local.go:25 local get failed    {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "status: code = 2049 message = object not found"}
2023-08-30T20:51:54.787Z    debug   get/get.go:108  operation finished with error   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "status: code = 2049 message = object not found"}
2023-08-30T20:51:54.787Z    debug   get/container.go:18 trying to execute in container...   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "netmap lookup depth": 0}
2023-08-30T20:51:54.787Z    debug   get/container.go:46 process epoch   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "number": 7}
2023-08-30T20:51:54.787Z    debug   get/remote.go:13    processing node...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.792Z    debug   get/remote.go:29    remote call failed  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "init object reading: header: status: code = 2048 message = access to object operation denied"}
2023-08-30T20:51:54.792Z    debug   get/remote.go:13    processing node...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.826Z    debug   get/remote.go:29    remote call failed  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "init object reading: header: status: code = 2048 message = access to object operation denied"}
2023-08-30T20:51:54.826Z    debug   get/remote.go:13    processing node...  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.836Z    debug   get/remote.go:29    remote call failed  {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "init object reading: header: status: code = 2048 message = access to object operation denied"}
2023-08-30T20:51:54.836Z    debug   get/container.go:63 no more nodes, abort placement iteration    {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true}
2023-08-30T20:51:54.836Z    debug   get/get.go:108  operation finished with error   {"component": "Object.Get service", "request": "GET_RANGE", "address": "AT95KqvYRw3AC1cCmPJdxwYAcXDJGFLv89rZaZKsmJk3/CdrUYtHAuDDzFF8iw4mAgN2qqb8SDKPo8Gpyg12Ree2k", "raw": false, "local": false, "with session": false, "with bearer": true, "error": "status: code = 2049 message = object not found"}

Expected Behavior

The command should work with this bearer token. All other commands work ok.

Steps to Reproduce

  1. Allure, test_bearer_token_expiration - allure.tar.gz

Regression

(No)

Your Environment

Run on current latest master of neofs-node - 98717120a74c62b328b45f036f770b02685fb9b8

roman-khimov commented 1 year ago

The problem is that getrangehash needs getrange to operate and it's a valid requirement (consider hashing a part of the large object). So any permission set that allows getrangehash only is useless (see https://github.com/nspcc-dev/neofs-spec/blob/master/01-arch/07-acl.md#extended-acl also). But the deeper problem in fact is that we have an insane ACL system that can't be explained to people and that doesn't add any value despite all of its complexity.

Allowing to GET, but not allowing to GETRANGE is like allowing read(), but not allowing mmap() (yeah, this has some difference SECCOMP-wise (RSBAC if anyone remembers), but that's a different problem). Allowing GETRANGEHASH, but not allowing to GET/GETRANGE does not protect data from being read, it just makes it a little harder to do that. There is absolutely zero security added (data can be read with any of these three), just a maintenance burden and configuration headache.

In short, protocol verbs are not the thing users operate with when they think about access. One can set different bits to these different verbs, but they will break in one way or another, so no one even tries (these verbs are configured identically). People usually think in terms of some rwx Unix model, even when they think of S3 actions they expect an action to work on its own, not require anything additional.

Specifically, get/getrange/getrangehash are the same thing. GETRANGE can be deleted completely and be a parameter of GET. GETRANGEHASH is somewhat specific to audit, so it can either be made tied to GET permission or just be available to system nodes with no user access at all (what application needs it?).

evgeniiz321 commented 1 year ago

In the failure above I generated a bearer token with the following command -

COMMAND: neofs-cli --config /home/runner/work/neofs-node/neofs-node/neofs-testcases/wallet_config.yml acl extended create --cid 'HMVBh53JLaPF38Ztca3TQKfgjPwvFhBto1bSeREjfyiy' --out '/home/runner/work/neofs-node/neofs-node/neofs-testcases/TemporaryDir/TestFilesDir/eacl_table_82a063fd-c6af-4a9c-905f-979d1de560ec.json' --rule 'allow put  user' --rule 'allow get  user' --rule 'allow head  user' --rule 'allow getrange  user' --rule 'allow getrangehash  user' --rule 'allow search  user' --rule 'allow delete  user'
RETCODE: 0

STDOUT:

STDERR:

Start / End / Elapsed    20:52:03.805656 / 20:52:03.819742 / 0:00:00.014086

So getrange should be allowed together with getrangehash