diff --git a/agent/consul/connect_ca_endpoint.go b/agent/consul/connect_ca_endpoint.go new file mode 100644 index 0000000000..3f35ad79ff --- /dev/null +++ b/agent/consul/connect_ca_endpoint.go @@ -0,0 +1,55 @@ +package consul + +import ( + "github.com/hashicorp/consul/agent/consul/state" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/go-memdb" +) + +// ConnectCA manages the Connect CA. +type ConnectCA struct { + // srv is a pointer back to the server. + srv *Server +} + +// Roots returns the currently trusted root certificates. +func (s *ConnectCA) Roots( + args *structs.DCSpecificRequest, + reply *structs.IndexedCARoots) error { + // Forward if necessary + if done, err := s.srv.forward("ConnectCA.Roots", args, args, reply); done { + return err + } + + return s.srv.blockingQuery( + &args.QueryOptions, &reply.QueryMeta, + func(ws memdb.WatchSet, state *state.Store) error { + index, roots, err := state.CARoots(ws) + if err != nil { + return err + } + + reply.Index, reply.Roots = index, roots + if reply.Roots == nil { + reply.Roots = make(structs.CARoots, 0) + } + + // The API response must NEVER contain the secret information + // such as keys and so on. We use a whitelist below to copy the + // specific fields we want to expose. + for i, r := range reply.Roots { + // IMPORTANT: r must NEVER be modified, since it is a pointer + // directly to the structure in the memdb store. + + reply.Roots[i] = &structs.CARoot{ + ID: r.ID, + Name: r.Name, + RootCert: r.RootCert, + RaftIndex: r.RaftIndex, + } + } + + return nil + }, + ) +} diff --git a/agent/consul/server_oss.go b/agent/consul/server_oss.go index e633c26991..016420476d 100644 --- a/agent/consul/server_oss.go +++ b/agent/consul/server_oss.go @@ -4,6 +4,7 @@ func init() { registerEndpoint(func(s *Server) interface{} { return &ACL{s} }) registerEndpoint(func(s *Server) interface{} { return &Catalog{s} }) registerEndpoint(func(s *Server) interface{} { return NewCoordinate(s) }) + registerEndpoint(func(s *Server) interface{} { return &ConnectCA{s} }) registerEndpoint(func(s *Server) interface{} { return &Health{s} }) registerEndpoint(func(s *Server) interface{} { return &Intention{s} }) registerEndpoint(func(s *Server) interface{} { return &Internal{s} })