xds: document how authorization works

This commit is contained in:
Daniel Nephin 2021-08-13 11:53:19 -04:00
parent 1cef3c99c2
commit 9df2464c7c
4 changed files with 45 additions and 8 deletions

View File

@ -138,7 +138,7 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove
} }
checkStreamACLs := func(cfgSnap *proxycfg.ConfigSnapshot) error { checkStreamACLs := func(cfgSnap *proxycfg.ConfigSnapshot) error {
return s.checkStreamACLs(stream.Context(), cfgSnap) return s.authorize(stream.Context(), cfgSnap)
} }
for { for {

View File

@ -327,7 +327,7 @@ func (s *Server) process(stream ADSStream, reqCh <-chan *envoy_discovery_v3.Disc
} }
checkStreamACLs := func(cfgSnap *proxycfg.ConfigSnapshot) error { checkStreamACLs := func(cfgSnap *proxycfg.ConfigSnapshot) error {
return s.checkStreamACLs(stream.Context(), cfgSnap) return s.authorize(stream.Context(), cfgSnap)
} }
for { for {
@ -564,13 +564,22 @@ func NewGRPCServer(s *Server, tlsConfigurator *tlsutil.Configurator) *grpc.Serve
return srv return srv
} }
func (s *Server) checkStreamACLs(streamCtx context.Context, cfgSnap *proxycfg.ConfigSnapshot) error { // authorize the xDS request using the token stored in ctx. This authorization is
// a bit different from most interfaces. Instead of explicitly authorizing or
// filtering each piece of data in the response, the request is authorized
// by checking the token has `service:write` for the service ID of the destination
// service (for kind=ConnectProxy), or the gateway service (for other kinds).
// This authorization strategy requires that agent/proxycfg only fetches data
// using a token with the same permissions, and that it stores the data by
// proxy ID. We assume that any data in the snapshot was already filtered,
// which allows this authorization to be a shallow authorization check
// for all the data in a ConfigSnapshot.
func (s *Server) authorize(ctx context.Context, cfgSnap *proxycfg.ConfigSnapshot) error {
if cfgSnap == nil { if cfgSnap == nil {
return status.Errorf(codes.Unauthenticated, "unauthenticated: no config snapshot") return status.Errorf(codes.Unauthenticated, "unauthenticated: no config snapshot")
} }
authz, err := s.ResolveToken(tokenFromContext(streamCtx)) authz, err := s.ResolveToken(tokenFromContext(ctx))
if acl.IsErrNotFound(err) { if acl.IsErrNotFound(err) {
return status.Errorf(codes.Unauthenticated, "unauthenticated: %v", err) return status.Errorf(codes.Unauthenticated, "unauthenticated: %v", err)
} else if acl.IsErrPermissionDenied(err) { } else if acl.IsErrPermissionDenied(err) {

View File

@ -1,12 +1,15 @@
# Service Mesh (Connect) # Service Mesh (Connect)
- call out: envoy/proxy is the data plane, Consul is the control plane - call out: envoy/proxy is the data plane, Consul is the control plane
- agent/xds - gRPC service that implements - [xDS Server] - a gRPC service that implements [xDS] and handles requests from an [envoy proxy].
[xDS](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol) - [agent/proxycfg]
- [agent/proxycfg](https://github.com/hashicorp/consul/blob/master/agent/proxycfg/proxycfg.go)
- CA Manager - certificate authority - CA Manager - certificate authority
- command/connect/envoy - bootstrapping and running envoy - command/connect/envoy - bootstrapping and running envoy
- command/connect/proxy - built-in proxy that is dev-only and not supported - command/connect/proxy - built-in proxy that is dev-only and not supported
for production. for production.
- `connect/` - "Native" service mesh - `connect/` - "Native" service mesh
[xDS Server]: ./xds.md
[xDS]: https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol
[envoy proxy]: https://www.consul.io/docs/connect/proxies/envoy
[agent/proxycfg]: https://github.com/hashicorp/consul/blob/main/agent/proxycfg

View File

@ -0,0 +1,25 @@
# xDS Server
The xDS Server is a gRPC service that implements [xDS] and handles requests from
an [envoy proxy].
[xDS]: https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol
[envoy proxy]: https://www.consul.io/docs/connect/proxies/envoy
## Authorization
Requests to the xDS server are authorized based on an assumption of how
`proxycfg.ConfigSnapshot` are constructed. Most interfaces (HTTP, DNS, RPC)
authorize requests by authorizing the data in the response, or by filtering
out data that the requester is not authorized to view. The xDS server authorizes
requests by looking at the proxy ID in the request and ensuring the ACL token has
`service:write` access to either the destination service (for kind=ConnectProxy), or
the gateway service (for other kinds).
This authorization strategy requires that [agent/proxycfg] only fetches data using a
token with the same permissions, and that it only stores data by proxy ID. We assume
that any data in the snapshot was already filtered, which allows this authorization to
only perform a shallow check against the proxy ID.
[agent/proxycfg]: https://github.com/hashicorp/consul/blob/main/agent/proxycfg