Secure Web Gateway
2 TopicsSWG, Kerberos Auth and identify users by credentials
Problem this snippet solves: When using SWG and NTLM Auth it's possible to identify users by IP address or credentials. However, when using Kerberos Auth it isn't possible to identify users by credentials. This iRule enables the 'identify users by credentials' feature for SWG and Kerberos Auth. The 'identify by credentials' method adds security to environments that use shared systems (like terminal servers) where multiple users are hidden behind the same IP address. How to use this snippet: How to use Configure an APM Explicit Forwarding Proxy Configuration. Call it for example: /Common/vs_proxy_kerberos. Follow the instructions provided by AskF5, but make sure that this virtual server doesn't listen on any VLAN or tunnel. This will be an internal virtual server. Create a datagroup of type Address and add IP addresses of shared systems to it. Call it for example: /Common/data_group_ip. Edit the f5.swg_kerberos_identify_by_credentials iRule variables in the RULE_INIT event to match your configuration. Configure a second virtual server that holds the f5.swg_kerberos_identify_by_credentials iRule. Call it for example: /Common/vs_proxy_kerberos_front. This virtual server will accept proxy traffic from clients and route it to the internal virtual server. How it works The iRule will check if the HTTP request contains a Proxy-Authorization header. If the request contains a Proxy-Authorization header it will take a part of the Base64 Kerberos ticket and maps it to an internal IP address. This internal IP address will be used as a SNAT address. The internal virtual server will use the standard Kerberos Auth 'identification by IP' method to authenticate this session. The iRule uses tables to map Kerberos tickets to IP addresses. Please note that single users can sometimes use different Kerberos tickets. This results in a single user consuming more than one session. Like NTLM Auth, the 'identify by credentials' method adds extra overhead in the communication between the client and the proxy, because the client is forced to send a Proxy-Authorization header with each request. Disclaimer This iRule has been tested in a lab environment only Code : https://github.com/nvansluis/f5.swg_kerberos_identify_by_credentials676Views0likes2CommentsOffice 365 Data Group builder using F5 Python SDK
Problem this snippet solves: Python script which pulls O365 URL's/IP's from microsoft published XML formatted list, parses into python dictionaries formatted for F5 data group, and uses F5 Python SDK to create or update data groups on BIG-IP for each MS product. The script will check if the data group already exists, and if so update based on changes. Once the data groups are installed they can used/referenced by any F5 feature/configuration that can reference a data group. How to use this snippet: Python version: 3.6 Python Modules Required: * f5-sdk * requests * f5-icontrol-rest * xmltodict Update script variables for your environment: BIGIP_ADDRESS = ' ' BIGIP_USER = ' ' BIGIP_PASS = ' ' to execute: python3 o365_dg_builder.py Code : import requests import xmltodict from collections import OrderedDict from f5.bigip import ManagementRoot from icontrol.exceptions import iControlUnexpectedHTTPError import argparse MS_URL = 'https://support.content.office.net/en-us/static/O365IPAddresses.xml' BIGIP_ADDRESS = '192.168.15.165' BIGIP_USER = 'admin' BIGIP_PASS = 'admin' def load_bigip(f5_host, f5_user, f5_pass): bigip = ManagementRoot(f5_host, f5_user, f5_pass) return bigip def get_o365_data(): o365data = requests.get(MS_URL) records = [] pdata = xmltodict.parse(o365data.content) for product in pdata['products']['product']: prod_name = product['@name'] if isinstance(product['addresslist'],list): for addrlist in product['addresslist']: record = {} if 'address' in addrlist.keys(): record['name'] = "{}_{}_{}".format('MS',prod_name, addrlist['@type']) if '@type' in addrlist.keys(): if addrlist['@type'] == 'URL': record['type'] = 'string' elif (addrlist['@type'] == 'IPv4' or addrlist['@type'] == 'IPv6'): record['type'] = 'ip' # MS XML has duplicate entries, unify the list before adding to record new_addr_l = list(set(addrlist['address'])) record['records'] = new_addr_l records.append(record) if isinstance(product['addresslist'],OrderedDict): if len(product['addresslist']['address']) > 0: record = {} record['name'] = "{}_{}_{}".format('MS', prod_name, product['addresslist']['@type']) if product['addresslist']['@type'] == 'URL': record['type'] = 'string' elif product['addresslist']['@type'] == 'IPv4' or product['addresslist']['@type'] == 'IPv6': record['type'] = 'ip' record['records'] = list(set(product['addresslist']['address'])) records.append(record) return records def compare_dg_entries(record, old_dg_l): # let's get the values to compare, and see what updates we need to make #compare lists addrs_to_rem = [x for x in old_dg_l if x not in record] addrs_to_add = [x for x in record if x not in old_dg_l] return addrs_to_rem, addrs_to_add def create_dg(bigip, record): if not bigip.tm.ltm.data_group.internals.internal.exists(name=record['name']): bigip.tm.ltm.data_group.internals.internal.create(**record) create_status = 'SUCCESS' else: old_dg_entries = bigip.tm.ltm.data_group.internals.internal.load(name=record['name']) # pull into a list old_dg_l = [] for entry in old_dg_entries.records: old_dg_l.append(entry['name']) addrs_to_rem, addrs_to_add = compare_dg_entries(record['records'], old_dg_l) if len(addrs_to_add)==0 and len(addrs_to_rem)==0: create_status = 'SKIPPED' else: if len(addrs_to_rem) > 0: for addr in addrs_to_rem: old_dg_entries.records.remove(next(x for x in old_dg_entries.records if x['name'] == addr)) if len(addrs_to_add) > 0: for addr in addrs_to_add: old_dg_entries.records.append({'name':addr}) old_dg_entries.update() # if you get time create log of updated entries create_status = 'UPDATED' return create_status # ----- try: bigip = load_bigip(BIGIP_ADDRESS, BIGIP_USER, BIGIP_PASS) except iControlUnexpectedHTTPError as e: print(e) exit(1) if bigip: records = get_o365_data() for record in records: try: status = create_dg(bigip, record) print("BIGIP: {}, Data Group: {}, Create Status {}".format(BIGIP_ADDRESS, record['name'], status)) except iControlUnexpectedHTTPError as e: status = 'FAILED' print("BIGIP: {}, Data Group: {}, Create Status {}, Error {}".format(BIGIP_ADDRESS, record['name'], status, e)) Tested this on version: 13.0625Views0likes1Comment