403 Forbidden / 404 Not Found from KV GET requests depending on 'recurse' parameter
- Dominant language
- Go
- Stars
- 30.1k
- Forks
- 4.6k
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 39
Description
#### Overview of the Issue
My setup consists of 1 server, 2 agents and ACLs enabled.
When I attempt to submit a GET requests on KV using a token with no permissions on the KV store and the `recurse` parameter set, I get a **404 Not Found** error while I'd expect to receive a **403 Forbidden**.
#### Reproduction Steps
1. Create some nested entries in the KV store
```
consul kv put foo/a aaa
consul kv put foo/b bbb
consul kv put foo/c ccc
```
2. Attempt to retrieve a specific key via HTTP API using a token without permissions (CORRECT)
```
$ curl -sv "http://127.0.0.1:8500/v1/kv/foo?token=anonymous"
* About to connect() to 127.0.0.1 port 8500 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8500 (#0)
> GET /v1/kv/foo?token=anonymous HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8500
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Vary: Accept-Encoding
< X-Consul-Default-Acl-Policy: deny
< Date: Tue, 11 May 2021 11:27:26 GMT
< Content-Length: 40
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host 127.0.0.1 left intact
rpc error making call: Permission denied
```
3. Attempt to retrieve a key via HTTP API using a token without permissions and `recurse` parameter set (**WRONG**)
```
$ curl -sv "http://127.0.0.1:8500/v1/kv/foo/?token=anonymous&recurse="
* About to connect() to 127.0.0.1 port 8500 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8500 (#0)
> GET /v1/kv/foo/?token=anonymous&recurse= HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8500
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Vary: Accept-Encoding
< X-Consul-Default-Acl-Policy: deny
< X-Consul-Index: 34405
< X-Consul-Knownleader: true
< X-Consul-Lastcontact: 0
< Date: Tue, 11 May 2021 11:33:26 GMT
< Content-Length: 0
<
* Connection #0 to host 127.0.0.1 left intact
```
4. Same request as above but with valid token this time (CORRECT)
```
$ curl -sv "http://127.0.0.1:8500/v1/kv/foo/?token=&recurse="
* About to connect() to 127.0.0.1 port 8500 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8500 (#0)
> GET /v1/kv/foo/?token=&recurse= HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8500
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Vary: Accept-Encoding
< X-Consul-Default-Acl-Policy: deny
< X-Consul-Index: 34405
< X-Consul-Knownleader: true
< X-Consul-Lastcontact: 0
< Date: Tue, 11 May 2021 11:33:44 GMT
< Content-Length: 286
<
* Connection #0 to host 127.0.0.1 left intact
[{"LockIndex":0,"Key":"foo/a","Flags":0,"Value":"YWFh","CreateIndex":34402,"ModifyIndex":34402},{"LockIndex":0,"Key":"foo/b","Flags":0,"Value":"YmJi","CreateIndex":34404,"ModifyIndex":34404},{"LockIndex":0,"Key":"foo/c","Flags":0,"Value":"Y2Nj","CreateIndex":34405,"ModifyIndex":34405}]
```
The behavior is the same whether the request is made to the client or to the server.
### Consul info for both Client and Server
Client info
```
agent:
check_monitors = 0
check_ttls = 0
checks = 0
services = 0
build:
prerelease =
revision = 3c1c2267
version = 1.9.5
consul:
acl = enabled
known_servers = 1
server = false
runtime:
arch = amd64
cpu_count = 2
goroutines = 54
max_procs = 2
os = linux
version = go1.15.8
serf_lan:
coordinate_resets = 0
encrypted = true
event_queue = 0
event_time = 2
failed = 0
health_score = 0
intent_queue = 0
left = 0
member_time = 105
members = 2
query_queue = 0
query_time = 1
```
Server info
```
agent:
check_monitors = 0
check_ttls = 0
checks = 0
services = 0
build:
prerelease =
revision = 3c1c2267
version = 1.9.5
consul:
acl = enabled
bootstrap = true
known_datacenters = 1
leader = true
leader_addr = 10.42.0.16:8300
server = true
raft:
applied_index = 34583
commit_index = 34583
fsm_pending = 0
last_contact = 0
last_log_index = 34583
last_log_term = 7
last_snapshot_index = 19873
last_snapshot_term = 6
latest_configuration = [{Suffrage:Voter ID:6997cba7-08bd-cdac-eb46-fe51befbe3a5 Address:10.42.0.16:8300}]
latest_configuration_index = 0
num_peers = 0
protocol_version = 3
protocol_version_max = 3
protocol_version_min = 0
snapshot_version_max = 1
snapshot_version_min = 0
state = Leader
term = 7
runtime:
arch = amd64
cpu_count = 2
goroutines = 102
max_procs = 2
os = linux
version = go1.15.8
serf_lan:
coordinate_resets = 0
encrypted = true
event_queue = 0
event_time = 2
failed = 0
health_score = 0
intent_queue = 0
left = 0
member_time = 105
members = 2
query_queue = 0
query_time = 1
serf_wan:
coordinate_resets = 0
encrypted = true
event_queue = 0
event_time = 1
failed = 0
health_score = 0
intent_queue = 0
left = 0
member_time = 4
members = 1
query_queue = 0
query_time = 1
```
### Operating system and Environment details
Red Hat Linux Enterprise 7, x86_64
Contributor guide
Research direction
Reproduce the issue against the /v1/kv endpoint using an ACL-denied token, comparing requests with and without recurse. Trace the Go HTTP handling and authorization response path; done means the denied recursive request returns 403 Forbidden, while the valid-token request continues to return 200 OK.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, authorization
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100