Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove NAT gateway and ALB, including HTTPS support #16

Merged
merged 1 commit into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/restate-constructs/restate-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as ssm from "aws-cdk-lib/aws-secretsmanager";
* service.
*/
export interface RestateInstance {
readonly invokerRole: iam.Role;
readonly invokerRole: iam.IRole;
readonly metaEndpoint: string;
readonly authToken?: ssm.ISecret;
readonly registrationProviderToken: cdk.CfnOutput;
Expand Down
90 changes: 20 additions & 70 deletions lib/restate-constructs/single-node-restate-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ import { Construct } from "constructs";
import * as logs from "aws-cdk-lib/aws-logs";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as iam from "aws-cdk-lib/aws-iam";
import * as elb_v2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { ApplicationProtocol } from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { InstanceTarget } from "aws-cdk-lib/aws-elasticloadbalancingv2-targets";
import * as cdk from "aws-cdk-lib";
import * as acm from "aws-cdk-lib/aws-certificatemanager";
import { RestateInstance } from "./restate-instance";
import { RegistrationProvider } from "./registration-provider";

Expand All @@ -35,7 +31,7 @@ export interface RestateInstanceProps {
/** Log group for Restate service logs. */
logGroup: logs.LogGroup;

/** Tracing mode for Restate services. Disabled by default. */
/** Tracing mode for Restate services. Defaults to {@link TracingMode.DISABLED}. */
tracing?: TracingMode;

/** Prefix for resources created by this construct that require unique names. */
Expand All @@ -46,30 +42,30 @@ export interface RestateInstanceProps {

/** Amazon Distro for Open Telemetry Docker image tag. Defaults to `latest`. */
adotTag?: string;

/** Optional certificate for ingress endpoint. If unspecified, a plain HTTP listener will be created. */
certificate?: acm.ICertificate;
}

/**
* Creates a Restate service deployment backed by a single EC2 instance,
* suitable for development and testing purposes.
* suitable for development and testing purposes. The instance will be created
* in a dedicated VPC (unless one is provided). EC2 instance will be allocated
* a public IP address.
*/
export class SingleNodeRestateInstance extends Construct implements RestateInstance {
readonly instance: ec2.Instance;
readonly invokerRole: iam.Role;
readonly invokerRole: iam.IRole;
readonly vpc: ec2.Vpc;

readonly publicIngressEndpoint: string;
readonly privateIngressEndpoint: string;
readonly ingressEndpoint: string;
readonly metaEndpoint: string;
readonly registrationProviderToken: cdk.CfnOutput;

constructor(scope: Construct, id: string, props: RestateInstanceProps) {
super(scope, id);

this.vpc = new ec2.Vpc(this, "RestateVpc", {
this.vpc = new ec2.Vpc(this, "Vpc", {
maxAzs: 3,
createInternetGateway: true,
natGateways: 0,
});

this.invokerRole = new iam.Role(this, "InstanceRole", {
Expand Down Expand Up @@ -103,6 +99,7 @@ export class SingleNodeRestateInstance extends Construct implements RestateInsta

const restateInstance = new ec2.Instance(this, "Host", {
vpc: this.vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
instanceType: new ec2.InstanceType("t4g.micro"),
machineImage: ec2.MachineImage.latestAmazonLinux2023({
cpuType: ec2.AmazonLinuxCpuType.ARM_64,
Expand All @@ -121,77 +118,30 @@ export class SingleNodeRestateInstance extends Construct implements RestateInsta
const restateInstanceSecurityGroup = new ec2.SecurityGroup(this, "RestateSecurityGroup", {
vpc: this.vpc,
securityGroupName: "RestateSecurityGroup",
description: "Allow inbound traffic to Restate",
});

const ingressLoadBalancer = new elb_v2.ApplicationLoadBalancer(this, "RestateAlb", {
vpc: this.vpc,
internetFacing: true,
});
const targetGroup = new elb_v2.ApplicationTargetGroup(this, "TargetGroup", {
vpc: this.vpc,
protocol: elb_v2.ApplicationProtocol.HTTP,
port: RESTATE_INGRESS_PORT,
targets: [new InstanceTarget(restateInstance)],
healthCheck: {
protocol: elb_v2.Protocol.HTTP,
path: "/grpc.health.v1.Health/Check",
interval: cdk.Duration.seconds(60),
},
});
ingressLoadBalancer.addListener("Listener", {
port: props.certificate ? 443 : 80,
protocol: props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP,
defaultTargetGroups: [targetGroup],
certificates: props.certificate ? [elb_v2.ListenerCertificate.fromCertificateManager(props.certificate)] : [],
description: "Restate service ACLs",
});
restateInstance.addSecurityGroup(restateInstanceSecurityGroup);

const albSecurityGroup = new ec2.SecurityGroup(this, "AlbSecurityGroup", {
vpc: this.vpc,
description: "ALB security group",
allowAllOutbound: false,
});
albSecurityGroup.addEgressRule(
restateInstanceSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(RESTATE_INGRESS_PORT),
"Allow outbound HTTP traffic to Restate ingress",
"Allow traffic from anywhere to Restate ingress",
);
ingressLoadBalancer.addSecurityGroup(albSecurityGroup);

restateInstanceSecurityGroup.addIngressRule(
albSecurityGroup,
ec2.Port.tcp(RESTATE_INGRESS_PORT),
"Allow traffic from ALB to Restate ingress",
ec2.Peer.anyIpv4(),
ec2.Port.tcp(RESTATE_META_PORT),
"Allow traffic from anywhere to Restate meta",
);

// These rules allow the service registration component to trigger service discovery as needed; the requests
// originate from a VPC-bound Lambda function that backs the custom resource.
this.vpc.privateSubnets.forEach((subnet) => {
restateInstanceSecurityGroup.addIngressRule(
ec2.Peer.ipv4(subnet.ipv4CidrBlock),
ec2.Port.tcp(RESTATE_META_PORT),
"Allow traffic from the VPC to Restate meta",
);
});
this.vpc.privateSubnets.forEach((subnet) => {
restateInstanceSecurityGroup.addIngressRule(
ec2.Peer.ipv4(subnet.ipv4CidrBlock),
ec2.Port.tcp(RESTATE_INGRESS_PORT),
"Allow traffic from the VPC to Restate ingress",
);
});
restateInstance.addSecurityGroup(restateInstanceSecurityGroup);

const registrationProvider = new RegistrationProvider(this, "RegistrationProvider", { vpc: this.vpc });
const registrationProvider = new RegistrationProvider(this, "RegistrationProvider", {});
this.registrationProviderToken = new cdk.CfnOutput(this, "RegistrationProviderToken", {
description:
"Custom resource provider service token, needed by the Restate service registry component to trigger discovery",
exportName: [props.prefix, "RegistrationProviderToken"].join("-"),
value: registrationProvider.serviceToken,
});

this.publicIngressEndpoint = `${props.certificate ? "https" : "http"}://${ingressLoadBalancer.loadBalancerDnsName}`;
this.privateIngressEndpoint = `http://${this.instance.instancePrivateDnsName}:${RESTATE_INGRESS_PORT}`;
this.metaEndpoint = `http://${this.instance.instancePrivateDnsName}:${RESTATE_META_PORT}`;
this.ingressEndpoint = `http://${restateInstance.instancePublicDnsName}:${RESTATE_INGRESS_PORT}`;
this.metaEndpoint = `http://${restateInstance.instancePublicDnsName}:${RESTATE_META_PORT}`;
}
}