Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagates tls cert to oneagents #433

Merged
merged 4 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions src/api/v1beta1/properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ func (dk *DynaKube) KubernetesMonitoringMode() bool {
return dk.IsActiveGateMode(string(KubeMonCapability.DisplayName)) || dk.Spec.KubernetesMonitoring.Enabled
}

func (dk *DynaKube) HasActiveGateTLS() bool {
return dk.ActiveGateMode() && dk.Spec.ActiveGate.TlsSecretName != ""
}

// ShouldAutoUpdateOneAgent returns true if the Operator should update OneAgent instances automatically.
func (dk *DynaKube) ShouldAutoUpdateOneAgent() bool {
if dk.CloudNativeFullstackMode() {
Expand Down
34 changes: 34 additions & 0 deletions src/controllers/dynakube/oneagent/daemonset/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
corev1 "k8s.io/api/core/v1"
)

const OneAgentCustomKeysPath = "/var/lib/dynatrace/oneagent/agent/customkeys"

func prepareVolumeMounts(instance *dynatracev1beta1.DynaKube) []corev1.VolumeMount {
rootMount := getRootMount()
var volumeMounts []corev1.VolumeMount
Expand All @@ -13,6 +15,10 @@ func prepareVolumeMounts(instance *dynatracev1beta1.DynaKube) []corev1.VolumeMou
volumeMounts = append(volumeMounts, getCertificateMount())
}

if instance.HasActiveGateTLS() {
volumeMounts = append(volumeMounts, getTLSMount())
}

volumeMounts = append(volumeMounts, rootMount)
return volumeMounts
}
Expand All @@ -24,6 +30,13 @@ func getCertificateMount() corev1.VolumeMount {
}
}

func getTLSMount() corev1.VolumeMount {
return corev1.VolumeMount{
Name: "tls",
MountPath: OneAgentCustomKeysPath,
}
}

func getRootMount() corev1.VolumeMount {
return corev1.VolumeMount{
Name: hostRootMount,
Expand All @@ -38,6 +51,10 @@ func prepareVolumes(instance *dynatracev1beta1.DynaKube) []corev1.Volume {
volumes = append(volumes, getCertificateVolume(instance))
}

if instance.HasActiveGateTLS() {
volumes = append(volumes, getTLSVolume(instance))
}

return volumes
}

Expand All @@ -60,6 +77,23 @@ func getCertificateVolume(instance *dynatracev1beta1.DynaKube) corev1.Volume {
}
}

func getTLSVolume(instance *dynatracev1beta1.DynaKube) corev1.Volume {
return corev1.Volume{
Name: "tls",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: instance.Spec.ActiveGate.TlsSecretName,
Items: []corev1.KeyToPath{
{
Key: "server.crt",
Path: "custom.pem",
},
},
},
},
}
}

func getRootVolume() corev1.Volume {
return corev1.Volume{
Name: hostRootMount,
Expand Down
22 changes: 22 additions & 0 deletions src/controllers/dynakube/oneagent/daemonset/volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,34 @@ func TestPrepareVolumes(t *testing.T) {
assert.Contains(t, volumes, getRootVolume())
assert.Contains(t, volumes, getCertificateVolume(instance))
})
t.Run(`has tls volume`, func(t *testing.T) {
instance := &dynatracev1beta1.DynaKube{
Spec: dynatracev1beta1.DynaKubeSpec{
TrustedCAs: testName,
ActiveGate: dynatracev1beta1.ActiveGateSpec{
Capabilities: []dynatracev1beta1.CapabilityDisplayName{
dynatracev1beta1.KubeMonCapability.DisplayName,
},
TlsSecretName: "testing",
},
},
}
volumes := prepareVolumes(instance)
assert.Contains(t, volumes, getTLSVolume(instance))
})
t.Run(`has all volumes`, func(t *testing.T) {
instance := &dynatracev1beta1.DynaKube{
Spec: dynatracev1beta1.DynaKubeSpec{
TrustedCAs: testName,
OneAgent: dynatracev1beta1.OneAgentSpec{
HostMonitoring: &dynatracev1beta1.HostMonitoringSpec{},
},
ActiveGate: dynatracev1beta1.ActiveGateSpec{
Capabilities: []dynatracev1beta1.CapabilityDisplayName{
dynatracev1beta1.KubeMonCapability.DisplayName,
},
TlsSecretName: "testing",
},
},
}
dsInfo := HostMonitoring{
Expand All @@ -52,5 +73,6 @@ func TestPrepareVolumes(t *testing.T) {

assert.Contains(t, volumes, getRootVolume())
assert.Contains(t, volumes, getCertificateVolume(instance))
assert.Contains(t, volumes, getTLSVolume(instance))
})
}
16 changes: 16 additions & 0 deletions src/initgeneration/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package initgeneration

import (
_ "embed"
"text/template"

"github.com/Dynatrace/dynatrace-operator/src/logger"
)

var (
log = logger.NewDTLogger().WithName("initgeneration")

//go:embed init.sh.tmpl
scriptContent string
scriptTmpl = template.Must(template.New("initScript").Parse(scriptContent))
)

const (
notMappedIM = "-"
trustedCASecretField = "certs"
proxyInitSecretField = "proxy"
trustedCAInitSecretField = "ca.pem"
initScriptSecretField = "init.sh"
tlsCertKey = "server.crt"
)
8 changes: 8 additions & 0 deletions src/initgeneration/init.sh.test-sample
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ custom_ca="true"
fail_code=0
cluster_id="42"
has_host="true"
tls_cert="testing"

declare -A im_nodes
im_nodes=(
Expand Down Expand Up @@ -155,6 +156,12 @@ createConfigurationFilesDataIngest() {
writeConfEnrichmentTo "/var/lib/dynatrace/enrichment" "dt_metadata"
}

propagateTLSCert() {
if [[ "${tls_cert}" != "" ]]; then
echo "${tls_cert}" > "${share_dir}/custom.pem"
fi
}

####### MAIN #######
printf "\nSetting fail code\n"
setFailCode
Expand All @@ -164,6 +171,7 @@ if [[ "${ONEAGENT_INJECTED}" == "true" ]]; then
downloadOneAgentIfNecessary
printf "\nCreating configuration files for containers\n"
createConfigurationFilesOneAgent
propagateTLSCert
fi

if [[ "${DATA_INGEST_INJECTED}" == "true" ]]; then
Expand Down
8 changes: 8 additions & 0 deletions src/initgeneration/init.sh.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ custom_ca="{{if .TrustedCAs}}true{{else}}false{{end}}"
fail_code=0
cluster_id="{{.ClusterID}}"
has_host="{{.HasHost}}"
tls_cert="{{.TlsCert}}"

declare -A im_nodes
im_nodes=(
Expand Down Expand Up @@ -156,6 +157,12 @@ createConfigurationFilesDataIngest() {
writeConfEnrichmentTo "/var/lib/dynatrace/enrichment" "dt_metadata"
}

propagateTLSCert() {
if [[ "${tls_cert}" != "" ]]; then
echo "${tls_cert}" > "${share_dir}/custom.pem"
fi
}

####### MAIN #######
printf "\nSetting fail code\n"
setFailCode
Expand All @@ -165,6 +172,7 @@ if [[ "${ONEAGENT_INJECTED}" == "true" ]]; then
downloadOneAgentIfNecessary
printf "\nCreating configuration files for containers\n"
createConfigurationFilesOneAgent
propagateTLSCert
fi

if [[ "${DATA_INGEST_INJECTED}" == "true" ]]; then
Expand Down
27 changes: 11 additions & 16 deletions src/initgeneration/initgeneration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package initgeneration
import (
"bytes"
"context"
_ "embed"
"fmt"
"text/template"

dynatracev1beta1 "github.com/Dynatrace/dynatrace-operator/src/api/v1beta1"
"github.com/Dynatrace/dynatrace-operator/src/dtclient"
Expand All @@ -20,20 +18,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
notMappedIM = "-"
trustedCASecretField = "certs"
proxyInitSecretField = "proxy"
trustedCAInitSecretField = "ca.pem"
initScriptSecretField = "init.sh"
)

var (
//go:embed init.sh.tmpl
scriptContent string
scriptTmpl = template.Must(template.New("initScript").Parse(scriptContent))
)

// InitGenerator manages the init secret generation for the user namespaces.
type InitGenerator struct {
client client.Client
Expand All @@ -58,6 +42,7 @@ type script struct {
TenantUUID string
IMNodes map[string]string
HasHost bool
TlsCert string
}

func NewInitGenerator(client client.Client, apiReader client.Reader, ns string) *InitGenerator {
Expand Down Expand Up @@ -159,6 +144,15 @@ func (g *InitGenerator) prepareScriptForDynaKube(dk *dynatracev1beta1.DynaKube,
trustedCAs = []byte(cam.Data[trustedCASecretField])
}

var tlsCert string
if dk.HasActiveGateTLS() {
var tlsSecret corev1.Secret
if err := g.client.Get(context.TODO(), client.ObjectKey{Name: dk.Spec.ActiveGate.TlsSecretName, Namespace: g.namespace}, &tlsSecret); err != nil {
return nil, fmt.Errorf("failed to query tls secret: %w", err)
}
tlsCert = string(tlsSecret.Data[tlsCertKey])
}

return &script{
ApiUrl: dk.Spec.APIURL,
SkipCertCheck: dk.Spec.SkipCertCheck,
Expand All @@ -169,6 +163,7 @@ func (g *InitGenerator) prepareScriptForDynaKube(dk *dynatracev1beta1.DynaKube,
TenantUUID: dk.Status.ConnectionInfo.TenantUUID,
IMNodes: infraMonitoringNodes,
HasHost: dk.CloudNativeFullstackMode(),
TlsCert: tlsCert,
}, nil
}

Expand Down
18 changes: 15 additions & 3 deletions src/initgeneration/initgeneration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ var (
},
},
}},
ActiveGate: dynatracev1beta1.ActiveGateSpec{
Capabilities: []dynatracev1beta1.CapabilityDisplayName{
dynatracev1beta1.KubeMonCapability.DisplayName,
},
TlsSecretName: "testing",
},
},
Status: dynatracev1beta1.DynaKubeStatus{
ConnectionInfo: dynatracev1beta1.ConnectionInfoStatus{
Expand Down Expand Up @@ -125,6 +131,11 @@ var (
Data: map[string][]byte{"apiToken": []byte("42")},
}

testTlsSecretDynakubeComplex = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "testing", Namespace: operatorNamespace},
Data: map[string][]byte{tlsCertKey: []byte("testing")},
}

testSecretDynakubeSimple = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: testDynakubeSimpleName, Namespace: operatorNamespace},
Data: map[string][]byte{"paasToken": []byte("42"), "apiToken": []byte("84")},
Expand Down Expand Up @@ -158,7 +169,7 @@ func TestGenerateForNamespace(t *testing.T) {
Labels: map[string]string{mapper.InstanceLabel: testDynakubeComplex.Name},
},
}
clt := fake.NewClient(testDynakubeComplex, &testNamespace, testSecretDynakubeComplex, kubeNamespace, caConfigMap, testNode1, testNode2)
clt := fake.NewClient(testDynakubeComplex, &testNamespace, testSecretDynakubeComplex, kubeNamespace, caConfigMap, testTlsSecretDynakubeComplex, testNode1, testNode2)
ig := NewInitGenerator(clt, clt, operatorNamespace)

_, err := ig.GenerateForNamespace(context.TODO(), *testDynakubeComplex, testNamespace.Name)
Expand Down Expand Up @@ -210,7 +221,7 @@ func TestGenerateForDynakube(t *testing.T) {
Labels: map[string]string{mapper.InstanceLabel: testDynakubeComplex.Name},
},
}
clt := fake.NewClient(&testNamespace, testSecretDynakubeComplex, kubeNamespace, caConfigMap, testNode1, testNode2)
clt := fake.NewClient(&testNamespace, testSecretDynakubeComplex, kubeNamespace, caConfigMap, testTlsSecretDynakubeComplex, testNode1, testNode2)
ig := NewInitGenerator(clt, clt, operatorNamespace)

updated, err := ig.GenerateForDynakube(context.TODO(), dk)
Expand Down Expand Up @@ -340,7 +351,7 @@ func testForCorrectContent(t *testing.T, secret *corev1.Secret) {
Labels: map[string]string{mapper.InstanceLabel: testDynakubeComplex.Name},
},
}
clt := fake.NewClient(&testNamespace, secret, caConfigMap)
clt := fake.NewClient(&testNamespace, secret, caConfigMap, testTlsSecretDynakubeComplex)
ig := NewInitGenerator(clt, clt, operatorNamespace)
imNodes := map[string]string{testNode1Name: testTenantUUID, testNode2Name: testTenantUUID}
sc, err := ig.prepareScriptForDynaKube(dk, kubesystemUID, imNodes)
Expand All @@ -355,6 +366,7 @@ func testForCorrectContent(t *testing.T, secret *corev1.Secret) {
TenantUUID: dk.Status.ConnectionInfo.TenantUUID,
IMNodes: imNodes,
HasHost: true,
TlsCert: "testing",
}
assert.Equal(t, &expectedScript, sc)

Expand Down
18 changes: 14 additions & 4 deletions src/webhook/mutation/pod_mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"

dynatracev1beta1 "github.com/Dynatrace/dynatrace-operator/src/api/v1beta1"
dtcsi "github.com/Dynatrace/dynatrace-operator/src/controllers/csi"
oneagent "github.com/Dynatrace/dynatrace-operator/src/controllers/dynakube/oneagent/daemonset"
"github.com/Dynatrace/dynatrace-operator/src/deploymentmetadata"
"github.com/Dynatrace/dynatrace-operator/src/dtclient"
dtingestendpoint "github.com/Dynatrace/dynatrace-operator/src/ingestendpoint"
Expand Down Expand Up @@ -687,7 +689,7 @@ func updateInstallContainerOneAgent(ic *corev1.Container, number int, name strin
}

// updateContainerOA sets missing preload Variables
func updateContainerOneAgent(c *corev1.Container, oa *dynatracev1beta1.DynaKube, pod *corev1.Pod, deploymentMetadata *deploymentmetadata.DeploymentMetadata) {
func updateContainerOneAgent(c *corev1.Container, dk *dynatracev1beta1.DynaKube, pod *corev1.Pod, deploymentMetadata *deploymentmetadata.DeploymentMetadata) {

podLog.Info("updating container with missing preload variables", "containerName", c.Name)
installPath := kubeobjects.GetField(pod.Annotations, dtwebhook.AnnotationInstallPath, dtwebhook.DefaultInstallPath)
Expand All @@ -709,14 +711,22 @@ func updateContainerOneAgent(c *corev1.Container, oa *dynatracev1beta1.DynaKube,
MountPath: "/var/lib/dynatrace/oneagent/agent/config/container.conf",
SubPath: fmt.Sprintf("container_%s.conf", c.Name),
})
if dk.HasActiveGateTLS() {
c.VolumeMounts = append(c.VolumeMounts,
corev1.VolumeMount{
Name: oneAgentShareVolumeName,
MountPath: filepath.Join(oneagent.OneAgentCustomKeysPath, "custom.pem"),
SubPath: "custom.pem",
})
}

c.Env = append(c.Env,
corev1.EnvVar{
Name: "LD_PRELOAD",
Value: installPath + "/agent/lib64/liboneagentproc.so",
})

if oa.Spec.Proxy != nil && (oa.Spec.Proxy.Value != "" || oa.Spec.Proxy.ValueFrom != "") {
if dk.Spec.Proxy != nil && (dk.Spec.Proxy.Value != "" || dk.Spec.Proxy.ValueFrom != "") {
c.Env = append(c.Env,
corev1.EnvVar{
Name: "DT_PROXY",
Expand All @@ -731,8 +741,8 @@ func updateContainerOneAgent(c *corev1.Container, oa *dynatracev1beta1.DynaKube,
})
}

if oa.Spec.NetworkZone != "" {
c.Env = append(c.Env, corev1.EnvVar{Name: "DT_NETWORK_ZONE", Value: oa.Spec.NetworkZone})
if dk.Spec.NetworkZone != "" {
c.Env = append(c.Env, corev1.EnvVar{Name: "DT_NETWORK_ZONE", Value: dk.Spec.NetworkZone})
}

}
Expand Down