Note:
- This tutorial requires access to Oracle Cloud. To sign up for a free account, see Get started with Oracle Cloud Infrastructure Free Tier.
- It uses example values for Oracle Cloud Infrastructure credentials, tenancy, and compartments. When completing your lab, substitute these values with ones specific to your cloud environment.
Send Oracle Cloud Guard Problems through Email using Oracle Cloud Infrastructure Functions
Introduction
Today, cybersecurity teams across industries face the complex challenge of maintaining a solid security posture while dealing with cloud environments’ dynamic nature. With countless resources, configurations, and evolving threats, tracking and addressing issues promptly is crucial. At Oracle, we recognize the importance of equipping organizations with tools to streamline their security management, helping them tackle these challenges head-on. Oracle Cloud Guard offers robust functionality to help enterprises simplify cloud security management, moving from merely identifying vulnerabilities to automatically distributing issues across teams for timely resolution.
This tutorial outlines an automated solution leveraging OCI’s native services that enables security teams to receive and share detailed Oracle Cloud Guard security reports directly through email. This approach reduces manual intervention, facilitates continuous monitoring, and ensures a proactive stance in cloud security.
Objective
- Receive all Oracle Cloud Guard open problems in an email that can be distributed to appropriate teams, streamlining the path to resolution.
Prerequisites
-
Access to an Oracle Cloud Infrastructure (OCI) tenancy.
-
Privileges to manage Oracle Cloud Guard, OCI Functions, OCI Email Delivery service, OCI Vault, and OCI Resource Scheduler.
Task 1: Set Up the Required Policies and Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) Permissions
Each component of this solution must have access to the OCI resources it interacts with.
-
Resource Scheduler Policy: Permit the scheduler to run the function on a defined schedule. For more information, see Example Policies.
-
Function Policy: Grant the function permission to read secrets from OCI Vault and retrieve Oracle Cloud Guard issues. For more information, see Details for Functions.
Task 2: Configure the OCI Email Delivery Service
-
Set up the OCI Email Delivery service by creating an Approved Sender email address, which will be used to send reports. For more information, see Creating an Approved Sender.
-
Generate Simple Mail Transfer Protocol (SMTP) credentials for the email account by creating a dedicated user with limited SMTP access permissions.
-
Create an OCI IAM user. For more information, see Creating a User.
-
To edit user capabilities, see Editing a User’s Capabilities.
-
To create SMTP credentials, see Creating SMTP Credentials.
-
Task 3: Store SMTP Credentials in OCI Vault
Using OCI Vault, securely store SMTP credentials. This adds an extra layer of security by keeping sensitive information outside the function.
-
Set up an OCI Vault. For more information, see Creating a Vault.
-
To create a Master Encryption Key, see Creating a Master Encryption Key.
-
To create a secret, see Creating a Secret in a Vault.
Task 4: Develop and Deploy the Function
This function fetches unresolved security posture issues detected in the past year. It formats the data into a structured report based on parameters such as risk level and detection time and then sends it as a comma-separated values (CSV) attachment via email. For more information, see Deploying a function.
Here is an overview of the core function steps:
- Retrieve unresolved issues from Oracle Cloud Guard.
- Organize and format the issues based on severity.
- Generate a CSV report and format the report.
- Retrieve the SMTP credentials from the vault.
- Send the email to designated recipients with CSV as an attachment.
Using OCI’s serverless function capabilities, this report can be customized to provide maximum clarity on critical security areas for cybersecurity teams.
-
func.py
:import oci import io import smtplib import logging import base64 from oci.pagination import list_call_get_all_results from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders from email.mime.text import MIMEText from openpyxl import Workbook from datetime import datetime, timedelta, timezone from openpyxl.styles import Font # Retrieve secrets from OCI Vault def get_secret_value(secret_ocid): print(f"Retrieving secret for OCID: {secret_ocid}") signer = oci.auth.signers.get_resource_principals_signer() secrets_client = oci.secrets.SecretsClient({}, signer=signer) try: secret_content = secrets_client.get_secret_bundle(secret_ocid) secret_data = secret_content.data.secret_bundle_content.content secret_value = base64.b64decode(secret_data).decode('utf-8') return secret_value except Exception as e: print(f"Failed to retrieve secret: {e}") raise # Format the CSV def get_font_style(risk_level, time_condition): color_map = { "CRITICAL": "8B0000", "HIGH": "FF8C00", "MEDIUM": "006400", "LOW": "00008B", "MINOR": "000000" } font_color = color_map.get(risk_level, "000000") is_bold = time_condition return Font(color=font_color, bold=is_bold) def get_clients_with_resource_principal(): signer = oci.auth.signers.get_resource_principals_signer() cloud_guard_client = oci.cloud_guard.CloudGuardClient({}, signer=signer) return cloud_guard_client def send_email_via_oci(subject, body, email, attachment, username_secret_ocid, password_secret_ocid, from_email, smtp_endpoint, smtp_port): msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = from_email msg['To'] = email msg.attach(MIMEText(body, 'plain')) today_date = datetime.today().strftime('%Y-%m-%d') filename = f"CloudGuardReport_{today_date}.xlsx" part = MIMEBase('application', "octet-stream") part.set_payload(attachment) encoders.encode_base64(part) part.add_header('Content-Disposition', f"attachment; filename={filename}") msg.attach(part) try: username = get_secret_value(username_secret_ocid) password = get_secret_value(password_secret_ocid) server = smtplib.SMTP(smtp_endpoint, smtp_port) server.starttls() server.login(username, password) server.sendmail(msg['From'], [msg['To']], msg.as_string()) server.quit() print("Email sent successfully.") except Exception as e: print(f"Failed to send email: {e}") raise def handler(ctx, data: io.BytesIO=None): try: cfg = ctx.Config() compartment_id = cfg["compartment-id"] from_email = cfg["from-email"] email = cfg["to-email"] smtp_endpoint = cfg["smtp-endpoint"] smtp_port = cfg["smtp-port"] username_secret_ocid = cfg["smtp-username-secret-ocid"] password_secret_ocid = cfg["smtp-password-secret-ocid"] cg_access_level = cfg["cloudguard-access-level"] cloud_guard_client = get_clients_with_resource_principal() current_time = datetime.now(timezone.utc) time_last_7_days = current_time - timedelta(days=7) formatted_time_one_year_ago = (current_time - timedelta(days=365)).strftime("%Y-%m-%dT%H:%M:%S.%fZ") formatted_time_last_7_days = time_last_7_days.strftime("%Y-%m-%dT%H:%M:%S.%fZ") # List problems problem_response = list_call_get_all_results( cloud_guard_client.list_problems, compartment_id, compartment_id_in_subtree=True, access_level=cg_access_level, time_first_detected_greater_than_or_equal_to=formatted_time_one_year_ago, time_last_detected_greater_than_or_equal_to=formatted_time_last_7_days ).data if not problem_response: logging.info("No open problems found.") return {"statusCode": 200, "body": "No open problems found."} print(f"Found {len(problem_response)} problems") # Sort problems by Risk Level risk_level_order = {"CRITICAL": 1, "HIGH": 2, "MEDIUM": 3, "LOW": 4, "MINOR": 5} problem_response.sort(key=lambda x: risk_level_order.get(x.risk_level, 6)) # Create a workbook and select active worksheet wb = Workbook() ws = wb.active ws.title = "Cloud Guard Problems" ws.append([ "Region", "ID", "Resource Type", "Resource Name", "Risk Level", "Detector", "Rule Display Name", "Rule Description", "Rule Recommendation", "Resource ID", "Time First Detected", "Time Last Detected" ]) # Iterate through the problems for problem in problem_response: try: detector_rule_response = cloud_guard_client.get_detector_rule(problem.detector_id, problem.detector_rule_id).data rule_description = detector_rule_response.description detector = detector_rule_response.detector rule_display_name = detector_rule_response.display_name rule_recommendation = detector_rule_response.recommendation except Exception as e: logging.error(f"Error fetching detector rule details for problem {problem.id}: {str(e)}") rule_description, detector, rule_display_name, rule_recommendation = "N/A", "N/A", "N/A", "N/A" problem_details = [ problem.region, problem.id, problem.resource_type, problem.resource_name, problem.risk_level, detector, rule_display_name, rule_description, rule_recommendation, problem.resource_id, problem.time_first_detected.replace(tzinfo=None) if problem.time_first_detected else None, problem.time_last_detected.replace(tzinfo=None) if problem.time_last_detected else None ] # Add row to worksheet ws.append(problem_details) # Apply format time_condition = problem.time_last_detected > problem.time_first_detected if problem.time_last_detected and problem.time_first_detected else False font_style = get_font_style(problem.risk_level, time_condition) row_number = ws.max_row for cell in ws[row_number]: cell.font = font_style virtual_workbook = io.BytesIO() wb.save(virtual_workbook) virtual_workbook.seek(0) # Send email send_email_via_oci("OCI Cloud Guard Report", "Find attached the OCI Cloud Guard Report.", email, virtual_workbook.getvalue(), username_secret_ocid, password_secret_ocid, from_email, smtp_endpoint, smtp_port) return {"statusCode": 200, "body": "Email sent successfully."} except Exception as e: logging.error(f"Error: {str(e)}") return {"statusCode": 500, "body": f"Error: {str(e)}"}
-
func.yaml
:schema_version: 20180708 name: oci-cloud-guard-problems version: 0.0.1 runtime: python build_image: fnproject/python:3.9-dev run_image: fnproject/python:3.9 entrypoint: /python/bin/fdk /function/func.py handler memory: 256 config: compartment-id: Provide a compartment ID here to-email: Provide a valid email ID here from-email: Provide the Approved Sender Email ID created in the Email Delivery Service smtp-username-secret-ocid: Provide the SMTP Username Secret OCID smtp-password-secret-ocid: Provide the SMTP Password Secret OCID smtp-endpoint: Provide the SMTP endpoint from the Email Delivery Service smtp-port: 587 cloudguard-access-level: ACCESSIBLE or RESTRICTED
-
requirements.txt
:fdk oci openpyxl
Task 5: Schedule the Function with OCI Resource Scheduler
The final task is to use OCI Resource Scheduler to automate the execution of the function. This configuration can run weekly or at a customized interval, ensuring timely and consistent security reporting. For more information, see Creating Schedules.
-
To run the function, enter the following required information.
Before deploying the function, gather the following configuration details. These inputs will be provided in the function configuration file (
func.yaml
) or directly in the OCI Console, depending on your deployment method.- Compartment ID: This is your tenancy ID where Oracle Cloud Guard is enabled.
- From Email: The approved sender email you created in the OCI Email Delivery Service.
- To Email: The email address where the report will be sent.
- SMTP Endpoint: To find it, go to Email Delivery and Configuration.
- SMTP Port: Typically 587 or 25, as specified in OCI Email Delivery service configuration.
- SMTP Username Secret OCID: The OCID for SMTP username, securely stored in OCI Vault.
- SMTP Password Secret OCID: The OCID for SMTP password, securely stored in OCI Vault.
- Cloud Guard Access Level: Defines access level for resources (
ACCESSIBLE
orRESTRICTED
). Defaults toACCESSIBLE
.
-
We will get a sample output which is an actionable Oracle Cloud Guard report.
This Oracle Cloud Guard report provides a structured overview of unresolved security issues in your OCI environment, categorized by risk level. Critical details like region, resource type, severity, and detection timestamps enable cybersecurity teams to assess and prioritize actions.
Next Steps
Oracle Cloud Guard’s automated reporting offers cybersecurity teams a streamlined, proactive approach to managing cloud security risks. Organizations can receive weekly reports on unresolved security issues with a one-time configuration, categorized by severity and risk level. This solution addresses the complex manual task of cloud security management, empowering teams to focus on timely issue resolution rather than tracking down issues. For more information on using Oracle Cloud Guard and its CNAPP capabilities, contact your Oracle representative or see Cloud Security Services.
Acknowledgments
- Author - Aneel Kanuri (Distinguished Cloud Architect)
More Learning Resources
Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.
For product documentation, visit Oracle Help Center.
Send Oracle Cloud Guard Problems through Email using Oracle Cloud Infrastructure Functions
G23045-01
December 2024