Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functional tests for HSM Support #190

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions tests/functional/barbican_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"

barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1"
controllers "github.com/openstack-k8s-operators/barbican-operator/controllers"
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbican"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers"
Expand Down Expand Up @@ -431,6 +432,185 @@ var _ = Describe("Barbican controller", func() {
})
})

When("A Barbican with HSM is created", func() {
BeforeEach(func() {
DeferCleanup(k8sClient.Delete, ctx, CreateHSMLoginSecret(barbicanTest.Instance.Namespace, HSMLoginSecret))
DeferCleanup(k8sClient.Delete, ctx, CreateHSMCertsSecret(barbicanTest.Instance.Namespace, HSMCertsSecret))

DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, GetHSMBarbicanSpec()))
DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanTest.Instance.Namespace, barbicanTest.RabbitmqSecretName))
infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL)
DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(barbicanTest.Instance.Namespace, SecretName))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
barbicanTest.Instance.Namespace,
GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
mariadb.SimulateMariaDBAccountCompleted(barbicanTest.BarbicanDatabaseAccount)
mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.BarbicanDatabaseName)
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace))
th.SimulateJobSuccess(barbicanTest.BarbicanDBSync)
DeferCleanup(th.DeleteInstance, CreateBarbicanAPI(barbicanTest.Instance, GetHSMBarbicanAPISpec()))
th.SimulateJobSuccess(barbicanTest.BarbicanP11Prep)
})

It("Creates BarbicanAPI", func() {
keystone.SimulateKeystoneEndpointReady(barbicanTest.BarbicanKeystoneEndpoint)

th.ExpectCondition(
barbicanTest.Instance,
ConditionGetterFunc(BarbicanAPIConditionGetter),
condition.TLSInputReadyCondition,
corev1.ConditionTrue,
)

BarbicanAPIExists(barbicanTest.Instance)

d := th.GetDeployment(barbicanTest.BarbicanAPI)
// Check the resulting deployment fields
Expect(int(*d.Spec.Replicas)).To(Equal(1))

Expect(d.Spec.Template.Spec.Volumes).To(HaveLen(4))
mauricioharley marked this conversation as resolved.
Show resolved Hide resolved
Expect(d.Spec.Template.Spec.Containers).To(HaveLen(2))

container := d.Spec.Template.Spec.Containers[1]

Expect(container.ReadinessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTP))
Expect(container.LivenessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTP))

// Checking the HSM container
Expect(container.Name).To(Equal(barbican.ComponentAPI))
foundMount := false
indexMount := 0
for index, volumeMount := range container.VolumeMounts {
if volumeMount.Name == barbican.LunaVolume {
foundMount = true
indexMount = index
break
}
}
Expect(foundMount).To(BeTrue())
Expect(container.VolumeMounts[indexMount].MountPath).To(Equal(HSMCertificatesMountPoint))
})

It("Verifies the PKCS11 struct is in good shape", func() {
Barbican := GetBarbican(barbicanTest.Instance)
Expect(Barbican.Spec.EnabledSecretStores).Should(Equal([]barbicanv1beta1.SecretStore{"pkcs11"}))
Expect(Barbican.Spec.GlobalDefaultSecretStore).Should(Equal(barbicanv1beta1.SecretStore("pkcs11")))

pkcs11 := Barbican.Spec.PKCS11
Expect(pkcs11.SlotId).Should(Equal(HSMSlotID))
Expect(pkcs11.LibraryPath).Should(Equal(HSMLibraryPath))
Expect(pkcs11.CertificatesMountPoint).Should(Equal(HSMCertificatesMountPoint))
Expect(pkcs11.LoginSecret).Should(Equal(HSMLoginSecret))
Expect(pkcs11.CertificatesSecret).Should(Equal(HSMCertsSecret))
Expect(pkcs11.MKEKLabel).Should(Equal(HSMMKEKLabel))
Expect(pkcs11.HMACLabel).Should(Equal(HSMHMACLabel))
Expect(pkcs11.ServerAddress).Should(Equal(HSMServerAddress))
Expect(pkcs11.ClientAddress).Should(Equal(HSMClientAddress))
Expect(pkcs11.Type).Should(Equal(HSMType))
})

It("Checks if the two relevant secrets have the right contents", func() {
hsmSecret := th.GetSecret(barbicanTest.BarbicanHSMLoginSecret)
Expect(hsmSecret).ShouldNot(BeNil())
confHSM := hsmSecret.Data["hsmLogin"]
Expect(confHSM).To(
ContainSubstring("12345678"))

certsSecret := th.GetSecret(barbicanTest.BarbicanHSMCertsSecret)
Expect(certsSecret).ShouldNot(BeNil())
confCA := certsSecret.Data["CACert.pem"]
Expect(confCA).To(
ContainSubstring("dummy-data"))
confServer := certsSecret.Data[HSMServerAddress+"Server.pem"]
Expect(confServer).To(
ContainSubstring("dummy-data"))

confClient := certsSecret.Data[HSMClientAddress+"Client.pem"]
Expect(confClient).To(
ContainSubstring("dummy-data"))
confKey := certsSecret.Data[HSMClientAddress+"Client.key"]
Expect(confKey).To(
ContainSubstring("dummy-data"))
})

It("Verifies if 00-default.conf, barbican-api-config.json and Chrystoki.conf have the right contents.", func() {
confSecret := th.GetSecret(barbicanTest.BarbicanConfigSecret)
Expect(confSecret).ShouldNot(BeNil())

conf := confSecret.Data["Chrystoki.conf"]
Expect(conf).To(
ContainSubstring("Chrystoki2"))
Expect(conf).To(
ContainSubstring("LunaSA Client"))
Expect(conf).To(
ContainSubstring("ProtectedAuthenticationPathFlagStatus = 0"))
mauricioharley marked this conversation as resolved.
Show resolved Hide resolved
Expect(conf).To(
ContainSubstring("ClientPrivKeyFile = " + HSMCertificatesMountPoint + "/" + HSMClientAddress + "Key.pem"))
Expect(conf).To(
ContainSubstring("ClientCertFile = " + HSMCertificatesMountPoint + "/" + HSMClientAddress + ".pem"))
Expect(conf).To(
ContainSubstring("ServerCAFile = " + HSMCertificatesMountPoint + "/CACert.pem"))

conf = confSecret.Data["00-default.conf"]
Expect(conf).To(
ContainSubstring("[secretstore:pkcs11]"))
Expect(conf).To(
ContainSubstring("plugin_name = PKCS11"))
Expect(conf).To(
ContainSubstring("slot_id = " + HSMSlotID))

conf = confSecret.Data["barbican-api-config.json"]
Expect(conf).To(
ContainSubstring("/var/lib/config-data/default/Chrystoki.conf"))
Expect(conf).To(
ContainSubstring("/usr/local/luna/Chrystoki.conf"))
})

It("Checks if the P11PreJob successfully executed", func() {
BarbicanExists(barbicanTest.Instance)

th.ExpectCondition(
barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
controllers.P11PrepReadyCondition,
corev1.ConditionTrue,
)

// Checking if both, the volume mount name and its mount path match the specified values.
var elemLuna, elemScript = 0, 0
for index, mount := range th.GetJob(barbicanTest.BarbicanP11Prep).Spec.Template.Spec.Containers[0].VolumeMounts {
if mount.Name == barbican.LunaVolume {
elemLuna = index
} else if mount.Name == barbican.ScriptVolume {
elemScript = index
}
}

volume := th.GetJob(barbicanTest.BarbicanP11Prep).Spec.Template.Spec.Containers[0].VolumeMounts[elemLuna].Name
mountPath := th.GetJob(barbicanTest.BarbicanP11Prep).Spec.Template.Spec.Containers[0].VolumeMounts[elemLuna].MountPath

Eventually(func(g Gomega) {
g.Expect(volume).To(Equal(barbican.LunaVolume))
g.Expect(mountPath).To(Equal(HSMCertificatesMountPoint))
}, timeout, interval).Should(Succeed())
mauricioharley marked this conversation as resolved.
Show resolved Hide resolved

volume = th.GetJob(barbicanTest.BarbicanP11Prep).Spec.Template.Spec.Containers[0].VolumeMounts[elemScript].Name
mountPath = th.GetJob(barbicanTest.BarbicanP11Prep).Spec.Template.Spec.Containers[0].VolumeMounts[elemScript].MountPath

Eventually(func(g Gomega) {
g.Expect(volume).To(Equal(barbican.ScriptVolume))
g.Expect(mountPath).To(Equal(P11PrepMountPoint))
}, timeout, interval).Should(Succeed())
})
})

// Run MariaDBAccount suite tests. these are pre-packaged ginkgo tests
// that exercise standard account create / update patterns that should be
// common to all controllers that ensure MariaDBAccount CRs.
Expand Down
17 changes: 17 additions & 0 deletions tests/functional/barbican_test_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type BarbicanTestData struct {
BarbicanDatabaseName types.NamespacedName
BarbicanDatabaseAccount types.NamespacedName
BarbicanDBSync types.NamespacedName
BarbicanP11Prep types.NamespacedName
BarbicanAPI types.NamespacedName
BarbicanRole types.NamespacedName
BarbicanRoleBinding types.NamespacedName
Expand All @@ -65,6 +66,8 @@ type BarbicanTestData struct {
BarbicanServiceInternal types.NamespacedName
BarbicanConfigSecret types.NamespacedName
BarbicanAPIConfigSecret types.NamespacedName
BarbicanHSMLoginSecret types.NamespacedName
BarbicanHSMCertsSecret types.NamespacedName
BarbicanConfigScripts types.NamespacedName
BarbicanConfigMapData types.NamespacedName
BarbicanScheduler types.NamespacedName
Expand Down Expand Up @@ -97,6 +100,10 @@ func GetBarbicanTestData(barbicanName types.NamespacedName) BarbicanTestData {
Namespace: barbicanName.Namespace,
Name: fmt.Sprintf("%s-db-sync", barbicanName.Name),
},
BarbicanP11Prep: types.NamespacedName{
Namespace: barbicanName.Namespace,
Name: fmt.Sprintf("%s-p11-prep", barbicanName.Name),
},
BarbicanAPI: types.NamespacedName{
Namespace: barbicanName.Namespace,
Name: fmt.Sprintf("%s-api-api", barbicanName.Name),
Expand Down Expand Up @@ -142,6 +149,16 @@ func GetBarbicanTestData(barbicanName types.NamespacedName) BarbicanTestData {
Namespace: barbicanName.Namespace,
Name: fmt.Sprintf("%s-%s", barbicanName.Name, "api-config-data"),
},
// This secret stores the password to connect to the HSM.
BarbicanHSMLoginSecret: types.NamespacedName{
Namespace: barbicanName.Namespace,
Name: "hsm-login",
},
// This secret stores the certificates used to interact with the HSM.
BarbicanHSMCertsSecret: types.NamespacedName{
Namespace: barbicanName.Namespace,
Name: "hsm-certs",
},
BarbicanConfigScripts: types.NamespacedName{
Namespace: barbicanName.Namespace,
Name: fmt.Sprintf("%s-%s", barbicanName.Name, "scripts"),
Expand Down
61 changes: 60 additions & 1 deletion tests/functional/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,14 @@ func BarbicanKeystoneListenerNotExists(name types.NamespacedName) {
}, timeout, interval).Should(Succeed())
}

// ========== TLS Stuff ==============
func BarbicanExists(name types.NamespacedName) {
Consistently(func(g Gomega) {
instance := &barbicanv1.Barbican{}
err := k8sClient.Get(ctx, name, instance)
g.Expect(k8s_errors.IsNotFound(err)).To(BeFalse())
}, timeout, interval).Should(Succeed())
}

func BarbicanAPIConditionGetter(name types.NamespacedName) condition.Conditions {
instance := GetBarbicanAPI(name)
return instance.Status.Conditions
Expand All @@ -145,6 +152,7 @@ func GetBarbicanAPI(name types.NamespacedName) *barbicanv1.BarbicanAPI {
return instance
}

// ========== TLS Stuff ==============
func GetTLSBarbicanSpec() map[string]interface{} {
return map[string]interface{}{
"databaseInstance": "openstack",
Expand Down Expand Up @@ -172,6 +180,57 @@ func GetTLSBarbicanAPISpec() map[string]interface{} {
return spec
}

// ========== End of TLS Stuff ============

// ========== HSM Stuff ============
func GetHSMBarbicanSpec() map[string]interface{} {
spec := GetDefaultBarbicanSpec()
maps.Copy(spec, map[string]interface{}{
"enabledSecretStores": []string{"pkcs11"},
"globalDefaultSecretStore": "pkcs11",
"pkcs11": map[string]interface{}{
"slotId": HSMSlotID,
"libraryPath": HSMLibraryPath,
"certificatesMountPoint": HSMCertificatesMountPoint,
"loginSecret": HSMLoginSecret,
"certificatesSecret": HSMCertsSecret,
"MKEKLabel": HSMMKEKLabel,
"HMACLabel": HSMHMACLabel,
"serverAddress": HSMServerAddress,
"clientAddress": HSMClientAddress,
"type": HSMType,
},
})
return spec
}

func GetHSMBarbicanAPISpec() map[string]interface{} {
return GetDefaultBarbicanAPISpec()
}

func CreateHSMLoginSecret(namespace string, name string) *corev1.Secret {
return th.CreateSecret(
types.NamespacedName{Namespace: namespace, Name: name},
map[string][]byte{
"hsmLogin": []byte("12345678"),
},
)
}

func CreateHSMCertsSecret(namespace string, name string) *corev1.Secret {
return th.CreateSecret(
types.NamespacedName{Namespace: namespace, Name: name},
map[string][]byte{
"CACert.pem": []byte("dummy-data"),
HSMServerAddress + "Server.pem": []byte("dummy-data"),
HSMClientAddress + "Client.pem": []byte("dummy-data"),
HSMClientAddress + "Client.key": []byte("dummy-data"),
},
)
}

// ========== End of HSM Stuff ============

func GetDefaultBarbicanAPISpec() map[string]interface{} {
return map[string]interface{}{
"secret": SecretName,
Expand Down
13 changes: 13 additions & 0 deletions tests/functional/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ const (
SecretName = "test-osp-secret"

interval = time.Millisecond * 200

// HSM Constants
HSMType = "luna" // Using them Luna model without any specific selection criteria.
HSMLibraryPath = "/usr/local/luna/libs/64/libCryptoki2.so"
HSMCertificatesMountPoint = "/usr/local/luna/config/certs"
HSMSlotID = "1"
HSMMKEKLabel = "MKEKLabel"
HSMHMACLabel = "HMACLabel"
HSMServerAddress = "192.168.0.1"
HSMClientAddress = "192.168.0.2"
HSMLoginSecret = "hsm-login"
HSMCertsSecret = "hsm-certs"
P11PrepMountPoint = "/usr/local/bin/container-scripts"
)

func TestAPIs(t *testing.T) {
Expand Down
Loading