この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
NAT ゲートウェイ作ります!
前回の記事はこちら。
AWS 構成図
前回作成した Elastic IP を使用して、パブリックサブネットに配置する NAT ゲートウェイを作成していきます。
設計
NAT ゲートウェイのプロパティはこちら。
リソース名 | サブネット | Elastic IP |
---|---|---|
devio-stg-ngw-1a | devio-stg-subnet-public-1a | devio-stg-eip-ngw-1a |
devio-stg-ngw-1c | devio-stg-subnet-public-1c | devio-stg-eip-ngw-1c |
2 つの NAT ゲートウェイを作成します。
サブネットと Elastic IP はそれぞれ以前作成したものを設定します。
実装
NAT ゲートウェイに関する処理を行うクラスはこちら。
lib/resource/natGateway.ts
import * as cdk from '@aws-cdk/core';
import { CfnNatGateway, CfnSubnet, CfnEIP } from '@aws-cdk/aws-ec2';
import { Resource } from './abstract/resource';
interface ResourceInfo {
readonly id: string;
readonly resourceName: string;
readonly allocationId: () => string;
readonly subnetId: () => string;
readonly assign: (natGateway: CfnNatGateway) => void;
}
export class NatGateway extends Resource {
public ngw1a: CfnNatGateway;
public ngw1c: CfnNatGateway;
private readonly subnetPublic1a: CfnSubnet;
private readonly subnetPublic1c: CfnSubnet;
private readonly elasticIpNgw1a: CfnEIP;
private readonly elasticIpNgw1c: CfnEIP;
private readonly resourcesInfo: ResourceInfo[] = [
{
id: 'NatGateway1a',
resourceName: 'ngw-1a',
allocationId: () => this.elasticIpNgw1a.attrAllocationId,
subnetId: () => this.subnetPublic1a.ref,
assign: natGateway => this.ngw1a = natGateway
},
{
id: 'NatGateway1c',
resourceName: 'ngw-1c',
allocationId: () => this.elasticIpNgw1c.attrAllocationId,
subnetId: () => this.subnetPublic1c.ref,
assign: natGateway => this.ngw1c = natGateway
}
];
constructor(
subnetPublic1a: CfnSubnet,
subnetPublic1c: CfnSubnet,
elasticIpNgw1a: CfnEIP,
elasticIpNgw1c: CfnEIP
) {
super();
this.subnetPublic1a = subnetPublic1a;
this.subnetPublic1c = subnetPublic1c;
this.elasticIpNgw1a = elasticIpNgw1a;
this.elasticIpNgw1c = elasticIpNgw1c;
};
createResources(scope: cdk.Construct) {
for (const resourceInfo of this.resourcesInfo) {
const natGateway = this.createNatGateway(scope, resourceInfo);
resourceInfo.assign(natGateway);
}
}
private createNatGateway(scope: cdk.Construct, resourceInfo: ResourceInfo): CfnNatGateway {
const natGateway = new CfnNatGateway(scope, resourceInfo.id, {
allocationId: resourceInfo.allocationId(),
subnetId: resourceInfo.subnetId(),
tags: [{
key: 'Name',
value: this.createResourceName(scope, resourceInfo.resourceName)
}]
});
return natGateway;
}
}
NAT ゲートウェイ生成時には allocationId
と subnetId
を指定する必要があります。これらは動的に取得したいため、ResourceInfo
インタフェースで関数として定義しています。
allocationId: () => this.elasticIpNgw1a.attrAllocationId,
subnetId: () => this.subnetPublic1a.ref,
resourcesInfo
でこのように指定することで、各変数から getter のように取得できます。
なお、allocationId は CfnEIP インスタンスの attrAllocationId
で取得しなければなりません。ref
で取得できる値は IP アドレス となるのでご注意ください。(ハマリポイントです)
メインのプログラムはこちら。
ハイライト部分を追記しました。
lib/devio-stack.ts
import * as cdk from '@aws-cdk/core';
import { Vpc } from './resource/vpc';
import { Subnet } from './resource/subnet';
import { InternetGateway } from './resource/internetGateway';
import { ElasticIp } from './resource/elasticIp';
import { NatGateway } from './resource/natGateway';
export class DevioStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// VPC
const vpc = new Vpc();
vpc.createResources(this);
// Subnet
const subnet = new Subnet(vpc.vpc);
subnet.createResources(this);
// Internet Gateway
const internetGateway = new InternetGateway(vpc.vpc);
internetGateway.createResources(this);
// Elastic IP
const elasticIp = new ElasticIp();
elasticIp.createResources(this);
// NAT Gateway
const natGateway = new NatGateway(
subnet.public1a,
subnet.public1c,
elasticIp.ngw1a,
elasticIp.ngw1c
);
natGateway.createResources(this);
}
}
今回はコンストラクタに渡す引数が多めです。しかし、このように書くことで関連するリソースがわかりやすくなっていますね。
テスト
テストコードはこちら。
test/resource/natGateway.test.ts
import { expect, countResources, haveResource } from '@aws-cdk/assert';
import * as cdk from '@aws-cdk/core';
import * as Devio from '../../lib/devio-stack';
test('NatGateway', () => {
const app = new cdk.App();
const stack = new Devio.DevioStack(app, 'DevioStack');
expect(stack).to(countResources('AWS::EC2::NatGateway', 2));
expect(stack).to(haveResource('AWS::EC2::NatGateway', {
Tags: [{ 'Key': 'Name', 'Value': 'undefined-undefined-ngw-1a' }]
}));
expect(stack).to(haveResource('AWS::EC2::NatGateway', {
Tags: [{ 'Key': 'Name', 'Value': 'undefined-undefined-ngw-1c' }]
}));
});
以下を確認しています。
- NAT ゲートウェイリソースが 2 つあること
- 各 NAT ゲートウェイのリソース名が正しいこと
確認
マネジメントコンソール上でリソースを確認してみましょう。
きちんと作成されていますね。
CloudFormation 版
今回のコードを CFn で書くと以下のようになります。
NatGateway1a:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- ElasticIpNgw1a
- AllocationId
SubnetId:
Ref: SubnetPublic1a
Tags:
- Key: Name
Value: devio-stg-ngw-1a
NatGateway1c:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- ElasticIpNgw1c
- AllocationId
SubnetId:
Ref: SubnetPublic1c
Tags:
- Key: Name
Value: devio-stg-ngw-1c
GitHub
今回のソースコードは コチラ です。
おわりに
これでインターネットにアクセスする口はできました。
ネットワークに関して作成したいリソースはあと 2 つ。
- ルートテーブル
- ネットワーク ACL
順に作っていきましょう。