Skip to content

Commit f04a6dd

Browse files
authored
Merge pull request #483 from catpineapple/feature/dcr-mtls-support
[feature](tls) support mTLS for DCR
2 parents f7a8afa + 4c0424d commit f04a6dd

3 files changed

Lines changed: 74 additions & 1 deletion

File tree

pkg/common/utils/resource/pod.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package resource
1919

2020
import (
21+
"fmt"
2122
"strconv"
2223
"strings"
2324

@@ -543,6 +544,31 @@ func NewBaseMainContainer(dcr *v1.DorisCluster, config map[string]interface{}, c
543544
// use liveness as startup, when in debugging mode will not be killed
544545
c.StartupProbe = startupProbe(livenessPort, spec.StartTimeout, health_api_path, commands, liveProbeType)
545546
c.ReadinessProbe = readinessProbe(readnessPort, health_api_path, commands, readinessProbeType)
547+
548+
// When TLS is enabled, replace HTTPGet readiness probe with Exec curl that carries client certs.
549+
// In mTLS mode (tls_verify_mode=verify_fail_if_no_peer_cert), the HTTPS endpoint requires
550+
// client certificates. Kubernetes HTTPGet probes cannot provide client certs, so we use
551+
// an Exec probe with curl instead. This is compatible with both TLS and mTLS modes.
552+
enableTLS := GetString(config, ENABLE_TLS_KEY)
553+
if enableTLS == "true" && c.ReadinessProbe != nil && c.ReadinessProbe.HTTPGet != nil {
554+
caCert := GetString(config, TLS_CA_CERTIFICATE_PATH_KEY)
555+
clientCert := GetString(config, TLS_CERTIFICATE_PATH_KEY)
556+
clientKey := GetString(config, TLS_PRIVATE_KEY_PATH_KEY)
557+
curlCmd := fmt.Sprintf(
558+
"curl --fail --silent --output /dev/null --cacert %s --cert %s --key %s https://localhost:%d%s",
559+
caCert, clientCert, clientKey, readnessPort, health_api_path,
560+
)
561+
c.ReadinessProbe = &corev1.Probe{
562+
PeriodSeconds: 5,
563+
FailureThreshold: 3,
564+
ProbeHandler: corev1.ProbeHandler{
565+
Exec: &corev1.ExecAction{
566+
Command: []string{"bash", "-c", curlCmd},
567+
},
568+
},
569+
}
570+
}
571+
546572
c.Lifecycle = lifeCycle(prestopScript)
547573

548574
return c

pkg/controller/sub_controller/fe/prepare_modify.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/apache/doris-operator/pkg/common/utils/resource"
2626
sc "github.com/apache/doris-operator/pkg/controller/sub_controller"
2727
appv1 "k8s.io/api/apps/v1"
28+
corev1 "k8s.io/api/core/v1"
2829
"k8s.io/apimachinery/pkg/types"
2930
"k8s.io/klog/v2"
3031
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -119,7 +120,15 @@ func (fc *Controller) dropObserverBySqlClient(ctx context.Context, k8sclient cli
119120
Port: strconv.FormatInt(int64(queryPort), 10),
120121
Database: "mysql",
121122
}
122-
masterDBClient, err := mysql.NewDorisMasterSqlDB(dbConf, nil, nil)
123+
124+
// check if TLS is enabled in FE config and find the corresponding secret
125+
tlsConfig, secretName := fc.FindSecretTLSConfig(maps, targetDCR)
126+
var tlsSecret *corev1.Secret
127+
if tlsConfig != nil && secretName != "" {
128+
tlsSecret, _ = k8s.GetSecret(ctx, k8sclient, targetDCR.Namespace, secretName)
129+
}
130+
131+
masterDBClient, err := mysql.NewDorisMasterSqlDB(dbConf, tlsConfig, tlsSecret)
123132
if err != nil {
124133
klog.Errorf("NewDorisMasterSqlDB failed, get fe node connection err:%s", err.Error())
125134
return err

pkg/controller/sub_controller/sub_controller.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
dorisv1 "github.com/apache/doris-operator/api/doris/v1"
2424
utils "github.com/apache/doris-operator/pkg/common/utils"
2525
"github.com/apache/doris-operator/pkg/common/utils/k8s"
26+
"github.com/apache/doris-operator/pkg/common/utils/mysql"
2627
"github.com/apache/doris-operator/pkg/common/utils/resource"
2728
"github.com/apache/doris-operator/pkg/common/utils/set"
2829
appv1 "k8s.io/api/apps/v1"
@@ -32,6 +33,8 @@ import (
3233
"k8s.io/apimachinery/pkg/types"
3334
"k8s.io/client-go/tools/record"
3435
"k8s.io/klog/v2"
36+
"path"
37+
"path/filepath"
3538
"sigs.k8s.io/controller-runtime/pkg/client"
3639
"strconv"
3740
"strings"
@@ -280,6 +283,41 @@ func (d *SubDefaultController) CheckSecretExist(ctx context.Context, dcr *dorisv
280283
}
281284
}
282285

286+
// FindSecretTLSConfig reads TLS configuration from FE config map and returns
287+
// the TLS config and secret name for establishing TLS-enabled MySQL connections.
288+
func (d *SubDefaultController) FindSecretTLSConfig(feConfMap map[string]interface{}, dcr *dorisv1.DorisCluster) (*mysql.TLSConfig, string) {
289+
enableTLS := resource.GetString(feConfMap, resource.ENABLE_TLS_KEY)
290+
if enableTLS == "" {
291+
return nil, ""
292+
}
293+
294+
caCertFile := resource.GetString(feConfMap, resource.TLS_CA_CERTIFICATE_PATH_KEY)
295+
clientCertFile := resource.GetString(feConfMap, resource.TLS_CERTIFICATE_PATH_KEY)
296+
clientKeyFile := resource.GetString(feConfMap, resource.TLS_PRIVATE_KEY_PATH_KEY)
297+
caFileName := path.Base(caCertFile)
298+
clientCertFileName := path.Base(clientCertFile)
299+
clientKeyFileName := path.Base(clientKeyFile)
300+
301+
caCertDir := filepath.Dir(caCertFile)
302+
secretName := ""
303+
if dcr.Spec.FeSpec != nil {
304+
for _, sn := range dcr.Spec.FeSpec.Secrets {
305+
if sn.MountPath == caCertDir {
306+
secretName = sn.SecretName
307+
break
308+
}
309+
}
310+
}
311+
312+
tlsConfig := &mysql.TLSConfig{
313+
CAFileName: caFileName,
314+
ClientCertFileName: clientCertFileName,
315+
ClientKeyFileName: clientKeyFileName,
316+
}
317+
318+
return tlsConfig, secretName
319+
}
320+
283321
// CheckSharedPVC verifies two points:
284322
// 1. Whether the SharePVC exists
285323
// 2. Whether the AccessMode of the SharePVC is ReadWriteMany

0 commit comments

Comments
 (0)