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

[ASCII-2626] Add FIPS linux cipher compliance tests for agent flavor #32366

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aef35cd
Copy FIPS linux cipher compliance tests from PR 29560 and hook up e2e…
jeremy-hanna Dec 18, 2024
416bcd8
Update CODEOWNERS for new test suite
jeremy-hanna Dec 18, 2024
f704971
Use correctly flavor agentparam in e2e test
jeremy-hanna Dec 18, 2024
0796c16
Add missed ci job dependencies
jeremy-hanna Dec 18, 2024
0adbb01
Merge branch 'main' into jeremy.hanna/add-fips-compliance-e2e-tests
jeremy-hanna Jan 6, 2025
c67945a
Update e2e provisioner import to reflect main
jeremy-hanna Jan 6, 2025
50122d0
Fix import naming issue from master and update docker provisioner to …
jeremy-hanna Jan 6, 2025
8b1279b
Improve the test case and use envvar for cipher templates in fips-ser…
jeremy-hanna Jan 7, 2025
7d9f1ff
Fix linter naming issue
jeremy-hanna Jan 7, 2025
49d5a34
Fix linter issue with gofmt
jeremy-hanna Jan 7, 2025
9fd7626
use docker-compose command instead of docker compose to stop service
jeremy-hanna Jan 7, 2025
e10407d
Supply the compose file for the compose commands
jeremy-hanna Jan 7, 2025
0712ed2
Green build passing formatted compose files to fips-server service st…
jeremy-hanna Jan 7, 2025
31a700c
Use down and up instead of stop and run for fips-server service to pi…
jeremy-hanna Jan 8, 2025
8bbd4fb
Fix flag ordering with docker-compose up
jeremy-hanna Jan 8, 2025
08dd804
Merge branch 'main' into jeremy.hanna/add-fips-compliance-e2e-tests
jeremy-hanna Jan 8, 2025
285ebc8
Change compose tmpl to yaml and remove disabled FIPS tests to get gre…
jeremy-hanna Jan 8, 2025
4b9dc3d
Merge branch 'main' into jeremy.hanna/add-fips-compliance-e2e-tests
jeremy-hanna Jan 8, 2025
7443668
Run the diagnose command with GOFIPS=1
jeremy-hanna Jan 8, 2025
e29f1b6
Dont delete tests on failure for troubleshooting
jeremy-hanna Jan 9, 2025
f8b150c
Fix linter error
jeremy-hanna Jan 9, 2025
342f769
Sprintf the exec command
jeremy-hanna Jan 9, 2025
ba89b54
Merge branch 'main' into jeremy.hanna/add-fips-compliance-e2e-tests
jeremy-hanna Jan 9, 2025
61b96d1
try using the image in the compose yaml
jeremy-hanna Jan 9, 2025
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@
/test/new-e2e/tests/agent-subcommands @DataDog/agent-shared-components
/test/new-e2e/tests/containers @DataDog/container-integrations @DataDog/container-platform
/test/new-e2e/tests/discovery @DataDog/universal-service-monitoring
/test/new-e2e/tests/fips-compliance @DataDog/agent-shared-components
/test/new-e2e/tests/ha-agent @DataDog/ndm-core
/test/new-e2e/tests/language-detection @DataDog/container-intake
/test/new-e2e/tests/ndm @DataDog/ndm-core
Expand Down
16 changes: 16 additions & 0 deletions .gitlab/dev_container_deploy/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ qa_agent:
IMG_SOURCES: ${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-amd64,${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-arm64,${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-win1809-amd64,${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-winltsc2022-amd64
IMG_DESTINATIONS: agent:${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}

qa_agent_fips:
extends: .docker_publish_job_definition
stage: dev_container_deploy
rules:
- !reference [.except_mergequeue]
- !reference [.except_disable_e2e_tests]
- when: on_success
needs:
- docker_build_fips_agent7
- docker_build_fips_agent7_arm64
- docker_build_fips_agent7_windows2022_core
variables:
IMG_REGISTRIES: agent-qa
IMG_SOURCES: ${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-fips-amd64,${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-fips-arm64,${SRC_AGENT}:v${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-7-fips-winltsc2022-servercore-amd64
IMG_DESTINATIONS: agent:${CI_PIPELINE_ID}-${CI_COMMIT_SHORT_SHA}-fips

qa_agent_jmx:
extends: .docker_publish_job_definition
stage: dev_container_deploy
Expand Down
13 changes: 13 additions & 0 deletions .gitlab/e2e/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,19 @@ new-e2e-agent-subcommands:
- EXTRA_PARAMS: --run "Test(Linux|Windows)CheckSuite"
- EXTRA_PARAMS: --run "Test(Linux|Windows)RunSuite"

new-e2e-fips-compliance-test:
extends: .new_e2e_template_needs_deb_x64
needs:
- !reference [.needs_new_e2e_template]
- qa_agent_fips
- deploy_deb_testing-a7_x64
rules:
- !reference [.on_asc_or_e2e_changes]
- !reference [.manual]
variables:
TARGETS: ./tests/fips-compliance
TEAM: agent-shared-components

new-e2e-windows-service-test:
extends: .new_e2e_template
needs:
Expand Down
163 changes: 163 additions & 0 deletions test/new-e2e/tests/fips-compliance/fips_ciphers_nix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// 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 fipscompliance

import (
_ "embed"
"fmt"
"os"
"strings"
"time"

"testing"

"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e"
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments"
awsdocker "github.com/DataDog/datadog-agent/test/new-e2e/pkg/provisioners/aws/docker"

"github.com/DataDog/test-infra-definitions/components/datadog/dockeragentparams"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

type cipherTestCase struct {
cert string
cipher string
tlsMax string
want bool
}

var (
testcases = []cipherTestCase{
{cert: "ecc", cipher: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", want: true},
{cert: "ecc", cipher: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", want: true},
{cert: "ecc", cipher: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", want: false},
{cert: "ecc", cipher: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", want: false},
{cert: "ecc", cipher: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", want: false},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", want: true},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", want: true},
{cert: "rsa", cipher: "TLS_AES_128_GCM_SHA256", tlsMax: "1.3", want: true},
{cert: "rsa", cipher: "TLS_AES_256_GCM_SHA384", tlsMax: "1.3", want: true},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", want: false},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", want: false},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", want: false},
{cert: "rsa", cipher: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", want: false},
}
)

//go:embed fixtures/docker-compose.yaml
var dockerCompose string

type fipsServerSuite struct {
e2e.BaseSuite[environments.DockerHost]
}

func TestFIPSCiphersSuite(t *testing.T) {
e2e.Run(t, &fipsServerSuite{}, e2e.WithProvisioner(awsdocker.Provisioner()), e2e.WithSkipDeleteOnFailure())
}

func (v *fipsServerSuite) TestFIPSCiphersFIPSEnabled() {
var imageTag string
if os.Getenv("E2E_PIPELINE_ID") != "" && os.Getenv("CI_COMMIT_SHA") != "" {
imageTag = fmt.Sprintf("v%s-%s-7-fips-arm64", os.Getenv("E2E_PIPELINE_ID"), os.Getenv("CI_COMMIT_SHA"))
} else {
imageTag = "latest"
}

fmt.Println("ImageTag: " + imageTag)
v.UpdateEnv(
awsdocker.Provisioner(
awsdocker.WithAgentOptions(
// dockeragentparams.WithImageTag(imageTag), // "registry.ddbuild.io/ci/datadog-agent/agent:v51515213-0796c161-7-fips-arm64"),
dockeragentparams.WithImageTag("registry.ddbuild.io/ci/datadog-agent/agent:v51515213-0796c161-7-fips-arm64"),
dockeragentparams.WithExtraComposeManifest("fips-server", pulumi.String(dockerCompose)),
),
),
)

composeFiles := strings.Split(v.Env().RemoteHost.MustExecute(`docker inspect --format='{{index (index .Config.Labels "com.docker.compose.project.config_files")}}' dd-fips-server`), ",")
formattedComposeFiles := strings.Join(composeFiles, " -f ")

for _, tc := range testcases {
v.Run(fmt.Sprintf("FIPS enabled testing '%v -c %v' (should connect %v)", tc.cert, tc.cipher, tc.want), func() {

// Start the fips-server and waits for it to be ready
runFipsServer(v, tc, formattedComposeFiles)
defer stopFipsServer(v, formattedComposeFiles)

// Run diagnose to send requests and verify the server logs
runAgentDiagnose(v, formattedComposeFiles)

serverLogs := v.Env().RemoteHost.MustExecute("docker logs dd-fips-server")
if tc.want {
assert.NotContains(v.T(), serverLogs, "no cipher suite supported by both client and server")
} else {
assert.Contains(v.T(), serverLogs, "no cipher suite supported by both client and server")
}
})
}
}

func (v *fipsServerSuite) TestFIPSCiphersTLSVersion() {
v.UpdateEnv(
awsdocker.Provisioner(
awsdocker.WithAgentOptions(
dockeragentparams.WithFullImagePath("registry.ddbuild.io/ci/datadog-agent/agent:v51515213-0796c161-7-fips-arm64"),
dockeragentparams.WithExtraComposeManifest("fips-server", pulumi.String(dockerCompose)),
),
),
)

composeFiles := strings.Split(v.Env().RemoteHost.MustExecute(`docker inspect --format='{{index (index .Config.Labels "com.docker.compose.project.config_files")}}' dd-fips-server`), ",")
formattedComposeFiles := strings.Join(composeFiles, " -f ")

runFipsServer(v, cipherTestCase{cert: "rsa", tlsMax: "1.1"}, formattedComposeFiles)
defer stopFipsServer(v, formattedComposeFiles)

runAgentDiagnose(v, formattedComposeFiles)

serverLogs := v.Env().RemoteHost.MustExecute("docker logs dd-fips-server")
assert.Contains(v.T(), serverLogs, "tls: client offered only unsupported version")
}

func runFipsServer(v *fipsServerSuite, tc cipherTestCase, composeFiles string) {
require.EventuallyWithT(v.T(), func(t *assert.CollectT) {
stopFipsServer(v, composeFiles)
envvar := fmt.Sprintf("CERT=%s", tc.cert)
if tc.cipher != "" {
envvar = fmt.Sprintf(`%s CIPHER="-c %s"`, envvar, tc.cipher)
}
if tc.tlsMax != "" {
envvar = fmt.Sprintf(`%s TLS_MAX="--tls-max %s"`, envvar, tc.tlsMax)
}

_, err := v.Env().RemoteHost.Execute(fmt.Sprintf("%s docker-compose -f %s up --detach --wait --timeout 300", envvar, strings.TrimSpace(composeFiles)))
if err != nil {
v.T().Logf("Error starting fips-server: %v", err)
require.NoError(t, err)
}
assert.Nil(t, err)
}, 60*time.Second, 20*time.Second)

require.EventuallyWithT(v.T(), func(t *assert.CollectT) {
serverLogs, _ := v.Env().RemoteHost.Execute("docker logs dd-fips-server")
assert.Contains(t, serverLogs, "Server Starting...", "Server should start")
assert.Equal(t, 1, strings.Count(serverLogs, "Server Starting..."), "Server should start only once, logs from previous runs should not be present")
}, 10*time.Second, 2*time.Second)
}

func runAgentDiagnose(v *fipsServerSuite, composeFiles string) {
_ = v.Env().RemoteHost.MustExecute(fmt.Sprintf("docker-compose -f %s exec agent sh -c GOFIPS=1 DD_DD_URL=https://dd-fips-server:443 agent diagnose --include connectivity-datadog-core-endpoints --local", composeFiles))
}

func stopFipsServer(v *fipsServerSuite, composeFiles string) {
fipsContainer := v.Env().RemoteHost.MustExecute("docker container ls -a --filter name=dd-fips-server --format '{{.Names}}'")
if fipsContainer != "" {
v.Env().RemoteHost.MustExecute(fmt.Sprintf("docker-compose -f %s down fips-server", strings.TrimSpace(composeFiles)))
}
}
78 changes: 78 additions & 0 deletions test/new-e2e/tests/fips-compliance/fips_nix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 fipscompliance

import (
_ "embed"
"fmt"

"testing"

"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/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"
)

//go:embed fixtures/openssl-default.cnf
var defaultOpenSSLConfig []byte

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

func TestLinuxFIPSComplianceSuite(t *testing.T) {
e2e.Run(t, &LinuxFIPSComplianceSuite{},
e2e.WithProvisioner(awshost.ProvisionerNoFakeIntake(
awshost.WithEC2InstanceOptions(ec2.WithOS(os.UbuntuDefault)),
awshost.WithAgentOptions(agentparams.WithFlavor("datadog-fips-agent")),
)))
}

func (v *LinuxFIPSComplianceSuite) TestFIPSDefaultConfig() {
status := v.Env().RemoteHost.MustExecute("sudo GOFIPS=0 datadog-agent status")
assert.NotContains(v.T(), status, "can't enable FIPS mode for OpenSSL")
assert.Contains(v.T(), status, "Status date")

status = v.Env().RemoteHost.MustExecute("sudo GOFIPS=1 datadog-agent status")
assert.NotContains(v.T(), status, "can't enable FIPS mode for OpenSSL")
assert.Contains(v.T(), status, "Status date")
}

func (v *LinuxFIPSComplianceSuite) TestFIPSNoFIPSProvider() {
v.Env().RemoteHost.MustExecute("sudo mv /opt/datadog-agent/embedded/ssl/openssl.cnf /opt/datadog-agent/embedded/ssl/openssl.cnf.tmp")
v.Env().RemoteHost.MustExecute(fmt.Sprintf(`sudo sh -c "echo '%s' > /opt/datadog-agent/embedded/ssl/openssl.cnf"`, defaultOpenSSLConfig))

status, err := v.Env().RemoteHost.Execute("sudo GOFIPS=0 datadog-agent status")
assert.Nil(v.T(), err)
assert.Contains(v.T(), status, "Status date")

status, err = v.Env().RemoteHost.Execute("sudo GOFIPS=1 datadog-agent status")
require.NotNil(v.T(), err)
assert.Contains(v.T(), err.Error(), "can't enable FIPS mode for OpenSSL")
assert.NotContains(v.T(), status, "Status date")

v.Env().RemoteHost.MustExecute("sudo mv /opt/datadog-agent/embedded/ssl/openssl.cnf.tmp /opt/datadog-agent/embedded/ssl/openssl.cnf")
}

func (v *LinuxFIPSComplianceSuite) TestFIPSEnabledNoConfig() {
v.Env().RemoteHost.MustExecute("sudo mv /opt/datadog-agent/embedded/ssl/openssl.cnf /opt/datadog-agent/embedded/ssl/openssl.cnf.tmp")

status, err := v.Env().RemoteHost.Execute("sudo GOFIPS=0 datadog-agent status")
assert.Nil(v.T(), err)
assert.Contains(v.T(), status, "Status date")

status, err = v.Env().RemoteHost.Execute("sudo GOFIPS=1 datadog-agent status")
require.NotNil(v.T(), err)
assert.Contains(v.T(), err.Error(), "can't enable FIPS mode for OpenSSL")
assert.NotContains(v.T(), status, "Status date")

v.Env().RemoteHost.MustExecute("sudo mv /opt/datadog-agent/embedded/ssl/openssl.cnf.tmp /opt/datadog-agent/embedded/ssl/openssl.cnf")
}
16 changes: 16 additions & 0 deletions test/new-e2e/tests/fips-compliance/fixtures/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
version: "3.9"

services:
agent:
image: "registry.ddbuild.io/ci/datadog-agent/agent:v51515213-0796c161-7-fips-arm64"
environment:
GOFIPS: 1
DD_SKIP_SSL_VALIDATION: "true"

fips-server:
container_name: "dd-fips-server"
image: "ghcr.io/datadog/apps-fips-server:main"
ports:
- "443:443"
entrypoint: ["./run.sh", "${CERT:-rsa}", "${CIPHER}", "${TLS_MAX}"]
14 changes: 14 additions & 0 deletions test/new-e2e/tests/fips-compliance/fixtures/openssl-default.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1
Loading