Skip to content
Open
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
165 changes: 126 additions & 39 deletions platform/src/components/aws/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,14 @@ export class Vpc extends Component implements Link.Linkable {
private securityGroup: ec2.SecurityGroup;
private natGateways: Output<ec2.NatGateway[]>;
private natInstances: Output<ec2.Instance[]>;
private natSecurityGroup: Output<ec2.SecurityGroup | undefined>;
private elasticIps: Output<ec2.Eip[]>;
private _publicSubnets: Output<ec2.Subnet[]>;
private _privateSubnets: Output<ec2.Subnet[]>;
private publicRouteTables: Output<ec2.RouteTable[]>;
private privateRouteTables: Output<ec2.RouteTable[]>;
private bastionInstance: Output<ec2.Instance | undefined>;
private bastionSecurityGroup: Output<ec2.SecurityGroup | undefined>;
private cloudmapNamespace: servicediscovery.PrivateDnsNamespace;
private privateKeyValue: Output<string | undefined>;
public static v1 = VpcV1;
Expand All @@ -376,8 +378,10 @@ export class Vpc extends Component implements Link.Linkable {
this.privateRouteTables = output(ref.privateRouteTables);
this.natGateways = output(ref.natGateways);
this.natInstances = output(ref.natInstances);
this.natSecurityGroup = output(ref.natSecurityGroup);
this.elasticIps = ref.elasticIps;
this.bastionInstance = ref.bastionInstance;
this.bastionSecurityGroup = output(ref.bastionSecurityGroup);
this.cloudmapNamespace = ref.cloudmapNamespace;
this.privateKeyValue = output(ref.privateKeyValue);
registerOutputs();
Expand All @@ -396,22 +400,24 @@ export class Vpc extends Component implements Link.Linkable {
const { publicSubnets, publicRouteTables } = createPublicSubnets();
const elasticIps = createElasticIps();
const natGateways = createNatGateways();
const natInstances = createNatInstances();
const { natInstances, natSecurityGroup } = createNatInstances();
const { privateSubnets, privateRouteTables } = createPrivateSubnets();
const bastionInstance = createBastion();
const { bastionInstance, bastionSecurityGroup } = createBastion();
const cloudmapNamespace = createCloudmapNamespace();

this.vpc = vpc;
this.internetGateway = internetGateway;
this.securityGroup = securityGroup;
this.natGateways = natGateways;
this.natInstances = natInstances;
this.natSecurityGroup = natSecurityGroup;
this.elasticIps = elasticIps;
this._publicSubnets = publicSubnets;
this._privateSubnets = privateSubnets;
this.publicRouteTables = publicRouteTables;
this.privateRouteTables = privateRouteTables;
this.bastionInstance = output(bastionInstance);
this.bastionSecurityGroup = bastionSecurityGroup;
this.cloudmapNamespace = cloudmapNamespace;
this.privateKeyValue = output(privateKeyValue);
registerOutputs();
Expand Down Expand Up @@ -466,9 +472,11 @@ export class Vpc extends Component implements Link.Linkable {
)
.ids.apply((ids) => {
if (!ids.length) {
throw new VisibleError(
`Security group not found in VPC ${vpcId}`,
);
vpcId.apply(vpcId => {
throw new VisibleError(
`Security group not found in VPC ${vpcId}`,
);
});
}
return ids[0];
}),
Expand Down Expand Up @@ -582,6 +590,23 @@ export class Vpc extends Component implements Link.Linkable {
}),
),
);
const natSecurityGroup = ec2
.getSecurityGroupsOutput(
{
filters: [
{ name: "tag:sst:is-nat-sg", values: ["true"] },
{ name: "vpc-id", values: [vpcId] },
],
},
{ parent: self },
)
.ids.apply((ids) =>
ids.length
? ec2.SecurityGroup.get(`${name}NatInstanceSecurityGroup`, ids[0], undefined, {
parent: self
})
: undefined,
);
const bastionInstance = ec2
.getInstancesOutput(
{
Expand All @@ -599,6 +624,23 @@ export class Vpc extends Component implements Link.Linkable {
})
: undefined,
);
const bastionSecurityGroup = ec2
.getSecurityGroupsOutput(
{
filters: [
{ name: "tag:sst:is-bastion-sg", values: ["true"] },
{ name: "vpc-id", values: [vpcId] },
],
},
{ parent: self },
)
.ids.apply((ids) =>
ids.length
? ec2.SecurityGroup.get(`${name}BastionSecurityGroup`, ids[0], undefined, {
parent: self
})
: undefined,
);

// Note: can also use servicediscovery.getDnsNamespaceOutput() here, ie.
// ```ts
Expand Down Expand Up @@ -657,8 +699,10 @@ export class Vpc extends Component implements Link.Linkable {
privateRouteTables,
natGateways,
natInstances,
natSecurityGroup,
elasticIps,
bastionInstance,
bastionSecurityGroup,
cloudmapNamespace,
privateKeyValue,
};
Expand Down Expand Up @@ -909,9 +953,13 @@ export class Vpc extends Component implements Link.Linkable {

function createNatInstances() {
return nat.apply((nat) => {
if (nat?.type !== "ec2") return output([]);
if (nat?.type !== "ec2")
return output({
natSecurityGroup: undefined,
natInstances: [] as ec2.Instance[],
});

const sg = new ec2.SecurityGroup(
const natSecurityGroup = new ec2.SecurityGroup(
...transform(
args.transform?.natSecurityGroup,
`${name}NatInstanceSecurityGroup`,
Expand All @@ -933,6 +981,9 @@ export class Vpc extends Component implements Link.Linkable {
cidrBlocks: ["0.0.0.0/0"],
},
],
tags: {
"sst:is-nat-sg": "true",
},
},
{ parent: self },
),
Expand Down Expand Up @@ -994,36 +1045,52 @@ export class Vpc extends Component implements Link.Linkable {
elasticIps,
keyPair,
args.bastion,
]).apply(([zones, publicSubnets, elasticIps, keyPair, bastion]) =>
zones.map((_, i) => {
const instance = new ec2.Instance(
...transform(
args.transform?.natInstance,
`${name}NatInstance${i + 1}`,
{
instanceType: nat.ec2.instance,
ami,
subnetId: publicSubnets[i].id,
vpcSecurityGroupIds: [sg.id],
iamInstanceProfile: instanceProfile.name,
sourceDestCheck: false,
keyName: keyPair?.keyName,
tags: {
Name: `${name} NAT Instance`,
"sst:is-nat": "true",
...(bastion && i === 0 ? { "sst:is-bastion": "true" } : {}),
natSecurityGroup,
]).apply(
([
zones,
publicSubnets,
elasticIps,
keyPair,
bastion,
natSecurityGroup,
]) => ({
natInstances: zones.map((_, i) => {
const instance = new ec2.Instance(
...transform(
args.transform?.natInstance,
`${name}NatInstance${i + 1}`,
{
instanceType: nat.ec2.instance,
ami,
subnetId: publicSubnets[i].id,
vpcSecurityGroupIds: [natSecurityGroup.id],
iamInstanceProfile: instanceProfile.name,
sourceDestCheck: false,
keyName: keyPair?.keyName,
tags: {
Name: `${name} NAT Instance`,
"sst:is-nat": "true",
...(bastion && i === 0
? { "sst:is-bastion": "true" }
: {}),
},
},
},
{ parent: self },
),
);
{ parent: self },
),
);

new ec2.EipAssociation(`${name}NatInstanceEipAssociation${i + 1}`, {
instanceId: instance.id,
allocationId: elasticIps[i]?.id ?? nat.ip![i],
});
new ec2.EipAssociation(
`${name}NatInstanceEipAssociation${i + 1}`,
{
instanceId: instance.id,
allocationId: elasticIps[i]?.id ?? nat.ip![i],
},
);

return instance;
return instance;
}),
natSecurityGroup,
}),
);
});
Expand Down Expand Up @@ -1152,11 +1219,19 @@ export class Vpc extends Component implements Link.Linkable {
function createBastion() {
return all([args.bastion, natInstances, keyPair]).apply(
([bastion, natInstances, keyPair]) => {
if (!bastion) return undefined;
if (!bastion)
return {
bastionSecurityGroup: undefined,
bastionInstance: undefined,
};

if (natInstances.length) return natInstances[0];
if (natInstances.length)
return {
bastionSecurityGroup: natSecurityGroup,
bastionInstance: natInstances[0],
};

const sg = new ec2.SecurityGroup(
const bastionSecurityGroup = new ec2.SecurityGroup(
...transform(
args.transform?.bastionSecurityGroup,
`${name}BastionSecurityGroup`,
Expand All @@ -1178,6 +1253,9 @@ export class Vpc extends Component implements Link.Linkable {
cidrBlocks: ["0.0.0.0/0"],
},
],
tags: {
"sst:is-bastion-sg": "true",
}
},
{ parent: self },
),
Expand Down Expand Up @@ -1228,15 +1306,15 @@ export class Vpc extends Component implements Link.Linkable {
},
{ parent: self },
);
return new ec2.Instance(
const bastionInstance = new ec2.Instance(
...transform(
args.transform?.bastionInstance,
`${name}BastionInstance`,
{
instanceType: "t4g.nano",
ami: ami.id,
subnetId: publicSubnets.apply((v) => v[0].id),
vpcSecurityGroupIds: [sg.id],
vpcSecurityGroupIds: [bastionSecurityGroup.id],
iamInstanceProfile: instanceProfile.name,
keyName: keyPair?.keyName,
tags: {
Expand All @@ -1246,6 +1324,7 @@ export class Vpc extends Component implements Link.Linkable {
{ parent: self },
),
);
return { bastionInstance, bastionSecurityGroup };
},
);
}
Expand Down Expand Up @@ -1333,6 +1412,10 @@ export class Vpc extends Component implements Link.Linkable {
* The Amazon EC2 NAT instances.
*/
natInstances: this.natInstances,
/**
* The Amazon EC2 Security Group for the NAT instances.
*/
natSecurityGroup: this.natSecurityGroup,
/**
* The Amazon EC2 Elastic IP.
*/
Expand All @@ -1357,6 +1440,10 @@ export class Vpc extends Component implements Link.Linkable {
* The Amazon EC2 bastion instance.
*/
bastionInstance: this.bastionInstance,
/**
* The Amazon EC2 Security Group for the bastion instance.
*/
bastionSecurityGroup: this.bastionSecurityGroup,
/**
* The AWS Cloudmap namespace.
*/
Expand Down