Usage
Basic usage description covers the step to instantiate the Producer and the Consumer, and to send messages.
This requires the availability of a minimal set of encoders, transfer protocols, profiles, and actuator implementations.
See the Developing extensions Section to learn how to add your custom extensions.
In the following we refer to the implementation of a Controller that sends Commands and a Server that controls
local security functions. Simple implementation of these functions are provided in the examples folder.
Create a Server
A Server is intended to instantiate and run the OpenC2 Consumer.
Instantiation requires the definition of the protocol stack and the
configuration of the ``Actuator``s that will be exposed.
As a preliminary step, the necessary modules must be imported. Note that
otupy only includes core grammar and syntax elements, and all
the necessary extensions (including encoders, trasfer protocols,
profiles, and actuators) must be imported separetely. We will use json
encoding and HTTP for our protocol stack, and an iptables actuator for
stateless packet filtering:
import otupy as oc2
from otupy.encoders.json_encoder import JSONEncoder
from otupy.transfers.http_transfer import HTTPTransfer
import otupy.profiles.slpf as slpf
from otupy.actuators.iptables_actuator import IptablesActuator
First, we instantiate the IptablesActuator as an implementation of
the slpf profile:
actuators = {}
actuators[(slpf.nsid,'iptables')]=IptablesActuator()
(there is no specific configuration here because the
IptablesActuator is currently a mockup)
Next, we create the Consumer by instantiating its execution
environment with the list of served ``Actuator``s and the protocol
stack. We also provide an identification string:
consumer = oc2.Consumer("consumer.example.net", actuators, JSONEncoder(), HTTPTransfer("127.0.0.1", 8080))
(the server will be listening on the loopback interface, port 8080)
Finally, start the server:
consumer.run()
The server code can indeed be improved by loading the configuration from file and setting up logging (Logging for otupy).
Create the Controller
A Controller is intended to instantiate an OpenC2 Producer and
to use it to control a remote security function. Instantiation requires
the definition of the same protocol stack we used for the server, and an
identifier:
producer = oc2.Producer("producer.example.net", JSONEncoder(), HTTPTransfer("127.0.0.1", 8080))
(the same modules must be imported as for the Server but the
iptables_actuator)
Next we create the Command, by combining the Action, Target,
Arguments, and Actuator. We will query the remote slpf actuator
for its capabilities. Note how we mix common language elements with
specific extensions for the slpf profile, as expected by the
Specification:
pf = slpf.slpf({'hostname':'firewall', 'named_group':'firewalls', 'asset_id':'iptables'})
arg = slpf.ExtArgs({'response_requested': oc2.ResponseType.complete})
cmd = oc2.Command(oc2.Actions.query, oc2.Features(), actuator=pf)
Finally, we send the command and catch the response:
resp = p.sendcmd(cmd)
(print out resp to check what the server returned)
A concrete implementation of a Controller would also include the business logic to update rules on specific events (even by specific input from the user).