kanidm/docs/v1.0.0rc1/integrations/radius.html

352 lines
23 KiB
HTML
Raw Normal View History

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>RADIUS - Kanidm Administration</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<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" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var 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 type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="../intro.html"><strong aria-hidden="true">1.</strong> Introduction to Kanidm</a></li><li class="chapter-item expanded "><a href="../installing_the_server.html"><strong aria-hidden="true">2.</strong> Installing the Server</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../server_configuration.html"><strong aria-hidden="true">2.1.</strong> Server Configuration</a></li><li class="chapter-item expanded "><a href="../security_hardening.html"><strong aria-hidden="true">2.2.</strong> Security Hardening</a></li></ol></li><li class="chapter-item expanded "><a href="../client_tools.html"><strong aria-hidden="true">3.</strong> Client Tools</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../installing_client_tools.html"><strong aria-hidden="true">3.1.</strong> Installing client tools</a></li></ol></li><li class="chapter-item expanded "><a href="../accounts_and_groups.html"><strong aria-hidden="true">4.</strong> Accounts and Groups</a></li><li class="chapter-item expanded "><a href="../administrivia.html"><strong aria-hidden="true">5.</strong> Administrative Tasks</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../monitoring.html"><strong aria-hidden="true">5.1.</strong> Monitoring the platform</a></li><li class="chapter-item expanded "><a href="../password_quality.html"><strong aria-hidden="true">5.2.</strong> Password Quality and Badlisting</a></li><li class="chapter-item expanded "><a href="../posix_accounts.html"><strong aria-hidden="true">5.3.</strong> POSIX Accounts and Groups</a></li><li class="chapter-item expanded "><a href="../ssh_key_dist.html"><strong aria-hidden="true">5.4.</strong> SSH Key Distribution</a></li><li class="chapter-item expanded "><a href="../recycle_bin.html"><strong aria-hidden="true">5.5.</strong> The Recycle Bin</a></li><li class="chapter-item expanded "><a href="../why_tls.html"><strong aria-hidden="true">5.6.</strong> Why TLS?</a></li></ol></li><li class="chapter-item expanded "><li class="part-title">For Developers</li><li class="chapter-item expanded "><a href="../DEVELOPER_README.html"><strong aria-hidden="true">6.</strong> Developer Guide</a></li><li class="chapter-item expanded "><div><strong aria-hidden="true">7.</strong> Design Documents</div></li><li><ol class="section"><li class="chapter-item expanded "><a href="../developers/designs/access_profiles_and_security.html"><strong aria-hidden="true">7.1.</strong> Access Profiles</a></li><li class="chapter-item expanded "><a href="../developers/designs/rest_interface.html"><strong aria-hidden="true">7.2.</strong> REST Interface</a></li></ol></li><li class="chapter-item expanded "><a href="../developers/python.html"><strong aria-hidden="true">8.</strong> Python Module</a></li><li class="chapter-item expanded "><a href="../developers/radius.html"><strong aria-hidden="true">9.</strong> RADIUS Integration</a></li><li class="chapter-item expanded affix "><li class="part-title">Integrations</li><li class="chapter-item expanded "><a href="../integrations/oauth2.html"><strong aria-hidden="true">10.</strong> Oauth2</a></li><li class="chapter-item expanded "><a href="../integrations/pam_and_nsswitch.html"><strong aria-hidden="true">11.</strong> PAM and nsswitch</a></li><li class="chapter-item expanded "><a href="../integrations/radius.html" class="active"><strong aria-hidden="true">12.</strong> RADIUS</a></li><li class="chapter-item expanded "><a href="../integrations/ldap.html"><strong aria-hidden="true">13.</strong> LDAP</a></li><li class="chapter-item expanded affix "><li class="part-title">Integration Examples</li><li class="chapter-item expanded "><a href="../examples/k8s_ingress_example.html"><strong aria-hidden="true">14.</strong> Kubernetes Ingress</a></li><li class="chapter-item expanded affix "><li class="part-title">Packaging</li><li class="chapter-item expanded "><a href="../packaging.html"><strong aria-hidden="true">15.</strong> Packaging</a></li><li class="chapter-item expanded "><
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></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 bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<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="light">Light (default)</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. (Shortkey: s)" 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">Kanidm Administration</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/kanidm/kanidm" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/kanidm/kanidm/edit/master/kanidm_book/src/integrations/radius.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 type="text/javascript">
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="radius"><a class="header" href="#radius">RADIUS</a></h1>
<p>Remote Authentication Dial In User Service (RADIUS) is a network protocol
that is commonly used to authenticate Wi-Fi devices or Virtual Private
Networks (VPNs). While it should not be a sole point of trust/authentication
to an identity, it's still an important control for protecting network resources.</p>
<p>Kanidm has a philosophy that each account can have multiple credentials which
are related to their devices, and limited to specific resources. RADIUS is
no exception and has a separate credential for each account to use for
RADIUS access.</p>
<h2 id="disclaimer"><a class="header" href="#disclaimer">Disclaimer</a></h2>
<p>It's worth noting some disclaimers about Kanidm's RADIUS integration.</p>
<h3 id="one-credential---one-account"><a class="header" href="#one-credential---one-account">One Credential - One Account</a></h3>
<p>Kanidm normally attempts to have credentials for each <em>device</em> and
<em>application</em> rather than the legacy model of one to one.</p>
<p>The RADIUS protocol is only able to attest a <em>single</em> credential in an
authentication attempt, which limits us to storing a single RADIUS credential
per account. However, despite this limitation, it still greatly improves the
situation by isolating the RADIUS credential from the primary or application
credentials of the account. This solves many common security concerns around
credential loss or disclosure, and prevents rogue devices from locking out
accounts as they attempt to authenticate to Wi-Fi with expired credentials.</p>
<h3 id="cleartext-credential-storage"><a class="header" href="#cleartext-credential-storage">Cleartext Credential Storage</a></h3>
<p>RADIUS offers many different types of tunnels and authentication mechanisms.
However, most client devices &quot;out of the box&quot; only attempt a single type when
a WPA2-Enterprise network is selected: MSCHAPv2 with PEAP. This is a
challenge-response protocol that requires clear text or Windows NT LAN
Manager (NTLM) credentials.</p>
<p>As MSCHAPv2 with PEAP is the only practical, universal RADIUS-type supported
on all devices with minimal configuration, we consider it imperative
that it MUST be supported as the default. Esoteric RADIUS types can be used
as well, but this is up to administrators to test and configure.</p>
<p>Due to this requirement, we must store the RADIUS material as clear text or
NTLM hashes. It would be silly to think that NTLM is secure as it relies on
the obsolete and deprecated MD4 cryptographic hash, providing only an
illusion of security.</p>
<p>This means Kanidm stores RADIUS credentials in the database as clear text.</p>
<p>We believe this is a reasonable decision and is a low risk to security because:</p>
<ul>
<li>The access controls around RADIUS secrets by default are strong, limited
to only self-account read and RADIUS-server read.</li>
<li>As RADIUS credentials are separate from the primary account credentials and
have no other rights, their disclosure is not going to lead to a full
account compromise.</li>
<li>Having the credentials in clear text allows a better user experience as<br />
clients can view the credentials at any time to enroll further devices.</li>
</ul>
<h2 id="account-credential-configuration"><a class="header" href="#account-credential-configuration">Account Credential Configuration</a></h2>
<p>For an account to use RADIUS they must first generate a RADIUS secret unique
to that account. By default, all accounts can self-create this secret.</p>
<pre><code>kanidm account radius generate_secret --name william william
kanidm account radius show_secret --name william william
</code></pre>
<h2 id="account-group-configuration"><a class="header" href="#account-group-configuration">Account Group Configuration</a></h2>
<p>In Kanidm, accounts which can authenticate to RADIUS must be a member
of an allowed group. This allows you to define which users or groups may use
a Wi-Fi or VPN infrastructure, and provides a path for revoking access to the
resources through group management. The key point of this is that service
accounts should not be part of this group:</p>
<pre><code>kanidm group create --name idm_admin radius_access_allowed
kanidm group add_members --name idm_admin radius_access_allowed william
</code></pre>
<h2 id="radius-server-service-account"><a class="header" href="#radius-server-service-account">RADIUS Server Service Account</a></h2>
<p>To read these secrets, the RADIUS server requires an account with the
correct privileges. This can be created and assigned through the group
&quot;idm_radius_servers&quot;, which is provided by default.</p>
<p>First, create the account and add it to the group:</p>
<pre><code class="language-shell">kanidm account create --name admin radius_service_account &quot;Radius Service Account&quot;
kanidm group add_members --name admin idm_radius_servers radius_service_account
</code></pre>
<p>Now reset the account password, using the <code>admin</code> account:</p>
<pre><code class="language-shell">kanidm account credential update --name admin radius_service_account
</code></pre>
<h2 id="deploying-a-radius-container"><a class="header" href="#deploying-a-radius-container">Deploying a RADIUS Container</a></h2>
<p>We provide a RADIUS container that has all the needed integrations.
This container requires some cryptographic material, with the following files being in <code>/etc/raddb/certs</code>. (Modifiable in the configuration)</p>
<div class="table-wrapper"><table><thead><tr><th>filename</th><th>description</th></tr></thead><tbody>
<tr><td>ca.pem</td><td>The signing CA of the RADIUS certificate</td></tr>
<tr><td>dh.pem</td><td>The output of <code>openssl dhparam -in ca.pem -out ./dh.pem 2048</code></td></tr>
<tr><td>cert.pem</td><td>The certificate for the RADIUS server</td></tr>
<tr><td>key.pem</td><td>The signing key for the RADIUS certificate</td></tr>
</tbody></table>
</div>
<p>The configuration file (<code>/data/kanidm</code>) has the following template:</p>
<pre><code class="language-toml">uri = &quot;https://example.com&quot; # URL to the Kanidm server
verify_hostnames = true # verify the hostname of the Kanidm server
verify_ca = false # Strict CA verification
ca = /data/ca.pem # Path to the kanidm ca
username = # Username of the RADIUS service account
password = # Generated secret for the service account
# Default vlans for groups that don't specify one.
radius_default_vlan = 1
# A list of Kanidm groups which must be a member
# before they can authenticate via RADIUS.
radius_required_groups = [
&quot;radius_access_allowed&quot;,
]
# A mapping between Kanidm groups and VLANS
radius_groups = [
{ name = &quot;radius_access_allowed&quot;, vlan = 10 },
]
# A mapping of clients and their authentication tokens
radius_clients = [
{ name = &quot;test&quot;, ipaddr = &quot;127.0.0.1&quot;, secret = &quot;testing123&quot; },
# TODO: see if this works - it gets written out to the file
{ name = &quot;docker&quot; , ipaddr = &quot;172.17.0.0/16&quot;, secret = &quot;testing123&quot; },
]
# radius_cert_path = &quot;/etc/raddb/certs/cert.pem&quot;
# the signing key for radius TLS
# radius_key_path = &quot;/etc/raddb/certs/key.pem&quot;
# the diffie-hellman output
# radius_dh_path = &quot;/etc/raddb/certs/dh.pem&quot;
# the CA certificate
# radius_ca_path = &quot;/etc/raddb/certs/ca.pem&quot;
</code></pre>
<h2 id="a-fully-configured-example"><a class="header" href="#a-fully-configured-example">A fully configured example</a></h2>
<pre><code class="language-toml">url = &quot;https://example.com&quot;
username = &quot;radius_service_account&quot;
# The generated password from above
password = &quot;cr4bzr0ol&quot;
# default vlan for groups that don't specify one.
radius_default_vlan = 99
# if the user is in one of these Kanidm groups,
# then they're allowed to authenticate
radius_required_groups = [
&quot;radius_access_allowed&quot;,
]
radius_groups = [
{ name = &quot;radius_access_allowed&quot;, vlan = 10 }
]
radius_clients = [
{ name = &quot;localhost&quot;, ipaddr = &quot;127.0.0.1&quot;, secret = &quot;testing123&quot; },
{ name = &quot;docker&quot; , ipaddr = &quot;172.17.0.0/16&quot;, secret = &quot;testing123&quot; },
]
</code></pre>
<h2 id="moving-to-production"><a class="header" href="#moving-to-production">Moving to Production</a></h2>
<p>To expose this to a Wi-Fi infrastructure, add your NAS in the configuration:</p>
<pre><code class="language-toml">radius_clients = [
{ name = &quot;access_point&quot;, ipaddr = &quot;10.2.3.4&quot;, secret = &quot;&lt;a_random_value&gt;&quot; }
]
</code></pre>
<p>Then re-create/run your docker instance and expose the ports by adding
<code>-p 1812:1812 -p 1812:1812/udp</code> to the command.</p>
<p>If you have any issues, check the logs from the RADIUS output, as they tend
to indicate the cause of the problem. To increase the logging level you can
re-run your environment with debug enabled:</p>
<pre><code class="language-shell">docker rm radiusd
docker run --name radiusd \
-e DEBUG=True \
-p 1812:1812 \
-p 1812:1812/udp
--interactive --tty \
--volume /tmp/kanidm:/etc/raddb/certs \
kanidm/radius:latest
</code></pre>
<p>Note: the RADIUS container <em>is</em> configured to provide
<a href="https://freeradius.org/rfc/rfc2868.html#Tunnel-Private-Group-ID">Tunnel-Private-Group-ID</a>,
so if you wish to use Wi-Fi-assigned VLANs on your infrastructure, you can
assign these by groups in the configuration file as shown in the above examples.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../integrations/pam_and_nsswitch.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" href="../integrations/ldap.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="../integrations/pam_and_nsswitch.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" href="../integrations/ldap.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>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>