1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/// Default AWS partition used when no override is configured.
pub const DEFAULT_PARTITION: &str = "aws";
/// Context extracted from an incoming AWS API request.
///
/// Contains the account ID, region, service, and request metadata
/// needed by service handlers to process the request.
#[derive(Debug, Clone)]
pub struct RequestContext {
/// AWS account ID (default: "000000000000" in bypass mode)
pub account_id: String,
/// AWS region (e.g., "us-east-1")
pub region: String,
/// AWS partition: `aws`, `aws-cn`, `aws-us-gov`, `aws-iso(-b)`. Used
/// in every ARN this request emits.
pub partition: String,
/// Service name extracted from the request
pub service: String,
/// Access key ID (if present in Authorization header)
pub access_key: Option<String>,
/// Unique request ID for this API call
pub request_id: String,
/// HTTP method of the original request
pub method: String,
/// URI path of the original request
pub uri: String,
/// Internal event bus - present for requests routed through the gateway;
/// `None` in unit tests or any context where no bus was configured.
pub event_bus: Option<crate::events::EventBus>,
/// Source IP of the caller, if recoverable from `X-Forwarded-For` (or
/// any future axum-side wiring of `ConnectInfo`). Surfaced into
/// `aws:SourceIp` for IAM condition evaluation.
pub source_ip: Option<String>,
/// Whether the original request reached us over TLS, recovered from
/// `X-Forwarded-Proto` when present. Surfaced as `aws:SecureTransport`.
pub is_secure: bool,
/// True when the request originated inside the server (bootstrap
/// setup, background tasks) rather than from an external HTTP call.
/// Used to bypass guardrails that AWS-parity demands of external
/// callers but that the server itself must be able to perform during
/// startup. For example, real AWS forbids any IAM mutation against
/// the root user, but AWSim's first-run setup must be able to
/// CreateUser("root") to provision the account-owner record.
pub internal_bypass: bool,
}
impl Default for RequestContext {
fn default() -> Self {
Self {
account_id: String::new(),
region: String::new(),
partition: DEFAULT_PARTITION.to_string(),
service: String::new(),
access_key: None,
request_id: String::new(),
method: String::new(),
uri: String::new(),
event_bus: None,
source_ip: None,
is_secure: false,
internal_bypass: false,
}
}
}
impl RequestContext {
pub fn new(service: impl Into<String>, region: impl Into<String>) -> Self {
Self {
account_id: "000000000000".to_string(),
region: region.into(),
partition: DEFAULT_PARTITION.to_string(),
service: service.into(),
access_key: None,
request_id: uuid::Uuid::new_v4().to_string(),
method: "POST".to_string(),
uri: "/".to_string(),
event_bus: None,
source_ip: None,
is_secure: false,
internal_bypass: false,
}
}
/// Like [`new`] but with an explicit account id, used by background
/// pollers that fan out across every (account, region) pair.
pub fn new_with_account(
service: impl Into<String>,
region: impl Into<String>,
account_id: impl Into<String>,
) -> Self {
Self {
account_id: account_id.into(),
region: region.into(),
partition: DEFAULT_PARTITION.to_string(),
service: service.into(),
access_key: None,
request_id: uuid::Uuid::new_v4().to_string(),
method: "POST".to_string(),
uri: "/".to_string(),
event_bus: None,
source_ip: None,
is_secure: false,
internal_bypass: false,
}
}
/// Builder variant for server-internal callers (bootstrap setup,
/// background tasks). Identical to [`new_with_account`] except the
/// resulting context has [`internal_bypass`](Self::internal_bypass)
/// set to `true`, so guardrails that would reject the same call
/// coming from an external HTTP client (notably the root-user
/// protection in awsim-iam) will let it through.
pub fn internal(
service: impl Into<String>,
region: impl Into<String>,
account_id: impl Into<String>,
) -> Self {
let mut ctx = Self::new_with_account(service, region, account_id);
ctx.internal_bypass = true;
ctx
}
/// Returns an ARN prefix for this partition, account, and region.
///
/// e.g. `arn:aws:s3:us-east-1:000000000000`.
pub fn arn_prefix(&self, service: &str) -> String {
format!(
"arn:{}:{}:{}:{}",
self.partition, service, self.region, self.account_id
)
}
}