dsmwatcher.DSMWatcher.java Source code

Java tutorial

Introduction

Here is the source code for dsmwatcher.DSMWatcher.java

Source

/*
* Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package dsmwatcher;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.autoscaling.AmazonAutoScalingClient;
import com.amazonaws.services.autoscaling.model.AutoScalingInstanceDetails;
import com.amazonaws.services.autoscaling.model.DescribeAutoScalingInstancesRequest;
import com.amazonaws.services.autoscaling.model.DescribeAutoScalingInstancesResult;
import com.amazonaws.services.autoscaling.model.DetachInstancesRequest;
import com.amazonaws.services.ec2.model.DeleteTagsRequest;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AttachNetworkInterfaceRequest;
import com.amazonaws.services.ec2.model.AttachNetworkInterfaceResult;
import com.amazonaws.services.ec2.model.CreateNetworkInterfaceRequest;
import com.amazonaws.services.ec2.model.CreateNetworkInterfaceResult;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DeleteNetworkInterfaceRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DescribeNetworkInterfacesRequest;
import com.amazonaws.services.ec2.model.DescribeNetworkInterfacesResult;
import com.amazonaws.services.ec2.model.DescribeSubnetsRequest;
import com.amazonaws.services.ec2.model.DetachNetworkInterfaceRequest;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.GroupIdentifier;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceNetworkInterface;
import com.amazonaws.services.ec2.model.ModifyNetworkInterfaceAttributeRequest;
import com.amazonaws.services.ec2.model.NetworkInterfaceAttachmentChanges;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.Subnet;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.util.EC2MetadataUtils;
import com.amazonaws.util.EC2MetadataUtils.NetworkInterface;
import com.trendmicro.ds.platform.rest.api.ICloudAccountAPI;
import com.trendmicro.ds.platform.rest.message.error.ErrorMessage;
import com.trendmicro.ds.platform.rest.object.cloud.CloudAccountElement;
import com.trendmicro.ds.platform.rest.object.cloud.CloudAccountListing;
import com.trendmicro.webserviceclient.generated.*;

import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.jboss.resteasy.client.ClientResponse;
import org.jboss.resteasy.client.ClientResponseFailure;
import org.jboss.resteasy.client.ProxyFactory;
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.spi.ResteasyProviderFactory;

/**
 * class <code>DSMWatcher</code> DSM API client
 *
 */
public class DSMWatcher extends ClientUtils {

    public DSMWatcher() throws Exception {
        super();
        // TODO Auto-generated constructor stub
    }

    /*************************************************************************
      * Data Members
      *************************************************************************/
    private String _sid = null;

    /*************************************************************************
     * Main
     *************************************************************************/

    public static void main(String[] args) throws Exception {
        DSMWatcher client = new DSMWatcher();
        while (true) {
            client.doRetrieveAgentInformation();
            TimeUnit.MINUTES.sleep(1);
            client.loadProps();
        }
    }

    public void doRetrieveAgentInformation() throws Exception {
        HostStatusTransport hostStatus;
        boolean isolationCandidate;
        List<NetworkInterface> netInts = EC2MetadataUtils.getNetworkInterfaces();
        String vpcid = EC2MetadataUtils.getData(
                "/latest/meta-data/network/interfaces/macs/" + netInts.get(0).getMacAddress() + "/vpc-id/");
        String placement = EC2MetadataUtils.getData("/latest/meta-data/placement/availability-zone/");
        region = Regions.fromName(placement.substring(0, placement.length() - 1));
        AmazonEC2Client ec2 = new AmazonEC2Client().withRegion(region);
        DescribeInstancesResult descInstances = ec2.describeInstances(new DescribeInstancesRequest().withFilters(
                new Filter("vpc-id").withValues(vpcid), new Filter("instance-state-name").withValues("running")));
        List<Reservation> runningInstances = descInstances.getReservations();
        _ManagerService = _Service.getManager(new URL(dsmSOAP));
        try {

            _sid = _ManagerService.authenticate(dsmUser, dsmPass);
            HostTransport host;

            RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
            ApacheHttpClient4Executor executor = new ApacheHttpClient4Executor();
            ICloudAccountAPI cloudAPI = ProxyFactory.create(ICloudAccountAPI.class, dsmREST, executor);
            // resync the cloud accounts to ensure the DSM has the latest info
            try {
                CloudAccountListing cloudAccounts = cloudAPI.getCloudAccounts(_sid);
                List<CloudAccountElement> accounts = cloudAccounts.getCloudAccounts();
                for (CloudAccountElement account : accounts)
                    if (account.getCloudType().equals("AMAZON"))
                        cloudAPI.synchronizeCloudAccount(account.getCloudAccountId(), _sid);
            } catch (ClientResponseFailure e) {

                ClientResponse<?> clientResponse = e.getResponse();
                javax.ws.rs.core.Response.Status status = clientResponse.getResponseStatus();
                log("Server returned error status code " + status.getStatusCode() + " (" + status + ")");
                ErrorMessage errorMessage = clientResponse.getEntity(ErrorMessage.class);
                log("Returned error message: " + errorMessage.getMessage());
                e.printStackTrace();

            } catch (Exception e) {
                this.log("error:" + e.getMessage());
                e.printStackTrace();

            }
            for (Reservation reservation : runningInstances) {
                List<Instance> instances = reservation.getInstances();
                for (Instance instance : instances) {
                    Boolean beenNotified = notifiedInstances.contains(instance.getInstanceId());
                    Boolean isExempt = checkExempt(instance, ec2);
                    ArrayList<String> violationReasons = new ArrayList<String>();
                    host = null;
                    isolationCandidate = false;
                    if (!instance.getPrivateDnsName().isEmpty())
                        host = _ManagerService.hostRetrieveByName(instance.getPrivateDnsName(), _sid);
                    if (host == null)
                        host = _ManagerService.hostRetrieveByName(instance.getInstanceId(), _sid);
                    if (host == null && !instance.getPublicDnsName().isEmpty())
                        host = _ManagerService.hostRetrieveByName(instance.getPublicDnsName(), _sid);
                    if (host == null && !(instance.getPublicIpAddress() == null))
                        host = _ManagerService.hostRetrieveByName(instance.getPublicIpAddress(), _sid);
                    if (host == null)
                        host = _ManagerService.hostRetrieveByName(instance.getPrivateIpAddress(), _sid);
                    if (host == null) //giveup
                        error("Error: instance found in DescribeInstances but not found in DSM");
                    if (host != null) {
                        hostStatus = (HostStatusTransport) _ManagerService.hostGetStatus(host.getID(), _sid);
                        Boolean isIsolated = checkIfIsolated(instance, ec2);
                        if (hostStatus.getOverallStatus().equals("Unmanaged (Unknown)")) {
                            if (!isIsolated && !isExempt && !beenNotified)
                                log("Found unmanaged instance in EC2:" + instance.getInstanceId()
                                        + " with IP address of " + instance.getPrivateIpAddress()
                                        + " is currently running and not managed by Deep Security.");
                            isolationCandidate = true;
                            violationReasons.add("Instance is unmanaged");

                        } else {

                            // SecurityProfileTransport hostSecurityProfile = _ManagerService.securityProfileRetrieve(hostSecurityProfileID, _sid);
                            if (requireAV && (hostStatus.getOverallAntiMalwareStatus().startsWith(avOn) == false)) {

                                if (!isIsolated && !isExempt && !beenNotified
                                        && (hostStatus.getOverallAntiMalwareStatus().compareTo(
                                                "Anti-Malware: Smart Protection Server Disconnected for Smart Scan") != 0)) {
                                    log("Policy violation: Instance " + instance.getInstanceId()
                                            + " with IP address of " + instance.getPrivateIpAddress()
                                            + " found with AV agent disabled");
                                    //log("DEBUG: getOverallAntiMalwareStatus() returned:" + hostStatus.getOverallAntiMalwareStatus());
                                }
                                if (!isIsolated && (hostStatus.getOverallAntiMalwareStatus().compareTo(
                                        "Anti-Malware: Smart Protection Server Disconnected for Smart Scan") != 0)) {
                                    isolationCandidate = true;
                                    violationReasons.add("AV is required but disabled");
                                }
                            }

                            if (requireFW && (hostStatus.getOverallFirewallStatus().substring(0, fwOn.length())
                                    .compareTo(fwOn) != 0)) {
                                if (!isIsolated && !isExempt && !beenNotified)
                                    log("Policy violation: Instance " + instance.getInstanceId()
                                            + " with IP address of " + instance.getPrivateIpAddress()
                                            + " found with host based firewall disabled");
                                isolationCandidate = true;
                                violationReasons.add("Firewall is required but disabled");
                            }

                            if (requireFIM && (hostStatus.getOverallIntegrityMonitoringStatus()
                                    .substring(0, fimOn.length()).compareTo(fimOn) != 0)) {
                                if (!isIsolated && !isExempt && !beenNotified)
                                    log("Policy violation: Instance " + instance.getInstanceId()
                                            + " with IP address of " + instance.getPrivateIpAddress()
                                            + " found with file integrity monitoring disabled");
                                isolationCandidate = true;
                                violationReasons.add("File Integrity Monitoring is required but disabled");
                            }

                            if (requireDPI && (hostStatus.getOverallDpiStatus().substring(0, dpiOn.length())
                                    .compareTo(dpiOn) != 0)) {
                                if (!isIsolated && !isExempt && !beenNotified)
                                    log("Policy violation: Instance " + instance.getInstanceId()
                                            + " with IP address of " + instance.getPrivateIpAddress()
                                            + " found with deep packet inspection disabled or in an invalid mode");
                                isolationCandidate = true;
                                violationReasons.add(
                                        "Deep Packet Instection is required but disabled or not in enforce mode");
                            }

                        }

                        if (isolationCandidate && enableIsolation && !isIsolated && !isExempt) {
                            log("Instance " + instance.getInstanceId()
                                    + " will be isolated for failing one or more policy checks");
                            notifyAdmin(instance, violationReasons, false);
                            notifiedInstances.add(instance.getInstanceId());
                            isolateInstance(instance, ec2);

                        }
                        if (isolationCandidate && !enableIsolation && !isIsolated && !isExempt && !beenNotified) {
                            log("Instance " + instance.getInstanceId()
                                    + " is elligable for isolation but enforcement is disabled");
                            notifyAdmin(instance, violationReasons, false);
                            notifiedInstances.add(instance.getInstanceId());
                        }

                        if (!isolationCandidate && isIsolated) {
                            removeIsolation(instance, ec2);
                            notifyAdmin(instance, violationReasons, true);
                        }
                        if (beenNotified && !isolationCandidate)
                            notifiedInstances.remove(instance.getInstanceId());
                    }

                }
            }
        }

        catch (Exception e) {
            this.log("Error: " + e.getMessage());
            e.printStackTrace();
        }
        if (_sid != null)
            _ManagerService.endSession(_sid);

    }

    public void removeIsolation(Instance instance, AmazonEC2Client ec2) throws Exception {
        List<InstanceNetworkInterface> ienis = instance.getNetworkInterfaces();
        for (InstanceNetworkInterface ieni : ienis) {
            DescribeNetworkInterfacesRequest netReq = new DescribeNetworkInterfacesRequest()
                    .withNetworkInterfaceIds(ieni.getNetworkInterfaceId());
            DescribeNetworkInterfacesResult netResult = ec2.describeNetworkInterfaces(netReq);
            List<com.amazonaws.services.ec2.model.NetworkInterface> enis = netResult.getNetworkInterfaces();
            for (com.amazonaws.services.ec2.model.NetworkInterface eni : enis) {
                List<Tag> tagSet = eni.getTagSet();
                List<Tag> tagSetRemove = new LinkedList<Tag>();
                boolean isolatedENI = false;
                boolean IRENI = false;
                String origSecGroups = null;
                List<String> origSecGroupsList = new ArrayList<String>();

                for (Tag tag : tagSet) {
                    if (tag.getKey().compareTo("PreIsolationSG") == 0) {
                        origSecGroups = tag.getValue();
                        tagSetRemove.add(tag);
                        isolatedENI = true;
                    } else if (tag.getKey().compareTo("InIsolation") == 0) {
                        tagSetRemove.add(tag);
                    } else if (tag.getKey().compareTo("IRENI") == 0) {
                        IRENI = true;
                    }
                }
                if (isolatedENI) {
                    for (String s : origSecGroups.split(",")) {
                        origSecGroupsList.add(s);
                    }

                    ModifyNetworkInterfaceAttributeRequest netReqest = new ModifyNetworkInterfaceAttributeRequest()
                            .withNetworkInterfaceId(eni.getNetworkInterfaceId()).withGroups(origSecGroupsList);
                    ec2.modifyNetworkInterfaceAttribute(netReqest);
                    DeleteTagsRequest dtr = new DeleteTagsRequest().withResources(eni.getNetworkInterfaceId())
                            .withTags(tagSetRemove);
                    ec2.deleteTags(dtr);
                }
                if (IRENI) {
                    DetachNetworkInterfaceRequest detachNetworkInterfaceRequest = new DetachNetworkInterfaceRequest()
                            .withAttachmentId(eni.getAttachment().getAttachmentId());
                    ec2.detachNetworkInterface(detachNetworkInterfaceRequest);
                    TimeUnit.SECONDS.sleep(30);
                    if (eni.getStatus().compareTo("available") != 0) { //detach is taking awhile, wait another 30 seconds
                        TimeUnit.SECONDS.sleep(30);
                    }
                    DeleteNetworkInterfaceRequest deleteNetworkInterfaceRequest = new DeleteNetworkInterfaceRequest()
                            .withNetworkInterfaceId(eni.getNetworkInterfaceId());
                    ec2.deleteNetworkInterface(deleteNetworkInterfaceRequest);
                }
            }
        }
        log("Instance " + instance.getInstanceId() + " with IP address of " + instance.getPrivateIpAddress()
                + " has been removed from isolation");
    }

    public Boolean checkExempt(Instance instance, AmazonEC2Client ec2) throws Exception {
        //check for DSM IP address, address of ourself, presence of the EXEMPTTAG
        // and if Start Time is < 5 mintues from now
        List<Tag> tagSet = instance.getTags();
        //EC2MetadataUtils metadata = new EC2MetadataUtils();
        List<NetworkInterface> netInts = EC2MetadataUtils.getNetworkInterfaces();
        String myIP = netInts.get(0).getLocalIPv4s().get(0);
        if (instance.getPrivateIpAddress().compareTo(myIP) == 0) {
            return true;
        }
        if (instance.getPrivateIpAddress().compareTo(dsmIP) == 0) {
            return true;
        }
        for (Tag tag : tagSet) {
            if ((tag.getKey().compareTo(exemptTag) == 0) && (tag.getValue().compareTo(exemptTagValue)) == 0) {
                return true;
            }
        }
        if ((instance.getLaunchTime().getTime() + 300000) > System.currentTimeMillis()) {
            return true;
        }
        return false;
    }

    public Boolean checkIfIsolated(Instance instance, AmazonEC2Client ec2) throws Exception {
        boolean inIRSubnet = false;
        boolean hasDenySG = false;
        //check for tags on other ENIs
        List<InstanceNetworkInterface> ienis = instance.getNetworkInterfaces();
        for (InstanceNetworkInterface ieni : ienis) {
            for (String IRSubnet : IRSubnets) {
                if (IRSubnet.compareTo(ieni.getSubnetId()) == 0) {
                    inIRSubnet = true;
                }
            }
            List<GroupIdentifier> inititalSecGroups = ieni.getGroups();
            for (GroupIdentifier secGroup : inititalSecGroups) {
                if (secGroup.getGroupId().equals(denyAllSG)) {
                    DescribeNetworkInterfacesRequest netReq = new DescribeNetworkInterfacesRequest()
                            .withNetworkInterfaceIds(ieni.getNetworkInterfaceId());
                    DescribeNetworkInterfacesResult netResult = ec2.describeNetworkInterfaces(netReq);
                    List<com.amazonaws.services.ec2.model.NetworkInterface> enis = netResult.getNetworkInterfaces();
                    for (com.amazonaws.services.ec2.model.NetworkInterface eni : enis) {
                        List<Tag> tagSet = eni.getTagSet();
                        for (Tag tag : tagSet) {
                            if (tag.getKey().compareTo("InIsolation") == 0) {
                                hasDenySG = true;
                            }
                        }
                    }
                }
            }

        }
        return (inIRSubnet && hasDenySG);
    }

    public void handleAutoScaledInstance(Instance instance) throws Exception {
        AmazonAutoScalingClient as = new AmazonAutoScalingClient().withRegion(region);
        DescribeAutoScalingInstancesResult describeResult = as.describeAutoScalingInstances(
                new DescribeAutoScalingInstancesRequest().withInstanceIds(instance.getInstanceId()));
        if (describeResult.getAutoScalingInstances().size() == 0) {
            return;
        }
        AutoScalingInstanceDetails instanceDetails = describeResult.getAutoScalingInstances().get(0);
        DetachInstancesRequest detachRequest = new DetachInstancesRequest()
                .withInstanceIds(instanceDetails.getInstanceId())
                .withAutoScalingGroupName(instanceDetails.getAutoScalingGroupName())
                .withShouldDecrementDesiredCapacity(false);
        as.detachInstances(detachRequest);
    }

    public void isolateInstance(Instance instance, AmazonEC2Client ec2) throws Exception {
        Subnet targetIRSubnet = null;
        handleAutoScaledInstance(instance); //check for autoscaling, if autoscaled instance detach first 
                                            // to prevent heathcheck failure and termination
        DescribeSubnetsRequest subnetRequest = new DescribeSubnetsRequest().withSubnetIds(instance.getSubnetId());
        List<Subnet> sourceSubnet = ec2.describeSubnets(subnetRequest).getSubnets();
        String targetAZStr = sourceSubnet.get(0).getAvailabilityZone();
        for (String IRSubnet : IRSubnets) {
            subnetRequest = new DescribeSubnetsRequest().withSubnetIds(IRSubnet);
            if (targetAZStr
                    .compareTo(ec2.describeSubnets(subnetRequest).getSubnets().get(0).getAvailabilityZone()) == 0) {
                targetIRSubnet = ec2.describeSubnets(subnetRequest).getSubnets().get(0);
            }
        }
        if (targetIRSubnet == null) {
            error("Unable to find an isolation subnet for instance " + instance.getInstanceId());
            return;
        }
        List<InstanceNetworkInterface> ienis = instance.getNetworkInterfaces();
        for (InstanceNetworkInterface ieni : ienis) {
            String eniTag = "";
            List<GroupIdentifier> inititalSecGroups = ieni.getGroups();
            for (GroupIdentifier secGroup : inititalSecGroups) {
                eniTag += secGroup.getGroupId() + ",";
            }
            eniTag = eniTag.substring(0, eniTag.length() - 1);
            DescribeNetworkInterfacesRequest netReq = new DescribeNetworkInterfacesRequest()
                    .withNetworkInterfaceIds(ieni.getNetworkInterfaceId());
            DescribeNetworkInterfacesResult netResult = ec2.describeNetworkInterfaces(netReq);
            List<com.amazonaws.services.ec2.model.NetworkInterface> enis = netResult.getNetworkInterfaces();
            for (com.amazonaws.services.ec2.model.NetworkInterface eni : enis) {
                List<Tag> tagSet = eni.getTagSet();
                Tag saveSGTag = new Tag().withKey("PreIsolationSG").withValue(eniTag);
                Tag isolationTag = new Tag().withKey("InIsolation").withValue("True");
                tagSet.add(saveSGTag);
                tagSet.add(isolationTag);
                CreateTagsRequest ctr = new CreateTagsRequest().withResources(eni.getNetworkInterfaceId())
                        .withTags(tagSet);
                ec2.createTags(ctr);
                ModifyNetworkInterfaceAttributeRequest netReqest = new ModifyNetworkInterfaceAttributeRequest()
                        .withNetworkInterfaceId(eni.getNetworkInterfaceId()).withGroups(denyAllSG);
                ec2.modifyNetworkInterfaceAttribute(netReqest);
            }
        }
        CreateNetworkInterfaceRequest newENIReq = new CreateNetworkInterfaceRequest()
                .withSubnetId(targetIRSubnet.getSubnetId()).withGroups(IRSecGrp);
        CreateNetworkInterfaceResult newENIResult = ec2.createNetworkInterface(newENIReq);
        AttachNetworkInterfaceRequest attachReq = new AttachNetworkInterfaceRequest()
                .withNetworkInterfaceId(newENIResult.getNetworkInterface().getNetworkInterfaceId())
                .withInstanceId(instance.getInstanceId())
                .withDeviceIndex(instance.getNetworkInterfaces().size() + 1);
        AttachNetworkInterfaceResult attachResults = ec2.attachNetworkInterface(attachReq);
        NetworkInterfaceAttachmentChanges attachTerm = new NetworkInterfaceAttachmentChanges()
                .withAttachmentId(attachResults.getAttachmentId()).withDeleteOnTermination(true);
        ModifyNetworkInterfaceAttributeRequest setDeleteOnTerm = new ModifyNetworkInterfaceAttributeRequest()
                .withAttachment(attachTerm)
                .withNetworkInterfaceId(newENIResult.getNetworkInterface().getNetworkInterfaceId());
        ec2.modifyNetworkInterfaceAttribute(setDeleteOnTerm);
        CreateTagsRequest tagNewENIReq = new CreateTagsRequest();
        List<Tag> isolationENITags = newENIResult.getNetworkInterface().getTagSet();
        Tag newENITag = new Tag().withKey("IRENI").withValue("True");
        isolationENITags.add(newENITag);
        tagNewENIReq.setTags(isolationENITags);
        tagNewENIReq.withResources(newENIResult.getNetworkInterface().getNetworkInterfaceId());
        ec2.createTags(tagNewENIReq);
    }

    public void notifyAdmin(Instance instance, ArrayList<String> violations, Boolean remediated) throws Exception {
        AmazonSNSClient snsClient = new AmazonSNSClient().withRegion(region);
        String message = "The instance " + instance.getInstanceId() + " with IP address "
                + instance.getPrivateIpAddress() + " was found with the following violations:";
        if (!remediated) {
            for (String reason : violations)
                message += "\n" + reason;
            if (enableIsolation)
                message += "\nEnforcement is enabled and the instance has been isolated";
            else
                message += "\nEnforcement is disabled - no action was taken";
        } else
            message = "The instance " + instance.getInstanceId() + " with IP address "
                    + instance.getPrivateIpAddress()
                    + " is no longer in violation of any policies and has been removed from isolation";
        PublishRequest publishRequest = new PublishRequest(topicARN, message);
        snsClient.publish(publishRequest);

    }

}