provisioning/docs/book/user/PLUGIN_INTEGRATION_GUIDE.html
Jesús Pérez 6a59d34bb1
chore: update provisioning configuration and documentation
Update configuration files, templates, and internal documentation
for the provisioning repository system.

Configuration Updates:
- KMS configuration modernization
- Plugin system settings
- Service port mappings
- Test cluster topologies
- Installation configuration examples
- VM configuration defaults
- Cedar authorization policies

Documentation Updates:
- Library module documentation
- Extension API guides
- AI system documentation
- Service management guides
- Test environment setup
- Plugin usage guides
- Validator configuration documentation

All changes are backward compatible.
2025-12-11 21:50:42 +00:00

2026 lines
82 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="ayu sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Plugin Integration Guide - Provisioning Platform Documentation</title>
<!-- Custom HTML head -->
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "ayu";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('ayu')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Provisioning Platform Documentation</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/user/PLUGIN_INTEGRATION_GUIDE.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="nushell-plugin-integration-guide"><a class="header" href="#nushell-plugin-integration-guide">Nushell Plugin Integration Guide</a></h1>
<p><strong>Version</strong>: 1.0.0
<strong>Last Updated</strong>: 2025-10-09
<strong>Target Audience</strong>: Developers, DevOps Engineers, System Administrators</p>
<hr />
<h2 id="table-of-contents"><a class="header" href="#table-of-contents">Table of Contents</a></h2>
<ol>
<li><a href="#overview">Overview</a></li>
<li><a href="#why-native-plugins">Why Native Plugins?</a></li>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#quick-start-5-minutes">Quick Start (5 Minutes)</a></li>
<li><a href="#authentication-plugin-nu_plugin_auth">Authentication Plugin (nu_plugin_auth)</a></li>
<li><a href="#kms-plugin-nu_plugin_kms">KMS Plugin (nu_plugin_kms)</a></li>
<li><a href="#orchestrator-plugin-nu_plugin_orchestrator">Orchestrator Plugin (nu_plugin_orchestrator)</a></li>
<li><a href="#integration-examples">Integration Examples</a></li>
<li><a href="#best-practices">Best Practices</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
<li><a href="#migration-guide">Migration Guide</a></li>
<li><a href="#advanced-configuration">Advanced Configuration</a></li>
<li><a href="#security-considerations">Security Considerations</a></li>
<li><a href="#faq">FAQ</a></li>
</ol>
<hr />
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>The Provisioning Platform provides three native Nushell plugins that dramatically improve performance and user experience compared to traditional HTTP API calls:</p>
<div class="table-wrapper"><table><thead><tr><th>Plugin</th><th>Purpose</th><th>Performance Gain</th></tr></thead><tbody>
<tr><td><strong>nu_plugin_auth</strong></td><td>JWT authentication, MFA, session management</td><td>20% faster</td></tr>
<tr><td><strong>nu_plugin_kms</strong></td><td>Encryption/decryption with multiple KMS backends</td><td><strong>10x faster</strong></td></tr>
<tr><td><strong>nu_plugin_orchestrator</strong></td><td>Orchestrator operations without HTTP overhead</td><td><strong>50x faster</strong></td></tr>
</tbody></table>
</div>
<h3 id="architecture-benefits"><a class="header" href="#architecture-benefits">Architecture Benefits</a></h3>
<pre><code>Traditional HTTP Flow:
User Command → HTTP Request → Network → Server Processing → Response → Parse JSON
Total: ~50-100ms per operation
Plugin Flow:
User Command → Direct Rust Function Call → Return Nushell Data Structure
Total: ~1-10ms per operation
</code></pre>
<h3 id="key-features"><a class="header" href="#key-features">Key Features</a></h3>
<p><strong>Performance</strong>: 10-50x faster than HTTP API
<strong>Type Safety</strong>: Full Nushell type system integration
<strong>Pipeline Support</strong>: Native Nushell data structures
<strong>Offline Capability</strong>: KMS and orchestrator work without network
<strong>OS Integration</strong>: Native keyring for secure token storage
<strong>Graceful Fallback</strong>: HTTP still available if plugins not installed</p>
<hr />
<h2 id="why-native-plugins"><a class="header" href="#why-native-plugins">Why Native Plugins?</a></h2>
<h3 id="performance-comparison"><a class="header" href="#performance-comparison">Performance Comparison</a></h3>
<p>Real-world benchmarks from production workload:</p>
<div class="table-wrapper"><table><thead><tr><th>Operation</th><th>HTTP API</th><th>Plugin</th><th>Improvement</th><th>Speedup</th></tr></thead><tbody>
<tr><td><strong>KMS Encrypt (RustyVault)</strong></td><td>~50ms</td><td>~5ms</td><td>-45ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>KMS Decrypt (RustyVault)</strong></td><td>~50ms</td><td>~5ms</td><td>-45ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>KMS Encrypt (Age)</strong></td><td>~30ms</td><td>~3ms</td><td>-27ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>KMS Decrypt (Age)</strong></td><td>~30ms</td><td>~3ms</td><td>-27ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>Orchestrator Status</strong></td><td>~30ms</td><td>~1ms</td><td>-29ms</td><td><strong>30x</strong></td></tr>
<tr><td><strong>Orchestrator Tasks List</strong></td><td>~50ms</td><td>~5ms</td><td>-45ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>Orchestrator Validate</strong></td><td>~100ms</td><td>~10ms</td><td>-90ms</td><td><strong>10x</strong></td></tr>
<tr><td><strong>Auth Login</strong></td><td>~100ms</td><td>~80ms</td><td>-20ms</td><td>1.25x</td></tr>
<tr><td><strong>Auth Verify</strong></td><td>~50ms</td><td>~10ms</td><td>-40ms</td><td><strong>5x</strong></td></tr>
<tr><td><strong>Auth MFA Verify</strong></td><td>~80ms</td><td>~60ms</td><td>-20ms</td><td>1.3x</td></tr>
</tbody></table>
</div>
<h3 id="use-case-batch-processing"><a class="header" href="#use-case-batch-processing">Use Case: Batch Processing</a></h3>
<p><strong>Scenario</strong>: Encrypt 100 configuration files</p>
<pre><code class="language-nushell"># HTTP API approach
ls configs/*.yaml | each { |file|
http post http://localhost:9998/encrypt { data: (open $file) }
} | save encrypted/
# Total time: ~5 seconds (50ms × 100)
# Plugin approach
ls configs/*.yaml | each { |file|
kms encrypt (open $file) --backend rustyvault
} | save encrypted/
# Total time: ~0.5 seconds (5ms × 100)
# Result: 10x faster
</code></pre>
<h3 id="developer-experience-benefits"><a class="header" href="#developer-experience-benefits">Developer Experience Benefits</a></h3>
<p><strong>1. Native Nushell Integration</strong></p>
<pre><code class="language-nushell"># HTTP: Parse JSON, check status codes
let result = http post http://localhost:9998/encrypt { data: "secret" }
if $result.status == "success" {
$result.encrypted
} else {
error make { msg: $result.error }
}
# Plugin: Direct return values
kms encrypt "secret"
# Returns encrypted string directly, errors use Nushell's error system
</code></pre>
<p><strong>2. Pipeline Friendly</strong></p>
<pre><code class="language-nushell"># HTTP: Requires wrapping, JSON parsing
["secret1", "secret2"] | each { |s|
(http post http://localhost:9998/encrypt { data: $s }).encrypted
}
# Plugin: Natural pipeline flow
["secret1", "secret2"] | each { |s| kms encrypt $s }
</code></pre>
<p><strong>3. Tab Completion</strong></p>
<pre><code class="language-nushell"># All plugin commands have full tab completion
kms &lt;TAB&gt;
# → encrypt, decrypt, generate-key, status, backends
kms encrypt --&lt;TAB&gt;
# → --backend, --key, --context
</code></pre>
<hr />
<h2 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h2>
<h3 id="required-software"><a class="header" href="#required-software">Required Software</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Software</th><th>Minimum Version</th><th>Purpose</th></tr></thead><tbody>
<tr><td><strong>Nushell</strong></td><td>0.107.1</td><td>Shell and plugin runtime</td></tr>
<tr><td><strong>Rust</strong></td><td>1.75+</td><td>Building plugins from source</td></tr>
<tr><td><strong>Cargo</strong></td><td>(included with Rust)</td><td>Build tool</td></tr>
</tbody></table>
</div>
<h3 id="optional-dependencies"><a class="header" href="#optional-dependencies">Optional Dependencies</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Software</th><th>Purpose</th><th>Platform</th></tr></thead><tbody>
<tr><td><strong>gnome-keyring</strong></td><td>Secure token storage</td><td>Linux</td></tr>
<tr><td><strong>kwallet</strong></td><td>Secure token storage</td><td>Linux (KDE)</td></tr>
<tr><td><strong>age</strong></td><td>Age encryption backend</td><td>All</td></tr>
<tr><td><strong>RustyVault</strong></td><td>High-performance KMS</td><td>All</td></tr>
</tbody></table>
</div>
<h3 id="platform-support"><a class="header" href="#platform-support">Platform Support</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Platform</th><th>Status</th><th>Notes</th></tr></thead><tbody>
<tr><td><strong>macOS</strong></td><td>✅ Full</td><td>Keychain integration</td></tr>
<tr><td><strong>Linux</strong></td><td>✅ Full</td><td>Requires keyring service</td></tr>
<tr><td><strong>Windows</strong></td><td>✅ Full</td><td>Credential Manager integration</td></tr>
<tr><td><strong>FreeBSD</strong></td><td>⚠️ Partial</td><td>No keyring integration</td></tr>
</tbody></table>
</div>
<hr />
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
<h3 id="step-1-clone-or-navigate-to-plugin-directory"><a class="header" href="#step-1-clone-or-navigate-to-plugin-directory">Step 1: Clone or Navigate to Plugin Directory</a></h3>
<pre><code class="language-bash">cd /Users/Akasha/project-provisioning/provisioning/core/plugins/nushell-plugins
</code></pre>
<h3 id="step-2-build-all-plugins"><a class="header" href="#step-2-build-all-plugins">Step 2: Build All Plugins</a></h3>
<pre><code class="language-bash"># Build in release mode (optimized for performance)
cargo build --release --all
# Or build individually
cargo build --release -p nu_plugin_auth
cargo build --release -p nu_plugin_kms
cargo build --release -p nu_plugin_orchestrator
</code></pre>
<p><strong>Expected output:</strong></p>
<pre><code> Compiling nu_plugin_auth v0.1.0
Compiling nu_plugin_kms v0.1.0
Compiling nu_plugin_orchestrator v0.1.0
Finished release [optimized] target(s) in 2m 15s
</code></pre>
<h3 id="step-3-register-plugins-with-nushell"><a class="header" href="#step-3-register-plugins-with-nushell">Step 3: Register Plugins with Nushell</a></h3>
<pre><code class="language-bash"># Register all three plugins
plugin add target/release/nu_plugin_auth
plugin add target/release/nu_plugin_kms
plugin add target/release/nu_plugin_orchestrator
# On macOS, full paths:
plugin add $PWD/target/release/nu_plugin_auth
plugin add $PWD/target/release/nu_plugin_kms
plugin add $PWD/target/release/nu_plugin_orchestrator
</code></pre>
<h3 id="step-4-verify-installation"><a class="header" href="#step-4-verify-installation">Step 4: Verify Installation</a></h3>
<pre><code class="language-bash"># List registered plugins
plugin list | where name =~ "auth|kms|orch"
# Test each plugin
auth --help
kms --help
orch --help
</code></pre>
<p><strong>Expected output:</strong></p>
<pre><code>╭───┬─────────────────────────┬─────────┬───────────────────────────────────╮
│ # │ name │ version │ filename │
├───┼─────────────────────────┼─────────┼───────────────────────────────────┤
│ 0 │ nu_plugin_auth │ 0.1.0 │ .../nu_plugin_auth │
│ 1 │ nu_plugin_kms │ 0.1.0 │ .../nu_plugin_kms │
│ 2 │ nu_plugin_orchestrator │ 0.1.0 │ .../nu_plugin_orchestrator │
╰───┴─────────────────────────┴─────────┴───────────────────────────────────╯
</code></pre>
<h3 id="step-5-configure-environment-optional"><a class="header" href="#step-5-configure-environment-optional">Step 5: Configure Environment (Optional)</a></h3>
<pre><code class="language-bash"># Add to ~/.config/nushell/env.nu
$env.RUSTYVAULT_ADDR = "http://localhost:8200"
$env.RUSTYVAULT_TOKEN = "your-vault-token"
$env.CONTROL_CENTER_URL = "http://localhost:3000"
$env.ORCHESTRATOR_DATA_DIR = "/opt/orchestrator/data"
</code></pre>
<hr />
<h2 id="quick-start-5-minutes"><a class="header" href="#quick-start-5-minutes">Quick Start (5 Minutes)</a></h2>
<h3 id="1-authentication-workflow"><a class="header" href="#1-authentication-workflow">1. Authentication Workflow</a></h3>
<pre><code class="language-nushell"># Login (password prompted securely)
auth login admin
# ✓ Login successful
# User: admin
# Role: Admin
# Expires: 2025-10-09T14:30:00Z
# Verify session
auth verify
# {
# "active": true,
# "user": "admin",
# "role": "Admin",
# "expires_at": "2025-10-09T14:30:00Z"
# }
# Enroll in MFA (optional but recommended)
auth mfa enroll totp
# QR code displayed, save backup codes
# Verify MFA
auth mfa verify --code 123456
# ✓ MFA verification successful
# Logout
auth logout
# ✓ Logged out successfully
</code></pre>
<h3 id="2-kms-operations"><a class="header" href="#2-kms-operations">2. KMS Operations</a></h3>
<pre><code class="language-nushell"># Encrypt data
kms encrypt "my secret data"
# vault:v1:8GawgGuP...
# Decrypt data
kms decrypt "vault:v1:8GawgGuP..."
# my secret data
# Check available backends
kms status
# {
# "backend": "rustyvault",
# "status": "healthy",
# "url": "http://localhost:8200"
# }
# Encrypt with specific backend
kms encrypt "data" --backend age --key age1xxxxxxx
</code></pre>
<h3 id="3-orchestrator-operations"><a class="header" href="#3-orchestrator-operations">3. Orchestrator Operations</a></h3>
<pre><code class="language-nushell"># Check orchestrator status (no HTTP call)
orch status
# {
# "active_tasks": 5,
# "completed_tasks": 120,
# "health": "healthy"
# }
# Validate workflow
orch validate workflows/deploy.k
# {
# "valid": true,
# "workflow": { "name": "deploy_k8s", "operations": 5 }
# }
# List running tasks
orch tasks --status running
# [ { "task_id": "task_123", "name": "deploy_k8s", "progress": 45 } ]
</code></pre>
<h3 id="4-combined-workflow"><a class="header" href="#4-combined-workflow">4. Combined Workflow</a></h3>
<pre><code class="language-nushell"># Complete authenticated deployment pipeline
auth login admin
| if $in.success { auth verify }
| if $in.active {
orch validate workflows/production.k
| if $in.valid {
kms encrypt (open secrets.yaml | to json)
| save production-secrets.enc
}
}
# ✓ Pipeline completed successfully
</code></pre>
<hr />
<h2 id="authentication-plugin-nu_plugin_auth"><a class="header" href="#authentication-plugin-nu_plugin_auth">Authentication Plugin (nu_plugin_auth)</a></h2>
<p>The authentication plugin manages JWT-based authentication, MFA enrollment/verification, and session management with OS-native keyring integration.</p>
<h3 id="available-commands"><a class="header" href="#available-commands">Available Commands</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Command</th><th>Purpose</th><th>Example</th></tr></thead><tbody>
<tr><td><code>auth login</code></td><td>Login and store JWT</td><td><code>auth login admin</code></td></tr>
<tr><td><code>auth logout</code></td><td>Logout and clear tokens</td><td><code>auth logout</code></td></tr>
<tr><td><code>auth verify</code></td><td>Verify current session</td><td><code>auth verify</code></td></tr>
<tr><td><code>auth sessions</code></td><td>List active sessions</td><td><code>auth sessions</code></td></tr>
<tr><td><code>auth mfa enroll</code></td><td>Enroll in MFA</td><td><code>auth mfa enroll totp</code></td></tr>
<tr><td><code>auth mfa verify</code></td><td>Verify MFA code</td><td><code>auth mfa verify --code 123456</code></td></tr>
</tbody></table>
</div>
<h3 id="command-reference"><a class="header" href="#command-reference">Command Reference</a></h3>
<h4 id="auth-login-username-password"><a class="header" href="#auth-login-username-password"><code>auth login &lt;username&gt; [password]</code></a></h4>
<p>Login to provisioning platform and store JWT tokens securely in OS keyring.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>username</code> (required): Username for authentication</li>
<li><code>password</code> (optional): Password (prompted if not provided)</li>
</ul>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--url &lt;url&gt;</code>: Control center URL (default: <code>http://localhost:3000</code>)</li>
<li><code>--password &lt;password&gt;</code>: Password (alternative to positional argument)</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Interactive password prompt (recommended)
auth login admin
# Password: ••••••••
# ✓ Login successful
# User: admin
# Role: Admin
# Expires: 2025-10-09T14:30:00Z
# Password in command (not recommended for production)
auth login admin mypassword
# Custom control center URL
auth login admin --url https://control-center.example.com
# Pipeline usage
let creds = { username: "admin", password: (input --suppress-output "Password: ") }
auth login $creds.username $creds.password
</code></pre>
<p><strong>Token Storage Locations:</strong></p>
<ul>
<li><strong>macOS</strong>: Keychain Access (<code>login</code> keychain)</li>
<li><strong>Linux</strong>: Secret Service API (gnome-keyring, kwallet)</li>
<li><strong>Windows</strong>: Windows Credential Manager</li>
</ul>
<p><strong>Security Notes:</strong></p>
<ul>
<li>Tokens encrypted at rest by OS</li>
<li>Requires user authentication to access (macOS Touch ID, Linux password)</li>
<li>Never stored in plain text files</li>
</ul>
<h4 id="auth-logout"><a class="header" href="#auth-logout"><code>auth logout</code></a></h4>
<p>Logout from current session and remove stored tokens from keyring.</p>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Simple logout
auth logout
# ✓ Logged out successfully
# Conditional logout
if (auth verify | get active) {
auth logout
echo "Session terminated"
}
# Logout all sessions (requires admin role)
auth sessions | each { |sess|
auth logout --session-id $sess.session_id
}
</code></pre>
<h4 id="auth-verify"><a class="header" href="#auth-verify"><code>auth verify</code></a></h4>
<p>Verify current session status and check token validity.</p>
<p><strong>Returns:</strong></p>
<ul>
<li><code>active</code> (bool): Whether session is active</li>
<li><code>user</code> (string): Username</li>
<li><code>role</code> (string): User role</li>
<li><code>expires_at</code> (datetime): Token expiration</li>
<li><code>mfa_verified</code> (bool): MFA verification status</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Check if logged in
auth verify
# {
# "active": true,
# "user": "admin",
# "role": "Admin",
# "expires_at": "2025-10-09T14:30:00Z",
# "mfa_verified": true
# }
# Pipeline usage
if (auth verify | get active) {
echo "✓ Authenticated"
} else {
auth login admin
}
# Check expiration
let session = auth verify
if ($session.expires_at | into datetime) &lt; (date now) {
echo "Session expired, re-authenticating..."
auth login $session.user
}
</code></pre>
<h4 id="auth-sessions"><a class="header" href="#auth-sessions"><code>auth sessions</code></a></h4>
<p>List all active sessions for current user.</p>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># List all sessions
auth sessions
# [
# {
# "session_id": "sess_abc123",
# "created_at": "2025-10-09T12:00:00Z",
# "expires_at": "2025-10-09T14:30:00Z",
# "ip_address": "192.168.1.100",
# "user_agent": "nushell/0.107.1"
# }
# ]
# Filter recent sessions (last hour)
auth sessions | where created_at &gt; ((date now) - 1hr)
# Find sessions by IP
auth sessions | where ip_address =~ "192.168"
# Count active sessions
auth sessions | length
</code></pre>
<h4 id="auth-mfa-enroll-type"><a class="header" href="#auth-mfa-enroll-type"><code>auth mfa enroll &lt;type&gt;</code></a></h4>
<p>Enroll in Multi-Factor Authentication (TOTP or WebAuthn).</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>type</code> (required): MFA type (<code>totp</code> or <code>webauthn</code>)</li>
</ul>
<p><strong>TOTP Enrollment:</strong></p>
<pre><code class="language-nushell">auth mfa enroll totp
# ✓ TOTP enrollment initiated
#
# Scan this QR code with your authenticator app:
#
# ████ ▄▄▄▄▄ █▀█ █▄▀▀▀▄ ▄▄▄▄▄ ████
# ████ █ █ █▀▀▀█▄ ▀▀█ █ █ ████
# ████ █▄▄▄█ █ █▀▄ ▀▄▄█ █▄▄▄█ ████
# (QR code continues...)
#
# Or enter manually:
# Secret: JBSWY3DPEHPK3PXP
# URL: otpauth://totp/Provisioning:admin?secret=JBSWY3DPEHPK3PXP&amp;issuer=Provisioning
#
# Backup codes (save securely):
# 1. ABCD-EFGH-IJKL
# 2. MNOP-QRST-UVWX
# 3. YZAB-CDEF-GHIJ
# (8 more codes...)
</code></pre>
<p><strong>WebAuthn Enrollment:</strong></p>
<pre><code class="language-nushell">auth mfa enroll webauthn
# ✓ WebAuthn enrollment initiated
#
# Insert your security key and touch the button...
# (waiting for device interaction)
#
# ✓ Security key registered successfully
# Device: YubiKey 5 NFC
# Created: 2025-10-09T13:00:00Z
</code></pre>
<p><strong>Supported Authenticator Apps:</strong></p>
<ul>
<li>Google Authenticator</li>
<li>Microsoft Authenticator</li>
<li>Authy</li>
<li>1Password</li>
<li>Bitwarden</li>
</ul>
<p><strong>Supported Hardware Keys:</strong></p>
<ul>
<li>YubiKey (all models)</li>
<li>Titan Security Key</li>
<li>Feitian ePass</li>
<li>macOS Touch ID</li>
<li>Windows Hello</li>
</ul>
<h4 id="auth-mfa-verify---code-code"><a class="header" href="#auth-mfa-verify---code-code"><code>auth mfa verify --code &lt;code&gt;</code></a></h4>
<p>Verify MFA code (TOTP or backup code).</p>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--code &lt;code&gt;</code> (required): 6-digit TOTP code or backup code</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Verify TOTP code
auth mfa verify --code 123456
# ✓ MFA verification successful
# Verify backup code
auth mfa verify --code ABCD-EFGH-IJKL
# ✓ MFA verification successful (backup code used)
# Warning: This backup code cannot be used again
# Pipeline usage
let code = input "MFA code: "
auth mfa verify --code $code
</code></pre>
<p><strong>Error Cases:</strong></p>
<pre><code class="language-nushell"># Invalid code
auth mfa verify --code 999999
# Error: Invalid MFA code
# → Verify time synchronization on your device
# Rate limited
auth mfa verify --code 123456
# Error: Too many failed attempts
# → Wait 5 minutes before trying again
# No MFA enrolled
auth mfa verify --code 123456
# Error: MFA not enrolled for this user
# → Run: auth mfa enroll totp
</code></pre>
<h3 id="environment-variables"><a class="header" href="#environment-variables">Environment Variables</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Variable</th><th>Description</th><th>Default</th></tr></thead><tbody>
<tr><td><code>USER</code></td><td>Default username</td><td>Current OS user</td></tr>
<tr><td><code>CONTROL_CENTER_URL</code></td><td>Control center URL</td><td><code>http://localhost:3000</code></td></tr>
<tr><td><code>AUTH_KEYRING_SERVICE</code></td><td>Keyring service name</td><td><code>provisioning-auth</code></td></tr>
</tbody></table>
</div>
<h3 id="troubleshooting-authentication"><a class="header" href="#troubleshooting-authentication">Troubleshooting Authentication</a></h3>
<p><strong>“No active session”</strong></p>
<pre><code class="language-nushell"># Solution: Login first
auth login &lt;username&gt;
</code></pre>
<p><strong>“Keyring error” (macOS)</strong></p>
<pre><code class="language-bash"># Check Keychain Access permissions
# System Preferences → Security &amp; Privacy → Privacy → Full Disk Access
# Add: /Applications/Nushell.app (or /usr/local/bin/nu)
# Or grant access manually
security unlock-keychain ~/Library/Keychains/login.keychain-db
</code></pre>
<p><strong>“Keyring error” (Linux)</strong></p>
<pre><code class="language-bash"># Install keyring service
sudo apt install gnome-keyring # Ubuntu/Debian
sudo dnf install gnome-keyring # Fedora
sudo pacman -S gnome-keyring # Arch
# Or use KWallet (KDE)
sudo apt install kwalletmanager
# Start keyring daemon
eval $(gnome-keyring-daemon --start)
export $(gnome-keyring-daemon --start --components=secrets)
</code></pre>
<p><strong>“MFA verification failed”</strong></p>
<pre><code class="language-nushell"># Check time synchronization (TOTP requires accurate time)
# macOS:
sudo sntp -sS time.apple.com
# Linux:
sudo ntpdate pool.ntp.org
# Or
sudo systemctl restart systemd-timesyncd
# Use backup code if TOTP not working
auth mfa verify --code ABCD-EFGH-IJKL
</code></pre>
<hr />
<h2 id="kms-plugin-nu_plugin_kms"><a class="header" href="#kms-plugin-nu_plugin_kms">KMS Plugin (nu_plugin_kms)</a></h2>
<p>The KMS plugin provides high-performance encryption and decryption using multiple backend providers.</p>
<h3 id="supported-backends"><a class="header" href="#supported-backends">Supported Backends</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Backend</th><th>Performance</th><th>Use Case</th><th>Setup Complexity</th></tr></thead><tbody>
<tr><td><strong>rustyvault</strong></td><td>⚡ Very Fast (~5ms)</td><td>Production KMS</td><td>Medium</td></tr>
<tr><td><strong>age</strong></td><td>⚡ Very Fast (~3ms)</td><td>Local development</td><td>Low</td></tr>
<tr><td><strong>cosmian</strong></td><td>🐢 Moderate (~30ms)</td><td>Cloud KMS</td><td>Medium</td></tr>
<tr><td><strong>aws</strong></td><td>🐢 Moderate (~50ms)</td><td>AWS environments</td><td>Medium</td></tr>
<tr><td><strong>vault</strong></td><td>🐢 Moderate (~40ms)</td><td>Enterprise KMS</td><td>High</td></tr>
</tbody></table>
</div>
<h3 id="backend-selection-guide"><a class="header" href="#backend-selection-guide">Backend Selection Guide</a></h3>
<p><strong>Choose <code>rustyvault</code> when:</strong></p>
<ul>
<li>✅ Running in production with high throughput requirements</li>
<li>✅ Need ~5ms encryption/decryption latency</li>
<li>✅ Have RustyVault server deployed</li>
<li>✅ Require key rotation and versioning</li>
</ul>
<p><strong>Choose <code>age</code> when:</strong></p>
<ul>
<li>✅ Developing locally without external dependencies</li>
<li>✅ Need simple file encryption</li>
<li>✅ Want ~3ms latency</li>
<li>❌ Dont need centralized key management</li>
</ul>
<p><strong>Choose <code>cosmian</code> when:</strong></p>
<ul>
<li>✅ Using Cosmian KMS service</li>
<li>✅ Need cloud-based key management</li>
<li>⚠️ Can accept ~30ms latency</li>
</ul>
<p><strong>Choose <code>aws</code> when:</strong></p>
<ul>
<li>✅ Deployed on AWS infrastructure</li>
<li>✅ Using AWS IAM for access control</li>
<li>✅ Need AWS KMS integration</li>
<li>⚠️ Can accept ~50ms latency</li>
</ul>
<p><strong>Choose <code>vault</code> when:</strong></p>
<ul>
<li>✅ Using HashiCorp Vault enterprise</li>
<li>✅ Need advanced policy management</li>
<li>✅ Require audit trails</li>
<li>⚠️ Can accept ~40ms latency</li>
</ul>
<h3 id="available-commands-1"><a class="header" href="#available-commands-1">Available Commands</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Command</th><th>Purpose</th><th>Example</th></tr></thead><tbody>
<tr><td><code>kms encrypt</code></td><td>Encrypt data</td><td><code>kms encrypt "secret"</code></td></tr>
<tr><td><code>kms decrypt</code></td><td>Decrypt data</td><td><code>kms decrypt "vault:v1:..."</code></td></tr>
<tr><td><code>kms generate-key</code></td><td>Generate DEK</td><td><code>kms generate-key --spec AES256</code></td></tr>
<tr><td><code>kms status</code></td><td>Backend status</td><td><code>kms status</code></td></tr>
</tbody></table>
</div>
<h3 id="command-reference-1"><a class="header" href="#command-reference-1">Command Reference</a></h3>
<h4 id="kms-encrypt-data---backend-backend"><a class="header" href="#kms-encrypt-data---backend-backend"><code>kms encrypt &lt;data&gt; [--backend &lt;backend&gt;]</code></a></h4>
<p>Encrypt data using specified KMS backend.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>data</code> (required): Data to encrypt (string or binary)</li>
</ul>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--backend &lt;backend&gt;</code>: KMS backend (<code>rustyvault</code>, <code>age</code>, <code>cosmian</code>, <code>aws</code>, <code>vault</code>)</li>
<li><code>--key &lt;key&gt;</code>: Key ID or recipient (backend-specific)</li>
<li><code>--context &lt;context&gt;</code>: Additional authenticated data (AAD)</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Auto-detect backend from environment
kms encrypt "secret configuration data"
# vault:v1:8GawgGuP+emDKX5q...
# RustyVault backend
kms encrypt "data" --backend rustyvault --key provisioning-main
# vault:v1:abc123def456...
# Age backend (local encryption)
kms encrypt "data" --backend age --key age1xxxxxxxxx
# -----BEGIN AGE ENCRYPTED FILE-----
# YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+...
# -----END AGE ENCRYPTED FILE-----
# AWS KMS
kms encrypt "data" --backend aws --key alias/provisioning
# AQICAHhwbGF0Zm9ybS1wcm92aXNpb25p...
# With context (AAD for additional security)
kms encrypt "data" --backend rustyvault --key provisioning-main --context "user=admin,env=production"
# Encrypt file contents
kms encrypt (open config.yaml) --backend rustyvault | save config.yaml.enc
# Encrypt multiple files
ls configs/*.yaml | each { |file|
kms encrypt (open $file.name) --backend age
| save $"encrypted/($file.name).enc"
}
</code></pre>
<p><strong>Output Formats:</strong></p>
<ul>
<li><strong>RustyVault</strong>: <code>vault:v1:base64_ciphertext</code></li>
<li><strong>Age</strong>: <code>-----BEGIN AGE ENCRYPTED FILE-----...-----END AGE ENCRYPTED FILE-----</code></li>
<li><strong>AWS</strong>: <code>base64_aws_kms_ciphertext</code></li>
<li><strong>Cosmian</strong>: <code>cosmian:v1:base64_ciphertext</code></li>
</ul>
<h4 id="kms-decrypt-encrypted---backend-backend"><a class="header" href="#kms-decrypt-encrypted---backend-backend"><code>kms decrypt &lt;encrypted&gt; [--backend &lt;backend&gt;]</code></a></h4>
<p>Decrypt KMS-encrypted data.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>encrypted</code> (required): Encrypted data (detects format automatically)</li>
</ul>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--backend &lt;backend&gt;</code>: KMS backend (auto-detected from format if not specified)</li>
<li><code>--context &lt;context&gt;</code>: Additional authenticated data (must match encryption context)</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Auto-detect backend from format
kms decrypt "vault:v1:8GawgGuP..."
# secret configuration data
# Explicit backend
kms decrypt "vault:v1:abc123..." --backend rustyvault
# Age decryption
kms decrypt "-----BEGIN AGE ENCRYPTED FILE-----..."
# (uses AGE_IDENTITY from environment)
# With context (must match encryption context)
kms decrypt "vault:v1:abc123..." --context "user=admin,env=production"
# Decrypt file
kms decrypt (open config.yaml.enc) | save config.yaml
# Decrypt multiple files
ls encrypted/*.enc | each { |file|
kms decrypt (open $file.name)
| save $"configs/(($file.name | path basename) | str replace '.enc' '')"
}
# Pipeline decryption
open secrets.json
| get database_password_enc
| kms decrypt
| str trim
| psql --dbname mydb --password
</code></pre>
<p><strong>Error Cases:</strong></p>
<pre><code class="language-nushell"># Invalid ciphertext
kms decrypt "invalid_data"
# Error: Invalid ciphertext format
# → Verify data was encrypted with KMS
# Context mismatch
kms decrypt "vault:v1:abc..." --context "wrong=context"
# Error: Authentication failed (AAD mismatch)
# → Verify encryption context matches
# Backend unavailable
kms decrypt "vault:v1:abc..."
# Error: Failed to connect to RustyVault at http://localhost:8200
# → Check RustyVault is running: curl http://localhost:8200/v1/sys/health
</code></pre>
<h4 id="kms-generate-key---spec-spec"><a class="header" href="#kms-generate-key---spec-spec"><code>kms generate-key [--spec &lt;spec&gt;]</code></a></h4>
<p>Generate data encryption key (DEK) using KMS envelope encryption.</p>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--spec &lt;spec&gt;</code>: Key specification (<code>AES128</code> or <code>AES256</code>, default: <code>AES256</code>)</li>
<li><code>--backend &lt;backend&gt;</code>: KMS backend</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Generate AES-256 key
kms generate-key
# {
# "plaintext": "rKz3N8xPq...", # base64-encoded key
# "ciphertext": "vault:v1:...", # encrypted DEK
# "spec": "AES256"
# }
# Generate AES-128 key
kms generate-key --spec AES128
# Use in envelope encryption pattern
let dek = kms generate-key
let encrypted_data = ($data | openssl enc -aes-256-cbc -K $dek.plaintext)
{
data: $encrypted_data,
encrypted_key: $dek.ciphertext
} | save secure_data.json
# Later, decrypt:
let envelope = open secure_data.json
let dek = kms decrypt $envelope.encrypted_key
$envelope.data | openssl enc -d -aes-256-cbc -K $dek
</code></pre>
<p><strong>Use Cases:</strong></p>
<ul>
<li>Envelope encryption (encrypt large data locally, protect DEK with KMS)</li>
<li>Database field encryption</li>
<li>File encryption with key wrapping</li>
</ul>
<h4 id="kms-status"><a class="header" href="#kms-status"><code>kms status</code></a></h4>
<p>Show KMS backend status, configuration, and health.</p>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Show current backend status
kms status
# {
# "backend": "rustyvault",
# "status": "healthy",
# "url": "http://localhost:8200",
# "mount_point": "transit",
# "version": "0.1.0",
# "latency_ms": 5
# }
# Check all configured backends
kms status --all
# [
# { "backend": "rustyvault", "status": "healthy", ... },
# { "backend": "age", "status": "available", ... },
# { "backend": "aws", "status": "unavailable", "error": "..." }
# ]
# Filter to specific backend
kms status | where backend == "rustyvault"
# Health check in automation
if (kms status | get status) == "healthy" {
echo "✓ KMS operational"
} else {
error make { msg: "KMS unhealthy" }
}
</code></pre>
<h3 id="backend-configuration"><a class="header" href="#backend-configuration">Backend Configuration</a></h3>
<h4 id="rustyvault-backend"><a class="header" href="#rustyvault-backend">RustyVault Backend</a></h4>
<pre><code class="language-bash"># Environment variables
export RUSTYVAULT_ADDR="http://localhost:8200"
export RUSTYVAULT_TOKEN="hvs.xxxxxxxxxxxxx"
export RUSTYVAULT_MOUNT="transit" # Transit engine mount point
export RUSTYVAULT_KEY="provisioning-main" # Default key name
</code></pre>
<pre><code class="language-nushell"># Usage
kms encrypt "data" --backend rustyvault --key provisioning-main
</code></pre>
<p><strong>Setup RustyVault:</strong></p>
<pre><code class="language-bash"># Start RustyVault
rustyvault server -dev
# Enable transit engine
rustyvault secrets enable transit
# Create encryption key
rustyvault write -f transit/keys/provisioning-main
</code></pre>
<h4 id="age-backend"><a class="header" href="#age-backend">Age Backend</a></h4>
<pre><code class="language-bash"># Generate Age keypair
age-keygen -o ~/.age/key.txt
# Environment variables
export AGE_IDENTITY="$HOME/.age/key.txt" # Private key
export AGE_RECIPIENT="age1xxxxxxxxx" # Public key (from key.txt)
</code></pre>
<pre><code class="language-nushell"># Usage
kms encrypt "data" --backend age
kms decrypt (open file.enc) --backend age
</code></pre>
<h4 id="aws-kms-backend"><a class="header" href="#aws-kms-backend">AWS KMS Backend</a></h4>
<pre><code class="language-bash"># AWS credentials
export AWS_REGION="us-east-1"
export AWS_ACCESS_KEY_ID="AKIAXXXXX"
export AWS_SECRET_ACCESS_KEY="xxxxx"
# KMS configuration
export AWS_KMS_KEY_ID="alias/provisioning"
</code></pre>
<pre><code class="language-nushell"># Usage
kms encrypt "data" --backend aws --key alias/provisioning
</code></pre>
<p><strong>Setup AWS KMS:</strong></p>
<pre><code class="language-bash"># Create KMS key
aws kms create-key --description "Provisioning Platform"
# Create alias
aws kms create-alias --alias-name alias/provisioning --target-key-id &lt;key-id&gt;
# Grant permissions
aws kms create-grant --key-id &lt;key-id&gt; --grantee-principal &lt;role-arn&gt; \
--operations Encrypt Decrypt GenerateDataKey
</code></pre>
<h4 id="cosmian-backend"><a class="header" href="#cosmian-backend">Cosmian Backend</a></h4>
<pre><code class="language-bash"># Cosmian KMS configuration
export KMS_HTTP_URL="http://localhost:9998"
export KMS_HTTP_BACKEND="cosmian"
export COSMIAN_API_KEY="your-api-key"
</code></pre>
<pre><code class="language-nushell"># Usage
kms encrypt "data" --backend cosmian
</code></pre>
<h4 id="vault-backend-hashicorp"><a class="header" href="#vault-backend-hashicorp">Vault Backend (HashiCorp)</a></h4>
<pre><code class="language-bash"># Vault configuration
export VAULT_ADDR="https://vault.example.com:8200"
export VAULT_TOKEN="hvs.xxxxxxxxxxxxx"
export VAULT_MOUNT="transit"
export VAULT_KEY="provisioning"
</code></pre>
<pre><code class="language-nushell"># Usage
kms encrypt "data" --backend vault --key provisioning
</code></pre>
<h3 id="performance-benchmarks"><a class="header" href="#performance-benchmarks">Performance Benchmarks</a></h3>
<p><strong>Test Setup:</strong></p>
<ul>
<li>Data size: 1KB</li>
<li>Iterations: 1000</li>
<li>Hardware: Apple M1, 16GB RAM</li>
<li>Network: localhost</li>
</ul>
<p><strong>Results:</strong></p>
<div class="table-wrapper"><table><thead><tr><th>Backend</th><th>Encrypt (avg)</th><th>Decrypt (avg)</th><th>Throughput (ops/sec)</th></tr></thead><tbody>
<tr><td>RustyVault</td><td>4.8ms</td><td>5.1ms</td><td>~200</td></tr>
<tr><td>Age</td><td>2.9ms</td><td>3.2ms</td><td>~320</td></tr>
<tr><td>Cosmian HTTP</td><td>31ms</td><td>29ms</td><td>~33</td></tr>
<tr><td>AWS KMS</td><td>52ms</td><td>48ms</td><td>~20</td></tr>
<tr><td>Vault</td><td>38ms</td><td>41ms</td><td>~25</td></tr>
</tbody></table>
</div>
<p><strong>Scaling Test (1000 operations):</strong></p>
<pre><code class="language-nushell"># RustyVault: ~5 seconds
0..1000 | each { |_| kms encrypt "data" --backend rustyvault } | length
# Age: ~3 seconds
0..1000 | each { |_| kms encrypt "data" --backend age } | length
</code></pre>
<h3 id="troubleshooting-kms"><a class="header" href="#troubleshooting-kms">Troubleshooting KMS</a></h3>
<p><strong>“RustyVault connection failed”</strong></p>
<pre><code class="language-bash"># Check RustyVault is running
curl http://localhost:8200/v1/sys/health
# Expected: { "initialized": true, "sealed": false }
# Check environment
echo $env.RUSTYVAULT_ADDR
echo $env.RUSTYVAULT_TOKEN
# Test authentication
curl -H "X-Vault-Token: $RUSTYVAULT_TOKEN" $RUSTYVAULT_ADDR/v1/sys/health
</code></pre>
<p><strong>“Age encryption failed”</strong></p>
<pre><code class="language-bash"># Check Age keys exist
ls -la ~/.age/
# Expected: key.txt
# Verify key format
cat ~/.age/key.txt | head -1
# Expected: # created: &lt;date&gt;
# Line 2: # public key: age1xxxxx
# Line 3: AGE-SECRET-KEY-xxxxx
# Extract public key
export AGE_RECIPIENT=$(grep "public key:" ~/.age/key.txt | cut -d: -f2 | tr -d ' ')
echo $AGE_RECIPIENT
</code></pre>
<p><strong>“AWS KMS access denied”</strong></p>
<pre><code class="language-bash"># Verify AWS credentials
aws sts get-caller-identity
# Expected: Account, UserId, Arn
# Check KMS key permissions
aws kms describe-key --key-id alias/provisioning
# Test encryption
aws kms encrypt --key-id alias/provisioning --plaintext "test"
</code></pre>
<hr />
<h2 id="orchestrator-plugin-nu_plugin_orchestrator"><a class="header" href="#orchestrator-plugin-nu_plugin_orchestrator">Orchestrator Plugin (nu_plugin_orchestrator)</a></h2>
<p>The orchestrator plugin provides direct file-based access to orchestrator state, eliminating HTTP overhead for status queries and validation.</p>
<h3 id="available-commands-2"><a class="header" href="#available-commands-2">Available Commands</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Command</th><th>Purpose</th><th>Example</th></tr></thead><tbody>
<tr><td><code>orch status</code></td><td>Orchestrator status</td><td><code>orch status</code></td></tr>
<tr><td><code>orch validate</code></td><td>Validate workflow</td><td><code>orch validate workflow.k</code></td></tr>
<tr><td><code>orch tasks</code></td><td>List tasks</td><td><code>orch tasks --status running</code></td></tr>
</tbody></table>
</div>
<h3 id="command-reference-2"><a class="header" href="#command-reference-2">Command Reference</a></h3>
<h4 id="orch-status---data-dir-dir"><a class="header" href="#orch-status---data-dir-dir"><code>orch status [--data-dir &lt;dir&gt;]</code></a></h4>
<p>Get orchestrator status from local files (no HTTP, ~1ms latency).</p>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--data-dir &lt;dir&gt;</code>: Data directory (default from <code>ORCHESTRATOR_DATA_DIR</code>)</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Default data directory
orch status
# {
# "active_tasks": 5,
# "completed_tasks": 120,
# "failed_tasks": 2,
# "pending_tasks": 3,
# "uptime": "2d 4h 15m",
# "health": "healthy"
# }
# Custom data directory
orch status --data-dir /opt/orchestrator/data
# Monitor in loop
while true {
clear
orch status | table
sleep 5sec
}
# Alert on failures
if (orch status | get failed_tasks) &gt; 0 {
echo "⚠️ Failed tasks detected!"
}
</code></pre>
<h4 id="orch-validate-workflowk---strict"><a class="header" href="#orch-validate-workflowk---strict"><code>orch validate &lt;workflow.k&gt; [--strict]</code></a></h4>
<p>Validate workflow KCL file syntax and structure.</p>
<p><strong>Arguments:</strong></p>
<ul>
<li><code>workflow.k</code> (required): Path to KCL workflow file</li>
</ul>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--strict</code>: Enable strict validation (warnings as errors)</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># Basic validation
orch validate workflows/deploy.k
# {
# "valid": true,
# "workflow": {
# "name": "deploy_k8s_cluster",
# "version": "1.0.0",
# "operations": 5
# },
# "warnings": [],
# "errors": []
# }
# Strict mode (warnings cause failure)
orch validate workflows/deploy.k --strict
# Error: Validation failed with warnings:
# - Operation 'create_servers': Missing retry_policy
# - Operation 'install_k8s': Resource limits not specified
# Validate all workflows
ls workflows/*.k | each { |file|
let result = orch validate $file.name
if $result.valid {
echo $"✓ ($file.name)"
} else {
echo $"✗ ($file.name): ($result.errors | str join ', ')"
}
}
# CI/CD validation
try {
orch validate workflow.k --strict
echo "✓ Validation passed"
} catch {
echo "✗ Validation failed"
exit 1
}
</code></pre>
<p><strong>Validation Checks:</strong></p>
<ul>
<li>✅ KCL syntax correctness</li>
<li>✅ Required fields present (<code>name</code>, <code>version</code>, <code>operations</code>)</li>
<li>✅ Dependency graph valid (no cycles)</li>
<li>✅ Resource limits within bounds</li>
<li>✅ Provider configurations valid</li>
<li>✅ Operation types supported</li>
<li>⚠️ Optional: Retry policies defined</li>
<li>⚠️ Optional: Resource limits specified</li>
</ul>
<h4 id="orch-tasks---status-status---limit-n"><a class="header" href="#orch-tasks---status-status---limit-n"><code>orch tasks [--status &lt;status&gt;] [--limit &lt;n&gt;]</code></a></h4>
<p>List orchestrator tasks from local state.</p>
<p><strong>Flags:</strong></p>
<ul>
<li><code>--status &lt;status&gt;</code>: Filter by status (<code>pending</code>, <code>running</code>, <code>completed</code>, <code>failed</code>)</li>
<li><code>--limit &lt;n&gt;</code>: Limit results (default: 100)</li>
<li><code>--data-dir &lt;dir&gt;</code>: Data directory</li>
</ul>
<p><strong>Examples:</strong></p>
<pre><code class="language-nushell"># All tasks (last 100)
orch tasks
# [
# {
# "task_id": "task_abc123",
# "name": "deploy_kubernetes",
# "status": "running",
# "priority": 5,
# "created_at": "2025-10-09T12:00:00Z",
# "progress": 45
# }
# ]
# Running tasks only
orch tasks --status running
# Failed tasks (last 10)
orch tasks --status failed --limit 10
# Pending high-priority tasks
orch tasks --status pending | where priority &gt; 7
# Monitor active tasks
watch {
orch tasks --status running
| select name progress updated_at
| table
}
# Count tasks by status
orch tasks | group-by status | each { |group|
{ status: $group.0, count: ($group.1 | length) }
}
</code></pre>
<h3 id="environment-variables-1"><a class="header" href="#environment-variables-1">Environment Variables</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Variable</th><th>Description</th><th>Default</th></tr></thead><tbody>
<tr><td><code>ORCHESTRATOR_DATA_DIR</code></td><td>Data directory</td><td><code>provisioning/platform/orchestrator/data</code></td></tr>
</tbody></table>
</div>
<h3 id="performance-comparison-1"><a class="header" href="#performance-comparison-1">Performance Comparison</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Operation</th><th>HTTP API</th><th>Plugin</th><th>Latency Reduction</th></tr></thead><tbody>
<tr><td>Status query</td><td>~30ms</td><td>~1ms</td><td><strong>97% faster</strong></td></tr>
<tr><td>Validate workflow</td><td>~100ms</td><td>~10ms</td><td><strong>90% faster</strong></td></tr>
<tr><td>List tasks</td><td>~50ms</td><td>~5ms</td><td><strong>90% faster</strong></td></tr>
</tbody></table>
</div>
<p><strong>Use Case: CI/CD Pipeline</strong></p>
<pre><code class="language-nushell"># HTTP approach (slow)
http get http://localhost:9090/tasks --status running
| each { |task| http get $"http://localhost:9090/tasks/($task.id)" }
# Total: ~500ms for 10 tasks
# Plugin approach (fast)
orch tasks --status running
# Total: ~5ms for 10 tasks
# Result: 100x faster
</code></pre>
<h3 id="troubleshooting-orchestrator"><a class="header" href="#troubleshooting-orchestrator">Troubleshooting Orchestrator</a></h3>
<p><strong>“Failed to read status”</strong></p>
<pre><code class="language-bash"># Check data directory exists
ls -la provisioning/platform/orchestrator/data/
# Create if missing
mkdir -p provisioning/platform/orchestrator/data
# Check permissions (must be readable)
chmod 755 provisioning/platform/orchestrator/data
</code></pre>
<p><strong>“Workflow validation failed”</strong></p>
<pre><code class="language-nushell"># Use strict mode for detailed errors
orch validate workflows/deploy.k --strict
# Check KCL syntax manually
kcl fmt workflows/deploy.k
kcl run workflows/deploy.k
</code></pre>
<p><strong>“No tasks found”</strong></p>
<pre><code class="language-bash"># Check orchestrator running
ps aux | grep orchestrator
# Start orchestrator if not running
cd provisioning/platform/orchestrator
./scripts/start-orchestrator.nu --background
# Check task files
ls provisioning/platform/orchestrator/data/tasks/
</code></pre>
<hr />
<h2 id="integration-examples"><a class="header" href="#integration-examples">Integration Examples</a></h2>
<h3 id="example-1-complete-authenticated-deployment"><a class="header" href="#example-1-complete-authenticated-deployment">Example 1: Complete Authenticated Deployment</a></h3>
<p>Full workflow with authentication, secrets, and deployment:</p>
<pre><code class="language-nushell"># Step 1: Login with MFA
auth login admin
auth mfa verify --code (input "MFA code: ")
# Step 2: Verify orchestrator health
if (orch status | get health) != "healthy" {
error make { msg: "Orchestrator unhealthy" }
}
# Step 3: Validate deployment workflow
let validation = orch validate workflows/production-deploy.k --strict
if not $validation.valid {
error make { msg: $"Validation failed: ($validation.errors)" }
}
# Step 4: Encrypt production secrets
let secrets = open secrets/production.yaml
kms encrypt ($secrets | to json) --backend rustyvault --key prod-main
| save secrets/production.enc
# Step 5: Submit deployment
provisioning cluster create production --check
# Step 6: Monitor progress
while (orch tasks --status running | length) &gt; 0 {
orch tasks --status running
| select name progress updated_at
| table
sleep 10sec
}
echo "✓ Deployment complete"
</code></pre>
<h3 id="example-2-batch-secret-rotation"><a class="header" href="#example-2-batch-secret-rotation">Example 2: Batch Secret Rotation</a></h3>
<p>Rotate all secrets in multiple environments:</p>
<pre><code class="language-nushell"># Rotate database passwords
["dev", "staging", "production"] | each { |env|
# Generate new password
let new_password = (openssl rand -base64 32)
# Encrypt with environment-specific key
let encrypted = kms encrypt $new_password --backend rustyvault --key $"($env)-main"
# Save encrypted password
{
environment: $env,
password_enc: $encrypted,
rotated_at: (date now | format date "%Y-%m-%d %H:%M:%S")
} | save $"secrets/db-password-($env).json"
echo $"✓ Rotated password for ($env)"
}
</code></pre>
<h3 id="example-3-multi-environment-deployment"><a class="header" href="#example-3-multi-environment-deployment">Example 3: Multi-Environment Deployment</a></h3>
<p>Deploy to multiple environments with validation:</p>
<pre><code class="language-nushell"># Define environments
let environments = [
{ name: "dev", validate: "basic" },
{ name: "staging", validate: "strict" },
{ name: "production", validate: "strict", mfa_required: true }
]
# Deploy to each environment
$environments | each { |env|
echo $"Deploying to ($env.name)..."
# Authenticate if production
if $env.mfa_required? {
if not (auth verify | get mfa_verified) {
auth mfa verify --code (input $"MFA code for ($env.name): ")
}
}
# Validate workflow
let validation = if $env.validate == "strict" {
orch validate $"workflows/($env.name)-deploy.k" --strict
} else {
orch validate $"workflows/($env.name)-deploy.k"
}
if not $validation.valid {
echo $"✗ Validation failed for ($env.name)"
continue
}
# Decrypt secrets
let secrets = kms decrypt (open $"secrets/($env.name).enc")
# Deploy
provisioning cluster create $env.name
echo $"✓ Deployed to ($env.name)"
}
</code></pre>
<h3 id="example-4-automated-backup-and-encryption"><a class="header" href="#example-4-automated-backup-and-encryption">Example 4: Automated Backup and Encryption</a></h3>
<p>Backup configuration files with encryption:</p>
<pre><code class="language-nushell"># Backup script
let backup_dir = $"backups/(date now | format date "%Y%m%d-%H%M%S")"
mkdir $backup_dir
# Backup and encrypt configs
ls configs/**/*.yaml | each { |file|
let encrypted = kms encrypt (open $file.name) --backend age
let backup_path = $"($backup_dir)/($file.name | path basename).enc"
$encrypted | save $backup_path
echo $"✓ Backed up ($file.name)"
}
# Create manifest
{
backup_date: (date now),
files: (ls $"($backup_dir)/*.enc" | length),
backend: "age"
} | save $"($backup_dir)/manifest.json"
echo $"✓ Backup complete: ($backup_dir)"
</code></pre>
<h3 id="example-5-health-monitoring-dashboard"><a class="header" href="#example-5-health-monitoring-dashboard">Example 5: Health Monitoring Dashboard</a></h3>
<p>Real-time health monitoring:</p>
<pre><code class="language-nushell"># Health dashboard
while true {
clear
# Header
echo "=== Provisioning Platform Health Dashboard ==="
echo $"Updated: (date now | format date "%Y-%m-%d %H:%M:%S")"
echo ""
# Authentication status
let auth_status = try { auth verify } catch { { active: false } }
echo $"Auth: (if $auth_status.active { '✓ Active' } else { '✗ Inactive' })"
# KMS status
let kms_health = kms status
echo $"KMS: (if $kms_health.status == 'healthy' { '✓ Healthy' } else { '✗ Unhealthy' })"
# Orchestrator status
let orch_health = orch status
echo $"Orchestrator: (if $orch_health.health == 'healthy' { '✓ Healthy' } else { '✗ Unhealthy' })"
echo $"Active Tasks: ($orch_health.active_tasks)"
echo $"Failed Tasks: ($orch_health.failed_tasks)"
# Task summary
echo ""
echo "=== Running Tasks ==="
orch tasks --status running
| select name progress updated_at
| table
sleep 10sec
}
</code></pre>
<hr />
<h2 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h2>
<h3 id="when-to-use-plugins-vs-http"><a class="header" href="#when-to-use-plugins-vs-http">When to Use Plugins vs HTTP</a></h3>
<p><strong>✅ Use Plugins When:</strong></p>
<ul>
<li>Performance is critical (high-frequency operations)</li>
<li>Working in pipelines (Nushell data structures)</li>
<li>Need offline capability (KMS, orchestrator local ops)</li>
<li>Building automation scripts</li>
<li>CI/CD pipelines</li>
</ul>
<p><strong>Use HTTP When:</strong></p>
<ul>
<li>Calling from external systems (not Nushell)</li>
<li>Need consistent REST API interface</li>
<li>Cross-language integration</li>
<li>Web UI backend</li>
</ul>
<h3 id="performance-optimization"><a class="header" href="#performance-optimization">Performance Optimization</a></h3>
<p><strong>1. Batch Operations</strong></p>
<pre><code class="language-nushell"># ❌ Slow: Individual HTTP calls in loop
ls configs/*.yaml | each { |file|
http post http://localhost:9998/encrypt { data: (open $file.name) }
}
# Total: ~5 seconds (50ms × 100)
# ✅ Fast: Plugin in pipeline
ls configs/*.yaml | each { |file|
kms encrypt (open $file.name)
}
# Total: ~0.5 seconds (5ms × 100)
</code></pre>
<p><strong>2. Parallel Processing</strong></p>
<pre><code class="language-nushell"># Process multiple operations in parallel
ls configs/*.yaml
| par-each { |file|
kms encrypt (open $file.name) | save $"encrypted/($file.name).enc"
}
</code></pre>
<p><strong>3. Caching Session State</strong></p>
<pre><code class="language-nushell"># Cache auth verification
let $auth_cache = auth verify
if $auth_cache.active {
# Use cached result instead of repeated calls
echo $"Authenticated as ($auth_cache.user)"
}
</code></pre>
<h3 id="error-handling"><a class="header" href="#error-handling">Error Handling</a></h3>
<p><strong>Graceful Degradation:</strong></p>
<pre><code class="language-nushell"># Try plugin, fallback to HTTP if unavailable
def kms_encrypt [data: string] {
try {
kms encrypt $data
} catch {
http post http://localhost:9998/encrypt { data: $data } | get encrypted
}
}
</code></pre>
<p><strong>Comprehensive Error Handling:</strong></p>
<pre><code class="language-nushell"># Handle all error cases
def safe_deployment [] {
# Check authentication
let auth_status = try {
auth verify
} catch {
echo "✗ Authentication failed, logging in..."
auth login admin
auth verify
}
# Check KMS health
let kms_health = try {
kms status
} catch {
error make { msg: "KMS unavailable, cannot proceed" }
}
# Validate workflow
let validation = try {
orch validate workflow.k --strict
} catch {
error make { msg: "Workflow validation failed" }
}
# Proceed if all checks pass
if $auth_status.active and $kms_health.status == "healthy" and $validation.valid {
echo "✓ All checks passed, deploying..."
provisioning cluster create production
}
}
</code></pre>
<h3 id="security-best-practices"><a class="header" href="#security-best-practices">Security Best Practices</a></h3>
<p><strong>1. Never Log Decrypted Data</strong></p>
<pre><code class="language-nushell"># ❌ BAD: Logs plaintext password
let password = kms decrypt $encrypted_password
echo $"Password: ($password)" # Visible in logs!
# ✅ GOOD: Use directly without logging
let password = kms decrypt $encrypted_password
psql --dbname mydb --password $password # Not logged
</code></pre>
<p><strong>2. Use Context (AAD) for Critical Data</strong></p>
<pre><code class="language-nushell"># Encrypt with context
let context = $"user=(whoami),env=production,date=(date now | format date "%Y-%m-%d")"
kms encrypt $sensitive_data --context $context
# Decrypt requires same context
kms decrypt $encrypted --context $context
</code></pre>
<p><strong>3. Rotate Backup Codes</strong></p>
<pre><code class="language-nushell"># After using backup code, generate new set
auth mfa verify --code ABCD-EFGH-IJKL
# Warning: Backup code used
auth mfa regenerate-backups
# New backup codes generated
</code></pre>
<p><strong>4. Limit Token Lifetime</strong></p>
<pre><code class="language-nushell"># Check token expiration before long operations
let session = auth verify
let expires_in = (($session.expires_at | into datetime) - (date now))
if $expires_in &lt; 5min {
echo "⚠️ Token expiring soon, re-authenticating..."
auth login $session.user
}
</code></pre>
<hr />
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
<h3 id="common-issues-across-plugins"><a class="header" href="#common-issues-across-plugins">Common Issues Across Plugins</a></h3>
<p><strong>“Plugin not found”</strong></p>
<pre><code class="language-bash"># Check plugin registration
plugin list | where name =~ "auth|kms|orch"
# Re-register if missing
cd provisioning/core/plugins/nushell-plugins
plugin add target/release/nu_plugin_auth
plugin add target/release/nu_plugin_kms
plugin add target/release/nu_plugin_orchestrator
# Restart Nushell
exit
nu
</code></pre>
<p><strong>“Plugin command failed”</strong></p>
<pre><code class="language-nushell"># Enable debug mode
$env.RUST_LOG = "debug"
# Run command again to see detailed errors
kms encrypt "test"
# Check plugin version compatibility
plugin list | where name =~ "kms" | select name version
</code></pre>
<p><strong>“Permission denied”</strong></p>
<pre><code class="language-bash"># Check plugin executable permissions
ls -l provisioning/core/plugins/nushell-plugins/target/release/nu_plugin_*
# Should show: -rwxr-xr-x
# Fix if needed
chmod +x provisioning/core/plugins/nushell-plugins/target/release/nu_plugin_*
</code></pre>
<h3 id="platform-specific-issues"><a class="header" href="#platform-specific-issues">Platform-Specific Issues</a></h3>
<p><strong>macOS Issues:</strong></p>
<pre><code class="language-bash"># "cannot be opened because the developer cannot be verified"
xattr -d com.apple.quarantine target/release/nu_plugin_auth
xattr -d com.apple.quarantine target/release/nu_plugin_kms
xattr -d com.apple.quarantine target/release/nu_plugin_orchestrator
# Keychain access denied
# System Preferences → Security &amp; Privacy → Privacy → Full Disk Access
# Add: /usr/local/bin/nu
</code></pre>
<p><strong>Linux Issues:</strong></p>
<pre><code class="language-bash"># Keyring service not running
systemctl --user status gnome-keyring-daemon
systemctl --user start gnome-keyring-daemon
# Missing dependencies
sudo apt install libssl-dev pkg-config # Ubuntu/Debian
sudo dnf install openssl-devel # Fedora
</code></pre>
<p><strong>Windows Issues:</strong></p>
<pre><code class="language-powershell"># Credential Manager access denied
# Control Panel → User Accounts → Credential Manager
# Ensure Windows Credential Manager service is running
# Missing Visual C++ runtime
# Download from: https://aka.ms/vs/17/release/vc_redist.x64.exe
</code></pre>
<h3 id="debugging-techniques"><a class="header" href="#debugging-techniques">Debugging Techniques</a></h3>
<p><strong>Enable Verbose Logging:</strong></p>
<pre><code class="language-nushell"># Set log level
$env.RUST_LOG = "debug,nu_plugin_auth=trace"
# Run command
auth login admin
# Check logs
</code></pre>
<p><strong>Test Plugin Directly:</strong></p>
<pre><code class="language-bash"># Test plugin communication (advanced)
echo '{"Call": [0, {"name": "auth", "call": "login", "args": ["admin", "password"]}]}' \
| target/release/nu_plugin_auth
</code></pre>
<p><strong>Check Plugin Health:</strong></p>
<pre><code class="language-nushell"># Test each plugin
auth --help # Should show auth commands
kms --help # Should show kms commands
orch --help # Should show orch commands
# Test functionality
auth verify # Should return session status
kms status # Should return backend status
orch status # Should return orchestrator status
</code></pre>
<hr />
<h2 id="migration-guide"><a class="header" href="#migration-guide">Migration Guide</a></h2>
<h3 id="migrating-from-http-to-plugin-based"><a class="header" href="#migrating-from-http-to-plugin-based">Migrating from HTTP to Plugin-Based</a></h3>
<p><strong>Phase 1: Install Plugins (No Breaking Changes)</strong></p>
<pre><code class="language-bash"># Build and register plugins
cd provisioning/core/plugins/nushell-plugins
cargo build --release --all
plugin add target/release/nu_plugin_auth
plugin add target/release/nu_plugin_kms
plugin add target/release/nu_plugin_orchestrator
# Verify HTTP still works
http get http://localhost:9090/health
</code></pre>
<p><strong>Phase 2: Update Scripts Incrementally</strong></p>
<pre><code class="language-nushell"># Before (HTTP)
def encrypt_config [file: string] {
let data = open $file
let result = http post http://localhost:9998/encrypt { data: $data }
$result.encrypted | save $"($file).enc"
}
# After (Plugin with fallback)
def encrypt_config [file: string] {
let data = open $file
let encrypted = try {
kms encrypt $data --backend rustyvault
} catch {
# Fallback to HTTP if plugin unavailable
(http post http://localhost:9998/encrypt { data: $data }).encrypted
}
$encrypted | save $"($file).enc"
}
</code></pre>
<p><strong>Phase 3: Test Migration</strong></p>
<pre><code class="language-nushell"># Run side-by-side comparison
def test_migration [] {
let test_data = "test secret data"
# Plugin approach
let start_plugin = date now
let plugin_result = kms encrypt $test_data
let plugin_time = ((date now) - $start_plugin)
# HTTP approach
let start_http = date now
let http_result = (http post http://localhost:9998/encrypt { data: $test_data }).encrypted
let http_time = ((date now) - $start_http)
echo $"Plugin: ($plugin_time)ms"
echo $"HTTP: ($http_time)ms"
echo $"Speedup: (($http_time / $plugin_time))x"
}
</code></pre>
<p><strong>Phase 4: Gradual Rollout</strong></p>
<pre><code class="language-nushell"># Use feature flag for controlled rollout
$env.USE_PLUGINS = true
def encrypt_with_flag [data: string] {
if $env.USE_PLUGINS {
kms encrypt $data
} else {
(http post http://localhost:9998/encrypt { data: $data }).encrypted
}
}
</code></pre>
<p><strong>Phase 5: Full Migration</strong></p>
<pre><code class="language-nushell"># Replace all HTTP calls with plugin calls
# Remove fallback logic once stable
def encrypt_config [file: string] {
let data = open $file
kms encrypt $data --backend rustyvault | save $"($file).enc"
}
</code></pre>
<h3 id="rollback-strategy"><a class="header" href="#rollback-strategy">Rollback Strategy</a></h3>
<pre><code class="language-nushell"># If issues arise, quickly rollback
def rollback_to_http [] {
# Remove plugin registrations
plugin rm nu_plugin_auth
plugin rm nu_plugin_kms
plugin rm nu_plugin_orchestrator
# Restart Nushell
exec nu
}
</code></pre>
<hr />
<h2 id="advanced-configuration"><a class="header" href="#advanced-configuration">Advanced Configuration</a></h2>
<h3 id="custom-plugin-paths"><a class="header" href="#custom-plugin-paths">Custom Plugin Paths</a></h3>
<pre><code class="language-nushell"># ~/.config/nushell/config.nu
$env.PLUGIN_PATH = "/opt/provisioning/plugins"
# Register from custom location
plugin add $"($env.PLUGIN_PATH)/nu_plugin_auth"
plugin add $"($env.PLUGIN_PATH)/nu_plugin_kms"
plugin add $"($env.PLUGIN_PATH)/nu_plugin_orchestrator"
</code></pre>
<h3 id="environment-specific-configuration"><a class="header" href="#environment-specific-configuration">Environment-Specific Configuration</a></h3>
<pre><code class="language-nushell"># ~/.config/nushell/env.nu
# Development environment
if ($env.ENV? == "dev") {
$env.RUSTYVAULT_ADDR = "http://localhost:8200"
$env.CONTROL_CENTER_URL = "http://localhost:3000"
}
# Staging environment
if ($env.ENV? == "staging") {
$env.RUSTYVAULT_ADDR = "https://vault-staging.example.com"
$env.CONTROL_CENTER_URL = "https://control-staging.example.com"
}
# Production environment
if ($env.ENV? == "prod") {
$env.RUSTYVAULT_ADDR = "https://vault.example.com"
$env.CONTROL_CENTER_URL = "https://control.example.com"
}
</code></pre>
<h3 id="plugin-aliases"><a class="header" href="#plugin-aliases">Plugin Aliases</a></h3>
<pre><code class="language-nushell"># ~/.config/nushell/config.nu
# Auth shortcuts
alias login = auth login
alias logout = auth logout
alias whoami = auth verify | get user
# KMS shortcuts
alias encrypt = kms encrypt
alias decrypt = kms decrypt
# Orchestrator shortcuts
alias status = orch status
alias tasks = orch tasks
alias validate = orch validate
</code></pre>
<h3 id="custom-commands"><a class="header" href="#custom-commands">Custom Commands</a></h3>
<pre><code class="language-nushell"># ~/.config/nushell/custom_commands.nu
# Encrypt all files in directory
def encrypt-dir [dir: string] {
ls $"($dir)/**/*" | where type == file | each { |file|
kms encrypt (open $file.name) | save $"($file.name).enc"
echo $"✓ Encrypted ($file.name)"
}
}
# Decrypt all files in directory
def decrypt-dir [dir: string] {
ls $"($dir)/**/*.enc" | each { |file|
kms decrypt (open $file.name)
| save (echo $file.name | str replace '.enc' '')
echo $"✓ Decrypted ($file.name)"
}
}
# Monitor deployments
def watch-deployments [] {
while true {
clear
echo "=== Active Deployments ==="
orch tasks --status running | table
sleep 5sec
}
}
</code></pre>
<hr />
<h2 id="security-considerations"><a class="header" href="#security-considerations">Security Considerations</a></h2>
<h3 id="threat-model"><a class="header" href="#threat-model">Threat Model</a></h3>
<p><strong>What Plugins Protect Against:</strong></p>
<ul>
<li>✅ Network eavesdropping (no HTTP for KMS/orch)</li>
<li>✅ Token theft from files (keyring storage)</li>
<li>✅ Credential exposure in logs (prompt-based input)</li>
<li>✅ Man-in-the-middle attacks (local file access)</li>
</ul>
<p><strong>What Plugins Dont Protect Against:</strong></p>
<ul>
<li>❌ Memory dumping (decrypted data in RAM)</li>
<li>❌ Malicious plugins (trust registry only)</li>
<li>❌ Compromised OS keyring</li>
<li>❌ Physical access to machine</li>
</ul>
<h3 id="secure-deployment"><a class="header" href="#secure-deployment">Secure Deployment</a></h3>
<p><strong>1. Verify Plugin Integrity</strong></p>
<pre><code class="language-bash"># Check plugin signatures (if available)
sha256sum target/release/nu_plugin_auth
# Compare with published checksums
# Build from trusted source
git clone https://github.com/provisioning-platform/plugins
cd plugins
cargo build --release --all
</code></pre>
<p><strong>2. Restrict Plugin Access</strong></p>
<pre><code class="language-bash"># Set plugin permissions (only owner can execute)
chmod 700 target/release/nu_plugin_*
# Store in protected directory
sudo mkdir -p /opt/provisioning/plugins
sudo chown $(whoami):$(whoami) /opt/provisioning/plugins
sudo chmod 755 /opt/provisioning/plugins
mv target/release/nu_plugin_* /opt/provisioning/plugins/
</code></pre>
<p><strong>3. Audit Plugin Usage</strong></p>
<pre><code class="language-nushell"># Log plugin calls (for compliance)
def logged_encrypt [data: string] {
let timestamp = date now
let result = kms encrypt $data
{ timestamp: $timestamp, action: "encrypt" } | save --append audit.log
$result
}
</code></pre>
<p><strong>4. Rotate Credentials Regularly</strong></p>
<pre><code class="language-nushell"># Weekly credential rotation script
def rotate_credentials [] {
# Re-authenticate
auth logout
auth login admin
# Rotate KMS keys (if supported)
kms rotate-key --key provisioning-main
# Update encrypted secrets
ls secrets/*.enc | each { |file|
let plain = kms decrypt (open $file.name)
kms encrypt $plain | save $file.name
}
}
</code></pre>
<hr />
<h2 id="faq"><a class="header" href="#faq">FAQ</a></h2>
<p><strong>Q: Can I use plugins without RustyVault/Age installed?</strong></p>
<p>A: Yes, authentication and orchestrator plugins work independently. KMS plugin requires at least one backend configured (Age is easiest for local dev).</p>
<p><strong>Q: Do plugins work in CI/CD pipelines?</strong></p>
<p>A: Yes, plugins work great in CI/CD. For headless environments (no keyring), use environment variables for auth or file-based tokens.</p>
<pre><code class="language-bash"># CI/CD example
export CONTROL_CENTER_TOKEN="jwt-token-here"
kms encrypt "data" --backend age
</code></pre>
<p><strong>Q: How do I update plugins?</strong></p>
<p>A: Rebuild and re-register:</p>
<pre><code class="language-bash">cd provisioning/core/plugins/nushell-plugins
git pull
cargo build --release --all
plugin add --force target/release/nu_plugin_auth
plugin add --force target/release/nu_plugin_kms
plugin add --force target/release/nu_plugin_orchestrator
</code></pre>
<p><strong>Q: Can I use multiple KMS backends simultaneously?</strong></p>
<p>A: Yes, specify <code>--backend</code> for each operation:</p>
<pre><code class="language-nushell">kms encrypt "data1" --backend rustyvault
kms encrypt "data2" --backend age
kms encrypt "data3" --backend aws
</code></pre>
<p><strong>Q: What happens if a plugin crashes?</strong></p>
<p>A: Nushell isolates plugin crashes. The command fails with an error, but Nushell continues running. Check logs with <code>$env.RUST_LOG = "debug"</code>.</p>
<p><strong>Q: Are plugins compatible with older Nushell versions?</strong></p>
<p>A: Plugins require Nushell 0.107.1+. For older versions, use HTTP API.</p>
<p><strong>Q: How do I backup MFA enrollment?</strong></p>
<p>A: Save backup codes securely (password manager, encrypted file). QR code can be re-scanned from the same secret.</p>
<pre><code class="language-nushell"># Save backup codes
auth mfa enroll totp | save mfa-backup-codes.txt
kms encrypt (open mfa-backup-codes.txt) | save mfa-backup-codes.enc
rm mfa-backup-codes.txt
</code></pre>
<p><strong>Q: Can plugins work offline?</strong></p>
<p>A: Partially:</p>
<ul>
<li><code>kms</code> with Age backend (fully offline)</li>
<li><code>orch</code> status/tasks (reads local files)</li>
<li><code>auth</code> (requires control center)</li>
<li><code>kms</code> with RustyVault/AWS/Vault (requires network)</li>
</ul>
<p><strong>Q: How do I troubleshoot plugin performance?</strong></p>
<p>A: Use Nushells timing:</p>
<pre><code class="language-nushell">timeit { kms encrypt "data" }
# 5ms 123μs 456ns
timeit { http post http://localhost:9998/encrypt { data: "data" } }
# 52ms 789μs 123ns
</code></pre>
<hr />
<h2 id="related-documentation"><a class="header" href="#related-documentation">Related Documentation</a></h2>
<ul>
<li><strong>Security System</strong>: <code>/Users/Akasha/project-provisioning/docs/architecture/ADR-009-security-system-complete.md</code></li>
<li><strong>JWT Authentication</strong>: <code>/Users/Akasha/project-provisioning/docs/architecture/JWT_AUTH_IMPLEMENTATION.md</code></li>
<li><strong>Config Encryption</strong>: <code>/Users/Akasha/project-provisioning/docs/user/CONFIG_ENCRYPTION_GUIDE.md</code></li>
<li><strong>RustyVault Integration</strong>: <code>/Users/Akasha/project-provisioning/RUSTYVAULT_INTEGRATION_SUMMARY.md</code></li>
<li><strong>MFA Implementation</strong>: <code>/Users/Akasha/project-provisioning/docs/architecture/MFA_IMPLEMENTATION_SUMMARY.md</code></li>
<li><strong>Nushell Plugins Reference</strong>: <code>/Users/Akasha/project-provisioning/docs/user/NUSHELL_PLUGINS_GUIDE.md</code></li>
</ul>
<hr />
<p><strong>Version</strong>: 1.0.0
<strong>Maintained By</strong>: Platform Team
<strong>Last Updated</strong>: 2025-10-09
<strong>Feedback</strong>: Open an issue or contact platform-team@example.com</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../user/NUSHELL_PLUGINS_GUIDE.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../architecture/ARCHITECTURE_OVERVIEW.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../user/NUSHELL_PLUGINS_GUIDE.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../architecture/ARCHITECTURE_OVERVIEW.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>