towerops/lib/towerops_web/live/help_live/sections/mikrotik.ex
Graham McInitre 9d4a5f6d81 refactor: comprehensive simplification and functional programming improvements
- help_live/index.ex: 2,642→173 lines, 15 section modules + sidebar extracted
  MikroTik now real section, dead if false removed
- agent_channel.ex: 2,506→1,751 lines, 3 helper modules extracted
  (heartbeat/subscriptions/job_builder), decode_and_process/4 eliminates
  8 repeated handle_in patterns, guard-based size checks
- antenna_catalog.ex: 1,174→47 lines, 107 specs → priv/antennas/catalog.json
- topology.ex: unbounded query → batched loading (100/batch),
  all guard errors fixed, zero if/case/cond conditionals
- proto: decoder_macros.ex + field_specs.ex infrastructure for
  macro-generated protobuf decoders
2026-07-21 17:03:47 -05:00

334 lines
15 KiB
Elixir

defmodule ToweropsWeb.HelpLive.Sections.Mikrotik do
@moduledoc false
use ToweropsWeb, :html
import ToweropsWeb.HelpLive.Sections.Helpers
def render(assigns) do
~H"""
<div class="p-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-4">MikroTik Configuration</h2>
<div class="prose prose-sm dark:prose-invert max-w-none">
<p class="text-gray-600 dark:text-gray-400">
Towerops supports read-only monitoring of MikroTik RouterOS devices via SSH.
In addition to SNMP polling, SSH access allows Towerops to retrieve detailed system information
and create configuration backups of your MikroTik devices for disaster recovery and audit purposes.
</p>
<div class="mt-4 space-y-4">
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
<div class="flex gap-3">
<.icon
name="hero-information-circle"
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
/>
<div>
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
Read-Only Access
</h4>
<p class="text-sm text-blue-800 dark:text-blue-300">
Towerops currently operates in read-only mode for MikroTik devices. Configuration changes,
reboots, and other administrative actions are not supported. This ensures your device
configurations remain unchanged by monitoring operations.
</p>
</div>
</div>
</div>
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
<div class="flex gap-3">
<.icon
name="hero-server"
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
/>
<div>
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
Cloud or Agent-Based Connections
</h4>
<p class="text-sm text-blue-800 dark:text-blue-300">
Both SNMP polling and SSH connections to MikroTik devices can be performed from either
Towerops cloud infrastructure or your remote poller (agent). For publicly accessible devices,
cloud polling is the simplest option. For devices on private networks or when you prefer
to keep SSH credentials on your local network, deploy a remote poller. The device assignment
determines which poller handles both SNMP and SSH operations.
</p>
</div>
</div>
</div>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
Security Best Practices
</h3>
<p class="text-gray-600 dark:text-gray-400">
For security purposes, it is strongly recommended to create a dedicated read-only user account
for Towerops rather than using an administrator account. This follows the principle of least
privilege and minimizes potential security risks. Even though Towerops only performs read-only
operations, limiting the account permissions provides defense in depth.
</p>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-6 mb-3">
Creating a Read-Only User
</h3>
<p class="text-gray-600 dark:text-gray-400">
Connect to your MikroTik device via SSH or terminal and execute the following commands to
create a read-only user named <.code>towerops</.code>:
</p>
<div class="mt-4 space-y-3">
<div>
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
Step 1: Create a new user group with read-only permissions
</p>
<div class="p-4 bg-black rounded-lg not-prose">
<div class="flex items-start gap-2">
<code class="text-sm text-white font-mono break-all flex-1">
/user group add name=readonly policy=ssh,read,test,api
</code>
<button
type="button"
phx-click={JS.dispatch("phx:copy", to: "#step1-command")}
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
title="Copy to clipboard"
>
<.icon name="hero-clipboard-document" class="h-4 w-4" />
</button>
<input
type="hidden"
id="step1-command"
value="/user group add name=readonly policy=ssh,read,test,api"
/>
</div>
</div>
</div>
<div>
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
Step 2: Create the monitoring user with a strong password
</p>
<div class="p-4 bg-black rounded-lg not-prose">
<div class="flex items-start gap-2">
<code class="text-sm text-white font-mono break-all flex-1">
/user add name=towerops password={if @generated_password,
do: @generated_password,
else: "YOUR_STRONG_PASSWORD"} group=readonly
</code>
<%= if @generated_password do %>
<button
type="button"
phx-click={JS.dispatch("phx:copy", to: "#generated-password-value")}
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
title="Copy to clipboard"
>
<.icon name="hero-clipboard-document" class="h-4 w-4" />
</button>
<input type="hidden" id="generated-password-value" value={@generated_password} />
<% end %>
</div>
</div>
<div class="mt-3 flex items-start gap-3">
<.button
type="button"
phx-click="generate_password"
disabled={@password_generating}
>
<%= if @password_generating do %>
<.icon name="hero-arrow-path" class="h-4 w-4 mr-1 animate-spin" /> Generating...
<% else %>
<.icon name="hero-sparkles" class="h-4 w-4 mr-1" /> Regenerate Random Password
<% end %>
</.button>
<%= if @generated_password do %>
<p class="text-xs text-yellow-600 dark:text-yellow-400 font-medium mt-1.5">
⚠️ This truly random password from random.org will only be shown once!
</p>
<% end %>
</div>
</div>
<div>
<p class="text-sm text-gray-700 dark:text-gray-300 mb-2 font-medium">
Step 3: Verify the user was created successfully
</p>
<div class="p-4 bg-black rounded-lg not-prose">
<div class="flex items-start gap-2">
<code class="text-sm text-white font-mono break-all flex-1">
/user print detail where name=towerops
</code>
<button
type="button"
phx-click={JS.dispatch("phx:copy", to: "#step3-command")}
class="flex-shrink-0 p-1 text-blue-400 hover:text-blue-300"
title="Copy to clipboard"
>
<.icon name="hero-clipboard-document" class="h-4 w-4" />
</button>
<input
type="hidden"
id="step3-command"
value="/user print detail where name=towerops"
/>
</div>
</div>
</div>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
Permissions Explained
</h3>
<p class="text-gray-600 dark:text-gray-400">
The
<.code>readonly</.code>
group includes the following permissions. Note that while these
permissions are granted to the user account, Towerops only performs read operations and does
not make any configuration changes:
</p>
<div class="mt-4 bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
<table class="min-w-full divide-y divide-gray-200 dark:divide-white/10">
<thead class="bg-gray-50 dark:bg-gray-800/75">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Permission
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Description
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-white/10">
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
ssh
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Allow SSH access to the device
</td>
</tr>
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
read
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Allow viewing configuration and status (read-only)
</td>
</tr>
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
test
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Allow executing diagnostic commands (ping, traceroute, etc.)
</td>
</tr>
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900 dark:text-white">
api
</td>
<td class="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Allow API access for automated monitoring
</td>
</tr>
</tbody>
</table>
</div>
<div class="mt-6 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
<div class="flex gap-3">
<.icon
name="hero-information-circle"
class="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5"
/>
<div>
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-300 mb-1">
Important Notes
</h4>
<ul class="text-sm text-blue-800 dark:text-blue-300 space-y-1 list-disc list-inside">
<li>The read-only user cannot modify device configuration</li>
<li>No write, reboot, or sensitive permissions are granted</li>
<li>Use a strong, unique password for the monitoring account</li>
<li>Consider restricting SSH access by source IP if possible</li>
</ul>
</div>
</div>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mt-8 mb-3">
Configuring in Towerops
</h3>
<p class="text-gray-600 dark:text-gray-400">
After creating the read-only user, configure SSH credentials in Towerops:
</p>
<div class="mt-4 space-y-4">
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
Organization-Level Configuration
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">
Navigate to
<.code>Organization Settings</.code>
<.code>MikroTik tab</.code>
to set default
SSH credentials for all MikroTik devices in your organization.
</p>
</div>
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
Site-Level Configuration
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">
Navigate to
<.code>Sites</.code>
→ select a site →
<.code>Edit</.code>
to override
credentials for all devices at a specific location.
</p>
</div>
<div class="p-4 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-white/10 rounded-lg">
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">
Device-Level Configuration
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">
When editing a MikroTik device, you can specify unique SSH credentials that override
organization and site defaults.
</p>
</div>
</div>
<div class="mt-6 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
<div class="flex gap-3">
<.icon
name="hero-shield-check"
class="h-5 w-5 text-yellow-600 dark:text-yellow-400 flex-shrink-0 mt-0.5"
/>
<div>
<h4 class="text-sm font-semibold text-yellow-900 dark:text-yellow-300 mb-1">
Security Recommendations
</h4>
<ul class="text-sm text-yellow-800 dark:text-yellow-300 space-y-1 list-disc list-inside">
<li>Always use SSL/TLS for SSH connections (API-SSL on port 8729)</li>
<li>Store credentials at the organization or site level when possible</li>
<li>Rotate passwords periodically following your security policies</li>
<li>Monitor access logs for unauthorized SSH connection attempts</li>
<li>
Consider using SSH keys instead of passwords (if supported by your setup)
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
"""
end
end