A Kubernetes-native web dashboard for managing and orchestrating security testing infrastructure. The Kentra Dashboard provides a unified interface for managing attack scenarios, target configurations, storage resources, and real-time log monitoring across Kubernetes environments.
The Kentra Dashboard is a full-stack application built with Go (Gin framework) and vanilla JavaScript, designed to interact with Kubernetes Custom Resource Definitions (CRDs) for security testing orchestration. It features real-time log streaming via WebSocket, multi-tenant namespace management, and comprehensive resource quota controls.
- Environment Management: Create and manage isolated Kubernetes namespaces with resource quotas
- Attack Orchestration: Deploy and configure security attack scenarios using Kentra CRDs
- Target Management: Define and manage attack targets (TargetPools, AssetPools)
- Real-time Logging: WebSocket-based log streaming with Loki integration
- Storage Management: Handle PersistentVolumeClaims, ConfigMaps, and Secrets
- Report Viewing: Access and review security testing reports
- Multi-theme UI: 11 customizable themes for different visual preferences
- Read-only Mode: Optional read-only mode for safe observation
- Web Framework: Gin v1.11.0
- Kubernetes Client: k8s.io/client-go v0.35.0
- Log Aggregation: Grafana Loki client integration
- Real-time Communication: Gorilla WebSocket v1.5.4
- API Documentation: Swagger/OpenAPI (swaggo)
- JavaScript: Vanilla JavaScript with modular architecture
- State Management: Custom state system compatible with Alpine.js
- Styling: Tailwind CSS (CDN) + custom themes
- Templating: Go html/template (server-side rendering)
- WebSocket Client: Native browser WebSocket API
- Containerization: Docker (Alpine Linux)
- Orchestration: Kubernetes with Helm charts
- Log Backend: Grafana Loki
dashboard/
├── src/ # Go backend source
│ ├── app/ # Server, handlers, and routes
│ │ ├── server.go # Main application server
│ │ ├── routes.go # Route definitions
│ │ ├── handlers_*.go # Resource-specific handlers
│ │ └── middleware.go # HTTP middleware (auth, logging, read-only)
│ ├── clients/ # External client integrations
│ │ ├── kubernetes/ # Kubernetes client wrapper
│ │ ├── loki/ # Loki log client
│ │ └── websocket/ # WebSocket stream manager
│ ├── config/ # Configuration loader
│ └── models/ # Shared data models
├── web/ # Frontend assets
│ ├── static/ # CSS themes, JavaScript modules, images
│ │ ├── css/ # Theme stylesheets
│ │ └── js/modules/ # JavaScript modules
│ ├── templates/ # HTML templates
│ │ ├── views/ # Page views
│ │ ├── components/ # Reusable components (header, sidebar)
│ │ ├── modals/ # Modal dialogs
│ │ └── panels/ # Content panels
│ └── docs/ # Documentation assets
├── helm/ # Kubernetes Helm charts
├── kubernetes/ # Kubernetes manifests
├── main.go # Application entry point
├── Dockerfile # Docker build configuration
└── Makefile # Build and deployment commands
All API endpoints are prefixed with /api and return JSON responses.
GET /health # Health check endpoint
GET /api/pod-namespace # Get current pod namespace configuration
GET /api/environments # List all managed namespaces
POST /api/environments # Create new namespace with quotas
DELETE /api/environments/:namespace # Delete namespace
GET /api/environments/:namespace/quota # Get resource quota information
Create Environment Request:
{
"name": "test-env",
"description": "Testing environment",
"quotas": {
"cpu": "4",
"memory": "8Gi"
},
"limits": {
"cpu": "2",
"memory": "4Gi"
}
}GET /api/attacks/:namespace # List attacks in namespace
POST /api/attacks/:namespace # Create new attack
PUT /api/attacks/:namespace/:name # Update existing attack
DELETE /api/attacks/:namespace/:name # Delete attack
GET /api/attack-types # List available attack types
GET /api/crd-schema/:type # Get CRD schema for attack type
Supported Attack Types:
Enumeration- Network and service enumerationExploit- Exploitation scenariosLiveness- Continuous monitoring attacksOsint- Open-source intelligence gatheringSecurityAttack- General security attacks
Create Attack Request:
{
"name": "my-attack",
"attackType": "Enumeration",
"spec": {
"target": "target-pool-name",
"tools": ["nmap", "masscan"],
"options": {}
}
}GET /api/targets/:namespace # List targets in namespace
POST /api/targets/:namespace # Create new target
PUT /api/targets/:namespace/:name # Update existing target
DELETE /api/targets/:namespace/:name # Delete target
GET /api/target-types # List available target types
GET /api/target-crd-schema/:type # Get CRD schema for target type
Supported Target Types:
TargetPool- Pool of target hosts/IPsAssetPool- Pool of assets for testing
Create Target Request:
{
"name": "my-target",
"targetType": "TargetPool",
"spec": {
"targets": ["192.168.1.0/24"],
"ports": [80, 443, 8080],
"protocols": ["tcp"]
}
}GET /api/storage/:namespace # List storage resources
POST /api/storage/:namespace # Create storage resource
DELETE /api/storage/:namespace/:name # Delete storage resource
Storage Types:
pvc- PersistentVolumeClaimconfigmap- Kubernetes ConfigMapsecret- Kubernetes Secret
Create Storage Request:
{
"name": "my-storage",
"type": "pvc",
"size": "10Gi",
"mountPath": "/data",
"labels": {
"app": "my-app"
}
}GET /api/toolspecs/:namespace # List toolspecs
POST /api/toolspecs/:namespace # Create toolspec
POST /api/toolspecs/:namespace/:name/tools # Add tool to toolspec
DELETE /api/toolspecs/:namespace/:name/tools/:tool # Remove tool from toolspec
DELETE /api/toolspecs/:namespace/:name # Delete toolspec
Add Tool Request:
{
"name": "nmap",
"type": "scanner",
"category": "network",
"image": "instrumentisto/nmap:latest",
"commandTemplate": "nmap {options} {target}",
"capabilities": ["NET_RAW", "NET_ADMIN"]
}GET /api/reports/:namespace # List reports in namespace
GET /api/reports/:namespace/:id # Get specific report
POST /api/upload # Upload file
GET /api/files # List uploaded files
GET /api/files/download # Download file
DELETE /api/files # Delete file
GET /api/logs/:namespace/:pod/:container # Fetch historical pod logs
GET /ws/logs # WebSocket endpoint for real-time log streaming
WebSocket Log Message Format:
{
"timestamp": "2025-01-15T10:30:00Z",
"message": "Log message content",
"namespace": "test-env",
"pod": "attack-pod-123",
"container": "scanner",
"tool": "nmap",
"type": "info"
}GET /swagger/*any # Swagger UI (development mode only)
The dashboard follows a hierarchical navigation structure:
-
Home (
/)- Main landing page
- Environment selection and overview
- Quick access to recent environments
-
Environments (Sidebar: Environments)
- List all managed Kubernetes namespaces
- View resource quotas and usage
- Create new environments with resource limits
- Delete environments (with protection for system namespace)
-
Environment Details (
/environments/:namespace)- Overview of namespace resources
- Tabs for Attacks, Targets, Storage, and Reports
- Resource quota visualization
- Quick actions for common tasks
-
Attacks (Sidebar: Attacks)
- List all attacks in selected namespace
- Create new attack scenarios
- Configure attack parameters using CRD schemas
- View attack status and logs
- Edit and delete attacks
-
Targets (Sidebar: Targets)
- List all targets in selected namespace
- Create target pools and asset pools
- Define target specifications
- View target details
- Edit and delete targets
-
Storage (Sidebar: Storage)
- Manage PersistentVolumeClaims
- Configure ConfigMaps
- Handle Secrets
- View storage usage
- Create and delete storage resources
-
Reports (Sidebar: Reports)
- List available security reports
- View report details
- Filter reports by namespace
- Export report data
-
Settings (Sidebar: Settings)
- Theme selection (11 themes available)
- Configuration viewers (Kentra, Loki)
- Application settings
- Read-only mode indicator
- Navigate to Environments and create a new environment (namespace)
- Set resource quotas (CPU, Memory) for the environment
- Go to Targets and create a target pool
- Navigate to Attacks and create a new attack
- Select attack type (Enumeration, Exploit, etc.)
- Configure attack parameters using the dynamic form
- Assign the target pool to the attack
- Monitor real-time logs via the log panel
- View results in the Reports section
- Select an environment from the environment dropdown
- Use the sidebar to navigate to the resource type
- Click "Create" to add new resources
- Use the edit/delete actions on existing resources
- View resource details in expandable panels
- Open the log panel (available on attack and environment pages)
- Logs stream automatically via WebSocket
- Filter logs by:
- Namespace
- Pod name
- Tool name
- Log type (info, warning, error)
- Time range
- Use pause/resume controls for log scrolling
- Search within logs using the search bar
The frontend uses a modular JavaScript architecture:
| Module | Purpose | Key Functions |
|---|---|---|
| state.js | Global state management | createStore(), state getters/setters |
| navigation.js | View routing and navigation | navigateTo(), updateSidebar() |
| environments.js | Environment operations | fetchEnvironments(), createEnvironment(), deleteEnvironment() |
| attacks.js | Attack management | fetchAttacks(), createAttack(), updateAttack() |
| targets.js | Target operations | fetchTargets(), createTarget(), deleteTarget() |
| storage.js | Storage management | fetchStorage(), createStorage() |
| toolspecs.js | Tool specification handling | fetchToolspecs(), addTool() |
| logs.js | WebSocket log streaming | connectWebSocket(), filterLogs() |
| settings.js | Theme and settings | changeTheme(), saveSettings() |
| utils.js | Common utilities | apiCall(), showNotification(), formatTime() |
Create a .env file based on .env.template:
# Loki Configuration
LOKI_HOST="localhost"
LOKI_PORT="3100"
LOKI_TLS="off"
LOKI_TLS_VERIFY="off"
LOKI_TENANT_ID="" # Required if Loki has multi-tenancy
LOKI_AUTH_USERNAME="" # Optional Loki authentication
LOKI_AUTH_PASSWORD=""
LOKI_CLUSTER_NAME="default" # Cluster identification for logs
# Kubernetes Authentication
K8S_AUTH_MODE="auto" # auto, kubeconfig, serviceaccount
KUBECONFIG=".kubeconfig" # Path to kubeconfig file
# Server Configuration
PORT=8080
GIN_MODE=debug # debug or release
# Namespace Filtering
NS_ANNOTATION_FILTER="managed-by-kentra=" # Filter namespaces by annotation
POD_NAMESPACE="kentra-system" # Dashboard's own namespace
# Security
KENTRA_READONLY="false" # Enable read-only modeAuto Mode (default):
- Tries
KUBECONFIGenvironment variable - Falls back to in-cluster ServiceAccount
- Falls back to
~/.kube/config
Kubeconfig Mode:
- Uses only kubeconfig file
- Suitable for local development
ServiceAccount Mode:
- Uses only Kubernetes ServiceAccount token
- Required for in-cluster deployment
# Clone the repository
git clone https://github.com/kentrasecurity/dashboard.git
cd dashboard
# Copy environment template
cp .env.template .env
# Edit .env with your configuration
nano .env
# Build the application
make build
# Run locally
make run# Build Docker image
docker build -t kentra-dashboard:latest .
# Run container
docker run -d \
--name kentra-dashboard \
-p 8080:8080 \
-v $(pwd)/.env:/app/.env \
-v ~/.kube/config:/app/.kubeconfig \
kentra-dashboard:latest# Install with Helm
helm install kentra-dashboard ./helm \
--namespace kentra-system \
--create-namespace \
--values ./helm/values.yaml
# Upgrade existing installation
helm upgrade kentra-dashboard ./helm \
--namespace kentra-system- Go 1.25 or later
- Kubernetes cluster (local or remote)
- kubectl configured
- (Optional) Loki instance for log aggregation
# Install dependencies
go mod download
# Build binary
go build -o dashboard main.go
# Run tests
go test ./...
# Build with hot reload (requires air)
airWhen running in development mode (GIN_MODE=debug), Swagger UI is available at:
http://localhost:8080/swagger/index.html
- Backend: Add handlers in
src/app/handlers_*.go - Routes: Register routes in
src/app/routes.go - Frontend: Create JavaScript module in
web/static/js/modules/ - Views: Add HTML templates in
web/templates/views/ - Styling: Modify themes in
web/static/css/
Enable read-only mode to prevent modifications:
KENTRA_READONLY="true"When enabled, all POST, PUT, PATCH, and DELETE requests are blocked by middleware.
The dashboard requires Kubernetes RBAC permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kentra-dashboard
rules:
- apiGroups: [""]
resources: ["namespaces", "pods", "pods/log", "persistentvolumeclaims", "configmaps", "secrets"]
verbs: ["get", "list", "create", "update", "delete", "watch"]
- apiGroups: ["kentra.io"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list"]- Passwords and tokens are masked in logs (first 3 characters + ***)
- Secrets are not exposed in API responses
- WebSocket connections are validated
- Namespace deletion is protected for system namespace
Cannot connect to Kubernetes:
- Check
K8S_AUTH_MODEsetting - Verify kubeconfig file path
- Ensure ServiceAccount has proper RBAC permissions
Logs not streaming:
- Verify Loki configuration (
LOKI_HOST,LOKI_PORT) - Check Loki connectivity with
curl http://LOKI_HOST:LOKI_PORT/ready - Ensure WebSocket connection is not blocked by firewall
CRD schemas not loading:
- Verify Kentra CRDs are installed in the cluster
- Check dashboard has permissions to read CRDs
- Review logs for API server connection errors
Theme not applying:
- Clear browser cache
- Check browser console for CSS loading errors
- Verify theme file exists in
web/static/css/
View application logs:
# Docker
docker logs -f kentra-dashboard
# Kubernetes
kubectl logs -f deployment/kentra-dashboard -n kentra-system
# Local
# Logs are printed to stdoutContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License. See LICENSE file for details.
For issues, questions, or contributions:
- Issues: GitHub Issues
- Documentation: docs/
- Website: kentra.io