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
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ func main() {
Client: client,
Scheme: mgr.GetScheme(),
DisableDefaultInstall: strings.ToLower(os.Getenv(common.DisableDefaultInstallEnvVar)) == "true",
TLSMinVersion: string(profile.MinTLSVersion),
TLSCiphers: profile.Ciphers,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitopsService")
os.Exit(1)
Expand Down
93 changes: 82 additions & 11 deletions controllers/consoleplugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package controllers

import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"os"
"reflect"
"sort"
"strings"

argocommon "github.com/argoproj-labs/argocd-operator/common"
argocdutil "github.com/argoproj-labs/argocd-operator/controllers/argoutil"
Expand Down Expand Up @@ -240,18 +244,52 @@ func securityContextForPlugin() *corev1.SecurityContext {
}
}

var httpdConfig = fmt.Sprintf(`LoadModule ssl_module modules/mod_ssl.so
func TLSVersionToPlugin(tlsVersion string) string {
versionMap := map[string]string{
"VersionTLS12": "TLSv1.2",
"VersionTLS13": "TLSv1.3",
"VersionTLS11": "TLSv1.1",
"VersionTLS10": "TLSv1",
}
if v, ok := versionMap[tlsVersion]; ok {
return v
}
return "" // default fallback
}

// buildHttpdConfig generates httpd.conf with dynamic TLS settings
func (r *ReconcileGitopsService) buildHttpdConfig() string {
httpdConfigBase := fmt.Sprintf(`LoadModule ssl_module modules/mod_ssl.so
Listen %d https
ServerRoot "/etc/httpd"

<VirtualHost *:%d>
DocumentRoot /var/www/html/plugin
SSLEngine on
SSLCertificateFile "/etc/httpd-ssl/certs/tls.crt"
SSLCertificateKeyFile "/etc/httpd-ssl/private/tls.key"
</VirtualHost>`, servicePort, servicePort)
SSLCertificateKeyFile "/etc/httpd-ssl/private/tls.key"`, servicePort, servicePort)
// Add SSLProtocol only if explicitly set
switch r.TLSMinVersion {
case "VersionTLS10":
httpdConfigBase += "\n\tSSLProtocol -all +TLSv1 +TLSv1.1 +TLSv1.2 +TLSv1.3"
case "VersionTLS11":
httpdConfigBase += "\n\tSSLProtocol -all +TLSv1.1 +TLSv1.2 +TLSv1.3"
case "VersionTLS12":
httpdConfigBase += "\n\tSSLProtocol -all +TLSv1.2 +TLSv1.3"
case "VersionTLS13":
httpdConfigBase += "\n\tSSLProtocol -all +TLSv1.3"
}
if TLSVersionToPlugin(r.TLSMinVersion) != "TLSv1.3" && strings.Join(r.TLSCiphers, ":") != "" {
httpdConfigBase += fmt.Sprintf("\n\tSSLCipherSuite %s", strings.Join(r.TLSCiphers, ":"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a question here to confirm if Intermediate/Modern profile ciphers work with httpd as-is, or do we need to filter/map them?

}
// Close VirtualHost
httpdConfigBase += "\n</VirtualHost>"
return httpdConfigBase
}

// pluginConfigMap creates the ConfigMap with dynamic httpd.conf
func (r *ReconcileGitopsService) pluginConfigMap() *corev1.ConfigMap {
httpdConfig := r.buildHttpdConfig()

func pluginConfigMap() *corev1.ConfigMap {
cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: httpdConfigMapName,
Expand Down Expand Up @@ -337,7 +375,7 @@ func sortTolerations(tolerations []corev1.Toleration) []corev1.Toleration {
return sorted
}

func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.GitopsService, request reconcile.Request) (reconcile.Result, error) {
func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.GitopsService, request reconcile.Request, newPluginConfigMap *corev1.ConfigMap) (reconcile.Result, error) {
reqLogger := logs.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
newPluginDeployment := pluginDeployment(cr.Spec.ImagePullPolicy)

Expand All @@ -359,6 +397,13 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop
newPluginDeployment.Spec.Template.Spec.Tolerations = cr.Spec.Tolerations
}

// ADD THIS: Get ConfigMap and add hash to pod template annotations
configMapHash := getConfigMapHash(newPluginConfigMap)
if newPluginDeployment.Spec.Template.ObjectMeta.Annotations == nil {
newPluginDeployment.Spec.Template.ObjectMeta.Annotations = make(map[string]string)
}
newPluginDeployment.Spec.Template.ObjectMeta.Annotations["httpd-cfg-hash"] = configMapHash

// Check if this Deployment already exists
existingPluginDeployment := &appsv1.Deployment{}

Expand All @@ -381,6 +426,7 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop
!equality.Semantic.DeepEqual(existingPluginDeployment.Spec.Replicas, newPluginDeployment.Spec.Replicas) ||
!equality.Semantic.DeepEqual(existingPluginDeployment.Spec.Selector, newPluginDeployment.Spec.Selector) ||
!equality.Semantic.DeepEqual(existingSpecTemplate.Labels, newSpecTemplate.Labels) ||
!equality.Semantic.DeepEqual(existingSpecTemplate.ObjectMeta.Annotations["httpd-cfg-hash"], newSpecTemplate.ObjectMeta.Annotations["httpd-cfg-hash"]) ||
!equality.Semantic.DeepEqual(sortContainers(existingSpecTemplate.Spec.Containers), sortContainers(newSpecTemplate.Spec.Containers)) ||
!equality.Semantic.DeepEqual(sortVolumes(existingSpecTemplate.Spec.Volumes), sortVolumes(newSpecTemplate.Spec.Volumes)) ||
!equality.Semantic.DeepEqual(existingSpecTemplate.Spec.RestartPolicy, newSpecTemplate.Spec.RestartPolicy) ||
Expand All @@ -391,11 +437,15 @@ func (r *ReconcileGitopsService) reconcileDeployment(cr *pipelinesv1alpha1.Gitop
!equality.Semantic.DeepEqual(existingSpecTemplate.Spec.Containers[0].Resources, newSpecTemplate.Spec.Containers[0].Resources)

if changed {
if existingSpecTemplate.ObjectMeta.Annotations == nil {
existingSpecTemplate.ObjectMeta.Annotations = make(map[string]string)
}
reqLogger.Info("Reconciling plugin deployment", "Namespace", existingPluginDeployment.Namespace, "Name", existingPluginDeployment.Name)
existingPluginDeployment.Labels = newPluginDeployment.Labels
existingPluginDeployment.Spec.Replicas = newPluginDeployment.Spec.Replicas
existingPluginDeployment.Spec.Selector = newPluginDeployment.Spec.Selector
existingSpecTemplate.Labels = newSpecTemplate.Labels
existingSpecTemplate.ObjectMeta.Annotations["httpd-cfg-hash"] = newSpecTemplate.ObjectMeta.Annotations["httpd-cfg-hash"]
Comment thread
akhilnittala marked this conversation as resolved.
existingSpecTemplate.Spec.SecurityContext = newSpecTemplate.Spec.SecurityContext
existingSpecTemplate.Spec.Containers = newSpecTemplate.Spec.Containers
existingSpecTemplate.Spec.Volumes = newSpecTemplate.Spec.Volumes
Expand Down Expand Up @@ -487,9 +537,27 @@ func (r *ReconcileGitopsService) reconcileConsolePlugin(instance *pipelinesv1alp
return reconcile.Result{}, nil
}

func (r *ReconcileGitopsService) reconcileConfigMap(instance *pipelinesv1alpha1.GitopsService, request reconcile.Request) (reconcile.Result, error) {
// getConfigMapHash returns a deterministic SHA256 hash of ConfigMap data for change detection.
func getConfigMapHash(cm *corev1.ConfigMap) string {
hash := sha256.New()
keys := make([]string, 0, len(cm.Data))
for key := range cm.Data {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
if _, err := io.WriteString(hash, key); err != nil {
panic(fmt.Sprintf("failed to hash configmap key: %v", err))
}
if _, err := io.WriteString(hash, cm.Data[key]); err != nil {
panic(fmt.Sprintf("failed to hash configmap value: %v", err))
}
}
return hex.EncodeToString(hash.Sum(nil))
}

func (r *ReconcileGitopsService) reconcileConfigMap(instance *pipelinesv1alpha1.GitopsService, request reconcile.Request, newPluginConfigMap *corev1.ConfigMap) (reconcile.Result, error) {
reqLogger := logs.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
newPluginConfigMap := pluginConfigMap()

if err := controllerutil.SetControllerReference(instance, newPluginConfigMap, r.Scheme); err != nil {
return reconcile.Result{}, err
Expand All @@ -515,7 +583,7 @@ func (r *ReconcileGitopsService) reconcileConfigMap(instance *pipelinesv1alpha1.
reqLogger.Info("Reconciling plugin configMap", "Namespace", existingPluginConfigMap.Namespace, "Name", existingPluginConfigMap.Name)
existingPluginConfigMap.Data = newPluginConfigMap.Data
existingPluginConfigMap.Labels = newPluginConfigMap.Labels
return reconcile.Result{}, r.Client.Update(context.TODO(), newPluginConfigMap)
return reconcile.Result{}, r.Client.Update(context.TODO(), existingPluginConfigMap)
}
}
return reconcile.Result{}, nil
Expand All @@ -529,15 +597,18 @@ func (r *ReconcileGitopsService) reconcilePlugin(instance *pipelinesv1alpha1.Git
return reconcile.Result{}, nil
}

// Generate ConfigMap once
newPluginConfigMap := r.pluginConfigMap()

if result, err := r.reconcileService(instance, request); err != nil {
return result, err
}

if result, err := r.reconcileDeployment(instance, request); err != nil {
if result, err := r.reconcileConfigMap(instance, request, newPluginConfigMap); err != nil {
return result, err
}

if result, err := r.reconcileConfigMap(instance, request); err != nil {
if result, err := r.reconcileDeployment(instance, request, newPluginConfigMap); err != nil {
return result, err
}

Expand Down
Loading
Loading