X

Best Practices from Oracle Development's A‑Team

Little Known Ways to Do OCI Governance using Events and Functions

Kiran Thakkar
Consulting Solutions Architect

Overview

In the cloud era, the key metric is speed. That, in combination with a self-service model (every service team owns their little space on the cloud), leads to a less secure cloud. Some of the examples are,

  1. Creation of compute instance with public IP 
  2. Creation of public bucket
  3. Termination of a compute instance in PROD environment
  4. Creation or deletion of API key
  5. Route table or Security List changes

To be agile, you want users to be able to perform all of the above actions. However, as an Administrator, you want to be able to control or be notified when that happens. Or maybe in some cases, delete those artifacts when created. 

Oracle announced some new OCI native services that can be used to implement that. I will talk about those services first and then talk about the Implementation. 

OCI Events

Every OCI service emits events, which are structured messages indicating 1. CRUD operation on OCI service, and 2. The state change of an instance of a service. You can monitor those events and take corrective measures through functions or notify the administrator about the event. OCI also supports adding a filter to the monitored events. OCI Events (the messages, not the service) follow the CloudEvents industry-standard format hosted by the Cloud Native Computing Foundation (CNCF). This standard allows for interoperability between various cloud providers or on-premises systems and cloud providers. You can find more information about Events here

OCI Functions

OCI Functions is OCI service powered by the Fn Project open-source engine. It is a piece is code that you can write using your preferred language and trigger it as needed without worrying about underlying infrastructure including scaling requirements. Oracle will ensure that your application/function is highly-available, secure and monitored. You can invoke the function using CLI, OCI SDK, or events can trigger function invocation and you will be charged only for the resources consumed during the execution. You can find more information about Functions here.

OCI Notifications

OCI Notifications service broadcasts messages to selected channels. Channels can be Email or Pager duty. Notifications follow the Topic and Subscription model. You create topics and users can subscribe to those topics. You can find more information about Notifications here.

OCI Governance use case Implementation

Objective

If a compute instance in the given compartment has a public IP, then terminate the instance.

Implementation

When a monitored event takes place, take some action is the gist of the implementation. 

Implementation

A compute instance can get public IP in two ways. One during provisioning I can choose to assign a public IP or I can create secondary VNIC with public IP post compute instance provisioning. So to protect from both of them, I will monitor for both Instance launch and VNIC attach end events. Since I want to monitor the event in a given compartment, I will add a condition for that compartment.

As Actions, I will configure email notification and invoke a function. The function will check if the compute instance has public IP and terminate the instance if it has.

Events configuration

Event configuration is two parts. One what events do I want to monitor and second what action do I want to take when the event occurs.

Events Configuration screen shot

When the event occurs, I will configure OCI to send an email notification and invoke a function. Email notification, as the name suggests, it straight forward and sends emails to subscribed users with the event payload. I want to focus on function invocation and what can be done in the function.

Event Actions Configuration

IAM policies required for events to be able to invoke function and trigger notification are,

Allow service cloudEvents to use ons-topic in tenancy
Allow service cloudEvents to use functions-family in tenancy

Function Implementation

Function, when invoked, gets event payload in JSON format. The function first will read event payload to determine what is the event type. Every event type payload is different. For example, object storage event payload is different than compute creation. Compute Instance Creation event payload is different than VNIC attachment to compute instance. 
Once you know the event type in function, you can read resource OCID. With resource OCID, you can connect to OCI to fetch more details. For example, fetch public IP for the compute instance once you have OCID of the compute instance. If the compute instance has public IP then you can choose to terminate the instance. 
Below is the code snippet to check if the compute instance has a public IP.

if(cEvent!=null) {
      String eventType = cEvent.getEventType();
      resourceID = cEvent.getData().getResourceId();
      compartmentID = cEvent.getData().getCompartmentID();
      Iterable vnicAttachmentsIterable =computeClient.getPaginators()
            .listVnicAttachmentsRecordIterator(ListVnicAttachmentsRequest.builder()
            .compartmentId(compartmentID)
            .instanceId(resourceID)
            .build());
      List vnicIds = new ArrayList();
      for (VnicAttachment va : vnicAttachmentsIterable) {
         vnicIds.add(va.getVnicId());
      } 
      Set publicIps = new HashSet();
      for (String vnicId : vnicIds) {
         GetVnicResponse getVnicResponse =
             vcnClient.getVnic(GetVnicRequest.builder().vnicId(vnicId).build());
         if (getVnicResponse.getVnic().getPublicIp() != null) {
           publicIps.add(getVnicResponse.getVnic().getPublicIp());
         }
      }
      computeClient.close();
      vcnClient.close();
      if(publicIps.isEmpty()) {
          return "Success. Compute " + resourceID + " doesn't have public IP. You are goodt!";
      }
      else {
          return "Success. Compute " + resourceID + " has public IP. Terminate it!";
      }
}
Once you check that and if the compute instance has public IP, below is the code snippet to terminate the instance. I would like to warn you against doing this. There can be a genuine need to create an instance with public IP so be cognizant of this fact and make sure you know what you are doing.

 

TerminateInstanceRequest request = TerminateInstanceRequest.builder().build();
TerminateInstanceResponse response = computeClient.terminateInstance(request);
String opcRequestID = response.getOpcRequestId();
final GetWorkRequestRequest getWorkRequestRequest = 
      GetWorkRequestRequest.builder()
      .workRequestId(response.getOpcRequestId())
      .build();
GetWorkRequestResponse getWorkRequestResponse =
      Failsafe.with(RETRY_POLICY)
      .get(new Callable() {
            public GetWorkRequestResponse call() {
            return identityClient.getWorkRequest(getWorkRequestRequest);
      }
});

If you need more help with function implementation, you can refer to Github repo for samples.


Email Notification

The email notification configuration is two parts. One is the creation of the topic and the second one is the creation of a subscription for the topic. Here is how you create the topic.

Create Email Notification Topic

Once the topic is created, you can create subscriptions for the topic as captured in the below screenshot.

Subscribe to Notification Topic

A sample email notification with event payload looks like the below email.

Sample Email notification

Apart from governance use cases, Events plus functions can also help in other functional use cases. A couple of examples are,

  1. You want to take an action when a customer uploads a file to object storage
  2. Take an action when Resource Manager finishes the job

Oracle announced Cloud Guard that will do some of these governance use cases Out-Of the Box. We will get back to this topic when Cloud Guard is available.

References

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha