on 25-Apr-2017 18:33
Problem this snippet solves:
This iRules LX code dynamically registers a clients obtained IP from APM when they initiate a VPN tunnel to an AWS route 53 domain.
How to use this snippet:
Import attached tgz(zip will need to be re-packaged to tgz) to a new iRules LX workspace, create an iRule LX plugin, and attached the editRecord iRule to your virtual server.
You can also manually create a new workspace and add the iRules LX iRule and extension with the code below. You will also have to install the aws-sdk module using npm. Eric Flores has a good write-up on how to manage npm, https://devcentral.f5.com/articles/getting-started-with-irules-lx-part-4-npm-best-practices-20426.
iRule Code:
when CLIENT_ACCEPTED {
ACCESS::restrict_irule_events disable
}
when HTTP_REQUEST {
if { [ACCESS::policy result] eq "allow" && [HTTP::uri] starts_with "/myvpn?sess="} {
after 5000 {
set apmSessionId [ACCESS::session data get session.user.sessionid]
set apmProfileName [ACCESS::session data get session.access.profile]
set apmPart [ACCESS::session data get session.partition_id]
set DNSName "<your zone with trailing dot>"
set action "UPSERT"
set name "<your hostname>"
if {not ($name ends_with ".[string trimright ${DNSName} {.}]")}{
log -noname local1.err "${apmProfileName}:${apmPart}:${apmSessionId}: proper hostname was not provided ($name): 01490000: A Record will not be updated for this session."
event disable all
return
}
set TTL 1200
set ip [ACCESS::session data get "session.assigned.clientip"]
if {[catch {IP::addr $ip mask 255.255.255.255}]}{
log -noname local1.err "${apmProfileName}:${apmPart}:${apmSessionId}: proper IP addressed was not assigned ($ip): 01490000: A Record will not be updated for this session."
event disable all
return
}
set RPC_HANDLE [ILX::init route53]
if {[catch {set rpc_response [ILX::call $RPC_HANDLE route53_nodejs $DNSName $action $name $TTL $ip]}]}{
set rpc_response "Check LTM log for execution errors from sdmd. A Record may not have been updated for this session."
}
log -noname local1. "${apmProfileName}:${apmPart}:${apmSessionId}: Client connected: 01490000: Params sent = $DNSName $action $name $TTL $ip\r\nRPC response = $rpc_response"
}
}
}
when ACCESS_SESSION_CLOSED {
set apmSessionId [ACCESS::session data get session.user.sessionid]
set apmProfileName [ACCESS::session data get session.access.profile]
set apmPart [ACCESS::session data get session.partition_id]
set DNSName "<your zone with trailing dot>"
set action "DELETE"
set name "<your hostname>"
if {not ($name ends_with ".[string trimright ${DNSName} {.}]")}{
log -noname local1.err "${apmProfileName}:${apmPart}:${apmSessionId}: proper hostname was not provided ($name): 01490000: A Record will not be removed for this session."
event disable all
return
}
set TTL 1200
set ip [ACCESS::session data get "session.assigned.clientip"]
if {[catch {IP::addr $ip mask 255.255.255.255}]}{
log -noname local1.err "${apmProfileName}:${apmPart}:${apmSessionId}: proper IP addressed was not assigned ($ip): 01490000: A Record will not be removed for this session."
event disable all
return
}
set RPC_HANDLE [ILX::init route53]
if {[catch {set rpc_response [ILX::call $RPC_HANDLE route53_nodejs $DNSName $action $name $TTL $ip]}]}{
set rpc_response "Check LTM log for execution errors from sdmd. A Record may not have been removed for this session."
}
log -noname local1. "${apmProfileName}:${apmPart}:${apmSessionId}: Client disconnected: 01490000: Params sent = $DNSName $action $name $TTL $ip\r\nRPC response = $rpc_response"
}
node.js code:
var AWS = require('aws-sdk');
var f5 = require('f5-nodejs');
/* AWS Config */
//AWS.config.update({accessKeyId: "<your access key>", secretAccessKey: "<your secret>"});
/* get the Route53 library */
var route53 = new AWS.Route53();
/* Create a new rpc server for listening to TCL iRule calls. */
var ilx = new f5.ILXServer();
/* Start listening for ILX::call and ILX::notify events. */
ilx.listen();
/* Add a method and expect DNSName, action, name, TTL, and ip parameters and reply with response */
ilx.addMethod('route53_nodejs', function(req, response) {
var DNSName = req.params()[0];
var params = {
DNSName: DNSName
};
var action = req.params()[1];
var name = req.params()[2];
var TTL = req.params()[3];
var ip = req.params()[4];
route53.listHostedZonesByName(params, function(err,data) {
if (err) {
//console.log(err, err.stack);
response.reply(err.toString());
}
else if (data.HostedZones[0].Name !== params.DNSName) {
response.reply(params.DNSName + " is not a zone defined in Route53");
}
else {
var zoneId = data.HostedZones[0].Id;
var recParams = {
"HostedZoneId": zoneId,
"ChangeBatch": {
"Changes": [
{
"Action": action,
"ResourceRecordSet": {
"Name": name,
"Type": "A",
"TTL": TTL,
"ResourceRecords": [
{
"Value": ip
}
]
}
}
]
}
};
/* edit records using aws sdk */
route53.changeResourceRecordSets(recParams, function(err,data) {
if (err) {response.reply(err.toString());}
else if (data.ChangeInfo.Status === "PENDING") {response.reply("Record is being updated");}
else {response.reply(data);}
});
}
});
});
This is also on my github, https://github.com/bepsoccer/iRulesLX
Code :
75409
Tested this on version:
12.1