Expand description
AWS API request signatures verification routines.
The scratchstack_aws_signature
crate provides
AWS SigV4
validation routines. This is not the library you want if you just want to call AWS services
or other services that use AWS SigV4 signatures. Rusoto
already has a library, rusoto_signature, that provides
this functionality.
If you are attempting to perform AWS SigV4 verification using AWS-vended credentials, this library also will not work for you. You need the caller’s secret key (or a derivative), and AWS does not allow this for obvious reasons. Instead, you should be using API Gateway with IAM authentication.
On the other hand, if you have your own ecosystem of AWS-like credentials and are developing mock-AWS services or other services that need to use AWS SigV4, this might be the right crate for you.
Users migrating from version 0.10 to 0.11 should consult the migration guide.
§Feature flags
This crate has one feature flag:
unstable
: Allows access to unstable APIs (structs, traits, functions) such ascanonical::normalize_uri_path_component
. These APIs are not needed for normal use of this crate; they are provided for others exploring AWS SigV4 internals.
§Workflow
This assumes you have a complete HTTP request (headers and body) already. As a result, you may not be able to implement this as a middleware layer for a web server—those typically only provide the headers. Having the body is required for almost all modes of AWS SigV4.
The typical workflow is:
- Convert an HTTP
Request
object into a scratchstackRequest
object. - Create a
GetSigningKeyRequest
from thisRequest
. - Call your service to obtain the principal and signing key for this request.
- Verify the request using
sigv4_verify
orsigv4_verify_at
.
§Example
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use http::Request;
use scratchstack_aws_principal::{Principal, User};
use scratchstack_aws_signature::{
service_for_signing_key_fn, sigv4_validate_request, GetSigningKeyRequest,
GetSigningKeyResponse, KSecretKey, SignatureOptions, NO_ADDITIONAL_SIGNED_HEADERS,
};
use std::str::FromStr;
use tower::{BoxError, Service};
const ACCESS_KEY: &str = "AKIAIOSFODNN7EXAMPLE";
const SECRET_KEY: &str = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
const ACCOUNT_ID: &str = "123456789012";
const PARTITION: &str = "aws";
const PATH: &str = "/engineering/";
const REGION: &str = "us-east-1";
const SERVICE: &str = "example";
const USER_NAME: &str = "user";
const USER_ID: &str = "AIDAQXZEAEXAMPLEUSER";
// The date for which the signature calculation was made.
#[allow(deprecated)]
const TEST_TIMESTAMP: DateTime<Utc> = DateTime::<Utc>::from_naive_utc_and_offset(
NaiveDateTime::new(
NaiveDate::from_ymd(2021, 1, 1),
NaiveTime::from_hms(0, 0, 0)),
Utc
);
// This is a mock function that returns a static secret key converted into the requested type
// of signing key. For actual use, you would call out to a database or other service to obtain
// a signing key.
async fn get_signing_key(
request: GetSigningKeyRequest)
-> Result<GetSigningKeyResponse, BoxError> {
assert_eq!(request.access_key(), ACCESS_KEY);
assert_eq!(request.region(), REGION);
assert_eq!(request.service(), SERVICE);
let user = User::new(PARTITION, ACCOUNT_ID, PATH, USER_NAME)?;
let secret_key = KSecretKey::from_str(SECRET_KEY).unwrap();
let signing_key = secret_key.to_ksigning(request.request_date(), REGION, SERVICE);
Ok(GetSigningKeyResponse::builder()
.principal(user)
.signing_key(signing_key)
.build()?)
}
// Wrap `get_signing_key` in a `tower::Service`.
let mut get_signing_key_service = service_for_signing_key_fn(get_signing_key);
// Normally this would come from your web framework.
let req = Request::get("https://example.com")
.header("Host", "example.com")
.header("X-Amz-Date", "20210101T000000Z")
.header("Authorization", "AWS4-HMAC-SHA256 \
Credential=AKIAIOSFODNN7EXAMPLE/20210101/us-east-1/example/aws4_request, \
SignedHeaders=host;x-amz-date, \
Signature=3ea4679d2ecf5a8293e1fb10298c82988f024a2e937e9b37876b34bb119da0bc")
.body(())
.unwrap();
// The headers that _must_ be signed (beyond the default SigV4 headers) for this service.
// In this case, we're not requiring any additional headers.
let signed_headers = NO_ADDITIONAL_SIGNED_HEADERS;
// Signature options for the request. Defaults are typically used, except for S3.
let signature_options = SignatureOptions::default();
// Validate the request.
let (parts, body, auth) = sigv4_validate_request(
req, ®ION, &SERVICE, &mut get_signing_key_service, TEST_TIMESTAMP, &signed_headers,
signature_options).await.unwrap();
// The principal we expect to be associated with the request.
let expected_principal: Principal = User::new(PARTITION, ACCOUNT_ID, PATH, USER_NAME)
.unwrap()
.into();
assert_eq!(auth.principal(), &expected_principal);
Re-exports§
pub use scratchstack_errors as errors;
pub use scratchstack_aws_principal as principal;
Modules§
- auth
- AWS API request signatures verification routines.
- canonical
- Canonicalization functionality for signature generation and validation.
- migration
- Migrating from 0.10 to 0.11
Structs§
- GetSigning
KeyRequest - A request for a signing key of a given kind for the specified request.
- GetSigning
KeyRequest Builder - Builder for
GetSigningKeyRequest
. - GetSigning
KeyResponse - A response from the signing key provider.
- GetSigning
KeyResponse Builder - Builder for
GetSigningKeyResponse
. - KDate
Key - The
kDate
key:HMAC_SHA256("AWS4" + KSecretKey, "YYYYMMDD")
- KRegion
Key - The
kRegion
key: an AWSkDate
key, HMAC-SHA256 hashed with the region. - KSecret
Key - A raw AWS secret key (
kSecret
). - KService
Key - The
kService
key: an AWSkRegion
key, HMAC-SHA256 hashed with the service. - KSigning
Key - The
kSigning
key: an AWSkService
key, HMAC-SHA256 hashed with the “aws4_request” string. - KeyToo
Long Error - Error returned by
KSecretKey::from_str
when the secret key cannot fit in the expected size. - Signature
Options - Options that can be used to configure the signature service.
- Slice
Signed Header Requirements - Static implementation of SignedHeaderRequirements that uses slices of string slices.
- VecSigned
Header Requirements SignedHeaderRequirements
that can be dynamically changed.
Enums§
- GetSigning
KeyRequest Builder Error - Error type for GetSigningKeyRequestBuilder
- GetSigning
KeyResponse Builder Error - Error type for GetSigningKeyResponseBuilder
- Signature
Error - Error returned when an attempt at validating an AWS SigV4 signature fails.
Constants§
- NO_
ADDITIONAL_ SIGNED_ HEADERS - Constant
SignedHeaderRequirements
value to use when no additional signed headers are required.
Traits§
- Into
Request Bytes - A trait for converting various body types into a
Bytes
object. - Signed
Header Requirements - Trait for informing validation routines indicating which headers must be signed in addition to the standard AWS SigV4 headers.
Functions§
- service_
for_ signing_ key_ fn - Create a Service that wraps a function that can produce a signing key.
- sigv4_
validate_ request - Validate an AWS SigV4 request.
Type Aliases§
- Const
Signed Header Requirements - SignedHeaderRequirements from constant slices.