“Hey Juniper, How’s the security state of my network?”

“Hey Juniper, How’s the security state of my network?”

Most of us probably have asked Siri, Alexa, Google some questions and answers over the past years; Smart assistants are one of those new interactions. And honestly, not that many questions you asked were probably related to networks, were they? And yet, after hearing Juniper present at Security Field Day 3, these type of questions might in the near future become a normal way to allow you to interact with the network. Sounds like something from Star Trek, and is just science fiction? I beg to differ for a number of reasons. 

Before I dive into Juniper’s security strategy, let’s first review the current state of Artificial Intelligence (AI) and Machine Learning (ML) as a concept. To do that, I will explain what happens when you ask Siri to do something or a question like what is the date?.  

First of all, after you’ve asked the question, that audio bit (which is just a record of frequencies) is guessed into a sentence. It is a form of translation, where Machine Learning is used to do well-calculated guesses in what kind of word you tried to pronounce. And I can tell you that if English is not your native tongue, some weird word-guesses come out.

 

Once there is a digital sentence, another process is used to narrow down your digital sentence into a single pattern-matched result. This allows you to say things like “create a meeting on date X, Y or z”.
The model uses the pattern “create a meeting” for the match and the other values are stored in variables.

After a pattern has been matched, the code corresponding to that pattern is executed. The result of that code will be a string/sentence. That sentence is then being translated to audio using Text-To-Speech and read out loud to you.

This is a perfect flow for a single sentence / command /question. But many of these smart assistents start to show real issues once you start to create related questions, like you can do with a toddler.  And that is because the flow I described above does not have that much space for relaying context between flows. So most models in these smart assistents are built / designed for a single task, and if you put them in sequence, it appears as if the assistent is “smart”. But it is not (yet).

Yes, developments go fast, and I heard last year in San Jose a great story of self-learning models and also the core faults that are inside these models because of the way the models are designed and built. But that is a completely other discussion. 

But if AI/ML is not that far ahead yet, how would you then be able to ask Juniper about the security state of the network? That how is one of the things Juniper told at Security Field Day 3.

They leverage the power of AI/ML (and that is to have more answers than just a yes or now) in their security solutions for only a predefined, supervised, set of options. Juniper uses models (they call them supervised models) to analyse metadata about the flows in your network to detect malware and other anomalies in your network, just like other network and security vendors have done. Juniper has adopted AI/ML on detecting anomalies or other weird behaviour on your network. And that can help you a lot in gaining more visibility and control in your network.

Because with everything connected to the network, increased security by leveraging encryption, more data in the cloud, we as a human are reaching our limits in finding anomalies or odd behaviors by hand. A simple computer, using a properly tuned model, can find those anomalies much faster. And because that model does that, you can focus on determining whether that anomaly is really an anomaly of yet another new application on the network.

And if you would trust those reports blindly, you can of course automate actions, but personally I am always careful with those. Suppose it is the CEO’s smartphone, you might want to call the CEO first before you throw him off the network.

Personally I do believe firmly in that AI/ML can help you in your daily job in finding those odd behaviors that without them you’d never be able to spot and help you in providing a better, smoother, more stable and secure network. But you do need to keep in mind that it is still a computer that presents you information from a lot of data and that presentation will be biased.

But definitely a good thing that Juniper has started to embrace that principle across their portfolio. 
That can bring them quite a bit.

And to be able to ask Juniper about the security state of the network? That would be not that hard to implement, because JunOS has API’s from the start. Just build an application and integrate it with existing API’s for smart assistents. If you want to see a demo, just watch this video taken from a presentation where I asked Siri how many clients were connected to the network.

Swift, JSON Encoding/Decoding and subclasses

Swift, JSON Encoding/Decoding and subclasses

Over the past weeks I have been preparing for two CiscoLive Barcelona breakout sessions. In one of them I will give a brief demo and the other session where I will be covering parts of the Cisco Press book that I wrote. The preparation itself is not only about the slides, but also developing code that is to be used in the demo’s. These demo’s are built on iOS devices and run on some containers, so I have been writing that software in Swift, which is a beautiful and powerful programming language. One of my previous posts covers some principles of Swift. One really powerful feature is the easy capability to encode or decode data to the JSON format.  

If you want to have a class to be able to convert to and from a JSON format, just use the Codable protocol and you’re ready, see the code example below:

/*
 * Enumeration of supported message types. Extend this for new messages
 */
enum MessageType : Int, Codable {
    case unknown = 0            // default, unknown
    case acknowledgement = 255  // acknowledgement to message, if required
    case hello = 1              // hello, for keep alive, always followed by ack
    case sendMessage = 2        // send a unicast message to another client
    case broadcast = 3          // send a message to all connected clients
}

/*
 * Generic parent class
 * Every message has the following attributes
 * Version: To define which version we are talking about
 * Command of the message
 * client-id that sends the message
 */ unique request id, used for acknowledging, etc..
class Message : Codable, prettyPrint  {
    var version : String = "1.0"
    var msgType : MessageType = .unknown
    var clientId: String = "" // client host, generated by the server to guarantee
    var requestId: String = UUID.init().uuidString  // unique request id for this message, used in the ack
    
    // Default constructor
    // Not used cause calling super.init can override msgType value
    init() {
        // empty on purpose
    }
}
This code example defines a class message with variables for messageType (of type MessageType), requestId, which is a unique UUID string value, and a data variable which can contain any String. So let’s say I create a new message , called hello with the data “Hello there!” with the following code sample:
let msg = Message()
msg.msgType = .hello
msg.data = "Hello There!"

To convert this to JSON, this would only require a few lines of code:

let encoder = JSONEncoder()
let jsonData = try encoder.encode(msg)

The variable jsonData (of type Data) now contains a JSON-version of the earlier created message. Just to check the output, I can use the following commands to convert that data to String and output it in XCode’s Playground. 

let jsonDataAsString = String(data: jsonData, encoding: .utf8)

Suppose you would like to extend our message class with a special broadcast message, where the message can be sent to a all endpoints.. You could add an optional broadcastContent variable to the message class and create a state machine to determine when to use that value. Another alternative is to leverage the power of object-oriented programming and create a new subtype, like the following code example:

/*
 * BroadcastMessage is used to broadcast a message to all connected clients
 */
class BroadcastMessage : Message {
    // response message
    var msgContent : String = ""   // Message to broadcast   
}

So when you’d create a multicast message, like below, you’d expect that it would contain all attributes in the json file, right? Let’s check it out in Playground:

As you can see, the output does not contain all attributes of the broadcast message! It only contains the base message type class values. The msgContent variable is not included. It took me some time debugging and researching to figure out what happens. Swift bug SR-5431 and SR-4722  provide more details. Without going into those bugs, it comes down to the fact that as soon as you subclass a class that conforms to Codable, you need to override the default encode/decode methods and write your own. After some fiddling around, I have used the following code pattern to achieve that result.

/* Generic parent class
 * Every message has the following attributes
 * Version: To define which version we are talking about
 * Command of the message
 * client-id that sends the message
 * unique request id, used for acknowledging, etc..
 */
class Message : Codable, prettyPrint  {
    var version : String = "1.0"
    var msgType : MessageType = .unknown
    var data: String = "" // client host, generated by the server to guarantee
    var requestId: String = UUID.init().uuidString  // unique request id for this message, used in the ack
    
    private enum CodingKeys: CodingKey {
        case version, msgType, data, requestId
    }
    
    
    // Default constructor
    // Not used cause calling super.init can override msgType value
    init() {
        // empty on purpose
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        version = try container.decode(String.self, forKey: .version)
        msgType = try container.decode(MessageType.self, forKey: .msgType)
        data = try container.decode(String.self, forKey: .data)
        requestId = try container.decode(String.self, forKey: .requestId)
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(version, forKey: .version)
        try container.encode(msgType, forKey: .msgType)
        try container.encode(data, forKey: .data)
        try container.encode(requestId, forKey: .requestId)
    }
}

/*
 * BroadcastMessage is used to broadcast a message to all connected clients
 */
class BroadcastMessage : Message {
    // response message
    var msgContent : String = ""   // Message to broadcast
    
    // coding keys enumeration used for JSON encoding/decoding
    private  enum CodingKeys: CodingKey {
        case msgContent
    }
    
    // set class variables
    private func initClassVars() {
        self.msgType = .broadcast
        msgContent = ""
    }
    
    // default constructor. Call the parent and set variables
    override init() {
        super.init()
        initClassVars()
    }
    
    // Constructor used to instantiate a class from JSON Data
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        msgContent = try container.decode(String.self, forKey: .msgContent)
        try super.init(from: decoder)
    }
    
    // Method used to encode class to JSON
    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(msgContent, forKey: .msgContent)
        try super.encode(to: encoder)
    }
}

As you can see, when BroadcastMessage is converted to JSON, it is now correctly encoded.

I am now using the coding pattern below to achieve this functionality:

  • Create a private enum called CodingKeys that follows CodingKey. ]
  • Enter all class variables as part of the enumeration
  • Create custom encoders and decoders for the base class
  • In the subclass, define a new private enum called CodingKeys . I have marked both private so the compiler knows which variable to know in which function
  • Create the custom encoders
  • Encode the variables of the child class and then
  • Call the encoder / decoder of the parent class 

Swift & Network programmability, a good combo? An introduction.

Swift & Network programmability, a good combo? An introduction.

Swift is commonly known by iOS and MacOSX Software developers as Apple introduced the language in 2014 for MacOSX, iOS and Linux application development.
In my role as software engineer I’ve used different programming languages to build small tools, solutions or prototypes. For network programmability I’ve used Java as my primary language. I have my reasons, which I might share later in another post.

Network Programmability on the web pretty much evolves around Python. Is Swift mature enough and powerfull enough to be used for programming the network? Time to write up my experiences in a blog series. The first post is an introduction to Swift. (more…)