-
Notifications
You must be signed in to change notification settings - Fork 26
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
Ver 99110 allow users to specify tls certis for https server and client-server authentication #1041
base: main
Are you sure you want to change the base?
Changes from all commits
95c5dcd
80376e1
c2f98ba
16bf1b2
de4f89e
088c72f
59011d9
61c5527
2559379
b815b3c
85f9c01
4ebf883
6fb25a2
e57a360
e766324
130c2e3
6c31664
8f3f7b6
b747bbd
aef11f0
24cd539
31a7e50
707f441
b809533
6c4117f
02ef16b
48076eb
b0d5610
f5dc049
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -284,6 +284,23 @@ type VerticaDBSpec struct { | |
// prefix is the name of the secret in the service you are storing. | ||
NMATLSSecret string `json:"nmaTLSSecret,omitempty"` | ||
|
||
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden" | ||
// +kubebuilder:default:="" | ||
// +kubebuilder:validation:Optional | ||
// A secret that contains the TLS credentials to be used to authenticate Vertica clients' certificates | ||
// (vsql). If this is empty, the operator will create a secret to use and add | ||
// the name of the generate secret to this field. | ||
// When set, the secret must have the following keys defined: tls.key, | ||
// tls.crt and ca.crt. To store this secret outside of Kubernetes, you can | ||
// use a secret path reference prefix, such as gsm://. Everything after the | ||
// prefix is the name of the secret in the service you are storing. | ||
ClientServerTLSSecret string `json:"clientServerTLSSecret,omitempty"` | ||
|
||
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden" | ||
// +kubebuilder:default:=verify_ca | ||
// +kubebuilder:validation:Optional | ||
ClientServerTLSMode string `json:"clientServerTLSMode,omitempty"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Write a description of this field and list all its supported values. The default value should be "try_verify". |
||
|
||
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden" | ||
// +kubebuilder:validation:Optional | ||
// Allows tuning of the Vertica pods readiness probe. Each of the values | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,7 @@ const ( | |
HadoopConfigMountName = "hadoop-conf" | ||
Krb5SecretMountName = "krb5" | ||
SSHMountName = "ssh" | ||
NMACertsMountName = "nma-certs" | ||
NMATLSConfigMapName = "nma-tls-config" | ||
DepotMountName = "depot" | ||
S3Prefix = "s3://" | ||
GCloudPrefix = "gs://" | ||
|
@@ -227,6 +227,7 @@ func (v *VerticaDB) validateVerticaDBSpec() field.ErrorList { | |
allErrs = v.isServiceTypeValid(allErrs) | ||
allErrs = v.hasDuplicateScName(allErrs) | ||
allErrs = v.hasValidVolumeName(allErrs) | ||
allErrs = v.hasValidClientServerTLSMode(allErrs) | ||
allErrs = v.hasValidVolumeMountName(allErrs) | ||
allErrs = v.hasValidKerberosSetup(allErrs) | ||
allErrs = v.hasValidTemporarySubclusterRouting(allErrs) | ||
|
@@ -669,6 +670,26 @@ func (v *VerticaDB) hasDuplicateScName(allErrs field.ErrorList) field.ErrorList | |
return allErrs | ||
} | ||
|
||
func (v *VerticaDB) hasValidClientServerTLSMode(allErrs field.ErrorList) field.ErrorList { | ||
tlsModes := []string{"enable", "disable", "try_verify", "verify_ca", "verify_full"} | ||
if v.Spec.ClientServerTLSMode != "" { | ||
TLSMode := strings.ToLower(v.Spec.ClientServerTLSMode) | ||
validMode := false | ||
for _, mode := range tlsModes { | ||
if mode == TLSMode { | ||
validMode = true | ||
} | ||
} | ||
if !validMode { | ||
err := field.Invalid(field.NewPath("spec").Child("clientservertlssecret"), v.Spec.ClientServerTLSMode, "invalid tls mode") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use camel case for "clientservertlssecret" - "clientSeverTLSSecret" |
||
allErrs = append(allErrs, err) | ||
} | ||
} else { | ||
v.Spec.ClientServerTLSMode = "verify_ca" | ||
} | ||
return allErrs | ||
} | ||
|
||
func (v *VerticaDB) hasValidVolumeName(allErrs field.ErrorList) field.ErrorList { | ||
for i := range v.Spec.Volumes { | ||
vol := v.Spec.Volumes[i] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
kind: Added | ||
body: ClientServerTLSSecret has been added to Vertica DB definition. It contains the TLS credentials to authenticate Vertica clients' certificates (vsql) | ||
time: 2025-02-04T16:14:32.906578043-05:00 | ||
custom: | ||
Issue: "99110" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue number should be "1041" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
kind: Changed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be "Removed". Before NMATLSSecret supported both mount and unmount options, and now NMATLSSecret only supported unmount option, right? |
||
body: NMATLSSecret used to be mounted at /certs/nma in nma container. Now it is not mounted any more. NMA will read certs from the kuberntes secrets. | ||
time: 2025-02-04T16:24:21.090008412-05:00 | ||
custom: | ||
Issue: "99110" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue number should be "1041" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -355,16 +355,10 @@ func buildStartupConfVolumeMount() corev1.VolumeMount { | |
} | ||
} | ||
|
||
func buildScrutinizeVolumeMounts(vscr *v1beta1.VerticaScrutinize, vdb *vapi.VerticaDB) []corev1.VolumeMount { | ||
func buildScrutinizeVolumeMounts(vscr *v1beta1.VerticaScrutinize) []corev1.VolumeMount { | ||
volMnts := []corev1.VolumeMount{ | ||
buildScrutinizeSharedVolumeMount(vscr), | ||
} | ||
|
||
if vmeta.UseNMACertsMount(vdb.Annotations) && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why can't we no longer mount nma certs? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OpenText's new security policy does not allow the certificates to be stored on hard drives. |
||
vdb.Spec.NMATLSSecret != "" && | ||
secrets.IsK8sSecret(vdb.Spec.NMATLSSecret) { | ||
volMnts = append(volMnts, buildNMACertsVolumeMount()...) | ||
} | ||
return volMnts | ||
} | ||
|
||
|
@@ -425,11 +419,6 @@ func buildSSHVolumeMounts() []corev1.VolumeMount { | |
// used with NMA | ||
func buildCommonNMAVolumeMounts(vdb *vapi.VerticaDB) []corev1.VolumeMount { | ||
volMnts := buildScrutinizeVolumeMountForVerticaPod(vdb) | ||
if vmeta.UseNMACertsMount(vdb.Annotations) && | ||
vdb.Spec.NMATLSSecret != "" && | ||
secrets.IsK8sSecret(vdb.Spec.NMATLSSecret) { | ||
volMnts = append(volMnts, buildNMACertsVolumeMount()...) | ||
} | ||
return volMnts | ||
} | ||
|
||
|
@@ -450,15 +439,6 @@ func buildScrutinizeVolumeMountForVerticaPod(vdb *vapi.VerticaDB) []corev1.Volum | |
} | ||
} | ||
|
||
func buildNMACertsVolumeMount() []corev1.VolumeMount { | ||
return []corev1.VolumeMount{ | ||
{ | ||
Name: vapi.NMACertsMountName, | ||
MountPath: paths.NMACertsRoot, | ||
}, | ||
} | ||
} | ||
|
||
// buildCertSecretVolumeMounts returns the volume mounts for any cert secrets that are in the vdb | ||
func buildCertSecretVolumeMounts(vdb *vapi.VerticaDB) []corev1.VolumeMount { | ||
mnts := []corev1.VolumeMount{} | ||
|
@@ -487,12 +467,6 @@ func buildVolumes(vdb *vapi.VerticaDB) []corev1.Volume { | |
if vdb.GetSSHSecretName() != "" { | ||
vols = append(vols, buildSSHVolume(vdb)) | ||
} | ||
if vmeta.UseVClusterOps(vdb.Annotations) && | ||
vmeta.UseNMACertsMount(vdb.Annotations) && | ||
vdb.Spec.NMATLSSecret != "" && | ||
secrets.IsK8sSecret(vdb.Spec.NMATLSSecret) { | ||
vols = append(vols, buildNMACertsSecretVolume(vdb)) | ||
} | ||
if vdb.IsDepotVolumeEmptyDir() { | ||
vols = append(vols, buildDepotVolume()) | ||
} | ||
|
@@ -507,12 +481,6 @@ func buildVolumes(vdb *vapi.VerticaDB) []corev1.Volume { | |
// buildScrutinizeVolumes returns volumes that will be used by the scrutinize pod | ||
func buildScrutinizeVolumes(vscr *v1beta1.VerticaScrutinize, vdb *vapi.VerticaDB) []corev1.Volume { | ||
vols := []corev1.Volume{} | ||
if vmeta.UseVClusterOps(vdb.Annotations) && | ||
vmeta.UseNMACertsMount(vdb.Annotations) && | ||
vdb.Spec.NMATLSSecret != "" && | ||
secrets.IsK8sSecret(vdb.Spec.NMATLSSecret) { | ||
vols = append(vols, buildNMACertsSecretVolume(vdb)) | ||
} | ||
// we add a volume for the password when the password secret | ||
// is on k8s | ||
if vdb.Spec.PasswordSecret != "" && | ||
|
@@ -774,17 +742,6 @@ func buildSSHVolume(vdb *vapi.VerticaDB) corev1.Volume { | |
} | ||
} | ||
|
||
func buildNMACertsSecretVolume(vdb *vapi.VerticaDB) corev1.Volume { | ||
return corev1.Volume{ | ||
Name: vapi.NMACertsMountName, | ||
VolumeSource: corev1.VolumeSource{ | ||
Secret: &corev1.SecretVolumeSource{ | ||
SecretName: vdb.Spec.NMATLSSecret, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// buildEmptyDirVolume returns a generic 'emptyDir' volume | ||
func buildEmptyDirVolume(volName string) corev1.Volume { | ||
return corev1.Volume{ | ||
|
@@ -1112,7 +1069,7 @@ func makeScrutinizeInitContainer(vscr *v1beta1.VerticaScrutinize, vdb *vapi.Vert | |
Image: vdb.Spec.Image, | ||
Name: names.ScrutinizeInitContainer, | ||
Command: buildScrutinizeCmd(args), | ||
VolumeMounts: buildScrutinizeVolumeMounts(vscr, vdb), | ||
VolumeMounts: buildScrutinizeVolumeMounts(vscr), | ||
Resources: vscr.Spec.Resources, | ||
Env: buildCommonEnvVars(vdb), | ||
} | ||
|
@@ -1790,19 +1747,34 @@ func buildScrutinizeDBPasswordEnvVars(nm types.NamespacedName) []corev1.EnvVar { | |
// buildNMATLSCertsEnvVars returns environment variables about NMA certs, | ||
// that are needed by NMA and vcluster scrutinize | ||
func buildNMATLSCertsEnvVars(vdb *vapi.VerticaDB) []corev1.EnvVar { | ||
if vmeta.UseNMACertsMount(vdb.Annotations) && secrets.IsK8sSecret(vdb.Spec.NMATLSSecret) { | ||
return []corev1.EnvVar{ | ||
// Provide the path to each of the certs that are mounted in the container. | ||
{Name: NMARootCAEnv, Value: fmt.Sprintf("%s/%s", paths.NMACertsRoot, paths.HTTPServerCACrtName)}, | ||
{Name: NMACertEnv, Value: fmt.Sprintf("%s/%s", paths.NMACertsRoot, corev1.TLSCertKey)}, | ||
{Name: NMAKeyEnv, Value: fmt.Sprintf("%s/%s", paths.NMACertsRoot, corev1.TLSPrivateKeyKey)}, | ||
} | ||
} | ||
notTrue := false | ||
configMapName := fmt.Sprintf("%s-%s", vdb.Name, vapi.NMATLSConfigMapName) | ||
return []corev1.EnvVar{ | ||
// The NMA will read the secrets directly from the secret store. | ||
// We provide the secret namespace and name for this reason. | ||
{Name: NMASecretNamespaceEnv, Value: vdb.ObjectMeta.Namespace}, | ||
{Name: NMASecretNameEnv, Value: vdb.Spec.NMATLSSecret}, | ||
// {Name: NMASecretNamespaceEnv, Value: vdb.ObjectMeta.Namespace}, | ||
// {Name: NMASecretNameEnv, Value: vdb.Spec.NMATLSSecret}, | ||
|
||
{Name: NMASecretNamespaceEnv, | ||
ValueFrom: &corev1.EnvVarSource{ | ||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||
LocalObjectReference: corev1.LocalObjectReference{ | ||
Name: configMapName, | ||
}, | ||
Key: NMASecretNamespaceEnv, | ||
Optional: ¬True, | ||
}, | ||
}}, | ||
{Name: NMASecretNameEnv, | ||
ValueFrom: &corev1.EnvVarSource{ | ||
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ | ||
LocalObjectReference: corev1.LocalObjectReference{ | ||
Name: configMapName, | ||
}, | ||
Key: NMASecretNameEnv, | ||
Optional: ¬True, | ||
}, | ||
}}, | ||
} | ||
} | ||
|
||
|
@@ -1891,3 +1863,25 @@ func GetTarballName(cmd []string) string { | |
} | ||
return "" | ||
} | ||
|
||
// BuildNMATLSConfigMap builds a configmap with tls secret name it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "with tls secret name in it" |
||
// The configmap will be mapped to two environmental variables in NMA pod | ||
func BuildNMATLSConfigMap(configMapName string, vdb *vapi.VerticaDB) *corev1.ConfigMap { | ||
secretMap := map[string]string{ | ||
NMASecretNamespaceEnv: vdb.ObjectMeta.Namespace, | ||
NMASecretNameEnv: vdb.Spec.NMATLSSecret, | ||
} | ||
tlsConfigMap := &corev1.ConfigMap{ | ||
TypeMeta: metav1.TypeMeta{ | ||
Kind: "ConfigMap", | ||
APIVersion: "v1", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: configMapName, | ||
Namespace: vdb.Namespace, | ||
OwnerReferences: []metav1.OwnerReference{vdb.GenerateOwnerReference()}, | ||
}, | ||
Data: secretMap, | ||
} | ||
return tlsConfigMap | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -555,65 +555,6 @@ var _ = Describe("builder", func() { | |
} | ||
}) | ||
|
||
It("should mount or not mount NMA certs volume based on NMA container", func() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have a test to verify the ENV var are coming from the config map? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we able to add this kind of unit test? |
||
vdb := vapi.MakeVDBForHTTP("v-nma-tls-abcde") | ||
// monolithic container | ||
vdb.Annotations[vmeta.VClusterOpsAnnotation] = vmeta.VClusterOpsAnnotationTrue | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationFalse | ||
ps := buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c := makeServerContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeFalse()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeFalse()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeTrue()) | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationTrue | ||
ps = buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c = makeServerContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeTrue()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeTrue()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeTrue()) | ||
// test default value (which should be true) | ||
delete(vdb.Annotations, vmeta.MountNMACertsAnnotation) | ||
ps = buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c = makeServerContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeTrue()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeTrue()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeTrue()) | ||
}) | ||
|
||
It("should mount or not mount NMA certs volume according to annotation(sidecar)", func() { | ||
vdb := vapi.MakeVDBForHTTP("v-nma-tls-abcde") | ||
|
||
// server container | ||
vdb.Annotations[vmeta.VClusterOpsAnnotation] = vmeta.VClusterOpsAnnotationTrue | ||
vdb.Annotations[vmeta.VersionAnnotation] = vapi.NMAInSideCarDeploymentMinVersion | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationFalse | ||
ps := buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c := makeServerContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeFalse()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeFalse()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeFalse()) | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationTrue | ||
ps = buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c = makeServerContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeTrue()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeFalse()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeFalse()) | ||
|
||
// nma container | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationFalse | ||
ps = buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c = makeNMAContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeFalse()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeFalse()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeTrue()) | ||
vdb.Annotations[vmeta.MountNMACertsAnnotation] = vmeta.MountNMACertsAnnotationTrue | ||
ps = buildPodSpec(vdb, &vdb.Spec.Subclusters[0]) | ||
c = makeNMAContainer(vdb, &vdb.Spec.Subclusters[0]) | ||
Ω(NMACertsVolumeExists(vdb, ps.Volumes)).Should(BeTrue()) | ||
Ω(NMACertsVolumeMountExists(&c)).Should(BeTrue()) | ||
Ω(NMACertsEnvVarsExist(vdb, &c)).Should(BeTrue()) | ||
}) | ||
|
||
It("should not set any NMA resources if none are set for the subcluster", func() { | ||
vdb := vapi.MakeVDBForHTTP("v-nma-tls-abcde") | ||
sc := &vdb.Spec.Subclusters[0] | ||
|
@@ -767,24 +708,6 @@ func getVolume(vols []v1.Volume, mountName string) *v1.Volume { | |
return nil | ||
} | ||
|
||
func NMACertsVolumeExists(vdb *vapi.VerticaDB, vols []v1.Volume) bool { | ||
for i := range vols { | ||
if vols[i].Name == vapi.NMACertsMountName && vols[i].Secret.SecretName == vdb.Spec.NMATLSSecret { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func NMACertsVolumeMountExists(c *v1.Container) bool { | ||
for _, vol := range c.VolumeMounts { | ||
if vol.Name == vapi.NMACertsMountName && vol.MountPath == paths.NMACertsRoot { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func NMACertsEnvVarsExist(vdb *vapi.VerticaDB, c *v1.Container) bool { | ||
envMap := make(map[string]v1.EnvVar) | ||
for _, envVar := range c.Env { | ||
|
@@ -795,14 +718,8 @@ func NMACertsEnvVarsExist(vdb *vapi.VerticaDB, c *v1.Container) bool { | |
_, keyOk := envMap[NMAKeyEnv] | ||
_, secretNamespaceOk := envMap[NMASecretNamespaceEnv] | ||
_, secretNameOk := envMap[NMASecretNameEnv] | ||
if vmeta.UseNMACertsMount(vdb.Annotations) { | ||
if rootCAOk && certOk && keyOk && !secretNamespaceOk && !secretNameOk { | ||
return true | ||
} | ||
} else { | ||
if !rootCAOk && !certOk && !keyOk && secretNamespaceOk && secretNameOk { | ||
return true | ||
} | ||
if !rootCAOk && !certOk && !keyOk && secretNamespaceOk && secretNameOk { | ||
return true | ||
} | ||
return false | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove "(vsql)"