Skip to content

Commit

Permalink
Add a webhook validation for tls apiOverride
Browse files Browse the repository at this point in the history
Add webhook to validate TLS apiOverride completeness (CA certificate, certificate, key) before CR is applied.

Signed-off-by: Veronika Fisarova <[email protected]>
  • Loading branch information
Deydra71 committed Oct 2, 2024
1 parent 21b29b8 commit 783d095
Showing 1 changed file with 72 additions and 13 deletions.
85 changes: 72 additions & 13 deletions apis/core/v1beta1/openstackcontrolplane_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ import (
heatv1 "github.com/openstack-k8s-operators/heat-operator/api/v1beta1"
horizonv1 "github.com/openstack-k8s-operators/horizon-operator/api/v1beta1"
memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1"
redisv1 "github.com/openstack-k8s-operators/infra-operator/apis/redis/v1beta1"
networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
redisv1 "github.com/openstack-k8s-operators/infra-operator/apis/redis/v1beta1"
ironicv1 "github.com/openstack-k8s-operators/ironic-operator/api/v1beta1"
manilav1 "github.com/openstack-k8s-operators/manila-operator/api/v1beta1"
neutronv1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1"
Expand Down Expand Up @@ -245,26 +245,32 @@ func (r *OpenStackControlPlane) ValidateCreateServices(basePath *field.Path) (ad
// Call internal validation logic for individual service operators
if r.Spec.Keystone.Enabled {
errors = append(errors, r.Spec.Keystone.Template.ValidateCreate(basePath.Child("keystone").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Keystone.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Ironic.Enabled {
errors = append(errors, r.Spec.Ironic.Template.ValidateCreate(basePath.Child("ironic").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Ironic.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Nova.Enabled {
errors = append(errors, r.Spec.Nova.Template.ValidateCreate(basePath.Child("nova").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Nova.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Placement.Enabled {
errors = append(errors, r.Spec.Placement.Template.ValidateCreate(basePath.Child("placement").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Placement.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Barbican.Enabled {
errors = append(errors, r.Spec.Barbican.Template.ValidateCreate(basePath.Child("barbican").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Barbican.APIOverride.Route, basePath.Child("barbican").Child("apiOverride").Child("route"))...)
}

if r.Spec.Neutron.Enabled {
errors = append(errors, r.Spec.Neutron.Template.ValidateCreate(basePath.Child("neutron").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Neutron.APIOverride.Route, basePath.Child("neutron").Child("apiOverride").Child("route"))...)
}

if r.Spec.Glance.Enabled {
Expand All @@ -277,6 +283,11 @@ func (r *OpenStackControlPlane) ValidateCreateServices(basePath *field.Path) (ad
errors = append(errors, err...)
}
errors = append(errors, r.Spec.Glance.Template.ValidateCreate(basePath.Child("glance").Child("template"))...)

for key, override := range r.Spec.Glance.APIOverride {
overridePath := basePath.Child("glance").Child("apiOverride").Key(key)
errors = append(errors, validateTLSOverrideSpec(&override.Route, overridePath.Child("route"))...)
}
}

if r.Spec.Cinder.Enabled {
Expand All @@ -287,28 +298,35 @@ func (r *OpenStackControlPlane) ValidateCreateServices(basePath *field.Path) (ad
cinderv1.GetCrMaxLengthCorrection(cinderName)) // omit issue with statefulset pod label "controller-revision-hash": "<statefulset_name>-<hash>"
errors = append(errors, errs...)
errors = append(errors, r.Spec.Cinder.Template.ValidateCreate(basePath.Child("cinder").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Cinder.APIOverride.Route, basePath.Child("cinder").Child("apiOverride").Child("route"))...)
}

if r.Spec.Heat.Enabled {
errors = append(errors, r.Spec.Heat.Template.ValidateCreate(basePath.Child("heat").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Heat.APIOverride.Route, basePath.Child("heat").Child("apiOverride").Child("route"))...)
}

if r.Spec.Manila.Enabled {
errors = append(errors, r.Spec.Manila.Template.ValidateCreate(basePath.Child("manila").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Manila.APIOverride.Route, basePath.Child("manila").Child("apiOverride").Child("route"))...)
}

if r.Spec.Swift.Enabled {
errors = append(errors, r.Spec.Swift.Template.ValidateCreate(basePath.Child("swift").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Swift.ProxyOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Octavia.Enabled {
errors = append(errors, r.Spec.Octavia.Template.ValidateCreate(basePath.Child("octavia").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Octavia.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Designate.Enabled {
errors = append(errors, r.Spec.Designate.Template.ValidateCreate(basePath.Child("designate").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Designate.APIOverride.Route, basePath.Child("designate").Child("apiOverride").Child("route"))...)
}

// Validation for remaining services...
if r.Spec.Galera.Enabled {
for key, s := range *r.Spec.Galera.Templates {
warn, err := s.ValidateCreate(basePath.Child("galera").Child("template").Key(key))
Expand Down Expand Up @@ -372,41 +390,47 @@ func (r *OpenStackControlPlane) ValidateUpdateServices(old OpenStackControlPlane
old.Keystone.Template = &keystonev1.KeystoneAPISpecCore{}
}
errors = append(errors, r.Spec.Keystone.Template.ValidateUpdate(*old.Keystone.Template, basePath.Child("keystone").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Keystone.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Ironic.Enabled {
if old.Ironic.Template == nil {
old.Ironic.Template = &ironicv1.IronicSpecCore{}
}
errors = append(errors, r.Spec.Ironic.Template.ValidateUpdate(*old.Ironic.Template, basePath.Child("ironic").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Ironic.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Nova.Enabled {
if old.Nova.Template == nil {
old.Nova.Template = &novav1.NovaSpec{}
}
errors = append(errors, r.Spec.Nova.Template.ValidateUpdate(*old.Nova.Template, basePath.Child("nova").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Nova.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Placement.Enabled {
if old.Placement.Template == nil {
old.Placement.Template = &placementv1.PlacementAPISpecCore{}
}
errors = append(errors, r.Spec.Placement.Template.ValidateUpdate(*old.Placement.Template, basePath.Child("placement").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Placement.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Barbican.Enabled {
if old.Barbican.Template == nil {
old.Barbican.Template = &barbicanv1.BarbicanSpecCore{}
}
errors = append(errors, r.Spec.Barbican.Template.ValidateUpdate(*old.Barbican.Template, basePath.Child("barbican").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Barbican.APIOverride.Route, basePath.Child("barbican").Child("apiOverride").Child("route"))...)
}

if r.Spec.Neutron.Enabled {
if old.Neutron.Template == nil {
old.Neutron.Template = &neutronv1.NeutronAPISpecCore{}
}
errors = append(errors, r.Spec.Neutron.Template.ValidateUpdate(*old.Neutron.Template, basePath.Child("neutron").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Neutron.APIOverride.Route, basePath.Child("neutron").Child("apiOverride").Child("route"))...)
}

if r.Spec.Glance.Enabled {
Expand All @@ -422,6 +446,11 @@ func (r *OpenStackControlPlane) ValidateUpdateServices(old OpenStackControlPlane
errors = append(errors, err...)
}
errors = append(errors, r.Spec.Glance.Template.ValidateUpdate(*old.Glance.Template, basePath.Child("glance").Child("template"))...)

for key, override := range r.Spec.Glance.APIOverride {
overridePath := basePath.Child("glance").Child("apiOverride").Key(key)
errors = append(errors, validateTLSOverrideSpec(&override.Route, overridePath.Child("route"))...)
}
}

if r.Spec.Cinder.Enabled {
Expand All @@ -435,41 +464,47 @@ func (r *OpenStackControlPlane) ValidateUpdateServices(old OpenStackControlPlane
cinderv1.GetCrMaxLengthCorrection(cinderName)) // omit issue with statefulset pod label "controller-revision-hash": "<statefulset_name>-<hash>"
errors = append(errors, errs...)
errors = append(errors, r.Spec.Cinder.Template.ValidateUpdate(*old.Cinder.Template, basePath.Child("cinder").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Cinder.APIOverride.Route, basePath.Child("cinder").Child("apiOverride").Child("route"))...)
}

if r.Spec.Heat.Enabled {
if old.Heat.Template == nil {
old.Heat.Template = &heatv1.HeatSpecCore{}
}
errors = append(errors, r.Spec.Heat.Template.ValidateUpdate(*old.Heat.Template, basePath.Child("heat").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Heat.APIOverride.Route, basePath.Child("heat").Child("apiOverride").Child("route"))...)
}

if r.Spec.Manila.Enabled {
if old.Manila.Template == nil {
old.Manila.Template = &manilav1.ManilaSpecCore{}
}
errors = append(errors, r.Spec.Manila.Template.ValidateUpdate(*old.Manila.Template, basePath.Child("manila").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Manila.APIOverride.Route, basePath.Child("manila").Child("apiOverride").Child("route"))...)
}

if r.Spec.Swift.Enabled {
if old.Swift.Template == nil {
old.Swift.Template = &swiftv1.SwiftSpecCore{}
}
errors = append(errors, r.Spec.Swift.Template.ValidateUpdate(*old.Swift.Template, basePath.Child("swift").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Swift.ProxyOverride.Route, basePath.Child("neutron").Child("apiOverride").Child("route"))...)
}

if r.Spec.Octavia.Enabled {
if old.Octavia.Template == nil {
old.Octavia.Template = &octaviav1.OctaviaSpecCore{}
}
errors = append(errors, r.Spec.Octavia.Template.ValidateUpdate(*old.Octavia.Template, basePath.Child("octavia").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Octavia.APIOverride.Route, basePath.Child("octavia").Child("apiOverride").Child("route"))...)
}

if r.Spec.Designate.Enabled {
if old.Designate.Template == nil {
old.Designate.Template = &designatev1.DesignateSpecCore{}
}
errors = append(errors, r.Spec.Designate.Template.ValidateUpdate(*old.Designate.Template, basePath.Child("designate").Child("template"))...)
errors = append(errors, validateTLSOverrideSpec(&r.Spec.Designate.APIOverride.Route, basePath.Child("designate").Child("apiOverride").Child("route"))...)
}

if r.Spec.Memcached.Enabled {
Expand Down Expand Up @@ -875,23 +910,23 @@ func (r *OpenStackControlPlane) DefaultServices() {
}

// Redis
if r.Spec.Redis.Enabled || r.Spec.Redis.Templates != nil {
if r.Spec.Redis.Templates == nil {
r.Spec.Redis.Templates = ptr.To(map[string]redisv1.RedisSpecCore{})
}

for key, template := range *r.Spec.Redis.Templates {
template.Default()
// By-value copy, need to update
(*r.Spec.Redis.Templates)[key] = template
}
}
if r.Spec.Redis.Enabled || r.Spec.Redis.Templates != nil {
if r.Spec.Redis.Templates == nil {
r.Spec.Redis.Templates = ptr.To(map[string]redisv1.RedisSpecCore{})
}

for key, template := range *r.Spec.Redis.Templates {
template.Default()
// By-value copy, need to update
(*r.Spec.Redis.Templates)[key] = template
}
}

}

// DefaultLabel - adding default label to the OpenStackControlPlane
func (r *OpenStackControlPlane) DefaultLabel() {
// adds map[string]string{"core.openstack.org/openstackcontrolplane": r.name>} to the
// adds map[string]string{"core.openstack.org/openstackcontrolvplane": r.name>} to the
// instance, if not already provided in the CR. With this ctlplane object can be
// queried using the default label.
typeLabel := strings.ToLower(r.GroupVersionKind().Group + "/" + r.Kind)
Expand All @@ -902,3 +937,27 @@ func (r *OpenStackControlPlane) DefaultLabel() {
r.Labels[typeLabel] = ""
}
}

// ValidateTLSData checks if the TLS data in the apiOverride are valid.
func validateTLSOverrideSpec(override **route.OverrideSpec, basePath *field.Path) field.ErrorList {
var allErrs field.ErrorList

if *override == nil {
return allErrs
}

tlsSpec := (*override).Spec
if tlsSpec != nil && tlsSpec.TLS != nil {
if tlsSpec.TLS.CACertificate == "" {
allErrs = append(allErrs, field.Required(basePath.Child("tls").Child("caCertificate"), "CA Certificate is required"))
}
if tlsSpec.TLS.Certificate == "" {
allErrs = append(allErrs, field.Required(basePath.Child("tls").Child("certificate"), "Certificate is required"))
}
if tlsSpec.TLS.Key == "" {
allErrs = append(allErrs, field.Required(basePath.Child("tls").Child("key"), "Key is required"))
}
}

return allErrs
}

0 comments on commit 783d095

Please sign in to comment.