First part of the changes for SSLKEYR (#328)
* Squashed all commits * Addressed review comments
This commit is contained in:
committed by
GitHub Enterprise
parent
336d542ff1
commit
a824b75bfa
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2021
|
© Copyright IBM Corporation 2019, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -76,18 +76,20 @@ type TLSStore struct {
|
|||||||
Truststore KeyStoreData
|
Truststore KeyStoreData
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool) (string, KeyStoreData, KeyStoreData, error) {
|
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool, nativeTLSHA bool) (string, KeyStoreData, KeyStoreData, error) {
|
||||||
|
var keyLabel string
|
||||||
// Create the CMS Keystore & PKCS#12 Truststore (if required)
|
// Create the CMS Keystore & PKCS#12 Truststore (if required)
|
||||||
tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired)
|
tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired, nativeTLSHA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all keys - add them to the CMS KeyStore
|
if tlsStore.Keystore.Keystore != nil {
|
||||||
keyLabel, err := processKeys(&tlsStore, keystoreDir, keyDir)
|
// Process all keys - add them to the CMS KeyStore
|
||||||
if err != nil {
|
keyLabel, err = processKeys(&tlsStore, keystoreDir, keyDir)
|
||||||
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
if err != nil {
|
||||||
|
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore (if required)
|
// Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore (if required)
|
||||||
@@ -101,13 +103,13 @@ func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRe
|
|||||||
|
|
||||||
// ConfigureDefaultTLSKeystores configures the CMS Keystore & PKCS#12 Truststore
|
// ConfigureDefaultTLSKeystores configures the CMS Keystore & PKCS#12 Truststore
|
||||||
func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
|
func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
|
||||||
return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true)
|
return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureHATLSKeystore configures the CMS Keystore & PKCS#12 Truststore
|
// ConfigureHATLSKeystore configures the CMS Keystore & PKCS#12 Truststore
|
||||||
func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) {
|
func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) {
|
||||||
// *.crt files mounted to the HA TLS dir keyDirHA will be processed as trusted in the CMS keystore
|
// *.crt files mounted to the HA TLS dir keyDirHA will be processed as trusted in the CMS keystore
|
||||||
return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false)
|
return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureTLS configures TLS for the queue manager
|
// ConfigureTLS configures TLS for the queue manager
|
||||||
@@ -115,9 +117,18 @@ func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log *
|
|||||||
|
|
||||||
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
||||||
const mqscTemplate string = mqsc + ".tpl"
|
const mqscTemplate string = mqsc + ".tpl"
|
||||||
|
sslKeyRing := ""
|
||||||
|
|
||||||
|
// Don't set SSLKEYR if no keys or crts are not supplied
|
||||||
|
// Key label will be blank if no certs were added during processing keys and certs.
|
||||||
|
if cmsKeystore.Keystore != nil {
|
||||||
|
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
|
||||||
|
if len(certList) > 0 {
|
||||||
|
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
|
||||||
|
}
|
||||||
|
}
|
||||||
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
||||||
"SSLKeyR": strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"),
|
"SSLKeyR": sslKeyRing,
|
||||||
"CertificateLabel": keyLabel,
|
"CertificateLabel": keyLabel,
|
||||||
}, log)
|
}, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,7 +170,7 @@ func configureTLSDev(log *logger.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore (if required)
|
// generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore (if required)
|
||||||
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSStore, error) {
|
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool, nativeTLSHA bool) (TLSStore, error) {
|
||||||
|
|
||||||
var cmsKeystore, p12Truststore KeyStoreData
|
var cmsKeystore, p12Truststore KeyStoreData
|
||||||
|
|
||||||
@@ -175,11 +186,19 @@ func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSSt
|
|||||||
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err)
|
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the CMS Keystore
|
// Search the default keys directory for any keys/certs.
|
||||||
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
|
keysDirectory := keyDirDefault
|
||||||
err = cmsKeystore.Keystore.Create()
|
// Change to default native HA TLS directory if we are configuring nativeHA
|
||||||
if err != nil {
|
if nativeTLSHA {
|
||||||
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
|
keysDirectory = keyDirHA
|
||||||
|
}
|
||||||
|
// Create the CMS Keystore if we have been provided keys and certificates
|
||||||
|
if haveKeysAndCerts(keysDirectory) || haveKeysAndCerts(trustDirDefault) {
|
||||||
|
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
|
||||||
|
err = cmsKeystore.Keystore.Create()
|
||||||
|
if err != nil {
|
||||||
|
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the PKCS#12 Truststore (if required)
|
// Create the PKCS#12 Truststore (if required)
|
||||||
@@ -203,7 +222,6 @@ func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string,
|
|||||||
// Process all keys
|
// Process all keys
|
||||||
keyList, err := ioutil.ReadDir(keyDir)
|
keyList, err := ioutil.ReadDir(keyDir)
|
||||||
if err == nil && len(keyList) > 0 {
|
if err == nil && len(keyList) > 0 {
|
||||||
|
|
||||||
// Process each set of keys - each set should contain files: *.key & *.crt
|
// Process each set of keys - each set should contain files: *.key & *.crt
|
||||||
for _, keySet := range keyList {
|
for _, keySet := range keyList {
|
||||||
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, keySet.Name()))
|
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, keySet.Name()))
|
||||||
@@ -602,3 +620,23 @@ func writeCertificatesToFile(file string, certificates []*pem.Block) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search the specified directory for .key and .crt files.
|
||||||
|
// Return true if at least one .key or .crt file is found else false
|
||||||
|
func haveKeysAndCerts(keyDir string) bool {
|
||||||
|
fileList, err := os.ReadDir(keyDir)
|
||||||
|
if err == nil && len(fileList) > 0 {
|
||||||
|
for _, fileInfo := range fileList {
|
||||||
|
// Keys and certs will be supplied in an user defined subdirectory.
|
||||||
|
// Do a listing of the subdirectory and then search for .key and .cert files
|
||||||
|
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
|
||||||
|
for _, key := range keys {
|
||||||
|
if strings.Contains(key.Name(), ".key") || strings.Contains(key.Name(), ".crt") {
|
||||||
|
// We found at least one key/crt file.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
|
|||||||
// Check if a new self-signed certificate should be generated
|
// Check if a new self-signed certificate should be generated
|
||||||
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
|
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
|
||||||
if genHostName != "" {
|
if genHostName != "" {
|
||||||
|
|
||||||
// Create the Web Keystore
|
// Create the Web Keystore
|
||||||
newWebKeystore := keystore.NewPKCS12KeyStore(webKeystoreFile, p12Truststore.Password)
|
newWebKeystore := keystore.NewPKCS12KeyStore(webKeystoreFile, p12Truststore.Password)
|
||||||
err := newWebKeystore.Create()
|
err := newWebKeystore.Create()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build mqdev
|
||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -184,3 +185,76 @@ func TestDevConfigDisabled(t *testing.T) {
|
|||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test if SSLKEYR and CERTLABL attributes are not set when key and certificate
|
||||||
|
// are not supplied.
|
||||||
|
func TestSSLKEYRBlank(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=qm1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslkeyROutput := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
if !strings.Contains(sslkeyROutput, "SSLKEYR( )") && !strings.Contains(sslkeyROutput, "CERTLABL( )") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be blank but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if SSLKEYR and CERTLABL attributes are set when key and certificate
|
||||||
|
// are supplied.
|
||||||
|
func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") && !strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user