690 lines
34 KiB
HTML
690 lines
34 KiB
HTML
|
|
<!DOCTYPE HTML>
|
|||
|
|
<html lang="en" class="ayu sidebar-visible" dir="ltr">
|
|||
|
|
<head>
|
|||
|
|
<!-- Book generated using mdBook -->
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<title>Authentication Layer 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/AUTHENTICATION_LAYER_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="authentication-layer-implementation-guide"><a class="header" href="#authentication-layer-implementation-guide">Authentication Layer Implementation Guide</a></h1>
|
|||
|
|
<p><strong>Version</strong>: 1.0.0
|
|||
|
|
<strong>Date</strong>: 2025-10-09
|
|||
|
|
<strong>Status</strong>: Production Ready</p>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
|
|||
|
|
<p>A comprehensive authentication layer has been integrated into the provisioning system to secure sensitive operations. The system uses <code>nu_plugin_auth</code> for JWT authentication with MFA support, providing enterprise-grade security with graceful user experience.</p>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="key-features"><a class="header" href="#key-features">Key Features</a></h2>
|
|||
|
|
<h3 id="-jwt-authentication"><a class="header" href="#-jwt-authentication">✅ <strong>JWT Authentication</strong></a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li>RS256 asymmetric signing</li>
|
|||
|
|
<li>Access tokens (15min) + refresh tokens (7d)</li>
|
|||
|
|
<li>OS keyring storage (macOS Keychain, Windows Credential Manager, Linux Secret Service)</li>
|
|||
|
|
</ul>
|
|||
|
|
<h3 id="-mfa-support"><a class="header" href="#-mfa-support">✅ <strong>MFA Support</strong></a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li>TOTP (Google Authenticator, Authy)</li>
|
|||
|
|
<li>WebAuthn/FIDO2 (YubiKey, Touch ID)</li>
|
|||
|
|
<li>Required for production and destructive operations</li>
|
|||
|
|
</ul>
|
|||
|
|
<h3 id="-security-policies"><a class="header" href="#-security-policies">✅ <strong>Security Policies</strong></a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li><strong>Production environment</strong>: Requires authentication + MFA</li>
|
|||
|
|
<li><strong>Destructive operations</strong>: Requires authentication + MFA (delete, destroy)</li>
|
|||
|
|
<li><strong>Development/test</strong>: Requires authentication, allows skip with flag</li>
|
|||
|
|
<li><strong>Check mode</strong>: Always bypasses authentication (dry-run operations)</li>
|
|||
|
|
</ul>
|
|||
|
|
<h3 id="-audit-logging"><a class="header" href="#-audit-logging">✅ <strong>Audit Logging</strong></a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li>All authenticated operations logged</li>
|
|||
|
|
<li>User, timestamp, operation details</li>
|
|||
|
|
<li>MFA verification status</li>
|
|||
|
|
<li>JSON format for easy parsing</li>
|
|||
|
|
</ul>
|
|||
|
|
<h3 id="-user-friendly-error-messages"><a class="header" href="#-user-friendly-error-messages">✅ <strong>User-Friendly Error Messages</strong></a></h3>
|
|||
|
|
<ul>
|
|||
|
|
<li>Clear instructions for login/MFA</li>
|
|||
|
|
<li>Distinct error types (platform auth vs provider auth)</li>
|
|||
|
|
<li>Helpful guidance for setup</li>
|
|||
|
|
</ul>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="quick-start"><a class="header" href="#quick-start">Quick Start</a></h2>
|
|||
|
|
<h3 id="1-login-to-platform"><a class="header" href="#1-login-to-platform">1. Login to Platform</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Interactive login (password prompt)
|
|||
|
|
provisioning auth login <username>
|
|||
|
|
|
|||
|
|
# Save credentials to keyring
|
|||
|
|
provisioning auth login <username> --save
|
|||
|
|
|
|||
|
|
# Custom control center URL
|
|||
|
|
provisioning auth login admin --url http://control.example.com:9080
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="2-enroll-mfa-first-time"><a class="header" href="#2-enroll-mfa-first-time">2. Enroll MFA (First Time)</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Enroll TOTP (Google Authenticator)
|
|||
|
|
provisioning auth mfa enroll totp
|
|||
|
|
|
|||
|
|
# Scan QR code with authenticator app
|
|||
|
|
# Or enter secret manually
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="3-verify-mfa-for-sensitive-operations"><a class="header" href="#3-verify-mfa-for-sensitive-operations">3. Verify MFA (For Sensitive Operations)</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Get 6-digit code from authenticator app
|
|||
|
|
provisioning auth mfa verify --code 123456
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="4-check-authentication-status"><a class="header" href="#4-check-authentication-status">4. Check Authentication Status</a></h3>
|
|||
|
|
<pre><code class="language-bash"># View current authentication status
|
|||
|
|
provisioning auth status
|
|||
|
|
|
|||
|
|
# Verify token is valid
|
|||
|
|
provisioning auth verify
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="protected-operations"><a class="header" href="#protected-operations">Protected Operations</a></h2>
|
|||
|
|
<h3 id="server-operations"><a class="header" href="#server-operations">Server Operations</a></h3>
|
|||
|
|
<pre><code class="language-bash"># ✅ CREATE - Requires auth (prod: +MFA)
|
|||
|
|
provisioning server create web-01 # Auth required
|
|||
|
|
provisioning server create web-01 --check # Auth skipped (check mode)
|
|||
|
|
|
|||
|
|
# ❌ DELETE - Requires auth + MFA
|
|||
|
|
provisioning server delete web-01 # Auth + MFA required
|
|||
|
|
provisioning server delete web-01 --check # Auth skipped (check mode)
|
|||
|
|
|
|||
|
|
# 📖 READ - No auth required
|
|||
|
|
provisioning server list # No auth required
|
|||
|
|
provisioning server ssh web-01 # No auth required
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="task-service-operations"><a class="header" href="#task-service-operations">Task Service Operations</a></h3>
|
|||
|
|
<pre><code class="language-bash"># ✅ CREATE - Requires auth (prod: +MFA)
|
|||
|
|
provisioning taskserv create kubernetes # Auth required
|
|||
|
|
provisioning taskserv create kubernetes --check # Auth skipped
|
|||
|
|
|
|||
|
|
# ❌ DELETE - Requires auth + MFA
|
|||
|
|
provisioning taskserv delete kubernetes # Auth + MFA required
|
|||
|
|
|
|||
|
|
# 📖 READ - No auth required
|
|||
|
|
provisioning taskserv list # No auth required
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="cluster-operations"><a class="header" href="#cluster-operations">Cluster Operations</a></h3>
|
|||
|
|
<pre><code class="language-bash"># ✅ CREATE - Requires auth (prod: +MFA)
|
|||
|
|
provisioning cluster create buildkit # Auth required
|
|||
|
|
provisioning cluster create buildkit --check # Auth skipped
|
|||
|
|
|
|||
|
|
# ❌ DELETE - Requires auth + MFA
|
|||
|
|
provisioning cluster delete buildkit # Auth + MFA required
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="batch-workflows"><a class="header" href="#batch-workflows">Batch Workflows</a></h3>
|
|||
|
|
<pre><code class="language-bash"># ✅ SUBMIT - Requires auth (prod: +MFA)
|
|||
|
|
provisioning batch submit workflow.k # Auth required
|
|||
|
|
provisioning batch submit workflow.k --skip-auth # Auth skipped (if allowed)
|
|||
|
|
|
|||
|
|
# 📖 READ - No auth required
|
|||
|
|
provisioning batch list # No auth required
|
|||
|
|
provisioning batch status <task-id> # No auth required
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="configuration"><a class="header" href="#configuration">Configuration</a></h2>
|
|||
|
|
<h3 id="security-settings-configdefaultstoml"><a class="header" href="#security-settings-configdefaultstoml">Security Settings (<code>config.defaults.toml</code>)</a></h3>
|
|||
|
|
<pre><code class="language-toml">[security]
|
|||
|
|
require_auth = true # Enable authentication system
|
|||
|
|
require_mfa_for_production = true # MFA for prod environment
|
|||
|
|
require_mfa_for_destructive = true # MFA for delete operations
|
|||
|
|
auth_timeout = 3600 # Token timeout (1 hour)
|
|||
|
|
audit_log_path = "{{paths.base}}/logs/audit.log"
|
|||
|
|
|
|||
|
|
[security.bypass]
|
|||
|
|
allow_skip_auth = false # Allow PROVISIONING_SKIP_AUTH env var
|
|||
|
|
|
|||
|
|
[plugins]
|
|||
|
|
auth_enabled = true # Enable nu_plugin_auth
|
|||
|
|
|
|||
|
|
[platform.control_center]
|
|||
|
|
url = "http://localhost:9080" # Control center URL
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="environment-specific-configuration"><a class="header" href="#environment-specific-configuration">Environment-Specific Configuration</a></h3>
|
|||
|
|
<pre><code class="language-toml"># Development
|
|||
|
|
[environments.dev]
|
|||
|
|
security.bypass.allow_skip_auth = true # Allow auth bypass in dev
|
|||
|
|
|
|||
|
|
# Production
|
|||
|
|
[environments.prod]
|
|||
|
|
security.bypass.allow_skip_auth = false # Never allow bypass
|
|||
|
|
security.require_mfa_for_production = true
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="authentication-bypass-devtest-only"><a class="header" href="#authentication-bypass-devtest-only">Authentication Bypass (Dev/Test Only)</a></h2>
|
|||
|
|
<h3 id="environment-variable-method"><a class="header" href="#environment-variable-method">Environment Variable Method</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Export environment variable (dev/test only)
|
|||
|
|
export PROVISIONING_SKIP_AUTH=true
|
|||
|
|
|
|||
|
|
# Run operations without authentication
|
|||
|
|
provisioning server create web-01
|
|||
|
|
|
|||
|
|
# Unset when done
|
|||
|
|
unset PROVISIONING_SKIP_AUTH
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="per-command-flag"><a class="header" href="#per-command-flag">Per-Command Flag</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Some commands support --skip-auth flag
|
|||
|
|
provisioning batch submit workflow.k --skip-auth
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="check-mode-always-bypasses-auth"><a class="header" href="#check-mode-always-bypasses-auth">Check Mode (Always Bypasses Auth)</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Check mode is always allowed without auth
|
|||
|
|
provisioning server create web-01 --check
|
|||
|
|
provisioning taskserv create kubernetes --check
|
|||
|
|
</code></pre>
|
|||
|
|
<p>⚠️ <strong>WARNING</strong>: Auth bypass should ONLY be used in development/testing environments. Production systems should have <code>security.bypass.allow_skip_auth = false</code>.</p>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="error-messages"><a class="header" href="#error-messages">Error Messages</a></h2>
|
|||
|
|
<h3 id="not-authenticated"><a class="header" href="#not-authenticated">Not Authenticated</a></h3>
|
|||
|
|
<pre><code>❌ Authentication Required
|
|||
|
|
|
|||
|
|
Operation: server create web-01
|
|||
|
|
You must be logged in to perform this operation.
|
|||
|
|
|
|||
|
|
To login:
|
|||
|
|
provisioning auth login <username>
|
|||
|
|
|
|||
|
|
Note: Your credentials will be securely stored in the system keyring.
|
|||
|
|
</code></pre>
|
|||
|
|
<p><strong>Solution</strong>: Run <code>provisioning auth login <username></code></p>
|
|||
|
|
<hr />
|
|||
|
|
<h3 id="mfa-required"><a class="header" href="#mfa-required">MFA Required</a></h3>
|
|||
|
|
<pre><code>❌ MFA Verification Required
|
|||
|
|
|
|||
|
|
Operation: server delete web-01
|
|||
|
|
Reason: destructive operation (delete/destroy)
|
|||
|
|
|
|||
|
|
To verify MFA:
|
|||
|
|
1. Get code from your authenticator app
|
|||
|
|
2. Run: provisioning auth mfa verify --code <6-digit-code>
|
|||
|
|
|
|||
|
|
Don't have MFA set up?
|
|||
|
|
Run: provisioning auth mfa enroll totp
|
|||
|
|
</code></pre>
|
|||
|
|
<p><strong>Solution</strong>: Run <code>provisioning auth mfa verify --code 123456</code></p>
|
|||
|
|
<hr />
|
|||
|
|
<h3 id="token-expired"><a class="header" href="#token-expired">Token Expired</a></h3>
|
|||
|
|
<pre><code>❌ Authentication Required
|
|||
|
|
|
|||
|
|
Operation: server create web-02
|
|||
|
|
You must be logged in to perform this operation.
|
|||
|
|
|
|||
|
|
Error: Token verification failed
|
|||
|
|
</code></pre>
|
|||
|
|
<p><strong>Solution</strong>: Token expired, re-login with <code>provisioning auth login <username></code></p>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="audit-logging"><a class="header" href="#audit-logging">Audit Logging</a></h2>
|
|||
|
|
<p>All authenticated operations are logged to the audit log file with the following information:</p>
|
|||
|
|
<pre><code class="language-json">{
|
|||
|
|
"timestamp": "2025-10-09 14:32:15",
|
|||
|
|
"user": "admin",
|
|||
|
|
"operation": "server_create",
|
|||
|
|
"details": {
|
|||
|
|
"hostname": "web-01",
|
|||
|
|
"infra": "production",
|
|||
|
|
"environment": "prod",
|
|||
|
|
"orchestrated": false
|
|||
|
|
},
|
|||
|
|
"mfa_verified": true
|
|||
|
|
}
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="viewing-audit-logs"><a class="header" href="#viewing-audit-logs">Viewing Audit Logs</a></h3>
|
|||
|
|
<pre><code class="language-bash"># View raw audit log
|
|||
|
|
cat provisioning/logs/audit.log
|
|||
|
|
|
|||
|
|
# Filter by user
|
|||
|
|
cat provisioning/logs/audit.log | jq '. | select(.user == "admin")'
|
|||
|
|
|
|||
|
|
# Filter by operation type
|
|||
|
|
cat provisioning/logs/audit.log | jq '. | select(.operation == "server_create")'
|
|||
|
|
|
|||
|
|
# Filter by date
|
|||
|
|
cat provisioning/logs/audit.log | jq '. | select(.timestamp | startswith("2025-10-09"))'
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="integration-with-control-center"><a class="header" href="#integration-with-control-center">Integration with Control Center</a></h2>
|
|||
|
|
<p>The authentication system integrates with the provisioning platform’s control center REST API:</p>
|
|||
|
|
<ul>
|
|||
|
|
<li><strong>POST /api/auth/login</strong> - Login with credentials</li>
|
|||
|
|
<li><strong>POST /api/auth/logout</strong> - Revoke tokens</li>
|
|||
|
|
<li><strong>POST /api/auth/verify</strong> - Verify token validity</li>
|
|||
|
|
<li><strong>GET /api/auth/sessions</strong> - List active sessions</li>
|
|||
|
|
<li><strong>POST /api/mfa/enroll</strong> - Enroll MFA device</li>
|
|||
|
|
<li><strong>POST /api/mfa/verify</strong> - Verify MFA code</li>
|
|||
|
|
</ul>
|
|||
|
|
<h3 id="starting-control-center"><a class="header" href="#starting-control-center">Starting Control Center</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Start control center (required for authentication)
|
|||
|
|
cd provisioning/platform/control-center
|
|||
|
|
cargo run --release
|
|||
|
|
</code></pre>
|
|||
|
|
<p>Or use the orchestrator which includes control center:</p>
|
|||
|
|
<pre><code class="language-bash">cd provisioning/platform/orchestrator
|
|||
|
|
./scripts/start-orchestrator.nu --background
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="testing-authentication"><a class="header" href="#testing-authentication">Testing Authentication</a></h2>
|
|||
|
|
<h3 id="manual-testing"><a class="header" href="#manual-testing">Manual Testing</a></h3>
|
|||
|
|
<pre><code class="language-bash"># 1. Start control center
|
|||
|
|
cd provisioning/platform/control-center
|
|||
|
|
cargo run --release &
|
|||
|
|
|
|||
|
|
# 2. Login
|
|||
|
|
provisioning auth login admin
|
|||
|
|
|
|||
|
|
# 3. Try creating server (should succeed if authenticated)
|
|||
|
|
provisioning server create test-server --check
|
|||
|
|
|
|||
|
|
# 4. Logout
|
|||
|
|
provisioning auth logout
|
|||
|
|
|
|||
|
|
# 5. Try creating server (should fail - not authenticated)
|
|||
|
|
provisioning server create test-server --check
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="automated-testing"><a class="header" href="#automated-testing">Automated Testing</a></h3>
|
|||
|
|
<pre><code class="language-bash"># Run authentication tests
|
|||
|
|
nu provisioning/core/nulib/lib_provisioning/plugins/auth_test.nu
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
|
|||
|
|
<h3 id="plugin-not-available"><a class="header" href="#plugin-not-available">Plugin Not Available</a></h3>
|
|||
|
|
<p><strong>Error</strong>: <code>Authentication plugin not available</code></p>
|
|||
|
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
<ol>
|
|||
|
|
<li>Check plugin is built: <code>ls provisioning/core/plugins/nushell-plugins/nu_plugin_auth/target/release/</code></li>
|
|||
|
|
<li>Register plugin: <code>plugin add target/release/nu_plugin_auth</code></li>
|
|||
|
|
<li>Use plugin: <code>plugin use auth</code></li>
|
|||
|
|
<li>Verify: <code>which auth</code></li>
|
|||
|
|
</ol>
|
|||
|
|
<hr />
|
|||
|
|
<h3 id="control-center-not-running"><a class="header" href="#control-center-not-running">Control Center Not Running</a></h3>
|
|||
|
|
<p><strong>Error</strong>: <code>Cannot connect to control center</code></p>
|
|||
|
|
<p><strong>Solution</strong>:</p>
|
|||
|
|
<ol>
|
|||
|
|
<li>Start control center: <code>cd provisioning/platform/control-center && cargo run --release</code></li>
|
|||
|
|
<li>Or use orchestrator: <code>cd provisioning/platform/orchestrator && ./scripts/start-orchestrator.nu --background</code></li>
|
|||
|
|
<li>Check URL is correct in config: <code>provisioning config get platform.control_center.url</code></li>
|
|||
|
|
</ol>
|
|||
|
|
<hr />
|
|||
|
|
<h3 id="mfa-not-working"><a class="header" href="#mfa-not-working">MFA Not Working</a></h3>
|
|||
|
|
<p><strong>Error</strong>: <code>Invalid MFA code</code></p>
|
|||
|
|
<p><strong>Solutions</strong>:</p>
|
|||
|
|
<ul>
|
|||
|
|
<li>Ensure time is synchronized (TOTP codes are time-based)</li>
|
|||
|
|
<li>Code expires every 30 seconds, get fresh code</li>
|
|||
|
|
<li>Verify you’re using the correct authenticator app entry</li>
|
|||
|
|
<li>Re-enroll if needed: <code>provisioning auth mfa enroll totp</code></li>
|
|||
|
|
</ul>
|
|||
|
|
<hr />
|
|||
|
|
<h3 id="keyring-access-issues"><a class="header" href="#keyring-access-issues">Keyring Access Issues</a></h3>
|
|||
|
|
<p><strong>Error</strong>: <code>Keyring storage unavailable</code></p>
|
|||
|
|
<p><strong>macOS</strong>: Grant Keychain access to Terminal/iTerm2 in System Preferences → Security & Privacy</p>
|
|||
|
|
<p><strong>Linux</strong>: Ensure <code>gnome-keyring</code> or <code>kwallet</code> is running</p>
|
|||
|
|
<p><strong>Windows</strong>: Check Windows Credential Manager is accessible</p>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="architecture"><a class="header" href="#architecture">Architecture</a></h2>
|
|||
|
|
<h3 id="authentication-flow"><a class="header" href="#authentication-flow">Authentication Flow</a></h3>
|
|||
|
|
<pre><code>┌─────────────┐
|
|||
|
|
│ User Command│
|
|||
|
|
└──────┬──────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Infrastructure Command Handler │
|
|||
|
|
│ (infrastructure.nu) │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Auth Check │
|
|||
|
|
│ - Determine operation type │
|
|||
|
|
│ - Check if auth required │
|
|||
|
|
│ - Check environment (prod/dev) │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Auth Plugin Wrapper │
|
|||
|
|
│ (auth.nu) │
|
|||
|
|
│ - Call plugin or HTTP fallback │
|
|||
|
|
│ - Verify token validity │
|
|||
|
|
│ - Check MFA if required │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ nu_plugin_auth │
|
|||
|
|
│ - JWT verification (RS256) │
|
|||
|
|
│ - Keyring token storage │
|
|||
|
|
│ - MFA verification │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Control Center API │
|
|||
|
|
│ - /api/auth/verify │
|
|||
|
|
│ - /api/mfa/verify │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Operation Execution │
|
|||
|
|
│ (servers/create.nu, etc.) │
|
|||
|
|
└──────┬──────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────┐
|
|||
|
|
│ Audit Logging │
|
|||
|
|
│ - Log to audit.log │
|
|||
|
|
│ - Include user, timestamp, MFA │
|
|||
|
|
└─────────────────────────────────┘
|
|||
|
|
</code></pre>
|
|||
|
|
<h3 id="file-structure"><a class="header" href="#file-structure">File Structure</a></h3>
|
|||
|
|
<pre><code>provisioning/
|
|||
|
|
├── config/
|
|||
|
|
│ └── config.defaults.toml # Security configuration
|
|||
|
|
├── core/nulib/
|
|||
|
|
│ ├── lib_provisioning/plugins/
|
|||
|
|
│ │ └── auth.nu # Auth wrapper (550 lines)
|
|||
|
|
│ ├── servers/
|
|||
|
|
│ │ └── create.nu # Server ops with auth
|
|||
|
|
│ ├── workflows/
|
|||
|
|
│ │ └── batch.nu # Batch workflows with auth
|
|||
|
|
│ └── main_provisioning/commands/
|
|||
|
|
│ └── infrastructure.nu # Infrastructure commands with auth
|
|||
|
|
├── core/plugins/nushell-plugins/
|
|||
|
|
│ └── nu_plugin_auth/ # Native Rust plugin
|
|||
|
|
│ ├── src/
|
|||
|
|
│ │ ├── main.rs # Plugin implementation
|
|||
|
|
│ │ └── helpers.rs # Helper functions
|
|||
|
|
│ └── README.md # Plugin documentation
|
|||
|
|
├── platform/control-center/ # Control Center (Rust)
|
|||
|
|
│ └── src/auth/ # JWT auth implementation
|
|||
|
|
└── logs/
|
|||
|
|
└── audit.log # Audit trail
|
|||
|
|
</code></pre>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="related-documentation"><a class="header" href="#related-documentation">Related Documentation</a></h2>
|
|||
|
|
<ul>
|
|||
|
|
<li><strong>Security System Overview</strong>: <code>docs/architecture/ADR-009-security-system-complete.md</code></li>
|
|||
|
|
<li><strong>JWT Authentication</strong>: <code>docs/architecture/JWT_AUTH_IMPLEMENTATION.md</code></li>
|
|||
|
|
<li><strong>MFA Implementation</strong>: <code>docs/architecture/MFA_IMPLEMENTATION_SUMMARY.md</code></li>
|
|||
|
|
<li><strong>Plugin README</strong>: <code>provisioning/core/plugins/nushell-plugins/nu_plugin_auth/README.md</code></li>
|
|||
|
|
<li><strong>Control Center</strong>: <code>provisioning/platform/control-center/README.md</code></li>
|
|||
|
|
</ul>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="summary-of-changes"><a class="header" href="#summary-of-changes">Summary of Changes</a></h2>
|
|||
|
|
<div class="table-wrapper"><table><thead><tr><th>File</th><th>Changes</th><th>Lines Added</th></tr></thead><tbody>
|
|||
|
|
<tr><td><code>lib_provisioning/plugins/auth.nu</code></td><td>Added security policy enforcement functions</td><td>+260</td></tr>
|
|||
|
|
<tr><td><code>config/config.defaults.toml</code></td><td>Added security configuration section</td><td>+19</td></tr>
|
|||
|
|
<tr><td><code>servers/create.nu</code></td><td>Added auth check for server creation</td><td>+25</td></tr>
|
|||
|
|
<tr><td><code>workflows/batch.nu</code></td><td>Added auth check for batch workflow submission</td><td>+43</td></tr>
|
|||
|
|
<tr><td><code>main_provisioning/commands/infrastructure.nu</code></td><td>Added auth checks for all infrastructure commands</td><td>+90</td></tr>
|
|||
|
|
<tr><td><code>lib_provisioning/providers/interface.nu</code></td><td>Added authentication guidelines for providers</td><td>+65</td></tr>
|
|||
|
|
<tr><td><strong>Total</strong></td><td><strong>6 files modified</strong></td><td><strong>~500 lines</strong></td></tr>
|
|||
|
|
</tbody></table>
|
|||
|
|
</div>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h2>
|
|||
|
|
<h3 id="for-users"><a class="header" href="#for-users">For Users</a></h3>
|
|||
|
|
<ol>
|
|||
|
|
<li><strong>Always login</strong>: Keep your session active to avoid interruptions</li>
|
|||
|
|
<li><strong>Use keyring</strong>: Save credentials with <code>--save</code> flag for persistence</li>
|
|||
|
|
<li><strong>Enable MFA</strong>: Use MFA for production operations</li>
|
|||
|
|
<li><strong>Check mode first</strong>: Always test with <code>--check</code> before actual operations</li>
|
|||
|
|
<li><strong>Monitor audit logs</strong>: Review audit logs regularly for security</li>
|
|||
|
|
</ol>
|
|||
|
|
<h3 id="for-developers"><a class="header" href="#for-developers">For Developers</a></h3>
|
|||
|
|
<ol>
|
|||
|
|
<li><strong>Check auth early</strong>: Verify authentication before expensive operations</li>
|
|||
|
|
<li><strong>Log operations</strong>: Always log authenticated operations for audit</li>
|
|||
|
|
<li><strong>Clear error messages</strong>: Provide helpful guidance for auth failures</li>
|
|||
|
|
<li><strong>Respect check mode</strong>: Always skip auth in check/dry-run mode</li>
|
|||
|
|
<li><strong>Test both paths</strong>: Test with and without authentication</li>
|
|||
|
|
</ol>
|
|||
|
|
<h3 id="for-operators"><a class="header" href="#for-operators">For Operators</a></h3>
|
|||
|
|
<ol>
|
|||
|
|
<li><strong>Production hardening</strong>: Set <code>allow_skip_auth = false</code> in production</li>
|
|||
|
|
<li><strong>MFA enforcement</strong>: Require MFA for all production environments</li>
|
|||
|
|
<li><strong>Monitor audit logs</strong>: Set up log monitoring and alerts</li>
|
|||
|
|
<li><strong>Token rotation</strong>: Configure short token timeouts (15min default)</li>
|
|||
|
|
<li><strong>Backup authentication</strong>: Ensure multiple admins have MFA enrolled</li>
|
|||
|
|
</ol>
|
|||
|
|
<hr />
|
|||
|
|
<h2 id="license"><a class="header" href="#license">License</a></h2>
|
|||
|
|
<p>MIT License - See LICENSE file for details</p>
|
|||
|
|
<hr />
|
|||
|
|
<p><strong>Last Updated</strong>: 2025-10-09
|
|||
|
|
<strong>Maintained By</strong>: Security Team</p>
|
|||
|
|
|
|||
|
|
</main>
|
|||
|
|
|
|||
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|||
|
|
<!-- Mobile navigation buttons -->
|
|||
|
|
<a rel="prev" href="../user/troubleshooting-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="../user/AUTH_QUICK_REFERENCE.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/troubleshooting-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="../user/AUTH_QUICK_REFERENCE.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>
|