diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index e3e8fcd51f..97c52512a9 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -839,9 +839,8 @@ func (s *HTTPServer) AgentToken(resp http.ResponseWriter, req *http.Request) (in // AgentConnectCARoots returns the trusted CA roots. func (s *HTTPServer) AgentConnectCARoots(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - if req.Method != "GET" { - return nil, MethodNotAllowedError{req.Method, []string{"GET"}} - } - - return nil, nil + // NOTE(mitchellh): for now this is identical to /v1/connect/ca/roots. + // In the future, we're going to do some agent-local caching and the + // behavior will differ. + return s.ConnectCARoots(resp, req) } diff --git a/agent/connect_ca_endpoint_test.go b/agent/connect_ca_endpoint_test.go new file mode 100644 index 0000000000..ee30f57a90 --- /dev/null +++ b/agent/connect_ca_endpoint_test.go @@ -0,0 +1,27 @@ +package agent + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/hashicorp/consul/agent/structs" + "github.com/stretchr/testify/assert" +) + +func TestConnectCARoots_empty(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + a := NewTestAgent(t.Name(), "") + defer a.Shutdown() + + req, _ := http.NewRequest("GET", "/v1/connect/ca/roots", nil) + resp := httptest.NewRecorder() + obj, err := a.srv.ConnectCARoots(resp, req) + assert.Nil(err) + + value := obj.(structs.IndexedCARoots) + assert.Equal(value.ActiveRootID, "") + assert.Len(value.Roots, 0) +} diff --git a/agent/consul/connect_ca_endpoint.go b/agent/consul/connect_ca_endpoint.go index 9e6b8a4b19..1702c87403 100644 --- a/agent/consul/connect_ca_endpoint.go +++ b/agent/consul/connect_ca_endpoint.go @@ -56,6 +56,11 @@ func (s *ConnectCA) Roots( Name: r.Name, RootCert: r.RootCert, RaftIndex: r.RaftIndex, + Active: r.Active, + } + + if r.Active { + reply.ActiveRootID = r.ID } } diff --git a/agent/consul/connect_ca_endpoint_test.go b/agent/consul/connect_ca_endpoint_test.go index d658c7ade0..375d751152 100644 --- a/agent/consul/connect_ca_endpoint_test.go +++ b/agent/consul/connect_ca_endpoint_test.go @@ -12,6 +12,44 @@ import ( "github.com/stretchr/testify/assert" ) +// Test listing root CAs. +func TestConnectCARoots(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + dir1, s1 := testServer(t) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + codec := rpcClient(t, s1) + defer codec.Close() + + testrpc.WaitForLeader(t, s1.RPC, "dc1") + + // Insert some CAs + state := s1.fsm.State() + ca1 := connect.TestCA(t, nil) + ca2 := connect.TestCA(t, nil) + ca2.Active = false + assert.Nil(state.CARootSet(1, ca1)) + assert.Nil(state.CARootSet(2, ca2)) + + // Request + args := &structs.DCSpecificRequest{ + Datacenter: "dc1", + } + var reply structs.IndexedCARoots + assert.Nil(msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", args, &reply)) + + // Verify + assert.Equal(ca1.ID, reply.ActiveRootID) + assert.Len(reply.Roots, 2) + for _, r := range reply.Roots { + // These must never be set, for security + assert.Equal("", r.SigningCert) + assert.Equal("", r.SigningKey) + } +} + // Test CA signing // // NOTE(mitchellh): Just testing the happy path and not all the other validation