mirror of https://github.com/linkerd/linkerd2.git
103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package injector
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
|
|
"github.com/linkerd/linkerd2/controller/k8s"
|
|
pkgTls "github.com/linkerd/linkerd2/pkg/tls"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// WebhookServer is the webhook's HTTP server. It has an embedded webhook which
|
|
// mutate all the requests.
|
|
type WebhookServer struct {
|
|
*http.Server
|
|
*Webhook
|
|
}
|
|
|
|
// NewWebhookServer returns a new instance of the WebhookServer.
|
|
func NewWebhookServer(api *k8s.API, addr, controllerNamespace string, rootCA *pkgTls.CA) (*WebhookServer, error) {
|
|
c, err := tlsConfig(rootCA, controllerNamespace)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
server := &http.Server{
|
|
Addr: addr,
|
|
TLSConfig: c,
|
|
}
|
|
|
|
webhook, err := NewWebhook(api, controllerNamespace)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ws := &WebhookServer{server, webhook}
|
|
ws.Handler = http.HandlerFunc(ws.serve)
|
|
return ws, nil
|
|
}
|
|
|
|
func (w *WebhookServer) serve(res http.ResponseWriter, req *http.Request) {
|
|
var (
|
|
data []byte
|
|
err error
|
|
)
|
|
if req.Body != nil {
|
|
data, err = ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
http.Error(res, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
if len(data) == 0 {
|
|
return
|
|
}
|
|
|
|
response := w.Mutate(data)
|
|
responseJSON, err := json.Marshal(response)
|
|
if err != nil {
|
|
http.Error(res, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if _, err := res.Write(responseJSON); err != nil {
|
|
http.Error(res, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Shutdown initiates a graceful shutdown of the underlying HTTP server.
|
|
func (w *WebhookServer) Shutdown() error {
|
|
return w.Server.Shutdown(context.Background())
|
|
}
|
|
|
|
func tlsConfig(rootCA *pkgTls.CA, controllerNamespace string) (*tls.Config, error) {
|
|
// must use the service short name in this TLS identity as the k8s api server
|
|
// looks for the webhook at <svc_name>.<namespace>.svc, without the cluster
|
|
// domain.
|
|
dnsName := fmt.Sprintf("linkerd-proxy-injector.%s.svc", controllerNamespace)
|
|
cred, err := rootCA.GenerateEndEntityCred(dnsName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certPEM := cred.EncodePEM()
|
|
log.Debugf("PEM-encoded certificate: %s\n", certPEM)
|
|
|
|
keyPEM := cred.EncodePrivateKeyPEM()
|
|
cert, err := tls.X509KeyPair([]byte(certPEM), []byte(keyPEM))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
}, nil
|
|
}
|