Angel AI Assistant
March 16, 2026โข828 words
๐ก 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