Microsoft Azure 리소스 로그 수집
이 문서에서는 Microsoft Azure Blob Storage V2를 사용하여 Google Security Operations 피드를 설정하여 Microsoft Azure 리소스 로그를 수집하는 방법을 설명합니다.
Azure 리소스 로그는 Azure 리소스 내에서 수행된 작업에 관한 정보를 제공합니다. 이러한 로그는 리소스 작업, 상태, 성능 측정항목에 관한 세부정보를 캡처합니다. 콘텐츠는 리소스 유형에 따라 다르며 인증 이벤트, 구성 변경사항, 액세스 시도, 운영 측정항목과 같은 데이터가 포함됩니다.
시작하기 전에
다음 기본 요건이 충족되었는지 확인합니다.
- Google SecOps 인스턴스
다음 권한이 있는 Microsoft Azure 포털에 대한 액세스 권한:
- 스토리지 계정 만들기
- Azure 리소스의 진단 설정 구성
- 액세스 키 관리
Azure 스토리지 계정 구성
스토리지 계정 만들기
- Azure 포털에서 스토리지 계정을 검색합니다.
- + 만들기를 클릭합니다.
다음 구성 세부정보를 제공합니다.
설정 값 구독 Azure 구독 선택 리소스 그룹 기존 항목 선택 또는 새로 만들기 스토리지 계정 이름 고유한 이름 (예: azureresourcelogs)을 입력합니다.리전 리전을 선택합니다 (예: East US).성능 표준 (권장) 중복성 GRS (지리적 중복 스토리지) 또는 LRS (로컬 중복 스토리지) 검토 + 만들기를 클릭합니다.
계정 개요를 검토하고 만들기를 클릭합니다.
배포가 완료될 때까지 기다립니다.
스토리지 계정 사용자 인증 정보 가져오기
- 방금 만든 스토리지 계정으로 이동합니다.
- 왼쪽 탐색 메뉴의 보안 및 네트워킹에서 액세스 키를 선택합니다.
- 키 표시를 클릭합니다.
나중에 사용할 수 있도록 다음을 복사하여 저장합니다.
- 스토리지 계정 이름:
azureresourcelogs - 키 1 또는 키 2: 공유 액세스 키 (base-64 인코딩의 512비트 임의 문자열)
- 스토리지 계정 이름:
Blob 서비스 엔드포인트 가져오기
- 동일한 스토리지 계정의 왼쪽 탐색에서 엔드포인트를 선택합니다.
- Blob 서비스 엔드포인트 URL을 복사하여 저장합니다.
- 예:
https://azureresourcelogs.blob.core.windows.net/
- 예:
Azure 리소스 진단 설정 구성
Azure 리소스 로그는 기본적으로 수집되지 않습니다. 스토리지 계정으로 로그를 라우팅하려면 각 Azure 리소스에 대해 진단 설정을 만들어야 합니다.
- Azure 포털에서 모니터링할 Azure 리소스로 이동합니다.
- 왼쪽 탐색에서 모니터링 아래의 진단 설정을 선택합니다.
- + 진단 설정 추가를 클릭합니다.
- 다음 구성 세부정보를 제공합니다.
- 진단 설정 이름: 설명이 포함된 이름 (예:
export-to-secops)을 입력합니다. - 로그 섹션에서 수집할 로그 카테고리를 선택합니다. 사용 가능한 카테고리는 리소스 유형에 따라 다릅니다. 일반적인 카테고리는 다음과 같습니다.
- 관리 (활동 로그)
- 보안 (활동 로그용)
- AuditEvent (Key Vault용)
- ApplicationGatewayAccessLog (Application Gateway용)
- ApplicationGatewayFirewallLog (Application Gateway용)
- NetworkSecurityGroupEvent (네트워크 보안 그룹용)
- 측정항목 섹션 (선택사항)에서 AllMetrics를 선택하여 플랫폼 측정항목을 스토리지 계정으로 전송합니다.
- 대상 세부정보 섹션에서 스토리지 계정에 아카이브 체크박스를 선택합니다.
- 구독: 스토리지 계정이 포함된 구독을 선택합니다.
- 스토리지 계정: 만든 스토리지 계정을 선택합니다 (예:
azureresourcelogs).
- 진단 설정 이름: 설명이 포함된 이름 (예:
- 저장을 클릭합니다.
구성 후 로그가 스토리지 계정의 컨테이너로 자동 내보내집니다. Azure는 insights-logs-<log-category-name> 명명 패턴을 사용하여 컨테이너를 만듭니다. 예를 들면 다음과 같습니다.
- Key Vault 감사 로그:
insights-logs-auditevent - Application Gateway 액세스 로그:
insights-logs-applicationgatewayaccesslog - Application Gateway 방화벽 로그:
insights-logs-applicationgatewayfirewalllog 네트워크 보안 그룹 이벤트:
insights-logs-networksecuritygroupevent
Azure 리소스 로그를 수집하도록 Google SecOps에서 피드 구성
- SIEM 설정> 피드로 이동합니다.
- 새 피드 추가를 클릭합니다.
- 다음 페이지에서 단일 피드 구성을 클릭합니다.
- 피드 이름 필드에 피드 이름을 입력합니다(예:
Azure Resource Logs - Key Vault). - 소스 유형으로 Microsoft Azure Blob Storage V2를 선택합니다.
- 로그 유형으로 Microsoft Azure 리소스를 선택합니다.
- 다음을 클릭합니다.
다음 입력 매개변수의 값을 지정합니다.
- Azure URI: 컨테이너 경로와 함께 Blob 서비스 엔드포인트 URL을 입력합니다.
https://azureresourcelogs.blob.core.windows.net/insights-logs-auditevent/- 다음을 바꿉니다.
azureresourcelogs: Azure 스토리지 계정 이름입니다.insights-logs-auditevent: 로그가 저장된 blob 컨테이너 이름입니다 (리소스 유형 및 로그 카테고리에 따라 다름).
소스 삭제 옵션: 환경설정에 따라 삭제 옵션을 선택합니다.
- 삭제 안함: 전송 후 파일을 삭제하지 않습니다.
- 전송된 파일 삭제: 전송이 완료되면 파일을 삭제합니다.
- 전송된 파일 및 빈 디렉터리 삭제: 전송이 완료되면 파일과 빈 디렉터리를 삭제합니다.
최대 파일 기간: 지난 일수 동안 수정된 파일을 포함합니다. 기본값은 180일입니다.
공유 키: 3단계에서 스토리지 계정에서 캡처한 공유 키 값 (액세스 키)을 입력합니다.
애셋 네임스페이스: 애셋 네임스페이스입니다.
수집 라벨: 이 피드의 이벤트에 적용할 라벨입니다.
다음을 클릭합니다.
확정 화면에서 새 피드 구성을 검토한 다음 제출을 클릭합니다.
Azure Storage 방화벽 구성 (사용 설정된 경우)
Azure 스토리지 계정에서 방화벽을 사용하는 경우 Google SecOps IP 범위를 추가해야 합니다.
- Azure 포털에서 스토리지 계정 (예:
azureresourcelogs)으로 이동합니다. - 보안 + 네트워킹에서 네트워킹을 선택합니다.
- 방화벽 및 가상 네트워크에서 선택한 가상 네트워크 및 IP 주소에서 사용 설정됨을 선택합니다.
- 방화벽 섹션의 주소 범위에서 + IP 범위 추가를 클릭합니다.
각 Google SecOps IP 범위를 CIDR 표기법으로 추가합니다.
- 현재 IP 범위를 가져오려면 다음 옵션 중 하나를 선택합니다.
- IP 허용 목록 문서 참고
- 피드 관리 API를 사용하여 프로그래매틱 방식으로 검색
- 현재 IP 범위를 가져오려면 다음 옵션 중 하나를 선택합니다.
저장을 클릭합니다.
UDM 매핑 테이블
| 로그 필드 | UDM 매핑 | 논리 |
|---|---|---|
| 다양한 추가필드*_label 필드 | additional.fields | 다양한 추가필드*_label 필드에서 병합됨 |
| authenticationMethod | extensions.auth.mechanism | authenticationMethod가 Password인 경우 USERNAME_PASSWORD로 설정됩니다. |
| category, event_type | extensions.auth.type | SQLSecurityAuditEvents의 경우 MACHINE으로 설정, 특정 카테고리의 경우 SSO, 기타의 경우 AUTHTYPE_UNSPECIFIED |
| properties.partialipaddress | intermediary.ip | 비어 있지 않은 경우 properties.partialipaddress의 값 |
| properties.event_time, stage_time, risk_time, last_update_time, time | metadata.collected_timestamp | ISO8601을 사용하여 properties.event_time, stage_time, risk_time, last_update_time 또는 대체 grok의 시간에서 변환됨 |
| properties.message, properties.activity, properties.log.stage | metadata.description | 비어 있지 않은 경우 properties.message의 값, 그렇지 않은 경우 properties.activity의 값, 그렇지 않은 경우 properties.log.stage의 값 |
| event_type | metadata.event_type | 비어 있지 않은 경우 event_type의 값, 그렇지 않은 경우 GENERIC_EVENT |
| category, record.category | metadata.product_event_type | 카테고리 또는 record.category에서 직접 복사된 값 |
| properties.event_id, properties.log.auditID | metadata.product_log_id | 비어 있지 않은 경우 properties.event_id의 값, 비어 있는 경우 properties.log.auditID의 값 |
| properties.log.apiVersion | metadata.product_version | properties.log.apiVersion에서 직접 복사한 값 |
| 프로토콜 | network.application_protocol | 프로토콜에서 직접 복사된 값 |
| properties.log.verb | network.dhcp.opcode | properties.log.verb에서 직접 복사한 값 (대문자) |
| properties.CsMethod, record.properties.CsMethod | network.http.method | properties.CsMethod 또는 record.properties.CsMethod에서 직접 복사된 값 |
| user_agent | network.http.parsed_user_agent | user_agent에서 변환됨 |
| properties.Referer, uri | network.http.referral_url | 비어 있지 않으면 properties.Referer의 값, 비어 있으면 uri의 값 |
| properties.ScStatus, record.properties.ScStatus, properties.statusCode, record.properties.statusCode, responseStatus.code | network.http.response_code | properties.ScStatus, record.properties.ScStatus, properties.statusCode, record.properties.statusCode 또는 responseStatus.code에서 정수로 변환됨 |
| user_agent | network.http.user_agent | user_agent에서 직접 복사한 값 |
| properties.ScBytes, record.properties.ScBytes, properties.responseLength | network.received_bytes | properties.ScBytes, record.properties.ScBytes 또는 properties.responseLength에서 uinteger로 변환됨 |
| properties.CsBytes, record.properties.CsBytes, properties.requestLength | network.sent_bytes | properties.CsBytes, record.properties.CsBytes 또는 properties.requestLength에서 uinteger로 변환됨 |
| properties.session_id | network.session_id | properties.session_id에서 직접 복사한 값 (문자열로 변환됨) |
| properties.tlsVersion | network.tls.version | properties.tlsVersion에서 직접 복사된 값 |
| domain_name_value | principal.administrative_domain | domain_name_value에서 직접 복사된 값 |
| properties.clientAppUsed, target_application | principal.application | 비어 있지 않으면 properties.clientAppUsed의 값, 비어 있으면 target_application의 값 |
| prop_device_id | principal.asset.asset_id | null이 아닌 경우 '기기 ID:' 다음에 prop_device_id를 설정합니다. |
| 하드웨어 | principal.asset.hardware | 하드웨어에서 병합됨 |
| properties.host_name, properties.CIp, record.properties.CIp, properties.ComputerName, record.properties.ComputerName, properties.CsHost, record.properties.CsHost, properties.server_instance_name, record.properties.server_instance_name, server_name | principal.asset.hostname | 비어 있지 않은 경우 properties.host_name의 값, 그렇지 않은 경우 properties.CIp (grok IP), record.properties.CIp (grok IP), properties.ComputerName, record.properties.ComputerName, properties.CsHost, record.properties.CsHost, properties.server_instance_name, record.properties.server_instance_name 또는 server_name의 값 |
| src_ip, src_ip1, properties.client_ip, record.properties.clientIpAddress, properties.clientIpAddress, callerIpAddress, properties.ipAddress, ip | principal.asset.ip | src_ip, src_ip1, properties.client_ip (grok IP), record.properties.clientIpAddress, properties.clientIpAddress (grok IP), record.properties.clientIpAddress, callerIpAddress (grok IP), properties.ipAddress 또는 ip의 값 |
| properties.host_name, properties.CsHost, record.properties.CsHost | principal.hostname | 비어 있지 않은 경우 properties.host_name의 값, 그렇지 않은 경우 properties.CsHost 또는 record.properties.CsHost의 값 |
| src_ip, src_ip1, properties.client_ip, record.properties.clientIpAddress, properties.clientIpAddress, callerIpAddress, properties.ipAddress, ip | principal.ip | src_ip, src_ip1, properties.client_ip (grok IP), record.properties.clientIpAddress, properties.clientIpAddress (grok IP), record.properties.clientIpAddress, callerIpAddress (grok IP), properties.ipAddress 또는 ip의 값 |
| properties.location.city, provisioning_steps_city | principal.location.city | 비어 있지 않은 경우 properties.location.city의 값, 그렇지 않은 경우 provisioning_steps_city의 값 |
| properties.location.countryOrRegion, provisioning_steps_country, location, Region | principal.location.country_or_region | properties.location.countryOrRegion의 값(비어 있지 않은 경우), 그렇지 않으면 provisioning_steps_country의 값, 그렇지 않으면 location의 값, 그렇지 않으면 Region의 값 |
| properties.location.geoCoordinates.latitude | principal.location.region_latitude | properties.location.geoCoordinates.latitude에서 직접 복사된 값 |
| properties.location.geoCoordinates.longitude | principal.location.region_longitude | properties.location.geoCoordinates.longitude에서 직접 복사한 값 |
| properties.location.state | principal.location.state | properties.location.state에서 직접 복사한 값 |
| prop_os | principal.platform | prop_os가 (?i)Win과 일치하면 WINDOWS로 설정하고, (?i)Lin과 일치하면 LINUX로 설정하고, (?i)Mac과 일치하면 MAC으로 설정합니다. |
| properties.deviceDetail.operatingSystem | principal.platform_version | properties.deviceDetail.operatingSystem에서 직접 복사한 값 |
| src_port | principal.port | src_port에서 정수로 변환됨 |
| is_compliant_label, is_managed_label, serice_type_label, serice_credential_label | principal.resource.attribute.labels | is_compliant_label, is_managed_label, serice_type_label, serice_credential_label에서 병합됨 |
| properties.sourceSystem.Name | principal.resource.name | properties.sourceSystem.Name에서 직접 복사된 값 |
| properties.sourceSystem.Id | principal.resource.product_object_id | properties.sourceSystem.Id에서 직접 복사된 값 |
| properties.server_principal_name, source_user_principal_name, user_principal_name, local_account_username_value | principal.user.email_addresses | properties.server_principal_name (이메일과 일치하는 경우), source_user_principal_name (이메일과 일치하는 경우), user_principal_name (이메일과 일치하는 경우) 또는 local_account_username_value (이메일과 일치하는 경우)에서 병합됨 |
| properties.sequence_group_id, grpname, properties.log.user.groups | principal.user.group_identifiers | properties.sequence_group_id, grpname 또는 properties.log.user.groups에서 병합됨 |
| properties.sourceIdentity.details.id, properties.userId, details_id_not_present | principal.user.product_object_id | 비어 있지 않은 경우 properties.sourceIdentity.details.id의 값, 그렇지 않은 경우 properties.userId의 값, 그렇지 않은 경우 details_id_not_present의 값 |
| properties.ServicePrincipalDisplayName, properties.servicePrincipalName, properties.sourceIdentity.details.DisplayName, properties.userDisplayName, record.properties.log.user.username | principal.user.user_display_name | 비어 있지 않은 경우 properties.ServicePrincipalDisplayName의 값, 그렇지 않은 경우 properties.servicePrincipalName의 값, 그렇지 않은 경우 properties.sourceIdentity.details.DisplayName의 값, 그렇지 않은 경우 properties.userDisplayName의 값, 그렇지 않은 경우 record.properties.log.user.username의 값 |
| properties.servicePrincipalId, user_userPrincipalName, source_user_principal_name, details_user_principal_name, user_principal_name, properties.accountName, record.properties.log.user.uid | principal.user.userid | 비어 있지 않은 경우 properties.servicePrincipalId의 값, 비어 있는 경우 user_userPrincipalName의 값, 비어 있는 경우 source_user_principal_name의 값, 비어 있는 경우 details_user_principal_name의 값, 비어 있는 경우 user_principal_name의 값, 비어 있는 경우 properties.accountName의 값, 비어 있는 경우 record.properties.log.user.uid의 값 |
| security_action, succeeded, statusText, resultType | security_result.action | security_action이 허용인 경우 ALLOW로 설정됩니다. 그렇지 않고 성공이 true이거나 statusText가 Success이거나 resultType이 success인 경우 ALLOW로 설정됩니다. 그렇지 않고 성공이 false이거나 statusText가 failed이거나 resultType이 failed인 경우 BLOCK으로 설정됩니다. |
| properties.action_name | security_result.action_details | properties.action_name에서 직접 복사된 값 |
| status_label | security_result.about.resource.attribute.labels | status_label에서 병합됨 |
| properties_log_label, corr_key_label, resultType_label, resultSignature_label, networkName_label, networkType_label, method_label, authentication_step_requirement_label, authentication_step_result_detail_label, stepdate_label, initiatedby_name_label, initiatedby_id_label, initiatedby_type_label, targetSystem_id_label, targetSystem_name_label, containerID_label, pod_label, authentication_label, api_name_label, scale_unit_label, namespace_name_label, subscription_id_label, activity_id_label_1, task_name_label, environment_label, cookie, additional_field_event_ip, additional_field_event_primary_stamp, additional_field_event_stamp_type, source, correlationId_field, activityDateTime_field, detectedDateTime_field, lastUpdatedDateTime_field, count_label, total_label, minimum_label, maximum_label, average_label, metricName_label, timeGrain_label, ApiName_label, Authentication_label, GeoType_label, old_label, new_label, add_label, keyId_label, sr_result.rule_name, sr_result.rule_id, resultField, sr_result.detection_fields | security_result.detection_fields | properties_log_label, corr_key_label, resultType_label, resultSignature_label, networkName_label, networkType_label, method_label, authentication_step_requirement_label, authentication_step_result_detail_label, stepdate_label, initiatedby_name_label, initiatedby_id_label, initiatedby_type_label, targetSystem_id_label, targetSystem_name_label, containerID_label, pod_label, authentication_label, api_name_label, scale_unit_label, namespace_name_label, subscription_id_label, activity_id_label_1, task_name_label, environment_label, cookie, additional_field_event_ip, additional_field_event_primary_stamp, additional_field_event_stamp_type, source, correlationId_field, activityDateTime_field, detectedDateTime_field, lastUpdatedDateTime_field, count_label, total_label, minimum_label, maximum_label, average_label, metricName_label, timeGrain_label, ApiName_label, Authentication_label, GeoType_label, old_label, new_label, add_label, keyId_label, sr_result.rule_name, sr_result.rule_id, resultField, sr_result.detection_fields에서 병합됨 |
| resultDescription, sec_result.description, properties.queryexecutionstatus | security_result.description | resultDescription의 값 (gsub 줄바꿈) 또는 sec_result.description의 값 또는 properties.queryexecutionstatus의 값 |
| policy_id_value | security_result.rule_id | policy_id_value에서 직접 복사한 값 |
| properties.Result, statusText, properties.queryexecutionstatus | security_result.summary | 비어 있지 않으면 properties.Result의 값, 비어 있으면 statusText의 값, 비어 있으면 properties.queryexecutionstatus의 값 |
| target_application | target.application | target_application의 값 |
| properties.ComputerName, record.properties.ComputerName, properties.server_instance_name, record.properties.server_instance_name | target.asset.hostname | properties.ComputerName, record.properties.ComputerName, properties.server_instance_name 또는 record.properties.server_instance_name의 값 |
| (하드 코딩됨) | target.cloud.environment | 'MICROSOFT_AZURE'로 설정합니다. |
| properties.SPort, record.properties.SPort | target.port | properties.SPort 또는 record.properties.SPort에서 정수로 변환됨 |
| properties.querytext.query | target.process.command_line | properties.querytext.query에서 직접 복사한 값 |
| properties.processId | target.process.pid | properties.processId에서 문자열로 변환됨 |
| subscription_id_label, resource_group_label, request_resource_type_label, request_resource_id_label, additional_objectKey, additional_clientRequestId, additional_RiskEventType, additional_tokenIssuerType, keyId_label, appid_label | target.resource.attribute.labels | subscription_id_label, resource_group_label, request_resource_type_label, request_resource_id_label, additional_objectKey, additional_clientRequestId, additional_RiskEventType, additional_tokenIssuerType, keyId_label, appid_label에서 병합됨 |
| properties_databasename, properties.resourceDisplayName, record.properties.databasename, record.properties.databaseName | target.resource.name | 비어 있지 않은 경우 properties_databasename의 값, 그렇지 않은 경우 properties.resourceDisplayName의 값, 그렇지 않은 경우 record.properties.databasename의 값, 그렇지 않은 경우 record.properties.databaseName의 값 |
| resourceId, properties.resourceId | target.resource.product_object_id | 비어 있지 않으면 resourceId의 값, 비어 있으면 properties.resourceId의 값 |
| properties_collectionname, properties.resourceDisplayName, record.properties.collectionname, record.properties.collectionName, properties.log.objectRef.resource | target.resource.resource_subtype | 비어 있지 않은 경우 properties_collectionname의 값, 그렇지 않은 경우 properties.resourceDisplayName의 값, 그렇지 않은 경우 record.properties.collectionname의 값, 그렇지 않은 경우 record.properties.collectionName의 값, 그렇지 않은 경우 properties.log.objectRef.resource의 값 |
| resourceId, message | target.resource.resource_type | resourceId가 패턴과 일치하면 DATABASE로 설정하고, 메시지가 MANAGEDCLUSTERS와 일치하면 CLUSTER로 설정하고, MANAGEDINSTANCES와 일치하면 VIRTUAL_MACHINE으로 설정하고, DATABASEACCOUNTS와 일치하면 DATABASE로 설정합니다. |
| resourceType | target.resource.type | resourceType에서 직접 복사된 값 |
| properties.CsUriStem, properties.log.requestURI, value (additionalInfo에서 가져옴) | target.url | 비어 있지 않은 경우 properties.CsUriStem의 값, 그렇지 않은 경우 properties.log.requestURI의 값, 그렇지 않은 경우 값 (additionalInfo에서) |
| user_principal_name | target.user.email_addresses | user_principal_name에서 병합됨 (이메일과 일치하는 경우) |
| properties.userId | target.user.product_object_id | properties.userId에서 직접 복사된 값 |
| properties.userDisplayName | target.user.user_display_name | properties.userDisplayName에서 직접 복사된 값 |
| user_principal_name, properties.userPrincipalName | target.user.userid | 비어 있지 않은 경우 user_principal_name의 값, 비어 있는 경우 properties.userPrincipalName의 값 |
| (하드 코딩됨) | metadata.product_name | 'Azure 리소스 로그'로 설정 |
| (하드 코딩됨) | metadata.vendor_name | 'Microsoft'로 설정 |
도움이 더 필요하신가요? 커뮤니티 회원 및 Google SecOps 전문가에게 문의하여 답변을 받으세요.