附註:
- 此教學課程需要存取 Oracle Cloud。若要註冊免費帳戶,請參閱 Oracle Cloud Infrastructure Free Tier 入門。
- 它使用 Oracle Cloud Infrastructure 證明資料、租用戶及區間的範例值。完成實驗室時,請將這些值取代為您雲端環境特定的值。
使用 Oracle Cloud Infrastructure Functions 透過電子郵件傳送 Oracle Cloud Guard 問題
簡介
如今,各行各業的網路安全團隊面臨著維持穩固安全態勢的複雜挑戰,同時處理雲端環境的動態性質。由於無數資源、組態和不斷演變的威脅,因此即時追蹤和解決問題至關重要。在 Oracle,我們深知為組織提供工具來簡化安全性管理的重要性,協助組織應對上述挑戰。Oracle Cloud Guard 提供強大的功能,可協助企業簡化雲端安全性管理,從僅識別漏洞即可自動將問題分散到各個團隊,以適時解決問題。
本教學課程概述運用 OCI 原生服務的自動化解決方案,讓安全團隊能夠直接透過電子郵件接收及共用詳細的 Oracle Cloud Guard 安全報表。此方法可減少手動介入、促進持續監控,並確保雲端安全性的主動立場。
目標
- 您會收到電子郵件中所有 Oracle Cloud Guard 的未結問題,這些問題可分配給適當的團隊,藉此簡化解決問題的途徑。
必要條件
-
存取 Oracle Cloud Infrastructure (OCI) 租用戶。
-
管理 Oracle Cloud Guard、OCI Functions、OCI Email Delivery 服務、OCI Vault 以及 OCI Resource Scheduler 的權限。
作業 1:設定必要的原則和 Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 權限
此解決方案的每個元件都必須能夠存取與其互動的 OCI 資源。
-
資源排程器原則:允許排程器在定義的排程上執行函數。如需詳細資訊,請參閱範例原則。
-
函數原則: 授予從 OCI 保存庫讀取加密密碼及擷取 Oracle Cloud Guard 問題的功能權限。如需詳細資訊,請參閱函數詳細資訊。
作業 2:設定 OCI 電子郵件傳遞服務
-
建立將用於傳送報表的核准寄件者電子郵件地址,以設定 OCI 電子郵件傳遞服務。如需詳細資訊,請參閱建立核准的寄件者。
-
建立具有有限 SMTP 存取權限的專用使用者,以產生電子郵件帳戶的簡單郵件傳輸協定 (SMTP) 證明資料。
-
建立 OCI IAM 使用者。如需詳細資訊,請參閱建立使用者。
-
若要編輯使用者功能,請參閱編輯使用者的功能。
-
若要建立 SMTP 證明資料,請參閱 Creating SMTP Credentials 。
-
作業 3:在 OCI 保存庫中儲存 SMTP 證明資料
使用 OCI Vault,安全地儲存 SMTP 憑證。這樣可以透過將機密資訊保留在函數之外來增加額外的一層安全。
-
設定 OCI 保存庫。如需詳細資訊,請參閱建立保存庫。
-
若要建立主要加密金鑰,請參閱 Creating a Master Encryption Key 。
-
若要建立加密密碼,請參閱在保存庫中建立加密密碼。
作業 4:開發並部署函數
此功能會擷取過去一年偵測到的未解決安全性狀態問題。它會根據風險等級和偵測時間等參數,將資料格式化成結構化報表,然後透過電子郵件將其作為逗號分隔值 (CSV) 附件傳送。如需詳細資訊,請參閱部署函數。
以下是核心功能步驟的概要:
- 從 Oracle Cloud Guard 擷取未解決的問題。
- 依據嚴重性來組織與格式化問題。
- 產生 CSV 報表並格式化報表。
- 從 Vault 擷取 SMTP 憑證。
- 以 CSV 作為附件,傳送電子郵件給指定的收件者。
使用 OCI 的無伺服器功能,您可以自訂此報表,為網路安全團隊提供重要安全區域的最大清晰度。
-
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
作業 5:使用 OCI Resource Scheduler 排定函數
最終的任務是使用 OCI Resource Scheduler 來自動執行函數。此組態可以每週或自訂間隔執行,以確保及時且一致的安全報告。如需詳細資訊,請參閱建立排程。
-
若要執行功能,請輸入下列必要資訊。
部署函數之前,請先收集下列組態詳細資訊。視您的部署方法而定,函數組態檔 (
func.yaml
) 或直接在 OCI 主控台中提供這些輸入。- 區間 ID: 這是啟用 Oracle Cloud Guard 的租用戶 ID。
- 寄件者電子郵件:您在 OCI 電子郵件傳遞服務中建立的核准寄件者電子郵件。
- 傳送電子郵件:將傳送報表的電子郵件地址。
- SMTP 端點:若要尋找端點,請移至電子郵件傳遞和組態。
- SMTP 連接埠:通常為 587 或 25 (如 OCI Email Delivery 服務組態中所指定)。
- SMTP 使用者名稱加密密碼 OCID: SMTP 使用者名稱的 OCID,安全地儲存在 OCI 保存庫中。
- SMTP 密碼加密密碼 OCID: SMTP 密碼的 OCID,安全地儲存在 OCI 保存庫中。
- 雲端保全存取層次:定義資源的存取層次 (
ACCESSIBLE
或RESTRICTED
)。預設為ACCESSIBLE
。
-
我們將提供範例輸出,這是可行的 Oracle Cloud Guard 報表。
此 Oracle Cloud Guard 報表提供 OCI 環境中未解決之安全問題的結構化總覽,並依風險等級分類。重要詳細資訊 (例如區域、資源類型、嚴重性和偵測時戳) 可讓網路安全團隊評估及排定動作優先順序。
接下來的步驟
Oracle Cloud Guard 的自動化報告為網路安全團隊提供了精簡、主動的方式來管理雲端安全風險。組織可以每週接收一次性組態 (依嚴重度和風險等級分類) 的未解決安全問題報告。此解決方案解決了雲端安全管理的複雜手動工作,使團隊能夠專注於及時解決問題,而不是追蹤問題。如需有關使用 Oracle Cloud Guard 及其 CNAPP 功能的詳細資訊,請聯絡您的 Oracle 代表或參閱雲端安全服務。
認可
- 作者 - Aneel Kanuri (Distinguished Cloud Architect)
其他學習資源
探索 docs.oracle.com/learn 上的其他實驗室,或存取 Oracle Learning YouTube 頻道上的更多免費學習內容。此外,請造訪 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。
如需產品文件,請造訪 Oracle Help Center 。
Send Oracle Cloud Guard Problems through Email using Oracle Cloud Infrastructure Functions
G23229-01
December 2024