Make new TLSTermination option, with or w/o secret (#452)

New option is "spec.solrAddressability.external.ingressTLSTermination"
diff --git a/api/v1beta1/solrcloud_types.go b/api/v1beta1/solrcloud_types.go
index dd2344d..95fde5a 100644
--- a/api/v1beta1/solrcloud_types.go
+++ b/api/v1beta1/solrcloud_types.go
@@ -19,6 +19,7 @@
 
 import (
 	"fmt"
+	"github.com/go-logr/logr"
 	"strconv"
 	"strings"
 
@@ -139,7 +140,7 @@
 	AdditionalLibs []string `json:"additionalLibs,omitempty"`
 }
 
-func (spec *SolrCloudSpec) withDefaults() (changed bool) {
+func (spec *SolrCloudSpec) withDefaults(logger logr.Logger) (changed bool) {
 	if spec.Replicas == nil {
 		changed = true
 		r := DefaultSolrReplicas
@@ -166,7 +167,7 @@
 		spec.SolrGCTune = DefaultSolrGCTune
 	}
 
-	changed = spec.SolrAddressability.withDefaults(spec.SolrTLS != nil) || changed
+	changed = spec.SolrAddressability.withDefaults(spec.SolrTLS != nil, logger) || changed
 
 	changed = spec.UpdateStrategy.withDefaults() || changed
 
@@ -467,9 +468,9 @@
 	KubeDomain string `json:"kubeDomain,omitempty"`
 }
 
-func (opts *SolrAddressabilityOptions) withDefaults(usesTLS bool) (changed bool) {
+func (opts *SolrAddressabilityOptions) withDefaults(usesTLS bool, logger logr.Logger) (changed bool) {
 	if opts.External != nil {
-		changed = opts.External.withDefaults(usesTLS)
+		changed = opts.External.withDefaults(usesTLS, logger)
 	}
 	if opts.PodPort == 0 {
 		changed = true
@@ -554,11 +555,23 @@
 	//
 	// When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS.
 	//
+	// DEPRECATED: Use ingressTLSTermination.tlsSecret instead
+	//
 	// +optional
 	IngressTLSTerminationSecret string `json:"ingressTLSTerminationSecret,omitempty"`
+
+	// IngressTLSTermination tells the SolrCloud Ingress to terminate TLS on incoming connections.
+	//
+	// This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination.
+	// This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr.
+	//
+	// When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS.
+	//
+	// +optional
+	IngressTLSTermination *SolrIngressTLSTermination `json:"ingressTLSTermination,omitempty"`
 }
 
-// ExternalAddressability is a string enumeration type that enumerates
+// ExternalAddressabilityMethod is a string enumeration type that enumerates
 // all possible ways that a SolrCloud can be made addressable external to the kubernetes cluster.
 // +kubebuilder:validation:Enum=Ingress;ExternalDNS
 type ExternalAddressabilityMethod string
@@ -575,9 +588,29 @@
 	LoadBalancer ExternalAddressabilityMethod = "LoadBalancer"
 )
 
-func (opts *ExternalAddressability) withDefaults(usesTLS bool) (changed bool) {
+func (opts *ExternalAddressability) withDefaults(usesTLS bool, logger logr.Logger) (changed bool) {
+	// TODO: Remove in v0.7.0
+	// If the deprecated IngressTLSTerminationSecret exists, use it to default the new location of the value.
+	// If that location already exists, then merely remove the deprecated option.
+	if opts.IngressTLSTerminationSecret != "" {
+		terminationSecretLogger := logger.WithValues("option", "spec.solrAddressability.external.ingressTLSTerminationSecret").WithValues("newLocation", "spec.solrAddressability.external.ingressTLSTermination.tlsSecret")
+		var loggingAction string
+		if !opts.HasIngressTLSTermination() {
+			opts.IngressTLSTermination = &SolrIngressTLSTermination{
+				TLSSecret: opts.IngressTLSTerminationSecret,
+			}
+			loggingAction = "Moving"
+		} else {
+			terminationSecretLogger = terminationSecretLogger.WithValues("reason", "Cannot move deprecated option because ingressTLSTermination is already defined")
+			loggingAction = "Removing"
+		}
+		opts.IngressTLSTerminationSecret = ""
+		terminationSecretLogger.Info(loggingAction + " deprecated CRD option")
+		changed = true
+	}
+
 	// You can't use an externalAddress for Solr Nodes if the Nodes are hidden externally
-	if opts.UseExternalAddress && (opts.HideNodes || opts.IngressTLSTerminationSecret != "") {
+	if opts.UseExternalAddress && (opts.HideNodes || opts.IngressTLSTermination != nil) {
 		changed = true
 		opts.UseExternalAddress = false
 	}
@@ -606,6 +639,7 @@
 				}
 			}
 		}
+		logger.Info("Moving deprecated CRD option", "option", "spec.solrAddressability.external.additionalDomains", "newLocation", "spec.solrAddressability.external.additionalDomainNames")
 		changed = true
 		opts.AdditionalDomains = nil
 	}
@@ -628,6 +662,25 @@
 	return changed
 }
 
+// SolrIngressTLSTermination defines how a SolrCloud should have TLS Termination enabled.
+// Only one option can be provided.
+//
+// +kubebuilder:validation:MaxProperties=1
+type SolrIngressTLSTermination struct {
+
+	// UseDefaultTLSSecret determines whether the ingress should use the default TLS secret provided by the Ingress implementation.
+	//
+	// For example, using nginx: https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-ssl-certificate
+	//
+	// +optional
+	UseDefaultTLSSecret bool `json:"useDefaultTLSSecret,omitempty"`
+
+	// TLSSecret defines a TLS Secret to use for TLS termination of all exposed addresses for this SolrCloud in the Ingress.
+	//
+	// +optional
+	TLSSecret string `json:"tlsSecret,omitempty"`
+}
+
 type SolrUpdateStrategy struct {
 	// Method defines the way in which SolrClouds should be updated when the podSpec changes.
 	// +optional
@@ -1110,8 +1163,8 @@
 }
 
 // WithDefaults set default values when not defined in the spec.
-func (sc *SolrCloud) WithDefaults() bool {
-	return sc.Spec.withDefaults()
+func (sc *SolrCloud) WithDefaults(logger logr.Logger) bool {
+	return sc.Spec.withDefaults(logger)
 }
 
 func (sc *SolrCloud) GetAllSolrPodNames() []string {
@@ -1332,11 +1385,18 @@
 	return url
 }
 
+func (ea *ExternalAddressability) HasIngressTLSTermination() bool {
+	if ea != nil && ea.Method == Ingress && ea.IngressTLSTermination != nil {
+		return ea.IngressTLSTermination.UseDefaultTLSSecret || ea.IngressTLSTermination.TLSSecret != ""
+	}
+	return false
+}
+
 func (sc *SolrCloud) UrlScheme(external bool) string {
 	urlScheme := "http"
 	if sc.Spec.SolrTLS != nil {
 		urlScheme = "https"
-	} else if external && sc.Spec.SolrAddressability.External != nil && sc.Spec.SolrAddressability.External.Method == Ingress && sc.Spec.SolrAddressability.External.IngressTLSTerminationSecret != "" {
+	} else if external && sc.Spec.SolrAddressability.External.HasIngressTLSTermination() {
 		urlScheme = "https"
 	}
 	return urlScheme
diff --git a/api/v1beta1/solrcloud_with_defaults_test.go b/api/v1beta1/solrcloud_with_defaults_test.go
index 3f354ee..9c706e8 100644
--- a/api/v1beta1/solrcloud_with_defaults_test.go
+++ b/api/v1beta1/solrcloud_with_defaults_test.go
@@ -19,69 +19,128 @@
 
 import (
 	"github.com/stretchr/testify/assert"
+	ctrl "sigs.k8s.io/controller-runtime"
 	"testing"
 )
 
 func TestDeprecatedAdditionalDomains(t *testing.T) {
 	ext := &ExternalAddressability{}
+	logger := ctrl.Log
 
-	assert.False(t, ext.withDefaults(false), "withDefaults() returned true when nothing should have been changed (no additional domains in either field)")
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no additional domains in either field)")
 
 	ext.AdditionalDomainNames = []string{"t1", "t2"}
 
-	assert.False(t, ext.withDefaults(false), "withDefaults() returned true when nothing should have been changed (no additional domains in the deprecated field)")
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no additional domains in the deprecated field)")
 
 	ext.AdditionalDomains = nil
 
-	assert.False(t, ext.withDefaults(false), "withDefaults() returned true when nothing should have been changed (no additional domains in the deprecated field)")
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no additional domains in the deprecated field)")
 
 	ext.AdditionalDomains = []string{}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2"}, ext.AdditionalDomainNames, "There are no values from additionalDomains to append to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomains = []string{"t1", "t2"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2"}, ext.AdditionalDomainNames, "The values are the same between additionalDomains and additionalDomainNames, so nothing should be changed in additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomains = []string{"t1", "t2", "t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomains = []string{"t1", "t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomains = []string{"t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomains = []string{"t4", "t1", "t2", "t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t1", "t2", "t4", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomainNames = nil
 	ext.AdditionalDomains = []string{"t4", "t1", "t2", "t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t4", "t1", "t2", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 
 	ext.AdditionalDomainNames = []string{}
 	ext.AdditionalDomains = []string{"t4", "t1", "t2", "t3"}
 
-	assert.True(t, ext.withDefaults(false), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
 	assert.ElementsMatch(t, []string{"t4", "t1", "t2", "t3"}, ext.AdditionalDomainNames, "The unique values from additionalDomains were not appended to additionalDomainNames")
 	assert.Nil(t, ext.AdditionalDomains, "The additionalDomains field was not set to nil")
 }
+
+func TestDeprecatedIngressTerminationTLSSecret(t *testing.T) {
+	ext := &ExternalAddressability{
+		Method:           Ingress,
+		NodePortOverride: 80,
+	}
+
+	logger := ctrl.Log
+
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no termination in either field)")
+
+	ext.IngressTLSTerminationSecret = ""
+
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no termination in the deprecated field)")
+
+	ext.IngressTLSTermination = &SolrIngressTLSTermination{
+		TLSSecret: "test",
+	}
+
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no termination in the deprecated field)")
+
+	ext.IngressTLSTermination = &SolrIngressTLSTermination{
+		UseDefaultTLSSecret: true,
+	}
+
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no termination in the deprecated field)")
+
+	ext.IngressTLSTermination = &SolrIngressTLSTermination{
+		UseDefaultTLSSecret: false,
+	}
+
+	assert.False(t, ext.withDefaults(false, logger), "withDefaults() returned true when nothing should have been changed (no termination in the deprecated field)")
+
+	ext.IngressTLSTerminationSecret = "test2"
+
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.Equal(t, "test2", ext.IngressTLSTermination.TLSSecret, "The value from ingressTLSTerminationSecret should have populated ingressTLSTermination.tlsSecret")
+	assert.Empty(t, ext.IngressTLSTerminationSecret, "The ingressTLSTerminationSecret field was not set to nil")
+
+	ext.IngressTLSTerminationSecret = "test2"
+	ext.IngressTLSTermination = &SolrIngressTLSTermination{
+		UseDefaultTLSSecret: true,
+	}
+
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.Empty(t, ext.IngressTLSTermination.TLSSecret, "The value from ingressTLSTerminationSecret should not have populated ingressTLSTermination.tlsSecret, since useDefaultTLSSecret is set to true")
+	assert.Empty(t, ext.IngressTLSTerminationSecret, "The ingressTLSTerminationSecret field was not set to nil")
+
+	ext.IngressTLSTerminationSecret = "test2"
+	ext.IngressTLSTermination = &SolrIngressTLSTermination{
+		TLSSecret: "test",
+	}
+
+	assert.True(t, ext.withDefaults(false, logger), "withDefaults() returned false when the additionalDomains field needs to be removed")
+	assert.Equal(t, "test", ext.IngressTLSTermination.TLSSecret, "The value from ingressTLSTerminationSecret should not have populated ingressTLSTermination.tlsSecret, since the field is already set")
+	assert.Empty(t, ext.IngressTLSTerminationSecret, "The ingressTLSTerminationSecret field was not set to nil")
+}
diff --git a/api/v1beta1/suite_test.go b/api/v1beta1/suite_test.go
new file mode 100644
index 0000000..9d1b482
--- /dev/null
+++ b/api/v1beta1/suite_test.go
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package v1beta1
+
+import (
+	"os"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
+	"testing"
+)
+
+func TestMain(m *testing.M) {
+	ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
+
+	code := m.Run()
+	os.Exit(code)
+}
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index 235b6ea..513740c 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -263,6 +263,11 @@
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.IngressTLSTermination != nil {
+		in, out := &in.IngressTLSTermination, &out.IngressTLSTermination
+		*out = new(SolrIngressTLSTermination)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalAddressability.
@@ -1017,6 +1022,21 @@
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SolrIngressTLSTermination) DeepCopyInto(out *SolrIngressTLSTermination) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SolrIngressTLSTermination.
+func (in *SolrIngressTLSTermination) DeepCopy() *SolrIngressTLSTermination {
+	if in == nil {
+		return nil
+	}
+	out := new(SolrIngressTLSTermination)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SolrNodeStatus) DeepCopyInto(out *SolrNodeStatus) {
 	*out = *in
 }
diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml b/config/crd/bases/solr.apache.org_solrclouds.yaml
index d26e086..d0607e3 100644
--- a/config/crd/bases/solr.apache.org_solrclouds.yaml
+++ b/config/crd/bases/solr.apache.org_solrclouds.yaml
@@ -4860,8 +4860,19 @@
                       hideNodes:
                         description: Do not expose each of the Solr Node services externally. The number of services this affects could range from 1 (a headless service for ExternalDNS) to the number of Solr pods your cloud contains (individual node services for Ingress/LoadBalancer). Defaults to false.
                         type: boolean
+                      ingressTLSTermination:
+                        description: "IngressTLSTermination tells the SolrCloud Ingress to terminate TLS on incoming connections. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS."
+                        maxProperties: 1
+                        properties:
+                          tlsSecret:
+                            description: TLSSecret defines a TLS Secret to use for TLS termination of all exposed addresses for this SolrCloud in the Ingress.
+                            type: string
+                          useDefaultTLSSecret:
+                            description: "UseDefaultTLSSecret determines whether the ingress should use the default TLS secret provided by the Ingress implementation. \n For example, using nginx: https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-ssl-certificate"
+                            type: boolean
+                        type: object
                       ingressTLSTerminationSecret:
-                        description: "IngressTLSTerminationSecret defines a TLS Secret to use for TLS termination of all exposed addresses in the ingress. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS."
+                        description: "IngressTLSTerminationSecret defines a TLS Secret to use for TLS termination of all exposed addresses in the ingress. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS. \n DEPRECATED: Use ingressTLSTermination.tlsSecret instead"
                         type: string
                       method:
                         description: The way in which this SolrCloud's service(s) should be made addressable externally.
diff --git a/controllers/solrcloud_controller.go b/controllers/solrcloud_controller.go
index 89fbd06..c10a8de 100644
--- a/controllers/solrcloud_controller.go
+++ b/controllers/solrcloud_controller.go
@@ -100,7 +100,7 @@
 		return reconcile.Result{}, err
 	}
 
-	changed := instance.WithDefaults()
+	changed := instance.WithDefaults(logger)
 	if changed {
 		logger.Info("Setting default settings for SolrCloud")
 		if err = r.Update(ctx, instance); err != nil {
diff --git a/controllers/solrcloud_controller_backup_test.go b/controllers/solrcloud_controller_backup_test.go
index e70fe5c..46429cb 100644
--- a/controllers/solrcloud_controller_backup_test.go
+++ b/controllers/solrcloud_controller_backup_test.go
@@ -55,7 +55,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_basic_auth_test.go b/controllers/solrcloud_controller_basic_auth_test.go
index 05594a5..4305b3f 100644
--- a/controllers/solrcloud_controller_basic_auth_test.go
+++ b/controllers/solrcloud_controller_basic_auth_test.go
@@ -63,7 +63,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_externaldns_test.go b/controllers/solrcloud_controller_externaldns_test.go
index c3f5d4e..be1e922 100644
--- a/controllers/solrcloud_controller_externaldns_test.go
+++ b/controllers/solrcloud_controller_externaldns_test.go
@@ -70,7 +70,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_ingress_test.go b/controllers/solrcloud_controller_ingress_test.go
index 0f1a6c9..da20644 100644
--- a/controllers/solrcloud_controller_ingress_test.go
+++ b/controllers/solrcloud_controller_ingress_test.go
@@ -82,7 +82,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_storage_test.go b/controllers/solrcloud_controller_storage_test.go
index fbdf54d..f69351f 100644
--- a/controllers/solrcloud_controller_storage_test.go
+++ b/controllers/solrcloud_controller_storage_test.go
@@ -71,7 +71,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go
index 86d07f3..433ea9b 100644
--- a/controllers/solrcloud_controller_test.go
+++ b/controllers/solrcloud_controller_test.go
@@ -57,7 +57,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/solrcloud_controller_tls_test.go b/controllers/solrcloud_controller_tls_test.go
index 4983dd8..f07cb11 100644
--- a/controllers/solrcloud_controller_tls_test.go
+++ b/controllers/solrcloud_controller_tls_test.go
@@ -75,7 +75,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
@@ -382,11 +382,38 @@
 		tlsSecretName := "tls-cert-secret-from-user"
 		BeforeEach(func() {
 			solrCloud.Spec.SolrSecurity = &solrv1beta1.SolrSecurityOptions{AuthenticationType: solrv1beta1.Basic}
-			solrCloud.Spec.SolrAddressability.External.IngressTLSTerminationSecret = tlsSecretName
+			solrCloud.Spec.SolrAddressability.External.IngressTLSTermination = &solrv1beta1.SolrIngressTLSTermination{
+				TLSSecret: tlsSecretName,
+			}
+		})
+		FIt("has the correct resources - Explicit Secret", func() {
+			By("Checking that the Ingress will terminate TLS")
+			expectTerminateIngressTLSConfig(ctx, solrCloud, tlsSecretName, false)
+
+			By("Checking that the SolrCloud status has the correct scheme for URLs")
+			expectSolrCloudStatusWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloudStatus) {
+				g.Expect(found.InternalCommonAddress).To(Equal("http://"+solrCloud.Name+"-solrcloud-common."+solrCloud.Namespace), "Wrong internal common address in status")
+				g.Expect(found.ExternalCommonAddress).To(Not(BeNil()), "External common address in Status should not be nil.")
+				g.Expect(*found.ExternalCommonAddress).To(Equal("https://"+solrCloud.Namespace+"-"+solrCloud.Name+"-solrcloud."+testDomain), "Wrong external common address in status")
+			})
+
+			foundStatefulSet := expectStatefulSet(ctx, solrCloud, solrCloud.StatefulSetName())
+
+			By("Checking that the Service has the correct settings")
+			expectTLSService(ctx, solrCloud, foundStatefulSet.Spec.Selector.MatchLabels, false)
+		})
+	})
+
+	FContext("Common Ingress TLS Termination - Default Secret", func() {
+		BeforeEach(func() {
+			solrCloud.Spec.SolrSecurity = &solrv1beta1.SolrSecurityOptions{AuthenticationType: solrv1beta1.Basic}
+			solrCloud.Spec.SolrAddressability.External.IngressTLSTermination = &solrv1beta1.SolrIngressTLSTermination{
+				UseDefaultTLSSecret: true,
+			}
 		})
 		FIt("has the correct resources", func() {
 			By("Checking that the Ingress will terminate TLS")
-			expectTerminateIngressTLSConfig(ctx, solrCloud, tlsSecretName, false)
+			expectTerminateIngressTLSConfig(ctx, solrCloud, "", false)
 
 			By("Checking that the SolrCloud status has the correct scheme for URLs")
 			expectSolrCloudStatusWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloudStatus) {
diff --git a/controllers/solrcloud_controller_zk_test.go b/controllers/solrcloud_controller_zk_test.go
index 898a5f8..6bf4087 100644
--- a/controllers/solrcloud_controller_zk_test.go
+++ b/controllers/solrcloud_controller_zk_test.go
@@ -58,7 +58,7 @@
 
 		By("defaulting the missing SolrCloud values")
 		expectSolrCloudWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloud) {
-			g.Expect(found.WithDefaults()).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
+			g.Expect(found.WithDefaults(logger)).To(BeFalse(), "The SolrCloud spec should not need to be defaulted eventually")
 		})
 	})
 
diff --git a/controllers/suite_test.go b/controllers/suite_test.go
index 67b45fc..8d25a7f 100644
--- a/controllers/suite_test.go
+++ b/controllers/suite_test.go
@@ -19,6 +19,7 @@
 
 import (
 	zk_api "github.com/apache/solr-operator/controllers/zk_api"
+	"github.com/go-logr/logr"
 	"path/filepath"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"testing"
@@ -41,6 +42,7 @@
 // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
 
 var cfg *rest.Config
+var logger logr.Logger
 var k8sClient client.Client
 var testEnv *envtest.Environment
 
@@ -62,7 +64,8 @@
 	SetDefaultEventuallyTimeout(timeout)
 	SetDefaultEventuallyPollingInterval(interval)
 
-	logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
+	logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))
+	logf.SetLogger(logger)
 
 	By("bootstrapping test environment")
 	testEnv = &envtest.Environment{
diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go
index 31e516c..44851d0 100644
--- a/controllers/util/solr_util.go
+++ b/controllers/util/solr_util.go
@@ -921,11 +921,14 @@
 		ingressTLS = append(ingressTLS, netv1.IngressTLS{SecretName: solrCloud.Spec.SolrTLS.PKCS12Secret.Name})
 	} // else if using mountedTLSDir, it's likely they'll have an auto-wired TLS solution for Ingress as well via annotations
 
-	if extOpts.IngressTLSTerminationSecret != "" {
-		ingressTLS = append(ingressTLS, netv1.IngressTLS{
-			SecretName: extOpts.IngressTLSTerminationSecret,
-			Hosts:      allHosts,
-		})
+	if extOpts.HasIngressTLSTermination() {
+		newIngressTLS := netv1.IngressTLS{
+			Hosts: allHosts,
+		}
+		if extOpts.IngressTLSTermination.TLSSecret != "" {
+			newIngressTLS.SecretName = extOpts.IngressTLSTermination.TLSSecret
+		}
+		ingressTLS = append(ingressTLS, newIngressTLS)
 	}
 	solrNodesRequireTLS := solrCloud.Spec.SolrTLS != nil
 	ingressFrontedByTLS := len(ingressTLS) > 0
diff --git a/docs/README.md b/docs/README.md
index d2a97cb..04580d7 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -20,6 +20,7 @@
 Please visit the following pages for documentation on using and developing the Solr Operator:
 
 - [Local Tutorial](local_tutorial.md)
+- [Upgrade Notes](upgrade-notes.md)
 - [Running the Solr Operator](running-the-operator.md)
 - Available Solr Resources
     - [Solr Clouds](solr-cloud)
diff --git a/docs/solr-cloud/solr-cloud-crd.md b/docs/solr-cloud/solr-cloud-crd.md
index 2e28f36..f4dc6cf 100644
--- a/docs/solr-cloud/solr-cloud-crd.md
+++ b/docs/solr-cloud/solr-cloud-crd.md
@@ -119,11 +119,17 @@
   The goal is to support more methods in the future, such as LoadBalanced Services.
   - **`domainName`** - (Required) The primary domain name to open your cloud endpoints on. If `useExternalAddress` is set to `true`, then this is the domain that will be used in Solr Node names.
   - **`additionalDomainNames`** - You can choose to listen on additional domains for each endpoint, however Solr will not register itself under these names.
-  - **`useExternalAddress`** - Use the external address to advertise the SolrNode. If a domain name is required for the chosen external `method`, then the one provided in `domainName` will be used.
+  - **`useExternalAddress`** - Use the external address to advertise the SolrNode. If a domain name is required for the chosen external `method`, then the one provided in `domainName` will be used. \
+    This can not be set to `true` when **`hideNodes`** is set to `true` or **`ingressTLSTermination`** is used.
   - **`hideCommon`** - Do not externally expose the common service (one endpoint for all solr nodes).
   - **`hideNodes`** - Do not externally expose each node. (This cannot be set to `true` if the cloud is running across multiple kubernetes clusters)
   - **`nodePortOverride`** - Make the Node Service(s) override the podPort. This is only available for the `Ingress` external method. If `hideNodes` is set to `true`, then this option is ignored. If provided, this port will be used to advertise the Solr Node. \
-  If `method: Ingress` and `hideNodes: false`, then this value defaults to `80` since that is the default port that ingress controllers listen on.
+    If `method: Ingress` and `hideNodes: false`, then this value defaults to `80` since that is the default port that ingress controllers listen on.
+  - **`ingressTLSTermination`** - Terminate TLS for the SolrCloud at the `Ingress`, if using the `Ingress` **method**. This will leave the inter-node communication within the cluster to use HTTP. \
+    This option may not be used with **`useExternalAddress`**. Only one sub-option can be provided.
+    - **`useDefaultTLSSecret`** - Use the default TLS Secret set by your Ingress controller, if your Ingress controller supports this feature. Cannot be used when `tlsSecret` is used. \
+      For example, using nginx: https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-ssl-certificate
+    - **`tlsSecret`** - Name a of Kubernetes TLS Secret to terminate TLS when using the `Ingress` method. Cannot be used when `useDefaultTlsSecret` is used.
 
 **Note:** Unless both `external.method=Ingress` and `external.hideNodes=false`, a headless service will be used to make each Solr Node in the statefulSet addressable.
 If both of those criteria are met, then an individual ClusterIP Service will be created for each Solr Node/Pod.
@@ -623,7 +629,7 @@
 
 The Solr operator may create an Ingress for exposing Solr pods externally. When TLS is enabled, the operator adds the following annotation and TLS settings to the Ingress manifest, such as:
 ```yaml
-apiVersion: extensions/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
@@ -767,13 +773,14 @@
       method: Ingress
       hideNodes: true
       useExternalAddress: false
-      ingressTLSTerminationSecret: my-selfsigned-cert-tls
+      ingressTLSTermination:
+        tlsSecret: my-selfsigned-cert-tls
 ```
 
 The only additional settings required here are:
 - Making sure that you are not using the external TLS address for Solr to communicate internally via `useExternalAddress: false`.
   This will be ignored, even if it is set to `true`.
-- Adding a TLS secret through `ingressTLSTerminationSecret`, this is passed to the Kubernetes Ingress to handle the TLS termination.
+- Adding a TLS secret through `ingressTLSTermination.tlsSecret`, this is passed to the Kubernetes Ingress to handle the TLS termination.
   _This ensures that the only way to communicate with your Solr cluster externally is through the TLS protected common-endpoint._
 
 To generate a TLS secret, follow the [instructions above](#use-cert-manager-to-issue-the-certificate) and use the templated Hostname: `<namespace>-<name>-solrcloud.<domain>`
@@ -799,7 +806,8 @@
       method: Ingress
       hideNodes: true
       useExternalAddress: false
-      ingressTLSTerminationSecret: myingress-cert
+      ingressTLSTermination:
+        tlsSecret: myingress-cert
 ```
 
 For more information on the Ingress TLS Termination options for cert-manager, [refer to the documentation](https://cert-manager.io/docs/usage/ingress/).
diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md
index 756ac45..9380cb9 100644
--- a/docs/upgrade-notes.md
+++ b/docs/upgrade-notes.md
@@ -122,6 +122,10 @@
   In this release `additionalDomains` is still accepted, but all values will automatically be added to `additionalDomainNames` and the field will be set to `nil` by the operator.
   The `additionalDomains` option will be removed in a future version.
 
+- The SolrCloud CRD field `Spec.solrAddressability.external.ingressTLSTerminationSecret` has been moved to `Spec.solrAddressability.external.ingressTLSTermination.tlsSecret`.
+  In this release `ingressTLSTerminationSecret` is still accepted, but all values will automatically be changed to `ingressTLSTermination.tlsSecret` and the original field will be set to `nil` by the operator.
+  The `ingressTLSTerminationSecret` option will be removed in a future version.
+
 - `SolrPrometheusExporter` resources without any image specifications (`SolrPrometheusExporter.Spec.image.*`) will use the referenced `SolrCloud` image, if the reference is by `name`, not `zkConnectionString`.
   If any `SolrPrometheusExporter.Spec.image.*` option is provided, then those values will be defaulted by the Solr Operator and the `SolrCloud` image will not be used.
   When upgrading from `v0.5.*` to `v0.6.0`, only new `SolrPrometheusExporter` resources will use this new feature.
diff --git a/helm/solr-operator/Chart.yaml b/helm/solr-operator/Chart.yaml
index de5e399..28cd552 100644
--- a/helm/solr-operator/Chart.yaml
+++ b/helm/solr-operator/Chart.yaml
@@ -157,6 +157,17 @@
           url: https://github.com/apache/solr-operator/issues/376
         - name: Github PR
           url: https://github.com/apache/solr-operator/pull/455
+    - kind: changed
+      description: SolrClouds can now use the Ingress controller's default TLS Secret when terminating TLS at the Ingress. The old `ingressTLSTerminationSecret` option is now deprecated. Refer the upgrade notes for more information.
+      links:
+        - name: Github Issue
+          url: https://github.com/apache/solr-operator/issues/437
+        - name: Github PR
+          url: https://github.com/apache/solr-operator/pull/452
+        - name: Upgrade Notes
+          url: https://apache.github.io/solr-operator/docs/upgrade-notes.html#v060
+        - name: Solr Addressability Docs
+          url: https://apache.github.io/solr-operator/docs/solr-cloud/solr-cloud-crd.html#addressability
   artifacthub.io/images: |
     - name: solr-operator
       image: apache/solr-operator:v0.6.0-prerelease
diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml
index 2f68e55..164b130 100644
--- a/helm/solr-operator/crds/crds.yaml
+++ b/helm/solr-operator/crds/crds.yaml
@@ -5092,8 +5092,19 @@
                       hideNodes:
                         description: Do not expose each of the Solr Node services externally. The number of services this affects could range from 1 (a headless service for ExternalDNS) to the number of Solr pods your cloud contains (individual node services for Ingress/LoadBalancer). Defaults to false.
                         type: boolean
+                      ingressTLSTermination:
+                        description: "IngressTLSTermination tells the SolrCloud Ingress to terminate TLS on incoming connections. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS."
+                        maxProperties: 1
+                        properties:
+                          tlsSecret:
+                            description: TLSSecret defines a TLS Secret to use for TLS termination of all exposed addresses for this SolrCloud in the Ingress.
+                            type: string
+                          useDefaultTLSSecret:
+                            description: "UseDefaultTLSSecret determines whether the ingress should use the default TLS secret provided by the Ingress implementation. \n For example, using nginx: https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-ssl-certificate"
+                            type: boolean
+                        type: object
                       ingressTLSTerminationSecret:
-                        description: "IngressTLSTerminationSecret defines a TLS Secret to use for TLS termination of all exposed addresses in the ingress. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS."
+                        description: "IngressTLSTerminationSecret defines a TLS Secret to use for TLS termination of all exposed addresses in the ingress. \n This is option is only available when Method=Ingress, because ExternalDNS and LoadBalancer Services do not support TLS termination. This option is also unavailable when the SolrCloud has TLS enabled via `spec.solrTLS`, in this case the Ingress cannot terminate TLS before reaching Solr. \n When using this option, the UseExternalAddress option will be disabled, since Solr cannot be running in HTTP mode and making internal requests in HTTPS. \n DEPRECATED: Use ingressTLSTermination.tlsSecret instead"
                         type: string
                       method:
                         description: The way in which this SolrCloud's service(s) should be made addressable externally.
diff --git a/helm/solr/README.md b/helm/solr/README.md
index a6ce3e0..570eff2 100644
--- a/helm/solr/README.md
+++ b/helm/solr/README.md
@@ -143,11 +143,12 @@
 | addressability.external.method | string | | The method by which Solr should be made addressable outside of the Kubernetes cluster. Either `Ingress` or `ExternalDNS` |
 | addressability.external.domainName | string | | The base domain name that Solr nodes should be addressed under. |
 | addressability.external.additionalDomainNames | []string | | Additional base domain names that Solr nodes should be addressed under. These are not used to advertise Solr locations, just the `domainName` is. |
-| addressability.external.useExternalAddress | boolean | `false` | Make the official hostname of the SolrCloud nodes the external address. This cannot be used when `hideNodes` is set to `true` or `ingressTLSTerminationSecret` is set to `true`. |
+| addressability.external.useExternalAddress | boolean | `false` | Make the official hostname of the SolrCloud nodes the external address. This cannot be used when `hideNodes` is set to `true` or `ingressTLSTermination` is used. |
 | addressability.external.hideNodes | boolean | `false` | Do not make the individual Solr nodes addressable outside of the Kubernetes cluster. |
 | addressability.external.hideCommon | boolean | `false` | Do not make the load-balanced common Solr endpoint addressable outside of the Kubernetes cluster. |
 | addressability.external.nodePortOverride | int | | Override the port of individual Solr nodes when using the `Ingress` method. This will default to `80` if using an Ingress without TLS and `443` when using an Ingress with Solr TLS enabled (not TLS Termination described below). |
-| addressability.external.ingressTLSTerminationSecret | string | | Name of Kubernetes Secret to terminate TLS when using the `Ingress` method. |
+| addressability.external.ingressTLSTermination.tlsSecret | string | | Name a of Kubernetes TLS Secret to terminate TLS when using the `Ingress` method. Cannot be used when `useDefaultTlsSecret` is used. |
+| addressability.external.ingressTLSTermination.useDefaultTLSSecret | boolean | `false` | Use the default TLS Secret set by your Ingress controller, if your Ingress controller supports this feature. Cannot be used when `tlsSecret` is used. |
 
 ### ZK Options
 
diff --git a/helm/solr/values.yaml b/helm/solr/values.yaml
index d49ea54..c379b70 100644
--- a/helm/solr/values.yaml
+++ b/helm/solr/values.yaml
@@ -85,7 +85,9 @@
     # hideNodes: false
     # hideCommon: false
     # nodePortOverride: null
-    # ingressTLSTerminationSecret: ""
+    # ingressTLSTermination:
+    #   tlsSecret: ""
+    #   useDefaultTLSSecret: false
 
 # Specify how rolling updates should be managed for the Solr StatefulSet
 # https://apache.github.io/solr-operator/docs/solr-cloud/solr-cloud-crd.html#update-strategy