Add option to start https listener 02/85002/1
authorKiran Kamineni <kiran.k.kamineni@intel.com>
Thu, 11 Apr 2019 04:53:45 +0000 (21:53 -0700)
committerKiran Kamineni <kiran.k.kamineni@intel.com>
Thu, 11 Apr 2019 05:00:55 +0000 (22:00 -0700)
Added support for tls connection for k8splugin.
It will load the certificates from its current folder.
Any installer needs to just put these files in the same
folder as the executable and it will pick them up and start
in https mode.

Issue-ID: MULTICLOUD-570
Change-Id: I505135daa3933b76023c941e7bee54be65fa791f
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
src/k8splugin/cmd/main.go
src/k8splugin/go.mod
src/k8splugin/internal/auth/auth.go [new file with mode: 0644]
src/k8splugin/internal/auth/auth_test.go [new file with mode: 0644]
src/k8splugin/mock_files/mock_certs/auth_test_certificate.pem [new file with mode: 0644]
src/k8splugin/mock_files/mock_certs/auth_test_key.pem [new file with mode: 0644]

index e600c0d..53b6ab1 100644 (file)
@@ -24,6 +24,7 @@ import (
 
        "k8splugin/api"
        utils "k8splugin/internal"
+       "k8splugin/internal/auth"
 
        "github.com/gorilla/handlers"
 )
@@ -55,5 +56,13 @@ func main() {
                close(connectionsClose)
        }()
 
-       log.Fatal(httpServer.ListenAndServe())
+       tlsConfig, err := auth.GetTLSConfig("ca.cert", "server.cert", "server.key")
+       if err != nil {
+               log.Println("Error Getting TLS Configuration. Starting without TLS...")
+               log.Fatal(httpServer.ListenAndServe())
+       } else {
+               httpServer.TLSConfig = tlsConfig
+               // empty strings because tlsconfig already has this information
+               err = httpServer.ListenAndServeTLS("", "")
+       }
 }
index 29a10ec..531615a 100644 (file)
@@ -67,6 +67,7 @@ require (
        github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
        github.com/xdg/stringprep v1.0.0 // indirect
        go.mongodb.org/mongo-driver v1.0.0
+       golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
        golang.org/x/net v0.0.0-20181201002055-351d144fa1fc
        golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 // indirect
        golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
@@ -75,7 +76,7 @@ require (
        gopkg.in/square/go-jose.v2 v2.2.2 // indirect
        gopkg.in/yaml.v2 v2.2.1
        k8s.io/api v0.0.0-20181126151915-b503174bad59
-       k8s.io/apiextensions-apiserver v0.0.0-20181126155829-0cd23ebeb688 // indirect
+       k8s.io/apiextensions-apiserver v0.0.0-20181126155829-0cd23ebeb688
        k8s.io/apimachinery v0.0.0-20181126123746-eddba98df674
        k8s.io/apiserver v0.0.0-20181126153457-92fdef3a232a // indirect
        k8s.io/cli-runtime v0.0.0-20190107235426-31214e12222d // indirect
diff --git a/src/k8splugin/internal/auth/auth.go b/src/k8splugin/internal/auth/auth.go
new file mode 100644 (file)
index 0000000..3da8f2a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package auth
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "encoding/base64"
+       "encoding/pem"
+       "io/ioutil"
+       "log"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+// GetTLSConfig initializes a tlsConfig using the CA's certificate
+// This config is then used to enable the server for mutual TLS
+func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) {
+
+       // Initialize tlsConfig once
+       caCert, err := ioutil.ReadFile(caCertFile)
+
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read CA Cert file")
+       }
+
+       caCertPool := x509.NewCertPool()
+       caCertPool.AppendCertsFromPEM(caCert)
+
+       tlsConfig := &tls.Config{
+               // Change to RequireAndVerify once we have mandatory certs
+               ClientAuth: tls.VerifyClientCertIfGiven,
+               ClientCAs:  caCertPool,
+               MinVersion: tls.VersionTLS12,
+       }
+
+       certPEMBlk, err := readPEMBlock(certFile)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read Cert File")
+       }
+
+       keyPEMBlk, err := readPEMBlock(keyFile)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read Key File")
+       }
+
+       tlsConfig.Certificates = make([]tls.Certificate, 1)
+       tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Load x509 cert and key")
+       }
+
+       tlsConfig.BuildNameToCertificate()
+       return tlsConfig, nil
+}
+
+func readPEMBlock(filename string) ([]byte, error) {
+
+       pemData, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read PEM File")
+       }
+
+       pemBlock, rest := pem.Decode(pemData)
+       if len(rest) > 0 {
+               log.Println("Pemfile has extra data")
+       }
+
+       if x509.IsEncryptedPEMBlock(pemBlock) {
+               password, err := ioutil.ReadFile(filename + ".pass")
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Read Password File")
+               }
+
+               pByte, err := base64.StdEncoding.DecodeString(string(password))
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Decode PEM Password")
+               }
+
+               pemData, err = x509.DecryptPEMBlock(pemBlock, pByte)
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Decrypt PEM Data")
+               }
+               var newPEMBlock pem.Block
+               newPEMBlock.Type = pemBlock.Type
+               newPEMBlock.Bytes = pemData
+               // Converting back to PEM from DER data you get from
+               // DecryptPEMBlock
+               pemData = pem.EncodeToMemory(&newPEMBlock)
+       }
+
+       return pemData, nil
+}
diff --git a/src/k8splugin/internal/auth/auth_test.go b/src/k8splugin/internal/auth/auth_test.go
new file mode 100644 (file)
index 0000000..49494ee
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+* Copyright 2018 TechMahindra
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+ */
+
+package auth
+
+import (
+       "crypto/tls"
+       "testing"
+)
+
+//Unit test to varify GetTLSconfig func and varify the tls config min version to be 771
+//Assuming cert file name as auth_test.cert
+func TestGetTLSConfig(t *testing.T) {
+       _, err := GetTLSConfig("filedoesnotexist.cert", "filedoesnotexist.cert", "filedoesnotexist.cert")
+       if err == nil {
+               t.Errorf("Test failed, expected error but got none")
+       }
+       tlsConfig, err := GetTLSConfig("../../mock_files/mock_certs/auth_test_certificate.pem",
+               "../../mock_files/mock_certs/auth_test_certificate.pem",
+               "../../mock_files/mock_certs/auth_test_key.pem")
+       if err != nil {
+               t.Fatal("Test Failed as GetTLSConfig returned error: " + err.Error())
+       }
+       expected := tls.VersionTLS12
+       actual := tlsConfig.MinVersion
+       if tlsConfig != nil {
+               if int(actual) != expected {
+                       t.Errorf("Test Failed due to version mismatch")
+               }
+               if tlsConfig == nil {
+                       t.Errorf("Test Failed due to GetTLSConfig returned nil")
+               }
+       }
+}
diff --git a/src/k8splugin/mock_files/mock_certs/auth_test_certificate.pem b/src/k8splugin/mock_files/mock_certs/auth_test_certificate.pem
new file mode 100644 (file)
index 0000000..42e7749
--- /dev/null
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJAKAHJi8eUs73MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTgwNTE1MDQ0MDQwWhcNMTkwNTE1MDQ0MDQwWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA5PHDk+RRFh5o3Xe2nZuLn0Vo+5BjnHp/ul2NNYSG00Slc8F86gW4xcNA
+wm6xC8tYCSangV2lFG3E8H2L7SCEVaM5VDV2GCOpOoMihc+2Qenk/YbHwuYenwjo
+OgTK4aCItqjcAJ2DB1KC7AxARxHBDu9Kif+M/pc49so+G9ObQuS8k2vmTTaRYkMK
+ZvbTJcWsc0vbNnPhxcG5PVj4unlaREM+yQDm18/glUkkBNnYKMHABRvPnBrDktTT
+BQWsqkbQTw7ZuLOrl9rCzVTstZX9wEXarrstIdQJj3KZjbFOp2opND8bjNIjcdVt
+iRFnP1nHQYr7EgRqcx/YMJZ+gmCy3wIDAQABo1AwTjAdBgNVHQ4EFgQU9qPNwwIu
+kZh41sJqFtnMC2blSYMwHwYDVR0jBBgwFoAU9qPNwwIukZh41sJqFtnMC2blSYMw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA4+daLY1wE10IMPaOKurG
+QBvfYeO/rgNXGeg0TisTIKAfx/We9Hmwo/37Bd2Nk5gxfy/DIJ4lMbrzXjgWITlm
+XOrS5QfluwvaEcREtHFtPFa3NZqn2VzKNDFTR+rJj7I5o600NKdcPrGeQ1i/vny2
+K0g68ogw2jfufcuePvZTYGst8RclomPr7ZXxI24kIjcE1MbiViy68sQueTXBEr5s
+Th6RsvPfVnLxjR/m/V6VJl31nn4T6hbmKzXCHo/X7aC3I8Isui4bQGKgfAxyBkhE
+0T7tP+GgymiEKQ6qJ/1c4HFFSuFRUQjLnK7uJu9jM/HMKoLCPayx6birHZRIMF94
+pg==
+-----END CERTIFICATE-----
diff --git a/src/k8splugin/mock_files/mock_certs/auth_test_key.pem b/src/k8splugin/mock_files/mock_certs/auth_test_key.pem
new file mode 100644 (file)
index 0000000..5f01f57
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDk8cOT5FEWHmjd
+d7adm4ufRWj7kGOcen+6XY01hIbTRKVzwXzqBbjFw0DCbrELy1gJJqeBXaUUbcTw
+fYvtIIRVozlUNXYYI6k6gyKFz7ZB6eT9hsfC5h6fCOg6BMrhoIi2qNwAnYMHUoLs
+DEBHEcEO70qJ/4z+lzj2yj4b05tC5LyTa+ZNNpFiQwpm9tMlxaxzS9s2c+HFwbk9
+WPi6eVpEQz7JAObXz+CVSSQE2dgowcAFG8+cGsOS1NMFBayqRtBPDtm4s6uX2sLN
+VOy1lf3ARdquuy0h1AmPcpmNsU6naik0PxuM0iNx1W2JEWc/WcdBivsSBGpzH9gw
+ln6CYLLfAgMBAAECggEAYB3H2D0QddLKf8AUoNJ+qZ1AV+zkhPtAyIMiF4fN+sBl
+HdXrlWxViGFSvM4v8h2qlhzuUfd4qLz042ox5pmyNSnTlbDkJXpDP9dyFO+BOubx
+Ribhksd9r5LTvBfq/RKikt0NkAyQx/AyGtuB2NRxUs3PY2QwU2o1dhauQIx0MH5/
+6D8PgQf6+5njKQaKa4e8Kp4kB+KjnALvt6JgYuNJUHWap+nnDbuuVy5dl1bKkAZ+
+qa7CITKWO4kE2EqaCb2asFc2w3538+w72UJZtwQCmOaxtKpRSl9fQXu54N8jIGoZ
+1FvEj5x3X6QkglE+iVJYaX3RmiJ3uzZ2LICDr89vEQKBgQD7fquIw4p1idSxz3Cm
+5o3Y5kD0CKm61ZaRJWKd+tNlSsxubmV9HROYW6vj2xEPSDvyp1na00pDXxMJQLLc
+O5Awd1SaU+d45jnoi70fsEY8X0WH1rDTYfnU+zQBmpbGqX5qTIfpy4yoADiUD1CQ
+EBdaSBWiKPx2jFSct58TwDP9YwKBgQDpC64TScZYz7uQq4gAbDso/7TjNwgt/Bw8
+JgLSdx1UdUclh81smTujsouyCFwJSvRjKik8e/Qt0f5patukFbFRINxUGUDhOKbA
+7zqeNQbeYaP7Rvw+3z01CU2BTBmB/EWa2xWDam8B9xQvjiHSOrubqkt3sIQJb045
+hzuigdV7VQKBgQD7Gnd0nyCwyMSIIMGuswYv6X4y6i9lr3qdQ4GakOTe/vbsz+cf
+K5f0CJuwbnszEgFg/zzVIx/D8rqUA3hSMlp+ObdMO7gi22Q4TsWvTRZjkxBeV7rH
+48xJneNIMqyWgIcK5YzSn3y6BTZ4hm3+2UInz09iUJ/6UZTtwNzhIIgIVwKBgQCT
+LxRHDE4gIzrT+PHRSonmr/DfnA8nc9WlS2B26lH02IkRs/5Su0iGb6p4y3zNRbCp
+vKQElki2c60ZiSqlLCosEfP1jWmDlRMEQVMlPlpTMxmtBr0jPDzc9T4lDhoCFYEk
+d3/T2vG3LQRrsHm92+hHPTuioTIS/2BJRxar4RIibQKBgQC8zoayoQ7zfEYxy3Ax
+OSao8g85hj0EAJk/VKQP2POgz6KoPay3JE9D7P7OvkebTyv/pijAuTPby4XipCNI
+K0JbFC2Kn7RW/ZV23UdnoO9crh2omOh+/52prStWXKoc+/pJe70Af+4rU7FUiI7F
+y1mIE9krIoVis6iYsyFEmkP7iw==
+-----END PRIVATE KEY-----