Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Resource Formatting, deployment scripts and variables management. #10

Merged
merged 4 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cloudformation/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Enable AWS Config with required resources'

Parameters:
ConfigLogsS3BucketName:
Type: String
Description: Name of the S3 bucket to store Config logs

Resources:
# IAM Role for AWS Config
ConfigRole:
Expand All @@ -21,7 +26,7 @@ Resources:
ConfigBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'aws-config-logs-${AWS::AccountId}-${AWS::Region}'
BucketName: !Ref ConfigLogsS3BucketName
VersioningConfiguration:
Status: Enabled
BucketEncryption:
Expand Down
7 changes: 6 additions & 1 deletion cloudformation/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ Parameters:
MonitoringIntervalMinutes:
Type: Number
Description: Interval in minutes between monitoring runs

ConfigLogsS3BucketName:
Type: String
Description: Name of the S3 bucket to store Config logs

Resources:
# Nested Stack for AWS Config
AwsConfigStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub "https://s3.amazonaws.com/${LambdaCodeS3BucketName}/templates/config.yaml"
Parameters:
ConfigLogsS3BucketName: !Ref ConfigLogsS3BucketName

# Nested Stack for Lambda and API Gateway
LambdaApiStack:
Expand Down
20 changes: 3 additions & 17 deletions scripts/deploy.sh → deployment/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,8 @@ set -e # Exit immediately if a command exits with a non-zero status.
# Get the directory of the current script
PROJECT_ROOT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# Get the current timestamp
timestamp=$(date +%Y%m%d%H%M%S)

# Define variables
SERVICE_NAME="aws-service-monitor"
LAMBDA_CODE_S3_BUCKET_NAME="$SERVICE_NAME-bucket" # Replace with your actual S3 bucket name
LAMBDA_ASSETS_S3_BUCKET_NAME="$SERVICE_NAME-assets"
MONITORING_INTERVAL_MINUTES=60
SNS_TOPIC_NAME="$SERVICE_NAME-topic"
STACK_NAME="$SERVICE_NAME-stack"
TEMPLATE_FOLDER="$PROJECT_ROOT_PATH/cloudformation"
MAIN_TEMPLATE_FILE="$TEMPLATE_FOLDER/main.yaml"
LAMBDA_FUNCTION_NAME="$SERVICE_NAME"
LAMBDA_KEY="lambda/$SERVICE_NAME.zip"
AWS_REGION="eu-west-1"
EMAIL_ADDRESS="[email protected]"
ASSETS_DIR="$PROJECT_ROOT_PATH/assets"
# Source the variables from the external file
source "$(dirname "$0")/variables.env"

# Print the current script directory for debugging
echo "Script directory: $PROJECT_ROOT_PATH"
Expand Down Expand Up @@ -89,6 +74,7 @@ aws cloudformation deploy \
EmailAddress="$EMAIL_ADDRESS" \
MonitoringIntervalMinutes="$MONITORING_INTERVAL_MINUTES" \
SnsTopicName="$SNS_TOPIC_NAME" \
ConfigLogsS3BucketName="$CONFIG_LOGS_BUCKET_NAME" \
--region "$AWS_REGION"

echo "Deployment complete!"
49 changes: 49 additions & 0 deletions deployment/destroy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash

set -e # Exit immediately if a command exits with a non-zero status.

# Source the variables from the external file
source "$(dirname "$0")/variables.env"

# Check and remove S3 buckets
for bucket in $LAMBDA_CODE_S3_BUCKET_NAME $LAMBDA_ASSETS_S3_BUCKET_NAME $CONFIG_LOGS_BUCKET_NAME; do
if aws s3 ls "s3://$bucket" --region "$AWS_REGION" &>/dev/null; then
echo "Removing all files and versions from S3 bucket $bucket..."

# Check if the bucket is versioned
if aws s3api get-bucket-versioning --bucket "$bucket" --region "$AWS_REGION" | grep -q '"Status": "Enabled"'; then
echo "Bucket $bucket is versioned. Deleting all object versions..."

# Delete all versions of all objects
aws s3api list-object-versions --bucket "$bucket" --region "$AWS_REGION" --query 'Versions[].{Key:Key,VersionId:VersionId}' --output text | \
while read -r key version; do
aws s3api delete-object --bucket "$bucket" --key "$key" --version-id "$version" --region "$AWS_REGION"
done

# Delete all delete markers
aws s3api list-object-versions --bucket "$bucket" --region "$AWS_REGION" --query 'DeleteMarkers[].{Key:Key,VersionId:VersionId}' --output text | \
while read -r key version; do
aws s3api delete-object --bucket "$bucket" --key "$key" --version-id "$version" --region "$AWS_REGION"
done
else
# If the bucket is not versioned, just remove all files
aws s3 rm "s3://$bucket" --recursive --region "$AWS_REGION"
fi

echo "Deleting S3 bucket $bucket..."
aws s3 rb "s3://$bucket" --force --region "$AWS_REGION"
else
echo "Bucket $bucket does not exist, skipping..."
fi
done

# Delete the CloudFormation stack
echo "Deleting CloudFormation stack $STACK_NAME..."
aws cloudformation delete-stack --stack-name "$STACK_NAME" --region "$AWS_REGION"

# Wait for the stack to be deleted
echo "Waiting for stack deletion to complete..."
aws cloudformation wait stack-delete-complete --stack-name "$STACK_NAME" --region "$AWS_REGION"

echo "Stack deletion complete!"
echo "Cleanup complete!"
10 changes: 10 additions & 0 deletions deployment/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

set -e # Exit immediately if a command exits with a non-zero status.

# Source the variables from the external file
source "$(dirname "$0")/variables.env"

API_ENDPOINT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME --query "Stacks[0].Outputs[?OutputKey=='ApiEndpoint'].OutputValue" --output text)

curl -X POST $API_ENDPOINT
33 changes: 33 additions & 0 deletions deployment/variables.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Service Name
SERVICE_NAME="monitor-active-services"

# S3 Buckets
CONFIG_LOGS_BUCKET_NAME="${CONFIG_LOGS_BUCKET_NAME:-${SERVICE_NAME}-config-logs}"
LAMBDA_CODE_S3_BUCKET_NAME="${LAMBDA_CODE_S3_BUCKET_NAME:-${SERVICE_NAME}-lambda-code}"
LAMBDA_ASSETS_S3_BUCKET_NAME="${LAMBDA_ASSETS_S3_BUCKET_NAME:-${SERVICE_NAME}-lambda-assets}"

# Monitoring Settings
MONITORING_INTERVAL_MINUTES="${MONITORING_INTERVAL_MINUTES:-60}"

# SNS Topic
SNS_TOPIC_NAME="${SNS_TOPIC_NAME:-${SERVICE_NAME}-topic}"

# CloudFormation Stack
STACK_NAME="${STACK_NAME:-${SERVICE_NAME}-stack}"

# AWS Region
AWS_REGION="${AWS_REGION:-eu-west-1}"

# Email Address
EMAIL_ADDRESS="${EMAIL_ADDRESS:[email protected]}"

# Directory Paths
ASSETS_DIR="${ASSETS_DIR:-${PROJECT_ROOT_PATH}/assets}"
TEMPLATE_FOLDER="${TEMPLATE_FOLDER:-${PROJECT_ROOT_PATH}/cloudformation}"

# Lambda Function
LAMBDA_FUNCTION_NAME="${LAMBDA_FUNCTION_NAME:-${SERVICE_NAME}}"
LAMBDA_KEY="${LAMBDA_KEY:-lambda/${SERVICE_NAME}.zip}"

# Main CloudFormation Template
MAIN_TEMPLATE_FILE="${MAIN_TEMPLATE_FILE:-${TEMPLATE_FOLDER}/main.yaml}"
15 changes: 12 additions & 3 deletions lambda/service_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import boto3
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
try:
active_services = check_active_services()
Expand Down Expand Up @@ -49,6 +51,7 @@ def check_active_services():
logger.error(f"Error discovering resources for {resource_type}: {str(e)}")

return active_services

def list_discovered_resources(config_client, resource_type):
paginator = config_client.get_paginator('list_discovered_resources')
response_iterator = paginator.paginate(
Expand All @@ -61,23 +64,29 @@ def list_discovered_resources(config_client, resource_type):
for resource in page['resourceIdentifiers']:
resources.append({
'resourceId': resource['resourceId'],
'resourceName': resource.get('resourceName', 'N/A')
'resourceName': resource['resourceName']
})

return resources

def send_notification(active_services):
sns = boto3.client('sns')
topic_arn = os.environ['SNSTopicArn']

excluded_resource_types = ['AWS::IAM::Role','AWS::IAM::User']

message = "Active AWS Services Count and Details:\n\n"
for resource_type, resources in active_services.items():
if resource_type not in excluded_resource_types:
resource_count = len(resources)
message += f"{resource_type} (count={resource_count}):\n"
for resource in resources:
message += f"Name: {resource['resourceName']}\n"
message += "\n"
# Add bullet points and indentation for better readability
resource_name = resource['resourceName'] if resource['resourceName'] else 'N/A'
resource_id = resource['resourceId']
message += f" • {resource_name} (ID: {resource_id})\n"
message += "\n" # Add a blank line between resource types

# Check if the message has only the header, implying no active services were included
if message == "Active AWS Services Count and Details:\n\n":
logger.warning("No active services to report")
Expand Down
Loading