Drollery Medieval drollery of a knight on a horse

🏆 欢迎来到本站: https://xuchangwei.com/希望这里有你感兴趣的内容

flowery border with man falling
flowery border with man falling

Solutions: 解决方案-通用

httpDNS

背景

用户出口IP和LocalDNS供应商不一致,导致通过local dns解析的cdn域名返回的cdn节点为非就近或相同供应商的节点,进而导致用户访问资源质量下降、甚至不可用。

解决方案

采用httpdns,httpdns能直接获取客户端IP,基于客户端IP获得最精准的解析结果,让客户端更好的接入就近的业务节点。

项目收益

  1. 增加域名解析准确度,防止域名解析劫持。
  2. 降低解析延迟,提高用户体验。
  3. 更多可参见httpdsn优势。 注:目前因无更多数据支持,可简单通过服务上线后,此类客诉问题是否减少来评估项目收益。

httpdns的优势

  1. 绕过了运营商的local dns,可以防止域名劫持。
  2. 使用用户出口的真实IP地址做解析,使解析结果更加精准。
  3. 可做热点域名预热、缓存dns解析结果、解析结果懒更新等方式,有效的降低解析延迟,甚至可达到 0ms 解析延迟。
  4. 绕过了local dns,避免了local dns不遵循权威ttl的问题,可以使修改解析结果更快速的生效。

方案实施原则

  1. 不自行开发httpdns 服务,CDN域名使用CDN厂商的httpdns服务。
  2. 一期 API类域名暂不考虑使用httpdns。【API类域名防止DNS解析也需要使用httpdns,在二期再考虑加入。直接使用阿里云或腾讯云的httpdns服务】
  3. 客户端使用的 httpdns 服务地址:
    1. 客户端必须预置阿里云(或腾讯云)提供的httpdns服务的IP地址【即默认的httpdns api接口】【防止第一跳因dns劫持导致无法访问,从而导致后续的httpdns服务地址无法下发】。
    2. 必须支持httpdns服务地址由服务端下发。

服务端

  1. 需要开发httpdns api 下发接口。
  2. 接口下发粒度为【用户】级别,即自动切换用户的cdn供应商,比如从阿里切到腾讯或网宿等。
  3. 接口支持全部用户切换和批量用户切换cdn供应上。
  4. 待定或二期:支持根据区域切换cdn供应商。
  5. 需要做些IP储备,增加对cdn节点调度的支持,比如下发给用户的httpdns api 接口中包含请求的出口IP,让客户端请求的时候传给httpdns api 来源IP地址,进而对该用户强制调度到此IP的就近节点。

客户端

  1. 预置默认httpdns api接口地址【默认供应商需要确认】
  2. 做正常的业务请求
  3. 异步热点域名预热
  4. 异步请求【httpdns api 下发服务】API 获取新的httpdns api,并做结果缓存,如果下发了新的httpdns api,则使用新httpdns api 进行解析。
  5. httpdns api 接口调用鉴权,防止恶意刷量,导致不必要的成本。 注:① 异步请求的时效性需要再讨论 ② 异步请求避免对齐

具体技术细节和接口

需要客户端和服务端研发协商指定

阿里云HttpDNS

https://help.aliyun.com/product/30100.html?spm=a2c4g.11186623.6.540.6c136e96CHjOh8

注意事项

参考阿里云httpdns最佳实践

  1. HttpDNS降低dns解析开销
  2. HTTPS(含SNI) 业务场景IP直连
  3. HttpDNS场景下cookie使用

更多httpdns最佳实践:https://help.aliyun.com/document_detail/30143.html?spm=a2c4g.11186623.3.2.63be7f15odjGz0

Aliyun DTS基于VPN网关实现阿里云RDS和AWS EC2间的数据同步

官方文档:https://help.aliyun.com/zh/vpn/sub-product-ipsec-vpn/use-cases/dts-implements-data-synchronization-between-alibaba-cloud-rds-and-aws-vpc-based-on-vpn-gateway?spm=a2c4g.11186623.0.0.3a867d783Sfkn6

DTS基于VPN网关实现阿里云RDS和AWS EC2间的数据同步

背景:DTS 阿里云polarDB与AWS RDS双向同步调研

主要操作:阿里云与AWS内网互通,DTS配置,以下是针对文档的操作记录点

阿里云VPC 10.2.0.0/16

AWS VPC 10.0.0.0/16

步骤一:在阿里云创建VPN网关实例

IPsec地址1:8.219.102.177

IPsec地址2:8.222.171.136

步骤二:在AWS平台部署VPN

1.创建客户网关。

您需要在AWS侧创建2个客户网关,将阿里云VPN网关实例的2个IP地址作为客户网关的IP地址。

2.创建虚拟私有网关。

您需要在AWS侧创建虚拟私有网关,并将虚拟私有网关绑定到需要和阿里云互通的VPC实例上。

3.创建站点到站点VPN连接。

为站点到站点VPN连接配置路由时,您除了要指定阿里云VPC网段外,还需要指定100.104.0.0/16网段,DTS服务将使用该网段下的地址同步数据。

2个站点到站点VPN连接的配置,连接不同的客户网关

预共享密钥 12345678

aliyun1隧道状态

Tunnel 1 35.166.53.23 169.254.68.60/30 关联客户网关IPsec地址1

aliyun2隧道状态

Tunnel 1 34.208.190.223 169.254.250.112/30 关联客户网关IPsec地址2

4.配置路由传播。

您需要在虚拟私有网关关联的VPC实例的路由表下开启路由传播,以确保站点到站点VPN连接下的路由可以自动传播到VPC实例的路由表中。

步骤三:在阿里云部署VPN网关

1.创建用户网关。

用户网关1 对应aws站点连接随着tunnel1的外网地址

用户网关2 对应aws站点连接随着tunnel2的外网地址

2.创建IPsec连接。

路由模式:感兴趣流模式

本端网段

VPC网段:10.2.0.0/16

DTS网段:100.104.0.0/16

对端网段aws: 10.0.0.0/16

Tunnel-2:

  • 预共享密钥: 12345678
  • 用户网关: 用户网关1 用户网关2

3.配置VPN网关路由

策略路由表页签,找到目标路由条目,在操作列单击发布

步骤四:测试网络连通性

略。 验证两边可互通即可

步骤五:创建DTS数据同步任务 略

同步方案概览:https://help.aliyun.com/zh/dts/user-guide/data-synchronization-scenarios

DTS:

  • 阿里云PolarDB <–> AWS RDS 双向同步,支持。 注意AWS RDS不要开放外网
  • 阿里云MongoDB <–> AWS DocumentDB 双向同步,不支持。
    • 解决方案:

AWS CluoudFront-使用鉴权-URL

参考

1.使用 OpenSSL 生成长度为 2048 位的 RSA 密钥对

openssl genrsa -out private_key.pem 2048

2.提取公有密钥

openssl rsa -pubout -in private_key.pem -out public_key.pem

3.将公有密钥上传到 CloudFront https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#private-content-creating-cloudfront-key-pairs

4.重新设置私有密钥的格式 java 用

openssl pkcs8 -topk8 -nocrypt -in cloudfront_private_key.pem -inform PEM -out private_key.der -outform DER

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CFPrivateDistJavaDevelopment.html

5.cloudfront 控制台域名设置限制查看器访问,绑定密钥组

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#private-content-reformatting-private-key

6.手动测试

cat << \EOF >policy 
{
    "Statement": [
       {
            "Resource": "https://*",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1721471130
                }
            }
        }
    ]
}
EOF

#生成Policy=策略声明的 Base64 编码版本
cat policy | tr -d "\n" | tr -d " \t\n\r" |openssl base64 -A | tr -- '+=/' '-_~'

#生成Signature=策略声明经过哈希处理和签署后的版本
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'

样例: xx.com/{{ resource }}?Policy={{ policy-base64 }}&Signature={{ signature-base64 }}&Key-Pair-Id={{ keyid }}

https://awsvideo.xxx.online/102484ad37a371efbfff87c7371d0102/1331493f784b468c9edb7e1fdeb725f3-017411445de7b70fecf4b3b951960080-hd.m3u8?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzIxNDcxMTMwfX19XX0_&Signature=OAbMTqCZ9ifwuphR1zvajv9lcZj7MZPehSy-yCMy4nrJ5Nk3rwPNhCHjqUWpFtwq9ECSSidEC46NJHbey9uEr0GATbSTi27Udl4GvjfLe5mzrwELTkG-OooXuqz7CRKLoG9-FLxYEU~RlK6JpoX1p7k~JJf4OJ2ZWnlhM3qZBH1un6HK0qNYb~A1iPoIUXkXvD6bvMATsr6zhex02Sgf9CcOKuOHHp3op-ZJ8H1bPpXLV92KimogJr4g84PjkrOm0bEzMbA1bzYgkUrzSVOulZrGff29I4yr5~dXyguS0x9-SPjV-rgooVT73NS3LZe6mC1fyprLdIpdD73LAww5Mg__&Key-Pair-Id=K2xxxxxx

难点:流式传输视频点播限制,无法自动添加请求资源鉴权

解决方案:

方案1: 利用lambda改写,流量走api gateway https://aws.amazon.com/cn/blogs/networking-and-content-delivery/secure-and-cost-effective-video-streaming-using-cloudfront-signed-urls/

方案2:CDN边缘节点实现(自带lambda js脚本)

https://github.com/aws-samples/amazon-cloudfront-protecting-hls-manifest-with-signed-url?tab=readme-ov-file

注意:模板中nodejs14.x 改为nodejs16.x。 Origin 处改成自己的s3源地址,替换自己的证书信息。如:

...
Parameters:
  Origin:
    Description: Domain name of content origin
    Type: String
    Default: s3-video-storage-test.s3.us-west-2.amazonaws.com
...
      Runtime: nodejs16.x
...
                let duration = 900; //ts文件鉴权过期时间
...
    let policy = JSON.stringify({
        Statement: [{
            //Resource: 'http*://'+ domain+path.posix.join(dir,file), 如果有备用域名,修改此处
            Resource: 'http*://awsvideo.cici.online'+ path.posix.join(dir,file),
            Condition: {
...
      Runtime: nodejs16.x

测试环境-java代码对应信息

...
        String resourceUrl = "https://d2xxxxu.cloudfront.net";
        String keyPairId = "K9xxxxxV";
...
                .privateKey(new java.io.File("/path/to/private_key.der").toPath())
...

python测试脚本

import datetime

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from botocore.signers import CloudFrontSigner


def rsa_signer(message):
    with open('CF-priv-key.pem', 'rb') as key_file:
        private_key = serialization.load_pem_private_key(
            key_file.read(),
            password=None,
            backend=default_backend()
        )
    return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())

key_id = 'K94AXT0F34G8V'
#url = 'https://dlshqm8hlv94m.cloudfront.net/test2.m3u8'
url = 'https://awsvideo.cici.com/4031f27659f871ef997b5114c1ca0102/1289b553c5e64038bef3a2e91f8acd48-009825ad620ebb8a5131ed4c04115d4c-ld.m3u8'
expire_date = datetime.datetime(2054, 10, 20)

cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

# Create a signed url that will be valid until the specific expiry date
# provided using a canned policy.
signed_url = cloudfront_signer.generate_presigned_url(
    url, date_less_than=expire_date)
print(signed_url)