Add most infrastrucure for running AWS commands
This commit is contained in:
parent
1cedfb5c2d
commit
378baa7139
|
@ -3,7 +3,7 @@ import urllib2
|
|||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
class AWS(object):
|
||||
class AwsInstance(object):
|
||||
def __init__(self):
|
||||
try:
|
||||
self.instance_id = urllib2.urlopen('http://169.254.169.254/latest/meta-data/instance-id').read()
|
|
@ -0,0 +1,41 @@
|
|||
import boto3
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
class AwsService(object):
|
||||
"""
|
||||
Supplies various AWS services
|
||||
"""
|
||||
|
||||
# TODO: consider changing from static to singleton, and generally change design
|
||||
access_key_id = None
|
||||
secret_access_key = None
|
||||
region = None
|
||||
|
||||
@staticmethod
|
||||
def set_auth_params(access_key_id, secret_access_key):
|
||||
AwsService.access_key_id = access_key_id
|
||||
AwsService.secret_access_key = secret_access_key
|
||||
|
||||
@staticmethod
|
||||
def set_region(region):
|
||||
AwsService.region = region
|
||||
|
||||
@staticmethod
|
||||
def get_client(client_type, region=None):
|
||||
return boto3.client(
|
||||
client_type,
|
||||
aws_access_key_id=AwsService.access_key_id,
|
||||
aws_secret_access_key=AwsService.secret_access_key,
|
||||
region_name=region if region is not None else AwsService.region)
|
||||
|
||||
@staticmethod
|
||||
def get_session():
|
||||
return boto3.session.Session(
|
||||
aws_access_key_id=AwsService.access_key_id,
|
||||
aws_secret_access_key=AwsService.secret_access_key)
|
||||
|
||||
@staticmethod
|
||||
def get_regions():
|
||||
return AwsService.get_session().get_available_regions('ssm')
|
|
@ -0,0 +1,20 @@
|
|||
from common.cmd.cmd_result import CmdResult
|
||||
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
class AwsCmdResult(CmdResult):
|
||||
"""
|
||||
Class representing an AWS command result
|
||||
"""
|
||||
|
||||
def __init__(self, command_info):
|
||||
super(AwsCmdResult, self).__init__(
|
||||
self.is_successful(command_info), command_info[u'ResponseCode'], command_info[u'StandardOutputContent'],
|
||||
command_info[u'StandardErrorContent'])
|
||||
self.command_info = command_info
|
||||
|
||||
@staticmethod
|
||||
def is_successful(command_info):
|
||||
return command_info[u'Status'] == u'Success'
|
|
@ -0,0 +1,39 @@
|
|||
import time
|
||||
|
||||
from common.cloud.aws_service import AwsService
|
||||
from common.cmd.aws_cmd_result import AwsCmdResult
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
class AwsCmdRunner(object):
|
||||
"""
|
||||
Class for running a command on a remote AWS machine
|
||||
"""
|
||||
|
||||
def __init__(self, instance_id, region, is_powershell=False):
|
||||
self.instance_id = instance_id
|
||||
self.region = region
|
||||
self.is_powershell = is_powershell
|
||||
self.ssm = AwsService.get_client('ssm', region)
|
||||
|
||||
def run_command(self, command, timeout):
|
||||
command_id = self._send_command(command)
|
||||
init_time = time.time()
|
||||
curr_time = init_time
|
||||
command_info = None
|
||||
while curr_time - init_time < timeout:
|
||||
command_info = self.ssm.get_command_invocation(CommandId=command_id, InstanceId=self.instance_id)
|
||||
if AwsCmdResult.is_successful(command_info):
|
||||
break
|
||||
else:
|
||||
time.sleep(0.5)
|
||||
curr_time = time.time()
|
||||
|
||||
return AwsCmdResult(command_info)
|
||||
|
||||
def _send_command(self, command):
|
||||
doc_name = "AWS-RunPowerShellScript" if self.is_powershell else "AWS-RunShellScript"
|
||||
command_res = self.ssm.send_command(DocumentName=doc_name, Parameters={'commands': [command]},
|
||||
InstanceIds=[self.instance_id])
|
||||
return command_res['Command']['CommandId']
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
class CmdResult(object):
|
||||
"""
|
||||
Class representing a command result
|
||||
"""
|
||||
|
||||
def __init__(self, is_success, status_code=None, stdout=None, stderr=None):
|
||||
self.is_success = is_success
|
||||
self.status_code = status_code
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
|
@ -0,0 +1,22 @@
|
|||
from abc import abstractmethod
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
class CmdRunner(object):
|
||||
"""
|
||||
Interface for running a command on a remote machine
|
||||
"""
|
||||
|
||||
# Default command timeout in seconds
|
||||
DEFAULT_TIMEOUT = 5
|
||||
|
||||
@abstractmethod
|
||||
def run_command(self, command, timeout=DEFAULT_TIMEOUT):
|
||||
"""
|
||||
Runs the given command on the remote machine
|
||||
:param command: The command to run
|
||||
:param timeout: Timeout in seconds for command.
|
||||
:return: Command result
|
||||
"""
|
||||
raise NotImplementedError()
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
|
||||
from common.cloud.aws import AWS
|
||||
from common.cloud.aws_instance import AwsInstance
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
@ -15,7 +15,7 @@ class AwsCollector(object):
|
|||
@staticmethod
|
||||
def get_aws_info():
|
||||
LOG.info("Collecting AWS info")
|
||||
aws = AWS()
|
||||
aws = AwsInstance()
|
||||
info = {}
|
||||
if aws.is_aws_instance():
|
||||
LOG.info("Machine is an AWS instance")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import cc.auth
|
||||
from cc.environment import Environment
|
||||
from common.cloud.aws import AWS
|
||||
from common.cloud.aws_instance import AwsInstance
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
@ -8,7 +8,7 @@ __author__ = 'itay.mizeretz'
|
|||
class AwsEnvironment(Environment):
|
||||
def __init__(self):
|
||||
super(AwsEnvironment, self).__init__()
|
||||
self.aws_info = AWS()
|
||||
self.aws_info = AwsInstance()
|
||||
self._instance_id = self._get_instance_id()
|
||||
self.region = self._get_region()
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ from botocore.exceptions import UnknownServiceError
|
|||
from cc.resources.exporter import Exporter
|
||||
from cc.services.config import ConfigService
|
||||
from cc.environment.environment import load_server_configuration_from_file
|
||||
from common.cloud.aws import AWS
|
||||
from common.cloud.aws_instance import AwsInstance
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,7 +20,7 @@ class AWSExporter(Exporter):
|
|||
|
||||
@staticmethod
|
||||
def handle_report(report_json):
|
||||
aws = AWS()
|
||||
aws = AwsInstance()
|
||||
findings_list = []
|
||||
issues_list = report_json['recommendations']['issues']
|
||||
if not issues_list:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import json
|
||||
from flask import request, jsonify, make_response
|
||||
import flask_restful
|
||||
|
||||
|
||||
class RemoteRun(flask_restful.Resource):
|
||||
def run_aws_monkey(self, request_body):
|
||||
instance_id = request_body.get('instance_id')
|
||||
region = request_body.get('region')
|
||||
os = request_body.get('os') # TODO: consider getting this from instance
|
||||
island_ip = request_body.get('island_ip') # TODO: Consider getting this another way. Not easy to determine target interface
|
||||
|
||||
def post(self):
|
||||
body = json.loads(request.data)
|
||||
if body.get('type') == 'aws':
|
||||
local_run = self.run_aws_monkey(body)
|
||||
return jsonify(is_running=local_run[0], error_text=local_run[1])
|
||||
|
||||
# default action
|
||||
return make_response({'error': 'Invalid action'}, 500)
|
Loading…
Reference in New Issue