Exchange 2013 Deployment Guide – Ansible Playbook

Posted on

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:

- 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'
Posted on

Eiren McLoughlin

Eiren McLoughlin is a Front-End Developer with the Kemp 360 Central development team based in Ireland. She holds a level 9 special award in Lean UX Design from the Institute of Technology Tralee and a honours bachelor's degree in Creative Multimedia from Limerick Institute of Technology. She enjoy learning new technologies and in her spare time likes to do photography, explore and read.