Skip to content

Create EC2 Module

This quickstart creates a Nullstone Application module that provisions an AWS EC2 instance. This walks you through:

  • Registering a new module in Nullstone (and defining the contract)
  • Developing the Terraform code
  • Testing the module in a sandbox environment
  • Publishing the final version to Nullstone

The following category, provider, and platform are used when registering the module:

  • Category: app
  • Subcategory: server
  • Provider: aws
  • Platform: ec2

A working copy of this code can be found at


Before following this quickstart, make sure the following are installed and configured.

  1. An AWS Account
  2. Install/Configure Nullstone CLI
  3. Install Terraform CLI


If you are unfamiliar with Terraform, it may be helpful to follow their basic guide.

Create EC2 module

Create a new repository/directory to store the module. We recommend having a repository for each module; however, you may have multiple modules in a single repository as long as they are in different directories.

The following will create a .nullstone/module.yaml that contains metadata about the Nullstone module.

mkdir test-ec2 && cd test-ec2
nullstone modules generate
# This command will ask you a set of questions to configure the module
# Specify the following:
#   Module Name: test-ec2
#   Friendly Name: Test EC2 Instance
#   Description: Creates an EC2 instance
#   Make this module available to everybody? No
#   Category: app
#   Subcategory: server
#   ProviderTypes: aws
#   Platform: ec2

Register module

Run modules new to register the module. This uses .nullstone/module.yaml to register in the Nullstone catalog.

nullstone modules new

Define network connection

Add a network to our module by creating a with the following.

data "ns_connection" "network" {
  name = "network"
  type = "network/aws"
  contract = "aws/network/vpc"

locals {
  vpc_id             =
  private_subnet_ids =

Define EC2 instance

Create a file named with the following contents.

data "aws_ami" "this" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "owner-alias"
    values = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm*"]

locals {
  ami =

resource "aws_instance" "this" {
  ami                         = local.ami
  instance_type               = "t3.nano"
  subnet_id                   = local.private_subnet_ids[0]
  vpc_security_group_ids      = []
  associate_public_ip_address = false
  tags                        = merge(local.tags, { Name = local.resource_name })

resource "aws_security_group" "this" {
  name   = local.resource_name
  vpc_id = local.vpc_id
  tags   = merge(local.tags, { Name = local.resource_name })

resource "aws_security_group_rule" "this-https-to-world" {
  security_group_id =
  type              = "egress"
  protocol          = "tcp"
  from_port         = 443
  to_port           = 443
  cidr_blocks       = [""]

Enable nullstone ssh

To enable SSH to the server using Nullstone, add an adminer user to

resource "aws_iam_user" "adminer" {
  name = "adminer-${local.resource_name}"
  tags = local.tags

resource "aws_iam_access_key" "adminer" {
  user =

resource "aws_iam_user_policy" "adminer" {
  user   =
  policy = data.aws_iam_policy_document.adminer.json

data "aws_iam_policy_document" "adminer" {
  statement {
    sid     = "AllowSSMSession"
    effect  = "Allow"
    actions = ["ssm:StartSession"]

    resources = [

Adhere to server/aws-ec2

This quickstart launches an EC2 instance using Nullstone. To get the full benefits of Nullstone, amend to adhere to the app/aws/ec2 contract.


Terraform does not support output types in the definition. Nullstone encodes these into the description field as seen below.

data "aws_region" "this" {}
output "region" {
  value       =
  description = "string ||| The AWS region where the EC2 instance resides."

output "instance_id" {
  value       =
  description = "string ||| The Instance ID of the EC2 instance."

output "adminer" {
  value = {
    name       =
    access_key =
    secret_key = aws_iam_access_key.adminer.secret

  description = "object({ name: string, access_key: string, secret_key: string }) ||| An AWS User with explicit privilege to admin the EC2 instance."
  sensitive   = true

Test in Sandbox

To test our new module, create a sandbox environment and necessary dependencies. In this scenario, we need a network and an app for our new EC2 module.

Create sandbox provider

Follow the guide to Connect to AWS to create a provider named aws-sandbox.

Create sandbox environment

Create a sandbox stack and a sandbox environment.

nullstone stacks new --name=sandbox --description="Sandbox for module testing"
nullstone envs new --name=sandbox --stack=sandbox --provider=aws-sandbox --region=us-east-1

Create sandbox network

In our sandbox stack, create a network block using the nullstone/aws-network module. In our example, let's name the network network1 and launch the network.

nullstone blocks new --name=network1 --stack=sandbox --module=nullstone/aws-network
nullstone up --block=network1 --env=sandbox --watch

Create sandbox EC2

In our sandbox stack, create a block using our new module named test-ec2.

nullstone blocks new --name=test-ec2 --stack=sandbox --module=test-ec2

Initialize Terraform using the following command.

nullstone workspaces select --block=test-ec2 --env=sandbox


This command will generate and add to .gitignore. This contains state backend information that is automatically changed when workspaces select is run.

Configure AWS credentials

Previously, you configured a provider in Nullstone, but you need to authenticate with AWS locally test the module locally. Authenticate with AWS and export AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY. These access keys should have access to the aws-sandbox AWS account.

export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=<access key id>
export AWS_SECRET_ACCESS_KEY=<secret access key>

Apply infrastructure changes

Run terraform to test the module.

terraform apply

SSH into server

Once the infrastructure is provisioned, SSH into the box using the following command.


It can take several minutes for an EC2 instance to boot and become available depending on the image.

nullstone ssh --app=test-ec2 --env=sandbox

Publish module

Once your module is complete, publish the module to the Nullstone registry. A user can launch this module directly from the Nullstone UI without any coding or Terraform setup.

nullstone modules publish --version=v0.0.1
Create EC2 Module has loaded