@@ -23,11 +23,14 @@ import (
2323 "github.com/go-logr/logr"
2424
2525 corev1 "k8s.io/api/core/v1"
26+ networkingv1 "k8s.io/api/networking/v1"
2627 rbacv1 "k8s.io/api/rbac/v1"
2728 k8s_errors "k8s.io/apimachinery/pkg/api/errors"
2829 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930 "k8s.io/apimachinery/pkg/fields"
3031 "k8s.io/apimachinery/pkg/types"
32+ "k8s.io/apimachinery/pkg/util/intstr"
33+ "k8s.io/utils/ptr"
3134
3235 "k8s.io/apimachinery/pkg/runtime"
3336 "k8s.io/client-go/kubernetes"
@@ -41,7 +44,9 @@ import (
4144 "sigs.k8s.io/controller-runtime/pkg/reconcile"
4245
4346 keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
47+ "github.com/openstack-k8s-operators/lib-common/modules/certmanager"
4448 "github.com/openstack-k8s-operators/lib-common/modules/common"
49+ "github.com/openstack-k8s-operators/lib-common/modules/common/clusterdns"
4550 condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
4651 "github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
4752 "github.com/openstack-k8s-operators/lib-common/modules/common/env"
@@ -83,6 +88,9 @@ func (r *OpenStackClientReconciler) GetLogger(ctx context.Context) logr.Logger {
8388// +kubebuilder:rbac:groups="security.openshift.io",resourceNames=anyuid,resources=securitycontextconstraints,verbs=use
8489// +kubebuilder:rbac:groups="",resources=pods,verbs=create;delete;get;list;patch;update;watch;patch
8590// +kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch
91+ // +kubebuilder:rbac:groups=networking.k8s.io,resources=networkpolicies,verbs=get;list;watch;create;update;patch;delete
92+ // +kubebuilder:rbac:groups=cert-manager.io,resources=issuers,verbs=get;list;watch
93+ // +kubebuilder:rbac:groups=cert-manager.io,resources=certificates,verbs=get;list;watch;create;update;patch;delete
8694
8795// Reconcile -
8896func (r * OpenStackClientReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (result ctrl.Result , _err error ) {
@@ -308,7 +316,53 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
308316 instance .Status .Conditions .MarkTrue (condition .TLSInputReadyCondition , condition .InputReadyMessage )
309317
310318 // Reconcile MCP sidecar resources when enabled
319+ mcpTLSSecretName := ""
311320 if instance .Spec .MCP != nil && instance .Spec .MCP .Enabled {
321+ mcpTLSEnabled := instance .Spec .CaBundleSecretName != ""
322+
323+ if mcpTLSEnabled {
324+ issuer , err := certmanager .GetIssuerByLabels (
325+ ctx , helper ,
326+ instance .Namespace ,
327+ map [string ]string {certmanager .RootCAIssuerInternalLabel : "" },
328+ )
329+ if err != nil {
330+ instance .Status .Conditions .Set (condition .FalseCondition (
331+ clientv1 .OpenStackClientReadyCondition ,
332+ condition .ErrorReason ,
333+ condition .SeverityWarning ,
334+ clientv1 .OpenStackClientReadyErrorMessage ,
335+ err .Error ()))
336+ return ctrl.Result {}, err
337+ }
338+
339+ clusterDomain := clusterdns .GetDNSClusterDomain ()
340+ mcpSvcName := instance .Name + "-mcp"
341+ certRequest := certmanager.CertificateRequest {
342+ IssuerName : issuer .Name ,
343+ CertName : mcpSvcName + "-tls" ,
344+ Hostnames : []string {
345+ fmt .Sprintf ("%s.%s.svc" , mcpSvcName , instance .Namespace ),
346+ fmt .Sprintf ("%s.%s.svc.%s" , mcpSvcName , instance .Namespace , clusterDomain ),
347+ },
348+ Labels : map [string ]string {},
349+ }
350+ certSecret , ctrlResult , err := certmanager .EnsureCert (ctx , helper , certRequest , instance )
351+ if err != nil {
352+ instance .Status .Conditions .Set (condition .FalseCondition (
353+ clientv1 .OpenStackClientReadyCondition ,
354+ condition .ErrorReason ,
355+ condition .SeverityWarning ,
356+ clientv1 .OpenStackClientReadyErrorMessage ,
357+ err .Error ()))
358+ return ctrlResult , err
359+ } else if (ctrlResult != ctrl.Result {}) {
360+ return ctrlResult , nil
361+ }
362+ mcpTLSSecretName = certSecret .Name
363+ configVars [mcpTLSSecretName ] = env .SetValue (certSecret .ResourceVersion )
364+ }
365+
312366 mcpConfigCM := & corev1.ConfigMap {
313367 ObjectMeta : metav1.ObjectMeta {
314368 Name : instance .Name + "-mcp-config" ,
@@ -317,14 +371,14 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
317371 }
318372 _ , err = controllerutil .CreateOrPatch (ctx , r .Client , mcpConfigCM , func () error {
319373 mcpConfigCM .Data = map [string ]string {
320- "config.yaml" : openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName ),
374+ "config.yaml" : openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName , mcpTLSEnabled ),
321375 }
322376 return controllerutil .SetControllerReference (instance , mcpConfigCM , r .Scheme )
323377 })
324378 if err != nil {
325379 return ctrl.Result {}, fmt .Errorf ("error creating MCP config ConfigMap: %w" , err )
326380 }
327- configVars [instance .Name + "-mcp-config" ] = env .SetValue (openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName ))
381+ configVars [instance .Name + "-mcp-config" ] = env .SetValue (openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName , mcpTLSEnabled ))
328382
329383 }
330384
@@ -335,6 +389,12 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
335389
336390 // Reconcile MCP Service after configVarsHash so the hash annotation captures all config changes
337391 if instance .Spec .MCP != nil && instance .Spec .MCP .Enabled {
392+ mcpTLSEnabled := instance .Spec .CaBundleSecretName != ""
393+ mcpPort := int32 (8080 )
394+ if mcpTLSEnabled {
395+ mcpPort = 8443
396+ }
397+
338398 mcpService := & corev1.Service {
339399 ObjectMeta : metav1.ObjectMeta {
340400 Name : instance .Name + "-mcp" ,
@@ -344,7 +404,7 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
344404 mcpServiceHash , err := util .ObjectHash (map [string ]interface {}{
345405 "containerImage" : instance .Spec .ContainerImage ,
346406 "mcpContainerImage" : instance .Spec .MCP .ContainerImage ,
347- "mcpConfig" : openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName ),
407+ "mcpConfig" : openstackclient .MCPConfigYAML (instance .Spec .CaBundleSecretName , mcpTLSEnabled ),
348408 "configVarsHash" : configVarsHash ,
349409 })
350410 if err != nil {
@@ -359,7 +419,7 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
359419 mcpService .Spec .Ports = []corev1.ServicePort {
360420 {
361421 Name : "mcp" ,
362- Port : 8080 ,
422+ Port : mcpPort ,
363423 Protocol : corev1 .ProtocolTCP ,
364424 },
365425 }
@@ -368,6 +428,47 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
368428 if err != nil {
369429 return ctrl.Result {}, fmt .Errorf ("error creating MCP Service: %w" , err )
370430 }
431+
432+ // NetworkPolicy to restrict MCP access to openstackassistant pods only
433+ mcpNetPolicy := & networkingv1.NetworkPolicy {
434+ ObjectMeta : metav1.ObjectMeta {
435+ Name : instance .Name + "-mcp" ,
436+ Namespace : instance .Namespace ,
437+ },
438+ }
439+ _ , err = controllerutil .CreateOrPatch (ctx , r .Client , mcpNetPolicy , func () error {
440+ mcpNetPolicy .Spec = networkingv1.NetworkPolicySpec {
441+ PodSelector : metav1.LabelSelector {
442+ MatchLabels : clientLabels ,
443+ },
444+ Ingress : []networkingv1.NetworkPolicyIngressRule {
445+ {
446+ From : []networkingv1.NetworkPolicyPeer {
447+ {
448+ PodSelector : & metav1.LabelSelector {
449+ MatchLabels : map [string ]string {
450+ common .AppSelector : "openstackassistant" ,
451+ },
452+ },
453+ },
454+ },
455+ Ports : []networkingv1.NetworkPolicyPort {
456+ {
457+ Port : & intstr.IntOrString {Type : intstr .Int , IntVal : mcpPort },
458+ Protocol : ptr .To (corev1 .ProtocolTCP ),
459+ },
460+ },
461+ },
462+ },
463+ PolicyTypes : []networkingv1.PolicyType {
464+ networkingv1 .PolicyTypeIngress ,
465+ },
466+ }
467+ return controllerutil .SetControllerReference (instance , mcpNetPolicy , r .Scheme )
468+ })
469+ if err != nil {
470+ return ctrl.Result {}, fmt .Errorf ("error creating MCP NetworkPolicy: %w" , err )
471+ }
371472 }
372473
373474 osclient := & corev1.Pod {
@@ -377,7 +478,7 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ
377478 },
378479 }
379480
380- spec := openstackclient .ClientPodSpec (ctx , instance , helper , configVarsHash )
481+ spec := openstackclient .ClientPodSpec (ctx , instance , helper , configVarsHash , mcpTLSSecretName )
381482
382483 podSpecHash , err := util .ObjectHash (spec )
383484 if err != nil {
@@ -571,6 +672,7 @@ func (r *OpenStackClientReconciler) SetupWithManager(
571672 Owns (& corev1.ServiceAccount {}).
572673 Owns (& corev1.ConfigMap {}).
573674 Owns (& corev1.Service {}).
675+ Owns (& networkingv1.NetworkPolicy {}).
574676 Owns (& rbacv1.Role {}).
575677 Owns (& rbacv1.RoleBinding {}).
576678 Watches (
0 commit comments