generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 266
Closed
Description
Update.
I have been reading docs, and "chatting" with the AI gods. The program example is now closer to compiling. I use the EXACT same function as specified by Aaron above. That code is fine, it's just that there are still no examples of how to use that to build an actual functional S3 client. Note the following version that reports two errors from "cargo build". I will also attach my Cargo.toml file.
Cargo.toml:
[package]
name = "s3_custom"
version = "0.1.0"
edition = "2024"
[dependencies]
tokio = { version = "1.0", features = ["full"] }
aws-sdk-s3 = "1.82.0"
aws-smithy-client = "0.60.3"
clap = "4.5.36"
rustls = "0.23.26"
rustls-pemfile = "2.2.0"
hyper-rustls = "0.27.5"
tokio-rustls = "0.26.2"
aws-smithy-http-client = { version = "1.0.1", features = ["rustls-aws-lc"] }
Rust main.rs:
// src/main.rs
//
// This is intended to be a standalone, "simple" program that can demonstrate
// loading a custom certificate, and then performing a bucket list of an
// S3 provider, that uses a self signed certificate.
//
// This is close to the minimal set of code required to produce a usable
// example. Currently it does not compile because of a lack of documentation
// and / or examples.
//
// Note: this is getting close, but still has two cargo build errors.
// 1) The first on line 113: .rustls_connector(tls_context)
// 2) The second on line 119: .endpoint_resolver(Endpoint::immutable
//
use aws_sdk_s3::{Client, Config};
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::config::endpoint::Endpoint;
use aws_smithy_http_client::{
tls::{self},
Builder,
};
use clap::{Arg, Command};
use std::env;
use std::fs;
/// Function to create a TLS context from a PEM file (exactly as specified in the documentation).
fn tls_context_from_pem(filename: &str) -> tls::TlsContext {
let pem_contents = fs::read(filename).unwrap();
// Create a new empty trust store (this will not load platform native certificates)
let trust_store = tls::TrustStore::empty()
.with_pem_certificate(pem_contents.as_slice());
tls::TlsContext::builder()
.with_trust_store(trust_store)
.build()
.expect("valid TLS config")
}
/// Lists objects in the specified S3 bucket.
async fn list_bucket_objects(client: &Client, bucket: &str) {
match client.list_objects_v2().bucket(bucket).send().await {
Ok(output) => {
if let Some(contents) = output.contents {
println!("Objects in bucket '{}':", bucket);
for object in contents {
if let Some(key) = object.key {
println!("- {}", key);
}
}
} else {
println!("No objects found in bucket '{}'.", bucket);
}
}
Err(err) => {
eprintln!("Error listing objects in bucket '{}': {:?}", bucket, err);
}
}
}
#[tokio::main]
async fn main() {
// Command-line argument parsing using Clap
let matches = Command::new("S3 Client with Custom TLS")
.arg(
Arg::new("bucket")
.short('b')
.long("bucket")
.value_parser(clap::value_parser!(String))
.required(true)
.help("The S3 bucket to list objects from"),
)
.arg(
Arg::new("endpoint")
.short('e')
.long("endpoint")
.value_parser(clap::value_parser!(String))
.help("The custom S3 endpoint (e.g., http://localhost:9000)"),
)
.arg(
Arg::new("cert")
.short('c')
.long("cert")
.value_parser(clap::value_parser!(String))
.required(true)
.help("Path to the custom CA certificate file"),
)
.get_matches();
// Parse command-line arguments
let bucket = matches
.get_one::<String>("bucket")
.expect("Bucket name is required");
let endpoint = matches
.get_one::<String>("endpoint")
.cloned()
.unwrap_or_else(|| env::var("S3_ENDPOINT").unwrap_or_else(|_| "http://localhost:9000".to_string()));
let cert_path = matches
.get_one::<String>("cert")
.expect("Certificate path is required");
// Load AWS credentials from environment variables
let aws_access_key_id = env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID must be set");
let aws_secret_access_key =
env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY must be set");
// Create the TLS context using the custom CA certificate
let tls_context = tls_context_from_pem(cert_path);
// Create an AWS Smithy HTTP client builder and configure it
let smithy_client = Builder::new()
.rustls_connector(tls_context) // Reference: https://docs.rs/aws-smithy-http/0.53.0/aws_smithy_http/client/struct.Builder.html#method.rustls_connector
.build();
// Build the AWS SDK configuration
let aws_config = Config::builder()
.region(Region::new("us-east-1"))
.endpoint_resolver(Endpoint::immutable(endpoint.parse().expect("Invalid endpoint URL"))) // Reference: https://docs.rs/aws-sdk-s3/1.82.0/aws_sdk_s3/config/endpoint/trait.ResolveEndpoint.html
.credentials_provider(Credentials::new(
aws_access_key_id,
aws_secret_access_key,
None,
None,
"custom",
))
.build();
// Create the S3 client using the custom HTTP connector
let s3_client = Client::from_conf(aws_config);
// List objects in the specified bucket
list_bucket_objects(&s3_client, bucket).await;
}
Originally posted by @russfellows in #1277 (comment)
Metadata
Metadata
Assignees
Labels
No labels