In this post, I will show how to utilise Ansible via Kemp 360 Central to setup ESP Exchange 2013 services, while outlining how to create a LDAP authentication and SSO Domain on Kemp’s LoadMaster.
Getting Started
1. Install Ansible
Follow the installation guide at:https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
2. Download and extract the Kemp’s Ansible modules from Kemp’s website
Kemp’s module can be found here: https://kemptechnologies.com/kemp360/ansible-module/ Once extracted, you will have access to Kemp’s library modules, utility modules and example playbooks, including the ESP Exchange 2013 playbook.
3. Configure Ansible to recognise Kemp’s modules
To successfully run any playbooks that are created using Kemp’s Ansible modules, we must first tell Ansible where Kemp’s modules are located. The easiest way to achieve this is to create an Ansible config file within the /ansiblepoc-master/ directory. Create a file called:
ansible.cfg
And add the following lines:
[defaults] library = /home/path/to/kemp_ansible/library/ module_utils = /home/path/to/kemp_ansible/module_utils/
Ansible playbooks that are executed from this directory will identify the config file and load the necessary Kemp-specific libraries for use.
4. Configure Kemp’s ESP Exchange 2013 playbook
To successfully run Kemp’s ESP Exchange 2013 playbook, we need to provide configuration values. The playbook espExchange2013Playbook.yml is located in the /examples/ directory. The settings within the playbook are based on both Kemp’s Microsoft Exchange 2013 ESP Template and the deployment guide which is available here:
The playbook has been configured to upload and assign a certificate to the HTTPS Virtual Service, create and assign a number of Content Rules, Sub Virtual Services and Real Servers. The settings that require values for Exchange 2013 ESP are described below:
central_address | The IP address of the Kemp 360 Central that manages your LoadMaster. |
central_api_key | Please refer to step 4 here: https://kemptechnologies.com/blog/how-to-use-ansible-to-automate-the-configuration-and-deployment-of-load-balancers/ to get the required Kemp 360 Central API key. |
lm_address | The IP address of the LoadMaster where Virtual Services and Real Servers will be created. |
vs_ip | The Virtual Service IP address. |
cert_name | The certificate name |
cert_passphrase | Passphrase for certificate |
certificate_path | The path to where the certificate is located. |
exchange_servers | List of IP Address of exchange servers. |
allowed_hosts | Hosts that are allowed |
exchange_credentials | Credentials for Exchange |
Using ansible, you can now quickly setup and configure a LDAP endpoint. This LDAP endpoint can then be referenced where relevant such as setting up an LDAP SSO Domain. Kemp’s Ansible library supports creating SSO Domains such as Certificate, Radius, Radius LDAP, LDAP and SAML which can then be set on the desired service. A sample LDAP ndpoint and LDAP SSO Domain can be found at the bottom of the playbook. The following settings require values in creating up an LDAP endpoint.
ldap_name | Name to be given to the LDAP Endpoint |
ldap_server | The IP address for the LDAP Server |
ldap_admin_pass | Passphrase for LDAP Admin |
5. Run Kemp’s ESP Exchange 2013 playbook
Once we have added the necessary configuration values to your playbook, we can then run this playbook from the same directory as our Ansible config file. To run the playback, we execute the command:
ansible-playbook -vvv examples/espExchange2013Playbook.yml
Adding -vvv allows you to see information such as what settings were modified/configured in the playbook and if any errors occurred such as what value could not be set. As soon as the playbook has run successfully, your LoadMaster is now configured and ready to go.
Playbook – ESP Exchange 2013 with sample LDAP Endpoint and SSO LDAP:
Playbook - ESP Exchange 2013 with sample LDAP Endpoint and SSO LDAP:
- name: Configure Loadmaster for Exchange 2013 ESP hosts: localhost vars: # Customise the settings here for your environment central_address: '' central_username: 'Admin' # only Admin can execute ansible playbooks on Central central_api_key: '' lm_address: '' lm_port: '' vs_ip: '' cert_name: '' cert_passphrase: '' certificate_path: '' allowed_hosts: '' exchange_servers: - '' ldap_name: '' ldap_server: '' ldap_admin_pass: '' content_match_rules: - { name: 'Authentication_proxy', pattern: '/^\/lm_auth_proxy*$/' } - { name: 'ActiveSync', pattern: '/^\/microsoft-server-activesync.*/' } - { name: 'Autodiscover', pattern: '/^\/autodiscover.*/' } - { name: 'ECP', pattern: '/^\/ecp.*/' } - { name: 'EWS', pattern: '/^\/ews.*/' } - { name: 'Mapi', pattern: '/^\/mapi.*/' } - { name: 'OAB', pattern: '/^\/oab.*/' } - { name: 'OWA', pattern: '/^\/owa.*/' } - { name: 'OWA_Root_Redirect_match', pattern: '/^\/$/' } - { name: 'Powershell', pattern: '/^\/powershell.*/' } - { name: 'RPC_', pattern: '/^\/rpc.*/' } tasks: - name: Upload the Users Certificate cert_management: lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' central_address: '{{ central_address }}' central_username: '{{ central_username }}' cert_name: '{{ cert_name }}' cert_file: '{{ certificate_path }}' password: '{{ cert_passphrase }}' replace: 0 intermediate: 0 central_api_key: '{{ central_api_key }}' - name: Create Content Match Rules match_content_rule: lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' central_address: '{{ central_address }}' username: '{{ central_username }}' api_key: '{{ central_api_key }}' name: '{{ item.name }}' match_type: 'regex' ignore_case: 'Y' pattern: '{{item.pattern}}' loop: "{{ content_match_rules }}" - name: Create Redirect_Root URL modify rule modify_url_rule: lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' central_address: '{{ central_address }}' username: '{{ central_username }}' api_key: '{{ central_api_key }}' name: 'Redirect_Root' pattern: '/^\/$/' replacement: '/owa' - name: Create HTTP to HTTPS Redirect VS virtual_service: central_address: '{{ central_address }}' central_username: '{{ central_username }}' central_api_key: '{{ central_api_key }}' lm_address: '{{ lm_address }}' lm_port: '443' enable: 'Y' nickname: 'Exchange_2013_HTTPS_HTTP_Redirect' vs_ip: '{{ vs_ip }}' vs_port: 80 vs_protocol: 'tcp' vs_type: 'http' force_l7: 1 error_code: 302 error_url: 'https:\/\/%h%s' check_type: 'none' - name: Create main HTTPS VS virtual_service: central_address: '{{ central_address }}' central_username: '{{ central_username }}' central_api_key: '{{ central_api_key }}' lm_address: '{{ lm_address }}' lm_port: '443' enable: 'Y' nickname: 'Exchange_HTTPS_Offloaded' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_protocol: 'tcp' vs_type: 'http' force_l7: 1 subnet_originating: 1 ssl_acceleration: 1 transparent: 0 cert_name: '{{ cert_name }}' cipher_set: 'BestPractices' schedule: 'Least-Connection' idle_time: 1800 - name: Create Auth Proxy SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' vs_type: 'http' nickname: 'Auth_Proxy' enable: 'Y' schedule: 'Least-Connection' error_code: 503 error_url: 'Endpoint not available' esp_enabled: 1 esp_logs: 7 input_auth_mode: 2 output_auth_mode: 2 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/*' single_sign_on_message: 'Please enter your Exchange credentials' selection_rules: - 'Authentication_proxy' - name: Create Active Sync SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'Active_Sync' vs_type: 'http' enable: 'Y' schedule: 'Least-Connection' check_type: 'https' check_port: 443 check_use_get: 1 check_url: '/microsoft-server-activesync/healthcheck.htm' selection_rules: - 'ActiveSync' subnet_originating: 1 persist: 'none' idle_time: 1800 esp_enabled: 1 esp_logs: 7 input_auth_mode: 1 output_auth_mode: 1 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/microsoft-server-activesync*' - name: Create Autodiscover SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'Autodiscover' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/autodiscover/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'Autodiscover' esp_enabled: 1 esp_logs: 7 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/autodiscover*' - name: Create ECP SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'ECP' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/ecp/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'ECP' esp_enabled: 1 esp_logs: 7 input_auth_mode: 2 output_auth_mode: 2 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/ecp*' single_sign_on_message: 'Please enter your Exchange credentials' - name: Create EWS SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'EWS' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/ews/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'EWS' esp_enabled: 1 esp_logs: 7 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/ews*' - name: Create MAPI SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'MAPI' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/mapi/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'Mapi' esp_enabled: 1 esp_logs: 7 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/mapi*' - name: Create OAB SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'OAB' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/oab/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'OAB' esp_enabled: 1 esp_logs: 7 input_auth_mode: 0 output_auth_mode: 0 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/oab*' - name: Create OWA SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'OWA' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/owa/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'OWA' - 'OWA_Root_Redirect_match' request_rules: - 'Redirect_Root' esp_enabled: 1 esp_logs: 7 input_auth_mode: 2 output_auth_mode: 2 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/owa*' excluded_directories: '/owa/guid@smtpdomain*' single_sign_on_message: 'Please enter your Exchange credentials' logoff: '/owa/logoff.owa' - name: Create Powershell SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'Powershell' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/powershell/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'Powershell' esp_enabled: 1 esp_logs: 7 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/powershell*' - name: Create RPC SubVS sub_virtual_service: central_address: '{{ central_address }}' central_api_key: '{{ central_api_key }}' central_username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' nickname: 'RPC' vs_type: 'http' enable: 'Y' subnet_originating: 1 schedule: 'Least-Connection' idle_time: 1800 check_type: 'https' check_url: '/rpc/healthcheck.htm' check_port: 443 check_use_get: 1 selection_rules: - 'RPC_' esp_enabled: 1 esp_logs: 7 allowed_hosts: '{{ allowed_hosts }}' allowed_directories: '/rpc*' - name: Attach Exchange realservers to Auth_Proxy subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'Auth_Proxy' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to Active_Sync subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'Active_Sync' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to Autodiscover subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'Autodiscover' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to ECP subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'ECP' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to EWS subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'EWS' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to MAPI subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'MAPI' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to OAB subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'OAB' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to OWA subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'OWA' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to PowerShell subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'Powershell' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" - name: Attach Exchange realservers to RPC subvs real_server: central_address: '{{ central_address }}' username: '{{ central_username }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' api_key: '{{ central_api_key }}' vs_ip: '{{ vs_ip }}' vs_port: 443 vs_prot: 'tcp' sub_vs_nickname: 'RPC' rs_ip: '{{item}}' rs_port: 443 rs_enable: 'Y' loop: "{{ exchange_servers }}" # Creating an LDAP configuration - name: Setup LDAP configuration ldap: central_address: '{{ central_address }}' username: '{{ central_username }}' api_key: '{{ central_api_key }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' name: '{{ ldap_name }}' ldaptype: '1' server: '{{ ldap_server }}' adminuser: 'Admin' adminpass: '{{ ldap_admin_pass }}' timeout: '9' referralcount: '8' vinterval: '10' # Create SSO Domanis - name: Create SSO LDAP sso_ldap: central_address: '{{ central_address }}' username: '{{ central_username }}' api_key: '{{ central_api_key }}' lm_address: '{{ lm_address }}' lm_port: '{{ lm_port }}' domain: 'LdapDomain' ldap_endpoint: '{{ ldap_name }}' auth_type: 'LDAP-Unencrypted' logon_domain: 'logondomain' logon_fmt: 'Principalname' logon_transcode: '0' max_failed_auths: '18' unblock_tout: '2020' sess_tout_idle_pub: '900' sess_tout_duration_pub: '1800' sess_tout_idle_priv: '900' sess_tout_duration_priv: '28800' sess_tout_type: 'idle time' ldapephc: '1'