Skip to content

Commit 7fd82dc

Browse files
Merge pull request #102 from michaelklishin/tls-tests
TLS-enabled tests for CI
2 parents c0e5066 + 1531801 commit 7fd82dc

File tree

9 files changed

+835
-2
lines changed

9 files changed

+835
-2
lines changed

.github/scripts/free_disk_space.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env bash
2+
3+
# Based on https://github.com/apache/flink/blob/02d30ace69dc18555a5085eccf70ee884e73a16e/tools/azure-pipelines/free_disk_space.sh
4+
#
5+
# The GitHub Actions provided machines typically have the following disk allocation:
6+
# Total space: 85GB
7+
# Allocated: 67 GB
8+
# Free: 17 GB
9+
#
10+
# This script frees up disk space by deleting unneeded packages and large directories.
11+
12+
echo "=============================================================================="
13+
echo "Freeing up disk space on CI system"
14+
echo "=============================================================================="
15+
16+
echo "Listing 100 largest packages"
17+
dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 100
18+
df -h
19+
20+
echo "Removing large packages"
21+
sudo apt-get remove -y '^ghc-8.*'
22+
sudo apt-get remove -y '^dotnet-.*'
23+
sudo apt-get remove -y '^llvm-.*'
24+
sudo apt-get remove -y 'php.*'
25+
sudo apt-get remove -y azure-cli google-cloud-sdk hhvm google-chrome-stable firefox powershell mono-devel
26+
sudo apt-get autoremove -y
27+
sudo apt-get clean
28+
df -h
29+
30+
echo "Removing large directories"
31+
rm -rf /usr/share/dotnet/
32+
df -h

.github/workflows/ci.yaml

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ on:
1212
- 'src/**'
1313
- "tests/**"
1414
- "bin/ci/before_build.sh"
15+
- "bin/ci/before_build_tls.sh"
1516
pull_request: {}
1617

1718
env:
@@ -35,6 +36,10 @@ jobs:
3536

3637
steps:
3738
- uses: actions/checkout@v4
39+
40+
- name: Free up disk space
41+
run: .github/scripts/free_disk_space.sh
42+
3843
- uses: dtolnay/rust-toolchain@stable
3944
with:
4045
toolchain: ${{ matrix.rust-version }}
@@ -71,6 +76,10 @@ jobs:
7176

7277
steps:
7378
- uses: actions/checkout@v4
79+
80+
- name: Free up disk space
81+
run: .github/scripts/free_disk_space.sh
82+
7483
- name: Set up Rust toolchain
7584
uses: dtolnay/rust-toolchain@stable
7685
with:
@@ -88,4 +97,136 @@ jobs:
8897
run: sleep 10
8998

9099
- name: Run all tests
91-
run: RUST_BACKTRACE=1 TEST_STATS_DELAY=1500 cargo nextest run --workspace --no-fail-fast --all-features
100+
run: RUST_BACKTRACE=1 TEST_STATS_DELAY=1500 cargo nextest run --cargo-profile ci --workspace --no-fail-fast --all-features
101+
102+
tls-tests:
103+
name: TLS tests
104+
strategy:
105+
matrix:
106+
rabbitmq-series:
107+
- "4.0"
108+
- "4.1"
109+
rust-version:
110+
- stable
111+
runner:
112+
- "ubuntu-22.04"
113+
- "ubuntu-24.04"
114+
- "ubuntu-24.04-arm"
115+
runs-on: ${{ matrix.runner }}
116+
117+
steps:
118+
- uses: actions/checkout@v4
119+
120+
- name: Free up disk space
121+
run: .github/scripts/free_disk_space.sh
122+
123+
- name: Setup Rust
124+
uses: dtolnay/rust-toolchain@stable
125+
with:
126+
toolchain: ${{ matrix.rust-version }}
127+
128+
- uses: taiki-e/install-action@nextest
129+
130+
- name: Clone tls-gen
131+
run: git clone --depth 1 https://github.com/rabbitmq/tls-gen.git target/tls-gen
132+
133+
- name: Generate TLS certificates
134+
run: |
135+
cd target/tls-gen/basic
136+
make CN=localhost
137+
138+
- name: Create certs directory
139+
run: mkdir -p tests/tls/certs
140+
141+
- name: Copy certificates
142+
run: |
143+
cp target/tls-gen/basic/result/ca_certificate.pem tests/tls/certs/
144+
cp target/tls-gen/basic/result/server_localhost_certificate.pem tests/tls/certs/server_certificate.pem
145+
cp target/tls-gen/basic/result/server_localhost_key.pem tests/tls/certs/server_key.pem
146+
cp target/tls-gen/basic/result/client_localhost_certificate.pem tests/tls/certs/client_certificate.pem
147+
cp target/tls-gen/basic/result/client_localhost_key.pem tests/tls/certs/client_key.pem
148+
# Create PKCS#12 client identity for native-tls compatibility
149+
openssl pkcs12 -export \
150+
-out tests/tls/certs/client_identity.p12 \
151+
-inkey tests/tls/certs/client_key.pem \
152+
-in tests/tls/certs/client_certificate.pem \
153+
-certfile tests/tls/certs/ca_certificate.pem \
154+
-passout pass:
155+
chmod o+r tests/tls/certs/*
156+
chmod g+r tests/tls/certs/*
157+
158+
- name: Create RabbitMQ TLS configuration
159+
run: |
160+
cat > tests/tls/certs/rabbitmq.conf << 'EOF'
161+
management.ssl.port = 15671
162+
management.ssl.cacertfile = /certs/ca_certificate.pem
163+
management.ssl.certfile = /certs/server_certificate.pem
164+
management.ssl.keyfile = /certs/server_key.pem
165+
management.tcp.port = 15672
166+
loopback_users = none
167+
EOF
168+
sed -i 's/^[[:space:]]*//' tests/tls/certs/rabbitmq.conf
169+
echo "Generated config:"
170+
cat tests/tls/certs/rabbitmq.conf
171+
echo -n "rabbitmq-test-cookie" > tests/tls/certs/.erlang.cookie
172+
chmod 600 tests/tls/certs/.erlang.cookie
173+
174+
- name: Start RabbitMQ with TLS
175+
run: |
176+
docker run -d --name rabbitmq-tls \
177+
-p 15671:15671 \
178+
-p 15672:15672 \
179+
-p 5672:5672 \
180+
-v ${{ github.workspace }}/tests/tls/certs/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
181+
-v ${{ github.workspace }}/tests/tls/certs:/certs:ro \
182+
-v ${{ github.workspace }}/tests/tls/certs/rabbitmq.conf:/etc/rabbitmq/conf.d/10-tls.conf:ro \
183+
rabbitmq:${{ matrix.rabbitmq-series }}-management
184+
185+
- name: Wait for RabbitMQ to start
186+
run: |
187+
for i in $(seq 1 30); do
188+
if docker exec rabbitmq-tls rabbitmqctl await_startup --timeout 60; then
189+
echo "RabbitMQ is ready"
190+
exit 0
191+
fi
192+
echo "Waiting for container... ($i/30)"
193+
sleep 2
194+
done
195+
echo "RabbitMQ failed to start. Container logs:"
196+
docker logs rabbitmq-tls
197+
exit 1
198+
199+
- name: Verify TLS listener
200+
run: |
201+
docker exec rabbitmq-tls rabbitmq-diagnostics listeners
202+
echo "Checking if TLS port 15671 is listening..."
203+
docker exec rabbitmq-tls rabbitmq-diagnostics listeners | grep -E "15671|ssl" || echo "Note: TLS listener output"
204+
205+
- name: Debug TLS certificates
206+
run: |
207+
echo "=== CA Certificate ==="
208+
openssl x509 -in tests/tls/certs/ca_certificate.pem -noout -subject -issuer
209+
echo "=== Server Certificate ==="
210+
openssl x509 -in tests/tls/certs/server_certificate.pem -noout -subject -issuer
211+
echo "=== Verify server cert against CA ==="
212+
openssl verify -CAfile tests/tls/certs/ca_certificate.pem tests/tls/certs/server_certificate.pem
213+
echo "=== Test TLS connection with curl ==="
214+
curl -v --cacert tests/tls/certs/ca_certificate.pem https://localhost:15671/api/overview -u guest:guest 2>&1 | head -30 || true
215+
echo "=== Certificate file permissions ==="
216+
ls -la tests/tls/certs/
217+
218+
- name: Configure broker
219+
run: |
220+
docker exec rabbitmq-tls rabbitmqctl add_vhost / || true
221+
docker exec rabbitmq-tls rabbitmqctl add_user guest guest || true
222+
docker exec rabbitmq-tls rabbitmqctl set_permissions -p / guest ".*" ".*" ".*"
223+
224+
- name: Run TLS tests
225+
run: |
226+
TLS_CERTS_DIR=${{ github.workspace }}/tests/tls/certs \
227+
RUST_BACKTRACE=1 \
228+
cargo nextest run --cargo-profile ci -E 'binary(async_tls_tests) | binary(blocking_tls_tests)' --run-ignored=only --no-fail-fast --all-features
229+
230+
- name: Stop RabbitMQ container
231+
if: always()
232+
run: docker stop rabbitmq-tls && docker rm rabbitmq-tls || true

CONTRIBUTING.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,31 @@ cargo test blocking --all-features
2727

2828
``` bash
2929
NEXTEST_RETRIES=3 cargo nextest run -E "test(test_list_all_vhost_limits)"
30-
```
30+
```
31+
32+
## Running TLS Integration Tests
33+
34+
TLS-enabled tests require a set of certificate and private key pairs, plus
35+
a preconfigured RabbitMQ node. As such, they are excluded from standard `cargo nextest` runs.
36+
37+
To run these tests, generate certificates using [tls-gen](https://github.com/rabbitmq/tls-gen):
38+
39+
```shell
40+
cd /path/to/tls-gen/basic && make CN=localhost && make alias-leaf-artifacts
41+
```
42+
43+
Then [configure](https://www.rabbitmq.com/docs/management#single-listener-https) RabbitMQ management plugin to use TLS.
44+
45+
Next, export the `TLS_CERTS_DIR` environment variable:
46+
47+
```shell
48+
export TLS_CERTS_DIR=/path/to/tls-gen/basic/result
49+
```
50+
51+
Finally, run the tests in question only:
52+
53+
```shell
54+
cargo nextest run -E 'binary(async_tls_tests)' --run-ignored=only --all-features
55+
56+
cargo nextest run -E 'binary(blocking_tls_tests)' --run-ignored=only --all-features
57+
```

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,10 @@ native-tls = ["reqwest?/native-tls"]
6666
rustls-tls = ["reqwest?/rustls-tls"]
6767
hickory-dns = ["reqwest?/hickory-dns"]
6868

69+
[profile.ci]
70+
inherits = "dev"
71+
opt-level = "s"
72+
strip = true
73+
6974
[lints.clippy]
7075
uninlined_format_args = "allow"

bin/ci/before_build_tls.sh

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#!/bin/sh
2+
3+
# TLS test setup script for CI and local development
4+
# Generates certificates using tls-gen and configures RabbitMQ with TLS-enabled management API
5+
6+
set -e
7+
8+
CTL=${RUST_HTTP_API_CLIENT_RABBITMQCTL:="sudo rabbitmqctl"}
9+
PLUGINS=${RUST_HTTP_API_CLIENT_RABBITMQ_PLUGINS:="sudo rabbitmq-plugins"}
10+
11+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
13+
CERTS_DIR="${REPO_ROOT}/tests/tls/certs"
14+
15+
# Docker container ID (passed via environment or extracted from CTL)
16+
CONTAINER_ID=""
17+
18+
case $CTL in
19+
DOCKER*)
20+
CONTAINER_ID="${CTL##*:}"
21+
PLUGINS="docker exec ${CONTAINER_ID} rabbitmq-plugins"
22+
CTL="docker exec ${CONTAINER_ID} rabbitmqctl"
23+
;;
24+
esac
25+
26+
echo "Will use rabbitmqctl at ${CTL}"
27+
echo "Will use rabbitmq-plugins at ${PLUGINS}"
28+
29+
# Create certs directory
30+
mkdir -p "${CERTS_DIR}"
31+
32+
# Check if tls-gen is available
33+
TLSGEN_DIR="${TLSGEN_DIR:-}"
34+
if [ -z "$TLSGEN_DIR" ]; then
35+
echo "TLSGEN_DIR not set, cloning tls-gen..."
36+
TLSGEN_DIR="${REPO_ROOT}/target/tls-gen"
37+
if [ ! -d "$TLSGEN_DIR" ]; then
38+
git clone --depth 1 https://github.com/rabbitmq/tls-gen.git "$TLSGEN_DIR"
39+
fi
40+
fi
41+
42+
echo "Using tls-gen at ${TLSGEN_DIR}"
43+
44+
# Generate certificates using basic profile
45+
cd "${TLSGEN_DIR}/basic"
46+
make CN=localhost
47+
make alias-leaf-artifacts
48+
49+
# Copy certificates to the test directory
50+
cp result/ca_certificate.pem "${CERTS_DIR}/"
51+
cp result/server_certificate.pem "${CERTS_DIR}/"
52+
cp result/server_key.pem "${CERTS_DIR}/"
53+
cp result/client_certificate.pem "${CERTS_DIR}/"
54+
cp result/client_key.pem "${CERTS_DIR}/"
55+
56+
# Create PKCS#12 client identity for native-tls compatibility
57+
openssl pkcs12 -export \
58+
-out "${CERTS_DIR}/client_identity.p12" \
59+
-inkey "${CERTS_DIR}/client_key.pem" \
60+
-in "${CERTS_DIR}/client_certificate.pem" \
61+
-certfile "${CERTS_DIR}/ca_certificate.pem" \
62+
-passout pass:
63+
64+
echo "Certificates generated and copied to ${CERTS_DIR}"
65+
66+
# Create RabbitMQ configuration for TLS
67+
RABBITMQ_CONF="${CERTS_DIR}/rabbitmq.conf"
68+
cat > "${RABBITMQ_CONF}" << 'EOF'
69+
# Enable TLS on management plugin
70+
management.ssl.port = 15671
71+
management.ssl.cacertfile = /certs/ca_certificate.pem
72+
management.ssl.certfile = /certs/server_certificate.pem
73+
management.ssl.keyfile = /certs/server_key.pem
74+
75+
# Keep HTTP enabled for other tests
76+
management.tcp.port = 15672
77+
loopback_users = none
78+
EOF
79+
80+
echo "RabbitMQ TLS configuration written to ${RABBITMQ_CONF}"
81+
82+
# If using Docker, start a container with TLS configuration
83+
if [ -n "$CONTAINER_ID" ]; then
84+
echo "Note: Docker service container ${CONTAINER_ID} detected."
85+
echo "For TLS tests, use a standalone Docker container instead."
86+
echo ""
87+
echo "To start RabbitMQ with TLS manually:"
88+
echo " docker run -d --name rabbitmq-tls \\"
89+
echo " -p 15671:15671 -p 15672:15672 -p 5672:5672 \\"
90+
echo " -v ${CERTS_DIR}:/certs:ro \\"
91+
echo " -v ${RABBITMQ_CONF}:/etc/rabbitmq/conf.d/10-tls.conf:ro \\"
92+
echo " rabbitmq:4.0-management"
93+
fi
94+
95+
# Enable management plugin (should already be enabled in the management image)
96+
$PLUGINS enable rabbitmq_management
97+
98+
sleep 3
99+
100+
# Configure vhosts and users (same as before_build.sh)
101+
$CTL add_vhost /
102+
$CTL add_user guest guest || true
103+
$CTL set_permissions -p / guest ".*" ".*" ".*"
104+
105+
$CTL add_user rust3 rust3 || true
106+
$CTL set_permissions -p / rust3 ".*" ".*" ".*"
107+
108+
# Reduce retention policy for faster publishing of stats
109+
$CTL eval 'supervisor2:terminate_child(rabbit_mgmt_sup_sup, rabbit_mgmt_sup), application:set_env(rabbitmq_management, sample_retention_policies, [{global, [{605, 1}]}, {basic, [{605, 1}]}, {detailed, [{10, 1}]}]), rabbit_mgmt_sup_sup:start_child().'
110+
$CTL eval 'supervisor2:terminate_child(rabbit_mgmt_agent_sup_sup, rabbit_mgmt_agent_sup), application:set_env(rabbitmq_management_agent, sample_retention_policies, [{global, [{605, 1}]}, {basic, [{605, 1}]}, {detailed, [{10, 1}]}]), rabbit_mgmt_agent_sup_sup:start_child().'
111+
112+
$CTL add_vhost "rust/http/api/client" || true
113+
$CTL set_permissions -p "rust/http/api/client" guest ".*" ".*" ".*"
114+
115+
# Set cluster name
116+
$CTL set_cluster_name rabbitmq@localhost
117+
118+
$CTL enable_feature_flag all
119+
120+
# Enable additional plugins
121+
$PLUGINS enable rabbitmq_shovel
122+
$PLUGINS enable rabbitmq_shovel_management
123+
$PLUGINS enable rabbitmq_federation
124+
$PLUGINS enable rabbitmq_federation_management
125+
$PLUGINS enable rabbitmq_stream
126+
$PLUGINS enable rabbitmq_stream_management
127+
128+
# Export certificate paths for tests
129+
echo ""
130+
echo "=== TLS Test Environment ==="
131+
echo "CA Certificate: ${CERTS_DIR}/ca_certificate.pem"
132+
echo "Client Certificate: ${CERTS_DIR}/client_certificate.pem"
133+
echo "Client Key: ${CERTS_DIR}/client_key.pem"
134+
echo "TLS Endpoint: https://localhost:15671/api"
135+
echo ""
136+
echo "To run TLS tests:"
137+
echo " TLS_CERTS_DIR=${CERTS_DIR} cargo nextest run -E 'binary(async_tls_tests) | binary(blocking_tls_tests)' --run-ignored=only --all-features"
138+
echo ""
139+
140+
true

0 commit comments

Comments
 (0)