mirror of
https://github.com/BillyOutlast/pentestagent-podman.git
synced 2026-07-01 21:24:07 -04:00
Add OWASP ZAP and MCP ZAP Server integration with configuration updates
This commit is contained in:
@@ -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):
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -8,6 +8,7 @@ PodName=pentestagent
|
||||
Network=pentestagent-net
|
||||
PublishPort=4000:4000
|
||||
PublishPort=11434:11434
|
||||
PublishPort=7456:7456
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user