diff --git a/domain_admin/api/issue_certificate_api.py b/domain_admin/api/issue_certificate_api.py index 3dd90229cd..9dfa26f7f4 100644 --- a/domain_admin/api/issue_certificate_api.py +++ b/domain_admin/api/issue_certificate_api.py @@ -278,6 +278,8 @@ def get_issue_certificate_by_id(): data = issue_certificate_row.to_dict() data['deploy_dns'] = None data['deploy_host'] = None + data['cert_deploy_host'] = None + data['cert_deploy_dns'] = None if issue_certificate_row.challenge_deploy_type_id == ChallengeDeployTypeEnum.SSH: data['deploy_host'] = HostModel.get_or_none(HostModel.id == issue_certificate_row.challenge_deploy_id) @@ -285,6 +287,11 @@ def get_issue_certificate_by_id(): elif issue_certificate_row.challenge_deploy_type_id == ChallengeDeployTypeEnum.DNS: data['deploy_dns'] = DnsModel.get_or_none(DnsModel.id == issue_certificate_row.challenge_deploy_id) + if issue_certificate_row.deploy_type_id == SSLDeployTypeEnum.SSH: + data['cert_deploy_host'] = HostModel.get_or_none(HostModel.id == issue_certificate_row.deploy_host_id) + elif issue_certificate_row.deploy_type_id in [SSLDeployTypeEnum.OSS, SSLDeployTypeEnum.CDN, SSLDeployTypeEnum.DCDN]: + data['cert_deploy_dns'] = DnsModel.get_or_none(DnsModel.id == issue_certificate_row.deploy_host_id) + return data @@ -401,6 +408,66 @@ def deploy_cert_to_oss(): return ret +def deploy_cert_to_cdn(): + """ + 部署证书到阿里云cdn + :return: + """ + issue_certificate_id = request.json['issue_certificate_id'] + dns_id = request.json['dns_id'] + + ret = issue_certificate_service.deploy_cert_to_cdn( + issue_certificate_id=issue_certificate_id, + dns_id=dns_id, + ) + + # 更新验证信息 + IssueCertificateModel.update( + deploy_type_id=SSLDeployTypeEnum.CDN, + deploy_host_id=dns_id, + ssl_deploy_status=DeployStatusEnum.SUCCESS + ).where( + IssueCertificateModel.id == issue_certificate_id + ).execute() + + # 验证成功后, check_auto_renew + issue_certificate_service.check_auto_renew( + issue_certificate_id=issue_certificate_id + ) + + return ret + + +def deploy_cert_to_dcdn(): + """ + 部署证书到阿里云dcdn + :return: + """ + issue_certificate_id = request.json['issue_certificate_id'] + dns_id = request.json['dns_id'] + + ret = issue_certificate_service.deploy_cert_to_dcdn( + issue_certificate_id=issue_certificate_id, + dns_id=dns_id, + ) + + # 更新验证信息 + IssueCertificateModel.update( + deploy_type_id=SSLDeployTypeEnum.DCDN, + deploy_host_id=dns_id, + ssl_deploy_status=DeployStatusEnum.SUCCESS + ).where( + IssueCertificateModel.id == issue_certificate_id + ).execute() + + # 验证成功后, check_auto_renew + issue_certificate_service.check_auto_renew( + issue_certificate_id=issue_certificate_id + ) + + return ret + + def add_dns_domain_record(): """ 添加dns记录 diff --git a/domain_admin/enums/ssl_deploy_type_enum.py b/domain_admin/enums/ssl_deploy_type_enum.py index c185d385b2..b87f1c2250 100644 --- a/domain_admin/enums/ssl_deploy_type_enum.py +++ b/domain_admin/enums/ssl_deploy_type_enum.py @@ -14,3 +14,7 @@ class SSLDeployTypeEnum(object): WEB_HOOK = 1 OSS = 2 + + CDN = 3 + + DCDN = 4 diff --git a/domain_admin/router/api_map.py b/domain_admin/router/api_map.py index f2d1fc83f3..d3e257fef2 100644 --- a/domain_admin/router/api_map.py +++ b/domain_admin/router/api_map.py @@ -179,6 +179,8 @@ '/api/getAllowCommands': issue_certificate_api.get_allow_commands, '/api/notifyWebHook': issue_certificate_api.notify_web_hook, '/api/deployCertToOss': issue_certificate_api.deploy_cert_to_oss, + '/api/deployCertToCdn': issue_certificate_api.deploy_cert_to_cdn, + '/api/deployCertToDcdn': issue_certificate_api.deploy_cert_to_dcdn, '/api/addDnsDomainRecord': issue_certificate_api.add_dns_domain_record, '/api/updateRowAutoRenew': issue_certificate_api.update_row_auto_renew, '/api/getIssueCertificateOptions': issue_certificate_api.get_issue_certificate_options, diff --git a/domain_admin/service/issue_certificate_service.py b/domain_admin/service/issue_certificate_service.py index 9e295ed6ce..5ab82d4df6 100644 --- a/domain_admin/service/issue_certificate_service.py +++ b/domain_admin/service/issue_certificate_service.py @@ -25,7 +25,8 @@ from domain_admin.utils.acme_util.key_type_enum import KeyTypeEnum from domain_admin.utils.cert_util import cert_common from domain_admin.utils.flask_ext.app_exception import AppException -from domain_admin.utils.open_api import aliyun_domain_api, tencentcloud_domain_api, aliyun_oss_api +from domain_admin.utils.open_api import aliyun_domain_api, tencentcloud_domain_api, aliyun_oss_api, aliyun_cdn_api, \ + aliyun_dcdn_api from domain_admin.utils.open_api.aliyun_domain_api import RecordTypeEnum from domain_admin import config @@ -338,6 +339,17 @@ def renew_certificate_row(row): dns_id=row.deploy_host_id ) + elif row.deploy_type_id == SSLDeployTypeEnum.CDN: + deploy_cert_to_cdn( + issue_certificate_id=row.id, + dns_id=row.deploy_host_id + ) + elif row.deploy_type_id == SSLDeployTypeEnum.DCDN: + deploy_cert_to_dcdn( + issue_certificate_id=row.id, + dns_id=row.deploy_host_id + ) + def deploy_verify_file(host_id, verify_deploy_path, challenges): """ @@ -587,6 +599,60 @@ def deploy_cert_to_oss(issue_certificate_id, dns_id): ) +def deploy_cert_to_cdn(issue_certificate_id, dns_id): + """ + 部署ssl证书到cdn + """ + issue_certificate_row = IssueCertificateModel.get_by_id(issue_certificate_id) + + if not issue_certificate_row: + raise AppException('证书数据不存在') + + dns_row = DnsModel.get_by_id(dns_id) + if not dns_row: + raise AppException('DNS数据不存在') + + domain = issue_certificate_row.domains[0] + + # oss_info = aliyun_oss_api.cname_to_oss_info(domain) + # if not oss_info: + # raise AppException('dns 未设置') + # + # logger.info("oss_info: %s", oss_info) + + aliyun_cdn_api.set_cdn_domain_ssl_certificate_v2( + access_key_id=dns_row.access_key, + access_key_secret=dns_row.secret_key, + domain_name=domain, + certificate=issue_certificate_row.ssl_certificate, + private_key=issue_certificate_row.ssl_certificate_key, + ) + + +def deploy_cert_to_dcdn(issue_certificate_id, dns_id): + """ + 部署ssl证书到dcdn + """ + issue_certificate_row = IssueCertificateModel.get_by_id(issue_certificate_id) + + if not issue_certificate_row: + raise AppException('证书数据不存在') + + dns_row = DnsModel.get_by_id(dns_id) + if not dns_row: + raise AppException('DNS数据不存在') + + domain = issue_certificate_row.domains[0] + + aliyun_dcdn_api.set_dcdn_domain_ssl_certificate( + access_key_id=dns_row.access_key, + access_key_secret=dns_row.secret_key, + domain_name=domain, + certificate=issue_certificate_row.ssl_certificate, + private_key=issue_certificate_row.ssl_certificate_key, + ) + + def check_auto_renew(issue_certificate_id): """ 首次申请,自动判断是否可以自动续期 diff --git a/domain_admin/utils/open_api/aliyun_cas_api.py b/domain_admin/utils/open_api/aliyun_cas_api.py index 370524959f..1bb7587981 100644 --- a/domain_admin/utils/open_api/aliyun_cas_api.py +++ b/domain_admin/utils/open_api/aliyun_cas_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -@File : aliyun_api.py +@File : aliyun_cas_api.py @Date : 2024-07-24 """ @@ -9,6 +9,8 @@ from alibabacloud_tea_openapi import models as open_api_models from alibabacloud_tea_util import models as util_models +from domain_admin.utils import uuid_util + def upload_user_certificate( access_key_id, access_key_secret, @@ -16,8 +18,10 @@ def upload_user_certificate( ): """ 上传证书 - @return: Client + @return: cert_id @throws Exception + + https://api.aliyun.com/api-tools/sdk/cas?spm=api-workbench.api_explorer.0.0.74935d8cS3kyPm&version=2020-04-07&language=python-tea&tab=primer-doc """ # 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 # 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378659.html。 @@ -39,4 +43,6 @@ def upload_user_certificate( runtime = util_models.RuntimeOptions() - client.upload_user_certificate_with_options(upload_user_certificate_request, runtime) + response = client.upload_user_certificate_with_options(upload_user_certificate_request, runtime) + + return response.body.cert_id diff --git a/domain_admin/utils/open_api/aliyun_cdn_api.py b/domain_admin/utils/open_api/aliyun_cdn_api.py index f1d82627c5..7b5009908e 100644 --- a/domain_admin/utils/open_api/aliyun_cdn_api.py +++ b/domain_admin/utils/open_api/aliyun_cdn_api.py @@ -9,8 +9,22 @@ from alibabacloud_tea_openapi import models as open_api_models from alibabacloud_tea_util import models as util_models +from domain_admin.utils import uuid_util +from domain_admin.utils.open_api import aliyun_cas_api -def set_cdn_domain_ssl_certificate(access_key_id, access_key_secret, domain_name): + +def set_cdn_domain_ssl_certificate( + access_key_id, access_key_secret, + domain_name, + cert_id, cert_name): + """ + https://api.aliyun.com/api-tools/sdk/Cdn?spm=api-workbench.api_explorer.0.0.539f3761ceDHDv&version=2018-05-10&language=python-tea&tab=primer-doc + :param access_key_id: + :param access_key_secret: + :param domain_name: + :param cert_id: + :return: + """ # 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 # 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378659.html。 config = open_api_models.Config( @@ -19,11 +33,14 @@ def set_cdn_domain_ssl_certificate(access_key_id, access_key_secret, domain_name # 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。, access_key_secret=access_key_secret, ) + # Endpoint 请参考 https://api.aliyun.com/product/Cdn - config.endpoint = f'cdn.aliyuncs.com' + config.endpoint = 'cdn.aliyuncs.com' client = Cdn20180510Client(config) set_cdn_domain_sslcertificate_request = cdn_20180510_models.SetCdnDomainSSLCertificateRequest( + cert_id=cert_id, + cert_name=cert_name, cert_type='cas', domain_name=domain_name, sslprotocol='on' @@ -32,3 +49,73 @@ def set_cdn_domain_ssl_certificate(access_key_id, access_key_secret, domain_name # 复制代码运行请自行打印 API 的返回值 client.set_cdn_domain_sslcertificate_with_options(set_cdn_domain_sslcertificate_request, runtime) + + +def set_cdn_domain_cert( + access_key_id, access_key_secret, + domain, + certificate, private_key): + """ + 先上传,再部署 + :param access_key_id: + :param access_key_secret: + :param domain: + :param certificate: + :param private_key: + :return: + """ + cert_name = uuid_util.get_uuid() + cert_id = aliyun_cas_api.upload_user_certificate( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + cert_name=cert_name, + cert=certificate, + key=private_key + ) + + print('cert_id: ', cert_id) + + set_cdn_domain_ssl_certificate( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + domain_name=domain, + cert_id=cert_id, + cert_name=cert_name + ) + + +def set_cdn_domain_ssl_certificate_v2( + access_key_id, access_key_secret, + domain_name, + certificate, private_key +): + """ + 直接部署到CDN + https://api.aliyun.com/api-tools/sdk/Cdn?spm=api-workbench.api_explorer.0.0.539f3761ceDHDv&version=2018-05-10&language=python-tea&tab=primer-doc + :return: + """ + # 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 + # 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378659.html。 + config = open_api_models.Config( + # 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。, + access_key_id=access_key_id, + # 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。, + access_key_secret=access_key_secret, + ) + + # Endpoint 请参考 https://api.aliyun.com/product/Cdn + config.endpoint = 'cdn.aliyuncs.com' + client = Cdn20180510Client(config) + + set_cdn_domain_sslcertificate_request = cdn_20180510_models.SetCdnDomainSSLCertificateRequest( + domain_name=domain_name, + cert_type='upload', + sslpri=private_key, + sslpub=certificate, + sslprotocol='on' + ) + + runtime = util_models.RuntimeOptions() + + # 复制代码运行请自行打印 API 的返回值 + client.set_cdn_domain_sslcertificate_with_options(set_cdn_domain_sslcertificate_request, runtime) diff --git a/domain_admin/utils/open_api/aliyun_dcdn_api.py b/domain_admin/utils/open_api/aliyun_dcdn_api.py new file mode 100644 index 0000000000..0b854ee4f0 --- /dev/null +++ b/domain_admin/utils/open_api/aliyun_dcdn_api.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +aliyun_dcdn_api.py +""" +# This file is auto-generated, don't edit it. Thanks. + +from alibabacloud_dcdn20180115 import models as dcdn_20180115_models +from alibabacloud_dcdn20180115.client import Client as dcdn20180115Client +from alibabacloud_tea_openapi import models as open_api_models +from alibabacloud_tea_util import models as util_models + + +def set_dcdn_domain_ssl_certificate( + access_key_id, access_key_secret, + domain_name, + certificate, private_key): + """ + https://api.aliyun.com/api/dcdn/2018-01-15/SetDcdnDomainSSLCertificate?spm=api-workbench.API%20Document.0.0.26c93c7bP4PZn9&tab=DOC&lang=PYTHON¶ms={%22DomainName%22:%22www%22,%22SSLProtocol%22:%22on%22,%22SSLPub%22:%22xxx%22,%22SSLPri%22:%22xxx%22} + """ + # 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 + # 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378659.html。 + config = open_api_models.Config( + # 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。, + access_key_id=access_key_id, + # 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。, + access_key_secret=access_key_secret + ) + # Endpoint 请参考 https://api.aliyun.com/product/dcdn + config.endpoint = 'dcdn.aliyuncs.com' + client = dcdn20180115Client(config) + + set_dcdn_domain_sslcertificate_request = dcdn_20180115_models.SetDcdnDomainSSLCertificateRequest( + domain_name=domain_name, + sslprotocol='on', + sslpub=certificate, + sslpri=private_key + ) + runtime = util_models.RuntimeOptions() + + # 复制代码运行请自行打印 API 的返回值 + client.set_dcdn_domain_sslcertificate_with_options(set_dcdn_domain_sslcertificate_request, runtime) diff --git a/domain_admin/utils/uuid_util.py b/domain_admin/utils/uuid_util.py index 2f0131079b..bb133f6478 100644 --- a/domain_admin/utils/uuid_util.py +++ b/domain_admin/utils/uuid_util.py @@ -8,4 +8,12 @@ def get_uuid(): + """ + 返回36位的uuid + :return: eg: 2817cac5-d65f-4fec-8e78-1bdaf55655e8 + """ return str(uuid.uuid4()) + + +if __name__ == '__main__': + print(get_uuid()) diff --git a/requirements/production.txt b/requirements/production.txt index dd62b296a4..aeecdaf09c 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -23,4 +23,5 @@ aliyun-python-sdk-alidns tencentcloud-sdk-python alibabacloud_cdn20180510==4.0.0 alibabacloud_cas20200407==1.4.0 +alibabacloud_dcdn20180115==2.4.0 oss2 \ No newline at end of file diff --git a/tests/utils/test_dns_util.py b/tests/utils/test_dns_util.py new file mode 100644 index 0000000000..6f67c5de55 --- /dev/null +++ b/tests/utils/test_dns_util.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +""" +@File : dns_util_test.py +@Date : 2022-10-22 +@Author : Peng Shiyu +""" +from __future__ import print_function, unicode_literals, absolute_import, division +import socket +import unittest + +from domain_admin.enums.ssl_type_enum import SSLTypeEnum +from domain_admin.utils import cert_util, dns_util +from domain_admin.utils.cert_util import cert_socket_v2, cert_openssl_v2 + + +class DnsUtilTest(unittest.TestCase): + + def test_query_domain_cname(self): + print(dns_util.query_domain_cname('test.tiedankyy.com'))