Check certificate thumbprint when configured
This commit is contained in:
parent
9deaba0aa0
commit
ed4d445352
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package vclib
|
package vclib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
@ -24,6 +25,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
neturl "net/url"
|
neturl "net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/vmware/govmomi/session"
|
"github.com/vmware/govmomi/session"
|
||||||
@ -169,6 +171,13 @@ func (connection *VSphereConnection) NewClient(ctx context.Context) (*vim25.Clie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpHost := connection.Hostname + ":" + connection.Port
|
||||||
|
tp, err := normalizeThumbprint(connection.Thumbprint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sc.SetThumbprint(tpHost, tp)
|
||||||
|
|
||||||
client, err := vim25.NewClient(ctx, sc)
|
client, err := vim25.NewClient(ctx, sc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to create new client. err: %+v", err)
|
glog.Errorf("Failed to create new client. err: %+v", err)
|
||||||
@ -201,3 +210,25 @@ func (connection *VSphereConnection) UpdateCredentials(username string, password
|
|||||||
connection.Username = username
|
connection.Username = username
|
||||||
connection.Password = password
|
connection.Password = password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func normalizeThumbprint(original string) (string, error) {
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
outIdx := 0
|
||||||
|
|
||||||
|
for _, r := range original {
|
||||||
|
if outIdx%2 == 0 && outIdx > 0 {
|
||||||
|
if _, err := buffer.WriteRune(':'); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r == ':' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := buffer.WriteRune(unicode.ToUpper(r)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
outIdx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
|
@ -18,20 +18,29 @@ package vclib_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha1"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib/fixtures"
|
"k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vclib/fixtures"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createTestServer(t *testing.T, caCertPath, serverCertPath, serverKeyPath string, handler http.HandlerFunc) *httptest.Server {
|
func createTestServer(
|
||||||
|
t *testing.T,
|
||||||
|
caCertPath string,
|
||||||
|
serverCertPath string,
|
||||||
|
serverKeyPath string,
|
||||||
|
handler http.HandlerFunc,
|
||||||
|
) (*httptest.Server, string) {
|
||||||
caCertPEM, err := ioutil.ReadFile(caCertPath)
|
caCertPEM, err := ioutil.ReadFile(caCertPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Could not read ca cert from file")
|
t.Fatalf("Could not read ca cert from file")
|
||||||
@ -55,18 +64,18 @@ func createTestServer(t *testing.T, caCertPath, serverCertPath, serverKeyPath st
|
|||||||
RootCAs: certPool,
|
RootCAs: certPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// // calculate the leaf certificate's fingerprint
|
// calculate the leaf certificate's fingerprint
|
||||||
// x509LeafCert := server.TLS.Certificates[0].Certificate[0]
|
x509LeafCert := server.TLS.Certificates[0].Certificate[0]
|
||||||
// tpBytes := sha1.Sum(x509LeafCert)
|
tpBytes := sha1.Sum(x509LeafCert)
|
||||||
// tpString := fmt.Sprintf("%x", tpBytes)
|
tpString := fmt.Sprintf("%x", tpBytes)
|
||||||
|
|
||||||
return server
|
return server, tpString
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithValidCaCert(t *testing.T) {
|
func TestWithValidCaCert(t *testing.T) {
|
||||||
handler, verify := getRequestVerifier(t)
|
handler, verifyConnectionWasMade := getRequestVerifier(t)
|
||||||
|
|
||||||
server := createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
server, _ := createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
||||||
server.StartTLS()
|
server.StartTLS()
|
||||||
u := mustParseUrl(t, server.URL)
|
u := mustParseUrl(t, server.URL)
|
||||||
|
|
||||||
@ -79,27 +88,88 @@ func TestWithValidCaCert(t *testing.T) {
|
|||||||
// Ignoring error here, because we only care about the TLS connection
|
// Ignoring error here, because we only care about the TLS connection
|
||||||
connection.NewClient(context.Background())
|
connection.NewClient(context.Background())
|
||||||
|
|
||||||
verify()
|
verifyConnectionWasMade()
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestWithValidThumbprint(t *testing.T) {
|
func TestWithVerificationWithWrongThumbprint(t *testing.T) {
|
||||||
// handler, verify := getRequestVerifier(t)
|
handler, _ := getRequestVerifier(t)
|
||||||
//
|
|
||||||
// server, serverThumbprint := createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
server, _ := createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
||||||
// server.StartTLS()
|
server.StartTLS()
|
||||||
// u := mustParseUrl(t, server.URL)
|
u := mustParseUrl(t, server.URL)
|
||||||
//
|
|
||||||
// connection := &vclib.VSphereConnection{
|
connection := &vclib.VSphereConnection{
|
||||||
// Hostname: u.Hostname(),
|
Hostname: u.Hostname(),
|
||||||
// Port: u.Port(),
|
Port: u.Port(),
|
||||||
// Thumbprint: serverThumbprint,
|
Thumbprint: "obviously wrong",
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // Ignoring error here, because we only care about the TLS connection
|
_, err := connection.NewClient(context.Background())
|
||||||
// connection.NewClient(context.Background())
|
|
||||||
//
|
if msg := err.Error(); !strings.Contains(msg, "thumbprint does not match") {
|
||||||
// verify()
|
t.Fatalf("Expected wrong thumbprint error, got '%s'", msg)
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithVerificationWithoutCaCertOrThumbprint(t *testing.T) {
|
||||||
|
handler, _ := getRequestVerifier(t)
|
||||||
|
|
||||||
|
server, _ := createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
||||||
|
server.StartTLS()
|
||||||
|
u := mustParseUrl(t, server.URL)
|
||||||
|
|
||||||
|
connection := &vclib.VSphereConnection{
|
||||||
|
Hostname: u.Hostname(),
|
||||||
|
Port: u.Port(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := connection.NewClient(context.Background())
|
||||||
|
|
||||||
|
verifyWrappedX509UnkownAuthorityErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithValidThumbprint(t *testing.T) {
|
||||||
|
handler, verifyConnectionWasMade := getRequestVerifier(t)
|
||||||
|
|
||||||
|
server, thumbprint :=
|
||||||
|
createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
||||||
|
server.StartTLS()
|
||||||
|
u := mustParseUrl(t, server.URL)
|
||||||
|
|
||||||
|
connection := &vclib.VSphereConnection{
|
||||||
|
Hostname: u.Hostname(),
|
||||||
|
Port: u.Port(),
|
||||||
|
Thumbprint: thumbprint,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignoring error here, because we only care about the TLS connection
|
||||||
|
connection.NewClient(context.Background())
|
||||||
|
|
||||||
|
verifyConnectionWasMade()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithValidThumbprintAlternativeFormat(t *testing.T) {
|
||||||
|
handler, verifyConnectionWasMade := getRequestVerifier(t)
|
||||||
|
|
||||||
|
server, thumbprint :=
|
||||||
|
createTestServer(t, fixtures.CaCertPath, fixtures.ServerCertPath, fixtures.ServerKeyPath, handler)
|
||||||
|
server.StartTLS()
|
||||||
|
u := mustParseUrl(t, server.URL)
|
||||||
|
|
||||||
|
// lowercase, remove the ':'
|
||||||
|
tpDifferentFormat := strings.Replace(strings.ToLower(thumbprint), ":", "", -1)
|
||||||
|
|
||||||
|
connection := &vclib.VSphereConnection{
|
||||||
|
Hostname: u.Hostname(),
|
||||||
|
Port: u.Port(),
|
||||||
|
Thumbprint: tpDifferentFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignoring error here, because we only care about the TLS connection
|
||||||
|
connection.NewClient(context.Background())
|
||||||
|
|
||||||
|
verifyConnectionWasMade()
|
||||||
|
}
|
||||||
|
|
||||||
func TestWithInvalidCaCertPath(t *testing.T) {
|
func TestWithInvalidCaCertPath(t *testing.T) {
|
||||||
connection := &vclib.VSphereConnection{
|
connection := &vclib.VSphereConnection{
|
||||||
@ -130,6 +200,20 @@ func TestInvalidCaCert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifyWrappedX509UnkownAuthorityErr(t *testing.T, err error) {
|
||||||
|
urlErr, ok := err.(*url.Error)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Expected to receive an url.Error, got '%s' (%#v)", err.Error(), err)
|
||||||
|
}
|
||||||
|
x509Err, ok := urlErr.Err.(x509.UnknownAuthorityError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Expected to receive a wrapped x509.UnknownAuthorityError, got: '%s' (%#v)", urlErr.Error(), urlErr)
|
||||||
|
}
|
||||||
|
if msg := x509Err.Error(); msg != "x509: certificate signed by unknown authority" {
|
||||||
|
t.Fatalf("Expected 'signed by unknown authority' error, got: '%s'", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getRequestVerifier(t *testing.T) (http.HandlerFunc, func()) {
|
func getRequestVerifier(t *testing.T) (http.HandlerFunc, func()) {
|
||||||
gotRequest := false
|
gotRequest := false
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user