From 0261e875679f1bf63c8d689da7fc7e014597885d Mon Sep 17 00:00:00 2001 From: Stonewall Jackson Date: Sat, 4 Feb 2023 01:23:43 -0500 Subject: initial commit --- roles/asterisk/defaults/main.yml | 74 ++++++++++++++++++++ .../system/asterisk.service.d/override.conf | 6 ++ roles/asterisk/handlers/main.yml | 9 +++ roles/asterisk/meta/main.yml | 4 ++ roles/asterisk/tasks/main.yml | 81 ++++++++++++++++++++++ roles/asterisk/templates/etc/asterisk/ari.conf.j2 | 11 +++ .../templates/etc/asterisk/extensions.conf.j2 | 7 ++ roles/asterisk/templates/etc/asterisk/http.conf.j2 | 13 ++++ .../asterisk/templates/etc/asterisk/logger.conf.j2 | 3 + .../asterisk/templates/etc/asterisk/pjsip.conf.j2 | 28 ++++++++ .../templates/etc/asterisk/pjsip_wizard.conf.j2 | 57 +++++++++++++++ .../asterisk/templates/etc/asterisk/queues.conf.j2 | 46 ++++++++++++ roles/asterisk/templates/etc/asterisk/rtp.conf.j2 | 3 + .../templates/etc/asterisk/voicemail.conf.j2 | 37 ++++++++++ roles/asterisk/vars/main.yml | 20 ++++++ 15 files changed, 399 insertions(+) create mode 100644 roles/asterisk/defaults/main.yml create mode 100644 roles/asterisk/files/etc/systemd/system/asterisk.service.d/override.conf create mode 100644 roles/asterisk/handlers/main.yml create mode 100644 roles/asterisk/meta/main.yml create mode 100644 roles/asterisk/tasks/main.yml create mode 100644 roles/asterisk/templates/etc/asterisk/ari.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/extensions.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/http.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/logger.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/pjsip.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/pjsip_wizard.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/queues.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/rtp.conf.j2 create mode 100644 roles/asterisk/templates/etc/asterisk/voicemail.conf.j2 create mode 100644 roles/asterisk/vars/main.yml (limited to 'roles/asterisk') diff --git a/roles/asterisk/defaults/main.yml b/roles/asterisk/defaults/main.yml new file mode 100644 index 0000000..e7e5b74 --- /dev/null +++ b/roles/asterisk/defaults/main.yml @@ -0,0 +1,74 @@ +asterisk_local_nets: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + +asterisk_timezone: '{{ timezone }}' +asterisk_locale: en_US.UTF-8 + +asterisk_fqdn: '{{ ansible_fqdn }}' +asterisk_from_domain: '{{ email_domain }}' + +asterisk_rtp_port_start: 10000 +asterisk_rtp_port_end: 10999 +asterisk_sip_port: 5060 +asterisk_sip_tls_port: 5061 + +asterisk_http_port: 8088 +asterisk_https_port: 8089 + +asterisk_voicemail_formats: + - wav49 + - gsm + - wav + +asterisk_mail_from: asterisk-noreply@{{ email_domain }} + +asterisk_voicemail_email_subject: 'New voicemail ${VM_MSGNUM} in mailbox ${VM_MAILBOX}' +asterisk_voicemail_email_body: 'Hi ${VM_NAME},\n\nYou have a new voicemail in mailbox ${VM_MAILBOX}.\n\nFrom: ${VM_CALLERID}\nDate: ${VM_DATE}\nDuration: ${VM_DUR}\nMessage Number: ${VM_MSGNUM}' +asterisk_voicemail_email_date_format: '%A, %B %d, %Y at %r' +asterisk_voicemail_min_password: 4 + +asterisk_voicemail_max_message_count: 100 +asterisk_voicemail_max_message_secs: 300 +asterisk_voicemail_max_greeting_secs: 60 +asterisk_voicemail_max_failed_logins: 3 + +asterisk_sip_trunks: + - name: example + host: sip.example.com:5061 + codecs: g722,ulaw + username: testuser + password: testpass + transport: tls + media_encryption: sdes + +asterisk_sip_extensions: + - name: 6001 + context: from-internal + mailbox: 6001@default + cid_name: Test User + username: 6001 + password: testpassword + codecs: g722,ulaw + +asterisk_queues: + - name: home + strategy: ringall + retry: 1 + timeout: 30 + members: + - 6001 + - 6002 + +asterisk_ari_users: + - name: nagios + password: nagios + readonly: yes + +asterisk_voicemail_contexts: + default: + - address: 6001 + password: 1234 + name: John Doe + email: john@example.com diff --git a/roles/asterisk/files/etc/systemd/system/asterisk.service.d/override.conf b/roles/asterisk/files/etc/systemd/system/asterisk.service.d/override.conf new file mode 100644 index 0000000..88f8d60 --- /dev/null +++ b/roles/asterisk/files/etc/systemd/system/asterisk.service.d/override.conf @@ -0,0 +1,6 @@ +[Unit] +After=nss-lookup.target network-online.target + +[Service] +Restart=on-failure +RestartSec=4 diff --git a/roles/asterisk/handlers/main.yml b/roles/asterisk/handlers/main.yml new file mode 100644 index 0000000..b2d74af --- /dev/null +++ b/roles/asterisk/handlers/main.yml @@ -0,0 +1,9 @@ +- name: reload asterisk + systemd: + name: asterisk + state: reloaded + +- name: restart asterisk + systemd: + name: asterisk + state: restarted diff --git a/roles/asterisk/meta/main.yml b/roles/asterisk/meta/main.yml new file mode 100644 index 0000000..29230f9 --- /dev/null +++ b/roles/asterisk/meta/main.yml @@ -0,0 +1,4 @@ +dependencies: + - role: yum + yum_repositories: epel + tags: yum diff --git a/roles/asterisk/tasks/main.yml b/roles/asterisk/tasks/main.yml new file mode 100644 index 0000000..7bb259d --- /dev/null +++ b/roles/asterisk/tasks/main.yml @@ -0,0 +1,81 @@ +- name: install packages + dnf: + name: '{{ asterisk_packages }}' + state: present + +- name: create systemd override directory + file: + path: /etc/systemd/system/asterisk.service.d + state: directory + +- name: create systemd unit override + copy: + src: etc/systemd/system/asterisk.service.d/override.conf + dest: /etc/systemd/system/asterisk.service.d/override.conf + notify: restart asterisk + register: asterisk_unit + +- name: reload systemd units + systemd: + daemon_reload: yes + when: asterisk_unit.changed + +- name: download sound files + unarchive: + src: '{{ item.url }}' + remote_src: yes + dest: /usr/share/asterisk/sounds + creates: '/usr/share/asterisk/sounds/hello-world.{{ item.codec }}' + loop: "{{ asterisk_sound_tarballs | dict2items(key_name='codec', value_name='url') }}" + +- name: request public TLS certificate + include_role: + name: certbot + vars: + certificate_sans: ['{{ asterisk_fqdn }}'] + certificate_path: '{{ asterisk_certificate_path }}' + certificate_key_path: '{{ asterisk_certificate_key_path }}' + certificate_owner: asterisk + certificate_hook: systemctl reload asterisk + +- name: request internal HTTPS certificate + include_role: + name: getcert_request + vars: + certificate_sans: ['{{ ansible_fqdn }}'] + certificate_path: '{{ asterisk_https_certificate_path }}' + certificate_key_path: '{{ asterisk_https_certificate_key_path }}' + certificate_owner: asterisk + certificate_hook: systemctl reload asterisk + +- name: generate config files + template: + src: '{{ item.src }}' + dest: /etc/asterisk/{{ item.path | splitext | first }} + owner: asterisk + group: asterisk + mode: 0640 + loop: "{{ lookup('filetree', '../templates/etc/asterisk', wantlist=True) }}" + when: item.state == 'file' + notify: reload asterisk + +- name: open firewall ports + firewalld: + permanent: yes + immediate: yes + port: '{{ item }}' + state: enabled + loop: + - '{{ asterisk_https_port }}/tcp' + - '{{ asterisk_sip_port }}/tcp' + - '{{ asterisk_sip_port }}/udp' + - '{{ asterisk_sip_tls_port }}/tcp' + - '{{ asterisk_sip_tls_port }}/udp' + - '{{ asterisk_rtp_port_start }}-{{ asterisk_rtp_port_end }}/udp' + tags: firewalld + +- name: start asterisk + systemd: + name: asterisk + enabled: yes + state: started diff --git a/roles/asterisk/templates/etc/asterisk/ari.conf.j2 b/roles/asterisk/templates/etc/asterisk/ari.conf.j2 new file mode 100644 index 0000000..cc853c4 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/ari.conf.j2 @@ -0,0 +1,11 @@ +[general] +enabled = yes +pretty = no + +{% for user in asterisk_ari_users %} +[{{ user.name }}] +type = user +read_only = {{ 'yes' if (user.readonly | default(true)) else 'no' }} +password = {{ user.password | password_hash('sha512', asterisk_password_salt, rounds=5000) }} +password_format = crypt +{% endfor %} diff --git a/roles/asterisk/templates/etc/asterisk/extensions.conf.j2 b/roles/asterisk/templates/etc/asterisk/extensions.conf.j2 new file mode 100644 index 0000000..09345cf --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/extensions.conf.j2 @@ -0,0 +1,7 @@ +[public] +exten => _X.,1,Hangup(3) + +[default] +exten => _X.,1,Hangup(3) + +{{ asterisk_dialplan }} diff --git a/roles/asterisk/templates/etc/asterisk/http.conf.j2 b/roles/asterisk/templates/etc/asterisk/http.conf.j2 new file mode 100644 index 0000000..d9d92a1 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/http.conf.j2 @@ -0,0 +1,13 @@ +[general] +servername = Asterisk +enabled = yes +bindaddr = 127.0.0.1 +bindport = {{ asterisk_http_port }} +enable_status = no +tlsenable = yes +tlsbindaddr = 0.0.0.0:{{ asterisk_https_port }} +tlscertfile = {{ asterisk_https_certificate_path }} +tlsprivatekey = {{ asterisk_https_certificate_key_path }} +tlsdisablev1 = yes +tlsdisablev11 = yes +tlsdisablev12 = no diff --git a/roles/asterisk/templates/etc/asterisk/logger.conf.j2 b/roles/asterisk/templates/etc/asterisk/logger.conf.j2 new file mode 100644 index 0000000..65595d1 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/logger.conf.j2 @@ -0,0 +1,3 @@ +[logfiles] +console => verbose(3),notice,warning,error +messages => verbose(3),notice,warning,error diff --git a/roles/asterisk/templates/etc/asterisk/pjsip.conf.j2 b/roles/asterisk/templates/etc/asterisk/pjsip.conf.j2 new file mode 100644 index 0000000..d7dedf8 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/pjsip.conf.j2 @@ -0,0 +1,28 @@ +[transport-defaults](!) +type = transport +bind = 0.0.0.0 +local_net = 127.0.0.0/8 +{% for cidr in asterisk_local_nets %} +local_net = {{ cidr }} +{% endfor %} +{% if asterisk_external_ip is defined %} +external_media_address = {{ asterisk_external_ip }} +external_signaling_address = {{ asterisk_external_ip }} +{% endif %} + +[transport-udp](transport-defaults) +protocol = udp + +[transport-tcp](transport-defaults) +protocol = tcp + +[transport-tls](transport-defaults) +protocol = tls +bind = 0.0.0.0:5061 +method = tlsv1_2 +cert_file = {{ asterisk_certificate_path }} +priv_key_file = {{ asterisk_certificate_key_path }} +ca_list_file = {{ asterisk_ca_file }} +verify_client = no +verify_server = yes +allow_reload = yes diff --git a/roles/asterisk/templates/etc/asterisk/pjsip_wizard.conf.j2 b/roles/asterisk/templates/etc/asterisk/pjsip_wizard.conf.j2 new file mode 100644 index 0000000..67a6574 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/pjsip_wizard.conf.j2 @@ -0,0 +1,57 @@ +;;;;;;;;;;; +; Trunks +;;;;;;;;;;; + +[trunk-defaults](!) +type = wizard +sends_auth = yes +sends_registrations = yes +endpoint/rtp_symmetric = yes +endpoint/rewrite_contact = yes +endpoint/send_rpid = yes +endpoint/from_domain = {{ asterisk_from_domain }} +endpoint/allow = !all,ulaw +aor/qualify_frequency = 30 + +{% for trunk in asterisk_sip_trunks %} +[{{ trunk.name }}](trunk-defaults) +transport = transport-{{ trunk.transport | default('udp') }} +remote_hosts = {{ trunk.host if trunk.host is string else (trunk.host | join(',')) }} +endpoint/context = from-{{ trunk.name }} +{% if trunk.codecs is defined %} +endpoint/allow = !all,{{ trunk.codecs if trunk.codecs is string else (trunk.codecs | join(',')) }} +{% endif %} +endpoint/media_encryption = {{ trunk.media_encryption | default('no') }} +outbound_auth/username = {{ trunk.username }} +outbound_auth/password = {{ trunk.password }} + +{% endfor %} + + +;;;;;;;;;;;;; +; Extensions +;;;;;;;;;;;;; + +[extension-defaults](!) +type = wizard +accepts_registrations = yes +accepts_auth = yes +aor/remove_existing = yes +aor/qualify_frequency = 30 +endpoint/allow = !all,g722,ulaw +endpoint/from_domain = {{ asterisk_from_domain }} +endpoint/subscribe_context = subscribe + +{% for ext in asterisk_sip_extensions %} +[{{ ext.name }}](extension-defaults) +{% if ext.codecs is defined %} +endpoint/allow = !all,{{ ext.codecs if ext.codecs is string else (ext.codecs | join(',')) }} +{% endif %} +endpoint/context = {{ ext.context }} +endpoint/mailboxes = {{ ext.mailbox if ext.mailbox is string else (ext.mailbox | join(',')) }} +endpoint/callerid = {{ ext.cid_name }} <{{ ext.cid_number | default(ext.name) }}> +inbound_auth/username = {{ ext.username | default(ext.name) }} +inbound_auth/password = {{ ext.password }} +aor/max_contacts = {{ ext.max_contacts | default(1) }} + +{% endfor %} diff --git a/roles/asterisk/templates/etc/asterisk/queues.conf.j2 b/roles/asterisk/templates/etc/asterisk/queues.conf.j2 new file mode 100644 index 0000000..badecfb --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/queues.conf.j2 @@ -0,0 +1,46 @@ +[general] +persistentmembers = yes +autofill = yes +monitor-type = MixMonitor +shared_lastcall = yes +log_membername_as_agent = yes + + +{% for queue in asterisk_queues %} +[{{ queue.name }}] +{% if queue.music_class is defined %} +musicclass = {{ queue.music_class }} +{% endif %} +strategy = {{ queue.strategy }} +{% if queue.context is defined %} +context = {{ queue.context }} +{% endif %} +timeout = {{ queue.timeout | default(15) }} +retry = {{ queue.retry | default(5) }} +timeoutpriority = app +{% if queue.weight is defined %} +weight = {{ queue.weight }} +{% endif %} +{% if queue.maxlen is defined %} +maxlen = {{ queue.maxlen }} +{% endif %} +announce-frequency = {{ queue.announce_frequency | default(0) }} +min-announce-frequency = {{ queue.min_announce_frequency | default(15) }} +announce-holdtime = {{ queue.announce_holdtime | default('no') }} +announce-position = {{ queue.announce_position | default('no') }} +periodic-announce-frequency = {{ queue.periodic_announce_frequency | default(0) }} +{% if queue.peridic_announce is defined %} +periodic-announce = {{ queue.periodic_announce if queue.periodic_announce is string else (queue.periodic_announce | join(',')) }} +{% endif %} +{% if queue.monitor_format is defined %} +monitor-format = {{ queue.monitor_format if queue.monitor_format is string else (queue.montior_format | join('|')) }} +{% endif %} +joinempty = {{ queue.join_empty | default('yes') }} +leavewhenempty = {{ queue.leave_when_empty | default('no') }} +ringinuse = {{ 'yes' if (queue.ring_in_use | default(true)) else 'no' }} +timeoutrestart = yes +{% for ext in queue.members %} +member => PJSIP/{{ ext }},0,{{ asterisk_sip_extensions | selectattr('name', '==', ext) | map(attribute='cid_name') | first | default('') }},PJSIP/{{ ext }} +{% endfor %} + +{% endfor %} diff --git a/roles/asterisk/templates/etc/asterisk/rtp.conf.j2 b/roles/asterisk/templates/etc/asterisk/rtp.conf.j2 new file mode 100644 index 0000000..3d4edc2 --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/rtp.conf.j2 @@ -0,0 +1,3 @@ +[general] +rtpstart={{ asterisk_rtp_port_start }} +rtpend={{ asterisk_rtp_port_end }} diff --git a/roles/asterisk/templates/etc/asterisk/voicemail.conf.j2 b/roles/asterisk/templates/etc/asterisk/voicemail.conf.j2 new file mode 100644 index 0000000..32b4d0a --- /dev/null +++ b/roles/asterisk/templates/etc/asterisk/voicemail.conf.j2 @@ -0,0 +1,37 @@ +[general] +format={{ asterisk_voicemail_formats | join('|') }} + +serveremail={{ asterisk_mail_from }} +attach=yes +; Maximum number of messages per folder +maxmsg={{ asterisk_voicemail_max_message_count }} +; Maximum length of a voicemail message in seconds +maxsecs={{ asterisk_voicemail_max_message_secs }} +; Minimum length of a voicemail message in seconds for the message to be kept +maxgreet={{ asterisk_voicemail_max_greeting_secs }} +; How many milliseconds to skip forward/back when rew/ff in message playback +skipms=3000 +; How many seconds of silence before we end the recording +maxsilence=10 +; Silence threshold (what we consider silence: the lower, the more sensitive) +silencethreshold=128 +; Max number of failed login attempts +maxlogins={{ asterisk_voicemail_max_failed_logins }} + +emailsubject={{ asterisk_voicemail_email_subject }} +emailbody={{ asterisk_voicemail_email_body }} +emaildateformat={{ asterisk_voicemail_email_date_format }} + +tz=myzone +locale={{ asterisk_locale }} +minpassword={{ asterisk_voicemail_min_password }} + +[zonemessages] +myzone={{ asterisk_timezone }}|'vm-received' Q 'digits/at' IMp + +{% for item in asterisk_voicemail_contexts | dict2items(key_name='context', value_name='mailboxes') %} +[{{ item.context }}] +{% for mailbox in item.mailboxes %} +{{ mailbox.address }} => {{ mailbox.password }},{{ mailbox.name }},{{ mailbox.email if mailbox.email is string else (mailbox.email | join('|')) }},,, +{% endfor %} +{% endfor %} diff --git a/roles/asterisk/vars/main.yml b/roles/asterisk/vars/main.yml new file mode 100644 index 0000000..c4bf58a --- /dev/null +++ b/roles/asterisk/vars/main.yml @@ -0,0 +1,20 @@ +asterisk_packages: + - asterisk + - asterisk-pjsip + - asterisk-voicemail-plain + +asterisk_sound_tarballs: + g722: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-g722-current.tar.gz + g729: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-g729-current.tar.gz + gsm: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-gsm-current.tar.gz + sln16: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-sln16-current.tar.gz + ulaw: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-ulaw-current.tar.gz + wav: https://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-wav-current.tar.gz + +asterisk_certificate_path: /etc/asterisk/asterisk.crt +asterisk_certificate_key_path: /etc/asterisk/asterisk.key +asterisk_https_certificate_path: /etc/pki/tls/certs/asterisk-https.crt +asterisk_https_certificate_key_path: /etc/pki/tls/private/asterisk-https.key +asterisk_ca_file: /etc/pki/tls/certs/ca-bundle.crt + +asterisk_data_dir: /var/spool/asterisk -- cgit