Deno for Infrastructure as Code
Why
Deno is a v8 runtime built in Rust which makes it easy to write performant
and secure javascript/typescript apps. It has great developer tooling with a
single cli(deno
) containing the:
- runtime,
- code fromatter
- linter
- dependency inspector
- package and build manager
- repl
- script evaluator
- script installer
- documentation generator
- and a language server
So all you need to start a simple one file project with Deno, is the deno
cli.
But what’s exciting is that even for complex projects, that’s all you would ever
need ! The deno
cli also comes with sane defaults
so for the most part one
doesn’t need a configuration file to manage the aforementioned tooling.
Incidentally, many Deno features and design decisions are also a good match for using it to write infrastructure code. It allows you to write secure and reproducible code with a developer friendly interface in a succint way. Let’s walkthrough a simple example to see these aspects:
We have a handlebarsjs Dockerfile template where we
want to replace the port
variable using typescript in Deno.
Dockerfile.template
|
|
main.js
|
|
Secure by default
Let’s run the above script with the deno
cli
|
|
deno
refuses to execute the program since it doesn’t have permissions to read
the Dockefile.template
file.
Running it again with --allow-read
permission fixes this problem.
|
|
We can clamp it down further by permitting deno
to have read permissions
only for the Dockerifle.template
file
|
|
allow-read
takes a comma separated list of files.
So deno
doesn’t have access to anything by default: network, disk, environment
variables. It provides the following permissions to allow access:
|
|
More on permissions
here.. It also has a
permissions
module
to do granular runtime permission checks.
Offline modules
But doesn’t the import
fetch the handlebarjs
module over the network ? Yes.
That could be a problem.
Importing modules over the network in production might cause a number of problems:
- module hosting might fail
- module hosting might have been compromised
- remote module might have changed
- maybe there is no network access available
Deno solves this problem by providing three features:
-
Caches a module one time and never reloads them unless explicity asked by running
deno cache --reload <file|module url>
-
Provides a way to check subresource integrity for modules using a json
lock
file -
Provides a
--cache-only
flag indeno run
.
So for the above example, this strategy would look like this:
Create a lock file and commit it:
|
|
On another machine, a collaborator can using this lock file to get verified modules:
|
|
We can take it further by doing a runtime verification too:
|
|
The above command verifies using the lock file and uses only cached modules with no remote fetching. Read more about this here.
Hyper Modularity
Writing and publishing small, focused yet versioned
modules is a breeze. The
above docker_template
module is probably too small to publish as a npm module
and probably not worth the investment. In Deno, since you can import any
exported functions from a versioned file, one can simply do this:
|
|
This can be of enourmous value for operators to easily publish small reusable modules.
Typescript
The out of the box typescript support sweetens the deal. If you are an operator
trying to practice dev-ops(as in equitable participation of operators and
developers in maintaining infrastructure on a build it, run it basis) and wants
to provide a familiar and expressive frontend
for your infrastructure tooling,
typescript could be quite important. Especially if the majority of the engineers
in your organisation use typescript most of the time.
Typescript allows you to write type-safe code and a first class autocompletion support in most IDEs/text editors.
Let’s rewrite the above simple example in typescript:
Define a module, docker_template.ts
|
|
Use the module in main.ts
|
|
Run it,
|
|
In the typescript implementation we are able to constrain port
to a number
type which also shows up a autocompletion in the editor. Trivial, but enhances
the developer experience greatly.
Ecosystem and future
Deno has a great potential to become the a middle ground for developers and
operators to work together on building and maintaining infrastructure. Providing
a typed
and familiar
frontend
to infrastrcuture can unlock the next
generation of developer friendly tooling. This space is seeing some serious
activity too: aws cdk,
terraform cdk,
pulumi to name a few. Deno has an additional related
feature in terms of a simple, secure & performant runtime apart from the common
offering of a typed
and familiar
language.
Takeaway
Personally I am betting on Deno(and typescript) to be one of the key tools in an infrastructure operator’s toolkit. What I like about it:
- It’s a secure and perfomant sandbox.
- One can easily build a ts/js wrapper for an external rust or wasm library.
- For developers it can be used a familiar and expressive frontend.
- For operators it can be used as a backend for enforcing schema validation, security policies, resource usage policies and hermeticity
dxcfg: A configuration as code libary for Deno
The dxcfg project is my attempt to use Deno in
production infrastructure. It' an opinionated port of
jkcfg which has similar goals. In my current
workplace, we use jkcfg
to build a base typescript library which is used by
developers to deploy applications in a standardised way. I have taken learnings
from this experience and enhanced it with the power of Deno to try and build a
type-safe, familiar and safe infrastructure toolkit.