[Powershell]Submitting access request to tufin

Background
So here is a real life requirement that when vRealize Orchestrator created a new virtual machine, the ip addresses of the new VM are passed over to a list, another script will be triggered weekly to read from the list, base on the list create the firewall rules so that new servers can access common service.

The common services are these servers 192.168.0.1 – .4, the source address is dynamic, as it depends on your new virtual machine’s ip addresses.

Here’s a sample code to be sent over to Tufin SecureChange using its Ticket API. The workflow element depends on your environment, the workflow id and name need to be changed according to what you set. You can use Postman to test the api and see what is your workflow id. Do not copy the below wholesale, this is just for learning only.

<# Author: Cyrus
Unix server common services script. This is to build a standard firewall rules for new servers
Need to do exception handling so that troubleshooting is easier if the script fails. #>

#ignore certificate validation
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

#script integration. If there is an existing script that returns ip address, remove the Read-Host command and use the function you have.
#$new_server = Read-Host("New Server IP address ")

#to consolidate new servers from a list
function GatherNewServers($new_server){
$src_addr = @" 
<source type="IP">
    <ip_address>$new_server</ip_address>
    <netmask>255.255.255.255</netmask>
</source>
"@
return $src_addr + "`r"
}
#store the iteration in an array
$src_ip = @()
$src_addr = Get-Content "$env:HOMEDRIVE\Powershell\test_ip.txt"
for($i=0; $i -lt $src_addr.Count; $i++) {
    $src = $src_addr.item($i)
    $src_ip += GatherNewServers($src)
 
    }

$body = @"
    <ticket>
    <subject>Firewall rule for new server</subject>
    <priority>Normal</priority>
    <domain_name>Default</domain_name>
    <workflow>
         <id>154</id>
         <name>Submit a Change Request</name>
         <uses_topology>true</uses_topology>
    </workflow>
    <steps>
         <step>
             <name>Submit Access Request</name>
             <tasks>
                 <task>
                     <fields>
                         <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="multi_access_request">
                             <name>Required Access</name>
                             <access_request>
                                 <users>
                                     <user>Any</user>
                                 </users>
                                 <sources>
                                     $src_ip
                                 </sources>
                                 <destinations>
                                     <destination type="IP">
                                         <ip_address>192.168.0.1</ip_address>
                                         <netmask>255.255.255.255</netmask>
                                     </destination>
                                 </destinations>
                                 <services>
                                     <service type="PROTOCOL">
                                         <protocol>TCP</protocol>
                                         <port>8140</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                        <port>61613</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                        <port>8142</port>
                                     </service>
                                 </services>
                            	 <action>Accept</action>
                                 <labels/>
                             </access_request>
                             <access_request>
                                 <users>
                                     <user>Any</user>
                                 </users>
                                 <sources>
                                     $src_ip
                                 </sources>
                                 <destinations>
                                     <destination type="IP">
                                         <ip_address>192.168.0.2</ip_address>
                                         <netmask>255.255.255.255</netmask>
                                     </destination>
                                 </destinations>
                                 <services>
                                     <service type="PROTOCOL">
                                     	<protocol>TCP</protocol>
                                     	<port>111</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                     	<port>300</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                     	<port>302</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                     	<port>304</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>TCP</protocol>
                                     	<port>2049</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>UDP</protocol>
                                     	<port>2049</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>UDP</protocol>
                                     	<port>111</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>UDP</protocol>
                                     	<port>300</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>UDP</protocol>
                                     	<port>302</port>
                                     </service>
                                     <service type="PROTOCOL">
                                        <protocol>UDP</protocol>
                                     	<port>304</port>
                                     </service>
                                 </services>
                                 <action>Accept</action>
                                 <labels/>
                             </access_request>
                              <access_request>
                                 <users>
                                     <user>Any</user>
                                 </users>
                                 <sources>
                                     $src_ip
                                 </sources>
                                 <destinations>
                                     <destination type="IP">
                                         <ip_address>192.168.0.3</ip_address>
                                         <netmask>255.255.255.255</netmask>
                                     </destination>
                                     <destination type="IP">
                                         <ip_address>192.168.0.4</ip_address>
                                         <netmask>255.255.255.255</netmask>
                                     </destination>
                                 </destinations>
                                 <services>
                                     <service type="PROTOCOL">
                                     	<protocol>UDP</protocol>
                                     	<port>123</port>
                                     </service>
                                 </services>
                                 <action>Accept</action>
                                 <labels/>
                             </access_request>
                         </field>
                       </fields>
                 </task>
             </tasks>
        </step>
    </steps>
    <comments/>
</ticket>
"@

#preparing the header
$usr = "your_username_here"
$pwd = "your_password_here"
$cred = "${usr}:${pwd}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($cred)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{ Authorization = $basicAuthValue }

Invoke-RestMethod -Uri "https://tufinsecurechange_hostname/securechangeworkflow/api/securechange/tickets" -Method Post -Headers $headers -ContentType "application/xml" -Body $body
Advertisements
Posted in Powershell, Scripting | Tagged , , | Leave a comment

Compare-Object: Find item in file 1 that is not in file2

The objective is to compare two files, one reference list the other is the testing list. My colleague helped me wrote a script to do the comparison, there were many false positives, so here’s his script:

$output = Compare-Object $file1 $file2 -Property ip -IncludeEqual | Where-Object {$_.SideIndicator -eq "<="}
$output | select ip | Export-Csv .\logs\xxx_ip_diff.csv  -NoTypeInformation

The output always give me items i have on both files and some items from file1.

From stackoverflow i have found a solution to this problem.
See here

So based on the solution, I modified the commands like this:

function find_discrepancy($devices) {
    foreach($device in $devices.Keys) {
        $diff = (Import-Csv "C:\Temp\${device}_ip.csv").IP
        Compare-Object $base $diff -IncludeEqual | Where-Object { $_.SideIndicator -eq '<=' } | ForEach-Object { $_.InputObject } | Set-Content "C:\temp\diff_${device}_ip.csv"
        
        }
        
    }

So actually to properly enumerate the objects that has "<=" I need to use the command foreach-object.

Posted in Powershell, Scripting | Tagged , | Leave a comment

PyForms dependencies

While I was looking for a GUI programming in python I came across PyForms, the scripting with PyForms seemed easy so I install it using pip.

When I was testing a simple code from PyForms, my Python interpreter told me that no module pysettings was found… So I attempted to install from my pycharm repository, pysettings could not install…

Ok.. So I downloaded Git for Windows, and make a PATH in the environment variable, then do this pip install git+https://github.com/UmSenhorQualquer/pyforms.git and pip install git+https://github.com/UmSenhorQualquer/pysettings.git

So i thought all was settled and attempt to run the script again, python said no module loggingbootstrap...i could not find this module, so i commented the line. Here's the import in pyforms __init__.py:

import logging
#import loggingbootstrap
from pysettings import conf

I commented the second line. So i tried running the script again, it says no module for PyQT5... WTF!... Ok so here are the dependencies to use pyforms:

1. pysettings (because pyforms is using conf from this module)
2. pyqt5
3. numpy
4. matplotlib
5. visvis
6. cv2

Ok installing cv2 needs dependencies... read this blog: Install OpenCV 3 with Python 3 on Windows

Posted in Python, Scripting | Tagged , | Leave a comment

[Powershell] Finding discrepancy between two files

thanks to Stackoverlfow: https://stackoverflow.com/questions/8799847/compare-two-csv-files-and-find-discrepancies

The code snippet is about comparing two CSV files containing firewall object groups and list down the discrepancy. the code snippet can be used to out-file to a text.

[System.Collections.ArrayList]$base = Get-Content "C:\Temp\reference_ip.csv"
[System.Collections.ArrayList]$diff = Get-Content "C:\Temp\difference_ip.csv"
$notmatching = @()

foreach ($ip in $base) {
    if (!$diff.Contains($ip)) {
        $notmatching += $ip
        }
    }

Write-Host "Not Matches : "
foreach ($value in $notmatching) {
    $message += $value + [Environment]::NewLine
    }
Write-Host $message
Posted in Powershell, Scripting | Tagged , | Leave a comment

Powershell script to invoke Tufin Path analysis API

There is an undocumented Tufin API, see the code below:

#Parameters must be declared at the start of the script.
Param(
    [Parameter(Mandatory=$true)][string]$usr,
    #[Parameter(Mandatory=$true)][string]$pwd,
    [Parameter(Mandatory=$true)][ipaddress]$src,
    [Parameter(Mandatory=$true)][ipaddress]$dst,
    [Parameter(Mandatory=$false)][string]$svc = 'any'
    )

#Purpose is to obfuscate the password when user type his/her password.
$securepwd = Read-Host("Password") -AsSecureString
$bstrpwd = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securepwd)
#Need to convert the password from secure to plaintext otherwise the encrypted cipher text will locked your account.
$pwd = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstrpwd)

add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$cred = "${usr}:${pwd}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($cred)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{ Authorization = $basicAuthValue }
$date = Get-Date

try {
    #Invoke-RestMethod -Uri "https://tufin_Secure_track_ipaddress/securetrack/api/topology/path_image?src=$($src)&dst=$($dst)&service=$($svc)" -Method Get -ContentType 'application/xml' -Headers $headers -OutFile "$env:USERPROFILE\path_image_$($date.ToString('ddMMyy-HHmm')).png"
    Invoke-RestMethod -Uri "https://tufin_Secure_track_ipaddress/securetrack/api/path/calcImage/src/$($src)/dst/$($dst)/svc/ANY?arrow=true&WithPa=false" -Method Get -ContentType 'application/xml' -Headers $headers -OutFile "$env:USERPROFILE\path_image_$($date.ToString('ddMMyy-HHmm')).png"
} catch {
    $Error[0].ErrorDetails.Message
    
    }
Posted in Powershell, Scripting | Tagged , , , | Leave a comment

Update Cisco ASA object group with netmiko

This is a demo of configuring ASA with netmiko, there is a use case when a server is provisioned, the server’s hostname and ip addresses are assigned automatically by Vrealize, and run a python script to update the object-group of the server.

Here’s the code:

from netmiko import ConnectHandler
from getpass import getpass
import logging

usr = input("Username: ")
pwd = getpass()
asav = {  'device_type': 'cisco_asa',
    'ip': '192.168.1.15',
    'username': usr,
    'password': pwd,
    'secret': pwd,
    'port': '22', }

config_set = ['object network member1', 'host 1.1.1.1 ', 'exit', 'object network member2', 'host 2.2.2.2', 'exit', 'object-group network Group1',
           'network-object object member1', 'network-object object member2' ]

logging.basicConfig(level=logging.DEBUG)
with ConnectHandler(**asav) as m:
    m.enable()
    m.config_mode()
    m.send_config_set(config_set, True)
    m.send_command_expect('write memory')
Posted in Python, Scripting | Tagged , , , | Leave a comment

Extending the python script to configure OSPF with ncclient

Previously I have successfully download the configuration from the netconf enabled router, now i have extended support to configure ospf.
This is a simple lab to further extend and get myself familiarize and comfortable with netconf.

During the lab I was careless, I inadvertently left a space on my netconf snippet that breaks my script and it generate an error, I turned on the debug on the router and found that a “<" was missing.

*Sep  2 04:38:08.709: NETCONF: netconf_xml_interpret.86.failure<?xml version="1.0" encoding="UTF-8"?><nc:rpc xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"message-id="urn:uuid:36abc85e-d850-45b5-95d0-fdf5d0a3226f"><nc:edit-config><nc:target><nc:running/></nc:target><config>
             cli-config-data>
                <cmd<cmd>interface Ethernet0/0</cmd>
                <cmd>ip address 10.0.0.2 255.255.255.252</cmd>
                <cmd>no shutdown</cmd>
            </config></nc:edit-config></nc:rpc>
*Sep  2 04:38:08.709: NETCONF: _nssd.87.snd.now<?xml version="1.0" encoding="UTF-8"?><rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><rpc-error><error-type>rpc</error-type><error-tag>unknown-element</error-tag><error-severity>error</error-severity><error-info><bad-element>cmd</bad-element></error-info></rpc-error></rpc-reply>

So on this lab I have put together a simple menu, the feature to download configuration file and added ospf.
Here's the entire code

import sys, time, os.path
from ncclient import manager
from getpass import getpass
from datetime import datetime
import logging


CREATE_INTERFACE_IP = """
        <config>
            <cli-config-data>
                <cmd>interface %s</cmd>
                <cmd>description Configured by ncclient</cmd>
                <cmd>ip address %s %s</cmd>
                <cmd>no shutdown</cmd>
            </cli-config-data>
        </config>
        """

CREATE_OSPF = """
        <config>
            <cli-config-data>
                <cmd>router ospf %i</cmd>
                <cmd>router-id %s</cmd>
                <cmd>passive-interface default</cmd>
                <cmd>no passive-interface %s</cmd>
                <cmd>network %s 0.0.0.0 area 0</cmd>
                <cmd>network %s 0.0.0.0 area 0</cmd>
            </cli-config-data>
        </config>
     """


def create_interface_ip(conn, interface, ip, mask):
    try:
        config_str = CREATE_INTERFACE_IP % (interface, ip, mask)
        conn.edit_config(target='running', config=config_str)
    except Exception:
        print('Exception occurs while creating interface %s' % interface)


def create_ospf(conn, ospf_id, rid, interface, network1, network2):
    try:
        config_str = CREATE_OSPF % (ospf_id, rid, interface, network1, network2)
        conn.edit_config(target='running', config=config_str)
    except  Exception:
        print('Exception occurs while creating ospf %i' % ospf_id)


def r_connect(host,port,usr,passwd):
    try:
            return manager.connect(host=host,
                    port=port,
                    username=usr,
                    password=passwd,
                    hostkey_verify=False)
    except EnvironmentError:
        print('Exception occurred while connecting %s' % host)


def main_menu():
    print(30 * "*", "Simple Conf Wizard", 30 * "*")
    print("1. Configure OSPF for router.")
    print("2. Download router configuration.")
    print("3. Quit")
    print(60 * "*")


def conn():
    user = input('Username: ')
    password = getpass()
    #loop = True
    with r_connect('192.168.1.46','22',user,password) as m:
        print("Connection is established" )
        time.sleep(3)
        #while loop:
        main_menu()
        try:
                choice = int(input("What you want to do? [1-3] "))
        except ValueError:
                print("Oops you have entered an invalid choice")
                #continue
        if choice == 1:
            ip = input("Enter IP address for Ethernet0/0: ")
            mask = input("Enter subnet mask: ")
            print("Interface has been configured")
            ospf_id = int(input("Enter OSPF id: "))
            router_id = input("Enter router id: ")
            network1 = input("Enter 1st network to be advertised: ")
            network2 = input("Enter 2nd network to be advertised: ")
            create_interface_ip(m, "Ethernet0/0", ip, mask)
            create_ospf(m,ospf_id,router_id,'Ethernet0/0',network1,network2)
            print("OSPF has been configured")
            #time.sleep(3)
        elif choice == 2:
            path = 'd:/temp/'
            today = datetime.now().strftime("%d%m%y-%H%M")
            filename = "config" + today + ".cfg"
            fullpath = os.path.join(path, filename)
            output = m.get_config(source='running').data_xml
            with open(fullpath, "w") as f:
                f.write(output)
                print("Backup saved in {}".format(fullpath))
        elif choice == 3:
            print("bye")
        else:
            print("You may have entered an invalid choice")


if __name__ == '__main__':
    #logging.basicConfig(level=logging.DEBUG)
    conn()

Before configuration

R3#sh ip int brief | include Ethernet0/0
Ethernet0/0 unassigned YES TFTP administratively down down


R3#sh run | s r o
R3#

No OSPF and interface e0/0 is down and no ip address assigned.

Test option 1
pycharm2.png

Here’s the outcome after option 1 was chosen:

R3#
*Sep 2 05:13:58.873: %LINK-3-UPDOWN: Interface Ethernet0/0, changed state to up
R3#
*Sep 2 05:13:59.878: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet0/0, changed state to up
R3#

The interface is up after the option 1 was selected.

Here is the router’s configuration:

R3#sh run int e0/0
Building configuration...

Current configuration : 102 bytes
!
interface Ethernet0/0
description Configured by ncclient
ip address 10.0.0.2 255.255.255.252
end

R3#sh run | s r o
router ospf 1
router-id 3.3.3.3
passive-interface default
no passive-interface Ethernet0/0
network 10.0.0.2 0.0.0.0 area 0
network 192.168.1.46 0.0.0.0 area 0
R3#

Test option 2
pycharm3

Here’s the file in my folder:
pycharm4.png

This is the configuration which was downloaded:
pycharm5

Visible password
The password was visible in debug, however it is not visible when it was executed outside the Python IDE environment:
pycharm6

Posted in OSPF, Python, Scripting | Tagged , , , , , , , | Leave a comment