批量修改AlibabaCloud阿里云service访问控制和安全组白名单IP设置Python脚本

更新一

下文脚本已经重写并分享到GitHub,而且新的脚本同时集成了亚马逊AWS的相关操作实现,参考https://github.com/Bilery-Zoo/Cloud_Platform_Maintenance/tree/master/CloudPlatform_WhitelistIP_Switcher。而亚马逊AWS单独实现的脚本,也可以参考之后的博文https://blog.csdn.net/sweeper_freedoman/article/details/100868645


阿里云 / AlibabaCloud的若干服务(service)出于安全考虑都有访问控制(Access control)或者叫安全组(Security Group)的设计,类似白名单黑名单的功能,用于控制哪些网络 / 网络段可以访问或者不能访问该服务实例,是一种重要的安全策略。例如负载均衡SLB、内容分发网络CDN和云关系型数据库RDS等。

生产环境一般都会在这些服务的白名单里面配置本地的公网IP(公司或个人公网IP),以使得只有自己的本地网络才可以访问相关服务实例。但是如果本地公网IP发生变更,一个个地手动去修改云上配置,一方面工作比较繁复,另一方面也不安全。所以,用脚本去做是最理想的事情。

以下Python脚本即做了SLB、CDN和RDS三个service的白名单IP变更。过程分为两步:

1.向配置了旧的公网IP的白名单里面添加新的公网IP

2.从添加了新的公网IP的白名单里面删除旧的公网IP

这样可以实现平稳切换。

脚本文件定义如下:

├── functions.py

        base function of AlibabaCloud handlers module (may need OOP rewriting next time)
├── log.py

        log logging module
├── new_ip_append.py

        new IP appending call file
└── old_ip_delete.py

        odl IP deleting call file

functions.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


"""
create_author : 蛙鳜鸡鹳狸猿
create_time   : 2019-08-30
program       : *_* base function of AlibabaCloud handlers module (may need OOP rewriting next time) *_*
"""


import re
import json
import typing

from aliyunsdkcore.client import AcsClient
from aliyunsdkslb.request.v20140515 import DescribeAccessControlListsRequest, DescribeAccessControlListAttributeRequest
from aliyunsdkslb.request.v20140515 import AddAccessControlListEntryRequest, RemoveAccessControlListEntryRequest
from aliyunsdkcdn.request.v20180510 import DescribeUserDomainsRequest, DescribeCdnDomainConfigsRequest
from aliyunsdkcdn.request.v20180510 import BatchSetCdnDomainConfigRequest
from aliyunsdkrds.request.v20140815 import DescribeDBInstancesRequest, DescribeDBInstanceIPArrayListRequest
from aliyunsdkrds.request.v20140815 import ModifySecurityIpsRequest

import log

logger = log.LOG().logger()


@log.log(logger=logger, if_exit=True)
def get_slb_gip_info(re_ip, access_key_id=None, access_key_secret=None, region_id=None, ) -> typing.Generator:
    """
    Get IP info of SLB Access Control.
    :param re_ip: IP to get info.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Dict, {"AclId": ..., }.
    """
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = DescribeAccessControlListsRequest.DescribeAccessControlListsRequest()
    response = client.do_action_with_exception(request)
    for instance in json.loads((response.decode("utf-8")))["Acls"]["Acl"]:
        request_sub = DescribeAccessControlListAttributeRequest.DescribeAccessControlListAttributeRequest()
        request_sub.set_AclId(instance["AclId"])
        response_sub = client.do_action_with_exception(request_sub)
        data_sub = json.loads((response_sub.decode("utf-8")))
        if re.search(re_ip, str(data_sub)):
            gip_info = {"AclId": data_sub["AclId"], }
            logger.info("get_slb_gip_info:\n\t{gip_info}".format(gip_info=gip_info))
            yield gip_info


@log.log(logger=logger, if_exit=True)
def get_cdn_gip_info(re_ip, access_key_id=None, access_key_secret=None, region_id=None, ) -> typing.Generator:
    """
    Get IP info of SLB Access Control.
    :param re_ip: IP to get info.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Dict, {"DomainNames": ..., }.
    """
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = DescribeUserDomainsRequest.DescribeUserDomainsRequest()
    response = client.do_action_with_exception(request)
    for instance in json.loads((response.decode("utf-8")))["Domains"]["PageData"]:
        request_sub = DescribeCdnDomainConfigsRequest.DescribeCdnDomainConfigsRequest()
        request_sub.set_DomainName(instance["DomainName"])
        response_sub = client.do_action_with_exception(request_sub)
        data_sub = json.loads((response_sub.decode("utf-8")))
        if re.search(re_ip, str(data_sub)):
            for config in data_sub["DomainConfigs"]["DomainConfig"]:
                if config["FunctionName"] == "ip_allow_list_set":
                    gip_info = {"DomainNames": instance["DomainName"],
                                "ip_allow_list_set": config["FunctionArgs"]["FunctionArg"][0]["ArgValue"]}
                    logger.info("get_cdn_gip_info:\n\t{gip_info}".format(gip_info=gip_info))
                    yield gip_info
                    break


@log.log(logger=logger, if_exit=True)
def get_rds_gip_info(re_ip, access_key_id=None, access_key_secret=None, region_id=None, ) -> typing.Generator:
    """
    Get IP info of RDS Data Security.
    :param re_ip: IP to get info.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Dict, {"DBInstanceId": ..., }.
    """
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = DescribeDBInstancesRequest.DescribeDBInstancesRequest()
    response = client.do_action_with_exception(request)
    # print(json.loads((response.decode("utf-8"))))
    for instance in json.loads((response.decode("utf-8")))["Items"]["DBInstance"]:
        request_sub = DescribeDBInstanceIPArrayListRequest.DescribeDBInstanceIPArrayListRequest()
        request_sub.set_DBInstanceId(instance["DBInstanceId"])
        response_sub = client.do_action_with_exception(request_sub)
        data_sub = json.loads((response_sub.decode("utf-8")))
        # print(data_sub)
        if re.search(re_ip, str(data_sub)):
            for config in data_sub["Items"]["DBInstanceIPArray"]:
                if re.search(re_ip, str(config)):
                    gip_info = {"DBInstanceId": instance["DBInstanceId"],
                                "DBInstanceIPArrayName": config["DBInstanceIPArrayName"],
                                "DBInstanceIPArrayAttribute": config["DBInstanceIPArrayAttribute"],
                                "WhitelistNetworkType": config["WhitelistNetworkType"],
                                "SecurityIPType": config["SecurityIPType"]}
                    logger.info("get_rds_gip_info:\n\t{gip_info}".format(gip_info=gip_info))
                    yield gip_info
                    break


@log.log(logger=logger, if_exit=True)
def add_slb_gip_info(add_entry: list, acl_id: str, access_key_id=None, access_key_secret=None, region_id=None, ):
    """
    Add IP info into SLB Access Control. See also:
        https://www.alibabacloud.com/help/zh/doc-detail/70023.htm.
    :param add_entry: List consisted of Dict, eg `[{"entry": "IP / IP block", "comment": "..."}, ]`.
    :param acl_id: AclId of SLB.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Python built-in exit code.
    """
    logger.warning("add_slb_gip_info:\n\t{info}".format(info=str(
        {"acl_id": acl_id, "add_entry": add_entry, }
    )))
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = AddAccessControlListEntryRequest.AddAccessControlListEntryRequest()
    request.set_accept_format('json')
    request.set_AclId(acl_id)
    request.set_AclEntrys(str(add_entry))
    client.do_action_with_exception(request)


@log.log(logger=logger, if_exit=True)
def remove_slb_gip_info(remove_entry: list, acl_id: str, access_key_id=None, access_key_secret=None, region_id=None, ):
    """
    Remove IP info into SLB Access Control. See also:
        https://www.alibabacloud.com/help/zh/doc-detail/70055.htm.
    :param remove_entry: List consisted of Dict, eg `[{"entry": "IP / IP block", "comment": "..."}, ]`.
    :param acl_id: AclId of SLB.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Python built-in exit code.
    """
    logger.warning("remove_slb_gip_info:\n\t{info}".format(info=str(
        {"acl_id": acl_id, "remove_entry": remove_entry, }
    )))
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = RemoveAccessControlListEntryRequest.RemoveAccessControlListEntryRequest()
    request.set_accept_format('json')
    request.set_AclId(acl_id)
    request.set_AclEntrys(str(remove_entry))
    client.do_action_with_exception(request)


@log.log(logger=logger, if_exit=True)
def modify_cdn_gip_info(modify_entry: list, domain_name: str, access_key_id=None, access_key_secret=None, region_id=None, ):
    """
    Modify IP info into CDN Access Control. See also:
        https://www.alibabacloud.com/help/zh/doc-detail/90915.htm.
    :param modify_entry: List consisted of Dict, eg `[{"functionArgs": [{"argName": "ip_list", "argValue": ...}], "functionName": "ip_allow_list_set"}]`.
    :param domain_name: DomainName of CDN.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Python built-in exit code.
    """
    logger.warning("modify_cdn_gip_info:\n\t{info}".format(info=str(
        {"domain_name": domain_name, "modify_entry": modify_entry, }
    )))
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = BatchSetCdnDomainConfigRequest.BatchSetCdnDomainConfigRequest()
    request.set_accept_format('json')
    request.set_DomainNames(domain_name)
    request.set_Functions(modify_entry)
    client.do_action_with_exception(request)


@log.log(logger=logger, if_exit=True)
def modify_rds_gip_info(modify_ip: str, modify_mode: str, db_instance_id: str,
                        ip_array_name: str, ip_array_attribute: str, ip_type: str, network_type: str,
                        access_key_id=None, access_key_secret=None, region_id=None, ):
    """
    Modify IP info into RDS Data Security. See also:
        https://www.alibabacloud.com/help/zh/doc-detail/26242.htm?spm=a2c63.p38356.879954.54.6eb34542JGBoSp.
    :param modify_ip: IP address to modify.
    :param modify_mode: modify mode(valid values: Append, Delete, Cover).
    :param db_instance_id: RDS instance ID.
    :param ip_array_name: RDS instance IP array name.
    :param ip_array_attribute: RDS instance IP array attribute.
    :param ip_type: IP type.
    :param network_type: network type.
    :param access_key_id: AlibabaCloud auth access_key_id.
    :param access_key_secret: AlibabaCloud auth access_key_secret.
    :param region_id: AlibabaCloud region_id.
    :return: Python built-in exit code.
    """
    logger.warning("modify_rds_gip_info:\n\t{info}".format(info=str(
        {"db_instance_id": db_instance_id, "ip_array_name": ip_array_name,
         "modify_mode": modify_mode, "modify_ip": modify_ip, }
    )))
    client = AcsClient(access_key_id, access_key_secret, region_id)
    request = ModifySecurityIpsRequest.ModifySecurityIpsRequest()
    request.set_accept_format('json')
    request.set_SecurityIps(modify_ip)
    request.set_ModifyMode(modify_mode)
    request.set_DBInstanceId(db_instance_id)
    request.set_DBInstanceIPArrayName(ip_array_name)
    request.set_DBInstanceIPArrayAttribute(ip_array_attribute)
    request.set_SecurityIPType(ip_type)
    request.set_WhitelistNetworkType(network_type)
    client.do_action_with_exception(request)


if __name__ == "__main__":
    """
    SLB
    """
    # for i in get_slb_gip_info():
    #     print(i)
    # add_slb_gip_info("acl-......",
    #                  [{"entry": "127.0.0.0/32", "comment": "テストの為IP"}, ]
    #                  )
    # remove_slb_gip_info("acl-......",
    #                     [{"entry": "127.0.0.0/32", }, ]
    #                     )
    """
    CDN
    """
    # for i in get_cdn_gip_info():
    #     print(i)
    # modify_cdn_gip_info("www.ip_switch.test.com", [
    #     {"functionArgs": [{"argName": "ip_list", "argValue": "127.0.0.0/32,127.0.0.1/32"}],
    #  "functionName": "ip_allow_list_set"}])
    """
    RDS
    """
    # for i in get_rds_gip_info():
    #     print(i)
    # modify_rds_gip_info("127.0.0.0", "Delete", "rm-......", "test", '', "IPv4", "MIX")

log.py

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-


"""
create_author : 蛙鳜鸡鹳狸猿
create_time   : 2019-08-30
program       : *_* log logging module *_*
"""


import os
import sys
import logging
import functools


class LOG(object):
    """
    Log logging definition.
    """

    def __init__(self, level=logging.INFO, stream=sys.stdout, filemode='a',
                 filename=os.path.dirname(os.path.abspath(__file__)) + '/' + "log",
                 datefmt="%Y-%m-%d %H:%M:%S",
                 format="%(asctime)s\t%(levelname)s\t< Module: %(module)s, Function: %(funcName)s >\t%(message)s",
                 **kwargs):
        """
        LOG init.
        :param level: arg pass to standard library logging.basicConfig().
        :param stream: arg pass to standard library logging.basicConfig().
        :param filemode: arg pass to standard library logging.basicConfig().
        :param filename: arg pass to standard library logging.basicConfig().
        :param datefmt: arg pass to standard library logging.basicConfig().
        :param format: arg pass to standard library logging.basicConfig().
        :param kwargs: arg pass to standard library logging.basicConfig().
        """
        self.level = level
        self.stream = stream
        self.filename = filename
        self.filemode = filemode
        self.datefmt = datefmt
        self.format = format
        self.kwargs = kwargs

    def logger(self, name=__name__):
        """
        Logger object generates.
        :param name: Logger name(parameters pass to standard library logging.getLogger()).
        :return: Logger object.
        """
        args = {
            "level": self.level,
            "stream": self.stream,
            "filename": self.filename,
            "filemode": self.filemode,
            "datefmt": self.datefmt,
            "format": self.format,
        }
        try:
            if self.stream and self.filename:
                del args["stream"]
        except KeyError:
            pass
        logging.basicConfig(**args, **self.kwargs)
        return logging.getLogger(name)


def raise_log(raised_except, msg=''):
    """
    Raise exception by hand to escape error exit caused by built-in [raise].
    :param raised_except: Exception object.
    :param msg: Exception feedback message.
    :return: Python's built-in exit code.
        Output Exception of [raised_except].
    """
    try:
        raise raised_except(msg)
    except raised_except as E:
        logging.exception(E)


def log(logger=None, exc_msg='', if_exit=False, exit_msg='', result_check=False, check_except=None, check_msg=''):
    """
    Log logging decorator function.
    :param logger: Logger object(see also logging.getLogger()).
    :param exc_msg: extra message to return when exceptions catch.
    :param if_exit: Boolean.
        Whether to exit or not when catching exception.
    :param exit_msg: extra message to return when exceptions catch and exit.
    :param result_check: Boolean.
        Whether or not to check Python's False status result of [func]'s return.
    :param check_except: Exception object to raise when [result_check].
    :param check_msg: Exception feedback message to return when [result_check].
    :return: decorated function [func]'s return.
    """
    if not logger:
        logger = LOG().logger()

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = None
            try:
                result = func(*args, **kwargs)
            except BaseException:
                logger.exception(exc_msg)
                if if_exit:
                    sys.exit(exit_msg)
            finally:
                if result_check:
                    if not result:
                        raise_log(check_except, check_msg)
                return result
        return wrapper
    return decorator


if __name__ == "__main__":
    LOG_Test = LOG
    # LOG().logger().info("INFO:Come...")
    # LOG().logger().error("ERROR:Come...")

    # @log()
    # def get(a, b):
    #     return a / b
    # get(a=1, b=0)

new_ip_append.py

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-


"""
create_author : 蛙鳜鸡鹳狸猿
create_time   : 2019-08-30
program       : *_* new IP appending call file *_*
"""


import re
import functions


"""
*******************************************************************************
Unit test button
                        |\_/|
                        | ・x・ |
               \_____/    |
                 |         |
                \       ノ 
             ((( (/ ̄ ̄ ̄ ̄(/ヽ)
"""
UT_FLAG = True
"""
Default `True` for script testing
Set to `False` when production using
*******************************************************************************
"""


new_gip = ""
old_gip = "127.0.0.0" if UT_FLAG else ""
re_ip = re.compile(r"127[.]0[.]0[.]0") if UT_FLAG else re.compile(r"127[.]0[.]0[.]11")

sbcloud_region = ["ap-northeast-1",
                  "cn-qingdao",
                  "cn-beijing",
                  "cn-zhangjiakou",
                  "cn-huhehaote",
                  "cn-hangzhou",
                  "cn-shanghai",
                  "cn-shenzhen",
                  "cn-chengdu",
                  "cn-hongkong",
                  "ap-southeast-1",
                  "ap-southeast-2",
                  "ap-southeast-3",
                  "ap-southeast-5",
                  "ap-south-1",
                  "us-west-1",
                  "us-east-1",
                  "eu-central-1",
                  "eu-west-1",
                  "me-east-1",
                  ]
SBCloud_Access_Key = {"access_key_id": "",
                      "access_key_secret": "",
                      "region_id": sbcloud_region[0],
                      }


# append new IP into SLB
for slb_gip_info in functions.get_slb_gip_info(re_ip, **SBCloud_Access_Key):
    slb_append_info = ([{"entry": "{new_gip}/32".format(new_gip=new_gip), "comment": "汐留GIP"}, ],
                       slb_gip_info["AclId"], )
    functions.add_slb_gip_info(*slb_append_info, **SBCloud_Access_Key)


# append new IP into CDN
for cdn_gip_info in functions.get_cdn_gip_info(re_ip, **SBCloud_Access_Key):
    ip_append_info = re.sub(re_ip, "{old_gip}/32,{new_gip}".format(old_gip=old_gip, new_gip=new_gip),
                            cdn_gip_info["ip_allow_list_set"])
    cdn_append_info = ([{"functionArgs": [{"argName": "ip_list",
                                           "argValue": "{ip_append_info}".format(ip_append_info=ip_append_info)}],
                         "functionName": "ip_allow_list_set"}],
                       cdn_gip_info["DomainNames"], )
    functions.modify_cdn_gip_info(*cdn_append_info, **SBCloud_Access_Key)


# append new IP into RDS
for rds_gip_info in functions.get_rds_gip_info(re_ip, **SBCloud_Access_Key):
    rds_append_info = (new_gip, "Append", rds_gip_info["DBInstanceId"],
                       rds_gip_info["DBInstanceIPArrayName"], rds_gip_info["DBInstanceIPArrayAttribute"],
                       rds_gip_info["SecurityIPType"], rds_gip_info["WhitelistNetworkType"], )
    functions.modify_rds_gip_info(*rds_append_info, **SBCloud_Access_Key)

old_ip_delete.py

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-


"""
create_author : 蛙鳜鸡鹳狸猿
create_time   : 2019-08-30
program       : *_* odl IP deleting call file *_*
"""


import re
import functions


"""
*******************************************************************************
Unit test button
                        |\_/|
                        | ・x・ |
               \_____/    |
                 |         |
                \       ノ 
             ((( (/ ̄ ̄ ̄ ̄(/ヽ)
"""
UT_FLAG = True
"""
Default `True` for script testing
Set to `False` when production using
*******************************************************************************
"""


old_gip = "127.0.0.0" if UT_FLAG else ""
re_ip = re.compile(r"127[.]0[.]0[.]0") if UT_FLAG else re.compile(r"127[.]0[.]0[.]11")


sbcloud_region = ["ap-northeast-1",
                  "cn-qingdao",
                  "cn-beijing",
                  "cn-zhangjiakou",
                  "cn-huhehaote",
                  "cn-hangzhou",
                  "cn-shanghai",
                  "cn-shenzhen",
                  "cn-chengdu",
                  "cn-hongkong",
                  "ap-southeast-1",
                  "ap-southeast-2",
                  "ap-southeast-3",
                  "ap-southeast-5",
                  "ap-south-1",
                  "us-west-1",
                  "us-east-1",
                  "eu-central-1",
                  "eu-west-1",
                  "me-east-1",
                  ]
SBCloud_Access_Key = {"access_key_id": "LTAIhY89cQ2i0gdi",
                      "access_key_secret": "cXkEFvWUjpQvl0d4F0Le0dr2SI9d1o",
                      "region_id": sbcloud_region[0],
                      }


# delete old IP into SLB
for slb_gip_info in functions.get_slb_gip_info(re_ip, **SBCloud_Access_Key):
    slb_remove_info = ([{"entry": "{old_gip}/32".format(old_gip=old_gip), }, ],
                       slb_gip_info["AclId"], )
    functions.remove_slb_gip_info(*slb_remove_info, **SBCloud_Access_Key)


# delete old IP into CDN
for cdn_gip_info in functions.get_cdn_gip_info(re_ip, **SBCloud_Access_Key):
    ip_remove_info = re.sub("{old_gip}/32,".format(old_gip=old_gip), '', cdn_gip_info["ip_allow_list_set"])
    cdn_remove_info = ([{"functionArgs": [{"argName": "ip_list",
                                           "argValue": "{ip_remove_info}".format(ip_remove_info=ip_remove_info)}],
                         "functionName": "ip_allow_list_set"}],
                       cdn_gip_info["DomainNames"], )
    functions.modify_cdn_gip_info(*cdn_remove_info, **SBCloud_Access_Key)


# delete old IP into RDS
for rds_gip_info in functions.get_rds_gip_info(re_ip, **SBCloud_Access_Key):
    rds_remove_info = (old_gip, "Delete", rds_gip_info["DBInstanceId"],
                       rds_gip_info["DBInstanceIPArrayName"], rds_gip_info["DBInstanceIPArrayAttribute"],
                       rds_gip_info["SecurityIPType"], rds_gip_info["WhitelistNetworkType"], )
    functions.modify_rds_gip_info(*rds_remove_info, **SBCloud_Access_Key)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值