てっくらのーとは、触れた技術のメモと日常の記録が少し合わさった個人のサイトです。
AWS CDK を使用して VPN 接続環境をコード化してみた
AWS CDK for python です。
動機
環境をコード化するというところに興味があり、GA される前から Typescirpt で勉強がてら少し触っていたりしていました。さて、何か具体的なものにフォーカスして書いてみたいな、と思い以前作ったVPN接続環境をコード化してみようと思い立ち書いてみました。言語はそのまま Typescript でもよかったのですが、まずは(Typescriptに比べると)慣れている Python で書いてみようと。
環境
$ cdk --version
1.8.0 (build 5244f97)
$ python3 --version
Python 3.7.4
構成図
1AZ にパブリックとプライベートサブネットを1つずつ作成。パブリックに立てたEC2インスタンスと自宅の PC を softetherVPN で接続します。今回 softetherVPN 用のインスタンスは事前に作成している AMI を使用しています。プライベートサブネット側のインスタンスは当初の目的では VPN 経由で接続したいインスタンスなどを立てて使用しますが、今回は立てられることを確認するのみなので一般的な AMI を使用します。セキュリティグループはパブリックサブネット側のみに設定します。
書いたもの
https://github.com/paraselene92/aws-cdk-py
結果
$ cdk deploy --profile [profile]
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
Security Group Changes
┌───┬─────────────────┬─────┬────────────┬────────────────────┐
│ │ Group │ Dir │ Protocol │ Peer │
├───┼─────────────────┼─────┼────────────┼────────────────────┤
│ + │ ${mysg.GroupId} │ In │ TCP 22 │ 192.168.0.0/24 │
(略)
cdk deploy
でデプロイ。--profile [profile]
で認証情報に設定しているプロファイル情報を指定できます。
Do you wish to deploy these changes (y/n)? y
awscdk-py: deploying...
awscdk-py: creating CloudFormation changeset...
0/15 | 21:18:10 | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | awscdk-py User Initiated
0/15 | 21:18:18 | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | awscdk-py User Initiated
0/15 | 21:18:21 | CREATE_IN_PROGRESS | AWS::EC2::InternetGateway | testVpc/IGW (testVpcIGW8765943D)
0/15 | 21:18:21 | CREATE_IN_PROGRESS | AWS::EC2::VPC | testVpc (testVpcCB3A84F3)
(略)
y
で進めるとリソースが作成されていきます。良い感じ。
13/15 | 21:19:32 | CREATE_COMPLETE | AWS::EC2::Instance | softetherInstance
14/15 | 21:19:34 | CREATE_COMPLETE | AWS::EC2::Instance | IsolatedInstance
✅ awscdk-py
Outputs:
awscdk-py.myPublicInstanceattrprivateip = XXX.XXX.XXX.XXX
awscdk-py.myIsolatedInstanceattrprivateip = YYY.YYY.YYY.YYY
awscdk-py.myPublicInstanceattrpublicip = ZZZ.ZZZ.ZZZ.ZZZ
Stack ARN:
arn:aws:cloudformation:us-east-1:--------------:stack/awscdk-py/---------------------------
できました。Outputs
の一部と Stack ARN
は消しています。
softether のインスタンスと、プライベートサブネットに作成したインスタンスの作成成功ログがあります。Output も問題なく動作しています。
AWS コンソール側の表示
こちらもよい感じ。1つのインスタンスはパブリックIPアドレスが振られていることに対し、もう1つはパブリックIPアドレスは振られていない。
感想
aws-ec2.VPC()
がよしなにしてくれる所について
aws-ec2.VPC()
は最低限の引数定義をして生成すると、cdk がよしなに考えてくれて AWS が想定する高可用性ネットワークを意識した構成を作ります。パブリックサブネットには IGW が割り当てられるのはもちろんですが、プライベートサブネットには NATGW を割り当ててくれていて低レイヤに意識を向けさせない作りという感じ。
では今回そうしたのかと言うとそのまま使用してはおらず少し手を加えています。
- サブネットの数はプライベートとパブリックともに1つでよい
- プライベートサブネットにインターネット接続はいらない
前者は subnet_configuration
のパラメータを作成して、後者は private_subnet
の代わりに isolated_subnet
を使用しました。
特に後者は NATGW の数を 0 にして aws-ec2.VPC()
に渡しているのに何で NATGW が割り当てられるんだろうとずっと不思議がっていました。よく見ればドキュメントに記載されているのにね…。
高可用性ネットワークがそのまま当てはまることは稀だと思うので、是非一度試してみて想定する環境との差異を確認するのが吉。
分離
vpc
の cidr
や Name
など最初変数をクラス内にずらずら書いていたのですが記載が多くなり把握しにくくなったので vars.py
を作成してそこに分離しました。
- awscdk_py/vars.py
from aws_cdk import aws_ec2 as ec2
class var:
# vars
def __init__(self):
# vpc
self.vpcName = "testVpc"
self.vpcCidr = "192.168.96.0/20"
(略)
のような。少し考えてこのような形にしたのですが、ちゃんとしたやり方はなんだろうと今ももやもや考えています。
CloudFormation にはある程度親しんでおいたほうが良い
CloudFormation (というかyaml) のフォーマットをもっとプログラマブルに記載できないか?の方針だと思うのですが、結局は CloudFormation をもってリソースを作成することになるし、Cfn
系の低レイヤクラスを使用する場合は特にですが、CloudFormation フォーマットの外観が分かっていないと辛い場面は出てくるのではないかなあと思いました。これはまあ Terraform や pulumi を使用していても同じ話が出てくると思いますが。
ちなみに Terraform も触ってみたいなあと思うのですが、独自言語という気持ちの重みに負け続けています。
今後
書いたものは書いたもので使用とするとして、何か他にも書いてみたい気持ちもありますね。あとはちゃんとした書き方を身に着けたい。