docs: add guide and tooling for custom CA trust in Dockerized Checkmate (Fixes #2747)

This commit is contained in:
Tafadzwa Chiwozva
2025-08-13 17:50:30 -04:00
parent f2e2d5c2ed
commit f381b0ce4a
11 changed files with 1002 additions and 0 deletions

View File

@@ -54,6 +54,12 @@ See installation instructions in [Checkmate documentation portal](https://docs.c
Alternatively, you can also use [Coolify](https://coolify.io/), [Elestio](https://elest.io/open-source/checkmate), [K8s](./charts/helm/checkmate/INSTALLATION.md) or [Pikapods](https://www.pikapods.com/) to quickly spin off a Checkmate instance. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.
### Using a Custom CA
If you need to monitor internal HTTPS endpoints with certificates from private Certificate Authorities (like Smallstep), see our [Custom CA Trust Guide](./docs/custom-ca-trust.md) for Docker configuration options.
For more documentation, see the [docs directory](./docs/).
## Translations

10
docker/.gitignore vendored
View File

@@ -12,3 +12,13 @@ dist/docker-compose-test.yaml
/dist-mono/redis/data/*
/dist-arm/mongo/data/*
*.env
# Custom CA certificates and keys (should not be committed)
dev/certs/*
!dev/certs/.gitkeep
# Certificate artifacts
*.key
*.csr
*.srl
*.log

View File

View File

@@ -0,0 +1,30 @@
# Dev/Test only: Not required in production
# Example Docker Compose configuration for custom CA trust
# This file demonstrates how to configure Checkmate to trust custom CAs
#
# Usage: docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up
services:
server:
image: uptime_server:latest
restart: always
ports:
- "52345:52345"
env_file:
- server.env
environment:
# Mount your custom CA certificate
NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem
volumes:
# Mount the certs directory (read-only for security)
- ./certs:/certs:ro
depends_on:
- redis
- mongodb
# Optional: Add healthcheck to ensure the server starts properly
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:52345/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

View File

@@ -0,0 +1,13 @@
# Dev/Test only: Not required in production
# Docker Compose configuration for nginx test service
services:
nginx-test:
image: nginx:alpine
ports:
- "8443:443"
volumes:
- ../certs/host-int-cert.pem:/etc/nginx/certs/server.crt:ro
- ../certs/host-int-key.pem:/etc/nginx/certs/server.key:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped

View File

@@ -0,0 +1,14 @@
# Dev/Test only: Not required in production
# Nginx configuration for testing custom CA trust functionality
events {}
http {
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
location / {
return 200 "hello from tls\n";
}
}
}

38
docs/README.md Normal file
View File

@@ -0,0 +1,38 @@
# Checkmate Documentation
Welcome to the Checkmate documentation. This directory contains guides and references for various aspects of Checkmate deployment and configuration.
## Available Documentation
### Deployment & Configuration
- **[Custom CA Trust Guide](./custom-ca-trust.md)** - Configure Checkmate to trust custom Certificate Authorities
- **[Custom CA Quick Reference](./custom-ca-quick-reference.md)** - Quick setup guide for custom CA trust
## Docker Configuration
### Custom CA Trust
If you need to monitor internal HTTPS endpoints with certificates from private Certificate Authorities (like Smallstep), see our custom CA trust documentation:
- **Full Guide**: [Custom CA Trust Guide](./custom-ca-trust.md)
- **Quick Reference**: [Custom CA Quick Reference](./custom-ca-quick-reference.md)
### Example Configurations
The `docker/dev/` directory contains example configurations:
- `docker-compose.custom-ca-example.yaml` - Example Docker Compose with custom CA
- `server-custom-ca.Dockerfile` - Example Dockerfile for OS-level CA trust
- `export-smallstep-ca.sh` - Helper script for Smallstep CA export
## Contributing to Documentation
If you find issues or want to improve the documentation:
1. Check existing issues and discussions
2. Submit a pull request with your changes
3. Follow the same markdown formatting style
4. Include practical examples and code snippets
## Getting Help
- [GitHub Discussions](https://github.com/bluewave-labs/checkmate/discussions)
- [Discord Channel](https://discord.gg/NAb6H3UTjK)
- [Documentation Portal](https://docs.checkmate.so/)

View File

@@ -0,0 +1,60 @@
# Custom CA Trust - Quick Reference
## Fast Setup (Node-level)
1. **Export your CA certificate:**
```bash
# For Smallstep
step certificate inspect --format pem step-ca/root_ca.crt > docker/dev/certs/custom-ca.pem
```
2. **Use the provided example override:**
```bash
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d
```
3. **Or manually update docker-compose.yaml:**
```yaml
services:
server:
environment:
NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem
volumes:
- ./certs:/certs:ro
```
## Alternative Setup (OS-level)
1. **Use custom Dockerfile:**
```bash
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up
```
## File Structure
```
docker/dev/
├── docker-compose.yaml
├── docker-compose.custom-ca-example.yaml # Example config
├── certs/
│ ├── README.md
│ └── custom-ca.pem # Your CA certificate
└── export-smallstep-ca.sh # Helper script
```
## Environment Variables
- `NODE_EXTRA_CA_CERTS=/certs/custom-ca.pem` - Node.js trust
- Mount `./certs:/certs:ro` - Volume mount
## Security
- ✅ Only trust CAs you control
- ✅ Use read-only volume mounts
- ✅ Keep certificates out of version control
- ❌ Never trust untrusted CAs
## Troubleshooting
- Check container logs: `docker-compose logs server`
- Verify certificate: `docker exec -it <container> ls -la /certs/`
- Test connection: `docker exec -it <container> wget --ca-certificate=/certs/custom-ca.pem https://your-internal-site.com`
## Full Documentation
See [Custom CA Trust Guide](./custom-ca-trust.md) for detailed instructions.

234
docs/custom-ca-trust.md Normal file
View File

@@ -0,0 +1,234 @@
# Custom Certificate Authority Trust
This guide explains how to configure Checkmate to trust custom Certificate Authorities (CAs) when running in Docker, particularly useful for internal/private CAs like Smallstep.
## Understanding Certificate Authorities
Certificate Authorities (CAs) are entities that issue and manage digital certificates. While public CAs (like Let's Encrypt, DigiCert) are trusted by default in most systems, private or internal CAs (like those issued by Smallstep, internal PKI systems) require explicit trust configuration.
When Checkmate monitors HTTPS endpoints with certificates from private CAs, it may show them as "DOWN" due to certificate validation failures, even if the service is actually accessible.
## Node-level Trust Approach
The simplest approach is to mount your custom CA certificate and configure Node.js to trust it using the `NODE_EXTRA_CA_CERTS` environment variable.
### Docker Compose Configuration
Add a volume mount for your CA certificate and set the environment variable:
```yaml
services:
server:
image: uptime_server:latest
restart: always
ports:
- "52345:52345"
env_file:
- server.env
environment:
NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem
volumes:
- ./certs:/certs:ro
depends_on:
- redis
- mongodb
```
### Directory Structure
Create a `certs` directory in your Docker Compose project root:
```
docker/dev/
├── docker-compose.yaml
├── certs/
│ └── custom-ca.pem
└── ...
```
## OS-level Trust Approach (Debian-based)
For more comprehensive trust configuration, you can create a derived Dockerfile that installs your CA at the OS level.
### Custom Dockerfile
Create `docker/dev/server-custom-ca.Dockerfile`:
```dockerfile
FROM node:20-alpine
# Install ca-certificates for Alpine
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY ./server/package*.json ./
RUN npm install
COPY ./server/ ./
# Copy your custom CA certificate
COPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/
# Update CA certificates
RUN update-ca-certificates
EXPOSE 52345
CMD ["node", "src/index.js"]
```
### Docker Compose Override
Create `docker/dev/docker-compose.custom-ca.yaml`:
```yaml
services:
server:
build:
context: .
dockerfile: server-custom-ca.Dockerfile
restart: always
ports:
- "52345:52345"
env_file:
- server.env
depends_on:
- redis
- mongodb
```
Run with: `docker-compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up`
## Alpine Linux Considerations
Since Checkmate uses Alpine Linux as the base image, you need to install the `ca-certificates` package:
```dockerfile
# Install ca-certificates for Alpine
RUN apk add --no-cache ca-certificates
# Copy and update CA certificates
COPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
```
## Smallstep CA Configuration
If you're using Smallstep as your internal CA, you can export the root CA certificate:
### Export Smallstep Root CA
```bash
# Export the root CA certificate
step certificate inspect --format pem step-ca/root_ca.crt > custom-ca.pem
# Or if you have the CA URL configured
step certificate inspect --format pem $(step path)/certs/root_ca.crt > custom-ca.pem
```
### Using the Exported Certificate
1. Copy the exported `custom-ca.pem` to your `docker/dev/certs/` directory
2. Use either the Node-level or OS-level approach above
3. Restart your Checkmate server container
## Security Considerations
⚠️ **Important Security Warning**: Only trust CAs that you control or explicitly trust. Adding untrusted CAs can compromise the security of your monitoring system.
- **Private CAs**: Only trust CAs from your organization's PKI infrastructure
- **Self-signed certificates**: Consider using proper CA infrastructure instead
- **Certificate validation**: Ensure your CA certificates are valid and not expired
- **Access control**: Limit access to the CA certificate files in production
## Troubleshooting
### Verify CA Trust
Test if your CA is trusted by the container:
```bash
# Enter the running container
docker exec -it <container_name> sh
# Check if the CA is in the trust store
ls -la /usr/local/share/ca-certificates/
cat /etc/ssl/certs/ca-certificates.crt | grep -A 5 -B 5 "YOUR_CA_NAME"
```
### Common Issues
1. **Permission denied**: Ensure the CA certificate file has proper read permissions
2. **Certificate format**: Use PEM format (.pem, .crt) for best compatibility
3. **Container restart**: Always restart the container after adding new CA certificates
4. **Path issues**: Verify the certificate path in your volume mounts
## Example: Complete Working Setup
Here's a complete example for a Smallstep CA setup. This demonstrates both the baseline failure (expected) and the custom CA success:
### Baseline Test (Should Fail)
1. **Start Checkmate without custom CA trust:**
```bash
cd docker/dev
docker-compose up -d
```
2. **Test connection to internal HTTPS endpoint:**
```bash
# This should fail with TLS error (unknown CA)
docker-compose exec server node -e "
const https = require('https');
https.get('https://your-internal-site.com', res => {
console.log('STATUS:', res.statusCode);
}).on('error', e => {
console.error('ERR:', e.message);
});
"
```
**Expected result**: TLS error due to unknown CA
### Custom CA Test (Should Succeed)
1. **Export Smallstep Root CA:**
```bash
step certificate inspect --format pem step-ca/root_ca.crt > docker/dev/certs/smallstep-root-ca.pem
```
2. **Update docker-compose.yaml with custom CA trust:**
```yaml
services:
server:
environment:
NODE_EXTRA_CA_CERTS: /certs/smallstep-root-ca.pem
volumes:
- ./certs:/certs:ro
```
3. **Restart with custom CA:**
```bash
docker-compose down
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d
```
4. **Test the same connection:**
```bash
# This should now succeed
docker-compose exec server node -e "
const https = require('https');
https.get('https://your-internal-site.com', res => {
console.log('STATUS:', res.statusCode);
}).on('error', e => {
console.error('ERR:', e.message);
});
"
```
**Expected result**: HTTP 200 OK
### Verification
- **Baseline**: TLS failure proves default behavior (unknown CA)
- **Custom CA**: TLS success proves custom CA trust is working
- **Both tests must pass** to confirm the feature works correctly
Your Checkmate server should now trust certificates issued by your Smallstep CA, allowing you to monitor internal HTTPS endpoints without disabling SSL validation.

143
scripts/dev/setup-custom-ca.sh Executable file
View File

@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# Dev/Test only: Not required in production
# This script generates test certificates for development and testing purposes
set -euo pipefail
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CERTS_DIR="$REPO_ROOT/docker/dev/certs"
# Function to print colored output
print_status() {
local status=$1
local message=$2
case $status in
"PASS")
echo -e "${GREEN}[PASS]${NC} $message"
;;
"INFO")
echo -e "${BLUE}[INFO]${NC} $message"
;;
"WARN")
echo -e "${YELLOW}[WARN]${NC} $message"
;;
esac
}
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to generate certificates using mkcert
generate_certs_mkcert() {
print_status "INFO" "Generating certificates using mkcert..."
# Install mkcert CA (ignore if already done)
mkcert -install 2>/dev/null || true
# Copy root CA
local ca_root
ca_root=$(mkcert -CAROOT)
cp "$ca_root/rootCA.pem" "$CERTS_DIR/custom-ca.pem"
# Generate server certificate
mkcert -key-file "$CERTS_DIR/host-int-key.pem" \
-cert-file "$CERTS_DIR/host-int-cert.pem" \
host.docker.internal
print_status "PASS" "Certificates generated using mkcert"
}
# Function to generate certificates using OpenSSL
generate_certs_openssl() {
print_status "INFO" "Generating certificates using OpenSSL..."
# Create CA private key
openssl genrsa -out "$CERTS_DIR/ca.key" 2048
# Create CA certificate
openssl req -new -x509 -days 365 -key "$CERTS_DIR/ca.key" \
-out "$CERTS_DIR/custom-ca.pem" \
-subj "/C=US/ST=Test/L=Test/O=Test CA/CN=Test Root CA"
# Create server private key
openssl genrsa -out "$CERTS_DIR/host-int-key.pem" 2048
# Create server certificate signing request
openssl req -new -key "$CERTS_DIR/host-int-key.pem" \
-out "$CERTS_DIR/host-int-cert.csr" \
-subj "/C=US/ST=Test/L=Test/O=Test/CN=host.docker.internal"
# Create extfile for SAN
cat > "$CERTS_DIR/san.ext" << EOF
subjectAltName=DNS:host.docker.internal,IP:127.0.0.1
EOF
# Sign server certificate with CA
openssl x509 -req -days 365 \
-in "$CERTS_DIR/host-int-cert.csr" \
-CA "$CERTS_DIR/custom-ca.pem" \
-CAkey "$CERTS_DIR/ca.key" \
-CAcreateserial \
-out "$CERTS_DIR/host-int-cert.pem" \
-extfile "$CERTS_DIR/san.ext"
# Clean up temporary files
rm -f "$CERTS_DIR/ca.key" "$CERTS_DIR/host-int-cert.csr" "$CERTS_DIR/san.ext" "$CERTS_DIR/.srl"
print_status "PASS" "Certificates generated using OpenSSL"
}
# Main function
main() {
print_status "INFO" "Setting up custom CA certificates for Checkmate testing"
echo "================================================================"
# Create certs directory if missing
print_status "INFO" "Creating certificates directory..."
mkdir -p "$CERTS_DIR"
# Generate certificates
if command_exists mkcert; then
generate_certs_mkcert
else
print_status "WARN" "mkcert not found, falling back to OpenSSL"
generate_certs_openssl
fi
# Create duplicate for compatibility with existing overrides
print_status "INFO" "Creating duplicate CA file for compatibility..."
cp "$CERTS_DIR/custom-ca.pem" "$CERTS_DIR/smallstep-root-ca.pem"
# Verify certificates exist
if [ ! -f "$CERTS_DIR/custom-ca.pem" ] || [ ! -f "$CERTS_DIR/host-int-cert.pem" ] || [ ! -f "$CERTS_DIR/host-int-key.pem" ]; then
echo "Error: Failed to generate required certificates"
exit 1
fi
# Print summary
echo ""
print_status "PASS" "All required certificates generated successfully"
echo ""
echo "Certificate summary:"
echo "===================="
ls -l "$CERTS_DIR"
echo ""
echo "CA certificate preview:"
echo "======================"
head -3 "$CERTS_DIR/custom-ca.pem"
echo ""
print_status "INFO" "Certificates are ready for use with Checkmate custom CA trust"
}
# Run main function
main "$@"

454
scripts/test-custom-ca.sh Executable file
View File

@@ -0,0 +1,454 @@
#!/usr/bin/env bash
# Dev/Test only: Not required in production
# This script tests the custom CA trust functionality in development environment
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DEV_DIR="${ROOT_DIR}/docker/dev"
CERT_DIR="${DEV_DIR}/certs"
NGINX_DIR="${DEV_DIR}/nginx-test"
COMPOSE_BASELINE="${DEV_DIR}/docker-compose.yaml"
COMPOSE_CUSTOM_CA="${DEV_DIR}/docker-compose.custom-ca-example.yaml"
COMPOSE_NGINX_TEST="${NGINX_DIR}/docker-compose.nginx-test.yaml"
# Test configuration
NGINX_PORT=8443
CHECKMATE_PORT=52345
HEALTH_ENDPOINT="http://localhost:$CHECKMATE_PORT/api/v1/health"
TEST_URL="https://host.docker.internal:$NGINX_PORT"
MAX_WAIT=60
WAIT_INTERVAL=2
# Global flag for cleanup behavior
CLEAN_CERTS=false
# Function to print colored output
print_status() {
local status=$1
local message=$2
case $status in
"PASS")
echo -e "${GREEN}[PASS]${NC} $message"
;;
"FAIL")
echo -e "${RED}[FAIL]${NC} $message"
;;
"INFO")
echo -e "${BLUE}[INFO]${NC} $message"
;;
"WARN")
echo -e "${YELLOW}[WARN]${NC} $message"
;;
esac
}
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to check if certificates exist and are valid
check_certificates() {
local ca_file="${CERT_DIR}/custom-ca.pem"
local cert_file="${CERT_DIR}/host-int-cert.pem"
local key_file="${CERT_DIR}/host-int-key.pem"
if [ ! -f "$ca_file" ] || [ ! -f "$cert_file" ] || [ ! -f "$key_file" ]; then
return 1
fi
# Check if files are not empty
if [ ! -s "$ca_file" ] || [ ! -s "$cert_file" ] || [ ! -s "$key_file" ]; then
return 1
fi
# Check if CA file starts with BEGIN CERTIFICATE
if ! head -1 "$ca_file" | grep -q "BEGIN CERTIFICATE"; then
return 1
fi
return 0
}
# Function to wait for service to be ready
wait_for_service() {
local url=$1
local service_name=$2
local elapsed=0
print_status "INFO" "Waiting for $service_name to be ready..."
while [ $elapsed -lt $MAX_WAIT ]; do
if curl -s -f "$url" >/dev/null 2>&1; then
print_status "PASS" "$service_name is ready after ${elapsed}s"
return 0
fi
sleep $WAIT_INTERVAL
elapsed=$((elapsed + WAIT_INTERVAL))
echo -n "."
done
print_status "FAIL" "$service_name failed to start within ${MAX_WAIT}s"
return 1
}
# Function to get container name by image
get_container_name() {
local image_name=$1
docker ps --filter "ancestor=$image_name" --format "{{.Names}}" | head -n1
}
# Function to run Node.js probe test
run_probe_test() {
local container_name=$1
local test_name=$2
local expected_exit_code=$3
print_status "INFO" "Running $test_name probe test..."
local probe_script="
const https = require('https');
https.get('https://host.docker.internal:8443', res => {
console.log('STATUS', res.statusCode);
process.exit(res.statusCode===200?0:1);
}).on('error', e => {
console.error('ERR', e.code||e.message);
process.exit(1);
});
"
local exit_code
if docker exec -i "$container_name" node -e "$probe_script" 2>/dev/null; then
exit_code=$?
else
exit_code=$?
fi
if [ $exit_code -eq $expected_exit_code ]; then
print_status "PASS" "$test_name probe test completed with expected exit code $expected_exit_code"
return 0
else
print_status "FAIL" "$test_name probe test failed with exit code $exit_code (expected $expected_exit_code)"
return 1
fi
}
# Function to setup certificates if needed
setup_certificates_if_needed() {
if check_certificates; then
print_status "INFO" "Certificates already exist and are valid, skipping generation"
return 0
fi
print_status "INFO" "Certificates missing or invalid, generating new ones..."
if [ -x "${ROOT_DIR}/scripts/dev/setup-custom-ca.sh" ]; then
"${ROOT_DIR}/scripts/dev/setup-custom-ca.sh"
else
print_status "FAIL" "Certificate setup script not found at scripts/dev/setup-custom-ca.sh"
return 1
fi
}
# Function to create nginx test configuration
create_nginx_test_config() {
print_status "INFO" "Setting up nginx test configuration..."
mkdir -p "$NGINX_DIR"
# Create nginx.conf if it doesn't exist
if [ ! -f "${NGINX_DIR}/nginx.conf" ]; then
cat > "${NGINX_DIR}/nginx.conf" << 'EOF'
events {}
http {
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
location / {
return 200 "hello from tls\n";
}
}
}
EOF
fi
# Create docker-compose.nginx-test.yaml if it doesn't exist
if [ ! -f "$COMPOSE_NGINX_TEST" ]; then
cat > "$COMPOSE_NGINX_TEST" << EOF
services:
nginx-test:
image: nginx:alpine
ports:
- "$NGINX_PORT:443"
volumes:
- ../certs/host-int-cert.pem:/etc/nginx/certs/server.crt:ro
- ../certs/host-int-key.pem:/etc/nginx/certs/server.key:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped
EOF
fi
print_status "PASS" "Nginx test configuration created"
}
# Function to start nginx test service
start_nginx_test() {
print_status "INFO" "Starting nginx test service..."
cd "$NGINX_DIR"
docker-compose -f docker-compose.nginx-test.yaml up -d
# Wait for nginx to be ready
local elapsed=0
while [ $elapsed -lt $MAX_WAIT ]; do
if curl -s -f -k "https://localhost:$NGINX_PORT" >/dev/null 2>&1; then
print_status "PASS" "Nginx test service is ready"
cd "$ROOT_DIR"
return 0
fi
sleep $WAIT_INTERVAL
elapsed=$((elapsed + WAIT_INTERVAL))
echo -n "."
done
print_status "FAIL" "Nginx test service failed to start"
cd "$ROOT_DIR"
return 1
}
# Function to stop nginx test service
stop_nginx_test() {
print_status "INFO" "Stopping nginx test service..."
cd "$NGINX_DIR"
docker-compose -f docker-compose.nginx-test.yaml down 2>/dev/null || true
cd "$ROOT_DIR"
}
# Function to run baseline test
run_baseline_test() {
print_status "INFO" "Running baseline test (should fail due to unknown CA)..."
# Start baseline Checkmate
cd "$DEV_DIR"
docker-compose -f docker-compose.yaml up -d --build
# Wait for Checkmate to be ready
if ! wait_for_service "$HEALTH_ENDPOINT" "Checkmate baseline"; then
cd "$ROOT_DIR"
return 1
fi
# Get container name
local container_name
container_name=$(get_container_name "uptime_server")
if [ -z "$container_name" ]; then
print_status "FAIL" "Could not find Checkmate server container"
cd "$ROOT_DIR"
return 1
fi
# Run probe test (should fail)
if run_probe_test "$container_name" "baseline" 1; then
print_status "PASS" "Baseline test completed - TLS failure as expected"
cd "$ROOT_DIR"
return 0
else
print_status "FAIL" "Baseline test failed - unexpected behavior"
cd "$ROOT_DIR"
return 1
fi
}
# Function to run custom CA test
run_custom_ca_test() {
print_status "INFO" "Running custom CA test (should succeed)..."
# Stop baseline Checkmate
cd "$DEV_DIR"
docker-compose -f docker-compose.yaml down
# Start Checkmate with custom CA
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d --build
# Wait for Checkmate to be ready
if ! wait_for_service "$HEALTH_ENDPOINT" "Checkmate custom CA"; then
cd "$ROOT_DIR"
return 1
fi
# Get container name
local container_name
container_name=$(get_container_name "uptime_server")
if [ -z "$container_name" ]; then
print_status "FAIL" "Could not find Checkmate server container"
cd "$ROOT_DIR"
return 1
fi
# Run probe test (should succeed)
if run_probe_test "$container_name" "custom CA" 0; then
print_status "PASS" "Custom CA test completed - TLS success as expected"
cd "$ROOT_DIR"
return 0
else
print_status "FAIL" "Custom CA test failed - unexpected behavior"
cd "$ROOT_DIR"
return 1
fi
}
# Function to cleanup everything
cleanup() {
print_status "INFO" "Cleaning up test environment..."
# Stop all services
cd "$DEV_DIR"
docker-compose -f docker-compose.yaml down 2>/dev/null || true
docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml down 2>/dev/null || true
stop_nginx_test
# Only remove certificates if --clean was specified
if [ "$CLEAN_CERTS" = true ]; then
print_status "INFO" "Removing certificates as requested with --clean"
rm -rf "${CERT_DIR:?}"/*
else
print_status "INFO" "Preserving certificates for future test runs"
fi
cd "$ROOT_DIR"
print_status "PASS" "Cleanup completed"
}
# Function to show usage
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --clean Clean up all test containers and certificates"
echo " --help Show this help message"
echo ""
echo "This script tests the custom CA trust functionality in Checkmate."
}
# Main function
main() {
local clean_only=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--clean)
clean_only=true
CLEAN_CERTS=true
shift
;;
--help)
show_usage
exit 0
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
print_status "INFO" "Starting Checkmate Custom CA Trust Test"
echo "=================================================="
if [ "$clean_only" = true ]; then
cleanup
exit 0
fi
# Check prerequisites
if ! command_exists docker; then
print_status "FAIL" "Docker is not installed or not in PATH"
exit 1
fi
if ! command_exists docker-compose; then
print_status "FAIL" "docker-compose is not installed or not in PATH"
exit 1
fi
# Check if required files exist
if [ ! -f "$COMPOSE_BASELINE" ]; then
print_status "FAIL" "Baseline docker-compose.yaml not found at $COMPOSE_BASELINE"
exit 1
fi
if [ ! -f "$COMPOSE_CUSTOM_CA" ]; then
print_status "FAIL" "Custom CA docker-compose override not found at $COMPOSE_CUSTOM_CA"
exit 1
fi
# Setup test environment
setup_certificates_if_needed
create_nginx_test_config
start_nginx_test
# Run tests
local baseline_result=false
local custom_ca_result=false
if run_baseline_test; then
baseline_result=true
fi
if run_custom_ca_test; then
custom_ca_result=true
fi
# Print summary
echo ""
echo "=================================================="
print_status "INFO" "Test Summary"
echo "=================================================="
if [ "$baseline_result" = true ]; then
print_status "PASS" "Baseline: TLS failure as expected"
else
print_status "FAIL" "Baseline: Unexpected behavior"
fi
if [ "$custom_ca_result" = true ]; then
print_status "PASS" "Custom CA: TLS success (STATUS 200)"
else
print_status "FAIL" "Custom CA: Unexpected behavior"
fi
if [ "$baseline_result" = true ] && [ "$custom_ca_result" = true ]; then
echo ""
print_status "PASS" "All tests passed! Custom CA trust is working correctly."
echo ""
print_status "INFO" "To clean up, run: $0 --clean"
exit 0
else
echo ""
print_status "FAIL" "Some tests failed. Custom CA trust may not be working correctly."
echo ""
print_status "INFO" "To clean up, run: $0 --clean"
exit 1
fi
}
# Trap cleanup on script exit
trap cleanup EXIT
# Run main function
main "$@"