Skip to content

Commit

Permalink
Make TLS E2E tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
dkirov-dd committed Dec 12, 2024
1 parent 2a85b00 commit ff15b22
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 94 deletions.
24 changes: 20 additions & 4 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,38 @@ jobs:
zip_url: 'https://agent-ints-python-build-sandbox.s3.eu-north-1.amazonaws.com/python-windows-combined-v3.12.6-openssl-3.0.15-openssl-3.0.9-amd64.zip'
secrets: inherit

test-tls-linux:
test-tls-linux-inactive:
uses: ./.github/workflows/test-target.yml
with:
job-name: TLS
job-name: TLS-linux-FIPS-inactive
target: tls
platform: linux
runner: '["ubuntu-22.04"]'
repo: "core"
standard: true
agent-image: "datadog/agent-dev:nicolas-guerguadj-add-fips-mode-py3"
pytest-args: "-s -k test_fips_inactive_e2e"
fips-mode: false
agent-image: "datadog/agent-dev:main-fips"
secrets: inherit

test-tls-linux-active:
uses: ./.github/workflows/test-target.yml
with:
job-name: TLS-linux-FIPS-active
target: tls
platform: linux
runner: '["ubuntu-22.04"]'
repo: "core"
standard: true
pytest-args: "-s -k test_fips_active_e2e"
fips-mode: true
agent-image: "datadog/agent-dev:main-fips"
secrets: inherit

test-tls-windows:
uses: ./.github/workflows/test-target.yml
with:
job-name: TLS
job-name: TLS-windows
target: tls
platform: windows
runner: '["windows-2022"]'
Expand Down
23 changes: 14 additions & 9 deletions .github/workflows/test-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ on:
required: false
type: string
default: ""
fips-mode:
description: "Should the agent be run in FIPS mode for e2e tests"
required: false
type: boolean
default: false

defaults:
run:
Expand Down Expand Up @@ -270,7 +275,7 @@ jobs:
# by default
if [ '${{ inputs.pytest-args }}' = '-m flaky' ]; then
set +e # Disable immediate exit
ddev env test --base --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -281,7 +286,7 @@ jobs:
fi
elif [ '${{ inputs.pytest-args }}' = '-m "not flaky"' ]; then
set +e # Disable immediate exit
ddev env test --base --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -291,7 +296,7 @@ jobs:
exit $exit_code
fi
else
ddev env test --base --new-env --junit ${{ inputs.target }} ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }} ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
fi
- name: Run E2E tests
Expand All @@ -308,7 +313,7 @@ jobs:
# by default
if [ '${{ inputs.pytest-args }}' = '-m flaky' ]; then
set +e # Disable immediate exit
ddev env test --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -319,7 +324,7 @@ jobs:
fi
elif [ '${{ inputs.pytest-args }}' = '-m "not flaky"' ]; then
set +e # Disable immediate exit
ddev env test --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --new-env --junit ${{ inputs.target }} -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -329,7 +334,7 @@ jobs:
exit $exit_code
fi
else
ddev env test --new-env --junit ${{ inputs.target }} ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --new-env --junit ${{ inputs.target }} ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
fi
- name: Run benchmarks
Expand All @@ -355,7 +360,7 @@ jobs:
# by default
if [ '${{ inputs.pytest-args }}' = '-m flaky' ]; then
set +e # Disable immediate exit
ddev env test --base --new-env --junit ${{ inputs.target }}:latest -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }}:latest -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -366,7 +371,7 @@ jobs:
fi
elif [ '${{ inputs.pytest-args }}' = '-m "not flaky"' ]; then
set +e # Disable immediate exit
ddev env test --base --new-env --junit ${{ inputs.target }}:latest -- all ${{ inputs.pytest-args }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }}:latest -- all ${{ inputs.pytest-args }}
exit_code=$?
if [ $exit_code -eq 5 ]; then
# Flaky test count can be zero, this is done to avoid pipeline failure
Expand All @@ -376,7 +381,7 @@ jobs:
exit $exit_code
fi
else
ddev env test --base --new-env --junit ${{ inputs.target }}:latest ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
ddev env test -e GOFIPS=${{ inputs.fips-mode && '1' || '0' }} --base --new-env --junit ${{ inputs.target }}:latest ${{ inputs.pytest-args != '' && format('-- all {0}', inputs.pytest-args) || '' }}
fi
- name: View trace log
Expand Down
36 changes: 36 additions & 0 deletions datadog_checks_base/datadog_checks/base/checks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import importlib
import inspect
import logging
import os
import re
import traceback
import unicodedata
Expand Down Expand Up @@ -46,6 +47,7 @@
from ..utils.agent.utils import should_profile_memory
from ..utils.common import ensure_bytes, to_native_string
from ..utils.diagnose import Diagnosis
from ..utils.fips import enable_fips
from ..utils.http import RequestsWrapper
from ..utils.limiter import Limiter
from ..utils.metadata import MetadataManager
Expand Down Expand Up @@ -307,6 +309,40 @@ def __init__(self, *args, **kwargs):
self.__formatted_tags = None
self.__logs_enabled = None

if os.environ.get("GOFIPS", "0") == "1" or self.instance.get("fips", False):
with open("/opt/datadog-agent/embedded/ssl/openssl.cnf", "r") as f:
print(f.read())
with open("/opt/datadog-agent/embedded/ssl/openssl.cnf", "w") as f:
config = """
config_diagnostics = 1
openssl_conf = openssl_init
.include /opt/datadog-agent/embedded/ssl/fipsmodule.cnf
[openssl_init]
providers = provider_sect
alg_section = algorithm_sect
[provider_sect]
fips = fips_sect
base = base_sect
[base_sect]
activate = 1
[algorithm_sect]
default_properties = fips=yes
"""
f.write(config)
print("wrote")
with open("/opt/datadog-agent/embedded/ssl/openssl.cnf", "r") as f:
print(f.read())

enable_fips(
path_to_openssl_conf="/opt/datadog-agent/embedded/ssl/openssl.cnf",
path_to_openssl_modules="/opt/datadog-agent/embedded/lib/ossl-modules",
)

def _create_metrics_pattern(self, metric_patterns, option_name):
all_patterns = metric_patterns.get(option_name, [])

Expand Down
7 changes: 6 additions & 1 deletion ddev/src/ddev/e2e/agent/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,12 @@ def start(self, *, agent_build: str, local_packages: dict[Path, str], env_vars:

if agent_build.startswith("datadog/"):
# Add a potentially missing `py` suffix for default non-RC builds
if 'rc' not in agent_build and 'py' not in agent_build and not re.match(AGENT_VERSION_REGEX, agent_build):
if (
'rc' not in agent_build
and 'py' not in agent_build
and 'fips' not in agent_build
and not re.match(AGENT_VERSION_REGEX, agent_build)
):
agent_build = f'{agent_build}-py{self.python_version[0]}'

if self.metadata.get('use_jmx') and not agent_build.endswith('-jmx'):
Expand Down
9 changes: 9 additions & 0 deletions tls/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
}


@pytest.fixture(scope="function")
def clean_fips_environment():
os.environ["GOFIPS"] = "0"
os.environ["OPENSSL_CONF"] = ""
os.environ["OPENSSL_MODULES"] = ""
yield


@pytest.fixture(scope='session')
def dd_environment(instance_e2e, mock_local_tls_dns):
with docker_run(os.path.join(HERE, 'compose', 'docker-compose.yml'), build=True, sleep=20):
Expand Down Expand Up @@ -173,6 +181,7 @@ def instance_e2e_fips():
'tls_ca_cert': CA_CERT_MOUNT_PATH,
'tls_verify': False,
'tls_validate_hostname': False,
'fips': True, # TODO: remove in favor of env var GOFIPS
}


Expand Down
4 changes: 0 additions & 4 deletions tls/tests/fips/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@ RUN chmod +x /usr/local/bin/start-server.sh

# Expose port 443
EXPOSE 443

# Run the server script
CMD ["/usr/local/bin/start-server.sh"]

1 change: 1 addition & 0 deletions tls/tests/fips/start-server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ openssl s_server \
-cert /etc/ssl/certs/server.crt \
-key /etc/ssl/private/server.key \
-cipher $CIPHER \
-no_tls1_3 \
-WWW
39 changes: 39 additions & 0 deletions tls/tests/test_fips_active_e2e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-

# (C) Datadog, Inc. 2024-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
import os
from typing import Any # noqa: F401

import pytest

from datadog_checks.tls import TLSCheck
from datadog_checks.tls.const import (
SERVICE_CHECK_CAN_CONNECT,
SERVICE_CHECK_VALIDATION,
)


@pytest.mark.e2e
def test_connection_after_fips(clean_fips_environment, dd_fips_environment, dd_agent_check, instance_e2e_fips):
"""
Test connection to the FIPS server after enabling FIPS mode.
"""
os.environ["GOFIPS"] = "1"
aggregator = dd_agent_check(instance_e2e_fips)
aggregator.assert_service_check(SERVICE_CHECK_CAN_CONNECT, status=TLSCheck.OK, count=1)
aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1)


@pytest.mark.e2e
def test_connection_after_non_fips(clean_fips_environment, dd_fips_environment, dd_agent_check, instance_e2e_non_fips):
"""
Test connection to the non-FIPS server after enabling FIPS mode.
"""
os.environ["GOFIPS"] = "1"
aggregator = dd_agent_check(instance_e2e_non_fips)
aggregator.assert_service_check(
SERVICE_CHECK_VALIDATION,
message="[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure (_ssl.c:1000)",
)
76 changes: 0 additions & 76 deletions tls/tests/test_fips_e2e.py

This file was deleted.

34 changes: 34 additions & 0 deletions tls/tests/test_fips_inactive_e2e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-

# (C) Datadog, Inc. 2024-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from typing import Any # noqa: F401

import pytest

from datadog_checks.tls import TLSCheck
from datadog_checks.tls.const import (
SERVICE_CHECK_CAN_CONNECT,
SERVICE_CHECK_VALIDATION,
)


@pytest.mark.e2e
def test_connection_before_fips(clean_fips_environment, dd_fips_environment, dd_agent_check, instance_e2e_fips):
"""
Test connection to the FIPS server before enabling FIPS mode.
"""
aggregator = dd_agent_check(instance_e2e_fips)
aggregator.assert_service_check(SERVICE_CHECK_CAN_CONNECT, status=TLSCheck.OK, count=1)
aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1)


@pytest.mark.e2e
def test_connection_before_non_fips(clean_fips_environment, dd_fips_environment, dd_agent_check, instance_e2e_non_fips):
"""
Test connection to the non-FIPS server before enabling FIPS mode.
"""
aggregator = dd_agent_check(instance_e2e_non_fips)
aggregator.assert_service_check(SERVICE_CHECK_CAN_CONNECT, status=TLSCheck.OK, count=1)
aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1)

0 comments on commit ff15b22

Please sign in to comment.