334 lines
16 KiB
Markdown
334 lines
16 KiB
Markdown
# Headlamp Polaris Plugin
|
|
|
|
[](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)
|
|
[](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/ci.yaml)
|
|
[](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/e2e.yaml)
|
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
|
|
A [Headlamp](https://headlamp.dev/) plugin that surfaces [Fairwinds Polaris](https://polaris.docs.fairwinds.com/) audit results directly in the Headlamp UI.
|
|
|
|
**[Documentation](#documentation) | [Installation](#installing) | [Security](#rbac--security-setup) | [Development](#development)**
|
|
|
|
## What It Does
|
|
|
|
Adds a **Polaris** top-level sidebar section to Headlamp with comprehensive security, reliability, and efficiency audit integration:
|
|
|
|
### Main Views
|
|
|
|
- **Overview Dashboard** -- cluster score with percentage gauge, check distribution charts, top 10 most common failing checks across the cluster, cluster statistics, and last audit time with manual refresh button
|
|
- **Namespaces** -- table of all namespaces with per-namespace score and check counts; click a namespace to open a detailed side panel (1000px wide, theme-aware)
|
|
- **Namespace Detail Panel** -- per-namespace score, check counts, resource-level audit results, external Polaris dashboard link, and exemption management
|
|
|
|
### Integrated Features
|
|
|
|
- **App Bar Score Badge** -- cluster Polaris score displayed as a colored chip in the top navigation bar (green ≥80%, yellow ≥50%, red <50%); click to navigate to overview
|
|
- **Inline Resource Audits** -- Polaris audit results automatically injected into detail views for Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs; shows compact score, failing checks table, and link to full report
|
|
- **Exemption Management** -- add or remove Polaris exemptions via annotation patches directly from the UI; supports per-check exemptions or exempt-all
|
|
- **Configurable Dashboard URL** -- supports both Kubernetes service proxy URLs and full HTTP/HTTPS URLs for external Polaris deployments
|
|
- **Connection Testing** -- test button in settings to verify Polaris dashboard connectivity and show version info
|
|
- **Dark Mode Support** -- full theme adaptation using MUI `useTheme()` API; drawer, settings, and all UI elements respect system/Headlamp theme
|
|
|
|
### Data & Refresh
|
|
|
|
Data is fetched from the Polaris dashboard API through the Kubernetes service proxy (`/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`) or custom URLs. The plugin is primarily read-only; it only writes when explicitly applying exemption annotations.
|
|
|
|
Results are refreshed on a user-configurable interval (1 / 5 / 10 / 30 minutes, default 5). Settings are available in **Settings > Plugins > Polaris** and persist in browser localStorage.
|
|
|
|
Error states are handled explicitly with context-specific messages: RBAC denied (403), Polaris not installed (404/503), malformed JSON, network failures, and CORS issues.
|
|
|
|
## Prerequisites
|
|
|
|
| Requirement | Minimum version |
|
|
| -------------------------------- | ------------------ |
|
|
| Headlamp | v0.26+ |
|
|
| Polaris (with dashboard enabled) | Any recent release |
|
|
| Kubernetes | v1.24+ |
|
|
|
|
Polaris must be deployed in the `polaris` namespace with the dashboard component enabled (`dashboard.enabled: true` in the Helm chart, which is the default). The plugin reads from the `polaris-dashboard` ClusterIP service on port 80.
|
|
|
|
## Installing
|
|
|
|
The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin). Install via the Headlamp UI:
|
|
|
|
1. Go to **Settings → Plugins**
|
|
2. Click **Catalog** tab
|
|
3. Search for "Polaris"
|
|
4. Click **Install**
|
|
|
|
Or configure Headlamp via Helm:
|
|
|
|
```yaml
|
|
config:
|
|
pluginsDir: /headlamp/plugins
|
|
|
|
pluginsManager:
|
|
sources:
|
|
- name: headlamp-polaris-plugin
|
|
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
|
```
|
|
|
|
> See [Plugin Installation Policy](https://git.farh.net/privilegedescalation/privilegedescalation.com/wiki/Plugin-Installation-Policy) for approved installation methods.
|
|
|
|
## RBAC / Security Setup
|
|
|
|
The plugin fetches audit data through the Kubernetes API server's **service proxy** sub-resource. The identity making the request (Headlamp's service account, or the user's own token in token-auth mode) must be granted:
|
|
|
|
| Verb | API Group | Resource | Resource Name | Namespace |
|
|
| ----- | ----------- | ---------------- | ------------------- | --------- |
|
|
| `get` | `""` (core) | `services/proxy` | `polaris-dashboard` | `polaris` |
|
|
|
|
### Minimal RBAC manifests
|
|
|
|
```yaml
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
name: polaris-proxy-reader
|
|
namespace: polaris
|
|
rules:
|
|
- apiGroups: ['']
|
|
resources: ['services/proxy']
|
|
resourceNames: ['polaris-dashboard']
|
|
verbs: ['get']
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: headlamp-polaris-proxy
|
|
namespace: polaris
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: headlamp # adjust to match your Headlamp service account
|
|
namespace: <your-namespace>
|
|
roleRef:
|
|
kind: Role
|
|
name: polaris-proxy-reader
|
|
apiGroup: rbac.authorization.k8s.io
|
|
```
|
|
|
|
Apply with `kubectl apply -f polaris-rbac.yaml`.
|
|
|
|
### Token-auth mode
|
|
|
|
When Headlamp is configured for user-supplied tokens (rather than a fixed service account), **each user** must have the RoleBinding above attached to their own identity. A 403 error in the plugin means the currently logged-in user lacks this binding.
|
|
|
|
### NetworkPolicy
|
|
|
|
If the `polaris` namespace enforces network policies, ensure ingress is allowed from the Kubernetes API server (which performs the proxy hop) to `polaris-dashboard` on port 80.
|
|
|
|
### Read-only access
|
|
|
|
The plugin only performs `GET` requests through the service proxy. No `create`, `update`, `delete`, or `patch` verbs are required. Do not grant broader access than `get` on `services/proxy`.
|
|
|
|
### Audit logging
|
|
|
|
Every proxied request is recorded in Kubernetes API audit logs as a `get` on `services/proxy` in the `polaris` namespace. If the auto-refresh interval generates more audit volume than desired, increase the refresh interval in the plugin settings or adjust your audit policy.
|
|
|
|
## Documentation
|
|
|
|
**[Complete Documentation](docs/README.md)** - Documentation hub with all guides
|
|
|
|
### Quick Links
|
|
|
|
- **[Quick Start](docs/getting-started/quick-start.md)** - Get up and running in 5 minutes
|
|
- **[Installation Guide](docs/getting-started/installation.md)** - All installation methods (Plugin Manager, Sidecar, Manual, Source)
|
|
- **[Troubleshooting](docs/troubleshooting/README.md)** - Quick diagnosis and common issues
|
|
|
|
### Comprehensive Guides
|
|
|
|
| Guide | Description |
|
|
| ------------------------------------------------- | --------------------------------------------------------------------- |
|
|
| **[Architecture](docs/architecture/overview.md)** | System architecture, data flow, component hierarchy, design decisions |
|
|
| **[Deployment](docs/deployment/helm.md)** | Production deployment with Helm, Kubernetes, FluxCD |
|
|
| **[Security](SECURITY.md)** | Security model, RBAC requirements, vulnerability reporting |
|
|
| **[Testing](docs/development/testing.md)** | Unit tests, E2E tests, CI/CD, best practices |
|
|
| **[Contributing](CONTRIBUTING.md)** | Development workflow, branching strategy, PR process |
|
|
| **[Changelog](CHANGELOG.md)** | Complete release history (v0.0.1 to current) |
|
|
|
|
## Troubleshooting
|
|
|
|
**For comprehensive troubleshooting, see [docs/troubleshooting/README.md](docs/troubleshooting/README.md).**
|
|
|
|
Quick reference:
|
|
|
|
| Symptom | Likely Cause | Quick Fix |
|
|
| ------------------------------- | --------------------------------------------- | --------------------------------------------------------------------- |
|
|
| **Plugin not in sidebar** | Plugin not installed or needs browser refresh | Hard refresh browser (Cmd+Shift+R / Ctrl+Shift+F5) |
|
|
| **403 Access Denied** | Missing RBAC binding for `services/proxy` | Apply Role + RoleBinding from RBAC section |
|
|
| **404 or 503** | Polaris not installed, or dashboard disabled | Install Polaris with `dashboard.enabled: true` in `polaris` namespace |
|
|
| **Dark mode white backgrounds** | Old plugin version | Upgrade to v0.6.0+ and hard refresh browser |
|
|
| **Settings page empty** | Old plugin version | Upgrade to v0.3.3+ |
|
|
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` |
|
|
|
|
## Development
|
|
|
|
**For detailed development guide, see [CONTRIBUTING.md](CONTRIBUTING.md).**
|
|
|
|
### Quick Start
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
|
|
cd headlamp-polaris-plugin
|
|
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Run with hot reload
|
|
npm start # Opens Headlamp at http://localhost:4466
|
|
|
|
# Build for production
|
|
npm run build # outputs dist/main.js
|
|
npm run package # creates headlamp-polaris-plugin-<version>.tar.gz
|
|
|
|
# Run tests
|
|
npm test # unit tests
|
|
npm run e2e # E2E tests (requires Headlamp instance)
|
|
|
|
# Code quality
|
|
npm run lint # eslint
|
|
npm run tsc # type-check
|
|
npm run format # prettier format
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Unit tests (Vitest)
|
|
npm test
|
|
npm run test:watch
|
|
|
|
# E2E tests (Playwright)
|
|
export HEADLAMP_TOKEN=$(kubectl create token headlamp -n <your-namespace> --duration=24h)
|
|
npm run e2e
|
|
npm run e2e:headed # see browser
|
|
```
|
|
|
|
For complete testing guide including CI/CD integration, see **[docs/TESTING.md](docs/TESTING.md)**.
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
index.tsx -- Entry point. Registers sidebar entries, routes, and error boundaries.
|
|
test-utils.tsx -- Shared test fixtures (makeResult, makeAuditData).
|
|
api/
|
|
polaris.ts -- TypeScript types (AuditData schema), usePolarisData hook,
|
|
countResults utilities, refresh interval settings.
|
|
checkMapping.ts -- Polaris check ID → human-readable name mapping.
|
|
topIssues.ts -- Top failing checks aggregation logic.
|
|
PolarisDataContext.tsx -- React context provider; shared data fetch across views.
|
|
components/
|
|
DashboardView.tsx -- Overview page (score, check summary with skipped, cluster info).
|
|
NamespacesListView.tsx -- Namespace list with scores; MUI Drawer detail panel.
|
|
InlineAuditSection.tsx -- Inline audit for Deployment/StatefulSet/DaemonSet/Job/CronJob detail views.
|
|
ExemptionManager.tsx -- Polaris exemption annotation management.
|
|
AppBarScoreBadge.tsx -- App bar cluster score chip.
|
|
PolarisSettings.tsx -- Plugin settings page (refresh interval, dashboard URL).
|
|
vitest.config.mts -- Vitest configuration (jsdom environment).
|
|
```
|
|
|
|
## Data Source
|
|
|
|
The plugin fetches live audit results from the Polaris dashboard HTTP API via the Kubernetes service proxy:
|
|
|
|
```
|
|
GET /api/v1/namespaces/polaris/services/polaris-dashboard/proxy/results.json
|
|
```
|
|
|
|
This endpoint is served by the `polaris-dashboard` ClusterIP service, which is created by the Polaris Helm chart when `dashboard.enabled: true`. The JSON response matches Polaris's `AuditData` schema (`pkg/validator/output.go`):
|
|
|
|
```
|
|
AuditData
|
|
ClusterInfo -- nodes, pods, namespaces, controllers
|
|
Results[] -- per-workload results
|
|
Results{} -- top-level check results (ResultSet)
|
|
PodResult
|
|
Results{} -- pod-level check results
|
|
ContainerResults[]
|
|
Results{} -- container-level check results
|
|
```
|
|
|
|
Each check in a `ResultSet` has `Success` (bool) and `Severity` (`"warning"`, `"danger"`, or `"ignore"`). Checks with `Severity: "ignore"` and `Success: false` are counted as skipped. The cluster score is computed client-side as `pass / total * 100`.
|
|
|
|
## Known Limitations
|
|
|
|
### Skipped Count and Annotation-Based Exemptions
|
|
|
|
The **Skipped** count shown in the plugin only reflects checks with `Severity: "ignore"` in the Polaris API response. It does **not** include annotation-based exemptions (e.g., `polaris.fairwinds.com/privilegeEscalationAllowed-exempt: "true"`).
|
|
|
|
**Why?** Polaris completely omits exempted checks from the `results.json` endpoint. The native Polaris dashboard UI computes the "skipped" count client-side by:
|
|
|
|
1. Querying Kubernetes resources (Deployments, DaemonSets, StatefulSets, Pods) directly
|
|
2. Parsing their annotations for `polaris.fairwinds.com/*-exempt` keys
|
|
3. Counting how many checks were exempted
|
|
|
|
This plugin only has access to the processed audit results via the service proxy and does not query raw Kubernetes resources. To show accurate exemption counts, the plugin would need to:
|
|
|
|
- Request cluster-wide read access to all workload types (requires additional RBAC grants beyond `services/proxy`)
|
|
- Parse annotations on every workload in every namespace
|
|
- Cross-reference with the Polaris check catalog to count exemptions
|
|
|
|
This is a significant architectural change and is not currently implemented. Hover over the "Skipped" count in the UI to see a tooltip explaining this limitation.
|
|
|
|
**Workaround:** Use the "View in Polaris Dashboard" link from any namespace detail view to see the full exemption count in the native dashboard.
|
|
|
|
## Releasing
|
|
|
|
Releases are automated via **GitHub Actions**. To cut a release:
|
|
|
|
```bash
|
|
# 1. Update CHANGELOG.md with new version
|
|
# 2. Bump version in package.json and artifacthub-pkg.yml:
|
|
git add package.json artifacthub-pkg.yml CHANGELOG.md
|
|
git commit -m "chore: bump version to X.Y.Z"
|
|
git push origin main
|
|
|
|
# 3. Create and push tag:
|
|
git tag vX.Y.Z
|
|
git push origin vX.Y.Z
|
|
```
|
|
|
|
This triggers the **GitHub Actions** release workflow (`.github/workflows/release.yaml`):
|
|
|
|
1. Build the plugin in a `node:20` container
|
|
2. Package a `.tar.gz` tarball
|
|
3. Create a GitHub release with the tarball attached
|
|
4. Calculate SHA256 checksum
|
|
5. Update `artifacthub-pkg.yml` checksum on main branch
|
|
6. Force-move the tag to include checksum update
|
|
|
|
A guard step prevents infinite loops: if the release tarball checksum already matches the metadata, the workflow is skipped.
|
|
|
|
### ArtifactHub Sync
|
|
|
|
ArtifactHub pulls plugin metadata from GitHub every **30 minutes**. After creating a release:
|
|
|
|
- Wait 30 minutes for sync
|
|
- Check [ArtifactHub package page](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)
|
|
- New version should appear in Headlamp plugin catalog
|
|
|
|
For complete release process and version numbering guidelines, see **[CONTRIBUTING.md#release-process](CONTRIBUTING.md#release-process)**.
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
|
|
|
- Development workflow
|
|
- Branching strategy (feature branches required for code changes)
|
|
- Commit message conventions (Conventional Commits)
|
|
- PR process and review checklist
|
|
- Code style guidelines
|
|
- Testing requirements
|
|
|
|
## Links
|
|
|
|
- **[GitHub Repository](https://github.com/privilegedescalation/headlamp-polaris-plugin)** - Source code, issues, releases
|
|
- **[Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)** - Plugin catalog listing
|
|
- **[Headlamp](https://headlamp.dev/)** - Kubernetes web UI
|
|
- **[Fairwinds Polaris](https://polaris.docs.fairwinds.com/)** - Kubernetes best practices audit tool
|
|
|
|
## License
|
|
|
|
[Apache-2.0 License](LICENSE) - see LICENSE file for details.
|