mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-03-05 04:02:13 +00:00
Compare commits
8 Commits
release/v5
...
mcp-unit-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe2716aed6 | ||
|
|
a190de8f60 | ||
|
|
999299006f | ||
|
|
4c23290c29 | ||
|
|
b774d333e9 | ||
|
|
1471cb2365 | ||
|
|
9a6c81620a | ||
|
|
6d46d38701 |
201
.github/workflows/mcp-publish.yml
vendored
201
.github/workflows/mcp-publish.yml
vendored
@@ -1,201 +0,0 @@
|
||||
name: MCP Registry Publish
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: 'Release tag to publish (e.g., v52.13.0)'
|
||||
type: string
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Dry run - generate server.json but skip actual publishing'
|
||||
type: boolean
|
||||
default: true
|
||||
release_tag:
|
||||
description: 'Release tag to publish (e.g., v52.13.0)'
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
mcp-publish:
|
||||
name: Publish to MCP Registry
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # Required for OIDC authentication with MCP Registry
|
||||
contents: read # Required for checkout
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
# inputs.release_tag works for both workflow_call and workflow_dispatch
|
||||
VERSION="${{ inputs.release_tag }}"
|
||||
echo "tag=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
echo "Publishing MCP server for version: ${VERSION}"
|
||||
|
||||
- name: Download SHA256 files from release
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.tag }}"
|
||||
mkdir -p bin
|
||||
echo "Downloading SHA256 checksums from release ${VERSION}..."
|
||||
for platform in darwin_arm64 darwin_amd64 linux_arm64 linux_amd64 windows_amd64; do
|
||||
url="https://github.com/kubeshark/kubeshark/releases/download/${VERSION}/kubeshark-mcp_${platform}.mcpb.sha256"
|
||||
echo " Fetching ${platform}..."
|
||||
if ! curl -sfL "${url}" -o "bin/kubeshark-mcp_${platform}.mcpb.sha256"; then
|
||||
echo "::warning::Failed to download SHA256 for ${platform}"
|
||||
fi
|
||||
done
|
||||
echo "Downloaded checksums:"
|
||||
ls -la bin/*.sha256 2>/dev/null || echo "No SHA256 files found"
|
||||
|
||||
- name: Generate server.json
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.tag }}"
|
||||
CLEAN_VERSION="${VERSION#v}"
|
||||
|
||||
# Read SHA256 hashes
|
||||
get_sha256() {
|
||||
local file="bin/kubeshark-mcp_$1.mcpb.sha256"
|
||||
if [ -f "$file" ]; then
|
||||
awk '{print $1}' "$file"
|
||||
else
|
||||
echo "HASH_NOT_FOUND"
|
||||
fi
|
||||
}
|
||||
|
||||
DARWIN_ARM64_SHA256=$(get_sha256 "darwin_arm64")
|
||||
DARWIN_AMD64_SHA256=$(get_sha256 "darwin_amd64")
|
||||
LINUX_ARM64_SHA256=$(get_sha256 "linux_arm64")
|
||||
LINUX_AMD64_SHA256=$(get_sha256 "linux_amd64")
|
||||
WINDOWS_AMD64_SHA256=$(get_sha256 "windows_amd64")
|
||||
|
||||
echo "SHA256 hashes:"
|
||||
echo " darwin_arm64: ${DARWIN_ARM64_SHA256}"
|
||||
echo " darwin_amd64: ${DARWIN_AMD64_SHA256}"
|
||||
echo " linux_arm64: ${LINUX_ARM64_SHA256}"
|
||||
echo " linux_amd64: ${LINUX_AMD64_SHA256}"
|
||||
echo " windows_amd64: ${WINDOWS_AMD64_SHA256}"
|
||||
|
||||
# Generate server.json using jq for proper formatting
|
||||
jq -n \
|
||||
--arg version "$CLEAN_VERSION" \
|
||||
--arg full_version "$VERSION" \
|
||||
--arg darwin_arm64_sha "$DARWIN_ARM64_SHA256" \
|
||||
--arg darwin_amd64_sha "$DARWIN_AMD64_SHA256" \
|
||||
--arg linux_arm64_sha "$LINUX_ARM64_SHA256" \
|
||||
--arg linux_amd64_sha "$LINUX_AMD64_SHA256" \
|
||||
--arg windows_amd64_sha "$WINDOWS_AMD64_SHA256" \
|
||||
'{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
||||
"name": "io.github.kubeshark/mcp",
|
||||
"displayName": "Kubeshark",
|
||||
"description": "Real-time Kubernetes network traffic visibility and API analysis for HTTP, gRPC, Redis, Kafka, DNS.",
|
||||
"icon": "https://raw.githubusercontent.com/kubeshark/assets/refs/heads/master/logo/ico/icon.ico",
|
||||
"repository": { "url": "https://github.com/kubeshark/kubeshark", "source": "github" },
|
||||
"homepage": "https://kubeshark.com",
|
||||
"license": "Apache-2.0",
|
||||
"version": $version,
|
||||
"authors": [{ "name": "Kubeshark", "url": "https://kubeshark.com" }],
|
||||
"categories": ["kubernetes", "networking", "observability", "debugging", "security"],
|
||||
"tags": ["kubernetes", "network", "traffic", "api", "http", "grpc", "kafka", "redis", "dns", "pcap", "wireshark", "tcpdump", "observability", "debugging", "microservices"],
|
||||
"packages": [
|
||||
{ "registryType": "mcpb", "identifier": ("https://github.com/kubeshark/kubeshark/releases/download/" + $full_version + "/kubeshark-mcp_darwin_arm64.mcpb"), "fileSha256": $darwin_arm64_sha, "transport": { "type": "stdio" } },
|
||||
{ "registryType": "mcpb", "identifier": ("https://github.com/kubeshark/kubeshark/releases/download/" + $full_version + "/kubeshark-mcp_darwin_amd64.mcpb"), "fileSha256": $darwin_amd64_sha, "transport": { "type": "stdio" } },
|
||||
{ "registryType": "mcpb", "identifier": ("https://github.com/kubeshark/kubeshark/releases/download/" + $full_version + "/kubeshark-mcp_linux_arm64.mcpb"), "fileSha256": $linux_arm64_sha, "transport": { "type": "stdio" } },
|
||||
{ "registryType": "mcpb", "identifier": ("https://github.com/kubeshark/kubeshark/releases/download/" + $full_version + "/kubeshark-mcp_linux_amd64.mcpb"), "fileSha256": $linux_amd64_sha, "transport": { "type": "stdio" } },
|
||||
{ "registryType": "mcpb", "identifier": ("https://github.com/kubeshark/kubeshark/releases/download/" + $full_version + "/kubeshark-mcp_windows_amd64.mcpb"), "fileSha256": $windows_amd64_sha, "transport": { "type": "stdio" } }
|
||||
],
|
||||
"tools": [
|
||||
{ "name": "check_kubeshark_status", "description": "Check if Kubeshark is currently running in the cluster.", "mode": "proxy" },
|
||||
{ "name": "start_kubeshark", "description": "Deploy Kubeshark to the Kubernetes cluster. Requires --allow-destructive flag.", "mode": "proxy", "destructive": true },
|
||||
{ "name": "stop_kubeshark", "description": "Remove Kubeshark from the Kubernetes cluster. Requires --allow-destructive flag.", "mode": "proxy", "destructive": true },
|
||||
{ "name": "list_workloads", "description": "List pods, services, namespaces, and nodes with observed L7 traffic.", "mode": "all" },
|
||||
{ "name": "list_api_calls", "description": "Query L7 API transactions (HTTP, gRPC, Redis, Kafka, DNS) with KFL filtering.", "mode": "all" },
|
||||
{ "name": "get_api_call", "description": "Get detailed information about a specific API call including headers and body.", "mode": "all" },
|
||||
{ "name": "get_api_stats", "description": "Get aggregated API statistics and metrics.", "mode": "all" },
|
||||
{ "name": "list_l4_flows", "description": "List L4 (TCP/UDP) network flows with traffic statistics.", "mode": "all" },
|
||||
{ "name": "get_l4_flow_summary", "description": "Get L4 connectivity summary including top talkers and cross-namespace traffic.", "mode": "all" },
|
||||
{ "name": "list_snapshots", "description": "List all PCAP snapshots.", "mode": "all" },
|
||||
{ "name": "create_snapshot", "description": "Create a new PCAP snapshot of captured traffic.", "mode": "all" },
|
||||
{ "name": "get_dissection_status", "description": "Check L7 protocol parsing status.", "mode": "all" },
|
||||
{ "name": "enable_dissection", "description": "Enable L7 protocol dissection.", "mode": "all" },
|
||||
{ "name": "disable_dissection", "description": "Disable L7 protocol dissection.", "mode": "all" }
|
||||
],
|
||||
"prompts": [
|
||||
{ "name": "analyze_traffic", "description": "Analyze API traffic patterns and identify issues" },
|
||||
{ "name": "find_errors", "description": "Find and summarize API errors and failures" },
|
||||
{ "name": "trace_request", "description": "Trace a request path through microservices" },
|
||||
{ "name": "show_topology", "description": "Show service communication topology" },
|
||||
{ "name": "latency_analysis", "description": "Analyze latency patterns and identify slow endpoints" },
|
||||
{ "name": "security_audit", "description": "Audit traffic for security concerns" },
|
||||
{ "name": "compare_traffic", "description": "Compare traffic patterns between time periods" },
|
||||
{ "name": "debug_connection", "description": "Debug connectivity issues between services" }
|
||||
],
|
||||
"configuration": {
|
||||
"properties": {
|
||||
"url": { "type": "string", "description": "Direct URL to Kubeshark Hub (e.g., https://kubeshark.example.com). When set, connects directly without kubectl/proxy.", "examples": ["https://kubeshark.example.com", "http://localhost:8899"] },
|
||||
"kubeconfig": { "type": "string", "description": "Path to kubeconfig file for proxy mode.", "examples": ["~/.kube/config", "/path/to/.kube/config"] },
|
||||
"allow-destructive": { "type": "boolean", "description": "Enable destructive operations (start_kubeshark, stop_kubeshark). Default: false for safety.", "default": false }
|
||||
}
|
||||
},
|
||||
"modes": {
|
||||
"url": { "description": "Connect directly to an existing Kubeshark deployment via URL. Cluster management tools are disabled.", "args": ["mcp", "--url", "${url}"] },
|
||||
"proxy": { "description": "Connect via kubectl port-forward. Requires kubeconfig access to the cluster.", "args": ["mcp", "--kubeconfig", "${kubeconfig}"] },
|
||||
"proxy-destructive": { "description": "Proxy mode with destructive operations enabled.", "args": ["mcp", "--kubeconfig", "${kubeconfig}", "--allow-destructive"] }
|
||||
}
|
||||
}' > mcp/server.json
|
||||
|
||||
echo ""
|
||||
echo "Generated server.json:"
|
||||
cat mcp/server.json
|
||||
|
||||
- name: Install mcp-publisher
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Installing mcp-publisher..."
|
||||
curl -sfL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" | tar xz
|
||||
chmod +x mcp-publisher
|
||||
sudo mv mcp-publisher /usr/local/bin/
|
||||
echo "mcp-publisher installed successfully"
|
||||
|
||||
- name: Login to MCP Registry
|
||||
if: github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true'
|
||||
shell: bash
|
||||
run: mcp-publisher login github
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish to MCP Registry
|
||||
if: github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
cd mcp
|
||||
echo "Publishing to MCP Registry..."
|
||||
if ! mcp-publisher publish; then
|
||||
echo "::error::Failed to publish to MCP Registry"
|
||||
exit 1
|
||||
fi
|
||||
echo "Successfully published to MCP Registry"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Dry-run summary
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=============================================="
|
||||
echo "DRY RUN - Would publish the following server.json"
|
||||
echo "=============================================="
|
||||
cat mcp/server.json
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo "SHA256 checksums downloaded:"
|
||||
echo "=============================================="
|
||||
cat bin/*.sha256 2>/dev/null || echo "No SHA256 files found"
|
||||
24
.github/workflows/release-tag.yml
vendored
24
.github/workflows/release-tag.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Auto-tag release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create and push tag
|
||||
run: |
|
||||
VERSION="${GITHUB_HEAD_REF#release/}"
|
||||
echo "Creating tag $VERSION on master"
|
||||
git tag "$VERSION"
|
||||
git push origin "$VERSION"
|
||||
26
.github/workflows/release.yml
vendored
26
.github/workflows/release.yml
vendored
@@ -43,23 +43,6 @@ jobs:
|
||||
run: |
|
||||
echo '${{ steps.version.outputs.tag }}' >> bin/version.txt
|
||||
|
||||
- name: Create MCP Registry artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
cd bin
|
||||
# Create .mcpb copies for MCP Registry (URL must contain "mcp")
|
||||
for f in kubeshark_linux_amd64 kubeshark_linux_arm64 kubeshark_darwin_amd64 kubeshark_darwin_arm64; do
|
||||
if [ -f "$f" ]; then
|
||||
cp "$f" "${f/kubeshark_/kubeshark-mcp_}.mcpb"
|
||||
shasum -a 256 "${f/kubeshark_/kubeshark-mcp_}.mcpb" > "${f/kubeshark_/kubeshark-mcp_}.mcpb.sha256"
|
||||
fi
|
||||
done
|
||||
# Handle Windows executable
|
||||
if [ -f "kubeshark.exe" ]; then
|
||||
cp kubeshark.exe kubeshark-mcp_windows_amd64.mcpb
|
||||
shasum -a 256 kubeshark-mcp_windows_amd64.mcpb > kubeshark-mcp_windows_amd64.mcpb.sha256
|
||||
fi
|
||||
|
||||
- name: Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
@@ -67,11 +50,4 @@ jobs:
|
||||
artifacts: "bin/*"
|
||||
tag: ${{ steps.version.outputs.tag }}
|
||||
prerelease: false
|
||||
bodyFile: 'bin/README.md'
|
||||
|
||||
mcp-publish:
|
||||
name: Publish to MCP Registry
|
||||
needs: [release]
|
||||
uses: ./.github/workflows/mcp-publish.yml
|
||||
with:
|
||||
release_tag: ${{ needs.release.outputs.version }}
|
||||
bodyFile: 'bin/README.md'
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -63,7 +63,4 @@ bin
|
||||
scripts/
|
||||
|
||||
# CWD config YAML
|
||||
kubeshark.yaml
|
||||
|
||||
# Claude Code
|
||||
CLAUDE.md
|
||||
kubeshark.yaml
|
||||
68
Makefile
68
Makefile
@@ -242,75 +242,31 @@ proxy:
|
||||
port-forward:
|
||||
kubectl port-forward $$(kubectl get pods | awk '$$1 ~ /^$(POD_PREFIX)/' | awk 'END {print $$1}') $(SRC_PORT):$(DST_PORT)
|
||||
|
||||
release: ## Print release workflow instructions.
|
||||
@echo "Release workflow (2 steps):"
|
||||
@echo ""
|
||||
@echo " 1. make release-pr VERSION=x.y.z"
|
||||
@echo " Tags sibling repos, bumps version, creates PRs"
|
||||
@echo " (kubeshark + kubeshark.github.io helm chart)."
|
||||
@echo " Review and merge both PRs manually."
|
||||
@echo ""
|
||||
@echo " 2. (automatic) Tag is created when release PR merges."
|
||||
@echo " Fallback: make release-tag VERSION=x.y.z"
|
||||
|
||||
release-pr: ## Step 1: Tag sibling repos, bump version, create release PR.
|
||||
release:
|
||||
@cd ../worker && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags
|
||||
@cd ../tracer && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags
|
||||
@cd ../hub && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags
|
||||
@cd ../front && git checkout master && git pull && git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags
|
||||
@cd ../kubeshark && git checkout master && git pull
|
||||
@sed -i "s/^version:.*/version: \"$(shell echo $(VERSION) | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+)\..*/\1/')\"/" helm-chart/Chart.yaml
|
||||
@$(MAKE) build VER=$(VERSION)
|
||||
@cd ../kubeshark && git checkout master && git pull && sed -i "s/^version:.*/version: \"$(shell echo $(VERSION) | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+)\..*/\1/')\"/" helm-chart/Chart.yaml && make
|
||||
@if [ "$(shell uname)" = "Darwin" ]; then \
|
||||
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime ./bin/kubeshark__; \
|
||||
fi
|
||||
@$(MAKE) generate-helm-values && $(MAKE) generate-manifests
|
||||
@git checkout -b release/v$(VERSION)
|
||||
@git add -A .
|
||||
@git commit -m ":bookmark: Bump the Helm chart version to $(VERSION)"
|
||||
@git push -u origin release/v$(VERSION)
|
||||
@gh pr create --title ":bookmark: Release v$(VERSION)" \
|
||||
--body "Automated release PR for v$(VERSION)." \
|
||||
--base master \
|
||||
--reviewer corest
|
||||
@rm -rf ../kubeshark.github.io/charts/chart
|
||||
@mkdir ../kubeshark.github.io/charts/chart
|
||||
@cp -r helm-chart/ ../kubeshark.github.io/charts/chart/
|
||||
@cd ../kubeshark.github.io && git checkout master && git pull \
|
||||
&& git checkout -b helm-v$(VERSION) \
|
||||
&& git add -A . \
|
||||
&& git commit -m ":sparkles: Update the Helm chart to v$(VERSION)" \
|
||||
&& git push -u origin helm-v$(VERSION) \
|
||||
&& gh pr create --title ":sparkles: Helm chart v$(VERSION)" \
|
||||
--body "Update Helm chart for release v$(VERSION)." \
|
||||
--base master \
|
||||
--reviewer corest
|
||||
@make generate-helm-values && make generate-manifests
|
||||
@git add -A . && git commit -m ":bookmark: Bump the Helm chart version to $(VERSION)" && git push
|
||||
@git tag -d v$(VERSION); git tag v$(VERSION) && git push origin --tags
|
||||
@rm -rf ../kubeshark.github.io/charts/chart && mkdir ../kubeshark.github.io/charts/chart && cp -r helm-chart/ ../kubeshark.github.io/charts/chart/
|
||||
@cd ../kubeshark.github.io/ && git add -A . && git commit -m ":sparkles: Update the Helm chart" && git push
|
||||
@cd ../kubeshark
|
||||
@echo ""
|
||||
@echo "Release PRs created:"
|
||||
@echo " - kubeshark: Review and merge the release PR."
|
||||
@echo " - kubeshark.github.io: Review and merge the helm chart PR."
|
||||
@echo "Tag will be created automatically, or run: make release-tag VERSION=$(VERSION)"
|
||||
|
||||
release-tag: ## Step 2 (fallback): Tag master after release PR is merged.
|
||||
@echo "Verifying release PR was merged..."
|
||||
@if ! gh pr list --state merged --head release/v$(VERSION) --json number --jq '.[0].number' | grep -q .; then \
|
||||
echo "Error: No merged PR found for release/v$(VERSION). Merge the PR first."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@git checkout master && git pull
|
||||
@git tag -d v$(VERSION) 2>/dev/null; git tag v$(VERSION) && git push origin --tags
|
||||
@echo ""
|
||||
@echo "Tagged v$(VERSION) on master. GitHub Actions will build the release."
|
||||
|
||||
release-dry-run:
|
||||
@cd ../worker && git checkout master && git pull
|
||||
# @cd ../tracer && git checkout master && git pull
|
||||
@cd ../tracer && git checkout master && git pull
|
||||
@cd ../hub && git checkout master && git pull
|
||||
@cd ../front && git checkout master && git pull
|
||||
@cd ../kubeshark && sed -i "s/^version:.*/version: \"$(shell echo $(VERSION) | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+)\..*/\1/')\"/" helm-chart/Chart.yaml && make
|
||||
# @if [ "$(shell uname)" = "Darwin" ]; then \
|
||||
# codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime ./bin/kubeshark__; \
|
||||
# fi
|
||||
@if [ "$(shell uname)" = "Darwin" ]; then \
|
||||
codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime ./bin/kubeshark__; \
|
||||
fi
|
||||
@make generate-helm-values && make generate-manifests
|
||||
@rm -rf ../kubeshark.github.io/charts/chart && mkdir ../kubeshark.github.io/charts/chart && cp -r helm-chart/ ../kubeshark.github.io/charts/chart/
|
||||
@cd ../kubeshark.github.io/
|
||||
|
||||
180
README.md
180
README.md
@@ -1,132 +1,98 @@
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg" alt="Kubeshark" height="120px"/>
|
||||
<img src="https://raw.githubusercontent.com/kubeshark/assets/master/svg/kubeshark-logo.svg" alt="Kubeshark: Traffic analyzer for Kubernetes." height="128px"/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/kubeshark/kubeshark/releases/latest"><img alt="Release" src="https://img.shields.io/github/v/release/kubeshark/kubeshark?logo=GitHub&style=flat-square"></a>
|
||||
<a href="https://hub.docker.com/r/kubeshark/worker"><img alt="Docker pulls" src="https://img.shields.io/docker/pulls/kubeshark/worker?color=%23099cec&logo=Docker&style=flat-square"></a>
|
||||
<a href="https://discord.gg/WkvRGMUcx7"><img alt="Discord" src="https://img.shields.io/discord/1042559155224973352?logo=Discord&style=flat-square&label=discord"></a>
|
||||
<a href="https://join.slack.com/t/kubeshark/shared_invite/zt-3jdcdgxdv-1qNkhBh9c6CFoE7bSPkpBQ"><img alt="Slack" src="https://img.shields.io/badge/slack-join_chat-green?logo=Slack&style=flat-square"></a>
|
||||
<a href="https://github.com/kubeshark/kubeshark/releases/latest">
|
||||
<img alt="GitHub Latest Release" src="https://img.shields.io/github/v/release/kubeshark/kubeshark?logo=GitHub&style=flat-square">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/kubeshark/worker">
|
||||
<img alt="Docker pulls" src="https://img.shields.io/docker/pulls/kubeshark/worker?color=%23099cec&logo=Docker&style=flat-square">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/kubeshark/worker">
|
||||
<img alt="Image size" src="https://img.shields.io/docker/image-size/kubeshark/kubeshark/latest?logo=Docker&style=flat-square">
|
||||
</a>
|
||||
<a href="https://discord.gg/WkvRGMUcx7">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/1042559155224973352?logo=Discord&style=flat-square&label=discord">
|
||||
</a>
|
||||
<a href="https://join.slack.com/t/kubeshark/shared_invite/zt-3jdcdgxdv-1qNkhBh9c6CFoE7bSPkpBQ">
|
||||
<img alt="Slack" src="https://img.shields.io/badge/slack-join_chat-green?logo=Slack&style=flat-square&label=slack">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center"><b>Network Intelligence for Kubernetes</b></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://demo.kubeshark.com/">Live Demo</a> · <a href="https://docs.kubeshark.com">Docs</a>
|
||||
<b>
|
||||
Want to see Kubeshark in action right now? Visit this
|
||||
<a href="https://demo.kubeshark.com/">live demo deployment</a> of Kubeshark.
|
||||
</b>
|
||||
</p>
|
||||
|
||||
---
|
||||
**Kubeshark** is an API traffic analyzer for Kubernetes, providing deep packet inspection with complete API and Kubernetes contexts, retaining cluster-wide L4 traffic (PCAP), and using minimal production compute resources.
|
||||
|
||||
* **Cluster-wide, real-time visibility into every packet, API call, and service interaction.**
|
||||
* Replay any moment in time.
|
||||
* Resolve incidents at the speed of LLMs. 100% on-premises.
|
||||

|
||||
|
||||

|
||||
Think [TCPDump](https://en.wikipedia.org/wiki/Tcpdump) and [Wireshark](https://www.wireshark.org/) reimagined for Kubernetes.
|
||||
|
||||
---
|
||||
Access cluster-wide PCAP traffic by pressing a single button, without the need to install `tcpdump` or manually copy files. Understand the traffic context in relation to the API and Kubernetes contexts.
|
||||
|
||||
## Get Started
|
||||
#### Service-Map w/Kubernetes Context
|
||||
|
||||
```bash
|
||||

|
||||
|
||||
#### Export Cluster-Wide L4 Traffic (PCAP)
|
||||
|
||||
Imagine having a cluster-wide [TCPDump](https://www.tcpdump.org/)-like capability—exporting a single [PCAP](https://www.ietf.org/archive/id/draft-gharris-opsawg-pcap-01.html) file that consolidates traffic from multiple nodes, all accessible with a single click.
|
||||
|
||||
1. Go to the **Snapshots** tab
|
||||
2. Create a new snapshot
|
||||
3. **Optionally** select the nodes (default: all nodes)
|
||||
4. **Optionally** select the time frame (default: last one hour)
|
||||
5. Press **Create**
|
||||
|
||||
<img width="3342" height="1206" alt="image" src="https://github.com/user-attachments/assets/e8e47996-52b7-4028-9698-f059a13ffdb7" />
|
||||
|
||||
|
||||
Once the snapshot is ready, click the PCAP file to export its contents and open it in Wireshark.
|
||||
|
||||
## Getting Started
|
||||
Download **Kubeshark**'s binary distribution [latest release](https://github.com/kubeshark/kubeshark/releases/latest) or use one of the following methods to deploy **Kubeshark**. The [web-based dashboard](https://docs.kubeshark.com/en/ui) should open in your browser, showing a real-time view of your cluster's traffic.
|
||||
|
||||
### Homebrew
|
||||
|
||||
[Homebrew](https://brew.sh/) :beer: users can install the Kubeshark CLI with:
|
||||
|
||||
```shell
|
||||
brew install kubeshark
|
||||
kubeshark tap
|
||||
```
|
||||
|
||||
To clean up:
|
||||
```shell
|
||||
kubeshark clean
|
||||
```
|
||||
|
||||
### Helm
|
||||
|
||||
Add the Helm repository and install the chart:
|
||||
|
||||
```shell
|
||||
helm repo add kubeshark https://helm.kubeshark.com
|
||||
helm install kubeshark kubeshark/kubeshark
|
||||
```
|
||||
Follow the on-screen instructions how to connect to the dashboard.
|
||||
|
||||
Dashboard opens automatically. You're capturing traffic.
|
||||
|
||||
**With AI** — connect your assistant and debug with natural language:
|
||||
|
||||
```bash
|
||||
brew install kubeshark
|
||||
claude mcp add kubeshark -- kubeshark mcp
|
||||
To clean up:
|
||||
```shell
|
||||
helm uninstall kubeshark
|
||||
```
|
||||
|
||||
> *"Why did checkout fail at 2:15 PM?"*
|
||||
> *"Which services have error rates above 1%?"*
|
||||
## Building From Source
|
||||
|
||||
[MCP setup guide →](https://docs.kubeshark.com/en/mcp)
|
||||
Clone this repository and run the `make` command to build it. After the build is complete, the executable can be found at `./bin/kubeshark`.
|
||||
|
||||
---
|
||||
## Documentation
|
||||
|
||||
## Why Kubeshark
|
||||
|
||||
- **Instant root cause** — trace requests across services, see exact errors
|
||||
- **Zero instrumentation** — no code changes, no SDKs, just deploy
|
||||
- **Full payload capture** — request/response bodies, headers, timing
|
||||
- **TLS decryption** — see encrypted traffic without managing keys
|
||||
- **AI-ready** — query traffic with natural language via MCP
|
||||
|
||||
---
|
||||
|
||||
### Traffic Analysis and API Dissection
|
||||
|
||||
Capture and inspect every API call across your cluster—HTTP, gRPC, Redis, Kafka, DNS, and more. Request/response matching with full payloads, parsed according to protocol specifications. Headers, timing, and complete context. Zero instrumentation required.
|
||||
|
||||

|
||||
|
||||
[Learn more →](https://docs.kubeshark.com/en/v2/l7_api_dissection)
|
||||
|
||||
### L4/L7 Workload Map
|
||||
|
||||
Visualize how your services communicate. See dependencies, traffic flow, and identify anomalies at a glance.
|
||||
|
||||

|
||||
|
||||
[Learn more →](https://docs.kubeshark.com/en/v2/service_map)
|
||||
|
||||
### AI-Powered Root Cause Analysis
|
||||
|
||||
Resolve production issues in minutes instead of hours. Connect your AI assistant and investigate incidents using natural language. Build network-aware AI agents for forensics, monitoring, compliance, and security.
|
||||
|
||||
> *"Why did checkout fail at 2:15 PM?"*
|
||||
> *"Which services have error rates above 1%?"*
|
||||
> *"Trace request abc123 through all services"*
|
||||
|
||||
Works with Claude Code, Cursor, and any MCP-compatible AI.
|
||||
|
||||
[MCP setup guide →](https://docs.kubeshark.com/en/mcp)
|
||||
|
||||
### Traffic Retention
|
||||
|
||||
Retain every packet. Take snapshots. Export PCAP files. Replay any moment in time.
|
||||
|
||||

|
||||
|
||||
[Snapshots guide →](https://docs.kubeshark.com/en/v2/traffic_snapshots)
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| [**Raw Capture**](https://docs.kubeshark.com/en/v2/raw_capture) | Continuous cluster-wide packet capture with minimal overhead |
|
||||
| [**Traffic Snapshots**](https://docs.kubeshark.com/en/v2/traffic_snapshots) | Point-in-time snapshots, export as PCAP for Wireshark |
|
||||
| [**L7 API Dissection**](https://docs.kubeshark.com/en/v2/l7_api_dissection) | Request/response matching with full payloads and protocol parsing |
|
||||
| [**Protocol Support**](https://docs.kubeshark.com/en/protocols) | HTTP, gRPC, GraphQL, Redis, Kafka, DNS, and more |
|
||||
| [**TLS Decryption**](https://docs.kubeshark.com/en/encrypted_traffic) | eBPF-based decryption without key management |
|
||||
| [**AI-Powered Analysis**](https://docs.kubeshark.com/en/v2/ai_powered_analysis) | Query traffic with Claude, Cursor, or any MCP-compatible AI |
|
||||
| [**Display Filters**](https://docs.kubeshark.com/en/v2/kfl2) | Wireshark-inspired display filters for precise traffic analysis |
|
||||
| [**100% On-Premises**](https://docs.kubeshark.com/en/air_gapped) | Air-gapped support, no external dependencies |
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
| Method | Command |
|
||||
|--------|---------|
|
||||
| Helm | `helm repo add kubeshark https://helm.kubeshark.com && helm install kubeshark kubeshark/kubeshark` |
|
||||
| Homebrew | `brew install kubeshark && kubeshark tap` |
|
||||
| Binary | [Download](https://github.com/kubeshark/kubeshark/releases/latest) |
|
||||
|
||||
[Installation guide →](https://docs.kubeshark.com/en/install)
|
||||
|
||||
---
|
||||
To learn more, read the [documentation](https://docs.kubeshark.com).
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
[Apache-2.0](LICENSE)
|
||||
We :heart: pull requests! See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution guide.
|
||||
|
||||
169
cmd/mcpRunner.go
169
cmd/mcpRunner.go
@@ -10,7 +10,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -325,16 +324,6 @@ func (s *mcpServer) invalidateHubMCPCache() {
|
||||
s.cachedHubMCP = nil
|
||||
}
|
||||
|
||||
// getBaseURL returns the hub API base URL by stripping /mcp from hubBaseURL.
|
||||
// The hub URL is always the frontend URL + /api, and hubBaseURL is frontendURL/api/mcp.
|
||||
// Ensures backend connection is established first.
|
||||
func (s *mcpServer) getBaseURL() (string, error) {
|
||||
if errMsg := s.ensureBackendConnection(); errMsg != "" {
|
||||
return "", fmt.Errorf("%s", errMsg)
|
||||
}
|
||||
return strings.TrimSuffix(s.hubBaseURL, "/mcp"), nil
|
||||
}
|
||||
|
||||
func writeErrorToStderr(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
}
|
||||
@@ -390,14 +379,6 @@ func (s *mcpServer) handleRequest(req *jsonRPCRequest) {
|
||||
|
||||
func (s *mcpServer) handleInitialize(req *jsonRPCRequest) {
|
||||
var instructions string
|
||||
fileDownloadInstructions := `
|
||||
|
||||
Downloading files (e.g., PCAP exports):
|
||||
When a tool like export_snapshot_pcap returns a relative file path, you MUST use the file tools to retrieve the file:
|
||||
- get_file_url: Resolves the relative path to a full download URL you can share with the user.
|
||||
- download_file: Downloads the file to the local filesystem so it can be opened or analyzed.
|
||||
Typical workflow: call export_snapshot_pcap → receive a relative path → call download_file with that path → share the local file path with the user.`
|
||||
|
||||
if s.urlMode {
|
||||
instructions = fmt.Sprintf(`Kubeshark MCP Server - Connected to: %s
|
||||
|
||||
@@ -411,7 +392,7 @@ Available tools for traffic analysis:
|
||||
- get_api_stats: Get aggregated API statistics
|
||||
- And more - use tools/list to see all available tools
|
||||
|
||||
Use the MCP tools directly - do NOT use kubectl or curl to access Kubeshark.`, s.directURL) + fileDownloadInstructions
|
||||
Use the MCP tools directly - do NOT use kubectl or curl to access Kubeshark.`, s.directURL)
|
||||
} else if s.allowDestructive {
|
||||
instructions = `Kubeshark MCP Server - Proxy Mode (Destructive Operations ENABLED)
|
||||
|
||||
@@ -429,7 +410,7 @@ Safe operations:
|
||||
Traffic analysis tools (require Kubeshark to be running):
|
||||
- list_workloads, list_api_calls, list_l4_flows, get_api_stats, and more
|
||||
|
||||
Use the MCP tools - do NOT use kubectl, helm, or curl directly.` + fileDownloadInstructions
|
||||
Use the MCP tools - do NOT use kubectl, helm, or curl directly.`
|
||||
} else {
|
||||
instructions = `Kubeshark MCP Server - Proxy Mode (Read-Only)
|
||||
|
||||
@@ -444,7 +425,7 @@ Available operations:
|
||||
Traffic analysis tools (require Kubeshark to be running):
|
||||
- list_workloads, list_api_calls, list_l4_flows, get_api_stats, and more
|
||||
|
||||
Use the MCP tools - do NOT use kubectl, helm, or curl directly.` + fileDownloadInstructions
|
||||
Use the MCP tools - do NOT use kubectl, helm, or curl directly.`
|
||||
}
|
||||
|
||||
result := mcpInitializeResult{
|
||||
@@ -475,40 +456,6 @@ func (s *mcpServer) handleListTools(req *jsonRPCRequest) {
|
||||
}`),
|
||||
})
|
||||
|
||||
// Add file URL and download tools - available in all modes
|
||||
tools = append(tools, mcpTool{
|
||||
Name: "get_file_url",
|
||||
Description: "When a tool (e.g., export_snapshot_pcap) returns a relative file path, use this tool to resolve it into a fully-qualified download URL. The URL can be shared with the user for manual download.",
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The relative file path returned by a Hub tool (e.g., '/snapshots/abc/data.pcap')"
|
||||
}
|
||||
},
|
||||
"required": ["path"]
|
||||
}`),
|
||||
})
|
||||
tools = append(tools, mcpTool{
|
||||
Name: "download_file",
|
||||
Description: "When a tool (e.g., export_snapshot_pcap) returns a relative file path, use this tool to download the file to the local filesystem. This is the preferred way to retrieve PCAP exports and other files from Kubeshark.",
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "The relative file path returned by a Hub tool (e.g., '/snapshots/abc/data.pcap')"
|
||||
},
|
||||
"dest": {
|
||||
"type": "string",
|
||||
"description": "Local destination file path. If not provided, uses the filename from the path in the current directory."
|
||||
}
|
||||
},
|
||||
"required": ["path"]
|
||||
}`),
|
||||
})
|
||||
|
||||
// Add destructive tools only if --allow-destructive flag was set (and not in URL mode)
|
||||
if !s.urlMode && s.allowDestructive {
|
||||
tools = append(tools, mcpTool{
|
||||
@@ -706,20 +653,6 @@ func (s *mcpServer) handleCallTool(req *jsonRPCRequest) {
|
||||
IsError: isError,
|
||||
})
|
||||
return
|
||||
case "get_file_url":
|
||||
result, isError = s.callGetFileURL(params.Arguments)
|
||||
s.sendResult(req.ID, mcpCallToolResult{
|
||||
Content: []mcpContent{{Type: "text", Text: result}},
|
||||
IsError: isError,
|
||||
})
|
||||
return
|
||||
case "download_file":
|
||||
result, isError = s.callDownloadFile(params.Arguments)
|
||||
s.sendResult(req.ID, mcpCallToolResult{
|
||||
Content: []mcpContent{{Type: "text", Text: result}},
|
||||
IsError: isError,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Forward Hub tools to the API
|
||||
@@ -738,7 +671,7 @@ func (s *mcpServer) callHubTool(toolName string, args map[string]any) (string, b
|
||||
|
||||
// Build the request body
|
||||
requestBody := map[string]any{
|
||||
"name": toolName,
|
||||
"tool": toolName,
|
||||
"arguments": args,
|
||||
}
|
||||
|
||||
@@ -773,91 +706,6 @@ func (s *mcpServer) callHubTool(toolName string, args map[string]any) (string, b
|
||||
}
|
||||
|
||||
|
||||
func (s *mcpServer) callGetFileURL(args map[string]any) (string, bool) {
|
||||
filePath, _ := args["path"].(string)
|
||||
if filePath == "" {
|
||||
return "Error: 'path' parameter is required", true
|
||||
}
|
||||
|
||||
baseURL, err := s.getBaseURL()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error: %v", err), true
|
||||
}
|
||||
|
||||
// Ensure path starts with /
|
||||
if !strings.HasPrefix(filePath, "/") {
|
||||
filePath = "/" + filePath
|
||||
}
|
||||
|
||||
fullURL := strings.TrimSuffix(baseURL, "/") + filePath
|
||||
return fullURL, false
|
||||
}
|
||||
|
||||
func (s *mcpServer) callDownloadFile(args map[string]any) (string, bool) {
|
||||
filePath, _ := args["path"].(string)
|
||||
if filePath == "" {
|
||||
return "Error: 'path' parameter is required", true
|
||||
}
|
||||
|
||||
baseURL, err := s.getBaseURL()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error: %v", err), true
|
||||
}
|
||||
|
||||
// Ensure path starts with /
|
||||
if !strings.HasPrefix(filePath, "/") {
|
||||
filePath = "/" + filePath
|
||||
}
|
||||
|
||||
fullURL := strings.TrimSuffix(baseURL, "/") + filePath
|
||||
|
||||
// Determine destination file path
|
||||
dest, _ := args["dest"].(string)
|
||||
if dest == "" {
|
||||
dest = path.Base(filePath)
|
||||
}
|
||||
|
||||
// Use a dedicated HTTP client for file downloads.
|
||||
// The default s.httpClient has a 30s total timeout which would fail for large files (up to 10GB).
|
||||
// This client sets only connection-level timeouts and lets the body stream without a deadline.
|
||||
downloadClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ResponseHeaderTimeout: 30 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := downloadClient.Get(fullURL)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error downloading file: %v", err), true
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
return fmt.Sprintf("Error downloading file: HTTP %d", resp.StatusCode), true
|
||||
}
|
||||
|
||||
// Write to destination
|
||||
outFile, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error creating file %s: %v", dest, err), true
|
||||
}
|
||||
defer func() { _ = outFile.Close() }()
|
||||
|
||||
written, err := io.Copy(outFile, resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error writing file %s: %v", dest, err), true
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"url": fullURL,
|
||||
"path": dest,
|
||||
"size": written,
|
||||
}
|
||||
resultBytes, _ := json.MarshalIndent(result, "", " ")
|
||||
return string(resultBytes), false
|
||||
}
|
||||
|
||||
func (s *mcpServer) callStartKubeshark(args map[string]any) (string, bool) {
|
||||
// Build the kubeshark tap command
|
||||
cmdArgs := []string{"tap"}
|
||||
@@ -1065,11 +913,6 @@ func listMCPTools(directURL string) {
|
||||
fmt.Printf("URL Mode: %s\n\n", directURL)
|
||||
fmt.Println("Cluster management tools disabled (Kubeshark managed externally)")
|
||||
fmt.Println()
|
||||
fmt.Println("Local Tools:")
|
||||
fmt.Println(" check_kubeshark_status Check if Kubeshark is running")
|
||||
fmt.Println(" get_file_url Resolve a relative path to a full download URL")
|
||||
fmt.Println(" download_file Download a file from Kubeshark to local disk")
|
||||
fmt.Println()
|
||||
|
||||
hubURL := strings.TrimSuffix(directURL, "/") + "/api/mcp"
|
||||
fetchAndDisplayTools(hubURL, 30*time.Second)
|
||||
@@ -1082,10 +925,6 @@ func listMCPTools(directURL string) {
|
||||
fmt.Println(" start_kubeshark Start Kubeshark to capture traffic")
|
||||
fmt.Println(" stop_kubeshark Stop Kubeshark and clean up resources")
|
||||
fmt.Println()
|
||||
fmt.Println("File Tools:")
|
||||
fmt.Println(" get_file_url Resolve a relative path to a full download URL")
|
||||
fmt.Println(" download_file Download a file from Kubeshark to local disk")
|
||||
fmt.Println()
|
||||
|
||||
// Establish proxy connection to Kubeshark
|
||||
fmt.Println("Connecting to Kubeshark...")
|
||||
|
||||
205
cmd/mcp_test.go
205
cmd/mcp_test.go
@@ -5,8 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -128,18 +126,8 @@ func TestMCP_ToolsList_CLIOnly(t *testing.T) {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
tools := resp.Result.(map[string]any)["tools"].([]any)
|
||||
// Should have check_kubeshark_status + get_file_url + download_file = 3 tools
|
||||
if len(tools) != 3 {
|
||||
t.Errorf("Expected 3 tools, got %d", len(tools))
|
||||
}
|
||||
toolNames := make(map[string]bool)
|
||||
for _, tool := range tools {
|
||||
toolNames[tool.(map[string]any)["name"].(string)] = true
|
||||
}
|
||||
for _, expected := range []string{"check_kubeshark_status", "get_file_url", "download_file"} {
|
||||
if !toolNames[expected] {
|
||||
t.Errorf("Missing expected tool: %s", expected)
|
||||
}
|
||||
if len(tools) != 1 || tools[0].(map[string]any)["name"] != "check_kubeshark_status" {
|
||||
t.Error("Expected only check_kubeshark_status tool")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,9 +163,9 @@ func TestMCP_ToolsList_WithHubBackend(t *testing.T) {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
tools := resp.Result.(map[string]any)["tools"].([]any)
|
||||
// Should have CLI tools (3) + file tools (2) + Hub tools (2) = 7 tools
|
||||
if len(tools) < 7 {
|
||||
t.Errorf("Expected at least 7 tools, got %d", len(tools))
|
||||
// Should have CLI tools (3) + Hub tools (2) = 5 tools
|
||||
if len(tools) < 5 {
|
||||
t.Errorf("Expected at least 5 tools, got %d", len(tools))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +218,7 @@ func newTestMCPServerWithMockBackend(handler http.HandlerFunc) (*mcpServer, *htt
|
||||
}
|
||||
|
||||
type hubToolCallRequest struct {
|
||||
Tool string `json:"name"`
|
||||
Tool string `json:"tool"`
|
||||
Arguments map[string]any `json:"arguments"`
|
||||
}
|
||||
|
||||
@@ -475,187 +463,6 @@ func TestMCP_BackendInitialization_Concurrent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_GetFileURL_ProxyMode(t *testing.T) {
|
||||
s := &mcpServer{
|
||||
httpClient: &http.Client{},
|
||||
stdin: &bytes.Buffer{},
|
||||
stdout: &bytes.Buffer{},
|
||||
hubBaseURL: "http://127.0.0.1:8899/api/mcp",
|
||||
backendInitialized: true,
|
||||
}
|
||||
resp := parseResponse(t, sendRequest(s, "tools/call", 1, mcpCallToolParams{
|
||||
Name: "get_file_url",
|
||||
Arguments: map[string]any{"path": "/snapshots/abc/data.pcap"},
|
||||
}))
|
||||
if resp.Error != nil {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
text := resp.Result.(map[string]any)["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
expected := "http://127.0.0.1:8899/api/snapshots/abc/data.pcap"
|
||||
if text != expected {
|
||||
t.Errorf("Expected %q, got %q", expected, text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_GetFileURL_URLMode(t *testing.T) {
|
||||
s := &mcpServer{
|
||||
httpClient: &http.Client{},
|
||||
stdin: &bytes.Buffer{},
|
||||
stdout: &bytes.Buffer{},
|
||||
hubBaseURL: "https://kubeshark.example.com/api/mcp",
|
||||
backendInitialized: true,
|
||||
urlMode: true,
|
||||
directURL: "https://kubeshark.example.com",
|
||||
}
|
||||
resp := parseResponse(t, sendRequest(s, "tools/call", 1, mcpCallToolParams{
|
||||
Name: "get_file_url",
|
||||
Arguments: map[string]any{"path": "/snapshots/xyz/export.pcap"},
|
||||
}))
|
||||
if resp.Error != nil {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
text := resp.Result.(map[string]any)["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
expected := "https://kubeshark.example.com/api/snapshots/xyz/export.pcap"
|
||||
if text != expected {
|
||||
t.Errorf("Expected %q, got %q", expected, text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_GetFileURL_MissingPath(t *testing.T) {
|
||||
s := &mcpServer{
|
||||
httpClient: &http.Client{},
|
||||
stdin: &bytes.Buffer{},
|
||||
stdout: &bytes.Buffer{},
|
||||
hubBaseURL: "http://127.0.0.1:8899/api/mcp",
|
||||
backendInitialized: true,
|
||||
}
|
||||
resp := parseResponse(t, sendRequest(s, "tools/call", 1, mcpCallToolParams{
|
||||
Name: "get_file_url",
|
||||
Arguments: map[string]any{},
|
||||
}))
|
||||
result := resp.Result.(map[string]any)
|
||||
if !result["isError"].(bool) {
|
||||
t.Error("Expected isError=true when path is missing")
|
||||
}
|
||||
text := result["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
if !strings.Contains(text, "path") {
|
||||
t.Error("Error message should mention 'path'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_DownloadFile(t *testing.T) {
|
||||
fileContent := "test pcap data content"
|
||||
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/api/snapshots/abc/data.pcap" {
|
||||
_, _ = w.Write([]byte(fileContent))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}))
|
||||
defer mockServer.Close()
|
||||
|
||||
// Use temp dir for download destination
|
||||
tmpDir := t.TempDir()
|
||||
dest := filepath.Join(tmpDir, "downloaded.pcap")
|
||||
|
||||
s := &mcpServer{
|
||||
httpClient: &http.Client{},
|
||||
stdin: &bytes.Buffer{},
|
||||
stdout: &bytes.Buffer{},
|
||||
hubBaseURL: mockServer.URL + "/api/mcp",
|
||||
backendInitialized: true,
|
||||
}
|
||||
resp := parseResponse(t, sendRequest(s, "tools/call", 1, mcpCallToolParams{
|
||||
Name: "download_file",
|
||||
Arguments: map[string]any{"path": "/snapshots/abc/data.pcap", "dest": dest},
|
||||
}))
|
||||
if resp.Error != nil {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
result := resp.Result.(map[string]any)
|
||||
if result["isError"] != nil && result["isError"].(bool) {
|
||||
t.Fatalf("Expected no error, got: %v", result["content"])
|
||||
}
|
||||
|
||||
text := result["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
var downloadResult map[string]any
|
||||
if err := json.Unmarshal([]byte(text), &downloadResult); err != nil {
|
||||
t.Fatalf("Failed to parse download result JSON: %v", err)
|
||||
}
|
||||
if downloadResult["path"] != dest {
|
||||
t.Errorf("Expected path %q, got %q", dest, downloadResult["path"])
|
||||
}
|
||||
if downloadResult["size"].(float64) != float64(len(fileContent)) {
|
||||
t.Errorf("Expected size %d, got %v", len(fileContent), downloadResult["size"])
|
||||
}
|
||||
|
||||
// Verify the file was actually written
|
||||
content, err := os.ReadFile(dest)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read downloaded file: %v", err)
|
||||
}
|
||||
if string(content) != fileContent {
|
||||
t.Errorf("Expected file content %q, got %q", fileContent, string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_DownloadFile_CustomDest(t *testing.T) {
|
||||
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte("data"))
|
||||
}))
|
||||
defer mockServer.Close()
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
customDest := filepath.Join(tmpDir, "custom-name.pcap")
|
||||
|
||||
s := &mcpServer{
|
||||
httpClient: &http.Client{},
|
||||
stdin: &bytes.Buffer{},
|
||||
stdout: &bytes.Buffer{},
|
||||
hubBaseURL: mockServer.URL + "/api/mcp",
|
||||
backendInitialized: true,
|
||||
}
|
||||
resp := parseResponse(t, sendRequest(s, "tools/call", 1, mcpCallToolParams{
|
||||
Name: "download_file",
|
||||
Arguments: map[string]any{"path": "/snapshots/abc/export.pcap", "dest": customDest},
|
||||
}))
|
||||
result := resp.Result.(map[string]any)
|
||||
if result["isError"] != nil && result["isError"].(bool) {
|
||||
t.Fatalf("Expected no error, got: %v", result["content"])
|
||||
}
|
||||
|
||||
text := result["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
var downloadResult map[string]any
|
||||
if err := json.Unmarshal([]byte(text), &downloadResult); err != nil {
|
||||
t.Fatalf("Failed to parse download result JSON: %v", err)
|
||||
}
|
||||
if downloadResult["path"] != customDest {
|
||||
t.Errorf("Expected path %q, got %q", customDest, downloadResult["path"])
|
||||
}
|
||||
|
||||
if _, err := os.Stat(customDest); os.IsNotExist(err) {
|
||||
t.Error("Expected file to exist at custom destination")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_ToolsList_IncludesFileTools(t *testing.T) {
|
||||
s := newTestMCPServer()
|
||||
resp := parseResponse(t, sendRequest(s, "tools/list", 1, nil))
|
||||
if resp.Error != nil {
|
||||
t.Fatalf("Unexpected error: %v", resp.Error)
|
||||
}
|
||||
tools := resp.Result.(map[string]any)["tools"].([]any)
|
||||
toolNames := make(map[string]bool)
|
||||
for _, tool := range tools {
|
||||
toolNames[tool.(map[string]any)["name"].(string)] = true
|
||||
}
|
||||
for _, expected := range []string{"get_file_url", "download_file"} {
|
||||
if !toolNames[expected] {
|
||||
t.Errorf("Missing expected tool: %s", expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCP_FullConversation(t *testing.T) {
|
||||
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
clientk8s "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
@@ -38,7 +39,7 @@ type PodFileInfo struct {
|
||||
}
|
||||
|
||||
// listWorkerPods fetches all worker pods from multiple namespaces
|
||||
func listWorkerPods(ctx context.Context, clientset *kubernetes.Clientset, namespaces []string) ([]*PodFileInfo, error) {
|
||||
func listWorkerPods(ctx context.Context, clientset *clientk8s.Clientset, namespaces []string) ([]*PodFileInfo, error) {
|
||||
var podFileInfos []*PodFileInfo
|
||||
var errs []error
|
||||
labelSelector := label
|
||||
@@ -64,7 +65,7 @@ func listWorkerPods(ctx context.Context, clientset *kubernetes.Clientset, namesp
|
||||
}
|
||||
|
||||
// listFilesInPodDir lists all files in the specified directory inside the pod across multiple namespaces
|
||||
func listFilesInPodDir(ctx context.Context, clientset *kubernetes.Clientset, config *rest.Config, pod *PodFileInfo, cutoffTime *time.Time) error {
|
||||
func listFilesInPodDir(ctx context.Context, clientset *clientk8s.Clientset, config *rest.Config, pod *PodFileInfo, cutoffTime *time.Time) error {
|
||||
nodeName := pod.Pod.Spec.NodeName
|
||||
srcFilePath := filepath.Join("data", nodeName, srcDir)
|
||||
|
||||
|
||||
@@ -62,5 +62,4 @@ func init() {
|
||||
tapCmd.Flags().Bool(configStructs.TelemetryEnabledLabel, defaultTapConfig.Telemetry.Enabled, "Enable/disable Telemetry")
|
||||
tapCmd.Flags().Bool(configStructs.ResourceGuardEnabledLabel, defaultTapConfig.ResourceGuard.Enabled, "Enable/disable resource guard")
|
||||
tapCmd.Flags().Bool(configStructs.WatchdogEnabled, defaultTapConfig.Watchdog.Enabled, "Enable/disable watchdog")
|
||||
tapCmd.Flags().String(configStructs.HelmChartPathLabel, defaultTapConfig.Release.HelmChartPath, "Path to a local Helm chart folder (overrides the remote Helm repo)")
|
||||
}
|
||||
|
||||
@@ -116,7 +116,6 @@ func CreateDefaultConfig() ConfigStruct {
|
||||
},
|
||||
CanUpdateTargetedPods: true,
|
||||
CanStopTrafficCapturing: true,
|
||||
CanControlDissection: true,
|
||||
ShowAdminConsoleLink: true,
|
||||
},
|
||||
},
|
||||
@@ -140,8 +139,8 @@ func CreateDefaultConfig() ConfigStruct {
|
||||
"diameter",
|
||||
"udp-flow",
|
||||
"tcp-flow",
|
||||
"udp-conn",
|
||||
"tcp-conn",
|
||||
"udp-flow-full",
|
||||
"tcp-flow-full",
|
||||
},
|
||||
PortMapping: configStructs.PortMapping{
|
||||
HTTP: []uint16{80, 443, 8080},
|
||||
@@ -155,10 +154,8 @@ func CreateDefaultConfig() ConfigStruct {
|
||||
CompleteStreamingEnabled: true,
|
||||
},
|
||||
Capture: configStructs.CaptureConfig{
|
||||
Dissection: configStructs.DissectionConfig{
|
||||
Enabled: true,
|
||||
StopAfter: "5m",
|
||||
},
|
||||
Stopped: false,
|
||||
StopAfter: "5m",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -184,6 +181,7 @@ type ConfigStruct struct {
|
||||
License string `yaml:"license" json:"license" default:""`
|
||||
CloudApiUrl string `yaml:"cloudApiUrl" json:"cloudApiUrl" default:"https://api.kubeshark.com"`
|
||||
CloudLicenseEnabled bool `yaml:"cloudLicenseEnabled" json:"cloudLicenseEnabled" default:"true"`
|
||||
AiAssistantEnabled bool `yaml:"aiAssistantEnabled" json:"aiAssistantEnabled" default:"true"`
|
||||
DemoModeEnabled bool `yaml:"demoModeEnabled" json:"demoModeEnabled" default:"false"`
|
||||
SupportChatEnabled bool `yaml:"supportChatEnabled" json:"supportChatEnabled" default:"false"`
|
||||
BetaEnabled bool `yaml:"betaEnabled" json:"betaEnabled" default:"false"`
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
)
|
||||
|
||||
type ScriptingConfig struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled" default:"false"`
|
||||
Env map[string]interface{} `yaml:"env" json:"env" default:"{}"`
|
||||
Source string `yaml:"source" json:"source" default:""`
|
||||
Sources []string `yaml:"sources" json:"sources" default:"[]"`
|
||||
|
||||
@@ -45,7 +45,6 @@ const (
|
||||
PcapDumpEnabled = "enabled"
|
||||
PcapTime = "time"
|
||||
WatchdogEnabled = "watchdogEnabled"
|
||||
HelmChartPathLabel = "release-helmChartPath"
|
||||
)
|
||||
|
||||
type ResourceLimitsHub struct {
|
||||
@@ -168,7 +167,6 @@ type Role struct {
|
||||
ScriptingPermissions ScriptingPermissions `yaml:"scriptingPermissions" json:"scriptingPermissions"`
|
||||
CanUpdateTargetedPods bool `yaml:"canUpdateTargetedPods" json:"canUpdateTargetedPods" default:"false"`
|
||||
CanStopTrafficCapturing bool `yaml:"canStopTrafficCapturing" json:"canStopTrafficCapturing" default:"false"`
|
||||
CanControlDissection bool `yaml:"canControlDissection" json:"canControlDissection" default:"false"`
|
||||
ShowAdminConsoleLink bool `yaml:"showAdminConsoleLink" json:"showAdminConsoleLink" default:"false"`
|
||||
}
|
||||
|
||||
@@ -212,7 +210,6 @@ type ReleaseConfig struct {
|
||||
Repo string `yaml:"repo" json:"repo" default:"https://helm.kubeshark.com"`
|
||||
Name string `yaml:"name" json:"name" default:"kubeshark"`
|
||||
Namespace string `yaml:"namespace" json:"namespace" default:"default"`
|
||||
HelmChartPath string `yaml:"helmChartPath" json:"helmChartPath" default:""`
|
||||
}
|
||||
|
||||
type TelemetryConfig struct {
|
||||
@@ -263,8 +260,6 @@ type MiscConfig struct {
|
||||
DuplicateTimeframe string `yaml:"duplicateTimeframe" json:"duplicateTimeframe" default:"200ms"`
|
||||
DetectDuplicates bool `yaml:"detectDuplicates" json:"detectDuplicates" default:"false"`
|
||||
StaleTimeoutSeconds int `yaml:"staleTimeoutSeconds" json:"staleTimeoutSeconds" default:"30"`
|
||||
TcpFlowTimeout int `yaml:"tcpFlowTimeout" json:"tcpFlowTimeout" default:"1200"`
|
||||
UdpFlowTimeout int `yaml:"udpFlowTimeout" json:"udpFlowTimeout" default:"1200"`
|
||||
}
|
||||
|
||||
type PcapDumpConfig struct {
|
||||
@@ -310,34 +305,20 @@ type RawCaptureConfig struct {
|
||||
StorageSize string `yaml:"storageSize" json:"storageSize" default:"1Gi"`
|
||||
}
|
||||
|
||||
type SnapshotsLocalConfig struct {
|
||||
type SnapshotsConfig struct {
|
||||
StorageClass string `yaml:"storageClass" json:"storageClass" default:""`
|
||||
StorageSize string `yaml:"storageSize" json:"storageSize" default:"20Gi"`
|
||||
}
|
||||
|
||||
type SnapshotsCloudConfig struct {
|
||||
Provider string `yaml:"provider" json:"provider" default:""`
|
||||
ConfigMaps []string `yaml:"configMaps" json:"configMaps" default:"[]"`
|
||||
Secrets []string `yaml:"secrets" json:"secrets" default:"[]"`
|
||||
}
|
||||
|
||||
type SnapshotsConfig struct {
|
||||
Local SnapshotsLocalConfig `yaml:"local" json:"local"`
|
||||
Cloud SnapshotsCloudConfig `yaml:"cloud" json:"cloud"`
|
||||
}
|
||||
|
||||
type DelayedDissectionConfig struct {
|
||||
Image string `yaml:"image" json:"image" default:"kubeshark/worker:master"`
|
||||
CPU string `yaml:"cpu" json:"cpu" default:"1"`
|
||||
Memory string `yaml:"memory" json:"memory" default:"4Gi"`
|
||||
}
|
||||
|
||||
type DissectionConfig struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled" default:"true"`
|
||||
StopAfter string `yaml:"stopAfter" json:"stopAfter" default:"5m"`
|
||||
}
|
||||
|
||||
type CaptureConfig struct {
|
||||
Dissection DissectionConfig `yaml:"dissection" json:"dissection"`
|
||||
Stopped bool `yaml:"stopped" json:"stopped" default:"false"`
|
||||
StopAfter string `yaml:"stopAfter" json:"stopAfter" default:"5m"`
|
||||
CaptureSelf bool `yaml:"captureSelf" json:"captureSelf" default:"false"`
|
||||
Raw RawCaptureConfig `yaml:"raw" json:"raw"`
|
||||
DbMaxSize string `yaml:"dbMaxSize" json:"dbMaxSize" default:"500Mi"`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: kubeshark
|
||||
version: "53.1.0"
|
||||
version: "52.12.0"
|
||||
description: The API Traffic Analyzer for Kubernetes
|
||||
home: https://kubeshark.com
|
||||
keywords:
|
||||
|
||||
@@ -138,16 +138,13 @@ Example for overriding image names:
|
||||
| `tap.namespaces` | Target pods in namespaces | `[]` |
|
||||
| `tap.excludedNamespaces` | Exclude pods in namespaces | `[]` |
|
||||
| `tap.bpfOverride` | When using AF_PACKET as a traffic capture backend, override any existing pod targeting rules and set explicit BPF expression (e.g. `net 0.0.0.0/0`). | `[]` |
|
||||
| `tap.capture.dissection.enabled` | Set to `true` to have L7 protocol dissection start automatically. When set to `false`, dissection is disabled by default. This property can be dynamically controlled via the dashboard. | `true` |
|
||||
| `tap.capture.dissection.stopAfter` | Set to a duration (e.g. `30s`) to have L7 dissection stop after no activity. | `5m` |
|
||||
| `tap.capture.stopped` | Set to `false` to have traffic processing start automatically. When set to `true`, traffic processing is stopped by default, resulting in almost no resource consumption (e.g. Kubeshark is dormant). This property can be dynamically control via the dashboard. | `false` |
|
||||
| `tap.capture.stopAfter` | Set to a duration (e.g. `30s`) to have traffic processing stop after no websocket activity between worker and hub. | `30s` |
|
||||
| `tap.capture.raw.enabled` | Enable raw capture of packets and syscalls to disk for offline analysis | `true` |
|
||||
| `tap.capture.raw.storageSize` | Maximum storage size for raw capture files (supports K8s quantity format: `1Gi`, `500Mi`, etc.) | `1Gi` |
|
||||
| `tap.capture.dbMaxSize` | Maximum size for capture database (e.g., `4Gi`, `2000Mi`). When empty, automatically uses 80% of allocated storage (`tap.storageLimit`). | `""` |
|
||||
| `tap.snapshots.local.storageClass` | Storage class for local snapshots volume. When empty, uses `emptyDir`. When set, creates a PVC with this storage class | `""` |
|
||||
| `tap.snapshots.local.storageSize` | Storage size for local snapshots volume (supports K8s quantity format: `1Gi`, `500Mi`, etc.) | `20Gi` |
|
||||
| `tap.snapshots.cloud.provider` | Cloud storage provider for snapshots: `s3` or `azblob`. Empty string disables cloud storage. See [Cloud Storage docs](docs/snapshots_cloud_storage.md). | `""` |
|
||||
| `tap.snapshots.cloud.configMaps` | Names of ConfigMaps containing cloud storage environment variables. See [Cloud Storage docs](docs/snapshots_cloud_storage.md). | `[]` |
|
||||
| `tap.snapshots.cloud.secrets` | Names of Secrets containing cloud storage credentials. See [Cloud Storage docs](docs/snapshots_cloud_storage.md). | `[]` |
|
||||
| `tap.snapshots.storageClass` | Storage class for snapshots volume. When empty, uses `emptyDir`. When set, creates a PVC with this storage class | `""` |
|
||||
| `tap.snapshots.storageSize` | Storage size for snapshots volume (supports K8s quantity format: `1Gi`, `500Mi`, etc.) | `10Gi` |
|
||||
| `tap.release.repo` | URL of the Helm chart repository | `https://helm.kubeshark.com` |
|
||||
| `tap.release.name` | Helm release name | `kubeshark` |
|
||||
| `tap.release.namespace` | Helm release namespace | `default` |
|
||||
@@ -201,7 +198,7 @@ Example for overriding image names:
|
||||
| `tap.auth.saml.x509crt` | A self-signed X.509 `.cert` contents <br/>(effective, if `tap.auth.type = saml`) | `` |
|
||||
| `tap.auth.saml.x509key` | A self-signed X.509 `.key` contents <br/>(effective, if `tap.auth.type = saml`) | `` |
|
||||
| `tap.auth.saml.roleAttribute` | A SAML attribute name corresponding to user's authorization role <br/>(effective, if `tap.auth.type = saml`) | `role` |
|
||||
| `tap.auth.saml.roles` | A list of SAML authorization roles and their permissions <br/>(effective, if `tap.auth.type = saml`) | `{"admin":{"canDownloadPCAP":true,"canUpdateTargetedPods":true,"canUseScripting":true, "scriptingPermissions":{"canSave":true, "canActivate":true, "canDelete":true}, "canStopTrafficCapturing":true, "canControlDissection":true, "filter":"","showAdminConsoleLink":true}}` |
|
||||
| `tap.auth.saml.roles` | A list of SAML authorization roles and their permissions <br/>(effective, if `tap.auth.type = saml`) | `{"admin":{"canDownloadPCAP":true,"canUpdateTargetedPods":true,"canUseScripting":true, "scriptingPermissions":{"canSave":true, "canActivate":true, "canDelete":true}, "canStopTrafficCapturing":true, "filter":"","showAdminConsoleLink":true}}` |
|
||||
| `tap.ingress.enabled` | Enable `Ingress` | `false` |
|
||||
| `tap.ingress.className` | Ingress class name | `""` |
|
||||
| `tap.ingress.host` | Host of the `Ingress` | `ks.svc.cluster.local` |
|
||||
@@ -223,8 +220,6 @@ Example for overriding image names:
|
||||
| `tap.mountBpf` | BPF filesystem needs to be mounted for eBPF to work properly. This helm value determines whether Kubeshark will attempt to mount the filesystem. This option is not required if filesystem is already mounts. │ `true`|
|
||||
| `tap.hostNetwork` | Enable host network mode for worker DaemonSet pods. When enabled, worker pods use the host's network namespace for direct network access. | `true` |
|
||||
| `tap.gitops.enabled` | Enable GitOps functionality. This will allow you to use GitOps to manage your Kubeshark configuration. | `false` |
|
||||
| `tap.misc.tcpFlowTimeout` | TCP flow aggregation timeout in seconds. Controls how long the worker waits before finalizing a TCP flow. | `1200` |
|
||||
| `tap.misc.udpFlowTimeout` | UDP flow aggregation timeout in seconds. Controls how long the worker waits before finalizing a UDP flow. | `1200` |
|
||||
| `logs.file` | Logs dump path | `""` |
|
||||
| `pcapdump.enabled` | Enable recording of all traffic captured according to other parameters. Whatever Kubeshark captures, considering pod targeting rules, will be stored in pcap files ready to be viewed by tools | `false` |
|
||||
| `pcapdump.maxTime` | The time window into the past that will be stored. Older traffic will be discarded. | `2h` |
|
||||
@@ -234,7 +229,6 @@ Example for overriding image names:
|
||||
| `dumpLogs` | Enable dumping of logs | `false` |
|
||||
| `headless` | Enable running in headless mode | `false` |
|
||||
| `license` | License key for the Pro/Enterprise edition | `""` |
|
||||
| `scripting.enabled` | Enables scripting | `false` |
|
||||
| `scripting.env` | Environment variables for the scripting | `{}` |
|
||||
| `scripting.source` | Source directory of the scripts | `""` |
|
||||
| `scripting.watchScripts` | Enable watch mode for the scripts in source directory | `true` |
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
# Cloud Storage for Snapshots
|
||||
|
||||
Kubeshark can upload and download snapshots to cloud object storage, enabling cross-cluster sharing, backup/restore, and long-term retention.
|
||||
|
||||
Supported providers: **Amazon S3** (`s3`) and **Azure Blob Storage** (`azblob`).
|
||||
|
||||
## Helm Values
|
||||
|
||||
```yaml
|
||||
tap:
|
||||
snapshots:
|
||||
cloud:
|
||||
provider: "" # "s3" or "azblob" (empty = disabled)
|
||||
configMaps: [] # names of pre-existing ConfigMaps with cloud config env vars
|
||||
secrets: [] # names of pre-existing Secrets with cloud credentials
|
||||
```
|
||||
|
||||
- `provider` selects which cloud backend to use. Leave empty to disable cloud storage.
|
||||
- `configMaps` and `secrets` are lists of names of existing ConfigMap/Secret resources. They are mounted as `envFrom` on the hub pod, injecting all their keys as environment variables.
|
||||
|
||||
---
|
||||
|
||||
## Amazon S3
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `SNAPSHOT_AWS_BUCKET` | Yes | S3 bucket name |
|
||||
| `SNAPSHOT_AWS_REGION` | No | AWS region (uses SDK default if empty) |
|
||||
| `SNAPSHOT_AWS_ACCESS_KEY` | No | Static access key ID (empty = use default credential chain) |
|
||||
| `SNAPSHOT_AWS_SECRET_KEY` | No | Static secret access key |
|
||||
| `SNAPSHOT_AWS_ROLE_ARN` | No | IAM role ARN to assume via STS (for cross-account access) |
|
||||
| `SNAPSHOT_AWS_EXTERNAL_ID` | No | External ID for the STS AssumeRole call |
|
||||
| `SNAPSHOT_CLOUD_PREFIX` | No | Key prefix in the bucket (e.g. `snapshots/`) |
|
||||
|
||||
### Authentication Methods
|
||||
|
||||
Credentials are resolved in this order:
|
||||
|
||||
1. **Static credentials** -- If `SNAPSHOT_AWS_ACCESS_KEY` is set, static credentials are used directly.
|
||||
2. **STS AssumeRole** -- If `SNAPSHOT_AWS_ROLE_ARN` is also set, the static (or default) credentials are used to assume the given IAM role. This is useful for cross-account S3 access.
|
||||
3. **AWS default credential chain** -- When no static credentials are provided, the SDK default chain is used:
|
||||
- **IRSA** (EKS service account token) -- recommended for production on EKS
|
||||
- EC2 instance profile
|
||||
- Standard AWS environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, etc.)
|
||||
- Shared credentials file (`~/.aws/credentials`)
|
||||
|
||||
The provider validates bucket access on startup via `HeadBucket`. If the bucket is inaccessible, the hub will fail to start.
|
||||
|
||||
### Example: IRSA (recommended for EKS)
|
||||
|
||||
Create a ConfigMap with bucket configuration:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeshark-s3-config
|
||||
data:
|
||||
SNAPSHOT_AWS_BUCKET: my-kubeshark-snapshots
|
||||
SNAPSHOT_AWS_REGION: us-east-1
|
||||
```
|
||||
|
||||
Set Helm values:
|
||||
|
||||
```yaml
|
||||
tap:
|
||||
snapshots:
|
||||
cloud:
|
||||
provider: "s3"
|
||||
configMaps:
|
||||
- kubeshark-s3-config
|
||||
```
|
||||
|
||||
The hub pod's service account must be annotated for IRSA with an IAM role that has S3 access to the bucket.
|
||||
|
||||
### Example: Static Credentials
|
||||
|
||||
Create a Secret with credentials:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: kubeshark-s3-creds
|
||||
type: Opaque
|
||||
stringData:
|
||||
SNAPSHOT_AWS_ACCESS_KEY: AKIA...
|
||||
SNAPSHOT_AWS_SECRET_KEY: wJal...
|
||||
```
|
||||
|
||||
Create a ConfigMap with bucket configuration:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeshark-s3-config
|
||||
data:
|
||||
SNAPSHOT_AWS_BUCKET: my-kubeshark-snapshots
|
||||
SNAPSHOT_AWS_REGION: us-east-1
|
||||
```
|
||||
|
||||
Set Helm values:
|
||||
|
||||
```yaml
|
||||
tap:
|
||||
snapshots:
|
||||
cloud:
|
||||
provider: "s3"
|
||||
configMaps:
|
||||
- kubeshark-s3-config
|
||||
secrets:
|
||||
- kubeshark-s3-creds
|
||||
```
|
||||
|
||||
### Example: Cross-Account Access via AssumeRole
|
||||
|
||||
Add the role ARN to your ConfigMap:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeshark-s3-config
|
||||
data:
|
||||
SNAPSHOT_AWS_BUCKET: other-account-bucket
|
||||
SNAPSHOT_AWS_REGION: eu-west-1
|
||||
SNAPSHOT_AWS_ROLE_ARN: arn:aws:iam::123456789012:role/KubesharkCrossAccountRole
|
||||
SNAPSHOT_AWS_EXTERNAL_ID: my-external-id # optional, if required by the trust policy
|
||||
```
|
||||
|
||||
The hub will first authenticate using its own credentials (IRSA, static, or default chain), then assume the specified role to access the bucket.
|
||||
|
||||
---
|
||||
|
||||
## Azure Blob Storage
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `SNAPSHOT_AZBLOB_STORAGE_ACCOUNT` | Yes | Azure storage account name |
|
||||
| `SNAPSHOT_AZBLOB_CONTAINER` | Yes | Blob container name |
|
||||
| `SNAPSHOT_AZBLOB_STORAGE_KEY` | No | Storage account access key (empty = use DefaultAzureCredential) |
|
||||
| `SNAPSHOT_CLOUD_PREFIX` | No | Key prefix in the container (e.g. `snapshots/`) |
|
||||
|
||||
### Authentication Methods
|
||||
|
||||
Credentials are resolved in this order:
|
||||
|
||||
1. **Shared Key** -- If `SNAPSHOT_AZBLOB_STORAGE_KEY` is set, the storage account key is used directly.
|
||||
2. **DefaultAzureCredential** -- When no storage key is provided, the Azure SDK default credential chain is used:
|
||||
- **Workload Identity** (AKS pod identity) -- recommended for production on AKS
|
||||
- Managed Identity (system or user-assigned)
|
||||
- Azure CLI credentials
|
||||
- Environment variables (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`)
|
||||
|
||||
The provider validates container access on startup via `GetProperties`. If the container is inaccessible, the hub will fail to start.
|
||||
|
||||
### Example: Workload Identity (recommended for AKS)
|
||||
|
||||
Create a ConfigMap with storage configuration:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeshark-azblob-config
|
||||
data:
|
||||
SNAPSHOT_AZBLOB_STORAGE_ACCOUNT: mykubesharksa
|
||||
SNAPSHOT_AZBLOB_CONTAINER: snapshots
|
||||
```
|
||||
|
||||
Set Helm values:
|
||||
|
||||
```yaml
|
||||
tap:
|
||||
snapshots:
|
||||
cloud:
|
||||
provider: "azblob"
|
||||
configMaps:
|
||||
- kubeshark-azblob-config
|
||||
```
|
||||
|
||||
The hub pod's service account must be configured for AKS Workload Identity with a managed identity that has the **Storage Blob Data Contributor** role on the container.
|
||||
|
||||
### Example: Storage Account Key
|
||||
|
||||
Create a Secret with the storage key:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: kubeshark-azblob-creds
|
||||
type: Opaque
|
||||
stringData:
|
||||
SNAPSHOT_AZBLOB_STORAGE_KEY: "base64-encoded-storage-key..."
|
||||
```
|
||||
|
||||
Create a ConfigMap with storage configuration:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kubeshark-azblob-config
|
||||
data:
|
||||
SNAPSHOT_AZBLOB_STORAGE_ACCOUNT: mykubesharksa
|
||||
SNAPSHOT_AZBLOB_CONTAINER: snapshots
|
||||
```
|
||||
|
||||
Set Helm values:
|
||||
|
||||
```yaml
|
||||
tap:
|
||||
snapshots:
|
||||
cloud:
|
||||
provider: "azblob"
|
||||
configMaps:
|
||||
- kubeshark-azblob-config
|
||||
secrets:
|
||||
- kubeshark-azblob-creds
|
||||
```
|
||||
@@ -37,17 +37,13 @@ spec:
|
||||
- -loglevel
|
||||
- '{{ .Values.logLevel | default "warning" }}'
|
||||
- -capture-stop-after
|
||||
- "{{ if hasKey .Values.tap.capture.dissection "stopAfter" }}{{ .Values.tap.capture.dissection.stopAfter }}{{ else }}5m{{ end }}"
|
||||
- "{{ if hasKey .Values.tap.capture "stopAfter" }}{{ .Values.tap.capture.stopAfter }}{{ else }}5m{{ end }}"
|
||||
- -snapshot-size-limit
|
||||
- '{{ .Values.tap.snapshots.storageSize }}'
|
||||
{{- if .Values.tap.delayedDissection.image }}
|
||||
- -dissector-image
|
||||
{{- if .Values.tap.docker.overrideImage.worker }}
|
||||
- '{{ .Values.tap.docker.overrideImage.worker }}'
|
||||
{{- else if .Values.tap.docker.overrideTag.worker }}
|
||||
- '{{ .Values.tap.docker.registry }}/worker:{{ .Values.tap.docker.overrideTag.worker }}'
|
||||
{{- else }}
|
||||
- '{{ .Values.tap.docker.registry }}/worker:{{ not (eq .Values.tap.docker.tag "") | ternary .Values.tap.docker.tag (include "kubeshark.defaultVersion" .) }}'
|
||||
{{- end }}
|
||||
- '{{ .Values.tap.delayedDissection.image }}'
|
||||
{{- end }}
|
||||
{{- if .Values.tap.delayedDissection.cpu }}
|
||||
- -dissector-cpu
|
||||
- '{{ .Values.tap.delayedDissection.cpu }}'
|
||||
@@ -61,24 +57,12 @@ spec:
|
||||
{{- end }}
|
||||
- -cloud-api-url
|
||||
- '{{ .Values.cloudApiUrl }}'
|
||||
{{- if .Values.tap.snapshots.cloud.provider }}
|
||||
- -cloud-storage-provider
|
||||
- '{{ .Values.tap.snapshots.cloud.provider }}'
|
||||
{{- end }}
|
||||
{{- if or .Values.tap.secrets .Values.tap.snapshots.cloud.configMaps .Values.tap.snapshots.cloud.secrets }}
|
||||
{{- if .Values.tap.secrets }}
|
||||
envFrom:
|
||||
{{- range .Values.tap.secrets }}
|
||||
- secretRef:
|
||||
name: {{ . }}
|
||||
{{- end }}
|
||||
{{- range .Values.tap.snapshots.cloud.configMaps }}
|
||||
- configMapRef:
|
||||
name: {{ . }}
|
||||
{{- end }}
|
||||
{{- range .Values.tap.snapshots.cloud.secrets }}
|
||||
- secretRef:
|
||||
name: {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: POD_NAME
|
||||
@@ -200,10 +184,10 @@ spec:
|
||||
- key: AUTH_SAML_X509_KEY
|
||||
path: kubeshark.key
|
||||
- name: snapshots-volume
|
||||
{{- if .Values.tap.snapshots.local.storageClass }}
|
||||
{{- if .Values.tap.snapshots.storageClass }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "kubeshark.name" . }}-snapshots-pvc
|
||||
{{- else }}
|
||||
emptyDir:
|
||||
sizeLimit: {{ .Values.tap.snapshots.local.storageSize }}
|
||||
sizeLimit: {{ .Values.tap.snapshots.storageSize }}
|
||||
{{- end }}
|
||||
|
||||
@@ -48,12 +48,6 @@ spec:
|
||||
value: '{{ not (eq .Values.tap.auth.saml.idpMetadataUrl "") | ternary .Values.tap.auth.saml.idpMetadataUrl " " }}'
|
||||
- name: REACT_APP_TIMEZONE
|
||||
value: '{{ not (eq .Values.timezone "") | ternary .Values.timezone " " }}'
|
||||
- name: REACT_APP_SCRIPTING_HIDDEN
|
||||
value: '{{- if and .Values.scripting (eq (.Values.scripting.enabled | toString) "false") -}}
|
||||
true
|
||||
{{- else -}}
|
||||
false
|
||||
{{- end }}'
|
||||
- name: REACT_APP_SCRIPTING_DISABLED
|
||||
value: '{{- if .Values.tap.liveConfigMapChangesDisabled -}}
|
||||
{{- if .Values.demoModeEnabled -}}
|
||||
@@ -72,13 +66,11 @@ spec:
|
||||
value: '{{ eq .Values.tap.packetCapture "af_packet" | ternary "false" "true" }}'
|
||||
- name: REACT_APP_RECORDING_DISABLED
|
||||
value: '{{ .Values.tap.liveConfigMapChangesDisabled }}'
|
||||
- name: REACT_APP_DISSECTION_ENABLED
|
||||
value: '{{ .Values.tap.capture.dissection.enabled | ternary "true" "false" }}'
|
||||
- name: REACT_APP_DISSECTION_CONTROL_ENABLED
|
||||
value: '{{- if and .Values.tap.liveConfigMapChangesDisabled (not .Values.tap.capture.dissection.enabled) -}}
|
||||
true
|
||||
- name: REACT_APP_STOP_TRAFFIC_CAPTURING_DISABLED
|
||||
value: '{{- if and .Values.tap.liveConfigMapChangesDisabled .Values.tap.capture.stopped -}}
|
||||
false
|
||||
{{- else -}}
|
||||
{{ not .Values.tap.liveConfigMapChangesDisabled | ternary "true" "false" }}
|
||||
{{ .Values.tap.liveConfigMapChangesDisabled | ternary "true" "false" }}
|
||||
{{- end -}}'
|
||||
- name: 'REACT_APP_CLOUD_LICENSE_ENABLED'
|
||||
value: '{{- if or (and .Values.cloudLicenseEnabled (not (empty .Values.license))) (not .Values.internetConnectivity) -}}
|
||||
@@ -86,6 +78,8 @@ spec:
|
||||
{{- else -}}
|
||||
{{ .Values.cloudLicenseEnabled }}
|
||||
{{- end }}'
|
||||
- name: 'REACT_APP_AI_ASSISTANT_ENABLED'
|
||||
value: '{{ .Values.aiAssistantEnabled | ternary "true" "false" }}'
|
||||
- name: REACT_APP_SUPPORT_CHAT_ENABLED
|
||||
value: '{{ and .Values.supportChatEnabled .Values.internetConnectivity | ternary "true" "false" }}'
|
||||
- name: REACT_APP_BETA_ENABLED
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
{{- if .Values.tap.snapshots.local.storageClass }}
|
||||
{{- if .Values.tap.snapshots.storageClass }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
@@ -16,7 +16,7 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.tap.snapshots.local.storageSize }}
|
||||
storageClassName: {{ .Values.tap.snapshots.local.storageClass }}
|
||||
storage: {{ .Values.tap.snapshots.storageSize }}
|
||||
storageClassName: {{ .Values.tap.snapshots.storageClass }}
|
||||
status: {}
|
||||
{{- end }}
|
||||
|
||||
@@ -99,10 +99,6 @@ spec:
|
||||
- '{{ .Values.tap.misc.resolutionStrategy }}'
|
||||
- -staletimeout
|
||||
- '{{ .Values.tap.misc.staleTimeoutSeconds }}'
|
||||
- -tcp-flow-full-timeout
|
||||
- '{{ .Values.tap.misc.tcpFlowTimeout }}'
|
||||
- -udp-flow-full-timeout
|
||||
- '{{ .Values.tap.misc.udpFlowTimeout }}'
|
||||
- -storage-size
|
||||
- '{{ .Values.tap.storageLimit }}'
|
||||
- -capture-db-max-size
|
||||
@@ -406,8 +402,8 @@ spec:
|
||||
- hostPath:
|
||||
path: /
|
||||
name: root
|
||||
{{- end }}
|
||||
- name: data
|
||||
{{- end }}
|
||||
{{- if .Values.tap.persistentStorage }}
|
||||
persistentVolumeClaim:
|
||||
claimName: kubeshark-persistent-volume-claim
|
||||
|
||||
@@ -30,10 +30,8 @@ data:
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
proxy_pass_header Authorization;
|
||||
proxy_connect_timeout 4s;
|
||||
# Disable buffering for gRPC/Connect streaming
|
||||
client_max_body_size 0;
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_send_timeout 12s;
|
||||
proxy_pass_request_headers on;
|
||||
}
|
||||
|
||||
@@ -88,3 +86,4 @@ data:
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ data:
|
||||
NAMESPACES: '{{ gt (len .Values.tap.namespaces) 0 | ternary (join "," .Values.tap.namespaces) "" }}'
|
||||
EXCLUDED_NAMESPACES: '{{ gt (len .Values.tap.excludedNamespaces) 0 | ternary (join "," .Values.tap.excludedNamespaces) "" }}'
|
||||
BPF_OVERRIDE: '{{ .Values.tap.bpfOverride }}'
|
||||
DISSECTION_ENABLED: '{{ .Values.tap.capture.dissection.enabled | ternary "true" "false" }}'
|
||||
STOPPED: '{{ .Values.tap.capture.stopped | ternary "true" "false" }}'
|
||||
CAPTURE_SELF: '{{ .Values.tap.capture.captureSelf | ternary "true" "false" }}'
|
||||
SCRIPTING_SCRIPTS: '{}'
|
||||
SCRIPTING_ACTIVE_SCRIPTS: '{{ gt (len .Values.scripting.active) 0 | ternary (join "," .Values.scripting.active) "" }}'
|
||||
@@ -56,11 +56,11 @@ data:
|
||||
TARGETED_PODS_UPDATE_DISABLED: '{{ .Values.tap.liveConfigMapChangesDisabled | ternary "true" "" }}'
|
||||
PRESET_FILTERS_CHANGING_ENABLED: '{{ .Values.tap.liveConfigMapChangesDisabled | ternary "false" "true" }}'
|
||||
RECORDING_DISABLED: '{{ .Values.tap.liveConfigMapChangesDisabled | ternary "true" "" }}'
|
||||
DISSECTION_CONTROL_ENABLED: '{{- if and .Values.tap.liveConfigMapChangesDisabled (not .Values.tap.capture.dissection.enabled) -}}
|
||||
true
|
||||
{{- else -}}
|
||||
{{ not .Values.tap.liveConfigMapChangesDisabled | ternary "true" "false" }}
|
||||
{{- end }}'
|
||||
STOP_TRAFFIC_CAPTURING_DISABLED: '{{- if and .Values.tap.liveConfigMapChangesDisabled .Values.tap.capture.stopped -}}
|
||||
false
|
||||
{{- else -}}
|
||||
{{ .Values.tap.liveConfigMapChangesDisabled | ternary "true" "false" }}
|
||||
{{- end }}'
|
||||
GLOBAL_FILTER: {{ include "kubeshark.escapeDoubleQuotes" .Values.tap.globalFilter | quote }}
|
||||
DEFAULT_FILTER: {{ include "kubeshark.escapeDoubleQuotes" .Values.tap.defaultFilter | quote }}
|
||||
TRAFFIC_SAMPLE_RATE: '{{ .Values.tap.misc.trafficSampleRate }}'
|
||||
@@ -73,6 +73,7 @@ data:
|
||||
{{- else -}}
|
||||
{{ .Values.cloudLicenseEnabled }}
|
||||
{{- end }}'
|
||||
AI_ASSISTANT_ENABLED: '{{ .Values.aiAssistantEnabled | ternary "true" "false" }}'
|
||||
DUPLICATE_TIMEFRAME: '{{ .Values.tap.misc.duplicateTimeframe }}'
|
||||
ENABLED_DISSECTORS: '{{ gt (len .Values.tap.enabledDissectors) 0 | ternary (join "," .Values.tap.enabledDissectors) "" }}'
|
||||
CUSTOM_MACROS: '{{ toJson .Values.tap.customMacros }}'
|
||||
@@ -83,5 +84,5 @@ data:
|
||||
PCAP_MAX_TIME: '{{ .Values.pcapdump.maxTime }}'
|
||||
PCAP_MAX_SIZE: '{{ .Values.pcapdump.maxSize }}'
|
||||
PORT_MAPPING: '{{ toJson .Values.tap.portMapping }}'
|
||||
RAW_CAPTURE_ENABLED: '{{ .Values.tap.capture.raw.enabled | ternary "true" "false" }}'
|
||||
RAW_CAPTURE: '{{ .Values.tap.capture.raw.enabled | ternary "true" "false" }}'
|
||||
RAW_CAPTURE_STORAGE_SIZE: '{{ .Values.tap.capture.raw.storageSize }}'
|
||||
|
||||
@@ -26,30 +26,24 @@ tap:
|
||||
excludedNamespaces: []
|
||||
bpfOverride: ""
|
||||
capture:
|
||||
dissection:
|
||||
enabled: true
|
||||
stopAfter: 5m
|
||||
stopped: false
|
||||
stopAfter: 5m
|
||||
captureSelf: false
|
||||
raw:
|
||||
enabled: true
|
||||
storageSize: 1Gi
|
||||
dbMaxSize: 500Mi
|
||||
delayedDissection:
|
||||
image: kubeshark/worker:master
|
||||
cpu: "1"
|
||||
memory: 4Gi
|
||||
snapshots:
|
||||
local:
|
||||
storageClass: ""
|
||||
storageSize: 20Gi
|
||||
cloud:
|
||||
provider: ""
|
||||
configMaps: []
|
||||
secrets: []
|
||||
storageClass: ""
|
||||
storageSize: 20Gi
|
||||
release:
|
||||
repo: https://helm.kubeshark.com
|
||||
name: kubeshark
|
||||
namespace: default
|
||||
helmChartPath: ""
|
||||
persistentStorage: false
|
||||
persistentStorageStatic: false
|
||||
persistentStoragePvcVolumeMode: FileSystem
|
||||
@@ -151,7 +145,6 @@ tap:
|
||||
canDelete: true
|
||||
canUpdateTargetedPods: true
|
||||
canStopTrafficCapturing: true
|
||||
canControlDissection: true
|
||||
showAdminConsoleLink: true
|
||||
ingress:
|
||||
enabled: false
|
||||
@@ -196,8 +189,8 @@ tap:
|
||||
- diameter
|
||||
- udp-flow
|
||||
- tcp-flow
|
||||
- udp-conn
|
||||
- tcp-conn
|
||||
- tcp-flow-full
|
||||
- udp-flow-full
|
||||
portMapping:
|
||||
http:
|
||||
- 80
|
||||
@@ -233,8 +226,6 @@ tap:
|
||||
duplicateTimeframe: 200ms
|
||||
detectDuplicates: false
|
||||
staleTimeoutSeconds: 30
|
||||
tcpFlowTimeout: 1200
|
||||
udpFlowTimeout: 1200
|
||||
securityContext:
|
||||
privileged: true
|
||||
appArmorProfile:
|
||||
@@ -277,14 +268,14 @@ kube:
|
||||
dumpLogs: false
|
||||
headless: false
|
||||
license: ""
|
||||
cloudApiUrl: https://api.kubeshark.com
|
||||
cloudApiUrl: "https://api.kubeshark.com"
|
||||
cloudLicenseEnabled: true
|
||||
aiAssistantEnabled: true
|
||||
demoModeEnabled: false
|
||||
supportChatEnabled: false
|
||||
betaEnabled: false
|
||||
internetConnectivity: true
|
||||
scripting:
|
||||
enabled: false
|
||||
env: {}
|
||||
source: ""
|
||||
sources: []
|
||||
|
||||
@@ -67,10 +67,7 @@ func (h *Helm) Install() (rel *release.Release, err error) {
|
||||
client.Namespace = h.releaseNamespace
|
||||
client.ReleaseName = h.releaseName
|
||||
|
||||
chartPath := config.Config.Tap.Release.HelmChartPath
|
||||
if chartPath == "" {
|
||||
chartPath = os.Getenv(fmt.Sprintf("%s_HELM_CHART_PATH", strings.ToUpper(misc.Program)))
|
||||
}
|
||||
chartPath := os.Getenv(fmt.Sprintf("%s_HELM_CHART_PATH", strings.ToUpper(misc.Program)))
|
||||
if chartPath == "" {
|
||||
var chartURL string
|
||||
chartURL, err = repo.FindChartInRepoURL(h.repo, h.releaseName, "", "", "", "", getter.All(&cli.EnvSettings{}))
|
||||
|
||||
@@ -4,10 +4,10 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-hub-network-policy
|
||||
namespace: default
|
||||
@@ -33,10 +33,10 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
name: kubeshark-front-network-policy
|
||||
@@ -60,10 +60,10 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
name: kubeshark-dex-network-policy
|
||||
@@ -87,10 +87,10 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
name: kubeshark-worker-network-policy
|
||||
@@ -116,10 +116,10 @@ apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-service-account
|
||||
namespace: default
|
||||
@@ -132,10 +132,10 @@ metadata:
|
||||
namespace: default
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
stringData:
|
||||
LICENSE: ''
|
||||
@@ -151,10 +151,10 @@ metadata:
|
||||
namespace: default
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
stringData:
|
||||
AUTH_SAML_X509_CRT: |
|
||||
@@ -167,10 +167,10 @@ metadata:
|
||||
namespace: default
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
stringData:
|
||||
AUTH_SAML_X509_KEY: |
|
||||
@@ -182,10 +182,10 @@ metadata:
|
||||
name: kubeshark-nginx-config-map
|
||||
namespace: default
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
data:
|
||||
default.conf: |
|
||||
@@ -209,10 +209,8 @@ data:
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
proxy_pass_header Authorization;
|
||||
proxy_connect_timeout 4s;
|
||||
# Disable buffering for gRPC/Connect streaming
|
||||
client_max_body_size 0;
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_send_timeout 12s;
|
||||
proxy_pass_request_headers on;
|
||||
}
|
||||
|
||||
@@ -248,18 +246,17 @@ metadata:
|
||||
namespace: default
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
data:
|
||||
POD_REGEX: '.*'
|
||||
NAMESPACES: ''
|
||||
EXCLUDED_NAMESPACES: ''
|
||||
BPF_OVERRIDE: ''
|
||||
DISSECTION_ENABLED: 'true'
|
||||
CAPTURE_SELF: 'false'
|
||||
STOPPED: 'false'
|
||||
SCRIPTING_SCRIPTS: '{}'
|
||||
SCRIPTING_ACTIVE_SCRIPTS: ''
|
||||
INGRESS_ENABLED: 'false'
|
||||
@@ -269,7 +266,7 @@ data:
|
||||
AUTH_TYPE: 'default'
|
||||
AUTH_SAML_IDP_METADATA_URL: ''
|
||||
AUTH_SAML_ROLE_ATTRIBUTE: 'role'
|
||||
AUTH_SAML_ROLES: '{"admin":{"canControlDissection":true,"canDownloadPCAP":true,"canStopTrafficCapturing":true,"canUpdateTargetedPods":true,"canUseScripting":true,"filter":"","scriptingPermissions":{"canActivate":true,"canDelete":true,"canSave":true},"showAdminConsoleLink":true}}'
|
||||
AUTH_SAML_ROLES: '{"admin":{"canDownloadPCAP":true,"canStopTrafficCapturing":true,"canUpdateTargetedPods":true,"canUseScripting":true,"filter":"","scriptingPermissions":{"canActivate":true,"canDelete":true,"canSave":true},"showAdminConsoleLink":true}}'
|
||||
AUTH_OIDC_ISSUER: 'not set'
|
||||
AUTH_OIDC_REFRESH_TOKEN_LIFETIME: '3960h'
|
||||
AUTH_OIDC_STATE_PARAM_EXPIRY: '10m'
|
||||
@@ -279,7 +276,7 @@ data:
|
||||
TARGETED_PODS_UPDATE_DISABLED: ''
|
||||
PRESET_FILTERS_CHANGING_ENABLED: 'true'
|
||||
RECORDING_DISABLED: ''
|
||||
DISSECTION_CONTROL_ENABLED: 'true'
|
||||
STOP_TRAFFIC_CAPTURING_DISABLED: 'false'
|
||||
GLOBAL_FILTER: ""
|
||||
DEFAULT_FILTER: ""
|
||||
TRAFFIC_SAMPLE_RATE: '100'
|
||||
@@ -288,8 +285,9 @@ data:
|
||||
PCAP_ERROR_TTL: '0'
|
||||
TIMEZONE: ' '
|
||||
CLOUD_LICENSE_ENABLED: 'true'
|
||||
AI_ASSISTANT_ENABLED: 'true'
|
||||
DUPLICATE_TIMEFRAME: '200ms'
|
||||
ENABLED_DISSECTORS: 'amqp,dns,http,icmp,kafka,redis,ws,ldap,radius,diameter,udp-flow,tcp-flow,udp-conn,tcp-conn'
|
||||
ENABLED_DISSECTORS: 'amqp,dns,http,icmp,kafka,redis,ws,ldap,radius,diameter,udp-flow,tcp-flow'
|
||||
CUSTOM_MACROS: '{"https":"tls and (http or http2)"}'
|
||||
DISSECTORS_UPDATING_ENABLED: 'true'
|
||||
DETECT_DUPLICATES: 'false'
|
||||
@@ -298,7 +296,7 @@ data:
|
||||
PCAP_MAX_TIME: '1h'
|
||||
PCAP_MAX_SIZE: '500MB'
|
||||
PORT_MAPPING: '{"amqp":[5671,5672],"diameter":[3868],"http":[80,443,8080],"kafka":[9092],"ldap":[389],"redis":[6379]}'
|
||||
RAW_CAPTURE_ENABLED: 'true'
|
||||
RAW_CAPTURE: 'true'
|
||||
RAW_CAPTURE_STORAGE_SIZE: '1Gi'
|
||||
---
|
||||
# Source: kubeshark/templates/02-cluster-role.yaml
|
||||
@@ -306,10 +304,10 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-cluster-role-default
|
||||
namespace: default
|
||||
@@ -353,10 +351,10 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-cluster-role-binding-default
|
||||
namespace: default
|
||||
@@ -374,10 +372,10 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
name: kubeshark-self-config-role
|
||||
@@ -424,10 +422,10 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
name: kubeshark-self-config-role-binding
|
||||
@@ -447,10 +445,10 @@ kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-hub
|
||||
namespace: default
|
||||
@@ -468,10 +466,10 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-front
|
||||
namespace: default
|
||||
@@ -489,10 +487,10 @@ kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
@@ -502,10 +500,10 @@ metadata:
|
||||
spec:
|
||||
selector:
|
||||
app.kubeshark.com/app: worker
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
ports:
|
||||
- name: metrics
|
||||
@@ -518,10 +516,10 @@ kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
annotations:
|
||||
prometheus.io/scrape: 'true'
|
||||
@@ -531,10 +529,10 @@ metadata:
|
||||
spec:
|
||||
selector:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
ports:
|
||||
- name: metrics
|
||||
@@ -549,10 +547,10 @@ metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: worker
|
||||
sidecar.istio.io/inject: "false"
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: default
|
||||
@@ -566,10 +564,10 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: worker
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-worker-daemon-set
|
||||
namespace: kubeshark
|
||||
@@ -579,7 +577,7 @@ spec:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- mkdir -p /sys/fs/bpf && mount | grep -q '/sys/fs/bpf' || mount -t bpf bpf /sys/fs/bpf
|
||||
image: 'docker.io/kubeshark/worker:v53.1'
|
||||
image: 'docker.io/kubeshark/worker:v52.12'
|
||||
imagePullPolicy: Always
|
||||
name: mount-bpf
|
||||
securityContext:
|
||||
@@ -608,17 +606,11 @@ spec:
|
||||
- 'auto'
|
||||
- -staletimeout
|
||||
- '30'
|
||||
- -tcp-flow-full-timeout
|
||||
- '1200'
|
||||
- -udp-flow-full-timeout
|
||||
- '1200'
|
||||
- -storage-size
|
||||
- '10Gi'
|
||||
- -capture-db-max-size
|
||||
- '500Mi'
|
||||
- -cloud-api-url
|
||||
- 'https://api.kubeshark.com'
|
||||
image: 'docker.io/kubeshark/worker:v53.1'
|
||||
image: 'docker.io/kubeshark/worker:v52.12'
|
||||
imagePullPolicy: Always
|
||||
name: sniffer
|
||||
ports:
|
||||
@@ -638,6 +630,8 @@ spec:
|
||||
value: '10000'
|
||||
- name: TCP_STREAM_CHANNEL_TIMEOUT_SHOW
|
||||
value: 'false'
|
||||
- name: KUBESHARK_CLOUD_API_URL
|
||||
value: 'https://api.kubeshark.com'
|
||||
- name: PROFILING_ENABLED
|
||||
value: 'false'
|
||||
- name: SENTRY_ENABLED
|
||||
@@ -690,7 +684,7 @@ spec:
|
||||
- -disable-tls-log
|
||||
- -loglevel
|
||||
- 'warning'
|
||||
image: 'docker.io/kubeshark/worker:v53.1'
|
||||
image: 'docker.io/kubeshark/worker:v52.12'
|
||||
imagePullPolicy: Always
|
||||
name: tracer
|
||||
env:
|
||||
@@ -782,10 +776,10 @@ kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-hub
|
||||
namespace: default
|
||||
@@ -800,10 +794,10 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: hub
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
spec:
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
@@ -819,15 +813,13 @@ spec:
|
||||
- -capture-stop-after
|
||||
- "5m"
|
||||
- -snapshot-size-limit
|
||||
- ''
|
||||
- '20Gi'
|
||||
- -dissector-image
|
||||
- 'docker.io/kubeshark/worker:v53.1'
|
||||
- 'kubeshark/worker:master'
|
||||
- -dissector-cpu
|
||||
- '1'
|
||||
- -dissector-memory
|
||||
- '4Gi'
|
||||
- -cloud-api-url
|
||||
- 'https://api.kubeshark.com'
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
@@ -841,9 +833,11 @@ spec:
|
||||
value: 'false'
|
||||
- name: SENTRY_ENVIRONMENT
|
||||
value: 'production'
|
||||
- name: KUBESHARK_CLOUD_API_URL
|
||||
value: 'https://api.kubeshark.com'
|
||||
- name: PROFILING_ENABLED
|
||||
value: 'false'
|
||||
image: 'docker.io/kubeshark/hub:v53.1'
|
||||
image: 'docker.io/kubeshark/hub:v52.12'
|
||||
imagePullPolicy: Always
|
||||
readinessProbe:
|
||||
periodSeconds: 5
|
||||
@@ -911,10 +905,10 @@ kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: front
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: kubeshark-front
|
||||
namespace: default
|
||||
@@ -929,10 +923,10 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubeshark.com/app: front
|
||||
helm.sh/chart: kubeshark-53.1.0
|
||||
helm.sh/chart: kubeshark-52.12.0
|
||||
app.kubernetes.io/name: kubeshark
|
||||
app.kubernetes.io/instance: kubeshark
|
||||
app.kubernetes.io/version: "53.1.0"
|
||||
app.kubernetes.io/version: "52.12.0"
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
spec:
|
||||
containers:
|
||||
@@ -949,8 +943,6 @@ spec:
|
||||
value: ' '
|
||||
- name: REACT_APP_TIMEZONE
|
||||
value: ' '
|
||||
- name: REACT_APP_SCRIPTING_HIDDEN
|
||||
value: 'true'
|
||||
- name: REACT_APP_SCRIPTING_DISABLED
|
||||
value: 'false'
|
||||
- name: REACT_APP_TARGETED_PODS_UPDATE_DISABLED
|
||||
@@ -961,12 +953,12 @@ spec:
|
||||
value: 'true'
|
||||
- name: REACT_APP_RECORDING_DISABLED
|
||||
value: 'false'
|
||||
- name: REACT_APP_DISSECTION_ENABLED
|
||||
value: 'true'
|
||||
- name: REACT_APP_DISSECTION_CONTROL_ENABLED
|
||||
value: 'true'
|
||||
- name: REACT_APP_STOP_TRAFFIC_CAPTURING_DISABLED
|
||||
value: 'false'
|
||||
- name: 'REACT_APP_CLOUD_LICENSE_ENABLED'
|
||||
value: 'true'
|
||||
- name: 'REACT_APP_AI_ASSISTANT_ENABLED'
|
||||
value: 'true'
|
||||
- name: REACT_APP_SUPPORT_CHAT_ENABLED
|
||||
value: 'false'
|
||||
- name: REACT_APP_BETA_ENABLED
|
||||
@@ -979,7 +971,7 @@ spec:
|
||||
value: 'false'
|
||||
- name: REACT_APP_SENTRY_ENVIRONMENT
|
||||
value: 'production'
|
||||
image: 'docker.io/kubeshark/front:v53.1'
|
||||
image: 'docker.io/kubeshark/front:v52.12'
|
||||
imagePullPolicy: Always
|
||||
name: kubeshark-front
|
||||
livenessProbe:
|
||||
|
||||
@@ -59,18 +59,6 @@ Add to your Claude Desktop configuration:
|
||||
}
|
||||
}
|
||||
```
|
||||
or:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"kubeshark": {
|
||||
"command": "kubeshark",
|
||||
"args": ["mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### With Destructive Operations
|
||||
|
||||
@@ -186,18 +174,11 @@ src.pod.name == "frontend-.*"
|
||||
http and src.namespace == "default" and response.status == 500
|
||||
```
|
||||
|
||||
## MCP Registry
|
||||
|
||||
Kubeshark is published to the [MCP Registry](https://registry.modelcontextprotocol.io/) automatically on each release.
|
||||
|
||||
The `server.json` in this directory is a reference file. The actual registry metadata (version, SHA256 hashes) is auto-generated during the release workflow. See [`.github/workflows/release.yml`](../.github/workflows/release.yml) for details.
|
||||
|
||||
## Links
|
||||
|
||||
- [Documentation](https://docs.kubeshark.com/en/mcp)
|
||||
- [GitHub](https://github.com/kubeshark/kubeshark)
|
||||
- [Website](https://kubeshark.com)
|
||||
- [MCP Registry](https://registry.modelcontextprotocol.io/)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
113
mcp/server.json
113
mcp/server.json
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
||||
"name": "io.github.kubeshark/mcp",
|
||||
"$schema": "https://registry.modelcontextprotocol.io/schemas/server.schema.json",
|
||||
"name": "com.kubeshark/mcp",
|
||||
"displayName": "Kubeshark",
|
||||
"description": "Real-time Kubernetes network traffic visibility and API analysis for HTTP, gRPC, Redis, Kafka, DNS.",
|
||||
"icon": "https://raw.githubusercontent.com/kubeshark/assets/refs/heads/master/logo/ico/icon.ico",
|
||||
"description": "Real-time Kubernetes network traffic visibility and API analysis. Query L7 API transactions (HTTP, gRPC, Redis, Kafka, DNS), L4 network flows, and manage Kubeshark deployments directly from AI assistants.",
|
||||
"icon": "https://kubeshark.com/favicon.ico",
|
||||
"repository": {
|
||||
"url": "https://github.com/kubeshark/kubeshark",
|
||||
"source": "github"
|
||||
},
|
||||
"homepage": "https://kubeshark.com",
|
||||
"license": "Apache-2.0",
|
||||
"version": "AUTO_GENERATED_AT_RELEASE",
|
||||
"version": "52.12.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kubeshark",
|
||||
@@ -24,38 +24,41 @@
|
||||
"debugging",
|
||||
"security"
|
||||
],
|
||||
"_note": "version and packages.fileSha256 are auto-generated at release time by .github/workflows/release.yml",
|
||||
"tags": ["kubernetes", "network", "traffic", "api", "http", "grpc", "kafka", "redis", "dns", "pcap", "wireshark", "tcpdump", "observability", "debugging", "microservices"],
|
||||
"tags": [
|
||||
"kubernetes",
|
||||
"network",
|
||||
"traffic",
|
||||
"api",
|
||||
"http",
|
||||
"grpc",
|
||||
"kafka",
|
||||
"redis",
|
||||
"dns",
|
||||
"pcap",
|
||||
"wireshark",
|
||||
"tcpdump",
|
||||
"observability",
|
||||
"debugging",
|
||||
"microservices"
|
||||
],
|
||||
"packages": [
|
||||
{
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/kubeshark/kubeshark/releases/download/vX.Y.Z/kubeshark-mcp_darwin_arm64.mcpb",
|
||||
"fileSha256": "AUTO_GENERATED",
|
||||
"transport": { "type": "stdio" }
|
||||
},
|
||||
{
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/kubeshark/kubeshark/releases/download/vX.Y.Z/kubeshark-mcp_darwin_amd64.mcpb",
|
||||
"fileSha256": "AUTO_GENERATED",
|
||||
"transport": { "type": "stdio" }
|
||||
},
|
||||
{
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/kubeshark/kubeshark/releases/download/vX.Y.Z/kubeshark-mcp_linux_arm64.mcpb",
|
||||
"fileSha256": "AUTO_GENERATED",
|
||||
"transport": { "type": "stdio" }
|
||||
},
|
||||
{
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/kubeshark/kubeshark/releases/download/vX.Y.Z/kubeshark-mcp_linux_amd64.mcpb",
|
||||
"fileSha256": "AUTO_GENERATED",
|
||||
"transport": { "type": "stdio" }
|
||||
},
|
||||
{
|
||||
"registryType": "mcpb",
|
||||
"identifier": "https://github.com/kubeshark/kubeshark/releases/download/vX.Y.Z/kubeshark-mcp_windows_amd64.mcpb",
|
||||
"fileSha256": "AUTO_GENERATED",
|
||||
"transport": { "type": "stdio" }
|
||||
"registryType": "github-releases",
|
||||
"name": "kubeshark/kubeshark",
|
||||
"version": "52.12.0",
|
||||
"runtime": "binary",
|
||||
"platforms": [
|
||||
"darwin-arm64",
|
||||
"darwin-amd64",
|
||||
"linux-arm64",
|
||||
"linux-amd64",
|
||||
"windows-amd64"
|
||||
],
|
||||
"transport": {
|
||||
"type": "stdio",
|
||||
"command": "kubeshark",
|
||||
"args": ["mcp"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
@@ -133,14 +136,38 @@
|
||||
}
|
||||
],
|
||||
"prompts": [
|
||||
{ "name": "analyze_traffic", "description": "Analyze API traffic patterns and identify issues" },
|
||||
{ "name": "find_errors", "description": "Find and summarize API errors and failures" },
|
||||
{ "name": "trace_request", "description": "Trace a request path through microservices" },
|
||||
{ "name": "show_topology", "description": "Show service communication topology" },
|
||||
{ "name": "latency_analysis", "description": "Analyze latency patterns and identify slow endpoints" },
|
||||
{ "name": "security_audit", "description": "Audit traffic for security concerns" },
|
||||
{ "name": "compare_traffic", "description": "Compare traffic patterns between time periods" },
|
||||
{ "name": "debug_connection", "description": "Debug connectivity issues between services" }
|
||||
{
|
||||
"name": "analyze_traffic",
|
||||
"description": "Analyze API traffic patterns and identify issues"
|
||||
},
|
||||
{
|
||||
"name": "find_errors",
|
||||
"description": "Find and summarize API errors and failures"
|
||||
},
|
||||
{
|
||||
"name": "trace_request",
|
||||
"description": "Trace a request path through microservices"
|
||||
},
|
||||
{
|
||||
"name": "show_topology",
|
||||
"description": "Show service communication topology"
|
||||
},
|
||||
{
|
||||
"name": "latency_analysis",
|
||||
"description": "Analyze latency patterns and identify slow endpoints"
|
||||
},
|
||||
{
|
||||
"name": "security_audit",
|
||||
"description": "Audit traffic for security concerns"
|
||||
},
|
||||
{
|
||||
"name": "compare_traffic",
|
||||
"description": "Compare traffic patterns between time periods"
|
||||
},
|
||||
{
|
||||
"name": "debug_connection",
|
||||
"description": "Debug connectivity issues between services"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user