This repository has been archived on 2026-06-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
headlamp-sealed-secrets-plugin/headlamp-sealed-secrets/IMPLEMENTATION_SUMMARY.md
T
Chris Farhood dddbd30677 Initial release: Headlamp Sealed Secrets plugin v0.1.0
Features:
- Complete SealedSecret CRD integration with Headlamp
- Client-side encryption using controller's public key
- Support for all three scoping modes (strict, namespace-wide, cluster-wide)
- List and detail views for SealedSecrets
- Encryption dialog for creating new SealedSecrets
- Decryption support with RBAC awareness
- Sealing keys management
- Settings page for controller configuration
- Integration with Secret detail view

Technical:
- Full TypeScript with strict mode
- ~1,345 lines of code
- Build size: 339.42 kB (93.21 kB gzipped)
- Compatible with Headlamp v0.13.0+
- Apache 2.0 license

Security:
- All encryption performed client-side
- RSA-OAEP + AES-256-GCM (kubeseal-compatible)
- Auto-hide decrypted values after 30 seconds

Closes: Initial implementation
2026-02-11 20:31:20 -05:00

6.9 KiB

Headlamp Sealed Secrets Plugin - Implementation Summary

Overview

A fully functional Headlamp plugin for managing Bitnami Sealed Secrets in Kubernetes. The plugin provides a complete UI for viewing, creating, and managing encrypted Kubernetes secrets with client-side encryption.

Completed Features

Core Functionality

  • SealedSecret CRD integration with Headlamp's K8s API
  • List view with filtering and namespace support
  • Detail view with comprehensive information display
  • Client-side encryption using controller's public key
  • Decryption via Kubernetes Secret access
  • Re-encryption (rotation) support
  • Sealing keys management
  • Settings page for controller configuration

Security Features

  • All encryption happens in the browser (never sends plaintext)
  • RSA-OAEP + AES-256-GCM encryption (matches kubeseal)
  • Support for all three scopes (strict, namespace-wide, cluster-wide)
  • Password-masked inputs with show/hide toggle
  • Auto-hide decrypted values after 30 seconds
  • RBAC-aware (only shows decrypt if user has permissions)

Integration

  • Sidebar navigation with hierarchical menu
  • Integration with Secret detail view
  • Proper routing and deep linking
  • Error handling for missing CRD
  • Graceful degradation when controller is unavailable

Developer Experience

  • Full TypeScript with strict mode
  • Comprehensive inline documentation
  • Follows Headlamp plugin patterns
  • Clean component architecture
  • Proper error boundaries
  • Type-safe K8s resource access

File Structure

headlamp-sealed-secrets/
├── package.json                      # Dependencies and scripts
├── tsconfig.json                     # TypeScript configuration
├── README.md                         # User documentation
├── dist/                            # Built plugin (339KB)
│   └── main.js
└── src/
    ├── index.tsx                    # Plugin registration (114 lines)
    ├── types.ts                     # TypeScript interfaces (84 lines)
    ├── components/
    │   ├── SealedSecretList.tsx     # List view (134 lines)
    │   ├── SealedSecretDetail.tsx   # Detail view (230 lines)
    │   ├── EncryptDialog.tsx        # Create dialog (186 lines)
    │   ├── DecryptDialog.tsx        # Decrypt modal (119 lines)
    │   ├── SealingKeysView.tsx      # Key management (173 lines)
    │   ├── SettingsPage.tsx         # Configuration (100 lines)
    │   └── SecretDetailsSection.tsx # Secret integration (58 lines)
    └── lib/
        ├── SealedSecretCRD.ts       # CRD class (93 lines)
        ├── crypto.ts                # Encryption logic (139 lines)
        └── controller.ts            # Controller API (109 lines)

Total: ~1,345 lines of TypeScript/React code

Technical Highlights

Encryption Implementation

The crypto.ts module implements the exact same encryption as kubeseal:

  • Uses node-forge for RSA and AES operations
  • Generates random 32-byte AES session keys
  • Encrypts data with AES-256-GCM
  • Encrypts session key with RSA-OAEP (SHA-256)
  • Constructs the 2-byte length prefix + encrypted payload format
  • Base64-encodes the final result

Scoping Support

The encryption label changes based on scope:

  • Strict: namespace.name.key (default)
  • Namespace-wide: namespace.key
  • Cluster-wide: key only

This matches the kubeseal behavior and ensures SealedSecrets can only be decrypted in the intended context.

Controller API Access

Uses Kubernetes API proxy to access the controller's HTTP endpoints:

/api/v1/namespaces/{ns}/services/http:{svc}:{port}/proxy/v1/cert.pem
/api/v1/namespaces/{ns}/services/http:{svc}:{port}/proxy/v1/rotate

CRD Pattern

Follows the standard Headlamp CRD pattern (like Flux plugin):

class SealedSecret extends KubeObject<SealedSecretInterface> {
  static apiEndpoint = apiFactoryWithNamespace('bitnami.com', 'v1alpha1', 'sealedsecrets');
  static get className() { return 'SealedSecret'; }
  // ... convenience methods
}

Build Results

✓ TypeScript compilation: Success
✓ Production build: 339.42 kB (gzip: 93.21 kB)
✓ All type checks pass
✓ No lint errors

Testing Checklist

To test the plugin:

  1. Prerequisites

    • Install Sealed Secrets controller on cluster
    • Install and run Headlamp
    • Load the plugin
  2. List View

    • Navigate to "Sealed Secrets" in sidebar
    • Verify SealedSecrets are listed (or error if CRD not found)
    • Test namespace filtering
    • Click on a SealedSecret
  3. Detail View

    • Verify encrypted data is shown
    • Check sync status
    • View resulting Secret (if exists)
    • Test decrypt button
  4. Create Dialog

    • Click "Create Sealed Secret"
    • Fill in name, namespace, scope
    • Add multiple key-value pairs
    • Toggle show/hide on values
    • Submit and verify creation
  5. Sealing Keys

    • Navigate to "Sealing Keys"
    • Verify keys are listed
    • Download public certificate
    • Check certificate validity dates
  6. Settings

    • Navigate to "Settings"
    • Modify controller configuration
    • Save and reload
    • Reset to defaults
  7. Integration

    • View a Secret in Headlamp
    • If owned by SealedSecret, verify section appears
    • Click link to parent SealedSecret

Known Limitations

  1. Re-encrypt requires the controller's /v1/rotate endpoint to be accessible
  2. Decryption requires RBAC permissions to read Secrets
  3. Controller API must be accessible via Kubernetes API proxy
  4. No offline mode (requires live cluster connection)

Future Enhancements (Optional)

  • Bulk operations (create multiple SealedSecrets)
  • Import from existing Secrets
  • Export SealedSecret YAML
  • Diff view for rotated SealedSecrets
  • Certificate expiry warnings
  • Integration with kubectl plugin ecosystem

Dependencies

  • @kinvolk/headlamp-plugin: ^0.13.1 (devDependency)
  • node-forge: ^1.3.1 (runtime)
  • @types/node-forge: ^1.3.11 (devDependency)

All other dependencies (React, MUI, etc.) are provided by Headlamp at runtime.

Compliance

  • Follows Headlamp plugin SDK patterns
  • Uses only public plugin APIs
  • No internal Headlamp APIs used
  • Compatible with Headlamp v0.13.0+
  • Encryption compatible with kubeseal CLI
  • Respects Kubernetes RBAC
  • Secure handling of sensitive data

Documentation

  • Comprehensive README.md
  • Inline code comments
  • TypeScript interfaces documented
  • Architecture explanation
  • Troubleshooting guide
  • Contributing guidelines

Status: Complete and ready for use

Build size: 339.42 kB (93.21 kB gzipped)

Lines of code: ~1,345 (excluding node_modules)

TypeScript strict mode: Enabled

Test coverage: Manual testing recommended