diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0a65113611bf7..6b446eac6ba25 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -42,6 +42,7 @@ jobs: runner: '["ubuntu-22.04"]' repo: "core" standard: true + pytest-args: "-s" agent-image: "datadog/agent-dev:nicolas-guerguadj-add-fips-mode-py3" secrets: inherit diff --git a/.github/workflows/test-target.yml b/.github/workflows/test-target.yml index 489620e36dd94..5b22fe81f45f6 100644 --- a/.github/workflows/test-target.yml +++ b/.github/workflows/test-target.yml @@ -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: bool + default: false defaults: run: @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/datadog_checks_base/datadog_checks/base/checks/base.py b/datadog_checks_base/datadog_checks/base/checks/base.py index c87b2cdb70479..046a2c2cb16f2 100644 --- a/datadog_checks_base/datadog_checks/base/checks/base.py +++ b/datadog_checks_base/datadog_checks/base/checks/base.py @@ -6,6 +6,7 @@ import importlib import inspect import logging +import os import re import traceback import unicodedata @@ -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 @@ -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, []) diff --git a/tls/tests/conftest.py b/tls/tests/conftest.py index 3b765be4b4071..4d5db5eb72131 100644 --- a/tls/tests/conftest.py +++ b/tls/tests/conftest.py @@ -173,6 +173,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 } diff --git a/tls/tests/fips/Dockerfile b/tls/tests/fips/Dockerfile index 1e666418eea4e..dbf827d8f9d66 100644 --- a/tls/tests/fips/Dockerfile +++ b/tls/tests/fips/Dockerfile @@ -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"] - diff --git a/tls/tests/fips/start-server.sh b/tls/tests/fips/start-server.sh index 825c24125c8b6..e4eb4155ce18c 100644 --- a/tls/tests/fips/start-server.sh +++ b/tls/tests/fips/start-server.sh @@ -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 diff --git a/tls/tests/test_fips_e2e.py b/tls/tests/test_fips_e2e.py index 7cf79a99577d1..b7c7ca0007589 100644 --- a/tls/tests/test_fips_e2e.py +++ b/tls/tests/test_fips_e2e.py @@ -11,9 +11,7 @@ from datadog_checks.tls import TLSCheck from datadog_checks.tls.const import ( SERVICE_CHECK_CAN_CONNECT, - SERVICE_CHECK_EXPIRATION, SERVICE_CHECK_VALIDATION, - SERVICE_CHECK_VERSION, ) @@ -32,10 +30,7 @@ def test_connection_before_fips(clean_environment, dd_fips_environment, dd_agent """ 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_VERSION, status=TLSCheck.OK, count=1) aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1) - aggregator.assert_service_check(SERVICE_CHECK_EXPIRATION, status=TLSCheck.OK, count=1) - @pytest.mark.e2e @@ -45,9 +40,7 @@ def test_connection_before_non_fips(clean_environment, dd_fips_environment, dd_a """ 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_VERSION, status=TLSCheck.OK, count=1) aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1) - aggregator.assert_service_check(SERVICE_CHECK_EXPIRATION, status=TLSCheck.OK, count=1) @pytest.mark.e2e @@ -58,9 +51,7 @@ def test_connection_after_fips(clean_environment, dd_fips_environment, dd_agent_ 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_VERSION, status=TLSCheck.OK, count=1) aggregator.assert_service_check(SERVICE_CHECK_VALIDATION, status=TLSCheck.OK, count=1) - aggregator.assert_service_check(SERVICE_CHECK_EXPIRATION, status=TLSCheck.OK, count=1) @pytest.mark.e2e @@ -72,5 +63,5 @@ def test_connection_after_non_fips(clean_environment, dd_fips_environment, dd_ag aggregator = dd_agent_check(instance_e2e_non_fips) aggregator.assert_service_check( SERVICE_CHECK_VALIDATION, - message="[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1006)", + message="[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure (_ssl.c:1000)", )