feat(extensions): add security trust configuration and signature verification

Implements a comprehensive security system for Superset extensions:

Backend:
- Add EXTENSIONS_TRUST_CONFIG to superset_config.py for admin control
- Create ExtensionSecurityManager for trust validation and signature verification
- Support Ed25519 signatures for extension manifests
- Integrate trust validation into extension loading pipeline

CLI:
- Add `generate-keys` command for creating Ed25519 signing keypairs
- Add `sign` command and `--sign` option to `bundle` for manifest signing

Frontend:
- Add WASM support to webpack config for QuickJS sandbox
- Update Extension interface with trust-related fields
- ExtensionsManager now uses backend-validated trust levels

Documentation:
- Add Administrator Configuration guide for trust settings
- Add Extension Signing guide for developers
- Update security.md and sandbox.md with cross-references
- Add Security subcategory to sidebar

Tests:
- Add 21 unit tests for trust validation and signature verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Evan Rusackas
2026-02-07 23:43:07 -08:00
parent 87bbd54d0a
commit 4ae0bc9ade
31 changed files with 7800 additions and 62 deletions

View File

@@ -0,0 +1,248 @@
---
title: Administrator Configuration
sidebar_position: 12
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Extension Administrator Configuration
This guide covers how to configure extension security for production deployments. As an administrator, you control which extensions can run and at what trust level.
## Trust Configuration
Configure extension trust in `superset_config.py`:
```python
EXTENSIONS_TRUST_CONFIG = {
# Extensions that can run with full privileges ('core' trust level)
"trusted_extensions": [
"official-parquet-export",
"enterprise-sso-plugin",
],
# Allow any extension to run as 'core' without signature verification
# WARNING: NEVER enable in production - development use only!
"allow_unsigned_core": False,
# Default sandbox for extensions without explicit trust configuration
# Options: 'core', 'iframe', 'worker', 'wasm'
"default_trust_level": "iframe",
# Require valid signatures for extensions requesting 'core' trust
# Recommended for production deployments
"require_core_signatures": True,
# Public keys for verified publishers (file paths or PEM strings)
"trusted_signers": [
"/etc/superset/keys/apache-official.pub",
"/etc/superset/keys/enterprise-team.pub",
],
}
```
## Configuration Options
### `trusted_extensions`
A list of extension IDs that are allowed to run as `core` trust level without signature verification. Use this for extensions you've reviewed and trust completely.
```python
"trusted_extensions": [
"my-company-plugin",
"approved-community-extension",
],
```
### `allow_unsigned_core`
When `True`, allows any extension to run as `core` trust level regardless of signatures or trusted list. **Never enable this in production** - it's intended only for development environments.
```python
# Development only!
"allow_unsigned_core": True,
```
### `default_trust_level`
The trust level assigned to extensions that don't specify one in their manifest. The safest option is `iframe`, which provides browser-enforced isolation.
| Level | Description |
|-------|-------------|
| `iframe` | Browser-sandboxed iframe with controlled API access (recommended default) |
| `worker` | Web Worker sandbox for command-only extensions |
| `wasm` | WASM sandbox with no DOM access (most restrictive) |
| `core` | Full access to main context (not recommended as default) |
```python
"default_trust_level": "iframe",
```
### `require_core_signatures`
When `True`, extensions requesting `core` trust level must have a valid signature from a trusted signer. Extensions without valid signatures are downgraded to `default_trust_level`.
```python
"require_core_signatures": True,
```
### `trusted_signers`
A list of public keys authorized to sign extensions. Keys can be specified as file paths or inline PEM strings.
```python
"trusted_signers": [
# File path to public key
"/etc/superset/keys/publisher.pub",
# Inline PEM string
"""-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA...
-----END PUBLIC KEY-----""",
],
```
## Signature Verification
### How It Works
1. Extension developers generate a signing keypair using the CLI
2. They sign their extension's manifest during the build process
3. The signed bundle includes `manifest.sig` alongside `manifest.json`
4. When Superset loads the extension, it verifies the signature against `trusted_signers`
5. If verification passes, the extension can run at its requested trust level
### Configuring Trusted Signers
1. Obtain the publisher's public key file (`.pub` extension)
2. Place it in a secure location on your server (e.g., `/etc/superset/keys/`)
3. Add the path to `trusted_signers` in your configuration
```python
EXTENSIONS_TRUST_CONFIG = {
"trusted_signers": [
"/etc/superset/keys/acme-corp.pub",
],
"require_core_signatures": True,
}
```
### Verifying a Key Fingerprint
Before adding a public key to your trusted signers, verify its fingerprint with the publisher:
```bash
# On the publisher's machine
superset-extensions generate-keys --output my-key.pem
# Output: Fingerprint: MCowBQYDK2Vw...
```
Compare this fingerprint with what you receive to ensure authenticity.
## Security Recommendations
### Production Deployments
1. **Set `require_core_signatures: True`** - Ensures core extensions are verified
2. **Set `allow_unsigned_core: False`** - Never allow unsigned core extensions
3. **Use `iframe` as default** - Provides strong browser isolation
4. **Limit `trusted_extensions`** - Only add extensions you've thoroughly reviewed
5. **Secure key storage** - Store public keys in protected directories
### Development Environments
For local development, you may relax some restrictions:
```python
# Development configuration
EXTENSIONS_TRUST_CONFIG = {
"trusted_extensions": [],
"allow_unsigned_core": True, # OK for development
"default_trust_level": "core", # Easier debugging
"require_core_signatures": False,
"trusted_signers": [],
}
```
## Extension Installation
### From Trusted Sources
1. Download the `.supx` bundle from a trusted source
2. Verify any checksums or signatures provided by the publisher
3. Place the bundle in your `EXTENSIONS_PATH` directory
4. If the extension requires `core` trust, add it to `trusted_extensions` or configure signature verification
### From Community Registry
Extensions from the community registry should be treated as semi-trusted at best. Consider:
1. Using `iframe` sandbox for community extensions
2. Reviewing the extension's source code before installation
3. Testing in a staging environment first
## Monitoring Extensions
### Logging
Extension trust decisions are logged at the INFO level:
```
INFO: Extension my-extension granted core trust (trusted + valid signature)
WARNING: Extension unknown-ext trust downgraded from core to iframe: Extension not in trusted list
```
Review these logs to monitor extension behavior and identify potential issues.
### Trust Downgrades
If an extension's trust is downgraded, you'll see a warning in the logs. Common reasons:
| Reason | Meaning |
|--------|---------|
| "Extension not in trusted list" | Extension requests core but isn't in `trusted_extensions` |
| "Core trust requires a valid signature" | `require_core_signatures` is enabled but signature is missing |
| "Signature verification failed" | Signature doesn't match any trusted signer |
## Troubleshooting
### Extension Not Loading as Core
1. Check if the extension ID is in `trusted_extensions`
2. If using signatures, verify the public key is in `trusted_signers`
3. Check logs for trust downgrade messages
4. Verify the extension bundle contains `manifest.sig`
### Signature Verification Failing
1. Ensure the public key file is readable by the Superset process
2. Verify the key is in PEM format with correct Ed25519 type
3. Check that the manifest wasn't modified after signing
4. Confirm the signature was created with the matching private key
### Permission Denied Errors
Sandboxed extensions may encounter permission errors if:
1. The extension's declared permissions don't match its API calls
2. The sandbox is blocking access correctly (working as intended)
3. The extension was downgraded to a more restrictive sandbox
Check the extension's `sandbox.permissions` configuration against its actual needs.

View File

@@ -0,0 +1,416 @@
---
title: Extension Sandboxing
sidebar_position: 10
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Extension Sandboxing
Superset provides a tiered sandbox architecture for running extensions with varying levels of trust and isolation. This system balances security with functionality, allowing extensions to be safely executed based on their trust level and requirements.
## Overview
The sandbox system supports three tiers of trust:
| Tier | Trust Level | Isolation | Use Case |
|------|-------------|-----------|----------|
| **Tier 1** | `core` | None (main context) | Official/signed extensions |
| **Tier 2** | `iframe` | Browser sandbox | Community UI extensions |
| **Tier 3** | `wasm` | WASM sandbox | Logic-only extensions |
## Trust Levels
### Tier 1: Core (Trusted)
Core extensions run in the main JavaScript context with full access to Superset APIs, DOM, and browser capabilities. This is the same behavior as legacy extensions.
**Requirements:**
- Must be in the trusted extensions list, OR
- `allowUnsignedCore` configuration must be enabled
**Use cases:**
- Official Apache Superset extensions
- Enterprise-verified plugins
- Extensions from trusted sources
```json
{
"id": "official-extension",
"sandbox": {
"trustLevel": "core",
"requiresSignature": true
}
}
```
### Tier 2: Iframe (Semi-Trusted)
Iframe-sandboxed extensions run in isolated browser sandboxes with controlled API access via postMessage. This provides strong browser-enforced isolation while still allowing full UI rendering.
**Security features:**
- Browser-enforced same-origin isolation
- Content Security Policy (CSP) restrictions
- Permission-based API access
- No access to parent window's cookies, localStorage, or DOM
**Use cases:**
- Community-contributed extensions
- Third-party plugins
- Extensions that render custom UI
```json
{
"id": "community-extension",
"sandbox": {
"trustLevel": "iframe",
"permissions": ["sqllab:read", "notification:show"],
"csp": {
"connectSrc": ["https://api.example.com"]
}
}
}
```
### Tier 3: WASM (Untrusted)
WASM-sandboxed extensions run in a QuickJS WebAssembly sandbox with no DOM access. Only explicitly injected APIs are available. This provides the highest level of isolation.
**Security features:**
- Complete isolation from browser APIs
- Memory limits to prevent DoS
- Execution time limits
- No network or DOM access
**Use cases:**
- Custom data transformations
- Calculated fields and formatters
- Data validation rules
- Custom aggregation functions
```json
{
"id": "formatter-extension",
"sandbox": {
"trustLevel": "wasm",
"resourceLimits": {
"maxMemory": 10485760,
"maxExecutionTime": 5000
}
}
}
```
## Permissions
Sandboxed extensions (Tier 2 and 3) must declare the permissions they need. Permissions follow a least-privilege model.
### Available Permissions
| Permission | Description |
|------------|-------------|
| `api:read` | Read-only access to Superset APIs |
| `api:write` | Write access to Superset APIs |
| `sqllab:read` | Read SQL Lab state (queries, results) |
| `sqllab:execute` | Execute SQL queries |
| `dashboard:read` | Read dashboard data |
| `dashboard:write` | Modify dashboards |
| `chart:read` | Read chart data |
| `chart:write` | Modify charts |
| `user:read` | Read current user info |
| `notification:show` | Show notifications to user |
| `modal:open` | Open modal dialogs |
| `navigation:redirect` | Navigate to other pages |
| `clipboard:write` | Write to clipboard |
| `download:file` | Trigger file downloads |
### Example Permission Declaration
```json
{
"sandbox": {
"trustLevel": "iframe",
"permissions": [
"sqllab:read",
"notification:show",
"download:file"
]
}
}
```
## Sandboxed Extension API
Extensions running in iframe sandboxes have access to a controlled API through the `window.superset` object.
### SQL Lab API
```typescript
// Get the current SQL Lab tab (requires sqllab:read)
const tab = await window.superset.sqlLab.getCurrentTab();
// Get query results (requires sqllab:read)
const results = await window.superset.sqlLab.getQueryResults(queryId);
```
### Dashboard API
```typescript
// Get dashboard context (requires dashboard:read)
const context = await window.superset.dashboard.getContext();
// Get dashboard filters (requires dashboard:read)
const filters = await window.superset.dashboard.getFilters();
```
### Chart API
```typescript
// Get chart data (requires chart:read)
const chartData = await window.superset.chart.getData(chartId);
```
### User API
```typescript
// Get current user (requires user:read)
const user = await window.superset.user.getCurrentUser();
```
### UI API
```typescript
// Show notification (requires notification:show)
window.superset.ui.showNotification('Success!', 'success');
// Open modal (requires modal:open)
const result = await window.superset.ui.openModal({
title: 'Confirm',
content: 'Are you sure?',
type: 'confirm'
});
// Navigate (requires navigation:redirect)
window.superset.ui.navigateTo('/dashboard/1');
```
### Utility API
```typescript
// Copy to clipboard (requires clipboard:write)
await window.superset.utils.copyToClipboard('text');
// Download file (requires download:file)
window.superset.utils.downloadFile(blob, 'filename.csv');
// Get CSRF token (no permission required)
const token = await window.superset.utils.getCSRFToken();
```
### Event Subscriptions
```typescript
// Subscribe to events
const unsubscribe = window.superset.on('dashboard:filterChange', (filters) => {
console.log('Filters changed:', filters);
});
// Later, unsubscribe
unsubscribe();
```
## Content Security Policy
Iframe-sandboxed extensions can customize their Content Security Policy through the `csp` configuration:
```json
{
"sandbox": {
"trustLevel": "iframe",
"csp": {
"defaultSrc": ["'none'"],
"scriptSrc": ["'unsafe-inline'"],
"styleSrc": ["'unsafe-inline'"],
"imgSrc": ["data:", "blob:", "https://cdn.example.com"],
"connectSrc": ["https://api.example.com"],
"fontSrc": ["data:"]
}
}
}
```
### Default CSP
By default, iframe sandboxes use a restrictive CSP:
```
default-src 'none';
script-src 'unsafe-inline';
style-src 'unsafe-inline';
img-src data: blob:;
font-src data:;
connect-src 'none';
frame-src 'none';
```
## WASM Resource Limits
WASM-sandboxed extensions can configure resource limits:
```json
{
"sandbox": {
"trustLevel": "wasm",
"resourceLimits": {
"maxMemory": 10485760, // 10MB max memory
"maxExecutionTime": 5000, // 5 second timeout
"maxStackSize": 1000 // Max call stack depth
}
}
}
```
### Defaults
- **maxMemory**: 10MB
- **maxExecutionTime**: 5000ms (5 seconds)
- **maxStackSize**: 1000 calls
## Migration Guide
### Migrating from Legacy Extensions
Existing extensions that don't specify a `sandbox` configuration will continue to run as `core` extensions for backward compatibility. To migrate to a sandboxed model:
1. **Assess your extension's requirements**:
- Does it need to render UI? Use `iframe`
- Is it logic-only (formatters, validators)? Use `wasm`
- Does it need full access? Keep as `core` (requires trust)
2. **Add sandbox configuration to extension.json**:
```json
{
"sandbox": {
"trustLevel": "iframe",
"permissions": ["sqllab:read"]
}
}
```
3. **Update your code to use the sandboxed API**:
Before (core extension):
```typescript
import { sqlLab } from '@apache-superset/core';
const tab = sqlLab.getCurrentTab();
```
After (sandboxed extension):
```typescript
const tab = await window.superset.sqlLab.getCurrentTab();
```
4. **Test thoroughly** to ensure all functionality works within the sandbox
## Security Comparison
| Aspect | Core | Iframe | WASM |
|--------|------|--------|------|
| DOM Access | Full | Own iframe only | None |
| Network | Full | Restricted (CSP) | None |
| Cookies | Full | None | None |
| localStorage | Full | None | None |
| Superset APIs | Full | Controlled bridge | Injected only |
| Performance | Native | Near-native | ~40% slower |
| React rendering | Full | Own instance | Via descriptors |
## Administrator Configuration
Administrators can configure trust settings for their Superset deployment:
```python
# In superset_config.py
EXTENSIONS_TRUST_CONFIG = {
# Extensions allowed to run as 'core'
"trusted_extensions": [
"official-extension-1",
"enterprise-plugin",
],
# Allow unsigned extensions to run as core (not recommended for production)
"allow_unsigned_core": False,
# Default trust level for extensions without sandbox config
"default_trust_level": "iframe",
}
```
## Best Practices
1. **Request minimal permissions** - Only request the permissions your extension actually needs
2. **Prefer iframe over core** - Unless your extension requires deep integration, use iframe sandboxing
3. **Use WASM for pure logic** - If your extension doesn't need UI, WASM provides the best isolation
4. **Handle permission denials gracefully** - Your extension should degrade gracefully if a permission is not granted
5. **Don't store sensitive data** - Sandboxed extensions should not store sensitive user data
6. **Test in sandboxed mode** - Always test your extension in its intended sandbox environment
## Troubleshooting
### Permission Denied Errors
If you see "Permission denied" errors, verify that:
1. The permission is declared in your extension.json
2. The permission was granted by the administrator
3. You're calling the correct API method for that permission
### Timeout Errors (WASM)
If your WASM extension times out:
1. Optimize your code for faster execution
2. Request a higher `maxExecutionTime` limit
3. Break large operations into smaller chunks
### CSP Violations (Iframe)
If resources fail to load due to CSP:
1. Add the required domains to your CSP configuration
2. Ensure you're using HTTPS for external resources
3. Avoid inline scripts and styles where possible
### Core Trust Denied
If your extension is downgraded from `core` to another trust level:
1. Check if the extension ID is in the administrator's `trusted_extensions` list
2. If signature verification is required, ensure the extension is signed
3. Verify the signing key is in the administrator's `trusted_signers`
See [Extension Signing](./signing) for how to sign your extension.
## Related Documentation
- [Security Overview](./security) - Extension security fundamentals
- [Extension Signing](./signing) - How to sign extensions for core trust
- [Administrator Configuration](./admin-configuration) - Trust configuration for admins

View File

@@ -26,9 +26,44 @@ under the License.
By default, extensions are disabled and must be explicitly enabled by setting the `ENABLE_EXTENSIONS` feature flag. Built-in extensions are included as part of the Superset codebase and are held to the same security standards and review processes as the rest of the application.
For external extensions, administrators are responsible for evaluating and verifying the security of any extensions they choose to install, just as they would when installing third-party NPM or PyPI packages. At this stage, all extensions run in the same context as the host application, without additional sandboxing. This means that external extensions can impact the security and performance of a Superset environment in the same way as any other installed dependency.
## Extension Sandboxing
We plan to introduce an optional sandboxed execution model for extensions in the future (as part of an additional SIP). Until then, administrators should exercise caution and follow best practices when selecting and deploying third-party extensions. A directory of community extensions is available in the [Community Extensions](./registry) page. Note that these extensions are not vetted by the Apache Superset project—administrators must evaluate each extension before installation.
Superset provides a tiered sandbox architecture for running extensions with varying levels of trust and isolation. Extensions can declare their trust level and permissions in their manifest, and Superset will load them in the appropriate sandbox:
- **Core (Tier 1)**: Trusted extensions run in the main context with full access
- **Iframe (Tier 2)**: Semi-trusted extensions run in browser-sandboxed iframes
- **WASM (Tier 3)**: Untrusted logic runs in WebAssembly sandboxes
For detailed information about the sandbox system, see [Extension Sandboxing](./sandbox).
## Trust Model
Administrators are responsible for evaluating and verifying the security of any extensions they choose to install. Superset's sandbox system provides defense-in-depth:
1. **Core extensions** require explicit trust configuration and optionally signature verification
2. **Iframe-sandboxed extensions** are isolated by the browser's same-origin policy
3. **WASM-sandboxed extensions** have no access to browser APIs
A directory of community extensions is available in the [Community Extensions](./registry) page. Note that these extensions are not vetted by the Apache Superset project—administrators must evaluate each extension before installation.
## Extension Signing
Extensions can be cryptographically signed to verify their authenticity and integrity. This is required for extensions that need `core` trust level in production environments with signature verification enabled.
- **Developers**: See [Extension Signing](./signing) to learn how to sign your extensions
- **Administrators**: See [Administrator Configuration](./admin-configuration) to configure trusted signers
## Administrator Configuration
Superset provides extensive configuration options for controlling extension trust levels, signature verification, and security policies. Key settings include:
- **Trusted extensions list**: Extensions allowed to run as `core`
- **Signature verification**: Require valid signatures for core trust
- **Default trust level**: Sandbox level for unlisted extensions
For complete configuration details, see [Administrator Configuration](./admin-configuration).
## Security Reporting
**Any performance or security vulnerabilities introduced by external extensions should be reported directly to the extension author, not as Superset vulnerabilities.**

View File

@@ -0,0 +1,236 @@
---
title: Extension Signing
sidebar_position: 11
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Extension Signing
Signing your extension allows administrators to verify its authenticity and integrity. Signed extensions can run as `core` trust level in production environments where signature verification is required.
## Why Sign Extensions?
- **Trust**: Administrators can verify your extension comes from a known source
- **Integrity**: Ensures the extension hasn't been modified since you signed it
- **Core Access**: Required for extensions needing `core` trust level in secured deployments
- **Distribution**: Makes your extension suitable for enterprise environments
## Generating Signing Keys
Generate a new Ed25519 keypair for signing your extensions:
```bash
superset-extensions generate-keys --output my-signing-key.pem
```
This creates two files:
| File | Purpose | Share? |
|------|---------|--------|
| `my-signing-key.pem` | Private key for signing | **Never share!** |
| `my-signing-key.pub` | Public key for verification | Share with administrators |
**Output example:**
```
✅ Private key: my-signing-key.pem
✅ Public key: my-signing-key.pub
Fingerprint: MCowBQYDK2Vw...
⚠️ Keep the private key secure! Only share the public key with administrators.
Usage:
Sign an extension: superset-extensions bundle --sign my-signing-key.pem
Share with admins: my-signing-key.pub
```
## Signing an Extension
### During Bundle
The easiest way to sign is during the bundle step:
```bash
superset-extensions bundle --sign my-signing-key.pem
```
This builds, signs the manifest, and creates the `.supx` bundle in one command.
**Output:**
```
✅ Full build completed in dist/
✅ Manifest signed
✅ Bundle created (signed): my-extension-1.0.0.supx
```
### Signing Existing Manifest
To sign an already-built manifest:
```bash
superset-extensions sign --key my-signing-key.pem --manifest dist/manifest.json
```
This creates `dist/manifest.sig` containing the signature.
## Bundle Structure
A signed extension bundle contains:
```
my-extension-1.0.0.supx
├── manifest.json # Extension manifest
├── manifest.sig # Ed25519 signature (base64-encoded)
├── frontend/dist/ # Frontend assets
└── backend/src/ # Backend code (if applicable)
```
The signature file (`manifest.sig`) contains a base64-encoded Ed25519 signature of the manifest content.
## Distributing Your Public Key
Share your public key (`.pub` file) with administrators who want to trust your extensions:
1. **Direct sharing**: Send the `.pub` file via secure channels
2. **Documentation**: Include in your extension's README
3. **Website**: Host on your organization's website with HTTPS
Administrators will add your public key to their `EXTENSIONS_TRUST_CONFIG.trusted_signers` configuration.
### Key Fingerprint
The fingerprint helps administrators verify they have the correct key. Include it in your documentation:
```
Public Key Fingerprint: MCowBQYDK2Vw...
```
Administrators should verify this fingerprint matches when adding your key.
## Security Best Practices
### Protect Your Private Key
- **Never commit** private keys to version control
- **Use secure storage** like hardware security modules (HSM) for production keys
- **Limit access** to the private key to authorized personnel only
- **Back up securely** in case of key loss
### Key Rotation
Consider rotating keys periodically:
1. Generate a new keypair
2. Notify administrators of the new public key
3. Sign new releases with the new key
4. Keep the old key available for verifying existing releases
### Multiple Keys
For organizations, consider separate keys for:
- Development/testing releases
- Production releases
- Different product teams
## Requesting Core Trust
If your extension needs `core` trust level:
1. **Sign your extension** using the process above
2. **Document your public key** with fingerprint
3. **Explain why core is needed** in your extension documentation
4. **Provide your public key** to administrators
Administrators will then:
1. Add your public key to `trusted_signers`
2. Enable `require_core_signatures: True`
3. Your signed extension can now run as `core`
## Verification Process
When Superset loads your extension:
1. Reads `manifest.json` and `manifest.sig` from the bundle
2. Checks if the extension requests `core` trust level
3. If `require_core_signatures` is enabled, verifies the signature
4. Checks the signature against all keys in `trusted_signers`
5. If verification passes, grants the requested trust level
6. If verification fails, downgrades to `default_trust_level`
## Troubleshooting
### "Signature verification failed"
- Ensure you're using the matching private key for the public key given to admins
- Verify the manifest wasn't modified after signing
- Check that the `.sig` file was included in the bundle
### "Private key must be Ed25519"
- The signing system only supports Ed25519 keys
- Generate a new key using `superset-extensions generate-keys`
### Administrator Reports Invalid Signature
- Verify the public key file wasn't corrupted during transfer
- Confirm the fingerprint matches between your key and theirs
- Re-sign the extension and redistribute
## Technical Details
### Signature Algorithm
Extensions use **Ed25519** signatures:
- Fast signature generation and verification
- Small signature size (64 bytes)
- Strong security guarantees
- Deterministic signatures (same input always produces same output)
### Signature Format
The `manifest.sig` file contains:
```
<base64-encoded Ed25519 signature>
```
The signature is computed over the raw bytes of `manifest.json`.
### Key Format
Keys are stored in PEM format:
**Private key:**
```
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEI...
-----END PRIVATE KEY-----
```
**Public key:**
```
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA...
-----END PUBLIC KEY-----
```