provisioning/docs/book/user/NUSHELL_PLUGINS_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

993 lines
41 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>Nushell Plugins 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/NUSHELL_PLUGINS_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-plugins-for-provisioning-platform"><a class="header" href="#nushell-plugins-for-provisioning-platform">Nushell Plugins for Provisioning Platform</a></h1>
<p>Complete guide to authentication, KMS, and orchestrator plugins.</p>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>Three native Nushell plugins provide high-performance integration with the provisioning platform:</p>
<ol>
<li><strong>nu_plugin_auth</strong> - JWT authentication and MFA operations</li>
<li><strong>nu_plugin_kms</strong> - Key management (RustyVault, Age, Cosmian, AWS, Vault)</li>
<li><strong>nu_plugin_orchestrator</strong> - Orchestrator operations (status, validate, tasks)</li>
</ol>
<h2 id="why-native-plugins"><a class="header" href="#why-native-plugins">Why Native Plugins?</a></h2>
<p><strong>Performance Advantages</strong>:</p>
<ul>
<li><strong>10x faster</strong> than HTTP API calls (KMS operations)</li>
<li><strong>Direct access</strong> to Rust libraries (no HTTP overhead)</li>
<li><strong>Native integration</strong> with Nushell pipelines</li>
<li><strong>Type safety</strong> with Nushells type system</li>
</ul>
<p><strong>Developer Experience</strong>:</p>
<ul>
<li><strong>Pipeline friendly</strong> - Use Nushell pipes naturally</li>
<li><strong>Tab completion</strong> - All commands and flags</li>
<li><strong>Consistent interface</strong> - Follows Nushell conventions</li>
<li><strong>Error handling</strong> - Nushell-native error messages</li>
</ul>
<hr />
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
<h3 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h3>
<ul>
<li>Nushell 0.107.1+</li>
<li>Rust toolchain (for building from source)</li>
<li>Access to provisioning platform services</li>
</ul>
<h3 id="build-from-source"><a class="header" href="#build-from-source">Build from Source</a></h3>
<pre><code class="language-bash">cd /Users/Akasha/project-provisioning/provisioning/core/plugins/nushell-plugins
# Build all plugins
cargo build --release -p nu_plugin_auth
cargo build --release -p nu_plugin_kms
cargo build --release -p nu_plugin_orchestrator
# 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>
<h3 id="register-with-nushell"><a class="header" href="#register-with-nushell">Register with Nushell</a></h3>
<pre><code class="language-bash"># Register all plugins
plugin add target/release/nu_plugin_auth
plugin add target/release/nu_plugin_kms
plugin add target/release/nu_plugin_orchestrator
# Verify registration
plugin list | where name =~ "provisioning"
</code></pre>
<h3 id="verify-installation"><a class="header" href="#verify-installation">Verify Installation</a></h3>
<pre><code class="language-bash"># Test auth commands
auth --help
# Test KMS commands
kms --help
# Test orchestrator commands
orch --help
</code></pre>
<hr />
<h2 id="plugin-nu_plugin_auth"><a class="header" href="#plugin-nu_plugin_auth">Plugin: nu_plugin_auth</a></h2>
<p>Authentication plugin for JWT login, MFA enrollment, and session management.</p>
<h3 id="commands"><a class="header" href="#commands">Commands</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.</p>
<p><strong>Arguments</strong>:</p>
<ul>
<li><code>username</code> (required): Username for authentication</li>
<li><code>password</code> (optional): Password (prompts interactively 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:9080</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 in command (not recommended for production)
auth login admin mypassword
# Custom URL
auth login admin --url http://control-center:9080
# Pipeline usage
"admin" | auth login
</code></pre>
<p><strong>Token Storage</strong>:
Tokens are stored securely in OS-native keyring:</p>
<ul>
<li><strong>macOS</strong>: Keychain Access</li>
<li><strong>Linux</strong>: Secret Service (gnome-keyring, kwallet)</li>
<li><strong>Windows</strong>: Credential Manager</li>
</ul>
<p><strong>Success Output</strong>:</p>
<pre><code>✓ Login successful
User: admin
Role: Admin
Expires: 2025-10-09T14:30:00Z
</code></pre>
<hr />
<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.</p>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Simple logout
auth logout
# Pipeline usage (conditional logout)
if (auth verify | get active) { auth logout }
</code></pre>
<p><strong>Success Output</strong>:</p>
<pre><code>✓ Logged out successfully
</code></pre>
<hr />
<h4 id="auth-verify"><a class="header" href="#auth-verify"><code>auth verify</code></a></h4>
<p>Verify current session and check token validity.</p>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Check session status
auth verify
# Pipeline usage
auth verify | if $in.active { echo "Session valid" } else { echo "Session expired" }
</code></pre>
<p><strong>Success Output</strong>:</p>
<pre><code class="language-json">{
"active": true,
"user": "admin",
"role": "Admin",
"expires_at": "2025-10-09T14:30:00Z",
"mfa_verified": true
}
</code></pre>
<hr />
<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 sessions
auth sessions
# Filter by date
auth sessions | where created_at &gt; (date now | date to-timezone UTC | into string)
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">[
{
"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"
}
]
</code></pre>
<hr />
<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 MFA (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>Examples</strong>:</p>
<pre><code class="language-nushell"># Enroll TOTP (Google Authenticator, Authy)
auth mfa enroll totp
# Enroll WebAuthn (YubiKey, Touch ID, Windows Hello)
auth mfa enroll webauthn
</code></pre>
<p><strong>TOTP Enrollment Output</strong>:</p>
<pre><code>✓ TOTP enrollment initiated
Scan this QR code with your authenticator app:
████ ▄▄▄▄▄ █▀█ █▄▀▀▀▄ ▄▄▄▄▄ ████
████ █ █ █▀▀▀█▄ ▀▀█ █ █ ████
████ █▄▄▄█ █ █▀▄ ▀▄▄█ █▄▄▄█ ████
...
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
...
</code></pre>
<hr />
<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
# Verify backup code
auth mfa verify --code ABCD-EFGH-IJKL
</code></pre>
<p><strong>Success Output</strong>:</p>
<pre><code>✓ MFA verification successful
</code></pre>
<hr />
<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:9080</code></td></tr>
</tbody></table>
</div>
<hr />
<h3 id="error-handling"><a class="header" href="#error-handling">Error Handling</a></h3>
<p><strong>Common Errors</strong>:</p>
<pre><code class="language-nushell"># "No active session"
Error: No active session found
→ Run: auth login &lt;username&gt;
# "Invalid credentials"
Error: Authentication failed: Invalid username or password
→ Check username and password
# "Token expired"
Error: Token has expired
→ Run: auth login &lt;username&gt;
# "MFA required"
Error: MFA verification required
→ Run: auth mfa verify --code &lt;code&gt;
# "Keyring error" (macOS)
Error: Failed to access keyring
→ Check Keychain Access permissions
# "Keyring error" (Linux)
Error: Failed to access keyring
→ Install gnome-keyring or kwallet
</code></pre>
<hr />
<h2 id="plugin-nu_plugin_kms"><a class="header" href="#plugin-nu_plugin_kms">Plugin: nu_plugin_kms</a></h2>
<p>Key Management Service plugin supporting multiple backends.</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>Description</th><th>Use Case</th></tr></thead><tbody>
<tr><td><code>rustyvault</code></td><td>RustyVault Transit engine</td><td>Production KMS</td></tr>
<tr><td><code>age</code></td><td>Age encryption (local)</td><td>Development/testing</td></tr>
<tr><td><code>cosmian</code></td><td>Cosmian KMS (HTTP)</td><td>Cloud KMS</td></tr>
<tr><td><code>aws</code></td><td>AWS KMS</td><td>AWS environments</td></tr>
<tr><td><code>vault</code></td><td>HashiCorp Vault</td><td>Enterprise KMS</td></tr>
</tbody></table>
</div>
<h3 id="commands-1"><a class="header" href="#commands-1">Commands</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 KMS.</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 data"
# RustyVault
kms encrypt "data" --backend rustyvault --key provisioning-main
# Age (local encryption)
kms encrypt "data" --backend age --key age1xxxxxxxxx
# AWS KMS
kms encrypt "data" --backend aws --key alias/provisioning
# With context (AAD)
kms encrypt "data" --backend rustyvault --key provisioning-main --context "user=admin"
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code>vault:v1:abc123def456...
</code></pre>
<hr />
<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 (base64 or KMS format)</li>
</ul>
<p><strong>Flags</strong>:</p>
<ul>
<li><code>--backend &lt;backend&gt;</code>: KMS backend (auto-detected if not specified)</li>
<li><code>--context &lt;context&gt;</code>: Additional authenticated data (AAD, must match encryption)</li>
</ul>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Auto-detect backend
kms decrypt "vault:v1:abc123def456..."
# RustyVault explicit
kms decrypt "vault:v1:abc123..." --backend rustyvault
# Age
kms decrypt "-----BEGIN AGE ENCRYPTED FILE-----..." --backend age
# With context
kms decrypt "vault:v1:abc123..." --backend rustyvault --context "user=admin"
</code></pre>
<p><strong>Output</strong>:</p>
<pre><code>secret data
</code></pre>
<hr />
<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.</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
# Generate AES-128 key
kms generate-key --spec AES128
# Specific backend
kms generate-key --backend rustyvault
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">{
"plaintext": "base64-encoded-key",
"ciphertext": "vault:v1:encrypted-key",
"spec": "AES256"
}
</code></pre>
<hr />
<h4 id="kms-status"><a class="header" href="#kms-status"><code>kms status</code></a></h4>
<p>Show KMS backend status and configuration.</p>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Show status
kms status
# Filter to specific backend
kms status | where backend == "rustyvault"
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">{
"backend": "rustyvault",
"status": "healthy",
"url": "http://localhost:8200",
"mount_point": "transit",
"version": "0.1.0"
}
</code></pre>
<hr />
<h3 id="environment-variables-1"><a class="header" href="#environment-variables-1">Environment Variables</a></h3>
<p><strong>RustyVault Backend</strong>:</p>
<pre><code class="language-bash">export RUSTYVAULT_ADDR="http://localhost:8200"
export RUSTYVAULT_TOKEN="your-token-here"
export RUSTYVAULT_MOUNT="transit"
</code></pre>
<p><strong>Age Backend</strong>:</p>
<pre><code class="language-bash">export AGE_RECIPIENT="age1xxxxxxxxx"
export AGE_IDENTITY="/path/to/key.txt"
</code></pre>
<p><strong>HTTP Backend (Cosmian)</strong>:</p>
<pre><code class="language-bash">export KMS_HTTP_URL="http://localhost:9998"
export KMS_HTTP_BACKEND="cosmian"
</code></pre>
<p><strong>AWS KMS</strong>:</p>
<pre><code class="language-bash">export AWS_REGION="us-east-1"
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
</code></pre>
<hr />
<h3 id="performance-comparison"><a class="header" href="#performance-comparison">Performance Comparison</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Operation</th><th>HTTP API</th><th>Plugin</th><th>Improvement</th></tr></thead><tbody>
<tr><td>Encrypt (RustyVault)</td><td>~50ms</td><td>~5ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Decrypt (RustyVault)</td><td>~50ms</td><td>~5ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Encrypt (Age)</td><td>~30ms</td><td>~3ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Decrypt (Age)</td><td>~30ms</td><td>~3ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Generate Key</td><td>~60ms</td><td>~8ms</td><td><strong>7.5x faster</strong></td></tr>
</tbody></table>
</div>
<hr />
<h2 id="plugin-nu_plugin_orchestrator"><a class="header" href="#plugin-nu_plugin_orchestrator">Plugin: nu_plugin_orchestrator</a></h2>
<p>Orchestrator operations plugin for status, validation, and task management.</p>
<h3 id="commands-2"><a class="header" href="#commands-2">Commands</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).</p>
<p><strong>Flags</strong>:</p>
<ul>
<li><code>--data-dir &lt;dir&gt;</code>: Data directory (default: <code>provisioning/platform/orchestrator/data</code>)</li>
</ul>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Default data dir
orch status
# Custom dir
orch status --data-dir ./custom/data
# Pipeline usage
orch status | if $in.active_tasks &gt; 0 { echo "Tasks running" }
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">{
"active_tasks": 5,
"completed_tasks": 120,
"failed_tasks": 2,
"pending_tasks": 3,
"uptime": "2d 4h 15m",
"health": "healthy"
}
</code></pre>
<hr />
<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.</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 (all checks, warnings as errors)</li>
</ul>
<p><strong>Examples</strong>:</p>
<pre><code class="language-nushell"># Basic validation
orch validate workflows/deploy.k
# Strict mode
orch validate workflows/deploy.k --strict
# Pipeline usage
ls workflows/*.k | each { |file| orch validate $file.name }
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">{
"valid": true,
"workflow": {
"name": "deploy_k8s_cluster",
"version": "1.0.0",
"operations": 5
},
"warnings": [],
"errors": []
}
</code></pre>
<p><strong>Validation Checks</strong>:</p>
<ul>
<li>KCL syntax errors</li>
<li>Required fields present</li>
<li>Dependency graph valid (no cycles)</li>
<li>Resource limits within bounds</li>
<li>Provider configurations valid</li>
</ul>
<hr />
<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.</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 number of results (default: 100)</li>
<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"># All tasks
orch tasks
# Pending tasks only
orch tasks --status pending
# Running tasks (limit to 10)
orch tasks --status running --limit 10
# Pipeline usage
orch tasks --status failed | each { |task| echo $"Failed: ($task.name)" }
</code></pre>
<p><strong>Output Format</strong>:</p>
<pre><code class="language-json">[
{
"task_id": "task_abc123",
"name": "deploy_kubernetes",
"status": "running",
"priority": 5,
"created_at": "2025-10-09T12:00:00Z",
"updated_at": "2025-10-09T12:05:00Z",
"progress": 45
}
]
</code></pre>
<hr />
<h3 id="environment-variables-2"><a class="header" href="#environment-variables-2">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>
<hr />
<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>Improvement</th></tr></thead><tbody>
<tr><td>Status</td><td>~30ms</td><td>~3ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Validate</td><td>~100ms</td><td>~10ms</td><td><strong>10x faster</strong></td></tr>
<tr><td>Tasks List</td><td>~50ms</td><td>~5ms</td><td><strong>10x faster</strong></td></tr>
</tbody></table>
</div>
<hr />
<h2 id="pipeline-examples"><a class="header" href="#pipeline-examples">Pipeline Examples</a></h2>
<h3 id="authentication-flow"><a class="header" href="#authentication-flow">Authentication Flow</a></h3>
<pre><code class="language-nushell"># Login and verify in one pipeline
auth login admin
| if $in.success { auth verify }
| if $in.mfa_required { auth mfa verify --code (input "MFA code: ") }
</code></pre>
<h3 id="kms-operations"><a class="header" href="#kms-operations">KMS Operations</a></h3>
<pre><code class="language-nushell"># Encrypt multiple secrets
["secret1", "secret2", "secret3"]
| each { |data| kms encrypt $data --backend rustyvault }
| save encrypted_secrets.json
# Decrypt and process
open encrypted_secrets.json
| each { |enc| kms decrypt $enc }
| each { |plain| echo $"Decrypted: ($plain)" }
</code></pre>
<h3 id="orchestrator-monitoring"><a class="header" href="#orchestrator-monitoring">Orchestrator Monitoring</a></h3>
<pre><code class="language-nushell"># Monitor running tasks
while true {
orch tasks --status running
| each { |task| echo $"($task.name): ($task.progress)%" }
sleep 5sec
}
</code></pre>
<h3 id="combined-workflow"><a class="header" href="#combined-workflow">Combined Workflow</a></h3>
<pre><code class="language-nushell"># Complete deployment workflow
auth login admin
| auth mfa verify --code (input "MFA: ")
| orch validate workflows/deploy.k
| if $in.valid {
orch tasks --status pending
| where priority &gt; 5
| each { |task| echo $"High priority: ($task.name)" }
}
</code></pre>
<hr />
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
<h3 id="auth-plugin"><a class="header" href="#auth-plugin">Auth Plugin</a></h3>
<p><strong>“No active session”</strong>:</p>
<pre><code class="language-nushell">auth login &lt;username&gt;
</code></pre>
<p><strong>“Keyring error” (macOS)</strong>:</p>
<ul>
<li>Check Keychain Access permissions</li>
<li>Security &amp; Privacy → Privacy → Full Disk Access → Add Nushell</li>
</ul>
<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
# Or use KWallet
sudo apt install kwalletmanager
</code></pre>
<p><strong>“MFA verification failed”</strong>:</p>
<ul>
<li>Check time synchronization (TOTP requires accurate clocks)</li>
<li>Use backup codes if TOTP not working</li>
<li>Re-enroll MFA if device lost</li>
</ul>
<hr />
<h3 id="kms-plugin"><a class="header" href="#kms-plugin">KMS Plugin</a></h3>
<p><strong>“RustyVault connection failed”</strong>:</p>
<pre><code class="language-bash"># Check RustyVault running
curl http://localhost:8200/v1/sys/health
# Set environment
export RUSTYVAULT_ADDR="http://localhost:8200"
export RUSTYVAULT_TOKEN="your-token"
</code></pre>
<p><strong>“Age encryption failed”</strong>:</p>
<pre><code class="language-bash"># Check Age keys
ls -la ~/.age/
# Generate new key if needed
age-keygen -o ~/.age/key.txt
# Set environment
export AGE_RECIPIENT="age1xxxxxxxxx"
export AGE_IDENTITY="$HOME/.age/key.txt"
</code></pre>
<p><strong>“AWS KMS access denied”</strong>:</p>
<pre><code class="language-bash"># Check AWS credentials
aws sts get-caller-identity
# Check KMS key policy
aws kms describe-key --key-id alias/provisioning
</code></pre>
<hr />
<h3 id="orchestrator-plugin"><a class="header" href="#orchestrator-plugin">Orchestrator Plugin</a></h3>
<p><strong>“Failed to read status”</strong>:</p>
<pre><code class="language-bash"># Check data directory exists
ls provisioning/platform/orchestrator/data/
# Create if missing
mkdir -p 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
</code></pre>
<p><strong>“No tasks found”</strong>:</p>
<pre><code class="language-bash"># Check orchestrator running
ps aux | grep orchestrator
# Start orchestrator
cd provisioning/platform/orchestrator
./scripts/start-orchestrator.nu --background
</code></pre>
<hr />
<h2 id="development"><a class="header" href="#development">Development</a></h2>
<h3 id="building-from-source"><a class="header" href="#building-from-source">Building from Source</a></h3>
<pre><code class="language-bash">cd provisioning/core/plugins/nushell-plugins
# Clean build
cargo clean
# Build with debug info
cargo build -p nu_plugin_auth
cargo build -p nu_plugin_kms
cargo build -p nu_plugin_orchestrator
# Run tests
cargo test -p nu_plugin_auth
cargo test -p nu_plugin_kms
cargo test -p nu_plugin_orchestrator
# Run all tests
cargo test --all
</code></pre>
<h3 id="adding-to-cicd"><a class="header" href="#adding-to-cicd">Adding to CI/CD</a></h3>
<pre><code class="language-yaml">name: Build Nushell Plugins
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build Plugins
run: |
cd provisioning/core/plugins/nushell-plugins
cargo build --release --all
- name: Test Plugins
run: |
cd provisioning/core/plugins/nushell-plugins
cargo test --all
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: plugins
path: provisioning/core/plugins/nushell-plugins/target/release/nu_plugin_*
</code></pre>
<hr />
<h2 id="advanced-usage"><a class="header" href="#advanced-usage">Advanced Usage</a></h2>
<h3 id="custom-plugin-configuration"><a class="header" href="#custom-plugin-configuration">Custom Plugin Configuration</a></h3>
<p>Create <code>~/.config/nushell/plugin_config.nu</code>:</p>
<pre><code class="language-nushell"># Auth plugin defaults
$env.CONTROL_CENTER_URL = "https://control-center.example.com"
# KMS plugin defaults
$env.RUSTYVAULT_ADDR = "https://vault.example.com:8200"
$env.RUSTYVAULT_MOUNT = "transit"
# Orchestrator plugin defaults
$env.ORCHESTRATOR_DATA_DIR = "/opt/orchestrator/data"
</code></pre>
<h3 id="plugin-aliases"><a class="header" href="#plugin-aliases">Plugin Aliases</a></h3>
<p>Add to <code>~/.config/nushell/config.nu</code>:</p>
<pre><code class="language-nushell"># Auth shortcuts
alias login = auth login
alias logout = auth logout
# KMS shortcuts
alias encrypt = kms encrypt
alias decrypt = kms decrypt
# Orchestrator shortcuts
alias status = orch status
alias validate = orch validate
alias tasks = orch tasks
</code></pre>
<hr />
<h2 id="security-best-practices"><a class="header" href="#security-best-practices">Security Best Practices</a></h2>
<h3 id="authentication"><a class="header" href="#authentication">Authentication</a></h3>
<p><strong>DO</strong>: Use interactive password prompts
<strong>DO</strong>: Enable MFA for production environments
<strong>DO</strong>: Verify session before sensitive operations
<strong>DONT</strong>: Pass passwords in command line (visible in history)
<strong>DONT</strong>: Store tokens in plain text files</p>
<h3 id="kms-operations-1"><a class="header" href="#kms-operations-1">KMS Operations</a></h3>
<p><strong>DO</strong>: Use context (AAD) for encryption when available
<strong>DO</strong>: Rotate KMS keys regularly
<strong>DO</strong>: Use hardware-backed keys (WebAuthn, YubiKey) when possible
<strong>DONT</strong>: Share Age private keys
<strong>DONT</strong>: Log decrypted data</p>
<h3 id="orchestrator"><a class="header" href="#orchestrator">Orchestrator</a></h3>
<p><strong>DO</strong>: Validate workflows in strict mode before production
<strong>DO</strong>: Monitor task status regularly
<strong>DO</strong>: Use appropriate data directory permissions (700)
<strong>DONT</strong>: Run orchestrator as root
<strong>DONT</strong>: Expose data directory over network shares</p>
<hr />
<h2 id="faq"><a class="header" href="#faq">FAQ</a></h2>
<p><strong>Q: Why use plugins instead of HTTP API?</strong>
A: Plugins are 10x faster, have better Nushell integration, and eliminate HTTP overhead.</p>
<p><strong>Q: Can I use plugins without orchestrator running?</strong>
A: <code>auth</code> and <code>kms</code> work independently. <code>orch</code> requires access to orchestrator data directory.</p>
<p><strong>Q: How do I update plugins?</strong>
A: Rebuild and re-register: <code>cargo build --release --all &amp;&amp; plugin add target/release/nu_plugin_*</code></p>
<p><strong>Q: Are plugins cross-platform?</strong>
A: Yes, plugins work on macOS, Linux, and Windows (with appropriate keyring services).</p>
<p><strong>Q: Can I use multiple KMS backends simultaneously?</strong>
A: Yes, specify <code>--backend</code> flag for each operation.</p>
<p><strong>Q: How do I backup MFA enrollment?</strong>
A: Save backup codes securely (password manager, encrypted file). QR code can be re-scanned.</p>
<hr />
<h2 id="related-documentation"><a class="header" href="#related-documentation">Related Documentation</a></h2>
<ul>
<li><strong>Security System</strong>: <code>docs/architecture/ADR-009-security-system-complete.md</code></li>
<li><strong>JWT Auth</strong>: <code>docs/architecture/JWT_AUTH_IMPLEMENTATION.md</code></li>
<li><strong>Config Encryption</strong>: <code>docs/user/CONFIG_ENCRYPTION_GUIDE.md</code></li>
<li><strong>RustyVault Integration</strong>: <code>RUSTYVAULT_INTEGRATION_SUMMARY.md</code></li>
<li><strong>MFA Implementation</strong>: <code>docs/architecture/MFA_IMPLEMENTATION_SUMMARY.md</code></li>
</ul>
<hr />
<p><strong>Version</strong>: 1.0.0
<strong>Last Updated</strong>: 2025-10-09
<strong>Maintained By</strong>: Platform Team</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../user/extension-development.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="../user/PLUGIN_INTEGRATION_GUIDE.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/extension-development.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="../user/PLUGIN_INTEGRATION_GUIDE.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>