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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
|
@ -26,3 +27,30 @@ func (s *HTTPServer) ConnectCARoots(resp http.ResponseWriter, req *http.Request)
|
|||
|
||||
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/structs"
|
||||
"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.
|
||||
|
@ -22,6 +25,90 @@ type ConnectCA struct {
|
|||
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.
|
||||
func (s *ConnectCA) Roots(
|
||||
args *structs.DCSpecificRequest,
|
||||
|
|
|
@ -42,6 +42,7 @@ func init() {
|
|||
registerEndpoint("/v1/catalog/services", []string{"GET"}, (*HTTPServer).CatalogServices)
|
||||
registerEndpoint("/v1/catalog/service/", []string{"GET"}, (*HTTPServer).CatalogServiceNodes)
|
||||
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/intentions", []string{"GET", "POST"}, (*HTTPServer).IntentionEndpoint)
|
||||
registerEndpoint("/v1/connect/intentions/match", []string{"GET"}, (*HTTPServer).IntentionMatch)
|
||||
|
|
|
@ -113,3 +113,14 @@ type CARequest struct {
|
|||
// always be active.
|
||||
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