2019-08-02 20:34:54 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
2019-08-19 18:03:03 +00:00
|
|
|
"errors"
|
2019-08-02 20:34:54 +00:00
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
metrics "github.com/armon/go-metrics"
|
|
|
|
"github.com/hashicorp/consul/acl"
|
2019-08-19 18:03:03 +00:00
|
|
|
"github.com/hashicorp/consul/agent/connect"
|
2019-08-02 20:34:54 +00:00
|
|
|
"github.com/hashicorp/consul/agent/consul/discoverychain"
|
|
|
|
"github.com/hashicorp/consul/agent/consul/state"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
|
|
memdb "github.com/hashicorp/go-memdb"
|
|
|
|
)
|
|
|
|
|
|
|
|
type DiscoveryChain struct {
|
|
|
|
srv *Server
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *DiscoveryChain) Get(args *structs.DiscoveryChainRequest, reply *structs.DiscoveryChainResponse) error {
|
2019-08-19 18:03:03 +00:00
|
|
|
// Exit early if Connect hasn't been enabled.
|
|
|
|
if !c.srv.config.ConnectEnabled {
|
|
|
|
return ErrConnectNotEnabled
|
|
|
|
}
|
|
|
|
|
2019-08-02 20:34:54 +00:00
|
|
|
if done, err := c.srv.forward("DiscoveryChain.Get", args, args, reply); done {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer metrics.MeasureSince([]string{"discovery_chain", "get"}, time.Now())
|
|
|
|
|
|
|
|
// Fetch the ACL token, if any.
|
2020-01-24 15:04:58 +00:00
|
|
|
entMeta := args.GetEnterpriseMeta()
|
|
|
|
var authzContext acl.AuthorizerContext
|
|
|
|
rule, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, entMeta, &authzContext)
|
2019-08-02 20:34:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-01-24 15:04:58 +00:00
|
|
|
if rule != nil && rule.ServiceRead(args.Name, &authzContext) != acl.Allow {
|
2019-08-02 20:34:54 +00:00
|
|
|
return acl.ErrPermissionDenied
|
|
|
|
}
|
|
|
|
|
|
|
|
if args.Name == "" {
|
|
|
|
return fmt.Errorf("Must provide service name")
|
|
|
|
}
|
|
|
|
|
|
|
|
evalDC := args.EvaluateInDatacenter
|
|
|
|
if evalDC == "" {
|
|
|
|
evalDC = c.srv.config.Datacenter
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.srv.blockingQuery(
|
|
|
|
&args.QueryOptions,
|
|
|
|
&reply.QueryMeta,
|
|
|
|
func(ws memdb.WatchSet, state *state.Store) error {
|
2020-01-24 15:04:58 +00:00
|
|
|
index, entries, err := state.ReadDiscoveryChainConfigEntries(ws, args.Name, entMeta)
|
2019-08-02 20:34:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-19 18:03:03 +00:00
|
|
|
_, config, err := state.CAConfig(ws)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
} else if config == nil {
|
|
|
|
return errors.New("no cluster ca config setup")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build TrustDomain based on the ClusterID stored.
|
|
|
|
signingID := connect.SpiffeIDSigningForCluster(config)
|
|
|
|
if signingID == nil {
|
|
|
|
// If CA is bootstrapped at all then this should never happen but be
|
|
|
|
// defensive.
|
|
|
|
return errors.New("no cluster trust domain setup")
|
|
|
|
}
|
|
|
|
currentTrustDomain := signingID.Host()
|
|
|
|
|
2019-08-02 20:34:54 +00:00
|
|
|
// Then we compile it into something useful.
|
|
|
|
chain, err := discoverychain.Compile(discoverychain.CompileRequest{
|
|
|
|
ServiceName: args.Name,
|
2020-01-24 15:04:58 +00:00
|
|
|
EvaluateInNamespace: entMeta.NamespaceOrDefault(),
|
2019-08-05 18:30:35 +00:00
|
|
|
EvaluateInDatacenter: evalDC,
|
2019-08-19 18:03:03 +00:00
|
|
|
EvaluateInTrustDomain: currentTrustDomain,
|
2019-08-05 18:30:35 +00:00
|
|
|
UseInDatacenter: c.srv.config.Datacenter,
|
2019-08-02 20:34:54 +00:00
|
|
|
OverrideMeshGateway: args.OverrideMeshGateway,
|
|
|
|
OverrideProtocol: args.OverrideProtocol,
|
|
|
|
OverrideConnectTimeout: args.OverrideConnectTimeout,
|
|
|
|
Entries: entries,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
reply.Index = index
|
|
|
|
reply.Chain = chain
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|