From 2e094ddbabc78bde20e2b6e6bbd899a55f37218e Mon Sep 17 00:00:00 2001 From: HgO Date: Thu, 21 May 2020 22:15:33 +0200 Subject: [PATCH] create mumble role --- defaults/main.yml | 26 ++++++++++ handlers/main.yml | 23 +++++++++ handlers/nginx.yml | 7 +++ meta/main.yml | 59 +++++++++++++++++++++ tasks/main.yml | 11 ++++ tasks/mumble_web.yml | 78 ++++++++++++++++++++++++++++ tasks/nginx.yml | 18 +++++++ tasks/umurmur.yml | 91 +++++++++++++++++++++++++++++++++ templates/mumble-web.js.j2 | 23 +++++++++ templates/mumble-web.service.j2 | 16 ++++++ templates/nginx.conf.j2 | 65 +++++++++++++++++++++++ templates/umurmur.conf.j2 | 72 ++++++++++++++++++++++++++ templates/umurmur.service.j2 | 16 ++++++ 13 files changed, 505 insertions(+) create mode 100644 defaults/main.yml create mode 100644 handlers/main.yml create mode 100644 handlers/nginx.yml create mode 100644 meta/main.yml create mode 100644 tasks/main.yml create mode 100644 tasks/mumble_web.yml create mode 100644 tasks/nginx.yml create mode 100644 tasks/umurmur.yml create mode 100644 templates/mumble-web.js.j2 create mode 100644 templates/mumble-web.service.j2 create mode 100644 templates/nginx.conf.j2 create mode 100644 templates/umurmur.conf.j2 create mode 100644 templates/umurmur.service.j2 diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..4e170b2 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,26 @@ +umurmur_user_password: "" +umurmur_channel_links: +- source: "{{ umurmur_default_channel }}" + destinations: >- + {{ umurmur_channels + | selectattr('parent', 'defined') + | selectattr('parent', '==', umurmur_default_channel) + | map(attribute='name') + | list + }} +umurmur_ssl_group: "{{ acme_ssl_group }}" +umurmur_certificate: "{{ acme_certs_dir }}/{{ umurmur_domain }}.d/fullchain.pem" +umurmur_private_key: "{{ acme_keys_dir }}/{{ umurmur_domain }}.pem" +umurmur_version: master +umurmur_ispublic: yes +umurmur_port: "64738" + +mumble_web_owner: mumble-web +mumble_web_group: "{{ mumble_web_owner }}" +mumble_web_certificate: "{{ acme_certs_dir }}/{{ mumble_web_domain }}.d/fullchain.pem" +mumble_web_trusted_certificate: "{{ acme_certs_dir }}/{{ mumble_web_domain }}.d/chain.pem" +mumble_web_private_key: "{{ acme_keys_dir }}/{{ mumble_web_domain }}.pem" +mumble_web_dhparam: "/etc/nginx/ssl/dhparam.pem" +mumble_web_www_dir: /var/www/mumble-web +mumble_web_version: master +mumble_web_websockify_port: "64737" \ No newline at end of file diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..bb55ed2 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,23 @@ +- name: reload systemd + systemd: + daemon_reload: yes + register: systemd_reloaded + +# In order to take into account rooms config changes, umurmur must be restarted. +# A simple reload won't work for rooms positionning, for instance. +- name: restart umurmur + service: + name: umurmur + state: restarted + when: + - not (umurmur_started.changed | default(false)) + +- name: reload mumble-web + service: + name: mumble-web + state: reloaded + when: + - not (mumble_web_started.changed | default(false)) + +- name: reload nginx + include_tasks: ../handlers/nginx.yml \ No newline at end of file diff --git a/handlers/nginx.yml b/handlers/nginx.yml new file mode 100644 index 0000000..b8dc381 --- /dev/null +++ b/handlers/nginx.yml @@ -0,0 +1,7 @@ +- name: Validate Nginx config + command: nginx -t + +- name: Reload Nginx server + service: + name: nginx + state: reloaded \ No newline at end of file diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..a5650b1 --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,59 @@ + +dependencies: +- role: acme + tags: [acme] +- role: geerlingguy.nodejs + vars: + nodejs_install_npm_user: root + tags: [nodejs,mumble_web] + +galaxy_info: + role_name: mumble + author: HgO + description: Ansible role to install umurmur, the minimalistic Mumble server, and mumble-web client. + company: PPBe + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Some suggested licenses: + # - BSD (default) + # - MIT + # - GPLv2 + # - GPLv3 + # - Apache + # - CC-BY + license: GPLv3 + + min_ansible_version: 2.9 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # Optionally specify the branch Galaxy will use when accessing the GitHub + # repo for this role. During role install, if no tags are available, + # Galaxy will use this branch. During import Galaxy will access files on + # this branch. If Travis integration is configured, only notifications for this + # branch will be accepted. Otherwise, in all cases, the repo's default branch + # (usually master) will be used. + #github_branch: + + # + # platforms is a list of platforms, and each platform has a name and a list of versions. + # + platforms: + - name: Ubuntu + versions: + - all + - name: Debian + versions: + - all + + galaxy_tags: [mumble,voip,umurmur] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..ead630d --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,11 @@ +- name: Install and configure umurmur server + import_tasks: umurmur.yml + tags: umurmur + +- name: Install and configure mumble web client + import_tasks: mumble_web.yml + tags: mumble_web + +- name: Configure Nginx for mumble web client + import_tasks: nginx.yml + tags: nginx \ No newline at end of file diff --git a/tasks/mumble_web.yml b/tasks/mumble_web.yml new file mode 100644 index 0000000..df835a9 --- /dev/null +++ b/tasks/mumble_web.yml @@ -0,0 +1,78 @@ +- name: Install websockify + apt: + name: websockify + state: present + notify: reload mumble-web + tags: mumble_web_install + +- name: Create mumble-web system user + user: + name: "{{ mumble_web_owner }}" + home: "{{ mumble_web_www_dir }}" + groups: + - www-data + shell: /sbin/nologin + password: '*' + state: present + system: yes + append: yes + create_home: no + +- name: Change mumble-web home directory's permissions + file: + path: "{{ mumble_web_www_dir }}" + owner: "{{ mumble_web_owner }}" + group: "{{ mumble_web_group }}" + mode: "755" + state: directory + tags: mumble_web_install + +- name: Clone mumble-web git repository + git: + repo: https://github.com/Johni0702/mumble-web.git + dest: "{{ mumble_web_www_dir }}" + version: "{{ mumble_web_version }}" + register: mumble_web_cloned + become_user: "{{ mumble_web_owner }}" + tags: mumble_web_install + +- name: Build mumble-web from sources + command: npm clean-install + args: + chdir: "{{ mumble_web_www_dir }}" + register: _mumble_web_installed + become_user: "{{ mumble_web_owner }}" + when: mumble_web_cloned is changed + tags: [mumble_web_install,mumble_web_build] + +- name: Copy mumble-web config file + template: + src: mumble-web.js.j2 + dest: "{{ mumble_web_www_dir }}/dist/config.local.js" + owner: "{{ mumble_web_owner }}" + group: "{{ mumble_web_group }}" + mode: "644" + tags: [mumble_web_install,mumble_web_config] + +- name: Copy mumble-web systemd service + template: + src: mumble-web.service.j2 + dest: /etc/systemd/system/mumble-web.service + owner: root + group: root + mode: "644" + notify: + - reload systemd + - reload mumble-web + tags: [mumble_web_install,mumble_web_config] + +- name: Start mumble-web service + service: + name: mumble-web + state: started + enabled: yes + register: mumble_web_started + tags: mumble_web_run + +- name: Trigger mumble-web handlers + meta: flush_handlers \ No newline at end of file diff --git a/tasks/nginx.yml b/tasks/nginx.yml new file mode 100644 index 0000000..5e89113 --- /dev/null +++ b/tasks/nginx.yml @@ -0,0 +1,18 @@ +- name: Copy Nginx config file + template: + src: nginx.conf.j2 + dest: /etc/nginx/sites-available/mumble.conf + owner: root + group: www-data + mode: "755" + notify: reload nginx + +- name: Enable Nginx config file + file: + src: /etc/nginx/sites-available/mumble.conf + path: /etc/nginx/sites-enabled/mumble.conf + state: link + notify: reload nginx + +- name: Trigger Nginx handlers + meta: flush_handlers \ No newline at end of file diff --git a/tasks/umurmur.yml b/tasks/umurmur.yml new file mode 100644 index 0000000..2996b35 --- /dev/null +++ b/tasks/umurmur.yml @@ -0,0 +1,91 @@ +- name: Install umurmur build dependencies + apt: + name: "{{ package }}" + loop: + - git + - build-essential + - cmake + - libconfig-dev + - libprotobuf-c-dev + - libmbedtls-dev + - ssl-cert + loop_control: + loop_var: package + +- name: Clone umurmur git repository + git: + repo: https://github.com/umurmur/umurmur.git + dest: /opt/umurmur + version: "{{ umurmur_version }}" + +- name: Change umurmur git repository's permissions + file: + path: /opt/umurmur + owner: root + group: root + mode: "775" + state: directory + +- name: Create the build directory + file: + path: /opt/umurmur/build + owner: root + group: root + mode: "775" + state: directory + +- name: Generate the Makefile with cmake + shell: cd /opt/umurmur/build && cmake .. -DSSL=mbedtls + changed_when: no + +- name: Build umurmur from source + make: + chdir: /opt/umurmur/build + changed_when: _umurmur_built.stdout_lines | length > 1 + register: _umurmur_built + +- name: Install umurmur + make: + chdir: /opt/umurmur/build + target: install + changed_when: "'Installing' in _umurmur_installed.stdout" + register: _umurmur_installed + notify: restart umurmur + +- name: Copy umurmur config file + template: + src: umurmur.conf.j2 + dest: /usr/local/etc/umurmur.conf + owner: root + group: "{{ umurmur_ssl_group }}" + mode: "640" + validate: /usr/local/bin/umurmurd -t -c %s + notify: restart umurmur + tags: umurmur_config + +- name: Copy umurmur systemd service + template: + src: umurmur.service.j2 + dest: /etc/systemd/system/umurmur.service + owner: root + group: root + mode: "644" + notify: + - reload systemd + - restart umurmur + +- name: Start umurmur service + service: + name: umurmur + enabled: yes + state: started + register: umurmur_started + +- name: Trigger umurmur handlers + meta: flush_handlers + +- name: Open umurmur port with UFW + ufw: + rule: allow + port: "{{ umurmur_port }}" + when: umurmur_ispublic | bool \ No newline at end of file diff --git a/templates/mumble-web.js.j2 b/templates/mumble-web.js.j2 new file mode 100644 index 0000000..b18d954 --- /dev/null +++ b/templates/mumble-web.js.j2 @@ -0,0 +1,23 @@ +{{ ansible_managed | comment('c') }} +// You can overwrite the default configuration values set in [config.js] here. +// There should never be any required changes to this file and you can always +// simply copy it over when updating to a new version. + +let config = window.mumbleWebConfig // eslint-disable-line no-unused-vars + +// E.g. changing default address and theme: +// config.defaults.address = 'voice.example.com' +// config.defaults.theme = 'MetroMumbleDark + +// Which fields to show on the Connect to Server dialog +config.connectDialog.address = false +config.connectDialog.port = false +config.connectDialog.token = false +config.connectDialog.password = {{ (umurmur_user_password != '') | lower }} + +// Default values for user settings +// You can see your current value by typing `localStorage.getItem('mumble.$setting')` in the web console. +config.settings.pttKey = 'shift' + +// Default values (can be changed by passing a query parameter of the same name) +config.defaults.address = "{{ mumble_web_domain }}/mumble" \ No newline at end of file diff --git a/templates/mumble-web.service.j2 b/templates/mumble-web.service.j2 new file mode 100644 index 0000000..dc1b40d --- /dev/null +++ b/templates/mumble-web.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Mumble web client using websockets +After=network.target umurmur.service +Wants=umurmur.service + +[Service] +Type=simple +User=nobody +Group=nogroup +Restart=always +RestartSec=3 +ExecStart=/usr/bin/websockify --ssl-target {{ mumble_web_websockify_port }} localhost:{{ umurmur_port }} +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/templates/nginx.conf.j2 b/templates/nginx.conf.j2 new file mode 100644 index 0000000..976abe9 --- /dev/null +++ b/templates/nginx.conf.j2 @@ -0,0 +1,65 @@ +{{ ansible_managed | comment }} +server { + listen 80; + listen [::]:80; + server_name {{ mumble_web_domain }}; + + location / { + return 301 https://$host$request_uri; + } + +{% if acme_challenge_dir is defined %} + location ^~ /.well-known/acme-challenge/ { + allow all; + root {{ acme_challenge_dir }}; + try_files $uri =404; + } +{% endif %} +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + server_name {{ mumble_web_domain }}; + + ssl_certificate {{ mumble_web_certificate }}; + ssl_certificate_key {{ mumble_web_private_key }}; + + ssl_session_timeout 1d; + ssl_session_cache shared:AnsibleSSL:10m; # about 40000 sessions + ssl_session_tickets off; + +{% if mumble_web_dhparam is defined and mumble_web_dhparam != '' %} + ssl_dhparam {{ mumble_web_dhparam }}; +{% endif %} + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + add_header Strict-Transport-Security "max-age=63072000" always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # Verify chain of trust of OCSP response using Root CA and Intermediate certs + ssl_trusted_certificate {{ mumble_web_trusted_certificate }}; + + location / { + root /var/www/mumble-web/dist/; + } + + location /mumble { + proxy_pass http://127.0.0.1:{{ mumble_web_websockify_port }}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} \ No newline at end of file diff --git a/templates/umurmur.conf.j2 b/templates/umurmur.conf.j2 new file mode 100644 index 0000000..eeb63fa --- /dev/null +++ b/templates/umurmur.conf.j2 @@ -0,0 +1,72 @@ +{{ ansible_managed | comment }} +max_bandwidth = 48000; +welcometext = {{ umurmur_welcome_text + if umurmur_welcome_text is string + else (umurmur_welcome_text | join('
')) + | to_json }}; +certificate = {{ umurmur_certificate | to_json }}; +private_key = {{ umurmur_private_key | to_json }}; +password = {{ umurmur_user_password | to_json }}; +{% if umurmur_admin_password is defined %} +admin_password = {{ umurmur_admin_password | to_json }}; # Set to enable admin functionality. +{% endif %} +# ban_length = 0; # Length in seconds for a ban. Default is 0. 0 = forever. +# enable_ban = false; # Default is false +# banfile = "banfile.txt"; # File to save bans to. Default is to not save bans to file. +# sync_banfile = false; # Keep banfile synced. Default is false, which means it is saved to at shutdown only. +allow_textmessage = true; # Default is true +# opus_threshold = 100; # Percentage of users supporting Opus codec for it to be chosen. Default is 100. +# show_addresses = true; # Whether to show client's IP addresses under user information +max_users = {{ umurmur_max_users }}; + +bindport = {{ umurmur_port }}; +# bindaddr = "0.0.0.0"; + +# username and groupname for privilege dropping. +# Will attempt to switch user if set. +# username = ""; +# If groupname not set the user's default login group will be used +# groupname = ""; + +# Log to file option. Default is logging to syslog. +# umurmurd will close and reopen the logfile if SIGHUP is received. +logfile = "/var/log/umurmurd.log"; + +# CA location for CA-signed certificates +# ca_path = "/path/to/ca/certificates/"; + +# Channel tree definition: +# Root channel must always be defined first. +# If a channel has a parent, the parent must be defined before the child channel(s). +channels = ( +{% for channel in umurmur_channels %} + { + name = {{ channel.name | to_json }}; + description = {{ channel.description | default('') | to_json }}; + parent = {{ channel.parent | default('') | to_json }}; + noenter = {{ channel.noenter | default(false) | string | lower }}; + silent = {{ channel.silent | default(false) | string | lower }}; +{% if channel.position is defined %} + position = {{ channel.position }}; +{% endif %} +{% if channel.password is defined %} + password = {{ channel.password | to_json }}; +{% endif %} + }{{ loop.last | ternary("", ",") }} +{% endfor %} +); +# Channel links configuration. +channel_links = ( +{% for channel in umurmur_channel_links %} +{% for destination in channel.destinations %} + { + source = {{ channel.source | to_json }}; + destination = {{ destination | to_json }}; + }{{ loop.last | ternary('', ',') }} +{% endfor %} +{% endfor %} +); + +# The channel in which users will appear in when connecting. +# Note that default channel can't have 'noenter = true' or password set +default_channel = {{ umurmur_default_channel | to_json }}; \ No newline at end of file diff --git a/templates/umurmur.service.j2 b/templates/umurmur.service.j2 new file mode 100644 index 0000000..17c515d --- /dev/null +++ b/templates/umurmur.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Minimalistic Mumble server +After=network.target + +[Service] +Type=simple +User=nobody +Group={{ umurmur_ssl_group }} +Restart=always +RestartSec=3 +ExecStartPre=/usr/local/bin/umurmurd -t -c /usr/local/etc/umurmur.conf +ExecStart=/usr/local/bin/umurmurd -d -r -c /usr/local/etc/umurmur.conf +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target \ No newline at end of file