
A Kubernetes console built for EKS — keyless cluster access, every action signed by the human who took it.
Modern AWS security baselines are retiring long-lived IAM credentials — and most Kubernetes dashboards quietly depend on them. Take the static keys away and your console either stops working, or falls back to a single shared service-account identity. With a shared identity the audit trail goes blind: every action reads as dashboard-bot, never the person who actually took it.
Periscope is built for that world.
Periscope is a self-hosted, multi-cluster Kubernetes console focused on EKS. It authenticates to clusters with Pod Identity / IRSA — no static AWS keys on the console pod — authenticates users via OIDC, and impersonates each user on every API call, so your cluster's own audit log records alice@corp, never a shared bot. It runs as a single stateless binary.
- Keyless on EKS. Cluster access is obtained on demand through Pod Identity or IRSA. Nothing static lives on the console pod.
- A real human in every audit row. Impersonation carries each user's OIDC identity onto every Kubernetes call — so both your cluster's apiserver audit log and Periscope's own signed, searchable audit trail show the person, never
periscope-bot. - It understands EKS, not just Kubernetes. IAM access analysis ("which workloads can perform action X?"), Amazon Inspector v2 CVE findings grouped by package, EKS Access Entries / aws-auth reconciliation, upgrade-readiness insights, add-on management, and a Karpenter dashboard.
- And it's a complete console. Multi-cluster fleet view, live resource browsing over SSE, a schema-aware YAML editor with server-side apply, the full Helm lifecycle (install / upgrade / rollback / diff), logs, in-browser
exec— plus an agent tunnel that manages any cluster with outbound HTTPS, no IAM trust required.
The fastest way to see Periscope without touching AWS or an IdP. Runs on any local Kubernetes — kind / k3d / minikube. Sign-in uses an in-process dev fallback, so anyone hitting the dashboard becomes dev@local.
# 1. Create a local cluster
kind create cluster --name periscope-demo
# 2. Install with the kind-tuned values
helm install periscope \
oci://ghcr.io/gnana997/charts/periscope --version 1.1.2 \
--namespace periscope --create-namespace \
--values https://periscopehq.dev/examples/values-kind.yaml
# 3. Wait + open
kubectl -n periscope wait --for=condition=Available deploy/periscope --timeout=120s
kubectl -n periscope port-forward svc/periscope 8080:8080
# 4. Visit http://localhost:8080 in your browser.
# Sign-in is automatic — you arrive as "dev@local". No IdP setup.Cleanup: kind delete cluster --name periscope-demo.
⚠️ Dev sign-in is for local evaluation only. Don't run this profile against a cluster that holds real workloads — anyone who can reach the SPA becomes the configureddevuser withcluster-adminimpersonation.
Prerequisites: Go 1.26, Node 22, and a kubeconfig with access to at least one cluster.
make backend # Go API on :8088
make frontend # Vite dev server on :5173 (proxies /api -> :8088)Open http://localhost:5173.
A Helm chart lives at deploy/helm/periscope/. Full walkthrough including OIDC client setup and Pod Identity / IRSA wiring: docs/setup/deploy.md.
# Pin to a specific version. Find the latest at
# https://artifacthub.io/packages/helm/periscope/periscope
helm install periscope \
oci://ghcr.io/gnana997/charts/periscope \
--version <VERSION> \
--namespace periscope --create-namespaceFor CI / scripts that always want the latest stable, resolve the tag from the GitHub API:
LATEST=$(curl -s https://api.github.com/repos/gnana997/periscope/releases/latest \
| jq -r .tag_name | sed 's/^v//')
helm install periscope \
oci://ghcr.io/gnana997/charts/periscope \
--version "$LATEST" \
--namespace periscope --create-namespaceBoth signed (cosign keyless) and discoverable on Artifact Hub. To verify the chart signature before install, see the verification snippet in docs/RELEASING.md.
The What makes it different section above is the short version. For the complete capability list — authentication, multi-cluster, browsing, editing, Helm, EKS add-ons, upgrade readiness, Karpenter, CVE surfacing, AWS Access, and audit — see docs/features.md.
v1.1 stable. The public HTTP API, configuration shape, and Helm values are covered by semver — breaking changes will land in a future major (v2); bugfixes and additive features land on minor / patch tags off main. See CHANGELOG.md for what shipped per release.
Setup
- Configuration & deployment
- Helm values reference
- Environment variables reference
- OIDC setup — Auth0
- OIDC setup — Okta
- In-cluster RBAC the backend needs
- Audit log persistence
- Watch streams (SSE) operator guide
- Helm release browser
- Pod exec setup
- Cluster shell setup — in-browser cluster-wide kubectl REPL via per-session ephemeral pod (#104)
- NetworkPolicy
- Apply YAML dialog — paste/drop multi-doc YAML with per-doc RBAC pre-flight
- Multi-cluster onboarding (agent) — register a managed cluster via the periscope-agent tunnel
- EKS upgrade readiness — Upgrade Insights + managed node group AMI drift
- Troubleshooting — symptom-keyed index across every feature, plus cross-cutting gotchas (chart-versions OOM, scanner false-positives, local-dev TLS)
Usage
- Karpenter dashboard — NodePool/$/hr/Drift/pending-pods walkthrough + cost-RBAC sample
- CVE surfacing (Inspector v2) — chip column + Security tab walkthrough, enablement, audit + cost
- Cluster shell — open the in-browser cluster shell, identity wiring, security note
Architecture
- Architecture overview — component map, source-tree guide, reading order for new contributors
- Watch streams — push model, fallback, RBAC
- Agent tunnel — multi-cluster transport, PKI, registration
Reference
RFCs
- RFC 0001 — Pod exec support
- RFC 0002 — Authentication (OIDC + per-user K8s authz)
- RFC 0003 — Audit log: schema and retention semantics
| What | Where |
|---|---|
| OIDC (user auth) | examples/config/auth.yaml.auth0, examples/config/auth.yaml.okta |
| Cluster registry | Helm values; see deploy guide |
| In-cluster RBAC | docs/setup/cluster-rbac.md |
| Audit persistence | Helm audit: block; see docs/setup/audit.md |
| Watch streams | Helm watchStreams: block; see docs/setup/watch-streams.md |
Single Go binary embeds the React SPA. Stateless with respect to user credentials — OIDC sessions kept in memory only; no kubeconfigs or AWS keys persisted. Runs as non-root with a read-only root filesystem, no privilege escalation, and a RuntimeDefault seccomp profile (configured in the Helm chart).
For component-level detail see docs/architecture/ and docs/rfcs/.
Repository layout:
cmd/periscope/ backend entry point
internal/ backend packages (auth, authz, audit, clusters, credentials, exec, k8s, secrets, sse, httpx, spa)
web/ React + TypeScript SPA (Vite, Monaco editor)
deploy/helm/ Helm chart
docs/ setup guides, architecture notes, RFCs
examples/ reference configs
Makefile common targets
Common targets:
| Target | Purpose |
|---|---|
make backend |
Run the Go backend on :8088 |
make frontend |
Run the Vite dev server on :5173 |
make build |
Build the SPA, embed it, produce a single binary at bin/periscope |
make test |
Run Go tests |
make image |
Build the container image |
make helm-lint / make helm-template |
Validate or render the chart locally |
Frontend tests:
cd web && npx vitest runCI: every push and PR runs golangci-lint, go test, npm run lint, npm test, npm run build, helm lint + helm template smoke renders, and an embedded-binary build. See .github/workflows/ci.yaml.
(See CONTRIBUTING.md for coding conventions, PR process, and a longer dev guide.)
Planning is tracked in GitHub Milestones. v1.1 (shipped) delivered the AWS Access surfaces — Cluster Access page reconciling EKS Access Entries + aws-auth + IRSA + Pod Identity, per-workload AWS Access tab with sensitive-permissions chips, and reverse lookup ("which workloads can perform action X?").
- v1.2: operator daily-driver layer. In-browser cluster shell (#104, shipped on
develop— per-session ephemeral pod, tier-narrow impersonation, single-log audit; seedocs/setup/cluster-shell.md). In-browser node shell (#105, shipped ondevelop— SSM terminal onto an EKS node's EC2 host with per-user OIDC→STS AWS impersonation, CloudTrail-attributed; seedocs/setup/node-shell-ssm.md). GPU + AI workload visibility (Pod ↔ GPU map, idle-GPU finder, DCGM reconciler), Helm private-OCI auth via Pod Identity / IRSA (#121). - v1.3: AWS depth + observability. IAM effective-access engine (conditions, SCPs, cross-account
AssumeRolewalking), CloudTrail compliance lens, cluster-wide kube-apiserver audit ingestion, related-resources graph, CronJob CVE-ownership chain, per-NodeGroup CVE rollup. - v1.4: agent-native. MCP-style tool registry over the v1.1–v1.3 wire shapes (#151), LLM provider abstraction, in-app chat surface,
agent_tool_callaudit verb.
- Bugs & feature requests: GitHub Issues
- Questions & discussion: GitHub Discussions
- Security vulnerabilities: see
SECURITY.md
Contributions are welcome. Read CONTRIBUTING.md before opening a PR. By participating in this project you agree to abide by its CODE_OF_CONDUCT.md.
