fix: deregister service id in url format
Description
- When deregistering a service with an ID, which has an URL format (e.g., http://myservice.com), the http handler will return 301. This PR move the service id from path to the url’s query so that it can be passed to the agent endpoint’s handler.
Testing & Reproduction steps
- Register an service with ID in URL format
- Use cli to deregister the service and will get error
Links
fix https://github.com/hashicorp/consul/issues/13913
PR Checklist
- [x] updated test coverage
- [ ] external facing docs updated
- [x] not a security concern
@mkeeler : is this something we should change generally for all endpoints that accept unvalidated input in path parameters?
We could still merge just this PR first, but I'm concerned this will pop up for other endpoints and, while it's fresh, it might be best to address the others as well.
@mkeeler , thanks so much for your feedback.
@jkirschner-hashicorp , I did a quick search of strings.TrimPrefix in our external facing endpoint files; I will sift the results to make sure we won't miss anything else and report back. Thanks.
./agent/acl_endpoint.go: policyID := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/")
./agent/acl_endpoint.go: policyName := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/name/")
./agent/acl_endpoint.go: tokenID := strings.TrimPrefix(req.URL.Path, "/v1/acl/token/")
./agent/acl_endpoint.go: roleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/")
./agent/acl_endpoint.go: roleName := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/name/")
./agent/acl_endpoint.go: bindingRuleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/binding-rule/")
./agent/acl_endpoint.go: methodName := strings.TrimPrefix(req.URL.Path, "/v1/acl/auth-method/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/")
./agent/agent_endpoint.go: addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/join/")
./agent/agent_endpoint.go: addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/force-leave/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/pass/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/warn/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/fail/")
./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/update/")
./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/id/")
./agent/agent_endpoint.go: serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/name/")
./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/")
./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/")
./agent/agent_endpoint.go: target := strings.TrimPrefix(req.URL.Path, "/v1/agent/token/")
./agent/agent_endpoint.go: serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/ca/leaf/")
./agent/catalog_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, pathPrefix)
./agent/catalog_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node/")
./agent/catalog_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node-services/")
./agent/catalog_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/catalog/gateway-services/")
./agent/config_endpoint.go: kindAndName := strings.TrimPrefix(req.URL.Path, "/v1/config/")
./agent/config_endpoint.go: kindAndName := strings.TrimPrefix(req.URL.Path, "/v1/config/")
./agent/coordinate_endpoint.go: node := strings.TrimPrefix(req.URL.Path, "/v1/coordinate/node/")
./agent/discovery_chain_endpoint.go: args.Name = strings.TrimPrefix(req.URL.Path, "/v1/discovery-chain/")
./agent/event_endpoint.go: event.Name = strings.TrimPrefix(req.URL.Path, "/v1/event/fire/")
./agent/federation_state_endpoint.go: datacenterName := strings.TrimPrefix(req.URL.Path, "/v1/internal/federation-state/")
./agent/health_endpoint.go: args.State = strings.TrimPrefix(req.URL.Path, "/v1/health/state/")
./agent/health_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/health/node/")
./agent/health_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/health/checks/")
./agent/health_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, prefix)
./agent/intentions_endpoint.go: peerName := strings.TrimPrefix(ss[0], "peer:")
./agent/intentions_endpoint.go: peerName := strings.TrimPrefix(ss[0], "peer:")
./agent/intentions_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/connect/intentions/")
./agent/kvs_endpoint.go: args.Key = strings.TrimPrefix(req.URL.Path, "/v1/kv/")
./agent/peering_endpoint.go: name := strings.TrimPrefix(req.URL.Path, "/v1/peering/")
./agent/prepared_query_endpoint.go: id := strings.TrimPrefix(path, "/v1/query/")
./agent/session_endpoint.go: args.Session.ID = strings.TrimPrefix(req.URL.Path, "/v1/session/destroy/")
./agent/session_endpoint.go: args.SessionID = strings.TrimPrefix(req.URL.Path, "/v1/session/renew/")
./agent/session_endpoint.go: args.SessionID = strings.TrimPrefix(req.URL.Path, "/v1/session/info/")
./agent/session_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/session/node/")
./agent/ui_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/node/")
./agent/ui_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/gateway-services-nodes/")
./agent/ui_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/service-topology/")
./agent/ui_endpoint.go: name := strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/gateway-intentions/")
./agent/ui_endpoint.go: subPath := strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/metrics-proxy")
- [ ] ./agent/acl_endpoint.go: policyID := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/")
- [ ] ./agent/acl_endpoint.go: policyName := strings.TrimPrefix(req.URL.Path, "/v1/acl/policy/name/")
- [ ] ./agent/acl_endpoint.go: tokenID := strings.TrimPrefix(req.URL.Path, "/v1/acl/token/")
- [ ] ./agent/acl_endpoint.go: roleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/")
- [ ] ./agent/acl_endpoint.go: roleName := strings.TrimPrefix(req.URL.Path, "/v1/acl/role/name/")
- [ ] ./agent/acl_endpoint.go: bindingRuleID := strings.TrimPrefix(req.URL.Path, "/v1/acl/binding-rule/")
- [ ] ./agent/acl_endpoint.go: methodName := strings.TrimPrefix(req.URL.Path, "/v1/acl/auth-method/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/")
- [ ] ./agent/agent_endpoint.go: addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/join/")
- [ ] ./agent/agent_endpoint.go: addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/force-leave/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/pass/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/warn/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/fail/")
- [ ] ./agent/agent_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/update/")
- [ ] ./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/id/")
- [ ] ./agent/agent_endpoint.go: serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/name/")
- [ ] ./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/")
- [ ] ./agent/agent_endpoint.go: serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/")
- [ ] ./agent/agent_endpoint.go: target := strings.TrimPrefix(req.URL.Path, "/v1/agent/token/")
- [ ] ./agent/agent_endpoint.go: serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/ca/leaf/")
- [ ] ./agent/catalog_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, pathPrefix)
- [ ] ./agent/catalog_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node/")
- [ ] ./agent/catalog_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/catalog/node-services/")
- [ ] ./agent/catalog_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/catalog/gateway-services/")
- [ ] ./agent/config_endpoint.go: kindAndName := strings.TrimPrefix(req.URL.Path, "/v1/config/")
- [ ] ./agent/config_endpoint.go: kindAndName := strings.TrimPrefix(req.URL.Path, "/v1/config/")
- [ ] ./agent/coordinate_endpoint.go: node := strings.TrimPrefix(req.URL.Path, "/v1/coordinate/node/")
- [ ] ./agent/discovery_chain_endpoint.go: args.Name = strings.TrimPrefix(req.URL.Path, "/v1/discovery-chain/")
- [ ] ./agent/event_endpoint.go: event.Name = strings.TrimPrefix(req.URL.Path, "/v1/event/fire/")
- [ ] ./agent/federation_state_endpoint.go: datacenterName := strings.TrimPrefix(req.URL.Path, "/v1/internal/federation-state/")
- [ ] ./agent/health_endpoint.go: args.State = strings.TrimPrefix(req.URL.Path, "/v1/health/state/")
- [ ] ./agent/health_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/health/node/")
- [ ] ./agent/health_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/health/checks/")
- [ ] ./agent/health_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, prefix)
- [ ] ./agent/intentions_endpoint.go: peerName := strings.TrimPrefix(ss[0], "peer:")
- [ ] ./agent/intentions_endpoint.go: peerName := strings.TrimPrefix(ss[0], "peer:")
- [ ] ./agent/intentions_endpoint.go: id := strings.TrimPrefix(req.URL.Path, "/v1/connect/intentions/")
- [ ] ./agent/kvs_endpoint.go: args.Key = strings.TrimPrefix(req.URL.Path, "/v1/kv/")
- [ ] ./agent/peering_endpoint.go: name := strings.TrimPrefix(req.URL.Path, "/v1/peering/")
- [ ] ./agent/prepared_query_endpoint.go: id := strings.TrimPrefix(path, "/v1/query/")
- [ ] ./agent/session_endpoint.go: args.Session.ID = strings.TrimPrefix(req.URL.Path, "/v1/session/destroy/")
- [ ] ./agent/session_endpoint.go: args.SessionID = strings.TrimPrefix(req.URL.Path, "/v1/session/renew/")
- [ ] ./agent/session_endpoint.go: args.SessionID = strings.TrimPrefix(req.URL.Path, "/v1/session/info/")
- [ ] ./agent/session_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/session/node/")
- [ ] ./agent/ui_endpoint.go: args.Node = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/node/")
- [ ] ./agent/ui_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/gateway-services-nodes/")
- [ ] ./agent/ui_endpoint.go: args.ServiceName = strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/service-topology/")
- [ ] ./agent/ui_endpoint.go: name := strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/gateway-intentions/")
- [ ] ./agent/ui_endpoint.go: subPath := strings.TrimPrefix(req.URL.Path, "/v1/internal/ui/metrics-proxy")
@jkirschner-hashicorp , @mkeeler , I think we do need to handle some of the endpoints as there is no restriction on the url path to these endpoint. For example
curl -X GET --header 'X-Consul-Token: <my bootstrap token>' http://localhost:8500/v1/acl/policy/http://myservice.com
<a href="/v1/acl/policy/http:/myservice.com">Moved Permanently</a>.
The expected output should be
curl -X GET --header 'X-Consul-Token: <my bootstrap token>' http://localhost:8500/v1/acl/policy/http://myservice.com
failed acl policy lookup: index error: UUID must be 36 characters%
I will update the PR to address all those endpoints.