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

Add FIPS switch #19179

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
60 changes: 57 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,62 @@ concurrency:
cancel-in-progress: true

jobs:
test:
uses: ./.github/workflows/pr-test.yml
test-linux:
uses: ./.github/workflows/test-fips.yml
with:
repo: core
platform: linux
runner: '["ubuntu-22.04"]'
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-windows:
uses: ./.github/workflows/test-fips.yml
with:
platform: windows
runner: '["windows-2022"]'
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-inactive:
uses: ./.github/workflows/test-target.yml
with:
job-name: TLS
target: tls
platform: linux
runner: '["ubuntu-22.04"]'
repo: "core"
standard: true
pytest-args: "-s -k test_fips_inactive_e2e"
fips-mode: false
traces-artifact-name: traces-tls-linux-no-fips
test-results-name: test-tls-linux-no-fips
agent-image: "datadog/agent-dev:main-fips"
secrets: inherit

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

test-tls-windows:
uses: ./.github/workflows/test-target.yml
with:
job-name: TLS
target: tls
platform: windows
runner: '["windows-2022"]'
repo: "core"
standard: true
agent-image-windows: "datadog/agent-dev:main-py3-fips-win-servercore-ltsc2022"
secrets: inherit
213 changes: 213 additions & 0 deletions .github/workflows/test-fips.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
name: Test FIPS

on:
workflow_call:
inputs:
platform:
required: true
type: string
runner:
required: true
type: string
zip_url:
required: true
type: string

defaults:
run:
shell: bash

jobs:
run:
name: FIPS test on "${{ inputs.platform }}"
runs-on: ${{ fromJson(inputs.runner) }}

env:
FORCE_COLOR: "1"
DEBIAN_FRONTEND: "noninteractive"
OPENSSL_FIPS: 1
PYTHON_VERSION: "3.12"
OPENSSL_VERSION: "3.0.15"
FIPS_MODULE_VERSION: "3.0.9"

steps:

- uses: actions/checkout@v4

- name: Install System Dependencies
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install -y --no-install-recommends \
wget \
build-essential \
gcc \
make \
perl \
libc6-dev

- name: Build FIPS Module
if: runner.os == 'Linux'
run: |
wget https://www.openssl.org/source/openssl-${{ env.FIPS_MODULE_VERSION }}.tar.gz \
&& tar -xvzf openssl-${{ env.FIPS_MODULE_VERSION }}.tar.gz \
&& cd openssl-${{ env.FIPS_MODULE_VERSION }} \
&& ./Configure enable-fips \
&& make \
&& sudo make install

- name: Build OpenSSL
if: runner.os == 'Linux'
run: |
wget https://www.openssl.org/source/openssl-${{ env.OPENSSL_VERSION }}.tar.gz \
&& tar -xvzf openssl-${{ env.OPENSSL_VERSION }}.tar.gz \
&& cd openssl-${{ env.OPENSSL_VERSION }} \
&& ./Configure enable-fips \
&& make \
&& sudo make install

- name: Build Python from Source with Custom OpenSSL
if: runner.os == 'Linux'
run: |

# Install dependencies for building Python
sudo apt-get update && sudo apt-get install -y \
build-essential \
zlib1g-dev \
libffi-dev \
libssl-dev \
libncurses5-dev \
libsqlite3-dev \
libreadline-dev \
libbz2-dev \
liblzma-dev \
tk-dev \
uuid-dev \
libgdbm-dev \
wget

# Download and extract Python source
wget https://www.python.org/ftp/python/${{ env.PYTHON_VERSION }}/Python-${{ env.PYTHON_VERSION }}.tgz
tar -xvzf Python-${{ env.PYTHON_VERSION }}.tgz -C python_dir
cd python_dir

# Configure and build Python with custom OpenSSL
./configure --enable-optimizations --with-openssl=$(pwd)/../openssl-${{ env.OPENSSL_VERSION }}
make -j$(nproc)
sudo make altinstall

- name: Download python-windows-combined
if: runner.os == 'Windows'
shell: powershell
run: |
Invoke-WebRequest -Uri '${{ inputs.zip_url }}' -OutFile 'python_combined.zip'

- name: Unzip python_combined.zip
if: runner.os == 'Windows'
shell: powershell
run: |
Expand-Archive -Path python_combined.zip -DestinationPath .\python_dir

- name: Run fipsintall.exe
if: runner.os == 'Windows'
working-directory: .\python_dir
shell: powershell
run: |
.\openssl.exe fipsinstall -module .\ossl-modules\fips.dll -out fipsmodule.cnf

- name: Configure OpenSSL for FIPS
if: runner.os == 'Windows'
working-directory: .\python_dir
shell: powershell
run: |
# Create openssl.cnf to enable FIPS mode
$OpenSSLConf = @"
config_diagnostics = 1
openssl_conf = openssl_init

.include 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
"@
$OpenSSLConf | Set-Content -Path ".\openssl.cnf"

- name: Verify OpenSSL
if: runner.os == 'Windows'
working-directory: .\python_dir
shell: powershell
run: |
.\openssl.exe version -a
.\openssl.exe list -providers

- name: Verify OpenSSL with FIPS ENV vars
if: runner.os == 'Windows'
working-directory: .\python_dir
shell: powershell
run: |
$env:OPENSSL_MODULES = ".\ossl-modules"
$env:OPENSSL_CONF = ".\openssl.cnf"
.\openssl.exe list -providers

- name: Add Python to PATH Windows
if: runner.os == 'Windows'
shell: powershell
run: |
Add-Content -Path $env:GITHUB_ENV -Value "PATH=.\python_dir;.\python_dir\Scripts;$env:PATH"

- name: Add Python to PATH Linux
if: runner.os == 'Linux'
run: |
echo "PATH=./python_dir:$PATH" >> $GITHUB_ENV

- name: Install pip
run: |
python -m ensurepip

- name: Restore cache
uses: actions/cache/restore@v4
with:
path: ${{ runner.os == 'Windows' && '~\AppData\Local\pip\Cache' || '~/.cache/pip' }}
key: >-
${{ format(
'v01-python-{0}-{1}-{2}-{3}',
env.pythonLocation,
hashFiles('datadog_checks_base/pyproject.toml'),
hashFiles('datadog_checks_dev/pyproject.toml'),
hashFiles('ddev/pyproject.toml')
)}}
restore-keys: |-
v01-python-${{ env.pythonLocation }}

- name: Install ddev from local folder
run: |
python -m pip install -e ./datadog_checks_dev[cli]
python -m pip install -e ./ddev

- name: Configure ddev
run: |
ddev config set repos.core .
ddev config set repo core

- name: Test
if: runner.os == 'Windows'
working-directory: .\python_dir
shell: powershell
run: |
$env:PATH_TO_OPENSSL_CONF = "$(pwd)\openssl.cnf"
$env:PATH_TO_OPENSSL_MODULES = "$(pwd)\ossl-modules"
$env:OPENSSL_CONF = "$(pwd)\openssl.cnf"
$env:OPENSSL_MODULES = "$(pwd)\ossl-modules"
.\openssl.exe list -providers
ddev test datadog_checks_base -- -k fips
29 changes: 19 additions & 10 deletions .github/workflows/test-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ on:
required: false
default: "traces"
type: string
test-results-name:
required: false
default: "test-results"
type: string
trace-agent-port:
required: false
default: "8126"
Expand All @@ -85,6 +89,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 +279,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 +290,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 +300,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 +317,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 +328,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 +338,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 +364,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 +375,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 +385,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 All @@ -402,7 +411,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: "test-results-${{ inputs.target }}-${{ inputs.platform }}"
name: "${{ inputs.test-results-name }}-${{ inputs.target }}-${{ inputs.platform }}"
path: "${{ env.TEST_RESULTS_BASE_DIR }}"

- name: Upload coverage data
Expand Down
Loading
Loading