mirror of
https://github.com/prometheus-operator/prometheus-operator.git
synced 2025-04-13 15:56:28 +00:00
300 lines
10 KiB
Go
300 lines
10 KiB
Go
// Copyright 2024 The prometheus-operator Authors
|
|
//
|
|
// Licensed 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 clustertlsconfig
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
v1 "k8s.io/api/core/v1"
|
|
"k8s.io/utils/ptr"
|
|
|
|
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
|
webconfig "github.com/prometheus-operator/prometheus-operator/pkg/webconfig"
|
|
)
|
|
|
|
const (
|
|
cmdflag = "cluster.tls-config"
|
|
volumeName = "cluster-tls-config"
|
|
serverVolumePrefix = "cluster-tls-server-config-"
|
|
clientVolumePrefix = "cluster-tls-client-config-"
|
|
serverTLSCredDir = "server_tls"
|
|
clientTLSCredDir = "client_tls"
|
|
ConfigFileKey = "cluster-tls-config.yaml"
|
|
)
|
|
|
|
// Config is the web configuration for prometheus and alertmanager instance.
|
|
//
|
|
// Config can make a secret which holds the web config contents, as well as
|
|
// volumes and volume mounts for referencing the secret and the
|
|
// necessary TLS credentials.
|
|
type Config struct {
|
|
clusterTLSConfig *monitoringv1.ClusterTLSConfig
|
|
serverTLSReferences *webconfig.TLSReferences
|
|
clientTLSReferences *webconfig.TLSReferences
|
|
mountingDir string
|
|
secretName string
|
|
}
|
|
|
|
// New creates a new ClusterTLSConfig.
|
|
// All volumes related to the cluster TLS config will be mounted via the `mountingDir`.
|
|
// The Secret where the cluster TLS config will be stored will be named `secretName`.
|
|
// All volumes containing TLS credentials related to cluster TLS configuration will be prefixed with "cluster-tls-server-config-"
|
|
// or "cluster-tls-client-config-" respectively, for server and client credentials.
|
|
func New(mountingDir string, secretName string, clusterTLSConfig *monitoringv1.ClusterTLSConfig) (*Config, error) {
|
|
if clusterTLSConfig == nil {
|
|
return &Config{
|
|
mountingDir: mountingDir,
|
|
secretName: secretName,
|
|
}, nil
|
|
}
|
|
|
|
var (
|
|
clientTLSCreds *webconfig.TLSReferences
|
|
serverTLSCreds *webconfig.TLSReferences
|
|
)
|
|
|
|
serverTLSConfig := clusterTLSConfig.ServerTLS
|
|
if err := serverTLSConfig.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
clientTLSConfig := clusterTLSConfig.ClientTLS
|
|
if err := clientTLSConfig.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serverTLSCreds = webconfig.NewTLSReferences(path.Join(mountingDir, serverTLSCredDir), serverTLSConfig.KeySecret, serverTLSConfig.Cert, serverTLSConfig.ClientCA)
|
|
clientTLSCreds = webconfig.NewTLSReferences(path.Join(mountingDir, clientTLSCredDir), *clientTLSConfig.KeySecret, clientTLSConfig.Cert, clientTLSConfig.CA)
|
|
|
|
return &Config{
|
|
clusterTLSConfig: clusterTLSConfig,
|
|
serverTLSReferences: serverTLSCreds,
|
|
clientTLSReferences: clientTLSCreds,
|
|
mountingDir: mountingDir,
|
|
secretName: secretName,
|
|
}, nil
|
|
}
|
|
|
|
// GetMountParameters returns volumes and volume mounts referencing the cluster TLS config file
|
|
// and the associated TLS credentials.
|
|
// In addition, GetMountParameters returns a cluster.tls-config command line option pointing
|
|
// to the cluster TLS config file in the volume mount.
|
|
// All TLS credentials related to cluster TLS configuration will be prefixed with "cluster-tls-server-config-"
|
|
// or "cluster-tls-client-config-" respectively, for server and client credentials.
|
|
// The server and client TLS credentials are mounted in different paths: ~/{mountingDir}/server-tls/
|
|
// and ~/{mountingDir}/client-tls/ respectively.
|
|
func (c Config) GetMountParameters() (*monitoringv1.Argument, []v1.Volume, []v1.VolumeMount, error) {
|
|
destinationPath := path.Join(c.mountingDir, ConfigFileKey)
|
|
|
|
var volumes []v1.Volume
|
|
var mounts []v1.VolumeMount
|
|
var arg *monitoringv1.Argument
|
|
|
|
// Only return an argument if the cluster TLS config and it's server component are defined.
|
|
if c.clusterTLSConfig != nil {
|
|
arg = c.makeArg(destinationPath)
|
|
}
|
|
cfgVolume := c.makeVolume()
|
|
volumes = append(volumes, cfgVolume)
|
|
|
|
cfgMount := c.makeVolumeMount(destinationPath)
|
|
mounts = append(mounts, cfgMount)
|
|
|
|
if c.serverTLSReferences != nil {
|
|
servertlsVolumes, servertlsMounts, err := c.serverTLSReferences.GetMountParameters(serverVolumePrefix)
|
|
if err != nil {
|
|
return &monitoringv1.Argument{}, nil, nil, err
|
|
}
|
|
volumes = append(volumes, servertlsVolumes...)
|
|
mounts = append(mounts, servertlsMounts...)
|
|
}
|
|
|
|
if c.clientTLSReferences != nil {
|
|
clienttlsVolumes, clienttlsMounts, err := c.clientTLSReferences.GetMountParameters(clientVolumePrefix)
|
|
if err != nil {
|
|
return &monitoringv1.Argument{}, nil, nil, err
|
|
}
|
|
volumes = append(volumes, clienttlsVolumes...)
|
|
mounts = append(mounts, clienttlsMounts...)
|
|
}
|
|
|
|
return arg, volumes, mounts, nil
|
|
}
|
|
|
|
// CreateOrUpdateConfigSecret create or update a Kubernetes secret with the data for the cluster TLS config file.
|
|
// The format of the cluster TLS config file is available in the official prometheus documentation:
|
|
// https://github.com/prometheus/alertmanager/blob/main/docs/https.md#gossip-traffic/
|
|
func (c Config) ClusterTLSConfiguration() ([]byte, error) {
|
|
if c.clusterTLSConfig == nil {
|
|
return []byte{}, nil
|
|
}
|
|
data, err := c.generateConfigFileContents()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// generateConfigFileContents() generates the contents of cluster-tls-config.yaml
|
|
// from the Config in the form of an array of bytes.
|
|
func (c Config) generateConfigFileContents() ([]byte, error) {
|
|
cfg := yaml.MapSlice{}
|
|
|
|
cfg = c.addServerTLSConfigToYaml(cfg)
|
|
cfg = c.addClientTLSConfigToYaml(cfg)
|
|
|
|
return yaml.Marshal(cfg)
|
|
}
|
|
|
|
// makeArg() returns an argument with the name "cluster.tls-config" with the filePath
|
|
// as its value.
|
|
func (c Config) makeArg(filePath string) *monitoringv1.Argument {
|
|
return &monitoringv1.Argument{Name: cmdflag, Value: filePath}
|
|
}
|
|
|
|
// makeVolume() creates a Volume with volumeName = "cluster-tls-config" which stores
|
|
// the secret which contains the cluster TLS config.
|
|
func (c Config) makeVolume() v1.Volume {
|
|
return v1.Volume{
|
|
Name: volumeName,
|
|
VolumeSource: v1.VolumeSource{
|
|
Secret: &v1.SecretVolumeSource{
|
|
SecretName: c.secretName,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// makeVolumeMount() creates a VolumeMount, mounting the cluster_tls_config.yaml SubPath
|
|
// to the given filePath.
|
|
func (c Config) makeVolumeMount(filePath string) v1.VolumeMount {
|
|
return v1.VolumeMount{
|
|
Name: volumeName,
|
|
SubPath: ConfigFileKey,
|
|
ReadOnly: true,
|
|
MountPath: filePath,
|
|
}
|
|
}
|
|
|
|
func (c Config) GetSecretName() string {
|
|
return c.secretName
|
|
}
|
|
|
|
func (c Config) addServerTLSConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
|
|
tls := c.clusterTLSConfig.ServerTLS
|
|
|
|
mtlsServerConfig := yaml.MapSlice{}
|
|
tlsRefs := c.serverTLSReferences
|
|
|
|
switch {
|
|
case ptr.Deref(tls.KeyFile, "") != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "key_file", Value: *tls.KeyFile})
|
|
case tlsRefs.GetKeyMountPath() != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "key_file", Value: filepath.Join(tlsRefs.GetKeyMountPath(), tlsRefs.GetKeyFilename())})
|
|
}
|
|
|
|
switch {
|
|
case ptr.Deref(tls.CertFile, "") != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "cert_file", Value: *tls.CertFile})
|
|
case tlsRefs.GetCertMountPath() != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "cert_file", Value: filepath.Join(tlsRefs.GetCertMountPath(), tlsRefs.GetCertFilename())})
|
|
}
|
|
|
|
if ptr.Deref(tls.ClientAuthType, "") != "" {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "client_auth_type",
|
|
Value: *tls.ClientAuthType,
|
|
})
|
|
}
|
|
|
|
switch {
|
|
case ptr.Deref(tls.ClientCAFile, "") != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: *tls.ClientCAFile})
|
|
case tlsRefs.GetCAMountPath() != "":
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{Key: "client_ca_file", Value: filepath.Join(tlsRefs.GetCAMountPath(), tlsRefs.GetCAFilename())})
|
|
}
|
|
|
|
if ptr.Deref(tls.MinVersion, "") != "" {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "min_version",
|
|
Value: *tls.MinVersion,
|
|
})
|
|
}
|
|
|
|
if ptr.Deref(tls.MaxVersion, "") != "" {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "max_version",
|
|
Value: *tls.MaxVersion,
|
|
})
|
|
}
|
|
|
|
if len(tls.CipherSuites) != 0 {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "cipher_suites",
|
|
Value: tls.CipherSuites,
|
|
})
|
|
}
|
|
|
|
if tls.PreferServerCipherSuites != nil {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "prefer_server_cipher_suites",
|
|
Value: tls.PreferServerCipherSuites,
|
|
})
|
|
}
|
|
|
|
if len(tls.CurvePreferences) != 0 {
|
|
mtlsServerConfig = append(mtlsServerConfig, yaml.MapItem{
|
|
Key: "curve_preferences",
|
|
Value: tls.CurvePreferences,
|
|
})
|
|
}
|
|
|
|
return append(cfg, yaml.MapItem{Key: "tls_server_config", Value: mtlsServerConfig})
|
|
}
|
|
|
|
func (c Config) addClientTLSConfigToYaml(cfg yaml.MapSlice) yaml.MapSlice {
|
|
tls := c.clusterTLSConfig.ClientTLS
|
|
|
|
mtlsClientConfig := yaml.MapSlice{}
|
|
tlsRefs := c.clientTLSReferences
|
|
|
|
if keyPath := tlsRefs.GetKeyMountPath(); keyPath != "" {
|
|
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "key_file", Value: fmt.Sprintf("%s/%s", keyPath, tlsRefs.GetKeyFilename())})
|
|
}
|
|
|
|
if certPath := tlsRefs.GetCertMountPath(); certPath != "" {
|
|
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "cert_file", Value: fmt.Sprintf("%s/%s", certPath, tlsRefs.GetCertFilename())})
|
|
}
|
|
|
|
if caPath := tlsRefs.GetCAMountPath(); caPath != "" {
|
|
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "ca_file", Value: fmt.Sprintf("%s/%s", caPath, tlsRefs.GetCAFilename())})
|
|
}
|
|
|
|
if serverName := tls.ServerName; serverName != nil {
|
|
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{Key: "server_name", Value: serverName})
|
|
}
|
|
|
|
if tls.InsecureSkipVerify != nil {
|
|
mtlsClientConfig = append(mtlsClientConfig, yaml.MapItem{
|
|
Key: "insecure_skip_verify",
|
|
Value: tls.InsecureSkipVerify,
|
|
})
|
|
}
|
|
|
|
return append(cfg, yaml.MapItem{Key: "tls_client_config", Value: mtlsClientConfig})
|
|
}
|