Trong bài viết trước, mình đã chuẩn bị vài hàm tạo key cơ bản cho việc request SSL, trong bài viết này, mình sẽ xây dựng vài hàm cơ bản để tương tác với Aliababa Cloud DNS, CAS, trỏ domain và tự động hóa quá trình xác thực DNS mà Let's Encrypt yêu cầu. Cuối cùng là hàm request một SSL certificate hoàn chỉnh và upload lên Alibaba Certificate Management Service.
Để sử dụng các chức năng như mô tả, domain được sử dụng phải được thiết lập trên Alibaba Cloud DNS service (nameserver nằm ở Alibaba Cloud).
DCDN của Alibaba Cloud có thể sử dụng với second-level domain, nhưng để xác thực domain lúc triển khai cần phải xác thực trên first-level domain. Vậy nên các tên miền có đuôi như .id.vn, .name.vn sẽ không thể sử dụng DCDN. Do user không sở hữu first-level domain là id.vn
def addDnsRecord(AccessKey, SecretKey, PrimaryDomain,Type,RR, Value): # RR is hostname
config = open_api_models.Config(
access_key_id=AccessKey,
access_key_secret=SecretKey,
region_id="ap-southeast-1"
)
config.endpoint="alidns.ap-southeast-1.aliyuncs.com"
#[product_code].[region_id].aliyuncs.com
dns_client=AlidnsClient(config)
add_domain_record_request = alidns_models.AddDomainRecordRequest(
domain_name=PrimaryDomain,
rr=RR, #host
type=Type,
value=Value,
)
try:
repons = dns_client.add_domain_record_with_options(add_domain_record_request, util_models.RuntimeOptions())
return repons
except Exception as error:
print(error)
def main():
print("===========START-MAIN==============")
AccessKey='XXXXXXXX'
SecretKey='XXXXXXXXXXXXXXXXXXX'
res=addDnsRecord(AccessKey,SecretKey,'vinahost.cloud','A','blog','146.196.65.3')
print(res)
main()
Các bước để tạo chứng chỉ SSL được khái quát theo flow sau:
def GenSSLCert(acme_client,domainName,emailAddress,accessKey, secretKey):
KEY_FILE = domainName + '.key' #Binary File
CSR_FILE = domainName + '.csr'
CERT_FILE= domainName + '.cert' #Full Chain.pem
print("Create SSL Free For Domain:",domainName,"with email:",emailAddress)
pkey, csr= genCSR(domainName,emailAddress)
orderr = acme_client.new_order(csr.public_bytes(serialization.Encoding.PEM))
authz_list = orderr.authorizations
for authz in authz_list:
# Choosing challenge.
# authz.body.challenges is a set of ChallengeBody objects.
for item in authz.body.challenges:
if isinstance(item.chall, challenges.DNS01):
r_authz = authz
dns_challenge = item
dns_txt_value=dns_challenge.validation(acme_client.net.key)
if domainName != r_authz.body.identifier.value:
print("Domain Request Error:",r_authz.body.identifier.value)
continue
parts=r_authz.body.identifier.value.split('.')
RR = '.'.join(parts[:-2])
primary_domain='.'.join(parts[-2:])
if(len(parts)>2):
DnsRecord ={
'Name': f"_acme-challenge.{RR}",
'Type': 'TXT',
'TTL': 300,
'ResourceRecords': [{'Value': '"{}"'.format(dns_txt_value)}],
'Domain':f"{primary_domain}"
}
else:
DnsRecord ={
'Name': "_acme-challenge",
'Type': 'TXT',
'TTL': 300,
'ResourceRecords': [{'Value': '"{}"'.format(dns_txt_value)}],
'Domain':f"{primary_domain}"
}
print("Dns Challenge:", DnsRecord)
result=addDnsRecord(accessKey,secretKey,DnsRecord['Domain'],"TXT",DnsRecord['Name'],DnsRecord['ResourceRecords'][0]['Value'])
print("AddDnsRecord Result",result)
print("Check DNS: ",DnsRecord['Name']+DnsRecord['Domain'],"TXT",DnsRecord['ResourceRecords'][0]['Value'])
sleep(30)
try:
acme_client.answer_challenge(dns_challenge, dns_challenge.response(acme_client.net.key))
rauthz = acme_client.poll(r_authz)
print('Authorization status: %s', rauthz[0].body.status)
order = acme_client.poll_and_finalize(orderr)
cert = order.fullchain_pem
with open(CERT_FILE, "wt") as f:
f.write(cert)
print("Cert Private filepath: ",KEY_FILE,", Fullchain cert filepath: ",CERT_FILE)
return cert
except acme_errors.ValidationError:
print("Validation failed. Please check your DNS record")
return 0
def main():
print("===========START-MAIN==============")
AccessKey='XXXX'
SecretKey='XXXXXX'
genAccoutKey()
acme_client=getACMEAccount('temp@gmail.com',True)
GenSSLCert(acme_client,'vinahost.cloud','tempx@gmail.com',AccessKey,SecretKey)
main()
def LoadPrivateKeyAsText(fileName):
with open(fileName, "rb") as keyfile:
key_data=keyfile.read()
pkey=serialization.load_pem_private_key(key_data,None)
pem = pkey.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
keystring = b''.join([kp + bytes("\n",encoding='utf-8') for kp in pem.splitlines()])
private_key_text= str((keystring)[:-1], encoding='utf-8')
return private_key_text
def SplitFullChainPem(fullchain_data):
split_full_chain=fullchain_data.split('\n\n')
cert_pem=split_full_chain[0]
chain_pem=split_full_chain[1]
return cert_pem,chain_pem
def UploadUserCertToCAS(AccessKey,SecretKey,CertPem,PrivatePem,CACertPem,DomainName):
# Endpoint: https://api.alibabacloud.com/product/cas.
# Enpoint: <product iD><region><aliyuncs.com> , exam: cas.ap-southeast-1.aliyuncs.com (Outside China Mainland)
config = open_api_models.Config(
access_key_id=AccessKey,
access_key_secret=SecretKey,
region_id="ap-southeast-1"
)
config.endpoint = f'cas.ap-southeast-1.aliyuncs.com'
cas_client = casClient(config)
key_data=PrivatePem
cert_data=CertPem
ca_data=CACertPem
upload_cert_request = cas_20200407_models.UploadUserCertificateRequest(
cert=cert_data,
key=key_data,
sign_cert=ca_data,
name=DomainName,
)
try:
response= cas_client.upload_user_certificate_with_options(upload_cert_request, util_models.RuntimeOptions())
print("Upload Cert to Alibaba Cloud Certificate Management Service Success")
with open("CERT_ID_MAP.txt","a") as f:
cert_id_record=DomainName +" " + str(response.body.cert_id) + "\n"
f.write(cert_id_record)
print(response.body.cert_id)
return response.body.cert_id
except Exception as error:
print(error)
def main():
print("===========START-MAIN==============")
AccessKey='XXXXXX'
SecretKey='XXXXXXXXXXXXXXXXXXXXXx'
domainName='vinahost.cloud'
with open('vinahost.cloud.cert', "rt") as f:
cert_file=f.read()
cert_pem,ca_pem=SplitFullChainPem(cert_file)
pri_pem=LoadPrivateKeyAsText('vinahost.cloud.key')
cert_id=UploadUserCertToCAS(AccessKey,SecretKey,cert_pem,pri_pem,ca_pem,domainName)
main()
Các gói cần cài đặt:
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_alidns20150109.client import Client as AlidnsClient
from alibabacloud_alidns20150109 import models as alidns_models
from alibabacloud_tea_util import models as util_models
from time import sleep
from alibabacloud_cas20200407.client import Client as casClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_cas20200407 import models as cas_20200407_models
Tự động triển khai DCDN bằng Python SDK với Free SSL từ Let's encrypt (Phần 1)
Tự động triển khai DCDN bằng Python SDK với Free SSL từ Let's encrypt (Phần 3)
5 posts | 1 followers
FollowNguyen Phuc Khang - June 4, 2024
Nguyen Phuc Khang - June 4, 2024
Regional Content Hub - August 29, 2024
Regional Content Hub - August 29, 2024
Regional Content Hub - August 29, 2024
Nguyen Phuc Khang - July 13, 2024
5 posts | 1 followers
FollowA scalable and high-performance content delivery service for accelerated distribution of content to users across the globe
Learn MoreOpenAPI Explorer allows you to call an API through its web interface or WebCLI, and view the entire process.
Learn MoreAPI Gateway provides you with high-performance and high-availability API hosting services to deploy and release your APIs on Alibaba Cloud products.
Learn MoreSave egress traffic cost. Eliminate all complexity in managing storage cost.
Learn More