xds: document how authorization works
This commit is contained in:
parent
1cef3c99c2
commit
9df2464c7c
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue