Add OWASP ZAP and MCP ZAP Server integration with configuration updates

This commit is contained in:
John Doe
2026-02-28 18:04:58 -05:00
parent 168ac9eb16
commit c2a71046c7
9 changed files with 354 additions and 2 deletions
+87 -2
View File
@@ -9,6 +9,8 @@ This workspace provides a rootless Podman Quadlet setup with:
- `litellm` (`ghcr.io/berriai/litellm:main-stable`)
- `pentestagent` (`ghcr.io/gh05tcrew/pentestagent:latest`)
- `pentestagent-kali` (`ghcr.io/gh05tcrew/pentestagent:kali`) (optional)
- `zap` (`zaproxy/zap-stable`) (optional, for OWASP ZAP)
- `mcp-zap-server` (`ghcr.io/dtkmn/mcp-zap-server:latest`) (optional, MCP ZAP Server)
## 1) Install files
@@ -17,7 +19,7 @@ Run on the Linux host where Podman + systemd user services run:
```bash
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/pentestagent
mkdir -p ~/.local/share/pentestagent/{ollama,loot,workspace}
mkdir -p ~/.local/share/pentestagent/{ollama,loot,workspace,zap}
cp quadlet/*.network ~/.config/containers/systemd/
cp quadlet/*.pod ~/.config/containers/systemd/
@@ -25,6 +27,8 @@ cp quadlet/ollama.container ~/.config/containers/systemd/
cp quadlet/litellm.container ~/.config/containers/systemd/
cp quadlet/pentestagent.container ~/.config/containers/systemd/
cp quadlet/pentestagent-kali.container ~/.config/containers/systemd/
cp quadlet/zap.container ~/.config/containers/systemd/
cp quadlet/mcp-zap-server.container ~/.config/containers/systemd/
cp config/litellm-config.yaml ~/.config/pentestagent/litellm-config.yaml
cp config/pentestagent.env.example ~/.config/pentestagent/pentestagent.env
```
@@ -40,7 +44,7 @@ Use **system scope** Quadlet units instead:
```bash
mkdir -p /etc/containers/systemd
mkdir -p /etc/pentestagent
mkdir -p /var/lib/pentestagent/{ollama,loot,workspace}
mkdir -p /var/lib/pentestagent/{ollama,loot,workspace,zap}
cp quadlet/*.network /etc/containers/systemd/
cp quadlet/*.pod /etc/containers/systemd/
@@ -48,6 +52,8 @@ cp quadlet/ollama.container /etc/containers/systemd/
cp quadlet/litellm.container /etc/containers/systemd/
cp quadlet/pentestagent.container /etc/containers/systemd/
cp quadlet/pentestagent-kali.container /etc/containers/systemd/
cp quadlet/zap.container /etc/containers/systemd/
cp quadlet/mcp-zap-server.container /etc/containers/systemd/
cp config/litellm-config.yaml /etc/pentestagent/litellm-config.yaml
cp config/pentestagent.env.example /etc/pentestagent/pentestagent.env
```
@@ -73,6 +79,8 @@ systemctl start pentestagent-network.service
systemctl start pentestagent-pod.service
systemctl start ollama.service
systemctl start litellm.service
systemctl start zap.service
systemctl start mcp-zap-server.service
# Choose one runtime container (standard OR kali)
systemctl start pentestagent.service
@@ -98,6 +106,8 @@ systemctl --user start pentestagent-network.service
systemctl --user start pentestagent-pod.service
systemctl --user start ollama.service
systemctl --user start litellm.service
systemctl --user start zap.service
systemctl --user start mcp-zap-server.service
# Choose one runtime container (standard OR kali)
systemctl --user start pentestagent.service
@@ -115,6 +125,81 @@ journalctl --user -u ollama -u litellm -u pentestagent -f
- LiteLLM endpoint: `http://127.0.0.1:4000`
- Ollama endpoint: `http://127.0.0.1:11434`
- MCP ZAP Server (HTTP MCP): `http://127.0.0.1:7456/mcp`
## 4b) Wire MCP ZAP into PentestAgent
`GH05TCREW/pentestagent` supports MCP server config via `mcp_servers.json` and supports `type: "sse"` with optional `bearer` auth.
Use this example as a starting point:
```bash
cp config/mcp_servers.zap.example.json mcp_servers.json
```
Then set the bearer token to the same value as `MCP_API_KEY` from your `pentestagent.env`:
```json
{
"mcpServers": {
"zap-mcp-server": {
"type": "sse",
"description": "OWASP ZAP MCP server via streamable HTTP",
"url": "http://127.0.0.1:7456/mcp",
"bearer": "<MCP_API_KEY>"
}
}
}
```
Validate from inside your PentestAgent environment:
```bash
pentestagent mcp list
pentestagent mcp test zap-mcp-server
```
If `mcp_servers.json` is not in the current working directory, PentestAgent also checks:
- `./mcp.json`
- `~/.pentestagent/mcp_servers.json`
### Optional: no-auth lab profile (development only)
If you explicitly set the MCP ZAP server to no-auth mode in your env:
```bash
# in ~/.config/pentestagent/pentestagent.env (or /etc/pentestagent/pentestagent.env)
MCP_SECURITY_MODE=none
```
you can use this client config without a bearer token:
```bash
cp config/mcp_servers.zap.noauth.example.json mcp_servers.json
```
This mode is for trusted/local lab setups only.
### Helper: switch MCP client profile automatically
Use the helper script to generate `mcp_servers.json` for PentestAgent:
```bash
chmod +x scripts/switch-zap-mcp-profile.sh
# Auth profile (auto-reads MCP_API_KEY from env file)
./scripts/switch-zap-mcp-profile.sh auth
# Auth profile with explicit token/path
./scripts/switch-zap-mcp-profile.sh auth --bearer "<MCP_API_KEY>" --output /workspace/mcp_servers.json
# System scope env lookup (/etc/pentestagent/pentestagent.env)
./scripts/switch-zap-mcp-profile.sh auth --scope system
# No-auth lab profile
./scripts/switch-zap-mcp-profile.sh noauth
```
Before first use, pull your selected Ollama model (required):
+10
View File
@@ -0,0 +1,10 @@
{
"mcpServers": {
"zap-mcp-server": {
"type": "sse",
"description": "OWASP ZAP MCP server via streamable HTTP",
"url": "http://127.0.0.1:7456/mcp",
"bearer": "REPLACE_WITH_MCP_API_KEY"
}
}
}
@@ -0,0 +1,9 @@
{
"mcpServers": {
"zap-mcp-server": {
"type": "sse",
"description": "OWASP ZAP MCP server via streamable HTTP (NO AUTH - LAB ONLY)",
"url": "http://127.0.0.1:7456/mcp"
}
}
}
+27
View File
@@ -13,3 +13,30 @@ ANTHROPIC_API_KEY=
# Optional LiteLLM security
LITELLM_MASTER_KEY=
# Optional MCP ZAP Server / OWASP ZAP integration
# Generate secure keys before enabling these services.
# Example:
# openssl rand -hex 32
#
# ZAP API key used by the OWASP ZAP daemon inside the `zap` container.
ZAP_API_KEY=
# API key used by the MCP ZAP Server for client authentication.
MCP_API_KEY=
# Optional: enable stricter MCP security modes.
# See upstream docs: https://github.com/dtkmn/mcp-zap-server
# MCP_SECURITY_MODE=api-key
# MCP_SECURITY_ENABLED=true
# JWT_ENABLED=true
# JWT_SECRET=change-me-to-a-long-random-string
# Optional: relax URL security for local/private targets (use with care).
# ZAP_ALLOW_LOCALHOST=true
# ZAP_ALLOW_PRIVATE_NETWORKS=true
# ZAP_URL_WHITELIST=
# Optional: scan limits (in minutes).
# ZAP_MAX_ACTIVE_SCAN_DURATION=30
# ZAP_MAX_SPIDER_SCAN_DURATION=15
+22
View File
@@ -0,0 +1,22 @@
[Unit]
Description=MCP ZAP Server container in PentestAgent pod
Requires=zap.service
After=zap.service
[Container]
ContainerName=mcp-zap-server
Image=ghcr.io/dtkmn/mcp-zap-server:latest
Pod=pentestagent.pod
EnvironmentFile=%h/.config/pentestagent/pentestagent.env
Environment=ZAP_API_URL=127.0.0.1
Environment=ZAP_API_PORT=8090
Environment=LOCAL_ZAP_WORKPLACE_FOLDER=/zap/wrk
Volume=%h/.local/share/pentestagent/zap:/zap/wrk:Z
[Service]
ExecStartPre=-/usr/bin/podman rm -f mcp-zap-server
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
+1
View File
@@ -8,6 +8,7 @@ PodName=pentestagent
Network=pentestagent-net
PublishPort=4000:4000
PublishPort=11434:11434
PublishPort=7456:7456
[Install]
WantedBy=default.target
+20
View File
@@ -0,0 +1,20 @@
[Unit]
Description=OWASP ZAP daemon for MCP ZAP Server in PentestAgent pod
Requires=pentestagent-pod.service
After=pentestagent-pod.service
[Container]
ContainerName=zap
Image=zaproxy/zap-stable
Pod=pentestagent.pod
EnvironmentFile=%h/.config/pentestagent/pentestagent.env
Environment=ZAP_MEMORY=4G
Volume=%h/.local/share/pentestagent/zap:/zap/wrk:Z
[Service]
ExecStartPre=-/usr/bin/podman rm -f zap
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
./scripts/switch-zap-mcp-profile.sh <auth|noauth> [--output <path>] [--bearer <token>] [--env-file <path>] [--scope user|system]
Description:
Writes a PentestAgent-compatible mcp_servers.json for MCP ZAP Server.
Profiles:
auth Uses config/mcp_servers.zap.example.json and sets bearer token.
noauth Uses config/mcp_servers.zap.noauth.example.json.
Options:
--output <path> Output JSON file path (default: ./mcp_servers.json)
--bearer <token> Bearer token for auth profile (defaults to MCP_API_KEY from env file)
--env-file <path> Env file to read MCP_API_KEY from (default depends on scope)
--scope user|system Scope for default env file path (default: user)
Examples:
./scripts/switch-zap-mcp-profile.sh auth
./scripts/switch-zap-mcp-profile.sh auth --output /workspace/mcp_servers.json
./scripts/switch-zap-mcp-profile.sh auth --bearer "<MCP_API_KEY>"
./scripts/switch-zap-mcp-profile.sh noauth
./scripts/switch-zap-mcp-profile.sh auth --scope system
EOF
}
if [[ $# -lt 1 ]]; then
usage
exit 1
fi
PROFILE="$1"
OUTPUT="mcp_servers.json"
BEARER=""
ENV_FILE=""
SCOPE="user"
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--output)
if [[ $# -lt 2 ]]; then
echo "Missing value for --output"
exit 1
fi
OUTPUT="$2"
shift 2
;;
--bearer)
if [[ $# -lt 2 ]]; then
echo "Missing value for --bearer"
exit 1
fi
BEARER="$2"
shift 2
;;
--env-file)
if [[ $# -lt 2 ]]; then
echo "Missing value for --env-file"
exit 1
fi
ENV_FILE="$2"
shift 2
;;
--scope)
if [[ $# -lt 2 ]]; then
echo "Missing value for --scope"
exit 1
fi
SCOPE="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1"
usage
exit 1
;;
esac
done
case "$SCOPE" in
user|system)
;;
*)
echo "Invalid scope: $SCOPE (must be user or system)"
exit 1
;;
esac
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
REPO_ROOT="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
AUTH_TEMPLATE="$REPO_ROOT/config/mcp_servers.zap.example.json"
NOAUTH_TEMPLATE="$REPO_ROOT/config/mcp_servers.zap.noauth.example.json"
if [[ ! -f "$AUTH_TEMPLATE" ]]; then
echo "Missing template: $AUTH_TEMPLATE"
exit 1
fi
if [[ ! -f "$NOAUTH_TEMPLATE" ]]; then
echo "Missing template: $NOAUTH_TEMPLATE"
exit 1
fi
if [[ -z "$ENV_FILE" ]]; then
if [[ "$SCOPE" == "system" ]]; then
ENV_FILE="/etc/pentestagent/pentestagent.env"
else
ENV_FILE="$HOME/.config/pentestagent/pentestagent.env"
fi
fi
mkdir -p "$(dirname -- "$OUTPUT")"
extract_mcp_api_key() {
local env_path="$1"
if [[ ! -f "$env_path" ]]; then
return 1
fi
local line value
line="$(grep -E '^MCP_API_KEY=' "$env_path" | tail -n1 || true)"
if [[ -z "$line" ]]; then
return 1
fi
value="${line#MCP_API_KEY=}"
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
if [[ -z "$value" ]]; then
return 1
fi
printf '%s' "$value"
}
case "$PROFILE" in
auth)
if [[ -z "$BEARER" ]]; then
BEARER="$(extract_mcp_api_key "$ENV_FILE" || true)"
fi
if [[ -z "$BEARER" ]]; then
echo "Auth profile requires a bearer token."
echo "Provide --bearer <token> or set MCP_API_KEY in: $ENV_FILE"
exit 1
fi
sed "s|REPLACE_WITH_MCP_API_KEY|$BEARER|g" "$AUTH_TEMPLATE" > "$OUTPUT"
echo "Wrote auth MCP profile to: $OUTPUT"
;;
noauth)
cp "$NOAUTH_TEMPLATE" "$OUTPUT"
echo "Wrote noauth MCP profile to: $OUTPUT"
;;
*)
echo "Invalid profile: $PROFILE (must be auth or noauth)"
exit 1
;;
esac
@@ -55,6 +55,8 @@ UNITS=(
litellm.service
ollama.service
ollama-cpu.service
zap.service
mcp-zap-server.service
pentestagent-pod.service
pentestagent-network.service
)
@@ -71,6 +73,8 @@ case "$SCOPE" in
rm -f "$HOME/.config/containers/systemd/litellm.container"
rm -f "$HOME/.config/containers/systemd/pentestagent.container"
rm -f "$HOME/.config/containers/systemd/pentestagent-kali.container"
rm -f "$HOME/.config/containers/systemd/zap.container"
rm -f "$HOME/.config/containers/systemd/mcp-zap-server.container"
if [[ "$REMOVE_DATA" == "true" ]]; then
rm -rf "$HOME/.config/pentestagent"
@@ -88,6 +92,8 @@ case "$SCOPE" in
rm -f "/etc/containers/systemd/litellm.container"
rm -f "/etc/containers/systemd/pentestagent.container"
rm -f "/etc/containers/systemd/pentestagent-kali.container"
rm -f "/etc/containers/systemd/zap.container"
rm -f "/etc/containers/systemd/mcp-zap-server.container"
if [[ "$REMOVE_DATA" == "true" ]]; then
rm -rf "/etc/pentestagent"