pkg/controller/elasticsearch/settings/merged_config.go (129 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.
package settings
import (
"fmt"
"path"
corev1 "k8s.io/api/core/v1"
commonv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/common/v1"
esv1 "github.com/elastic/cloud-on-k8s/v3/pkg/apis/elasticsearch/v1"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/certificates"
common "github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/settings"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/common/version"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/client"
"github.com/elastic/cloud-on-k8s/v3/pkg/controller/elasticsearch/volume"
netutil "github.com/elastic/cloud-on-k8s/v3/pkg/utils/net"
)
// the name of the ES attribute indicating the pod's current k8s node
const nodeAttrK8sNodeName = "k8s_node_name"
var nodeAttrNodeName = fmt.Sprintf("%s.%s", esv1.NodeAttr, nodeAttrK8sNodeName)
// NewMergedESConfig merges user provided Elasticsearch configuration with configuration derived from the given
// parameters. The user provided config overrides have precedence over the ECK config.
func NewMergedESConfig(
clusterName string,
ver version.Version,
ipFamily corev1.IPFamily,
httpConfig commonv1.HTTPConfig,
userConfig commonv1.Config,
esConfigFromStackConfigPolicy *common.CanonicalConfig,
remoteClusterServerEnabled, remoteClusterClientEnabled bool,
) (CanonicalConfig, error) {
userCfg, err := common.NewCanonicalConfigFrom(userConfig.Data)
if err != nil {
return CanonicalConfig{}, err
}
config := baseConfig(clusterName, ver, ipFamily, remoteClusterServerEnabled).CanonicalConfig
err = config.MergeWith(
xpackConfig(ver, httpConfig, remoteClusterServerEnabled, remoteClusterClientEnabled).CanonicalConfig,
userCfg,
esConfigFromStackConfigPolicy,
)
if err != nil {
return CanonicalConfig{}, err
}
return CanonicalConfig{config}, nil
}
// baseConfig returns the base ES configuration to apply for the given cluster
func baseConfig(clusterName string, ver version.Version, ipFamily corev1.IPFamily, remoteClusterServerEnabled bool) *CanonicalConfig {
cfg := map[string]interface{}{
// derive node name dynamically from the pod name, injected as env var
esv1.NodeName: "${" + EnvPodName + "}",
esv1.ClusterName: clusterName,
// use the DNS name as the publish host
esv1.NetworkPublishHost: netutil.IPLiteralFor("${"+EnvPodIP+"}", ipFamily),
esv1.HTTPPublishHost: "${" + EnvPodName + "}.${" + HeadlessServiceName + "}.${" + EnvNamespace + "}.svc",
esv1.NetworkHost: "0",
// allow ES to be aware of k8s node the pod is running on when allocating shards
esv1.ShardAwarenessAttributes: nodeAttrK8sNodeName,
nodeAttrNodeName: "${" + EnvNodeName + "}",
esv1.PathData: volume.ElasticsearchDataMountPath,
esv1.PathLogs: volume.ElasticsearchLogsMountPath,
}
if remoteClusterServerEnabled {
cfg[esv1.RemoteClusterEnabled] = "true"
cfg[esv1.RemoteClusterPublishHost] = "${" + EnvPodName + "}.${" + HeadlessServiceName + "}.${" + EnvNamespace + "}.svc"
cfg[esv1.RemoteClusterHost] = "0"
}
// seed hosts setting name changed starting ES 7.X
fileProvider := "file"
if ver.Major < 7 {
cfg[esv1.DiscoveryZenHostsProvider] = fileProvider
} else {
cfg[esv1.DiscoverySeedProviders] = fileProvider
// to avoid misleading error messages about the inability to connect to localhost for discovery despite us using
// file based discovery
cfg[esv1.DiscoverySeedHosts] = []string{}
}
if ver.GTE(esv1.MinReadinessPortVersion) {
cfg[esv1.ReadinessPort] = "8080"
}
return &CanonicalConfig{common.MustCanonicalConfig(cfg)}
}
// xpackConfig returns the configuration bit related to XPack settings
func xpackConfig(ver version.Version, httpCfg commonv1.HTTPConfig, remoteClusterServerEnabled, remoteClusterClientEnabled bool) *CanonicalConfig {
// enable x-pack security, including TLS
cfg := map[string]interface{}{
// x-pack security general settings
esv1.XPackSecurityEnabled: "true",
esv1.XPackSecurityAuthcReservedRealmEnabled: "false",
esv1.XPackSecurityTransportSslVerificationMode: "certificate",
// x-pack security http settings
esv1.XPackSecurityHttpSslEnabled: httpCfg.TLS.Enabled(),
esv1.XPackSecurityHttpSslKey: path.Join(volume.HTTPCertificatesSecretVolumeMountPath, certificates.KeyFileName),
esv1.XPackSecurityHttpSslCertificate: path.Join(volume.HTTPCertificatesSecretVolumeMountPath, certificates.CertFileName),
// x-pack security transport settings
esv1.XPackSecurityTransportSslEnabled: "true",
esv1.XPackSecurityTransportSslKey: path.Join(
volume.TransportCertificatesSecretVolumeMountPath,
"${POD_NAME}."+certificates.KeyFileName,
),
esv1.XPackSecurityTransportSslCertificate: path.Join(
volume.TransportCertificatesSecretVolumeMountPath,
"${POD_NAME}."+certificates.CertFileName,
),
esv1.XPackSecurityTransportSslCertificateAuthorities: []string{
path.Join(volume.TransportCertificatesSecretVolumeMountPath, certificates.CAFileName),
path.Join(volume.RemoteCertificateAuthoritiesSecretVolumeMountPath, certificates.CAFileName),
},
esv1.XPackSecurityHttpSslCertificateAuthorities: path.Join(volume.HTTPCertificatesSecretVolumeMountPath, certificates.CAFileName),
}
if remoteClusterServerEnabled {
cfg[esv1.XPackSecurityRemoteClusterServerSslKey] = path.Join(
volume.TransportCertificatesSecretVolumeMountPath,
"${POD_NAME}."+certificates.KeyFileName,
)
cfg[esv1.XPackSecurityRemoteClusterServerSslCertificate] = path.Join(
volume.TransportCertificatesSecretVolumeMountPath,
"${POD_NAME}."+certificates.CertFileName,
)
cfg[esv1.XPackSecurityRemoteClusterServerSslCertificateAuthorities] = []string{
path.Join(volume.TransportCertificatesSecretVolumeMountPath, certificates.CAFileName),
path.Join(volume.RemoteCertificateAuthoritiesSecretVolumeMountPath, certificates.CAFileName),
}
}
if remoteClusterClientEnabled {
cfg[esv1.XPackSecurityRemoteClusterClientSslKey] = true
cfg[esv1.XPackSecurityRemoteClusterClientSslCertificateAuthorities] = []string{
// Include /usr/share/elasticsearch/config/transport-certs/ca.crt to trust any additional CA in transport.tls.certificateAuthorities
path.Join(volume.TransportCertificatesSecretVolumeMountPath, certificates.CAFileName),
path.Join(volume.RemoteCertificateAuthoritiesSecretVolumeMountPath, certificates.CAFileName),
}
}
// always enable the built-in file and native internal realms for user auth, ordered as first
if ver.Major < 7 {
// 6.x syntax
cfg[esv1.XPackSecurityAuthcRealmsFile1Type] = "file"
cfg[esv1.XPackSecurityAuthcRealmsFile1Order] = -100
cfg[esv1.XPackSecurityAuthcRealmsNative1Type] = "native"
cfg[esv1.XPackSecurityAuthcRealmsNative1Order] = -99
} else {
// 7.x syntax
cfg[esv1.XPackSecurityAuthcRealmsFileFile1Order] = -100
cfg[esv1.XPackSecurityAuthcRealmsNativeNative1Order] = -99
}
if ver.GTE(version.MustParse("7.8.1")) {
cfg[esv1.XPackLicenseUploadTypes] = []string{
string(client.ElasticsearchLicenseTypeTrial), string(client.ElasticsearchLicenseTypeEnterprise),
}
}
return &CanonicalConfig{common.MustCanonicalConfig(cfg)}
}