From 89adb744140ce60565b46a0acbacc5abb6118713 Mon Sep 17 00:00:00 2001 From: Mike Brown Date: Mon, 19 Mar 2018 13:23:10 -0500 Subject: [PATCH] adds tls certificate to tls config Signed-off-by: Mike Brown --- hack/utils.sh | 2 +- pkg/server/streaming.go | 110 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/hack/utils.sh b/hack/utils.sh index c00e94137..2daeaf0ff 100755 --- a/hack/utils.sh +++ b/hack/utils.sh @@ -17,7 +17,7 @@ ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/.. # Not from vendor.conf. -CRITOOL_VERSION=976680c4aa382339ccba214d1f1a88fdc8638b78 +CRITOOL_VERSION=207e773f72fde8d8aed1447692d8f800a6686d6c CRITOOL_PKG=github.com/kubernetes-incubator/cri-tools CRITOOL_REPO=github.com/kubernetes-incubator/cri-tools diff --git a/pkg/server/streaming.go b/pkg/server/streaming.go index 78787e0cd..07c92cdc1 100644 --- a/pkg/server/streaming.go +++ b/pkg/server/streaming.go @@ -17,20 +17,38 @@ limitations under the License. package server import ( + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" "io" "math" + "math/big" "net" + "os" + "time" "github.com/pkg/errors" k8snet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/tools/remotecommand" + k8scert "k8s.io/client-go/util/cert" "k8s.io/kubernetes/pkg/kubelet/server/streaming" "k8s.io/utils/exec" ctrdutil "github.com/containerd/cri/pkg/containerd/util" ) +const ( + // OrganizationName is is the name of this organization, used for certificates etc. + OrganizationName = "containerd" + // CRIName is the common name of the CRI plugin + CRIName = "cri" +) + func newStreamServer(c *criService, addr, port string) (streaming.Server, error) { if addr == "" { a, err := k8snet.ChooseBindAddress(nil) @@ -42,6 +60,14 @@ func newStreamServer(c *criService, addr, port string) (streaming.Server, error) config := streaming.DefaultConfig config.Addr = net.JoinHostPort(addr, port) runtime := newStreamRuntime(c) + tlsCert, err := newTLSCert() + if err != nil { + return nil, errors.Wrap(err, "failed to generate tls certificate for stream server") + } + config.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{tlsCert}, + InsecureSkipVerify: true, + } return streaming.NewServer(config, runtime) } @@ -112,3 +138,87 @@ func handleResizing(resize <-chan remotecommand.TerminalSize, resizeFunc func(si } }() } + +// newTLSCert returns a tls.certificate loaded from a newly generated +// x509certificate from a newly generated rsa public/private key pair. The +// x509certificate is self signed. +// TODO (mikebrow): replace / rewrite this function to support using CA +// signing of the cetificate. Requires a security plan for kubernetes regarding +// CRI connections / streaming, etc. For example, kubernetes could configure or +// require a CA service and pass a configuration down through CRI. +func newTLSCert() (tls.Certificate, error) { + fail := func(err error) (tls.Certificate, error) { return tls.Certificate{}, err } + var years = 1 // duration of certificate + + // Generate new private key + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return fail(errors.Wrap(err, "private key cannot be created")) + } + + // Generate pem block using the private key + keyPem := pem.EncodeToMemory(&pem.Block{ + Type: k8scert.RSAPrivateKeyBlockType, + Bytes: x509.MarshalPKCS1PrivateKey(privKey), + }) + + // Generate a new random serial number for certificate + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return fail(errors.Wrap(err, "failed to generate serial number")) + } + hostName, err := os.Hostname() + if err != nil { + return fail(errors.Wrap(err, "failed to get hostname")) + } + addrs, err := net.InterfaceAddrs() + if err != nil { + return fail(errors.Wrap(err, "failed to get host IP addresses")) + } + + // Configure and create new certificate + tml := x509.Certificate{ + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(years, 0, 0), + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: fmt.Sprintf("%s:%s:%s", OrganizationName, CRIName, hostName), + Organization: []string{OrganizationName}, + }, + BasicConstraintsValid: true, + } + for _, addr := range addrs { + var ip net.IP + + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + default: + continue + } + + tml.IPAddresses = append(tml.IPAddresses, ip) + tml.DNSNames = append(tml.DNSNames, ip.String()) + } + + cert, err := x509.CreateCertificate(rand.Reader, &tml, &tml, &privKey.PublicKey, privKey) + if err != nil { + return fail(errors.Wrap(err, "certificate cannot be created")) + } + + // Generate a pem block with the certificate + certPem := pem.EncodeToMemory(&pem.Block{ + Type: k8scert.CertificateBlockType, + Bytes: cert, + }) + + // Load the tls certificate + tlsCert, err := tls.X509KeyPair(certPem, keyPem) + if err != nil { + return fail(errors.Wrap(err, "certificate could not be loaded")) + } + + return tlsCert, nil +}