Skip to content
Open
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
12 changes: 12 additions & 0 deletions tools/c7n_huaweicloud/c7n_huaweicloud/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
from huaweicloudsdkram.v1.region.ram_region import RamRegion
from huaweicloudsdkcc.v3 import CcClient, ListCentralNetworksRequest
from huaweicloudsdkcc.v3.region.cc_region import CcRegion
from huaweicloudsdkwaf.v1 import WafClient, ListPolicyRequest, ShowLtsInfoConfigRequest
from huaweicloudsdkwaf.v1.region.waf_region import WafRegion

log = logging.getLogger("custodian.huaweicloud.client")

Expand Down Expand Up @@ -424,6 +426,12 @@ def client(self, service):
BmsClient.new_builder()
.with_credentials(credentials)
.with_region(BmsRegion.value_of(self.region))
)
elif service in ["waf", "waf-policy", "waf-log-config"]:
client = (
WafClient.new_builder()
.with_credentials(credentials)
.with_region(WafRegion.value_of(self.region))
.build()
)

Expand Down Expand Up @@ -538,5 +546,9 @@ def request(self, service):
request = ListInstancesRequest()
elif service == "bms":
request = ListBareMetalServerDetailsRequest()
elif service == 'waf-policy':
request = ListPolicyRequest()
elif service == 'waf-log-config':
request = ShowLtsInfoConfigRequest()

return request
35 changes: 35 additions & 0 deletions tools/c7n_huaweicloud/c7n_huaweicloud/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def filter(self, resource_manager, **params):
resources = self._non_pagination(m, enum_op, path)
elif pagination == "page":
resources = self._pagination_limit_page(m, enum_op, path)
elif pagination == "waf":
resources = self._pagination_waf(m, enum_op, path)
else:
log.exception(f"Unsupported pagination type: {pagination}")
sys.exit(1)
Expand Down Expand Up @@ -310,6 +312,39 @@ def _pagination_ims(self, m, enum_op, path):
data["tag_resource_type"] = m.tag_resource_type
resources.extend(res)
return resources

def _pagination_waf(self, m, enum_op, path):
session = local_session(self.session_factory)
client = session.client(m.service)

page = 1
resources = []
while 1:
request = session.request(m.service)
request.page = page
response = self._invoke_client_enum(client, enum_op, request)
res = jmespath.search(
path,
eval(
str(response)
.replace("null", "None")
.replace("false", "False")
.replace("true", "True")
),
)

if not res:
return resources

# replace id with the specified one
for data in res:
data["id"] = data[m.id]
data["tag_resource_type"] = m.tag_resource_type

resources = resources + res

page += 1
return resources

def _get_obs_account_id(self, response, manager, resources):
if manager.service == "obs":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@
"huaweicloud.kafka": "c7n_huaweicloud.resources.kafka.Kafka",
"huaweicloud.cc-cloud-connection": "c7n_huaweicloud.resources.cc.CloudConnection",
"huaweicloud.bms": "c7n_huaweicloud.resources.bms.Bms",
"huaweicloud.waf-policy": "c7n_huaweicloud.resources.waf.WafPolicy",
"huaweicloud.waf-log-config": "c7n_huaweicloud.resources.waf.WafLogConfig",
}
183 changes: 183 additions & 0 deletions tools/c7n_huaweicloud/c7n_huaweicloud/resources/waf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Copyright The Cloud Custodian Authors.
# SPDX-License-Identifier: Apache-2.0

import logging
from c7n.utils import type_schema
from c7n.filters.core import ValueFilter

from huaweicloudsdkcore.exceptions import exceptions
from huaweicloudsdkwaf.v1.model.update_lts_info_config_request import UpdateLtsInfoConfigRequest
from huaweicloudsdkwaf.v1.model.update_lts_info_config_request_body import UpdateLtsInfoConfigRequestBody
from huaweicloudsdkwaf.v1.model.lts_id_info import LtsIdInfo

from c7n_huaweicloud.actions.base import HuaweiCloudBaseAction
from c7n_huaweicloud.provider import resources
from c7n_huaweicloud.query import QueryResourceManager, TypeInfo

log = logging.getLogger('custodian.huaweicloud.resources.waf')


@resources.register('waf-policy')
class WafPolicy(QueryResourceManager):
"""Huawei Cloud Web Application Firewall (WAF) Policy Resource

:example:

.. code-block:: yaml

policies:
- name: waf-policy-list
resource: huaweicloud.waf-policy
"""

class resource_type(TypeInfo):
"""Define WAF policy resource metadata and type information"""
service = 'waf-policy' # Specify the corresponding Huawei Cloud service name
# Specify the API operation, result list key name, and pagination parameters for enumerating resources
# 'list_policy' is the API method name
# 'items' is the field name containing the instance list in the response
# None indicates no pagination is used
enum_spec = ('list_policy', 'items', "waf")
id = 'id' # Specify the resource unique identifier field name
name = 'name' # Specify the resource name field
date = 'timestamp' # Specify the resource creation time field
arn_type = 'waf-policy' # Resource ARN type
tag_resource_type = None # Tag not supported


@resources.register('waf-log-config')
class WafLogConfig(QueryResourceManager):
"""Huawei Cloud Web Application Firewall (WAF) Log Configuration Resource

:example:

.. code-block:: yaml

policies:
- name: waf-log-config-list
resource: huaweicloud.waf-log-config
"""

class resource_type(TypeInfo):
"""Define WAF log configuration resource metadata and type information"""
service = 'waf-log-config' # Specify the corresponding Huawei Cloud service name
# Specify the API operation, result list key name, and pagination parameters for enumerating resources
# 'show_lts_info_config' is the API method name
# 'lts_info' is the field name containing the instance info in the response
# None indicates no pagination is used
enum_spec = ('show_lts_info_config', "[ @ ]", None)
id = 'id' # Specify the resource unique identifier field name
name = 'id' # Specify the resource name field
arn_type = 'waf-log-config' # Resource ARN type
tag_resource_type = None # Tag not supported


@WafLogConfig.filter_registry.register('enabled')
class LogEnabledFilter(ValueFilter):
"""Filter by WAF log configuration enabled status

:example:

.. code-block:: yaml

policies:
- name: waf-logs-disabled
resource: huaweicloud.waf-log-config
filters:
- type: enabled
value: false # Not enabled
"""
schema = type_schema('enabled', rinherit=ValueFilter.schema)

def __init__(self, data, manager=None):
"""Initialize the filter

:param data: Filter configuration data
:param manager: Resource manager
"""
super(LogEnabledFilter, self).__init__(data, manager)
self.data['key'] = 'enabled'


@WafLogConfig.action_registry.register('update')
class UpdateLogConfig(HuaweiCloudBaseAction):
"""Update WAF log configuration

This operation allows enabling/disabling WAF log configuration and setting log group and log stream information.

:example:

.. code-block:: yaml

policies:
- name: enable-waf-logs
resource: huaweicloud.waf-log-config
filters:
- type: enabled
value: false # Not enabled
actions:
- type: update
enabled: true # Enabled
lts_id_info:
lts_group_id: "4bcff74d-f649-41c8-8325-1b0a264ff683"
lts_access_stream_id: "0a7ef713-cc3e-418d-abda-85df04db1a3c"
lts_attack_stream_id: "f4fa07f6-277b-4e4a-a257-26508ece81e6"
"""
schema = type_schema(
'update',
enabled={'type': 'boolean'},
lts_id_info={
'type': 'object',
'properties': {
'lts_group_id': {'type': 'string'},
'lts_access_stream_id': {'type': 'string'},
'lts_attack_stream_id': {'type': 'string'}
},
'additionalProperties': False
}
)

def perform_action(self, resource):
"""Perform action on a single resource

:param resource: Resource to perform action on
:return: API response
"""
client = self.manager.get_client()
resource_id = resource['id']

# Construct log information object
lts_id_info_data = self.data.get('lts_id_info')
lts_id_info = None

if lts_id_info_data:
lts_id_info = LtsIdInfo(
lts_group_id=lts_id_info_data.get('lts_group_id'),
lts_access_stream_id=lts_id_info_data.get('lts_access_stream_id'),
lts_attack_stream_id=lts_id_info_data.get('lts_attack_stream_id')
)

# Construct request body
request_body = UpdateLtsInfoConfigRequestBody(
enabled=self.data.get('enabled'),
lts_id_info=lts_id_info
)

# Construct request
request = UpdateLtsInfoConfigRequest(
ltsconfig_id=resource_id,
body=request_body
)

# Get enterprise project ID from resource data
if 'enterprise_project_id' in resource:
request.enterprise_project_id = resource['enterprise_project_id']

try:
# Call API to update log configuration
response = client.update_lts_info_config(request)
log.info(f"Updated WAF log configuration: {resource_id}")
return response
except exceptions.ClientRequestException as e:
log.error(f"Failed to update WAF log configuration: {e.status_code}, {e.request_id}, {e.error_code}, {e.error_msg}")
raise
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, zstd
Connection:
- keep-alive
Content-Type:
- application/json
Host:
- waf.ap-southeast-1.myhuaweicloud.com
User-Agent:
- huaweicloud-usdk-python/3.0
X-Project-Id:
- ap-southeat-1
X-Sdk-Date:
- 20250512T114219Z
method: GET
uri: https://waf.ap-southeast-1.myhuaweicloud.com/v1/ap-southeat-1/waf/config/lts
response:
body:
string: '{"id": "log-config-12345", "enabled": false, "lts_id_info": {"lts_group_id": "group-id-12345", "lts_access_stream_id": "access-stream-id-12345", "lts_attack_stream_id": "attack-stream-id-12345"}, "created_at": 1619760096000, "updated_at": 1619760096000}'
headers:
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Mon, 12 May 2025 11:42:19 GMT
Server:
- api-gateway
Strict-Transport-Security:
- max-age=31536000; includeSubdomains;
Transfer-Encoding:
- chunked
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Request-Id:
- 193cbe0734c19b58215a6d4ae57e10f3
X-XSS-Protection:
- 1; mode=block;
status:
code: 200
message: success
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, zstd
Connection:
- keep-alive
Content-Type:
- application/json
Host:
- waf.ap-southeast-1.myhuaweicloud.com
User-Agent:
- huaweicloud-usdk-python/3.0
X-Project-Id:
- ap-southeat-1
X-Sdk-Date:
- 20250512T114219Z
method: GET
uri: https://waf.ap-southeast-1.myhuaweicloud.com/v1/ap-southeat-1/waf/config/lts
response:
body:
string: '{"id": "log-config-12345", "enabled": true, "lts_id_info": {"lts_group_id": "group-id-12345", "lts_access_stream_id": "access-stream-id-12345", "lts_attack_stream_id": "attack-stream-id-12345"}, "created_at": 1619760096000, "updated_at": 1619760096000}'
headers:
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Mon, 12 May 2025 11:42:19 GMT
Server:
- api-gateway
Strict-Transport-Security:
- max-age=31536000; includeSubdomains;
Transfer-Encoding:
- chunked
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Request-Id:
- 2bc9734083ff7bc42e49dce25344025d
X-XSS-Protection:
- 1; mode=block;
status:
code: 200
message: success
version: 1
Loading