Conceptio › Archive › arXiv CS
arXiv CS open access

AWS Serverless Infrastructure from WebAssembly Components

Philipp Vollmer · arxiv_cs
arXiv CS · Papers
Open Source ↗Direct PDF ↓
clouddistributed-computingparallel-computing
The infrastructure definitions and the code for serverless applications are often only loosely connected. This yields a large error class: the referenced infrastructure components might not exist. It is also hard to keep the application and its permissions in sync. To address this problem we present
Conceptio Open Archive

Analyze & explore related research in Conceptio

Connect this record directly into your research workflow or AI agent. Explore citations across open repositories, query full text, and export structured proof bundles.

AWS Serverless Infrastructure from WebAssembly Components Philipp Vollmer

arXiv:2611.11293v1 [cs.SE] 8 Nov 2026

briefe@kebes.de

Abstract. The infrastructure definitions and the code for serverless applications are often only loosely connected. This yields a large error class: the referenced infrastructure components might not exist. It is also hard to keep the application and its permissions in sync. To address this problem we present an infrastructure from code solution where we provision cloud infrastructure from Wasm Interface Type (WIT)—the language defining the interface of WebAssembly components. We limit ourselves to the basic example of an AWS Lambda function accessing S3 buckets. We build two interpreters for the WIT language: one that derives the definition of S3 buckets as infrastructure as code and least-privilege IAM permissions, and a generic runtime that runs the component as a Lambda function and provides access to the S3 buckets as capabilities. We formulate consistency properties that ensure the existence of the S3 buckets and correct permissions of the Lambda, and provide evidence that our interpreters satisfy them. We show how selected failures for deployment of such cloud components can be prevented using our technique and how a baseline setup fails at this task. Together with the strict sandboxing of the WebAssembly runtime we achieve an instance of capability-based security for access to AWS infrastructure as a further result.

1

Introduction

There are good reasons to adopt serverless architectures in the cloud: they are very scalable and provide prepared components for different scenarios: queues, storage, databases, and functions. They are popular for low-volume applications as they free developers from the burden of maintaining server operating systems. Moreover, they are usually billed “pay per use” which makes sense for applications that are used only occasionally. They are also popular for applications with high, variable load because scaling the system is automatic to some extent. Yet, developing serverless software in the cloud comes with engineering challenges. The more components a piece of software has, the more likely it is to fail after a change—unnoticed by tests. Such systems consist of a lot of interdependent code components which are—from the code perspective—unrelated. It is hard to reason about changes in such software systems upfront—for human developers and coding agents alike. Hence, changes—even simple ones—must go through several deployments. This costs time, tokens, and concentration.

We are going to study a very simple example of a serverless application: an AWS Lambda that accesses a set of S3 buckets. A setup for deploying such an application can look as follows: – an npm package containing the code for the Lambda handler – an npm package containing the CDK infrastructure as code referencing the first package. The infrastructure as code package will set up the following: – the S3 buckets that the Lambda handler will use – the Lambda function referencing the Lambda handler build artifact (usually a CommonJS module) – IAM permissions to access the S3 buckets The following must now be configured in infrastructure as code in order for the system to work correctly: – The Lambda needs to know how to reference the S3 bucket (usually its name will be passed via environment variables or will be fixed by convention) – The execution role of the Lambda function must contain the proper policies to access the S3 buckets. This can be accomplished in CDK by method calls on the S3 bucket object. We will call this setup the baseline setup. The following problems can arise when the infrastructure as code and the handler code do not match. These problems fit into the taxonomy of Rahman et al. [12]. – Bucket Name Misconfiguration: the Lambda code tries to access a nonexisting S3 bucket due to drift between infrastructure as code and Lambda code. – Permission Misconfiguration: the Lambda code does not have access to the bucket or tries to access a bucket it does not have access to. Both problems can be attributed to the Configuration Data category. Also, the following problem might occur. Access Forging: the Lambda code might be allowed to perform operations that are not intentionally derived but can be derived from the permissions of the execution role. This problem belongs to the security category.

2

Prior Art

2.1

Related Work

Pulumi [11] is an Infrastructure from Code tool. It uses sophisticated closure serialization to serve as a universal language for describing serverless infrastructure. Yet, wiring infrastructure components into code and providing access are not automatic.

Spin [13] is a framework that facilitates the deployment of WebAssembly components to Kubernetes and other platforms. It allows declaring infrastructure components (e.g. databases) as imports in WIT and configures the components via a deployment manifest. wasmCloud [17] uses capability providers to give wasm components access to infrastructure. Cloudflare Workers bindings [5] inject capabilities declared in a configuration file into a component. Ampt [1] and Encore [7] are Infrastructure from Code tools. Winglang [22] is a unified programming language for infrastructure and code. Table 1 compares these solutions.

Table 1. Comparison of related infrastructure solutions

Product Cloudflare Workers Winglang Ampt Encore wasmCloud Spin Pulumi This work

Language Single Source Permission Capability-Based Agnostic of Truth Generation Security yes no no no yes yes partly yes

no yes yes yes no no yes yes

no yes yes yes no no no yes

yes no no no yes yes no yes

Our solution has—though for a much smaller feature set—all three properties.

2.2

Foundational Technologies

Much of our work is supported by sophisticated techniques and tools. We mention them here to make our contribution to the topic transparent.

The Rust programming language wasm32-wasip2 Target The Rust programming language supports wasm32-wasip2 as a compilation target [14]. This means that WebAssembly components which are the foundation of our work can be emitted from Rust code.

WIT-Bindgen WIT-Bindgen [3] is a tool to generate traits from WIT definitions. It reduces the creation of a WebAssembly component implementing the definition of a WIT file to implementing the traits generated by WIT-bindgen.

3

Infrastructure from WebAssembly Components

In this section we will use the interface description language Wasm Interface Type or WIT as a unified language for describing both the infrastructure and the runtime for the code. Our paradigm will be one language—two consistent interpreters. The example use case we describe here is a serverless function that writes to blob storage in the cloud. The code for this section is on GitHub [16]. 3.1

WebAssembly

WebAssembly [8] is a portable, low-level bytecode format. The semantics is formally defined. By itself it has a low-level interface only allowing the exchange of primitive fixed-size types (which are usually used to transport pointers). These wasm modules are often referred to as core modules. The functions exported by wasm modules usually run compiled ahead of time in a memory-isolated sandbox. This is an important security feature [18,15]. Other important features are short startup times and relatively low runtime overhead compared to native execution (see for example [9]). Interaction with the outer world is possible via imported functions. We will often denote these functions as capabilities. While usually conceived as a portable way of running native code in the browser, its purpose goes far beyond this: WebAssembly targets embedded and cloud computing as well. One popular example is Cloudflare’s wasm workers. The major cloud providers do not directly support WebAssembly yet. Hence, we have to invest a little here to fill the gap. 3.2

The WebAssembly Component Model

The WebAssembly Component Model [10,20] puts one layer of abstraction on top of wasm core modules. It allows WebAssembly Components to import and export functions using a rich type system with heap-allocated data structures like lists or strings and complex types like algebraic data types. It is the basis for all WASI versions from preview 2 on. WASI [4,21] is a system interface for WebAssembly Components comparable to POSIX (though at a much higher level). The interface of WebAssembly modules can be defined using the WIT language [19]. 3.3

Defining the Application using the Component Model

The component interface definition is given by WIT as follows. 1

package demo : uploader ;

2 3 4

world uploader { export aws : lambda / handler@1 .0.0;

5

@external-id (" w a s m - c a p a b i l i t y - d e m o - u p l o a d s ") import uploads : aws : s3 / blob@1 .0.0;

6 7 8

@external-id (" w a s m - c a p a b i l i t y - d e m o - a r c h i v e ") import archive : aws : s3 / blob@1 .0.0;

9 10 11

} Listing 1.1. The serverless demo application

The interface “blob” is defined as follows. 1

package aws : s3@1 .0.0;

2 3 4 5

interface blob { put-file : func ( content : list < u8 > , name : string ) ; } Listing 1.2. The ”blob” capability

The interface of a Lambda handler is that of an HTTP request. We do not repeat it here as it does not contribute to our discussion. Most of the language is self-explanatory. A world is the set of functions a component exports and imports. We are going to use the WIT file and the WIT from the component interchangeably: the reason is that unlike C header files, the interfaces from WIT can be essentially reconstructed using the wasm-tools crate [2]: wasm - tools component wit < filename >

3.4

Deriving the Infrastructure from WIT

This will be our first interpreter: it reads WIT and generates CDK from it. The infrastructure is derived as follows. We start with the derivation of S3 buckets. – Search for interfaces of the special type aws:s3/blob@1.0.0 – Determine the configuration (here given by an external id) – Create the required CDK constructs for the storage. Then we derive the Lambda handlers from it. – Search for interfaces of the special type aws:lambda/handler@1.0.0 – Create the required CDK constructs for the handler. – Give the Lambda handler’s execution role the required permissions on the S3 buckets. Moreover, there will be the need for a runtime that is not specific to the component. Thus we need to – Build a zip file with the runtime and the component. – Declare an AWS Lambda using this zip file.

3.5

The Runtime

This is our second interpreter. In the code it is the runtime crate. It searches for an entry point that can be used as the Lambda handler. Wasm Components have no capabilities by default: they run as functions inside a sandbox without I/O capabilities. Our runtime acts as a dynamic linker. It searches for imported capabilities in the module. Then it assembles a function “put-file” that puts a file to the S3 bucket given by the external id and links it to the WebAssembly component.

4

Evaluation

We will now compare our approach with the baseline setup. There are three stages at which failures can be detected: 1. Prevented by construction: an error is made impossible by the way our infrastructure is constructed. 2. Upon local execution: the issue gets detected when locally executing tests. 3. At runtime, deployed in the cloud. The second one deserves explanation: the runtime can be imported as a function and can run components. The S3 capabilities will then be provided as in-memory implementations. This test harness is a good simulation of a cloud deployment and we will mean this test harness when we refer to local tests. 4.1

Correctness Properties

We can now make our correctness property one language—two consistent interpreters precise. By this we mean the following: – For every import i with external id e of a component c, an S3 bucket with name e is created and a function f that only accesses e is provided to c. We denote these functions by cap(c). – For every function f in cap(c) and every AWS action a that f calls, we generate an IAM statement allowing this action and these are the only IAM actions generated. The first property is backed by tests. The second property comes from the fact that the implementation of the capability and the code generating the IAM actions live in the same module. There is a test in extractor/src/kinds/s3_ blob.rs that records all S3 actions in the capability passed to the component and checks whether the required IAM grants are generated. The test passes; given that the recorded actions map onto the IAM actions required to grant permission, this provides evidence for the second property. However, we clearly state that this consistency property is a requirement for the validity of our approach.

4.2

Access Forging

The forging of access to infrastructure components usually works along the following lines: – get credentials from instance metadata service – get credentials from environment variables – create an authenticated AWS SDK client – call an API Interestingly, the STS get-caller-identity endpoint does not need permissions and cannot be forbidden in the execution role. Lambda functions can use the described way to call APIs that they were not supposed to call. We have run explicit test cases for the runtime to verify that each of these steps fails for our runtime. The component has neither TCP nor environment variable access. Our access control to S3 buckets is an implementation of capability-based security: The access to resources cannot be forged from ambient authority and has to be passed explicitly as a handle (in this case: a function) to the component. As a corollary, we see that even forceful attempts to access S3 buckets that were not explicitly configured as capabilities are unsuccessful. We have tested the impossibility of accessing AWS APIs in the runtime/test folder for our solution. We have simulated the access forging for the baseline in the thinAir example in the pitfalls folder. 4.3

Bucket Name Misconfiguration

Due to the lack of network connectivity, the only way for a component to access S3 buckets at all is by importing the interfaces supplying access to the S3 buckets. The bucket that is accessed using the interface is completely abstract; the configuration is invisible. So this failure type is impossible by construction. Even attempts that do not use the provided capability but try to find credentials and use them to access the AWS API are prevented due to lack of network connectivity in the sandbox attempts will already fail on local execution of the comonent. For the baseline, the EnvMismatch example in the pitfalls directory shows how this case passes compilation and synthesis and only fails at run time. There are tests in pitfalls/lambda/test/handlers.test.ts for the S3 access operations but the responses from the S3 service are simulated by a test double. These tests pass but the access fails when deployed in the cloud. 4.4

Permission Misconfiguration

The required infrastructure permissions are set up automatically by the extractor. So this failure type is impossible by construction. The MissingGrant example in the pitfalls directory shows how this case passes compilation and synthesis and only fails at run time in the cloud. There are also tests pitfalls/lambda/test/handlers.test.ts which are successful but the example fails in the cloud.

4.5

Summary of Failure Types

We see that we are able to detect failures before the first deployment that, in the baseline setup, will only surface after a deployment. Table 2. Failure types and the stage at which they are detected Failure Type Bucket Name Misconfiguration Permission Misconfiguration Access Forging 1 – by construction

4.6

Our solution

Baseline

1 or 2 1 or 2 2

3 3 succeeds undetected

2 – in local tests

3 – deployed in the cloud

Performance

We also want to point out some performance implications. Depending on the requirements, the impact might be significant. There is one additional optimization we included in the benchmarks. Wasmtime compiles wasm modules aheadof-time. It also allows saving and loading a compiled artifact. We add this as an additional data point. Our test setup is shown in Table 3. All benchmarks can be found in the code for this article. Table 3. Benchmark environment CPU OS Rust

Intel Core i9-8950HK (6 cores, 12 threads), 32 GB RAM Linux 6.17.0 1.99.1; native binaries for x86 64-unknown-linux-musl, components for wasm32-wasip2 Libraries wasmtime 50.0.0, lambda http 1.3.2, tokio 1.54.1, criterion 0.7.0 Date 2026-11-05

Cold Start Times These are the results of a small benchmark measuring the cold start penalty we get when we work with WebAssembly and pre-compiled WebAssembly. In Table 4 we find the result of a benchmark with 50 samples. Note that we have not included the contributions from the AWS Lambda service in our benchmark. We can draw three conclusions here. – cold start times are significantly longer when using WebAssembly compared to native binaries

– cold start times can be improved by a factor of 8 when pre-compiling the wasm module – However, compared to the cold start times including the contribution from the AWS cloud infrastructure (which is about 20 ms, cf. [6]) the advantage is much smaller

Table 4. Cold start times in ms (single-threaded) p50 Scenario

total

init invoke min

native 5.0 wasm 105.0 precompiled 12.0

p50

p90 mean

0.32 2.0 5.3 7.0 5.1 0.55 102.7 105.6 108.0 105.8 0.52 9.4 12.5 14.1 12.5

Artifact Sizes We measure the artifact sizes. We have three different components here. – bootstrap: the entry point executable – the wasm component – the pre-compiled wasm component We see that the WebAssembly runtime contributes significantly to the artifact sizes. Table 5. Deployment artifact sizes in MB Scenario

Deployment zip contents

Raw Zipped

native bootstrap 4.00 wasm bootstrap + bench.wasm 45.27 precompiled bootstrap + bench.cwasm 45.41

1.64 15.23 15.27

Performance Although WebAssembly gets compiled to native code, it is significantly slower than native code. At least two reasons explain this: – Sandboxing: the strict sandboxing of WebAssembly runtimes slows down execution. – Missing optimizations: native compilers can make optimizations that WebAssembly does not offer. WebAssembly has the simd128 proposal, but we did not test it.

For our benchmark we ran the sort unstable function from the Rust language standard library on a vector of size n of 64-bit unsigned integers. We present our results in Table 6. As a rough estimate we can state that native execution is 1.5 times faster than WebAssembly. Table 6. Runtime of sort unstable on n 64-bit unsigned integers n native

wasm wasm / native

10,000 124 µs 273 µs 100,000 1.53 ms 2.56 ms 1,000,000 18.1 ms 27.9 ms

2.2× 1.7× 1.5×

5

Limitations

5.1

Dependency on an Unstable Features of WebAssembly

Currently, we use the unstable external-id feature of WIT. It is not intended for declaring infrastructure dependency configuration. We also depend on the unstable implements feature but its use is idiomatic. 5.2

No Empirical Data about the Likelihood of the Investigated Errors

Although it appears plausible from the author’s personal experience—errors of this kind occur frequently in his everyday work—we did not conduct empirical studies on these errors. One might deny the importance of such errors altogether or might object that these are prevented by common best practice. 5.3

The Runtime is the Security Boundary

Although it is backed by strict IAM policies for the execution role, the runtime for the wasm components is the security boundary. This implies that extra care has to be taken when developing it. 5.4

No Configurability of the Bucket Name

For multi-stage deployments (staging, production) this is a challenge as bucket names must be globally unique. In our case this means that for every stage we would have to build a separate component. However, there are resolutions for this issue whose implementation seems feasible. – Use the id only as an identifier that allows the runtime and extractor to do the assignment (the bucket name gets generated by CDK and injected via an environment variable). This would be the idiomatic CDK way. – Allow simple templating inside the external id (allow stage as a variable inside templates). This would be the idiomatic Azure Bicep way.

6

Conclusion

Although the idea of facilitating infrastructure by importing functions is basically everywhere in the specification and the examples for WebAssembly Components, there is no clear integration path (the stringly-typed external-id is a workaround). The big advantage and the author’s main motivation is that WIT can act as a universal language for the infrastructure while the implementation of the infrastructure components can be written in almost any other language. Yet the types in WIT are usually checked to agree with the types of the implementation—at least if the language for the implementation is statically typed. It would be interesting to enrich WIT with language elements that have the semantics of configuration of dependencies. Also our scope was limited to one serverless function - adding more types of infrastructure components and more ways of interaction between them is an interesting challenge for WIT language design.

Declaration of AI-Assisted Technologies The author hereby discloses the use of generative ai during the work on this article. The author used Claude 5.5 Opus by Anthropic for generating the code for this article. The conceptual ideas, choice of tools, architecture, design, and structure are the author’s own. The tests and benchmarks were performed and supervised by the author. The author claims full responsibility for the final results. The article is written by the author with the aforementioned tool used for review, spell checking, and formatting.

References 1. Ampt: Ampt documentation. https://getampt.com/docs/, accessed 2026-11-06 2. Bytecode Alliance: wasm-tools: CLI and Rust libraries for low-level manipulation of WebAssembly modules. https://github.com/bytecodealliance/wasm-tools, software. Accessed 2026-11-06 3. Bytecode Alliance: wit-bindgen: A language binding generator for WebAssembly interface types. https://github.com/bytecodealliance/wit-bindgen, software. Accessed 2026-11-03 4. Bytecode Alliance: WASI 0.2 launched. https://bytecodealliance.org/ articles/WASI-0.2 (2024), accessed 2026-10-28 5. Cloudflare: Bindings (env). https://developers.cloudflare.com/workers/ runtime-apis/bindings/, Cloudflare Workers documentation. Accessed 2026-1106 6. David, M.: lambda-perf: Cold start benchmark of AWS Lambda runtimes. https: //maxday.github.io/lambda-perf/, daily updated benchmark. Accessed 2026-1106 7. Encore: Encore documentation. https://encore.dev/docs, accessed 2026-11-06

8. Haas, A., Rossberg, A., Schuff, D.L., Titzer, B.L., Holman, M., Gohman, D., Wagner, L., Zakai, A., Bastien, J.: Bringing the web up to speed with WebAssembly. In: Proceedings of the 38th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI ’17). pp. 185–200. ACM (2017). https://doi.org/10.1145/3062341.3062363 9. Jangda, A., Powers, B., Berger, E.D., Guha, A.: Not so fast: Analyzing the performance of WebAssembly vs. native code. In: 2019 USENIX Annual Technical Conference (USENIX ATC 19). pp. 107–120. USENIX Association, Renton, WA (2019), https://www.usenix.org/conference/atc19/presentation/jangda 10. Menon, L., Wagner, L.: The WebAssembly component model. Talk at the WebAssembly Workshop (WAW 2025), co-located with POPL 2025, Denver, CO, https://popl25.sigplan.org/details/waw-2025-papers/4/ The-WebAssembly-Component-Model (2025) 11. Pulumi: Infrastructure as code. https://www.pulumi.com/docs/iac/, Pulumi documentation. Accessed 2026-11-01 12. Rahman, A., Farhana, E., Parnin, C., Williams, L.: Gang of Eight: A defect taxonomy for infrastructure as code scripts. In: Proceedings of the 42nd International Conference on Software Engineering (ICSE ’20). pp. 752–764. ACM, Seoul, Republic of Korea (2020). https://doi.org/10.1145/3377811.3380409 13. Spin contributors: Spin: A developer tool for building WebAssembly microservices and web applications. https://spinframework.dev/, Spin documentation. Accessed 2026-11-03 14. The Rust Project Developers: wasm32-wasip2. https://doc.rust-lang.org/ rustc/platform-support/wasm32-wasip2.html, the rustc book, Platform Support. Accessed 2026-11-03 15. VanHattum, A., Pardeshi, M., Fallin, C., Sampson, A., Brown, F.: Lightweight, modular verification for WebAssembly-to-native instruction selection. In: Proceedings of the 29th ACM International Conference on Architectural Support for Programming Languages and Operating Systems, Volume 1 (ASPLOS ’24). pp. 231– 248. ACM (2024). https://doi.org/10.1145/3617232.3624862 16. Vollmer, P.: infra-from-wit. https://github.com/torfmaster/infra-from-wit, software, Apache 2.0 or MIT license. Accessed 2026-11-01 17. wasmCloud contributors: Capability providers. https://wasmcloud.com/docs/v1/ concepts/providers/, wasmCloud documentation. Accessed 2026-11-06 18. Watt, C.: Mechanising and verifying the WebAssembly specification. In: Proceedings of the 7th ACM SIGPLAN International Conference on Certified Programs and Proofs (CPP ’18). pp. 53–65. ACM (2018). https://doi.org/10.1145/ 3167082 19. WebAssembly Community Group: The Wasm Interface Type (WIT) format. https://github.com/WebAssembly/component-model/blob/main/design/ mvp/WIT.md, accessed 2026-10-28 20. WebAssembly Community Group: The WebAssembly component model. https: //github.com/WebAssembly/component-model, specification repository. Accessed 2026-10-28 21. WebAssembly Community Group: WebAssembly system interface (WASI). https: //github.com/WebAssembly/WASI, specification repository. Accessed 2026-10-28 22. Wing contributors: Wing: A programming language for the cloud. https:// github.com/winglang/wing, GitHub repository. Accessed 2026-11-06

Related documents

Record · ID 1605214 · SHA-256 d80abd1fb0bb5bbf
Retrieved via Conceptio: every document is proof-bundled with source, license, and retrieval metadata.
Bring this data into your agent: Connect via MCP or API · 20 free credits to start · no card required
Read the Docs → · View CLI source on GitHub · Conceptio Open Knowledge Archive