Automated Provisioning and Hardening of Genesys Cloud On-Premises Media Gateways via Ansible
What This Guide Covers
This guide details the construction of production-grade Ansible playbooks to provision, configure, and validate Linux-based virtual machines hosting the Genesys Cloud On-Premises Media Gateway. The end result is an automated pipeline that delivers hardened, network-ready edge servers capable of registering with the Genesys Cloud environment without manual intervention.
Prerequisites, Roles & Licensing
To execute this automation successfully, the following foundational elements must be in place before writing a single line of playbook code. Failure to meet these requirements will result in provisioning failures or security vulnerabilities that compromise the entire telephony infrastructure.
Infrastructure Requirements
- Ansible Controller: A dedicated Linux host (RHEL 8/9, Ubuntu 20.04/22.04 LTS) with Ansible version 6.0 or higher installed. The controller must possess SSH key access to the target VMs without password prompts.
- Target Environment: Virtualized infrastructure (VMware vSphere, KVM, Nutanix, or Public Cloud IaaS) where the Genesys Media Gateway VMs will reside.
- Network Access: Outbound connectivity from the target network segment to specific Genesys Cloud endpoints on TCP 443 and UDP 10000-20000 (RTP).
Licensing and Permissions
- Genesys Cloud Licensing: Active CCX license entitlements assigned to the tenant. The On-Premises Media Gateway requires a specific license type; typically, this is bundled within the Contact Center Experience license but must be verified in the Control Panel under Administration > License.
- OS Permissions: Root or
sudoprivileges on the target Linux hosts to install packages and configure system services. - DNS Records: Static IP addresses assigned via DHCP reservation or static configuration, with valid PTR records for reverse DNS lookups required by Genesys security protocols.
OAuth and API Scopes
While this provisioning is infrastructure-focused, post-provisioning registration often requires API access. Ensure the following scopes are available if integrating the playbook with a registration script:
cloudapi:genecloud(Full Read/Write for configuration updates)telephony:trunks(For trunk validation via API)
The Implementation Deep-Dive
1. Inventory Management and Variable Structure
The foundation of any robust Ansible deployment is the separation of inventory data from logic. Hardcoding hostnames or IP addresses within playbooks creates technical debt that manifests during scaling. This step establishes a dynamic variable structure that allows you to manage different environments (Dev, UAT, Prod) without code changes.
Architectural Reasoning
You must treat environment variables as immutable inputs. The playbook should never determine the IP address or hostname; it must consume these from the inventory. This ensures that the same binary artifact is deployed consistently across all tiers. Group variables allow you to define shared hardening rules for all Media Gateways while overriding specific network parameters for individual nodes.
The Trap
A common failure mode involves mixing sensitive data directly in host variables without encryption or using vars_files that are checked into source control. Storing credentials or IP ranges in plaintext within group_vars violates security compliance standards like PCI-DSS. If a repository is compromised, the entire network topology becomes exposed.
Implementation
Create a directory structure that isolates variable definitions:
# /opt/ansible/inventory/group_vars/media_gateways.yml
---
# Shared configuration for all Media Gateway nodes
os_version: "rhel8"
base_domain: "prod.contactcenter.example.com"
ntp_servers:
- "10.10.10.5"
- "10.10.10.6"
# Genesys specific parameters
genesys_media_gateway_version: "24.1.0"
media_gateway_hostname_prefix: "MGW-PROD"
firewall_port_range_start: 10000
firewall_port_range_end: 20000
In the host inventory file (hosts.yml), you must explicitly define the instance parameters that differ per node. Do not rely on defaults for critical network settings.
# /opt/ansible/inventory/host_vars/mgw-node-01.yml
---
inventory_hostname: mgw-node-01
ip_address: 192.168.10.50
subnet_mask: "255.255.255.0"
gateway_ip: 192.168.10.1
dns_primary: 10.10.10.5
dns_secondary: 10.10.10.6
fqdn: mgw-node-01.prod.contactcenter.example.com
The Trap
Do not assume the ansible_host variable maps correctly to the internal network interface if the controller resides on a different subnet. Always verify connectivity using an explicit ping task before proceeding with configuration changes. If the Ansible controller cannot reach the target host via SSH, no subsequent tasks will execute.
2. OS Hardening and Network Security Configuration
Before installing the Genesys software, the operating system must be hardened to meet enterprise security standards. This involves configuring SELinux, firewalls, and kernel parameters. The goal is to create a secure baseline that does not inadvertently block telephony traffic.
Architectural Reasoning
SELinux (Security-Enhanced Linux) is often enabled by default on RHEL-based systems. Genesys Media Gateway processes may require specific context labels or permissions that are blocked by default policies. Disabling SELinux entirely is a security risk and violates compliance standards. Instead, you must configure the correct booleans and allow rules for the Genesys services to function while maintaining enforcement.
The Trap
The most frequent cause of post-installation connectivity failure is the firewall blocking outbound UDP traffic used for RTP media streams. Administrators often open port 443 for registration but forget to open the ephemeral UDP port range required for voice data. This results in one-way audio or complete call drops, which are difficult to troubleshoot without visibility into the OS-level packet filtering logs.
Implementation
The following task block configures the firewall and SELinux policies dynamically based on the Genesys requirements.
# tasks/harden_os.yml
- name: Configure SELinux for Genesys Media Gateway
ansible.builtin.seboolean:
name: "{{ item }}"
state: yes
persistent: yes
loop:
- httpd_can_network_connect
- container_manage_cgroup
ignore_errors: yes
- name: Set SELinux to Permissive Mode for installation (Temporary)
ansible.builtin.lineinfile:
path: /etc/selinux/config
regexp: "^SELINUX="
line: "SELINUX=permissive"
state: present
notify: Restart SELinux Service
- name: Configure Firewall Rules for SIP and RTP
ansible.posix.firewalld:
service: "{{ item.service }}"
port: "{{ item.port }}"
zone: public
permanent: yes
immediate: yes
state: "{{ item.state }}"
loop:
- { service: "https", state: "enabled" }
- { port: "{{ firewall_port_range_start }}-{{ firewall_port_range_end }}/udp", state: "enabled" }
- { port: "5060/tcp", state: "enabled" }
ignore_errors: yes
- name: Configure Kernel Parameters for High Concurrency
ansible.posix.sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
sysctl_set: yes
state: present
reload: yes
loop:
- { name: "net.ipv4.ip_local_port_range", value: "{{ firewall_port_range_start }} {{ firewall_port_range_end }}" }
- { name: "net.core.somaxconn", value: "65535" }
Validation of Logic
Ensure the firewalld service is enabled before attempting to configure rules. If the target system uses iptables directly rather than firewalld, this playbook will fail. You must include a pre-check task that detects the firewall daemon in use and applies the correct module.
3. Dependency Installation and Service Registration
With the OS hardened, the next phase involves installing the Genesys Media Gateway software packages. This step requires strict version pinning to ensure compatibility with the tenant configuration on the cloud side.
Architectural Reasoning
Using latest in package managers is a dangerous practice in production environments. A repository update could pull a newer version of the base OS kernel or dependency libraries that are not validated by Genesys support for your specific release. Pinning exact versions ensures reproducibility and reduces the risk of regression bugs introduced by upstream updates.
The Trap
A critical failure point occurs when the package manager cache is stale, leading to installation errors regarding missing dependencies. This often happens if the playbook runs on a host that has not been updated recently. The dnf or yum cache must be refreshed explicitly before installing the Genesys RPMs. Additionally, the hostname resolution for the Genesys Cloud tenant domain must be valid during the installation process, as the installer may attempt to validate connectivity immediately upon execution.
Implementation
This task block handles the repository configuration and package installation.
# tasks/install_media_gateway.yml
- name: Update Package Cache
ansible.builtin.yum:
update_cache: yes
state: latest
when: os_version == "rhel8"
- name: Add Genesys Repository GPG Key
ansible.builtin.get_url:
url: "https://download.genesys.cloud/repo/GPG-KEY-GC"
dest: "/etc/pki/rpm-gpg/"
mode: "0644"
- name: Configure Genesys Repository
ansible.builtin.yum_repository:
name: genesys_cloud_media_gateway
description: Genesys Cloud Media Gateway Repo
baseurl: https://download.genesys.cloud/repo/media-gateway/{{ os_version }}/
gpgcheck: yes
enabled: yes
priority: 1
- name: Install Genesys Media Gateway Package
ansible.builtin.yum:
name: "genesys-cloud-media-gateway-{{ genesys_media_gateway_version }}"
state: present
disable_gpg_check: no
- name: Start and Enable Media Gateway Service
ansible.builtin.systemd:
name: "genesys-media-gateway"
state: started
enabled: yes
Post-Installation Registration
After the service starts, it must register with the Genesys Cloud Control Panel. This is typically done via a configuration file update followed by a service restart. Do not automate the registration token generation within the playbook; this should be a manual step performed by a security administrator to ensure tokens are rotated securely and not stored in version control.
The Trap
If the hostname defined in the OS configuration does not match the hostname registered in the Genesys Cloud Control Panel, the service will fail to register with an authentication error. The playbook must enforce that the ansible_hostname matches the expected value in the inventory variables before attempting to start the service.
Validation, Edge Cases & Troubleshooting
Edge Case 1: DNS Resolution Failure During Boot
The Failure Condition
The Media Gateway service fails to start immediately after deployment, citing a “DNS lookup failed” error for the Genesys Cloud endpoint.
The Root Cause
This occurs when the network interface comes up before the DNS resolver is fully initialized in the OS boot sequence. Ansible often configures networking and DNS settings faster than the underlying system services are ready to query them.
The Solution
Include a validation loop in the playbook that waits for name resolution to succeed before proceeding with service installation. Use the ansible.builtin.wait_for module or a custom script check. Ensure /etc/resolv.conf is populated correctly and persists across reboots by binding it to the network interface configuration file (e.g., nmcli or /etc/sysconfig/network-scripts/).
Edge Case 2: RTP Port Range Conflicts
The Failure Condition
Audio quality degrades significantly, with packet loss occurring during active calls. The Genesys Cloud logs indicate “RTP allocation failed.”
The Root Cause
The UDP port range defined in the OS firewall configuration does not match the range configured in the Genesys Cloud tenant settings. If the OS allows ports 10000-20000 but the cloud tenant expects 50000-60000, the media packets are dropped by the local firewall.
The Solution
Cross-reference the firewall_port_range_start and firewall_port_range_end variables in your inventory with the values set in Genesys Cloud Control Panel > System Settings > Telephony. If they do not match, update the inventory variables and re-run the playbook. Always validate this configuration in a non-production environment first.
Edge Case 3: Service Startup Dependency Race Condition
The Failure Condition
The service starts but immediately stops, logging “Database connection timeout.”
The Root Cause
The Genesys Media Gateway relies on internal database processes (PostgreSQL) that may take longer to initialize than the main service expects. If the playbook restarts the main service before the database is ready, the startup loop fails repeatedly.
The Solution
Adjust the systemd unit file timeout settings or include a sleep task in the playbook after installation but before enabling the service. A more robust approach is to rely on the ExecStartPre directives within the systemd unit file rather than Ansible tasks for internal dependencies. Verify the systemctl status genesys-media-gateway output to confirm the health of all sub-processes before declaring success.