Skip to content
Open
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
851 changes: 851 additions & 0 deletions api/bases/core.openstack.org_openstackcontrolplanes.yaml

Large diffs are not rendered by default.

204 changes: 204 additions & 0 deletions api/core/v1beta1/openstackcontrolplane_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ type OpenStackControlPlaneSpec struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// Watcher - Parameters related to the Watcher service
Watcher WatcherSection `json:"watcher,omitempty"`

// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// ApplicationCredential - Global configuration for ApplicationCredentials.
// Both this global section AND the per-service applicationCredential section
// must be enabled for a service to use ApplicationCredentials.
// If omitted, defaults to enabled=false with standard expiration/grace periods.
ApplicationCredential ApplicationCredentialSection `json:"applicationCredential,omitempty"`
}

// TLSSection defines the desired state of TLS configuration
Expand Down Expand Up @@ -419,6 +427,13 @@ type PlacementSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// GlanceSection defines the desired state of Glance service
Expand All @@ -445,6 +460,13 @@ type GlanceSection struct {
// Convenient to avoid podname (and thus hostname) collision between different deployments.
// Useful for CI jobs as well as preproduction and production environments that use the same storage backend, etc.
UniquePodNames bool `json:"uniquePodNames"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// CinderSection defines the desired state of Cinder service
Expand All @@ -471,6 +493,13 @@ type CinderSection struct {
// Convenient to avoid podname (and thus hostname) collision between different deployments.
// Useful for CI jobs as well as preproduction and production environments that use the same storage backend, etc.
UniquePodNames bool `json:"uniquePodNames"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// GaleraSection defines the desired state of Galera services
Expand Down Expand Up @@ -564,6 +593,13 @@ type NeutronSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// NovaSection defines the desired state of Nova services
Expand All @@ -590,6 +626,13 @@ type NovaSection struct {
// for a nova cell. cell0 never have compute nodes and therefore it won't have a noVNCProxy deployed.
// Providing an override for cell0 noVNCProxy does not have an effect.
CellOverride map[string]NovaCellOverrideSpec `json:"cellOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// NovaCellOverrideSpec to override the generated manifest of several child resources.
Expand Down Expand Up @@ -620,6 +663,13 @@ type HeatSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// CnfAPIOverride, provides the ability to override the generated manifest of several child resources.
CnfAPIOverride Override `json:"cnfAPIOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// IronicSection defines the desired state of Ironic services
Expand All @@ -644,6 +694,13 @@ type IronicSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// InspectorOverride, provides the ability to override the generated manifest of several child resources.
InspectorOverride Override `json:"inspectorOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// ManilaSection defines the desired state of Manila service
Expand All @@ -663,6 +720,13 @@ type ManilaSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// HorizonSection defines the desired state of Horizon services
Expand Down Expand Up @@ -716,6 +780,27 @@ type TelemetrySection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// AlertmanagerOverride, provides the ability to override the generated manifest of several child resources.
AlertmanagerOverride Override `json:"alertmanagerOverride,omitempty"`

// ApplicationCredentialCeilometer allows service-specific overrides of the global AC configuration for Ceilometer.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredentialCeilometer *ServiceAppCredSection `json:"applicationCredentialCeilometer"`

// ApplicationCredentialAodh allows service-specific overrides of the global AC configuration for Aodh.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredentialAodh *ServiceAppCredSection `json:"applicationCredentialAodh"`

// ApplicationCredentialCloudKitty allows service-specific overrides of the global AC configuration for CloudKitty.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredentialCloudKitty *ServiceAppCredSection `json:"applicationCredentialCloudKitty"`
}

// SwiftSection defines the desired state of Swift service
Expand All @@ -735,6 +820,13 @@ type SwiftSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// ProxyOverride, provides the ability to override the generated manifest of several child resources.
ProxyOverride Override `json:"proxyOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// OctaviaSection defines the desired state of the Octavia service
Expand All @@ -754,6 +846,13 @@ type OctaviaSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// DesignateSection defines the desired state of the Designate service
Expand All @@ -773,6 +872,13 @@ type DesignateSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// BarbicanSection defines the desired state of Barbican service
Expand All @@ -792,6 +898,13 @@ type BarbicanSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// RedisSection defines the desired state of the Redis service
Expand Down Expand Up @@ -833,6 +946,97 @@ type WatcherSection struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// APIOverride, provides the ability to override the generated manifest of several child resources.
APIOverride Override `json:"apiOverride,omitempty"`

// ApplicationCredential allows service-specific overrides of the global AC configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Optional
// +nullable
// +kubebuilder:default={enabled:false}
ApplicationCredential *ServiceAppCredSection `json:"applicationCredential"`
}

// +kubebuilder:validation:XValidation:rule="self.gracePeriodDays < self.expirationDays",message="gracePeriodDays must be smaller than expirationDays"
// ApplicationCredentialSection defines the desired configuration for ApplicationCredentials
type ApplicationCredentialSection struct {
// Enabled indicates whether an ApplicationCredential should be created
// +kubebuilder:validation:Optional
// +kubebuilder:default=false
Enabled bool `json:"enabled"`
Comment on lines +961 to +964
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if we need this global switch, if you always have to enable it also on the per service level. if there is the req to always do it in each service do we need a global switch? wouldn't a global switch only make sense if we default the per service to true. like:

  • switch global to true ac is enable for all services
  • if you want to disable it for some services switch them to off

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know having two switches might feel confusing, but I was thinking about them as two different layers of control. - per-service enablement should stay explicit so the operator isn’t surprised by authentication changing in a service they didn’t mean to migrate yet. The global switch is mainly there for ops convenience and safety: if we ever need to disable AppCred everywhere, we can flip one flag instead of going service-by-service again. If we made per-service default to true, it could be missed and then users would wonder why auth changed unexpectedly. With opt-in per service and global gate, rollout stays controlled and predictable, and we can still turn it off fast at once.

But this is just my idea, I'm open to suggestion based on better practices.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inclined towards having a single switch too, but double knob makes sense now.

do you think we can enable a logs for same, so suppose operator only enabled in respective service but they wont see AC's until the global is enabled too.
to debug they will start with operator logs of respective service - will it make sense to add an warning or error log saying global one might not be enabled.


// ExpirationDays sets the lifetime in days for the AC
// +kubebuilder:validation:Optional
// +kubebuilder:default=730
// +kubebuilder:validation:Minimum=2
ExpirationDays *int `json:"expirationDays"`

// GracePeriodDays sets how many days before expiration the AC should be rotated
// +kubebuilder:validation:Optional
// +kubebuilder:default=364
// +kubebuilder:validation:Minimum=1
GracePeriodDays *int `json:"gracePeriodDays"`

// +kubebuilder:validation:Optional
// +kubebuilder:default={"admin","service"}
// +kubebuilder:validation:MinItems=1
// Roles to assign to the ApplicationCredential
Roles []string `json:"roles"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=false
// Whether the AC should be unrestricted
Unrestricted *bool `json:"unrestricted"`

// AccessRules lets supply a custom list of rules
// If unset, no accessRules field is emitted
// +kubebuilder:validation:Optional
// +listType=atomic
AccessRules []ACRule `json:"accessRules,omitempty"`
}

// +kubebuilder:validation:XValidation:rule="!(has(self.expirationDays) && has(self.gracePeriodDays)) || self.gracePeriodDays < self.expirationDays",message="gracePeriodDays must be smaller than expirationDays"
// ServiceAppCredSection allows service-specific overrides of the global AC configuration
type ServiceAppCredSection struct {
// +kubebuilder:validation:Optional
// +kubebuilder:default=false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see my comment on the global parameter, should this one default to true?

Enabled bool `json:"enabled"`

// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=2
ExpirationDays *int `json:"expirationDays,omitempty"`

// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
GracePeriodDays *int `json:"gracePeriodDays,omitempty"`

// +kubebuilder:validation:Optional
// Roles to assign to the ApplicationCredential
Roles []string `json:"roles,omitempty"`

// +kubebuilder:validation:Optional
// Whether the AC should be unrestricted
Unrestricted *bool `json:"unrestricted,omitempty"`

// AccessRules lets the service override the global AccessRules if specified
// +kubebuilder:validation:Optional
// +listType=atomic
AccessRules []ACRule `json:"accessRules,omitempty"`
}

// ACRule describes a single access rule for an ApplicationCredential
// +k8s:openapi-gen=true
type ACRule struct {
// Service is the name of the service to target (e.g. "identity").
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from where to get the service name? can we link a reference or will it be in product doc or how to use ac rules?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These access rules are a keystone upstream feature for app creds. It is documented directly in the OpenStackClient CLI docs and it will be documented in the product doc how to get the necessary fields (service, path, method) from the cluster.

@vakwetu Can you please provide better answer than me, I remember that I added the AccessRules based on your suggesitons.

// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Service string `json:"service"`
// Path is the HTTP path (e.g. "/v3/auth/tokens").
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from where you get this? you have to know or is there some doc? or do we document this as part of the AC feature in product doc?

// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Path string `json:"path"`
// Method is the HTTP method to allow (e.g. "POST").
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Method string `json:"method"`
}

// OpenStackControlPlaneStatus defines the observed state of OpenStackControlPlane
Expand Down
3 changes: 2 additions & 1 deletion api/core/v1beta1/openstackcontrolplane_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,7 @@ func (r *OpenStackControlPlane) DefaultServices() {
r.Spec.Glance.APIOverride = map[string]Override{}
}
for name, glanceAPI := range r.Spec.Glance.Template.GlanceAPIs {

var override Override
var ok bool

Expand Down Expand Up @@ -1151,7 +1152,7 @@ func (r *OpenStackControlPlane) ValidateNotificationsBusInstance(basePath *field
// NotificationsBusInstance is set and must be equal to an existing
// deployed rabbitmq instance, otherwise we should fail because it
// does not represent a valid string
for k := range(*r.Spec.Rabbitmq.Templates) {
for k := range *r.Spec.Rabbitmq.Templates {
if *r.Spec.NotificationsBusInstance == k {
return nil
}
Expand Down
Loading