provisioning/docs/book/user/PLUGIN_INTEGRATION_GUIDE.html

2026 lines
82 KiB
HTML
Raw Normal View History

<!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>