Expand description
§aws-sdk-cloudfront-url-signer
A library for generating signed URLs and cookies for Amazon CloudFront private content.
This crate provides utilities to create cryptographically signed URLs and cookies that grant time-limited access to private CloudFront distributions. It supports both RSA-SHA1 and ECDSA-SHA1 signing algorithms with canned (simple) and custom (advanced) policies.
§Key Features
- Signed URLs: Generate URLs with embedded signatures for single-resource access
- Signed Cookies: Generate cookies for multi-resource access without URL modification
- Canned Policies: Simple time-based expiration
- Custom Policies: Advanced access control with activation dates, IP restrictions, and wildcards
- Multiple Key Formats: RSA (PKCS#1/PKCS#8) and ECDSA P-256 (PKCS#8) private keys
§When to Use Signed URLs vs Cookies
Use signed URLs when:
- Restricting access to individual files (e.g., a download link)
- Users are accessing content through a client that doesn’t support cookies
- You want to share a link that works without additional setup
Use signed cookies when:
- Providing access to multiple restricted files (e.g., all files in a subscriber area)
- You don’t want to change your existing URLs
- You’re building a web application where cookies are naturally handled
§Feature Flags
| Feature | Description |
|---|---|
rt-tokio | Enables async file loading with PrivateKey::from_pem_file() |
http-1x | Enables conversion to http::Request types |
§CloudFront Setup
Before using this library, you need to:
- Create a CloudFront key pair in the AWS Console or via CLI
- Upload the public key to CloudFront
- Create a key group containing your public key
- Configure your CloudFront distribution to use the key group for restricted content
- Keep the private key secure for use with this library
See the CloudFront Developer Guide for detailed setup instructions.
§Basic Usage
§Signing a URL with Canned Policy
Canned policies provide simple time-based access control with just an expiration time:
use aws_sdk_cloudfront_url_signer::{sign_url, SigningRequest, PrivateKey};
use aws_smithy_types::DateTime;
// Load your CloudFront private key
let private_key = PrivateKey::from_pem(include_bytes!("private_key.pem"))?;
// Create a signing request
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/image.jpg")
.key_pair_id("APKAEIBAERJR2EXAMPLE")
.private_key(private_key)
.expires_at(DateTime::from_secs(1767290400)) // Absolute expiration
.build()?;
// Generate the signed URL
let signed_url = sign_url(request)?;
println!("Signed URL: {}", signed_url);The resulting URL will include Expires, Signature, and Key-Pair-Id query parameters.
§Using Relative Expiration
Instead of an absolute timestamp, you can specify a duration from now:
use std::time::Duration;
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/video.mp4")
.key_pair_id("APKAEIBAERJR2EXAMPLE")
.private_key(private_key)
.expires_in(Duration::from_secs(3600)) // Valid for 1 hour
.build()?;§Signing a URL with Custom Policy
Custom policies enable advanced access control with activation dates, IP restrictions, and wildcard patterns:
use aws_sdk_cloudfront_url_signer::{sign_url, SigningRequest, PrivateKey};
use aws_smithy_types::DateTime;
let private_key = PrivateKey::from_pem(include_bytes!("private_key.pem"))?;
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/videos/*")
.key_pair_id("APKAEIBAERJR2EXAMPLE")
.private_key(private_key)
.expires_at(DateTime::from_secs(1767290400))
.active_at(DateTime::from_secs(1767200000)) // Not valid before this time
.ip_range("192.0.2.0/24") // Restrict to IP range
.build()?;
let signed_url = sign_url(request)?;Custom policy URLs include a Policy parameter (base64-encoded JSON) instead of Expires.
§Generating Signed Cookies
Signed cookies work similarly but return cookie name-value pairs:
use aws_sdk_cloudfront_url_signer::{sign_cookies, SigningRequest, PrivateKey};
use aws_smithy_types::DateTime;
let private_key = PrivateKey::from_pem(include_bytes!("private_key.pem"))?;
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/*")
.key_pair_id("APKAEIBAERJR2EXAMPLE")
.private_key(private_key)
.expires_at(DateTime::from_secs(1767290400))
.build()?;
let cookies = sign_cookies(request)?;
// Set cookies in your HTTP response
for (name, value) in cookies.iter() {
println!("Set-Cookie: {}={}; Domain=d111111abcdef8.cloudfront.net; Secure; HttpOnly", name, value);
}For canned policies, cookies include:
CloudFront-ExpiresCloudFront-SignatureCloudFront-Key-Pair-Id
For custom policies, cookies include:
CloudFront-PolicyCloudFront-SignatureCloudFront-Key-Pair-Id
§Private Key Loading
§From PEM Bytes
Load a key from bytes (useful when loading from AWS Secrets Manager or environment variables):
use aws_sdk_cloudfront_url_signer::PrivateKey;
// From a byte slice
let key = PrivateKey::from_pem(include_bytes!("private_key.pem"))?;
// From a string
let pem_string = std::fs::read_to_string("private_key.pem")?;
let key = PrivateKey::from_pem(pem_string.as_bytes())?;§From File (Async)
With the rt-tokio feature enabled, you can load keys directly from files:
use aws_sdk_cloudfront_url_signer::PrivateKey;
let key = PrivateKey::from_pem_file("private_key.pem").await?;§Supported Key Formats
| Format | Header | Key Type |
|---|---|---|
| PKCS#1 | -----BEGIN RSA PRIVATE KEY----- | RSA only |
| PKCS#8 | -----BEGIN PRIVATE KEY----- | RSA or ECDSA P-256 |
Both RSA and ECDSA keys use SHA-1 signatures (required by CloudFront).
§Policy Types
§Canned Policy
A canned policy is automatically used when you only specify an expiration time. It’s simpler and produces shorter URLs:
let request = SigningRequest::builder()
.resource_url("https://example.cloudfront.net/file.pdf")
.key_pair_id("APKAEXAMPLE")
.private_key(key)
.expires_at(DateTime::from_secs(1767290400))
.build()?;§Custom Policy
A custom policy is used when you specify any of:
resource_pattern()- Wildcard pattern for the policy (different from the signed URL)active_at()- URL becomes valid at this time (not-before)ip_range()- Restrict access to an IPv4 CIDR range
let request = SigningRequest::builder()
.resource_url("https://example.cloudfront.net/premium/video.mp4")
.key_pair_id("APKAEXAMPLE")
.private_key(key)
.expires_at(DateTime::from_secs(1767290400))
.active_at(DateTime::from_secs(1767200000)) // Triggers custom policy
.ip_range("10.0.0.0/8") // Also triggers custom policy
.build()?;§Wildcard Patterns
Custom policies support wildcards in the resource pattern. Use resource_pattern() to specify
a wildcard pattern that grants access to multiple resources, while resource_url() specifies
the actual URL being signed:
*matches zero or more characters?matches exactly one character
// Sign a specific URL but grant access to all files under /videos/
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/videos/intro.mp4")
.resource_pattern("https://d111111abcdef8.cloudfront.net/videos/*")
.key_pair_id("APKAEXAMPLE")
.private_key(key)
.expires_at(DateTime::from_secs(1767290400))
.build()?;
// The signed URL points to intro.mp4, but the policy grants access to all /videos/*Common wildcard patterns:
https://example.cloudfront.net/videos/*- All files under /videos/https://example.cloudfront.net/*.mp4- All .mp4 fileshttps://example.cloudfront.net/video-?.mp4- video-1.mp4, video-2.mp4, etc.*- All resources (use with caution)
§Using Signed URLs with HTTP Clients
The SignedUrl type provides multiple ways to access the signed URL for use with HTTP clients:
let signed_url = sign_url(request)?;
// As a string slice
let url_str: &str = signed_url.as_str();
// As a parsed url::Url
let url: &url::Url = signed_url.as_url();
// Convert to owned url::Url
let url: url::Url = signed_url.into_url();
// Use with reqwest (reqwest re-exports url::Url)
let response = reqwest::get(signed_url.as_url()).await?;
// Display trait
println!("Signed URL: {}", signed_url);§HTTP 1.x Integration
With the http-1x feature enabled, you can convert signed URLs directly to http::Request:
use http::Request;
let signed_url = sign_url(request)?;
// Convert to http::Request
let http_request: Request<()> = signed_url.try_into()?;
// Or from a reference
let http_request: Request<()> = (&signed_url).try_into()?;This is useful when working with HTTP clients that use the http crate types.
§Error Handling
All operations return Result<T, SigningError>:
use aws_sdk_cloudfront_url_signer::{sign_url, SigningRequest, PrivateKey, error::SigningError};
let result = sign_url(request);
match result {
Ok(signed_url) => println!("Success: {}", signed_url),
Err(e) => {
eprintln!("Signing failed: {}", e);
if let Some(source) = e.source() {
eprintln!("Caused by: {}", source);
}
}
}Common error scenarios:
- Invalid private key format
- Missing required fields (resource_url, key_pair_id, private_key, expiration)
- Cryptographic signing failures
§URLs with Existing Query Parameters
The library correctly handles URLs that already have query parameters:
let request = SigningRequest::builder()
.resource_url("https://d111111abcdef8.cloudfront.net/video.mp4?quality=hd")
.key_pair_id("APKAEXAMPLE")
.private_key(key)
.expires_at(DateTime::from_secs(1767290400))
.build()?;
let signed_url = sign_url(request)?;
// Result: https://...?quality=hd&Expires=...&Signature=...&Key-Pair-Id=...This crate is part of the AWS SDK for Rust and the smithy-rs code generator.
Modules§
- error
- Error types for CloudFront signing operations.
Structs§
- Signed
Cookies - Signed cookies for CloudFront.
- Signed
Url - A signed CloudFront URL.
- Signing
Request - Request to sign a CloudFront URL or generate signed cookies.
- Signing
Request Builder - Builder for
SigningRequest.
Enums§
- Private
Key - Private key for signing CloudFront URLs and cookies.
Functions§
- sign_
cookies - Generate signed cookies with canned or custom policy
- sign_
url - Sign a CloudFront URL with canned or custom policy