Skip to the content.

Servers

These constructs create ready-to-use servers.

UbuntuLinuxBastion

You can use the UbuntuLinuxBastion construct to create a bastion host (also called a jump box). A bastion lets administrators reach resources in private subnets, like databases and file systems, without exposing those resources to the internet.

This construct produces an auto-scaling group and a corresponding launch template. The auto-scaling group has a minimum of zero instances and a maximum of one, so you can set the desired capacity to one when you need the bastion and back to zero when you don’t. Instances launch in a public subnet of the VPC.

import { Peer } from "aws-cdk-lib/aws-ec2";
import { UbuntuLinuxBastion } from "shady-island/lib/servers";

const bastion = new UbuntuLinuxBastion(stack, "Bastion", { vpc });
bastion.allowSshAccessFrom(Peer.ipv4("203.0.113.0/24"));
// bastion.autoScalingGroup instanceof AutoScalingGroup

By default, the bastion:

The bastion is IConnectable and IGrantable, so you can allow network traffic and grant permissions the same way as other CDK constructs.

import { DatabaseCluster } from "aws-cdk-lib/aws-rds";

declare const cluster: DatabaseCluster;

cluster.connections.allowDefaultPortFrom(bastion);

Instance firewall

The bastion configures an iptables firewall on the instance (see Configuration). By default, it allows only outbound DNS, HTTP, HTTPS, NTP, and ICMP traffic, plus DHCP. The allowSshAccessFrom method opens the SSH port in both the security group and the instance firewall.

The firewall property lets you add more rules. Remember to allow the traffic in the security group, too.

import { Port } from "aws-cdk-lib/aws-ec2";
import { Address } from "shady-island/lib/networking";

bastion.firewall.outbound(Port.tcp(5432), Address.ipv4(vpc.vpcCidrBlock));

Options

You can customize the bastion with several more options.

import { InstanceArchitecture } from "aws-cdk-lib/aws-ec2";
import { FileSystem } from "aws-cdk-lib/aws-efs";
import { IHostedZone } from "aws-cdk-lib/aws-route53";
import { ISecret } from "aws-cdk-lib/aws-secretsmanager";
import { UbuntuLinuxBastion } from "shady-island/lib/servers";

declare const hostedZone: IHostedZone;
declare const fileSystem: FileSystem;
declare const databaseSecret: ISecret;

const bastion = new UbuntuLinuxBastion(stack, "Bastion", {
  vpc,
  architecture: InstanceArchitecture.X86_64,
  enableIpv6: true,
  customDomain: { hostedZone, subdomain: "bastion" },
  fileSystems: [{ fileSystem, directory: "/mnt/shared" }],
  secrets: { database: databaseSecret },
  aptPackages: ["mysql-client", "postgresql-client"],
});

The /run directory is emptied on reboot, and the secrets are only downloaded when an instance first launches. If you reboot the bastion, the secrets are gone until a new instance replaces it.