Asterisk Security Hardening Checklist
Working through a hardening review on a live system, or want a second set of eyes before you make changes? Get in touch about a consulting engagement.
Asterisk Security Hardening Checklist
An internet-facing Asterisk system gets scanned within hours of going live. That is normal, not a sign you have been specifically targeted. What matters is whether a scanner or brute-force attempt can actually get anywhere. This checklist walks through the layers that matter, in the order they should stop an attacker: network, authentication, dialplan, and the management interfaces most guides forget about.
Each item links to the full snippet or reference entry with the actual configuration. This page is the map, not the manual for any one piece.
On this page
Network layer: stop it before authentication
- [ ] Deny-by-default ACLs on every PJSIPThe modern SIP channel driver in Asterisk (chan_pjsip), replacing the older chan_sip. Configured in pjsip.conf using endpoints, AORs, auths, and transports. transport and endpoint. An ACL that blocks everything except known ranges (your LAN, your SIP trunk provider's IPs) stops scanners before Asterisk even attempts to parse credentials. See PJSIP IP ACL.
- [ ] fail2ban watching Asterisk's security log. ACLs handle known-bad and unknown sources; fail2ban catches brute-force attempts coming from ranges you had to leave open (a SIP trunk provider's pool, a remote-worker VPN range). See Fail2ban for Asterisk, or the Debian 12+ without rsyslog variant if you are not running rsyslog.
- [ ] A way to see what fail2ban is actually catching. A jail nobody looks at is a jail nobody trusts. See fail2ban-stats for a quick report across active jails.
- [ ] TLS for signaling, SRTP for media, on anything that leaves a trusted network. Plaintext SIP over the internet exposes credentials and call content to anyone who can see the traffic. See Let's Encrypt TLS Certificates for Asterisk PJSIP and TLS Certificate Generation.
Authentication and endpoint identification
- [ ] No unintentional anonymous or catch-all endpoints. PJSIP does not have a
chan_sip-styleallowguestsetting that defaults to accepting unauthenticated calls. By design, any request that does not match a configured endpoint is handed to an internal artificial endpoint and rejected, it is not silently accepted. The real risk in PJSIP is the inverse: anidentifysection or endpoint matching too broad a range (an entire/16, ormatch=0.0.0.0/0) that ends up accepting traffic from anyone. Audit everyidentifyand endpoint match for scope creep. - [ ] No enumeration path for valid extensions.
chan_siphadalwaysauthrejectas an option you had to turn on to avoid leaking which usernames existed by responding differently to a valid vs. invalid account. PJSIP does not need the option: unmatched requests always get the same artificial-endpoint rejection, so there is nothing to misconfigure here. This is one case where the platform closed the gap for you, but it is worth knowing why the option does not exist rather than wondering if you are missing a step. - [ ] Strong, unique, generated secrets per endpoint. Twenty-plus random characters, not a word plus a number. Reused or short secrets are the single most common way a PBX gets pwned for toll fraud.
- [ ]
qualifyor registration-based reachability checks, so a compromised or misbehaving endpoint that stops responding gets flagged rather than silently sitting in a bad state.
Dialplan hygiene
- [ ] Never interpolate untrusted values into
System(),Shell(), or AGI calls without sanitizing them first.${EXTEN},${CALLERID(num)}, and DTMF-derived variables can all contain characters that mean something to a shell if you build a command string from them directly. Validate the pattern (a dialplan_NXXNXXXXXXmatch already constrains${EXTEN}more than you might think, but do not assume every variable is that constrained) before it reaches a shell-executing application. - [ ] Separate inbound contexts per trunk, per tenant, and per trust level. A context that receives calls from a SIP trunk provider should never also permit outbound dialing or reach internal-only extensions. See Dialplan Contexts, Extensions, and Priorities for the underlying model, and note the recurring pattern in trunk configuration guides: route trunk traffic to something like
[from-trunk], never[internal]. - [ ] Restrict international and premium-rate dialing by default, and require an explicit opt-in (a class of service, a specific context, an account flag) to enable it per endpoint. Toll fraud almost always routes through a dialplan that will place any outbound call an authenticated (or accidentally unauthenticated) endpoint asks for.
Management interfaces (AMI, ARI, the admin surfaces people forget)
- [ ] AMI bound to localhost or a trusted management network only, with
read/writepermissions scoped to what each integration actually needs, not a blanket admin user reused everywhere. AMI has no built-in rate limiting of its own. See AMI Configuration and Event Classes. - [ ] ARI treated as an administrative interface, because it is one. It can disrupt live calls and originate outbound traffic on your behalf. The ARI getting started guide's security checklist covers this in full; the short version is localhost by default, unique credentials per app, and TLS or a private network for anything that has to leave the host.
- [ ] The Asterisk HTTP server (
http.conf) locked down the same way as ARI, since ARI, static file serving, phone auto-provisioning (res_phoneprov), and other HTTP-served features all share that one listener. - [ ] Features that grant privileged access reviewed for exposure, not just left at their example config. Direct Inward System Access (DISA) is the classic case: it is meant to let an authorized caller dial back in and get a fresh dialtone, but a DISA extension reachable without a PIN, or a weak PIN, is a direct toll-fraud door.
Keep it that way
- [ ] Review ACLs, fail2ban jail status, and endpoint secrets on a schedule, not just when something breaks. A permit rule added for a one-time test and never removed is exactly the kind of gap that sits unnoticed for months.
- [ ] Watch for scanning as background noise, not an emergency. Constant SIP scanning and credential-stuffing traffic against port 5060 (and non-standard ports, once scanners find them) is the normal state of anything reachable on the internet. The goal of everything above is making sure that traffic bounces off ACLs and fail2ban before it ever reaches an authentication attempt that matters. If you are watching your logs and seeing zero scan traffic, check that logging is actually working, do not assume you are being ignored.
Related
- PJSIP IP ACL
- Fail2ban for Asterisk
- fail2ban for Asterisk on Debian with systemd (No rsyslog)
- Fail2ban reporting with fail2ban-stats
- Let's Encrypt TLS Certificates for Asterisk PJSIP
- TLS Certificate Generation
- AMI Configuration and Event Classes
- Getting Started with Asterisk ARI: Build Your First App
- Dialplan Contexts, Extensions, and Priorities
- DISA with Security Warnings
User Notes
Know a tip or gotcha for this topic? Share it below and help others.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.