Skip to content

Capabilities

Capability Modules provide infrastructure to extend and connect Applications to other areas of your infrastructure.

These modules are unique because they are normal Terraform, but never created in their own workspace. Instead, capabilities are attached to applications and managed by the connected application.

Subcategories

These modules provide glue and automatic configuration across 6 major subcategories:

datastores

When creating capabilities that connect applications to datastores, make sure to configure the following:

  • Grant network access from the application to the datastore. (see Network Access)
  • Generate/Configure credentials that the application can use to access the datastore.
  • Output the credentials and URL as secrets to be injected into the application. (see Secrets and Environment Variables)

Example modules:

events

When creating capabilities that trigger events, make sure to configure the following:

  • Configure the trigger in the cloud provider.
  • [Optional] Grant IAM privileges to the application.
  • [Optional] Grant network access to the application.

Example modules:

ingress

When creating capabilities that provide public access, make sure to configure the following:

  • Grant network access from the ingress device to the application.
  • Connect/Register app with ingress device.
  • [Optional] Configure subdomain connection and SSL cert to the ingress device.

Example modules:

secrets

When creating capabilities that provide secrets, make sure to configure the following:

  • Generate/Receive secrets.
  • Output secrets outputs.

Example modules:

sidecars

When creating capabilities that provide sidecar containers, make sure to configure the following:

  • Output sidecars outputs containing definitions used to attach containers to the application definition.

Example modules:

telemetry

When creating capabilities that emit logs/metrics to telemetry providers, make sure to configure the following:

  • Redirect/Subscribe log stream
  • Tag output log stream with vendor-specific tags marking the stack, environment, and application

Example modules:

Features

Network Access

Application modules create a network identity (e.g. in AWS, Security Group) and inject this into capability modules. When creating a capability module that connects two devices in a cloud provider, make sure to grant network access.

Here is an example snippet from nullstone-modules/aws-postgres-access. Note that the security_group_id is injected by the application and the database port and security group come from a connection to a postgres datastore.

hcl
locals {
  security_group_id    = var.app_metadata["security_group_id"]
  db_endpoint          = data.ns_connection.postgres.outputs.db_endpoint
  db_subdomain         = split(":", local.db_endpoint)[0]
  db_port              = split(":", local.db_endpoint)[1]
  db_security_group_id = data.ns_connection.postgres.outputs.db_security_group_id
}

resource "aws_security_group_rule" "app-to-datastore" {
  security_group_id        = local.security_group_id
  type                     = "egress"
  from_port                = local.db_port
  to_port                  = local.db_port
  protocol                 = "tcp"
  source_security_group_id = local.db_security_group_id
}

resource "aws_security_group_rule" "datastore-from-app" {
  security_group_id        = local.db_security_group_id
  type                     = "ingress"
  from_port                = local.db_port
  to_port                  = local.db_port
  protocol                 = "tcp"
  source_security_group_id = local.security_group_id
}
locals {
  security_group_id    = var.app_metadata["security_group_id"]
  db_endpoint          = data.ns_connection.postgres.outputs.db_endpoint
  db_subdomain         = split(":", local.db_endpoint)[0]
  db_port              = split(":", local.db_endpoint)[1]
  db_security_group_id = data.ns_connection.postgres.outputs.db_security_group_id
}

resource "aws_security_group_rule" "app-to-datastore" {
  security_group_id        = local.security_group_id
  type                     = "egress"
  from_port                = local.db_port
  to_port                  = local.db_port
  protocol                 = "tcp"
  source_security_group_id = local.db_security_group_id
}

resource "aws_security_group_rule" "datastore-from-app" {
  security_group_id        = local.db_security_group_id
  type                     = "ingress"
  from_port                = local.db_port
  to_port                  = local.db_port
  protocol                 = "tcp"
  source_security_group_id = local.security_group_id
}

Environment Variables

You can automatically inject environment variables into applications from a capability module. This is done through the env outputs of the capability module. These environment variables are treated as non-sensitive configuration.

The following example from the nullstone-modules/aws-postgres-access illustrates how to inject non-sensitive sensitive configuration into an application from a capability.

hcl
output "env" {
  value = [
    {
      name  = "POSTGRES_DB"
      value = local.database_name
    }
  ]
}
output "env" {
  value = [
    {
      name  = "POSTGRES_DB"
      value = local.database_name
    }
  ]
}

Secrets

You can securely inject secrets into applications from a capability module. This is done through the secrets outputs of the capability module. The format is identical to environment variables (name, value).

The following example from the nullstone-modules/aws-postgres-access illustrates how to inject sensitive configuration into an application from a capability.

hcl
output "secrets" {
  value = [
    {
      name  = "POSTGRES_URL"
      value = "postgres://${urlencode(local.username)}:${urlencode(random_password.this.result)}@${local.db_endpoint}/${urlencode(local.database_name)}"
    }
  ]
}
output "secrets" {
  value = [
    {
      name  = "POSTGRES_URL"
      value = "postgres://${urlencode(local.username)}:${urlencode(random_password.this.result)}@${local.db_endpoint}/${urlencode(local.database_name)}"
    }
  ]
}