mirror of https://github.com/status-im/consul.git
agent: /v1/connect/ca/configuration PUT for setting configuration
This commit is contained in:
parent
1c3dbc83ff
commit
63d674d07d
|
@ -1,6 +1,7 @@
|
||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
@ -26,3 +27,30 @@ func (s *HTTPServer) ConnectCARoots(resp http.ResponseWriter, req *http.Request)
|
||||||
|
|
||||||
return reply, nil
|
return reply, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /v1/connect/ca/configuration
|
||||||
|
func (s *HTTPServer) ConnectCAConfiguration(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
|
switch req.Method {
|
||||||
|
case "PUT":
|
||||||
|
return s.ConnectCAConfigurationSet(resp, req)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, MethodNotAllowedError{req.Method, []string{"GET", "POST"}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /v1/connect/ca/configuration
|
||||||
|
func (s *HTTPServer) ConnectCAConfigurationSet(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
|
// Method is tested in ConnectCAConfiguration
|
||||||
|
|
||||||
|
var args structs.CAConfiguration
|
||||||
|
if err := decodeBody(req, &args, nil); err != nil {
|
||||||
|
resp.WriteHeader(http.StatusBadRequest)
|
||||||
|
fmt.Fprintf(resp, "Request decode failed: %v", err)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply interface{}
|
||||||
|
err := s.agent.RPC("ConnectCA.ConfigurationSet", &args, &reply)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@ import (
|
||||||
"github.com/hashicorp/consul/agent/consul/state"
|
"github.com/hashicorp/consul/agent/consul/state"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
|
"github.com/mitchellh/go-testing-interface"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectCA manages the Connect CA.
|
// ConnectCA manages the Connect CA.
|
||||||
|
@ -22,6 +25,90 @@ type ConnectCA struct {
|
||||||
srv *Server
|
srv *Server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigurationSet updates the configuration for the CA.
|
||||||
|
//
|
||||||
|
// NOTE(mitchellh): This whole implementation is temporary until the real
|
||||||
|
// CA plugin work comes in. For now, this is only used to configure a single
|
||||||
|
// static CA root.
|
||||||
|
func (s *ConnectCA) ConfigurationSet(
|
||||||
|
args *structs.CAConfiguration,
|
||||||
|
reply *interface{}) error {
|
||||||
|
// NOTE(mitchellh): This is the temporary hardcoding of a static CA
|
||||||
|
// provider. This will allow us to test agent implementations and so on
|
||||||
|
// with an incomplete CA for now.
|
||||||
|
if args.Provider != "static" {
|
||||||
|
return fmt.Errorf("The CA provider can only be 'static' for now")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the configuration allowed for our static provider
|
||||||
|
var config struct {
|
||||||
|
Name string
|
||||||
|
CertPEM string
|
||||||
|
PrivateKeyPEM string
|
||||||
|
Generate bool
|
||||||
|
}
|
||||||
|
if err := mapstructure.Decode(args.Config, &config); err != nil {
|
||||||
|
return fmt.Errorf("error decoding config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic validation so demos aren't super jank
|
||||||
|
if config.Name == "" {
|
||||||
|
return fmt.Errorf("Name must be set")
|
||||||
|
}
|
||||||
|
if config.CertPEM == "" || config.PrivateKeyPEM == "" {
|
||||||
|
if !config.Generate {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"CertPEM and PrivateKeyPEM must be set, or Generate must be true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience to auto-generate the cert
|
||||||
|
if config.Generate {
|
||||||
|
ca := connect.TestCA(&testing.RuntimeT{}, nil)
|
||||||
|
config.CertPEM = ca.RootCert
|
||||||
|
config.PrivateKeyPEM = ca.SigningKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mitchellh): verify that the private key is valid for the cert
|
||||||
|
|
||||||
|
// Generate an ID for this
|
||||||
|
id, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the highest index
|
||||||
|
state := s.srv.fsm.State()
|
||||||
|
idx, _, err := state.CARoots(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit
|
||||||
|
resp, err := s.srv.raftApply(structs.ConnectCARequestType, &structs.CARequest{
|
||||||
|
Op: structs.CAOpSet,
|
||||||
|
Index: idx,
|
||||||
|
Roots: []*structs.CARoot{
|
||||||
|
&structs.CARoot{
|
||||||
|
ID: id,
|
||||||
|
Name: config.Name,
|
||||||
|
RootCert: config.CertPEM,
|
||||||
|
SigningKey: config.PrivateKeyPEM,
|
||||||
|
Active: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.srv.logger.Printf("[ERR] consul.test: Apply failed %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if respErr, ok := resp.(error); ok {
|
||||||
|
return respErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Roots returns the currently trusted root certificates.
|
// Roots returns the currently trusted root certificates.
|
||||||
func (s *ConnectCA) Roots(
|
func (s *ConnectCA) Roots(
|
||||||
args *structs.DCSpecificRequest,
|
args *structs.DCSpecificRequest,
|
||||||
|
|
|
@ -42,6 +42,7 @@ func init() {
|
||||||
registerEndpoint("/v1/catalog/services", []string{"GET"}, (*HTTPServer).CatalogServices)
|
registerEndpoint("/v1/catalog/services", []string{"GET"}, (*HTTPServer).CatalogServices)
|
||||||
registerEndpoint("/v1/catalog/service/", []string{"GET"}, (*HTTPServer).CatalogServiceNodes)
|
registerEndpoint("/v1/catalog/service/", []string{"GET"}, (*HTTPServer).CatalogServiceNodes)
|
||||||
registerEndpoint("/v1/catalog/node/", []string{"GET"}, (*HTTPServer).CatalogNodeServices)
|
registerEndpoint("/v1/catalog/node/", []string{"GET"}, (*HTTPServer).CatalogNodeServices)
|
||||||
|
registerEndpoint("/v1/connect/ca/configuration", []string{"PUT"}, (*HTTPServer).ConnectCAConfiguration)
|
||||||
registerEndpoint("/v1/connect/ca/roots", []string{"GET"}, (*HTTPServer).ConnectCARoots)
|
registerEndpoint("/v1/connect/ca/roots", []string{"GET"}, (*HTTPServer).ConnectCARoots)
|
||||||
registerEndpoint("/v1/connect/intentions", []string{"GET", "POST"}, (*HTTPServer).IntentionEndpoint)
|
registerEndpoint("/v1/connect/intentions", []string{"GET", "POST"}, (*HTTPServer).IntentionEndpoint)
|
||||||
registerEndpoint("/v1/connect/intentions/match", []string{"GET"}, (*HTTPServer).IntentionMatch)
|
registerEndpoint("/v1/connect/intentions/match", []string{"GET"}, (*HTTPServer).IntentionMatch)
|
||||||
|
|
|
@ -113,3 +113,14 @@ type CARequest struct {
|
||||||
// always be active.
|
// always be active.
|
||||||
Roots []*CARoot
|
Roots []*CARoot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAConfiguration is the configuration for the current CA plugin.
|
||||||
|
type CAConfiguration struct {
|
||||||
|
// Provider is the CA provider implementation to use.
|
||||||
|
Provider string
|
||||||
|
|
||||||
|
// Configuration is arbitrary configuration for the provider. This
|
||||||
|
// should only contain primitive values and containers (such as lists
|
||||||
|
// and maps).
|
||||||
|
Config map[string]interface{}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue