Angel AI Assistant

๐Ÿ›ก Home Assistant Sudo Agent

TOTP-Protected Root Command Execution via SIP Messages

Overview

The Sudo Agent is a lightweight HTTP server running on localhost (127.0.0.1:9999) that allows Home Assistant and Asterisk to execute privileged root commands securely.

It uses TOTP (Time-based One-Time Passwords) for authentication on every command.

Every command requires a fresh 6-digit PIN generated by your authenticator app.

PINs expire every 30 seconds and can never be reused.

Architecture

Linphone Message โ†’ Asterisk Dialplan โ†’ agent-wrapper.sh
โ†“
agent-message.sh
โ†“
POST localhost:9999
{pin, command}
โ†“
TOTP Verify PIN
โ†“
Execute as root
โ†“
HA Notification โ† Write result to file

Security Model

Localhost only: agent only accepts connections from 127.0.0.1

TOTP authentication: every command requires a valid time-based PIN

No PIN reuse: PINs expire every 30 seconds

Full audit log: every request logged to /var/log/sudo-agent.log

Per-job threading: long commands don't block other operations

No network exposure: port 9999 is never forwarded externally

Installation

Step 1 โ€”> Install Dependencies

pip install pyotp qrcode --break-system-packages

Step 2 โ€”> Generate TOTP Secret

python3 -c "
import pyotp
import qrcode
secret = pyotp.random_base32()
print(f'Secret: {secret}')
totp = pyotp.TOTP(secret)
uri = totp.provisioning_uri(name='your_username', issuer_name='HomeAssistant Agent')
qr = qrcode.QRCode()
qr.add_data(uri)
qr.make()
qr.print_ascii()
"

Scan the QR code with Aegis (or any TOTP app). If the QR code doesn't display correctly, manually enter the secret shown on screen.

Step 3 โ€”> Save the Secret

โš  Never delete this file โ€” the agent needs it to verify every PIN.

nano agent-secret.txt

Paste the secret and save. Protect the file:

sudo chown root:root agent-secret.txt
sudo chmod 600 agent-secret.txt

Step 4 โ€”> Verify TOTP Works


python3 -c "
import pyotp
secret = open('agent-secret.txt').read().strip()
totp = pyotp.TOTP(secret)
print(f'Current PIN: {totp.now()}')
print(f'Valid: {totp.verify(totp.now())}')
"

Confirm the PIN shown matches your authenticator app.

Step 5 โ€”> Install Agent Files

Copy the following files :

sudo-agent.py | main agent server
agent-message.sh | handles job submission and polling
agent-wrapper.sh | detaches from Asterisk SHELL()

Step 6 โ€”> Create systemd Service

sudo nano /etc/systemd/system/agent.service

Paste this:

[Unit]
Description=Sudo Agent
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /home/your_user/sudo-agent.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Reload and activate:

sudo systemctl daemon-reload
sudo systemctl enable agent
sudo systemctl start agent
sudo systemctl status agent

Usage:

Sending Commands via Linphone

Send a SIP message to Asterisk with the format:

Agent: PIN command

Examples:

Agent: 123456 uptime
Agent: 123456 df -h /
Agent: 123456 apt update
Agent: 123456 nmap -sn 192.168.1.0/24
Agent: 123456 cat /var/log/syslog | tail -20

Response Behavior

Fast commands (< 2 minutes): result returned directly via SIP message reply
Slow commands (> 2 minutes): immediate confirmation sent, result written to file, HA phone notification sent when done

For slow commands, when file is ready retrieve the result with:

Agent: PIN cat /tmp/agent-JOBID.txt

Direct API Testing

curl -s -X POST http://127.0.0.1:9999 \
-H 'Content-Type: application/json' \
-d '{"pin": "123456", "command": "whoami"}'

Check job status:

curl -s http://127.0.0.1:9999/job/JOBID

Logs

All agent activity is logged to /var/log/sudo-agent.log.

View live log:

sudo tail -f /var/log/sudo-agent.log

Example log entries:

2026-03-14 13:29:49 QUEUED [ec3da9f8]: nmap -p- 192.168.1.0/24
2026-03-14 13:29:49 EXECUTING [ec3da9f8]: nmap -p- 192.168.1.0/24
2026-03-14 13:45:12 RESULT [ec3da9f8] (rc=0): Nmap scan report...
2026-03-14 13:50:01 INVALID PIN attempt for command: uptime

File Reference

sudo-agent.py --> Main agent HTTP server runs as root via systemd

agent-message.sh --> Submits job, polls for result sends notification

agent-wrapper.sh --> Detaches agent-message.sh from Asterisk SHELL()

agent-secret.txt --> TOTP secret protected 600 owned by root

/etc/systemd/system/agent.service --> systemd service definition

/var/log/sudo-agent.log --> Full audit log of all commands and results

/tmp/agent-JOBID.txt --> Result file for long-running commands

Troubleshooting

Agent not starting

sudo systemctl status agent
sudo journalctl -u agent -n 50

Invalid PIN

Check your phone time is synced (TOTP is time-sensitive)

Verify the secret in agent-secret.txt matches Aegis

Run the TOTP verification script from Step 4

Command times out

Long running commands ( apt upgrade, etc.) will exceed the 2 minute polling window. This is expected wait for the HA phone notification with the result file path.

No phone notification received

Check HA is running: sudo systemctl status homeassistant

Check the notify service name matches your phone in agent-message.sh

Verify the HA token in secrets.yaml is valid

Known Limitations

Do not use double quotes " in Agent commands use single quotes ' instead

Commands run with no timeout be careful with commands that could run indefinitely

Job results stored in memory restarting the agent clears job history

Result files in /tmp are not automatically cleaned up

โš  Add a cron job to clean old result files:

find /tmp -name 'agent-*.txt' -mtime +1 -delete

You can use Linphone point to your Asterisk and control your computer and the HA

from anywhere via messages.

For free no ads no clouds.


You'll only receive email when they publish something new.

More from Carlostkd โœ…
All posts