【CDK v2 Go】Go で IaC - VPNサーバーをたてる -
モチベーション
- 我が家では感じの良い営業さんにのせられ SoftbankAir を契約しているのでIPを固定するのは無理
- 別途、固定IPを契約するほどの熱意もお金も無い
- いつもは
TypeScript
でインフラを書いてるけど、より慣れているGo
でも書いてみたい
ソース
内容
VPNサーバについては https://github.com/siomiz/SoftEtherVPN を利用しました。
色々あったのですが参考になる記事も多かった+シンプルだったのでこちらを使用させてもらいました。
構成については色々悩んでいてベストな構成が定まりきっていないのですが、現状は 「stack」 と 「resources」 に分けるのが好みです。
stack
stack
≒ CFn Stack
となるようにしています。
stack
パッケージ内で 複数の resources
を生成して一つの CFn Stack
が生成されるようにしています。
色々書いていた結果、この方法が依存関係の確認や頭の切り分けがしやすいなぁと思っています。
抜粋
// VPC を作る
vpc, publicSubnet := resources.NewVPC(scope, stack)
// EC2 作成時には VPC と配置するサブネットが必要なので引数として渡す
resources.NewEC2(scope, stack, &resources.CdkEc2Props{
VPC: vpc,
PublicSubnet: publicSubnet,
})
resources
resources
≒ AWS サービス
のようなイメージです。
以下の画像で言うと EC2
とか VPC
とか S3
とかのまとまりで分けたい気持ちです。
今回の例では VPC
と EC2
を作成しています。 以下ポイントだけピックアップします。
VPC
特になし!
パブリックなサブネットが一つだけあるVPCを切っています。(CIDRは適当)
めちゃくちゃ単純なので内容は割愛します。
EC2
キーペアについてはコンソール上から事前に手動で作成しています。
コストのことを考えて t4g.nano
で立てています。個人で使う分には十分です。
const (
imageId string = "ami-004332b441f90509b"
instanceType string = "t4g.nano"
keyName string = "VPNServerKey"
)
セキュリティグループについては https://hub.docker.com/r/siomiz/softethervpn/ のSetup に従いポートを開放しています。
SSHは必要ないですが動作の確認とかに使う間は開放しています。
SecurityGroupIngress: &[]*awsec2.CfnSecurityGroup_IngressProperty{
{
IpProtocol: jsii.String("tcp"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(22),
ToPort: jsii.Number(22),
},
{
IpProtocol: jsii.String("udp"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(500),
ToPort: jsii.Number(500),
},
{
IpProtocol: jsii.String("udp"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(4500),
ToPort: jsii.Number(4500),
},
{
IpProtocol: jsii.String("tcp"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(1701),
ToPort: jsii.Number(1701),
},
},
インスタンスの生成部分です。
UserData
に SoftEther VPN
を走らせるスクリプトを渡します。
これで起動時に自動的に立ち上がってくれるはずです。
instance := awsec2.NewCfnInstance(stack, jsii.String("EC2Instance"), &awsec2.CfnInstanceProps{
ImageId: jsii.String(imageId),
InstanceType: jsii.String(instanceType),
SubnetId: props.PublicSubnet.Ref(),
SecurityGroupIds: jsii.Strings(*vpnServerSG.AttrGroupId()),
KeyName: jsii.String(keyName),
UserData: jsii.String(base64.StdEncoding.EncodeToString(scripts)),
Tags: &[]*awscdk.CfnTag{{Key: jsii.String("Name"), Value: jsii.String("VPNServer")}},
})
SoftEther VPN
を起動させるスクリプトは以下です。
これをどこに置くかが一番悩んだのですが、結局 「embed
したらええか…」となった結果ここに収まりました。(今も悩んでいる)
#!/bin/bash
sudo yum update -y
sudo amazon-linux-extras install docker
sudo service docker start
sudo systemctl enable docker
sudo docker run --rm -d --privileged -p 500:500/udp -p 4500:4500/udp -p 1701:1701/tcp \
-e PSK='yourkey' \
-e USERS='user:password' \
siomiz/softethervpn
yourkey
,user:password
は適宜読み替えて下さい。
デプロイ
> cdk deploy --all --profile your-profile
とやれば一撃で作成してくれます。
権限周りなどややこしい制限がない限り「セキュリティグループ作っていいですか?」ぐらいの確認だけでサクッと作成出来るかと思います。
書いていて嬉しかった事
- いつもの業務では
Go
でお仕事をしているので、書き味が同じなのは嬉しい。- Web界隈ではサーバサイド兼インフラも触るみたいな方も多いのかな?と思いますのでこれはメリットだと思います。
- フォーマットとかリンターの設定も使い回せるのでいつも
Go
で開発している人は書き始める障壁が低いと思います。 -
package
でまとめられるのも可読性が良いと感じました。
つらみ
CDK Go
でのつらみ(?)も少しあったので書いておきたいと思います。
- パラメータが必須なのかどうか分かりづらい。
- 構造体のタグを見れば分かるのですが何度か失敗しました。
- 結局
CDK
がnpm
管理なので「全てGo」とはいかない。-
CDK
本体のバージョン管理が煩雑なのは変わらないです。(Go関係ない)
-
最後に(余談)
- フィールド名の
~~~Id
は~~~ID
に出来ないものか? - 構成についてはもっと良い構成がありそうなのでもっと真剣に考えたいです。
参考
- https://qiita.com/sammrai/items/fc167b11ae5b0d71fe32
- https://www.happylifecreators.com/blog/20220606/
追記
コスト
このままだと $2/月 くらい??? (704%増加の文字面は怖い)
あんまり使っていないのもありますが安すぎんか???(嬉しい)
Discussion