Skip to content

Commit

Permalink
add AWS Lambda sample scripts to examples
Browse files Browse the repository at this point in the history
  • Loading branch information
aaunario-keeper authored and sk-keeper committed Oct 11, 2024
1 parent 0e48383 commit b147c8e
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 0 deletions.
129 changes: 129 additions & 0 deletions examples/aws_lambda/lambda_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# _ __
# | |/ /___ ___ _ __ ___ _ _ ®
# | ' </ -_) -_) '_ \/ -_) '_|
# |_|\_\___\___| .__/\___|_|
# |_|
#
# Keeper Commander
# Copyright 2024 Keeper Security Inc.
# Contact: ops@keepersecurity.com
#
#
# Sample AWS Lambda handler script
# In this example, we generate a report that combines the outputs
# of the `security-audit-report` and `user-report` commands,
# and then send those results to a specified email address ("KEEPER_SENDTO")


import json
import os
import datetime
from typing import Optional

from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import boto3

from keepercommander import api
from keepercommander.commands.enterprise import UserReportCommand
from keepercommander.commands.security_audit import SecurityAuditReportCommand
from keepercommander.params import KeeperParams


# This Lambda's entry point
def lambda_handler(event, context):
params = get_params()
api.login(params)
api.query_enterprise(params, True)

# Log Commander-related issues (e.g., incorrect credentials)
# using AWS's built-in logging module and abort
if not params.session_token:
print('Not connected')
return 'Error: See Lambda log for details'
if not params.enterprise:
print('Not enterprise administrator')
return 'Error: See Lambda log for details'

# Generate and send report
report = create_user_report(params)
response = email_result(report)
return response


# Create report (format: JSON) combining data from 2 existing Commander reports
def create_user_report(params): # type: (KeeperParams) -> Optional[str]
user_report_cmd = UserReportCommand()
user_report_data = user_report_cmd.execute(params, format='json')
data = json.loads(user_report_data)
users = {x['email']: x for x in data}
security_audit_report = SecurityAuditReportCommand()
security_audit_report_data = security_audit_report.execute(params, format='json')
if security_audit_report_data:
data = json.loads(security_audit_report_data)
for x in data:
if 'email' in x:
email = x['email']
if email in users:
user = users[email]
for key in x:
if key not in user:
if key not in ('node_path', 'username'):
user[key] = x[key]
else:
users[email] = x

return json.dumps(list(users.values()), indent=2)


# Email report data (as JSON attachment) to recipient specified in this Lambda
# function's environment variables
def email_result(report):
sender = os.environ.get('KEEPER_SENDER')
sendto = os.environ.get('KEEPER_SENDTO')
region = 'us-east-1'
ses_client = boto3.client('ses', region_name=region)

message = MIMEMultipart('mixed')
message['Subject'] = 'Keeper Commander User Security Report With CSV (attached)'
message['To'] = sendto
message['From'] = sender
now = datetime.datetime.now()

body = MIMEText(f'User Report Output created and sent at {now}', 'plain')
message.attach(body)

attachment = MIMEApplication(report)
attachment.add_header(
'Content-Disposition',
'attachment',
filename='user-report.json'
)
message.attach(attachment)

response = ses_client.send_raw_email(
Source=message['From'],
Destinations=[sendto],
RawMessage={'Data': message.as_string()}
)

return response


# Get required Commander parameters from Lambda's environment variables (in "Configuration")
def get_params():
user = os.environ.get('KEEPER_USER')
pw = os.environ.get('KEEPER_PASSWORD')
server = os.environ.get('KEEPER_SERVER')
private_key = os.environ.get('KEEPER_PRIVATE_KEY')
token = os.environ.get('KEEPER_DEVICE_TOKEN')
my_params = KeeperParams()
my_params.user = user
my_params.password = pw
my_params.server = server
my_params.device_private_key = private_key
my_params.device_token = token
return my_params

62 changes: 62 additions & 0 deletions examples/aws_lambda/package_layer_content.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash

# To create a `keepercommander` dependency layer for your AWS Lambda function :
# 1. Upload this script to any folder in your CloudShell environment.
# 2. (Optional) Upload your project's `requirements.txt` file to the same folder.
# 3. In that folder, run
# source ./package_layer_content.sh
# 4. There should now be a file named `commander-layer.zip` that can be uploaded
# to your S3 bucket, where it can then be used to create a new Lambda layer

MAX_LIB_SIZE=262144000
LAYER_FILENAME='commander-layer.zip'
LAYER_PATH=$(pwd)/$LAYER_FILENAME
LIB_DIR='python'
VENV='commander-venv'
OTHER_DEPS='requirements.txt'

# Clean up previous artifacts
test -f $LAYER_FILENAME && rm $LAYER_FILENAME
test -d $LIB_DIR && rm -rf $LIB_DIR
test -d $VENV && rm -rf $VENV

# Create package folder to zip
mkdir $LIB_DIR

# Create and run virtual environment
python -m venv $VENV
source ./$VENV/bin/activate

# Install dependencies and package
pip install cryptography --platform manylinux2014_x86_64 --only-binary=:all: -t $LIB_DIR
pip install keepercommander -t $LIB_DIR

if test -f $OTHER_DEPS; then
pip install -r $OTHER_DEPS -t $LIB_DIR
fi

deactivate

# Check uncompressed library size
LIB_SIZE=$(du -sb $LIB_DIR | cut -f 1)
LIB_SIZE_MB=$(du -sm $LIB_DIR | cut -f 1)

if [ "$LIB_SIZE" -ge $MAX_LIB_SIZE ]; then
echo "*****************************************************************************************************************"
echo 'Operation was aborted'
echo "The resulting layer has too many dependencies and its size ($LIB_SIZE_MB MB) exceeds the maximum allowed (~262 MB)."
echo 'Try breaking up your dependencies into smaller groups and package them as separate layers.'
echo "*****************************************************************************************************************"
else
zip -r $LAYER_FILENAME $LIB_DIR
echo "***************************************************************************"
echo "***************************************************************************"
echo 'Lambda layer file has been created'
printf "To download, copy the following file path: %s\n%s\n$LAYER_PATH%s\n%s\n"
echo 'and click on "Actions" in the upper-right corner of your CloudShell console'
echo "***************************************************************************"
fi

# Clean-up
rm -rf $LIB_DIR
rm -rf $VENV

0 comments on commit b147c8e

Please sign in to comment.