如何从ESP32通过HTTP(S)访问AWS私有S3桶下载固件
解决ESP32从私有S3桶下载固件的问题
一、修复HTTPS连接超时问题
你用WiFiClient连接443端口超时,是因为ESP32需要验证S3的SSL证书才能建立HTTPS连接,普通WiFiClient不支持SSL加密,必须改用WiFiClientSecure并加载AWS根证书:
#include <WiFiClientSecure.h> WiFiClientSecure client; String host = "esp-data-exchange.s3.eu-central-1.amazonaws.com"; int port = 443; String bin = "/firmware.bin"; // 加载Amazon Root CA 1(用于验证S3的SSL证书) const char* aws_root_ca = R"EOF( -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/q IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1 L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+Oy QmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAM CAQYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwU AA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy rqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- )EOF"; void setup() { // 初始化WiFi逻辑... client.setCACert(aws_root_ca); if (client.connect(host.c_str(), port)) { // 后续添加带认证的请求头 } else { Serial.println("HTTPS连接失败"); } }
二、私有S3桶的认证:AWS V4签名
直接无签名的GET请求会返回403,必须生成AWS Signature Version 4签名并添加到请求头。可以用PlatformIO直接安装AWSV4Signature轻量库来简化签名生成:
核心实现步骤
- 准备有权限的AWS IAM用户凭证(Access Key ID和Secret Access Key),该用户需配置
s3:GetObject权限(仅针对目标桶和固件文件)。 - 生成V4签名所需的时间戳、日期、签名算法等参数。
- 将签名添加到
Authorization请求头中。
完整代码示例
#include <WiFiClientSecure.h> #include <AWSV4Signature.h> WiFiClientSecure client; String host = "esp-data-exchange.s3.eu-central-1.amazonaws.com"; String bucket = "esp-data-exchange"; String object_key = "firmware.bin"; String region = "eu-central-1"; // 替换为你的IAM凭证(测试用,正式环境请勿硬编码) String access_key = "YOUR_AWS_ACCESS_KEY"; String secret_key = "YOUR_AWS_SECRET_KEY"; const char* aws_root_ca = "-----BEGIN CERTIFICATE-----...(同上根证书内容)-----END CERTIFICATE-----"; void setup() { Serial.begin(115200); // 连接WiFi逻辑... client.setCACert(aws_root_ca); // 生成V4签名 AWSV4Signature sig(access_key, secret_key, region, "s3"); String date = sig.generateDateTimeString(); String canonical_request = sig.buildCanonicalRequest("GET", "/" + object_key, "", "host:" + host, ""); String string_to_sign = sig.buildStringToSign(date, canonical_request); String signature = sig.calculateSignature(string_to_sign); // 构造认证请求头 String auth_header = "AWS4-HMAC-SHA256 Credential=" + access_key + "/" + sig.getDateString() + "/" + region + "/s3/aws4_request, SignedHeaders=host, Signature=" + signature; if (client.connect(host.c_str(), 443)) { client.print(String("GET /") + object_key + " HTTP/1.1\r\n"); client.print("Host: " + host + "\r\n"); client.print("Authorization: " + auth_header + "\r\n"); client.print("X-Amz-Date: " + date + "\r\n"); client.print("Connection: close\r\n\r\n"); // 读取响应并处理固件更新(可结合Arduino Update库实现OTA) while (client.connected()) { String line = client.readStringUntil('\n'); Serial.println(line); // 解析响应头后,将固件数据写入Update库 } } else { Serial.println("HTTPS连接失败"); } }
三、关键注意事项
- 最小化IAM权限:给IAM用户仅分配目标文件的读取权限,示例策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::esp-data-exchange/firmware.bin" } ] } - 凭证安全:测试环境可临时硬编码凭证,正式环境需改用IoT Core获取临时凭证等安全方案。
- 证书更新:定期检查AWS官方根证书列表,避免证书过期导致连接失败。
- OTA结合:获取固件数据后,可参考你找到的AWS_S3_OTA_Update示例,用Arduino Update库完成固件写入。
内容的提问来源于stack exchange,提问作者Slev1n
相关产品推荐
相关产品推荐

