问题
需要给S3访问套一层CDN,AWS的CDN是CloudFront。
解决
主要步骤
- 创建公私钥密钥对
- 创建配置密钥组
- 创建CloudFront分配
- 测试(Java签名URL)
创建公私钥密钥对
生成私钥文件
openssl genrsa -out private_key.pem 2048
使用openssl命令生成私钥文件:private_key.pem
生成公钥文件
openssl rsa -pubout -in private_key.pem -out public_key.pem
通过私钥文件生成公钥文件:public_key.pem
。这个文件需要在AWS平台中进行配置。
AWS平台设置公钥
通过如果页面设置公钥,其中密钥值内容,通过如下命令获得:
cat public_key.pem
生成Java调用的der文件
openssl pkcs8 -topk8 -nocrypt -in private_key.pem -inform PEM -out private_key.der -outform DER
通过私钥文件生成der格式的私钥文件是为了方便Java程序进行开发。
创建配置密钥组
这里就将公钥设置到密钥组了。
创建CloudFront分配
开始创建CloudFront分配页面,继续:
源域名就是选择一个s3桶即可;这里重点主要是【限制存储访问】设置,这个设置主要是让CloudFront创建一个有权限访问对应到s3桶的身份,并将这个身份权限同步到s3的权限中。
这里主要给CloudFront的分配者设置公钥密钥组,主要就是为了使用CloudFront的CDN客户端访问CDN的时候需要使用私钥签名的URL才能正常访问CDN中的文件。
测试(Java签名URL)
Gradle依赖
compile group: 'org.bouncycastle', name:'bcprov-jdk15to18', version:'1.68'
compile group: 'net.java.dev.jets3t', name:'jets3t', version:'0.9.4'
compile group: 'com.amazonaws', name:'aws-java-sdk-s3', version:'1.11.993'
Java
package com.zyl.java;
import com.amazonaws.services.s3.internal.ServiceUtils;
import com.amazonaws.util.IOUtils;
import org.jets3t.service.CloudFrontService;
import org.jets3t.service.CloudFrontServiceException;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Security;
public class Main {
public static void main(String[] args) throws IOException, CloudFrontServiceException {
// Signed URLs for a private distribution
// Note that Java only supports SSL certificates in DER format,
// so you will need to convert your PEM-formatted file to DER format.
// To do this, you can use openssl:
// openssl pkcs8 -topk8 -nocrypt -in origin.pem -inform PEM -out new.der
// -outform DER
// So the encoder works correctly, you should also add the bouncy castle jar
// to your project and then add the provider.
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// CDN地址
String distributionDomain = "xxxxx.cloudfront.net";
// 私钥文件
String privateKeyFilePath = "/Users/zhangyalin/Downloads/private_key.der";
// key
String s3ObjectKey = "Exampl中文.txt";
// 中文URL处理
char[] chars = s3ObjectKey.toCharArray();
StringBuilder stringBuilder = new StringBuilder();
for (char c : chars){
if (Character.isIdeographic(c)){
stringBuilder.append(URLEncoder.encode(String.valueOf(c), StandardCharsets.UTF_8.toString()));
} else {
stringBuilder.append(c);
}
}
s3ObjectKey = stringBuilder.toString();
String policyResourcePath = "https://" + distributionDomain + "/" + s3ObjectKey;
// AWS平台配置的公钥ID
String keyPairId = "xxxxx";
// Convert your DER file into a byte array.
byte[] derPrivateKey = IOUtils.toByteArray(new
FileInputStream(privateKeyFilePath));
// Generate a "canned" signed URL to allow access to a
// specific distribution and file
String signedUrlCanned = CloudFrontService.signUrlCanned(
policyResourcePath, // Resource URL or Path
keyPairId, // Certificate identifier,
// an active trusted signer for the distribution
derPrivateKey, // DER Private key data
ServiceUtils.parseIso8601Date("2021-04-07T14:20:00.000Z") // DateLessThan
);
System.out.println(signedUrlCanned);
// Build a policy document to define custom restrictions for a signed URL.
String policy = CloudFrontService.buildPolicyForSignedUrl(
// Resource path (optional, can include '*' and '?' wildcards)
policyResourcePath,
// DateLessThan
ServiceUtils.parseIso8601Date("2021-11-14T22:20:00.000Z"),
// CIDR IP address restriction (optional, 0.0.0.0/0 means everyone)
"0.0.0.0/0",
// DateGreaterThan (optional)
ServiceUtils.parseIso8601Date("2011-10-16T06:31:56.000Z")
);
// Generate a signed URL using a custom policy document.
String signedUrl = CloudFrontService.signUrl(
// Resource URL or Path
policyResourcePath,
// Certificate identifier, an active trusted signer for the distribution
keyPairId,
// DER Private key data
derPrivateKey,
// Access control policy
policy
);
System.out.println(signedUrl);
}
}
然后控制URL签名的过期日期,运行后,得到两个URL,直接在浏览器打开这个URL即可。