mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			295 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Package signhandler provides the handlers for signers.
 | 
						|
package signhandler
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"io/ioutil"
 | 
						|
	"math/big"
 | 
						|
	"net/http"
 | 
						|
 | 
						|
	"github.com/cloudflare/cfssl/api"
 | 
						|
	"github.com/cloudflare/cfssl/auth"
 | 
						|
	"github.com/cloudflare/cfssl/bundler"
 | 
						|
	"github.com/cloudflare/cfssl/errors"
 | 
						|
	"github.com/cloudflare/cfssl/log"
 | 
						|
	"github.com/cloudflare/cfssl/signer"
 | 
						|
)
 | 
						|
 | 
						|
// NoBundlerMessage is used to alert the user that the server does not have a bundler initialized.
 | 
						|
const NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.`
 | 
						|
 | 
						|
// A Handler accepts requests with a hostname and certficate
 | 
						|
// parameter (which should be PEM-encoded) and returns a new signed
 | 
						|
// certificate. It includes upstream servers indexed by their
 | 
						|
// profile name.
 | 
						|
type Handler struct {
 | 
						|
	signer  signer.Signer
 | 
						|
	bundler *bundler.Bundler
 | 
						|
}
 | 
						|
 | 
						|
// NewHandlerFromSigner generates a new Handler directly from
 | 
						|
// an existing signer.
 | 
						|
func NewHandlerFromSigner(signer signer.Signer) (h *api.HTTPHandler, err error) {
 | 
						|
	policy := signer.Policy()
 | 
						|
	if policy == nil {
 | 
						|
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// Sign will only respond for profiles that have no auth provider.
 | 
						|
	// So if all of the profiles require authentication, we return an error.
 | 
						|
	haveUnauth := (policy.Default.Provider == nil)
 | 
						|
	for _, profile := range policy.Profiles {
 | 
						|
		haveUnauth = haveUnauth || (profile.Provider == nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if !haveUnauth {
 | 
						|
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	return &api.HTTPHandler{
 | 
						|
		Handler: &Handler{
 | 
						|
			signer: signer,
 | 
						|
		},
 | 
						|
		Methods: []string{"POST"},
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// SetBundler allows injecting an optional Bundler into the Handler.
 | 
						|
func (h *Handler) SetBundler(caBundleFile, intBundleFile string) (err error) {
 | 
						|
	h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// This type is meant to be unmarshalled from JSON so that there can be a
 | 
						|
// hostname field in the API
 | 
						|
// TODO: Change the API such that the normal struct can be used.
 | 
						|
type jsonSignRequest struct {
 | 
						|
	Hostname string          `json:"hostname"`
 | 
						|
	Hosts    []string        `json:"hosts"`
 | 
						|
	Request  string          `json:"certificate_request"`
 | 
						|
	Subject  *signer.Subject `json:"subject,omitempty"`
 | 
						|
	Profile  string          `json:"profile"`
 | 
						|
	Label    string          `json:"label"`
 | 
						|
	Serial   *big.Int        `json:"serial,omitempty"`
 | 
						|
	Bundle   bool            `json:"bundle"`
 | 
						|
}
 | 
						|
 | 
						|
func jsonReqToTrue(js jsonSignRequest) signer.SignRequest {
 | 
						|
	sub := new(signer.Subject)
 | 
						|
	if js.Subject == nil {
 | 
						|
		sub = nil
 | 
						|
	} else {
 | 
						|
		// make a copy
 | 
						|
		*sub = *js.Subject
 | 
						|
	}
 | 
						|
 | 
						|
	if js.Hostname != "" {
 | 
						|
		return signer.SignRequest{
 | 
						|
			Hosts:   signer.SplitHosts(js.Hostname),
 | 
						|
			Subject: sub,
 | 
						|
			Request: js.Request,
 | 
						|
			Profile: js.Profile,
 | 
						|
			Label:   js.Label,
 | 
						|
			Serial:  js.Serial,
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return signer.SignRequest{
 | 
						|
		Hosts:   js.Hosts,
 | 
						|
		Subject: sub,
 | 
						|
		Request: js.Request,
 | 
						|
		Profile: js.Profile,
 | 
						|
		Label:   js.Label,
 | 
						|
		Serial:  js.Serial,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Handle responds to requests for the CA to sign the certificate request
 | 
						|
// present in the "certificate_request" parameter for the host named
 | 
						|
// in the "hostname" parameter. The certificate should be PEM-encoded. If
 | 
						|
// provided, subject information from the "subject" parameter will be used
 | 
						|
// in place of the subject information from the CSR.
 | 
						|
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
						|
	log.Info("signature request received")
 | 
						|
 | 
						|
	body, err := ioutil.ReadAll(r.Body)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	r.Body.Close()
 | 
						|
 | 
						|
	var req jsonSignRequest
 | 
						|
 | 
						|
	err = json.Unmarshal(body, &req)
 | 
						|
	if err != nil {
 | 
						|
		return errors.NewBadRequestString("Unable to parse sign request")
 | 
						|
	}
 | 
						|
 | 
						|
	signReq := jsonReqToTrue(req)
 | 
						|
 | 
						|
	if req.Request == "" {
 | 
						|
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
 | 
						|
	}
 | 
						|
 | 
						|
	var cert []byte
 | 
						|
	profile, err := signer.Profile(h.signer, req.Profile)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if profile.Provider != nil {
 | 
						|
		log.Error("profile requires authentication")
 | 
						|
		return errors.NewBadRequestString("authentication required")
 | 
						|
	}
 | 
						|
 | 
						|
	cert, err = h.signer.Sign(signReq)
 | 
						|
	if err != nil {
 | 
						|
		log.Warningf("failed to sign request: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	result := map[string]interface{}{"certificate": string(cert)}
 | 
						|
	if req.Bundle {
 | 
						|
		if h.bundler == nil {
 | 
						|
			return api.SendResponseWithMessage(w, result, NoBundlerMessage,
 | 
						|
				errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
 | 
						|
		}
 | 
						|
 | 
						|
		bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "")
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		result["bundle"] = bundle
 | 
						|
	}
 | 
						|
	log.Info("wrote response")
 | 
						|
	return api.SendResponse(w, result)
 | 
						|
}
 | 
						|
 | 
						|
// An AuthHandler verifies and signs incoming signature requests.
 | 
						|
type AuthHandler struct {
 | 
						|
	signer  signer.Signer
 | 
						|
	bundler *bundler.Bundler
 | 
						|
}
 | 
						|
 | 
						|
// NewAuthHandlerFromSigner creates a new AuthHandler from the signer
 | 
						|
// that is passed in.
 | 
						|
func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) {
 | 
						|
	policy := signer.Policy()
 | 
						|
	if policy == nil {
 | 
						|
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
						|
	}
 | 
						|
 | 
						|
	if policy.Default == nil && policy.Profiles == nil {
 | 
						|
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
						|
	}
 | 
						|
 | 
						|
	// AuthSign will not respond for profiles that have no auth provider.
 | 
						|
	// So if there are no profiles with auth providers in this policy,
 | 
						|
	// we return an error.
 | 
						|
	haveAuth := (policy.Default.Provider != nil)
 | 
						|
	for _, profile := range policy.Profiles {
 | 
						|
		if haveAuth {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		haveAuth = (profile.Provider != nil)
 | 
						|
	}
 | 
						|
 | 
						|
	if !haveAuth {
 | 
						|
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
						|
	}
 | 
						|
 | 
						|
	return &api.HTTPHandler{
 | 
						|
		Handler: &AuthHandler{
 | 
						|
			signer: signer,
 | 
						|
		},
 | 
						|
		Methods: []string{"POST"},
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// SetBundler allows injecting an optional Bundler into the Handler.
 | 
						|
func (h *AuthHandler) SetBundler(caBundleFile, intBundleFile string) (err error) {
 | 
						|
	h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// Handle receives the incoming request, validates it, and processes it.
 | 
						|
func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
						|
	log.Info("signature request received")
 | 
						|
 | 
						|
	body, err := ioutil.ReadAll(r.Body)
 | 
						|
	if err != nil {
 | 
						|
		log.Errorf("failed to read response body: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	r.Body.Close()
 | 
						|
 | 
						|
	var aReq auth.AuthenticatedRequest
 | 
						|
	err = json.Unmarshal(body, &aReq)
 | 
						|
	if err != nil {
 | 
						|
		log.Errorf("failed to unmarshal authenticated request: %v", err)
 | 
						|
		return errors.NewBadRequest(err)
 | 
						|
	}
 | 
						|
 | 
						|
	var req jsonSignRequest
 | 
						|
	err = json.Unmarshal(aReq.Request, &req)
 | 
						|
	if err != nil {
 | 
						|
		log.Errorf("failed to unmarshal request from authenticated request: %v", err)
 | 
						|
		return errors.NewBadRequestString("Unable to parse authenticated sign request")
 | 
						|
	}
 | 
						|
 | 
						|
	// Sanity checks to ensure that we have a valid policy. This
 | 
						|
	// should have been checked in NewAuthHandler.
 | 
						|
	policy := h.signer.Policy()
 | 
						|
	if policy == nil {
 | 
						|
		log.Critical("signer was initialised without a signing policy")
 | 
						|
		return errors.NewBadRequestString("invalid policy")
 | 
						|
	}
 | 
						|
 | 
						|
	profile, err := signer.Profile(h.signer, req.Profile)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if profile.Provider == nil {
 | 
						|
		log.Error("profile has no authentication provider")
 | 
						|
		return errors.NewBadRequestString("no authentication provider")
 | 
						|
	}
 | 
						|
 | 
						|
	if !profile.Provider.Verify(&aReq) {
 | 
						|
		log.Warning("received authenticated request with invalid token")
 | 
						|
		return errors.NewBadRequestString("invalid token")
 | 
						|
	}
 | 
						|
 | 
						|
	signReq := jsonReqToTrue(req)
 | 
						|
 | 
						|
	if signReq.Request == "" {
 | 
						|
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
 | 
						|
	}
 | 
						|
 | 
						|
	cert, err := h.signer.Sign(signReq)
 | 
						|
	if err != nil {
 | 
						|
		log.Errorf("signature failed: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	result := map[string]interface{}{"certificate": string(cert)}
 | 
						|
	if req.Bundle {
 | 
						|
		if h.bundler == nil {
 | 
						|
			return api.SendResponseWithMessage(w, result, NoBundlerMessage,
 | 
						|
				errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
 | 
						|
		}
 | 
						|
 | 
						|
		bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "")
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		result["bundle"] = bundle
 | 
						|
	}
 | 
						|
	log.Info("wrote response")
 | 
						|
	return api.SendResponse(w, result)
 | 
						|
}
 |