예제 #1
0
def encrypt_payload(plaintext, encryption_context={}):
    """
    Encrypt CIS payload using keys derived from KMS.

    :plaintext: Payload to be encrypted
    """

    config = get_config()
    ams_key_id = config('arn_master_key', namespace='cis')
    data_key = kms.generate_data_key(KeyId=ams_key_id,
                                     KeySpec='AES_256',
                                     EncryptionContext=encryption_context)
    plaintext_key = data_key.get('Plaintext')
    ciphertext_key = data_key.get('CiphertextBlob')
    iv = os.urandom(12)

    encryptor = Cipher(algorithms.AES(plaintext_key),
                       modes.GCM(iv),
                       backend=default_backend()).encryptor()

    ciphertext = encryptor.update(plaintext) + encryptor.finalize()

    return {
        'ciphertext': ciphertext,
        'ciphertext_key': ciphertext_key,
        'iv': iv,
        'tag': encryptor.tag
    }
예제 #2
0
 def __init__(self, boto_session, publisher, signature,
              encrypted_profile_data):
     self.boto_session = boto_session
     self.config = get_config()
     self.encrypted_profile_data = encrypted_profile_data
     self.publisher = publisher
     self.signature = signature
     self.kinesis_client = None
예제 #3
0
파일: user.py 프로젝트: hidde/cis
 def __init__(self, boto_session=None, profile_data=None):
     """
     :param boto_session: The boto session object from the constructor.
     :param profile_data: The decrypted user profile JSON.
     """
     self.boto_session = boto_session
     self.config = get_config()
     self.profile_data = profile_data
     self.dynamodb_table = None
예제 #4
0
def assume_role_session():
    # Load config
    config = get_config()
    sts = boto3.client('sts')
    sts_response = sts.assume_role(RoleArn=config('iam_role_arn',
                                                  namespace='cis'),
                                   RoleSessionName=config(
                                       'iam_role_session_name',
                                       namespace='cis'))
    logger.info('CIS Publisher role assumed.')

    return boto3.session.Session(
        aws_access_key_id=sts_response['Credentials']['AccessKeyId'],
        aws_secret_access_key=sts_response['Credentials']['SecretAccessKey'],
        aws_session_token=sts_response['Credentials']['SessionToken'],
        region_name='us-west-2')
예제 #5
0
    def __init__(self, boto_session):
        self.config = get_config()
        self.data_key = None
        self.iv = None

        try:
            self.kms = boto_session.client(service_name='kms')
        except ClientError as e:
            logger.info('Boto initialization error : {e}'.format(e=e))
            self.kms = None
        except AttributeError as e:
            logger.info('Boto initialization error : {e}'.format(e=e))
            self.kms = None

        self.kms_key_arn = self.config('arn_master_key', namespace='cis')
        self.plaintext_key = None
예제 #6
0
    def __init__(self, publisher, signature, profile_data):
        """
        :param publisher: Dictionary of information about publisher only required attr is id:
        :param signature: A pykmssig signature.  For now this is optional.
        :param profile_data: The complete user profile as json.
        """
        self.config = get_config()
        self.encryptor = None
        self.publisher = publisher
        self.profile_data = profile_data
        self.signature = signature
        self.user = None

        # Centralize boto session for passing around.
        self.boto_session = None
        self.lambda_client = None
예제 #7
0
def invoke_cis_lambda(data):
    """
    Invoke lambda function in front of the CIS pipeline with data to be pushed to CIS

    :data: Data to be published to CIS (dict)
    """

    payload = prepare_payload(data)
    config = get_config()
    function_name = config('lambda_validator_arn', namespace='cis')
    response = lambda_client.invoke(
        FunctionName=function_name,
        InvocationType='RequestResponse',
        Payload=payload
    )

    return response
예제 #8
0
def publish_to_cis(data, partition_key):
    """
    Publish data to CIS kinesis stream given a partition key.

    :data: Data to be published to kinesis (dict)
    :partition_key: Kinesis partition key used to publish data to
    """

    payload = prepare_payload(data)
    config = get_config()
    stream_arn = config('kinesis_stream_arn', namespace='cis')
    stream_name = stream_arn.split('/')[1]
    response = kinesis.put_record(
        StreamName=stream_name,
        Data=payload,
        PartitionKey=partition_key
    )

    return response
def handle(event, context):
    """This is the main handler called during function invocation."""

    config = get_config()
    custom_logger = utils.CISLogger(
        name=__name__,
        level=config('logging_level', namespace='cis', default='INFO'),
        cis_logging_output=config('logging_output',
                                  namespace='cis',
                                  default='stream'),
        cis_cloudwatch_log_group=config('cloudwatch_log_group',
                                        namespace='cis',
                                        default='')).logger()

    logger = custom_logger.get_logger()

    # Encrypted profile packet contains ciphertext, iv, etc.
    encrypted_profile_packet = json.loads(
        base64.b64decode(event.get('profile').encode()))
    signature = event.get('signature', None)
    publisher = event.get('publisher', None)

    logger.debug(
        'Attempting to push an event for publisher: {}'.format(publisher))

    if signature is not None or signature != {}:
        p = processor.ValidatorOperation(
            boto_session=boto3.Session(region_name='us-west-2'),
            publisher=publisher,
            signature=signature,
            encrypted_profile_data=encrypted_profile_packet)

        result = p.run()
        logger.info(
            'The result of the change operation was {r}'.format(r=result))
    else:
        logger.error('No sigature was present. This operation was untrusted.')
        result = False

    logger.info('VALIDATOR: Processed 1 record.')
    return result
예제 #10
0
 def __init__(self, boto_session):
     self.boto_session = boto_session
     self.dynamodb_table = None
     self.config = get_config()
     self.people = CISTable(self.config('dynamodb_table',
                                        namespace='cis')).all
예제 #11
0
"""Object for fetching ldap data from kangsterizers ldap2s3 connector."""
import boto3
import json
import lzma

from cis.settings import get_config

CONFIG = get_config()


class People(object):
    def __init__(self):
        self.s3 = None

    def connect(self):
        """Returns an s3 bucket resource for a bucket."""
        s3_region = CONFIG('ldap_s3_region', namespace='cis')
        s3_bucket = CONFIG('ldap_diff_bucket', namespace='cis')
        boto_session = boto3.session.Session(region_name=s3_region)
        s3 = boto_session.resource('s3')
        self.s3 = s3.Bucket(s3_bucket)

        return self.s3

    @property
    def all(self):
        return self._get_ldap_json()

    def _get_ldap_json(self):
        if self.s3 is None:
            self.connect()
예제 #12
0
파일: validation.py 프로젝트: djmitche/cis
from pluginbase import PluginBase
from cis.encryption import decrypt_payload
from cis.settings import get_config

plugin_base = PluginBase(package='cis.plugins.validation')
plugin_source = plugin_base.make_plugin_source(searchpath=[
    os.path.join(os.path.abspath(os.path.dirname(__file__)),
                 'plugins/validation/')
])

# List of plugins to load, in order
plugin_load = ['json_schema_plugin', 'mozilliansorg_publisher_plugin']

dynamodb = boto3.resource('dynamodb')
config = get_config()
dynamodb_table = config('dynamodb_table', namespace='cis')
table = dynamodb.Table(dynamodb_table)

logger = logging.getLogger(__name__)


def validate(publisher, **payload):
    """
    Validates the payload passed to CIS.

    :payload: Encrypted payload based on the output of `cis.encryption.encrypt_payload` method
    """

    logger.info(
        "Attempting payload validation for publisher {}".format(publisher))
예제 #13
0
 def publisher(self):
     config = get_config()
     return {
         'id': config('publisher_name', namespace='cis')
     }
def handle(event, context):
    config = get_config()
    custom_logger = utils.CISLogger(
        name=__name__,
        level=config("logging_level", namespace="cis", default="INFO"),
        cis_logging_output=config("logging_output",
                                  namespace="cis",
                                  default="stream"),
        cis_cloudwatch_log_group=config("cloudwatch_log_group",
                                        namespace="cis",
                                        default=""),
    ).logger()

    logger = custom_logger.get_logger()
    logger.info("Stream Processor initialized for stage: idvtoauth0.")

    environment = os.getenv("ENVIRONMENT", "dev")

    if environment == "production":
        environment = "prod"
    else:
        logger.info("Development stage recognized.  Applying to credstash.")
        environment = "dev"

    # New up the config object for CISAuthZero
    config = authzero.DotDict(dict())
    config.client_id = credstash.getSecret(name="cis.client_id",
                                           context={
                                               "app": "cis",
                                               "environment": environment
                                           },
                                           region="us-west-2")

    config.client_secret = credstash.getSecret(name="cis.client_secret",
                                               context={
                                                   "app": "cis",
                                                   "environment": environment
                                               },
                                               region="us-west-2")

    config.uri = credstash.getSecret(name="cis.uri",
                                     context={
                                         "app": "cis",
                                         "environment": environment
                                     },
                                     region="us-west-2")

    client = authzero.CISAuthZero(config)
    client.get_access_token()

    for record in event["Records"]:
        # Kinesis data is base64 encoded so decode here
        user_id = record["dynamodb"]["Keys"]["user_id"]["S"]

        logger.info("Processing record for user: {}".format(user_id))
        logger.info("Searching for dynamo record for user: {}".format(user_id))

        profile = find_user(user_id)
        if profile is not {} or None:
            logger.info(
                "A profile has been located for user: {}".format(user_id))

        if profile is not None:
            logger.info(
                "Attemtping to reintegrate profile for user: {}".format(
                    user_id))
            logger.debug(
                "-------------------Pre-Integration---------------------------"
            )
            logger.debug(json.dumps(profile))
            logger.debug(
                "------------------------End----------------------------------"
            )

            compatible_group_list = []
            # Strip the LDAP prefix from LDAP groups for compatibility
            for group in profile.get("groups"):
                if group.startswith("ldap_"):
                    compatible_group_list.append(re.sub("ldap_", "", group))
                else:
                    compatible_group_list.append(group)

            # Update groups only in Auth0
            profile_groups = {"groups": compatible_group_list}

            try:
                res = client.update_user(user_id, profile_groups)
            except Exception as e:
                # if the user does not exist in auth0, we just skip the record
                if len(e.args) > 0:
                    if e.args[0] == "HTTPCommunicationFailed" and e.args[1][
                            0] == 404:
                        logger.info(
                            "User {} does not exist in Auth0, skipping record".
                            format(user_id))
                        logger.debug("Exception (handled) was: {}".format(e))
                        continue

            logger.info(
                "Updating user group information in auth0 for {}".format(
                    user_id))
            logger.debug(
                "-------------------Post-Integration--------------------------"
            )
            logger.debug(json.dumps(profile))
            logger.debug(
                "------------------------End----------------------------------"
            )

            logger.info("Auth0 processing complete for for user: {}".format(
                res, user_id))
            logger.debug(
                "-------------------Auth0-Response-----------------------------"
            )
            logger.debug(res)
            logger.debug(
                "------------------------End----------------------------------"
            )
        else:
            logger.critical(
                "User could not be matched in vault for userid : {}".format(
                    user_id))

    logger.info("IDVTOAUTH0: Successfully processed {} records.".format(
        len(event["Records"])))

    return "IDVTOAUTH0: Successfully processed {} records.".format(
        len(event["Records"]))