Skip to content

Commit

Permalink
[ASCII-2641] adding e2e test to check that IPC cert is used by the Ag…
Browse files Browse the repository at this point in the history
…ent IPC servers (#32570)
  • Loading branch information
misteriaud authored Jan 29, 2025
1 parent cb18ab6 commit 88a6d21
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/api/security/cert/cert_getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func fetchAgentIPCCert(config configModel.Reader, certCreationAllowed bool) ([]b
return nil, nil, fmt.Errorf("unable to read authentication IPC cert/key files: %s", e.Error())
}

// Demultiplexing cert and key from file
// Reading and decoding cert and key from file
var block *pem.Block

block, rest := pem.Decode(certAndKey)
Expand Down
7 changes: 7 additions & 0 deletions test/new-e2e/tests/agent-shared-components/ipc/docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

// Package ipc contains e2e tests for check security aroung IPC communications.
package ipc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
log_level: debug
ipc_cert_file_path: {{.IPCCertFilePath}}

cmd_port: {{.AgentCMDPort}}
agent_ipc:
port: {{.AgentIpcPort}}

apm_config:
enabled: true
debug:
port: {{.ApmCmdPort}}

security_agent:
cmd_port: {{.SecurityCmdPort}}

process_config:
process_collection:
enabled: true
cmd_port: {{.ProcessCmdPort}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
runtime_security_config:
enabled: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

package ipc

import (
"bytes"
"crypto/tls"
"crypto/x509"
_ "embed"
"fmt"
"html/template"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/DataDog/datadog-agent/test/new-e2e/pkg/components"
)

const (
coreCMDPort = 5001
coreIPCPort = 5004
securityCmdPort = 5010
apmCmdPort = 5012
apmReceiverPort = 8126
processCmdPort = 6162
configRefreshIntervalSec = 10
)

//go:embed fixtures/config.yaml.tmpl
var coreConfigTmpl string

//go:embed fixtures/security-agent.yaml
var securityAgentConfig string

type endpoint struct {
name string
port int
}

// assertAgentUseCert checks that all agents IPC server use the IPC certificate.
func assertAgentUseCert(t *assert.CollectT, host *components.RemoteHost, certPool *x509.CertPool) {
client := host.NewHTTPClient()

tr := client.Transport.(*http.Transport).Clone()
// Reinitializing tlsConfig and replace transport
tr.TLSClientConfig = &tls.Config{}
client.Transport = tr

//Assert that it's not working if the IPC cert is not set as RootCA
_, err := client.Get(fmt.Sprintf("https://127.0.0.1:%d", coreCMDPort)) // nolint: bodyclose
require.Error(t, err)

// Setting IPC certificate as Root CA
tr.TLSClientConfig.RootCAs = certPool

for _, endpoint := range []endpoint{
{"coreCMD", coreCMDPort},
{"coreIPC", coreIPCPort},
{"securityAgent", securityCmdPort},
{"traceAgentDebug", apmCmdPort},
{"processAgent", processCmdPort},
} {
// Make a request to the server
resp, err := client.Get(fmt.Sprintf("https://127.0.0.1:%d", endpoint.port))
require.NoErrorf(t, err, "unable to connect to %v", endpoint.name)
defer resp.Body.Close()

require.NotNilf(t, resp.TLS, "connection to %v didn't used TLS", endpoint.name)
require.Lenf(t, resp.TLS.PeerCertificates, 1, "server of %v server multiple certficiate", endpoint.name)
}
}

// fillTmplConfig fills the template with the given variables and returns the result.
func fillTmplConfig(t *testing.T, tmplContent string, templateVars any) string {
t.Helper()

var buffer bytes.Buffer

tmpl, err := template.New("").Parse(tmplContent)
require.NoError(t, err)

err = tmpl.Execute(&buffer, templateVars)
require.NoError(t, err)

return buffer.String()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

package ipc

import (
"crypto/x509"
"encoding/pem"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/DataDog/test-infra-definitions/components/datadog/agentparams"

"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e"
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
awshost "github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners/aws/host"
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/e2e/client/agentclientparams"
)

type ipcSecurityLinuxSuite struct {
e2e.BaseSuite[environments.Host]
}

func TestIPCSecuirityLinuxSuite(t *testing.T) {
t.Parallel()
e2e.Run(t, &ipcSecurityLinuxSuite{}, e2e.WithProvisioner(awshost.Provisioner()))
}

func (v *ipcSecurityLinuxSuite) TestServersideIPCCertUsage() {
rootDir := "/tmp/" + v.T().Name()
v.Env().RemoteHost.MkdirAll(rootDir)

ipcCertFilePath := "/etc/datadog-agent/ipc_cert.pem"

// fill the config template
templateVars := map[string]interface{}{
"IPCCertFilePath": ipcCertFilePath,
"AgentCMDPort": coreCMDPort,
"ApmCmdPort": apmCmdPort,
"AgentIpcPort": coreIPCPort,
"ProcessCmdPort": processCmdPort,
"SecurityCmdPort": securityCmdPort,
}
coreconfig := fillTmplConfig(v.T(), coreConfigTmpl, templateVars)

// start the agent with that configuration
v.UpdateEnv(awshost.Provisioner(
awshost.WithAgentOptions(
agentparams.WithAgentConfig(coreconfig),
agentparams.WithSecurityAgentConfig(securityAgentConfig),
),
awshost.WithAgentClientOptions(
agentclientparams.WithTraceAgentOnPort(apmReceiverPort),
agentclientparams.WithProcessAgentOnPort(processCmdPort),
agentclientparams.WithSecurityAgentOnPort(securityCmdPort),
),
))

// get auth token
v.T().Log("Getting the IPC cert")
ipcCertContent := v.Env().RemoteHost.MustExecute("sudo cat " + ipcCertFilePath)

// Reading and decoding cert and key from file
var block *pem.Block

block, _ = pem.Decode([]byte(strings.TrimSpace(ipcCertContent)))
require.NotNil(v.T(), block)
require.Equal(v.T(), block.Type, "CERTIFICATE")
cert := pem.EncodeToMemory(block)

certPool := x509.NewCertPool()
ok := certPool.AppendCertsFromPEM(cert)
require.True(v.T(), ok)

// check that the Agent API server use the IPC cert
require.EventuallyWithT(v.T(), func(t *assert.CollectT) {
assertAgentUseCert(t, v.Env().RemoteHost, certPool)
}, 2*configRefreshIntervalSec*time.Second, 1*time.Second)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
package ipc

import (
"crypto/x509"
"encoding/pem"
"testing"
"time"

"github.com/DataDog/test-infra-definitions/components/datadog/agentparams"
"github.com/DataDog/test-infra-definitions/components/os"
"github.com/DataDog/test-infra-definitions/scenarios/aws/ec2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e"
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
awshost "github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners/aws/host"
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/e2e/client/agentclientparams"
)

type ipcSecurityWindowsSuite struct {
e2e.BaseSuite[environments.Host]
}

func TestIPCSecurityWindowsSuite(t *testing.T) {
t.Parallel()
e2e.Run(t, &ipcSecurityWindowsSuite{}, e2e.WithProvisioner(awshost.Provisioner(awshost.WithEC2InstanceOptions(ec2.WithOS(os.WindowsDefault)))))
}

func (v *ipcSecurityWindowsSuite) TestServersideIPCCertUsage() {
rootDir := "C:/tmp/" + v.T().Name()
v.Env().RemoteHost.MkdirAll(rootDir)

ipcCertFilePath := `C:\ProgramData\Datadog\ipc_cert.pem`

templateVars := map[string]interface{}{
"IPCCertFilePath": ipcCertFilePath,
"AgentCMDPort": coreCMDPort,
"AgentIpcPort": coreIPCPort,
"ApmCmdPort": apmCmdPort,
"ProcessCmdPort": processCmdPort,
"SecurityCmdPort": securityCmdPort,
}
coreconfig := fillTmplConfig(v.T(), coreConfigTmpl, templateVars)

agentOptions := []func(*agentparams.Params) error{
agentparams.WithAgentConfig(coreconfig),
agentparams.WithSecurityAgentConfig(securityAgentConfig),
}
// start the agent with that configuration
v.UpdateEnv(awshost.Provisioner(
awshost.WithEC2InstanceOptions(ec2.WithOS(os.WindowsDefault)),
awshost.WithAgentOptions(agentOptions...),
awshost.WithAgentClientOptions(
agentclientparams.WithTraceAgentOnPort(apmReceiverPort),
agentclientparams.WithProcessAgentOnPort(processCmdPort),
),
))

// Currently the e2e framework does not restart the security agent on Windows so we need to do it manually.
// When the framework will support it, remove the line below and add `agentclientparams.WithSecurityAgentOnPort(securityCmdPort)` to the agent options.
v.Env().RemoteHost.MustExecute("Restart-Service datadog-security-agent")

// get auth token
v.T().Log("Getting the IPC cert")
ipcCertContent, err := v.Env().RemoteHost.ReadFile(ipcCertFilePath)
require.NoError(v.T(), err)

// Reading and decoding cert and key from file
var block *pem.Block

block, _ = pem.Decode(ipcCertContent)
require.NotNil(v.T(), block)
require.Equal(v.T(), block.Type, "CERTIFICATE")
cert := pem.EncodeToMemory(block)

certPool := x509.NewCertPool()
ok := certPool.AppendCertsFromPEM(cert)
require.True(v.T(), ok)

// check that the Agent API server use the IPC cert
require.EventuallyWithT(v.T(), func(t *assert.CollectT) {
assertAgentUseCert(t, v.Env().RemoteHost, certPool)
}, 2*configRefreshIntervalSec*time.Second, 1*time.Second)
}

0 comments on commit 88a6d21

Please sign in to comment.