1pub mod authz;
2mod error;
3mod executor;
4mod operations;
5pub mod state;
6mod util;
7
8pub use authz::LambdaResourcePolicyLookup;
9
10use std::sync::Arc;
11
12use async_trait::async_trait;
13use awsim_core::{
14 AccountRegionStore, AwsError, Protocol, RequestContext, RouteDefinition, ServiceHandler,
15};
16use serde_json::Value;
17use tracing::debug;
18
19use state::LambdaState;
20
21pub struct LambdaService {
22 store: AccountRegionStore<LambdaState>,
23}
24
25impl LambdaService {
26 pub fn new() -> Self {
27 Self {
28 store: AccountRegionStore::new(),
29 }
30 }
31
32 fn get_state(&self, ctx: &RequestContext) -> Arc<LambdaState> {
33 self.store.get(&ctx.account_id, &ctx.region)
34 }
35
36 pub fn store(&self) -> AccountRegionStore<LambdaState> {
37 self.store.clone()
38 }
39}
40
41impl Default for LambdaService {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47#[async_trait]
48impl ServiceHandler for LambdaService {
49 fn service_name(&self) -> &str {
50 "lambda"
51 }
52
53 fn signing_name(&self) -> &str {
54 "lambda"
55 }
56
57 fn protocol(&self) -> Protocol {
58 Protocol::RestJson1
59 }
60
61 fn routes(&self) -> Vec<RouteDefinition> {
62 vec![
63 RouteDefinition {
65 method: "POST",
66 path_pattern: "/2015-03-31/functions",
67 operation: "CreateFunction",
68 required_query_param: None,
69 },
70 RouteDefinition {
71 method: "GET",
72 path_pattern: "/2015-03-31/functions",
73 operation: "ListFunctions",
74 required_query_param: None,
75 },
76 RouteDefinition {
77 method: "GET",
78 path_pattern: "/2015-03-31/functions/{FunctionName}",
79 operation: "GetFunction",
80 required_query_param: None,
81 },
82 RouteDefinition {
83 method: "DELETE",
84 path_pattern: "/2015-03-31/functions/{FunctionName}",
85 operation: "DeleteFunction",
86 required_query_param: None,
87 },
88 RouteDefinition {
89 method: "GET",
90 path_pattern: "/2015-03-31/functions/{FunctionName}/configuration",
91 operation: "GetFunctionConfiguration",
92 required_query_param: None,
93 },
94 RouteDefinition {
95 method: "PUT",
96 path_pattern: "/2015-03-31/functions/{FunctionName}/code",
97 operation: "UpdateFunctionCode",
98 required_query_param: None,
99 },
100 RouteDefinition {
101 method: "PUT",
102 path_pattern: "/2015-03-31/functions/{FunctionName}/configuration",
103 operation: "UpdateFunctionConfiguration",
104 required_query_param: None,
105 },
106 RouteDefinition {
107 method: "POST",
108 path_pattern: "/2015-03-31/functions/{FunctionName}/invocations",
109 operation: "Invoke",
110 required_query_param: None,
111 },
112 RouteDefinition {
114 method: "POST",
115 path_pattern: "/2015-03-31/functions/{FunctionName}/versions",
116 operation: "PublishVersion",
117 required_query_param: None,
118 },
119 RouteDefinition {
120 method: "GET",
121 path_pattern: "/2015-03-31/functions/{FunctionName}/versions",
122 operation: "ListVersionsByFunction",
123 required_query_param: None,
124 },
125 RouteDefinition {
127 method: "POST",
128 path_pattern: "/2015-03-31/functions/{FunctionName}/aliases",
129 operation: "CreateAlias",
130 required_query_param: None,
131 },
132 RouteDefinition {
133 method: "GET",
134 path_pattern: "/2015-03-31/functions/{FunctionName}/aliases",
135 operation: "ListAliases",
136 required_query_param: None,
137 },
138 RouteDefinition {
139 method: "GET",
140 path_pattern: "/2015-03-31/functions/{FunctionName}/aliases/{Name}",
141 operation: "GetAlias",
142 required_query_param: None,
143 },
144 RouteDefinition {
145 method: "DELETE",
146 path_pattern: "/2015-03-31/functions/{FunctionName}/aliases/{Name}",
147 operation: "DeleteAlias",
148 required_query_param: None,
149 },
150 RouteDefinition {
152 method: "POST",
153 path_pattern: "/2015-03-31/event-source-mappings",
154 operation: "CreateEventSourceMapping",
155 required_query_param: None,
156 },
157 RouteDefinition {
158 method: "GET",
159 path_pattern: "/2015-03-31/event-source-mappings",
160 operation: "ListEventSourceMappings",
161 required_query_param: None,
162 },
163 RouteDefinition {
164 method: "GET",
165 path_pattern: "/2015-03-31/event-source-mappings/{UUID}",
166 operation: "GetEventSourceMapping",
167 required_query_param: None,
168 },
169 RouteDefinition {
170 method: "DELETE",
171 path_pattern: "/2015-03-31/event-source-mappings/{UUID}",
172 operation: "DeleteEventSourceMapping",
173 required_query_param: None,
174 },
175 RouteDefinition {
177 method: "POST",
178 path_pattern: "/2018-10-31/layers/{LayerName}/versions",
179 operation: "PublishLayerVersion",
180 required_query_param: None,
181 },
182 RouteDefinition {
183 method: "GET",
184 path_pattern: "/2018-10-31/layers",
185 operation: "ListLayers",
186 required_query_param: None,
187 },
188 RouteDefinition {
189 method: "GET",
190 path_pattern: "/2018-10-31/layers/{LayerName}/versions",
191 operation: "ListLayerVersions",
192 required_query_param: None,
193 },
194 RouteDefinition {
195 method: "DELETE",
196 path_pattern: "/2018-10-31/layers/{LayerName}/versions/{VersionNumber}",
197 operation: "DeleteLayerVersion",
198 required_query_param: None,
199 },
200 RouteDefinition {
202 method: "POST",
203 path_pattern: "/2021-10-31/functions/{FunctionName}/url",
204 operation: "CreateFunctionUrlConfig",
205 required_query_param: None,
206 },
207 RouteDefinition {
208 method: "GET",
209 path_pattern: "/2021-10-31/functions/{FunctionName}/url",
210 operation: "GetFunctionUrlConfig",
211 required_query_param: None,
212 },
213 RouteDefinition {
214 method: "DELETE",
215 path_pattern: "/2021-10-31/functions/{FunctionName}/url",
216 operation: "DeleteFunctionUrlConfig",
217 required_query_param: None,
218 },
219 RouteDefinition {
220 method: "GET",
221 path_pattern: "/2021-10-31/functions/{FunctionName}/urls",
222 operation: "ListFunctionUrlConfigs",
223 required_query_param: None,
224 },
225 RouteDefinition {
227 method: "GET",
228 path_pattern: "/2017-03-31/tags/{Resource}",
229 operation: "ListTags",
230 required_query_param: None,
231 },
232 RouteDefinition {
233 method: "POST",
234 path_pattern: "/2017-03-31/tags/{Resource}",
235 operation: "TagResource",
236 required_query_param: None,
237 },
238 RouteDefinition {
239 method: "DELETE",
240 path_pattern: "/2017-03-31/tags/{Resource}",
241 operation: "UntagResource",
242 required_query_param: None,
243 },
244 RouteDefinition {
246 method: "GET",
247 path_pattern: "/2015-03-31/functions/{FunctionName}/policy",
248 operation: "GetPolicy",
249 required_query_param: None,
250 },
251 RouteDefinition {
252 method: "POST",
253 path_pattern: "/2015-03-31/functions/{FunctionName}/policy",
254 operation: "AddPermission",
255 required_query_param: None,
256 },
257 RouteDefinition {
258 method: "DELETE",
259 path_pattern: "/2015-03-31/functions/{FunctionName}/policy/{StatementId}",
260 operation: "RemovePermission",
261 required_query_param: None,
262 },
263 RouteDefinition {
265 method: "GET",
266 path_pattern: "/2016-08-19/account-settings",
267 operation: "GetAccountSettings",
268 required_query_param: None,
269 },
270 RouteDefinition {
272 method: "PUT",
273 path_pattern: "/2019-09-25/functions/{FunctionName}/event-invoke-config",
274 operation: "PutFunctionEventInvokeConfig",
275 required_query_param: None,
276 },
277 RouteDefinition {
278 method: "GET",
279 path_pattern: "/2019-09-25/functions/{FunctionName}/event-invoke-config",
280 operation: "GetFunctionEventInvokeConfig",
281 required_query_param: None,
282 },
283 RouteDefinition {
284 method: "DELETE",
285 path_pattern: "/2019-09-25/functions/{FunctionName}/event-invoke-config",
286 operation: "DeleteFunctionEventInvokeConfig",
287 required_query_param: None,
288 },
289 RouteDefinition {
290 method: "POST",
291 path_pattern: "/2019-09-25/functions/{FunctionName}/event-invoke-config",
292 operation: "UpdateFunctionEventInvokeConfig",
293 required_query_param: None,
294 },
295 RouteDefinition {
296 method: "GET",
297 path_pattern: "/2019-09-25/functions/{FunctionName}/event-invoke-config/list",
298 operation: "ListFunctionEventInvokeConfigs",
299 required_query_param: None,
300 },
301 ]
302 }
303
304 async fn handle(
305 &self,
306 operation: &str,
307 input: Value,
308 ctx: &RequestContext,
309 ) -> Result<Value, AwsError> {
310 debug!(operation, "Lambda request");
311 let state = self.get_state(ctx);
312
313 match operation {
314 "CreateFunction" => operations::functions::create_function(&state, &input, ctx),
316 "GetFunction" => operations::functions::get_function(&state, &input, ctx),
317 "GetFunctionConfiguration" => {
318 operations::functions::get_function_configuration(&state, &input, ctx)
319 }
320 "DeleteFunction" => operations::functions::delete_function(&state, &input),
321 "ListFunctions" => operations::functions::list_functions(&state, &input, ctx),
322 "UpdateFunctionCode" => {
323 operations::functions::update_function_code(&state, &input, ctx)
324 }
325 "UpdateFunctionConfiguration" => {
326 operations::functions::update_function_configuration(&state, &input, ctx)
327 }
328
329 "Invoke" => operations::invocations::invoke(&state, &input, ctx),
331
332 "PublishVersion" => operations::versions::publish_version(&state, &input, ctx),
334 "ListVersionsByFunction" => {
335 operations::versions::list_versions_by_function(&state, &input, ctx)
336 }
337
338 "CreateAlias" => operations::aliases::create_alias(&state, &input, ctx),
340 "GetAlias" => operations::aliases::get_alias(&state, &input, ctx),
341 "DeleteAlias" => operations::aliases::delete_alias(&state, &input, ctx),
342 "ListAliases" => operations::aliases::list_aliases(&state, &input, ctx),
343
344 "CreateEventSourceMapping" => {
346 operations::event_source_mappings::create_event_source_mapping(&state, &input, ctx)
347 }
348 "GetEventSourceMapping" => {
349 operations::event_source_mappings::get_event_source_mapping(&state, &input, ctx)
350 }
351 "DeleteEventSourceMapping" => {
352 operations::event_source_mappings::delete_event_source_mapping(&state, &input, ctx)
353 }
354 "ListEventSourceMappings" => {
355 operations::event_source_mappings::list_event_source_mappings(&state, &input, ctx)
356 }
357
358 "PublishLayerVersion" => operations::layers::publish_layer_version(&state, &input, ctx),
360 "ListLayers" => operations::layers::list_layers(&state, &input, ctx),
361 "ListLayerVersions" => operations::layers::list_layer_versions(&state, &input, ctx),
362 "DeleteLayerVersion" => operations::layers::delete_layer_version(&state, &input, ctx),
363
364 "CreateFunctionUrlConfig" => {
366 operations::url_configs::create_function_url_config(&state, &input, ctx)
367 }
368 "GetFunctionUrlConfig" => {
369 operations::url_configs::get_function_url_config(&state, &input, ctx)
370 }
371 "DeleteFunctionUrlConfig" => {
372 operations::url_configs::delete_function_url_config(&state, &input, ctx)
373 }
374 "ListFunctionUrlConfigs" => {
375 operations::url_configs::list_function_url_configs(&state, &input, ctx)
376 }
377
378 "TagResource" => operations::tags::tag_resource(&state, &input, ctx),
380 "UntagResource" => operations::tags::untag_resource(&state, &input, ctx),
381 "ListTags" => operations::tags::list_tags(&state, &input, ctx),
382
383 "GetPolicy" => operations::permissions::get_policy(&state, &input, ctx),
385 "AddPermission" => operations::permissions::add_permission(&state, &input, ctx),
386 "RemovePermission" => operations::permissions::remove_permission(&state, &input, ctx),
387
388 "GetAccountSettings" => {
390 operations::permissions::get_account_settings(&state, &input, ctx)
391 }
392
393 "PutFunctionEventInvokeConfig" => {
395 operations::event_invoke_configs::put_function_event_invoke_config(
396 &state, &input, ctx,
397 )
398 }
399 "GetFunctionEventInvokeConfig" => {
400 operations::event_invoke_configs::get_function_event_invoke_config(
401 &state, &input, ctx,
402 )
403 }
404 "UpdateFunctionEventInvokeConfig" => {
405 operations::event_invoke_configs::update_function_event_invoke_config(
406 &state, &input, ctx,
407 )
408 }
409 "DeleteFunctionEventInvokeConfig" => {
410 operations::event_invoke_configs::delete_function_event_invoke_config(
411 &state, &input, ctx,
412 )
413 }
414 "ListFunctionEventInvokeConfigs" => {
415 operations::event_invoke_configs::list_function_event_invoke_configs(
416 &state, &input, ctx,
417 )
418 }
419
420 _ => Err(AwsError::unknown_operation(operation)),
421 }
422 }
423
424 fn iam_action(&self, operation: &str) -> Option<String> {
425 match operation {
426 "CreateFunction"
427 | "GetFunction"
428 | "GetFunctionConfiguration"
429 | "DeleteFunction"
430 | "ListFunctions"
431 | "UpdateFunctionCode"
432 | "UpdateFunctionConfiguration"
433 | "Invoke"
434 | "InvokeFunction"
435 | "InvokeAsync"
436 | "PublishVersion"
437 | "ListVersionsByFunction"
438 | "CreateAlias"
439 | "GetAlias"
440 | "DeleteAlias"
441 | "ListAliases"
442 | "UpdateAlias"
443 | "CreateEventSourceMapping"
444 | "GetEventSourceMapping"
445 | "DeleteEventSourceMapping"
446 | "ListEventSourceMappings"
447 | "UpdateEventSourceMapping"
448 | "PublishLayerVersion"
449 | "ListLayers"
450 | "ListLayerVersions"
451 | "DeleteLayerVersion"
452 | "GetLayerVersion"
453 | "CreateFunctionUrlConfig"
454 | "GetFunctionUrlConfig"
455 | "DeleteFunctionUrlConfig"
456 | "ListFunctionUrlConfigs"
457 | "UpdateFunctionUrlConfig"
458 | "TagResource"
459 | "UntagResource"
460 | "ListTags"
461 | "GetPolicy"
462 | "AddPermission"
463 | "RemovePermission"
464 | "GetAccountSettings"
465 | "PutFunctionEventInvokeConfig"
466 | "GetFunctionEventInvokeConfig"
467 | "UpdateFunctionEventInvokeConfig"
468 | "DeleteFunctionEventInvokeConfig"
469 | "ListFunctionEventInvokeConfigs" => Some(format!("lambda:{operation}")),
470 _ => None,
471 }
472 }
473
474 fn iam_resource(&self, operation: &str, input: &Value, ctx: &RequestContext) -> Option<String> {
475 let prefix = format!("arn:aws:lambda:{}:{}", ctx.region, ctx.account_id);
476 match operation {
477 "ListFunctions"
478 | "ListEventSourceMappings"
479 | "ListLayers"
480 | "GetAccountSettings"
481 | "CreateFunction"
482 | "CreateEventSourceMapping" => Some("*".to_string()),
483 "TagResource" | "UntagResource" | "ListTags" => input
484 .get("Resource")
485 .and_then(|v| v.as_str())
486 .map(|s| s.to_string()),
487 "GetEventSourceMapping" | "DeleteEventSourceMapping" | "UpdateEventSourceMapping" => {
488 input
489 .get("UUID")
490 .and_then(|v| v.as_str())
491 .map(|uuid| format!("{prefix}:event-source-mapping:{uuid}"))
492 }
493 "PublishLayerVersion" | "ListLayerVersions" => input
494 .get("LayerName")
495 .and_then(|v| v.as_str())
496 .map(|name| format!("{prefix}:layer:{name}")),
497 "GetLayerVersion" | "DeleteLayerVersion" => {
498 let name = input.get("LayerName").and_then(|v| v.as_str())?;
499 let version = input
500 .get("VersionNumber")
501 .and_then(|v| v.as_i64())
502 .unwrap_or(0);
503 Some(format!("{prefix}:layer:{name}:{version}"))
504 }
505 _ => {
506 let name = input.get("FunctionName").and_then(|v| v.as_str())?;
507 if name.starts_with("arn:") {
508 Some(name.to_string())
509 } else {
510 Some(format!("{prefix}:function:{name}"))
511 }
512 }
513 }
514 }
515}