管理コンソールでセキュリティグループ設定を管理するのは限界があると思っていて,例えば以下のような状態になってしまうことがあると思う.
- 必要に応じて日々増えていくルール設定(無意識にポチポチと追加してしまう)
- 使って無さそうだから消したいけど影響が出たら嫌だから残しているルール設定(何のために追加したのか情報が無い)
- 無駄に広く開放されてしまっているルール設定(動作確認のために取り急ぎ設定したまま残ってしまう)
そこで,セキュリティグループ設定もバージョン管理できれば良さそうだと考えて,AWS Community Hero の @sgwr_dts さんが開発した Piculet を検証している.Piculet 以外にも Codenize.tools に AWS のリソースを管理するツールが多く公開されていて,素晴らしすぎる!
インストール
簡単!
$ gem install piculet
エクスポート
簡単!
$ piculet --export --output Groupfile Export SecurityGroup to `Groupfile`
追加で --split
オプションを付けると VPC ごとに Groupfile を分割できる.もし複数 VPC を運用してる場合だと便利な機能だと思う.
$ piculet --export --output Groupfile --split Export SecurityGroup write `./vpc-xxxxxxxx.group` write `Groupfile`
$ cat Groupfile # -*- mode: ruby -*- # vi: set ft=ruby : require 'vpc-xxxxxxxx.group'
また --names
オプションでグループ名を指定すると対象のセキュリティグループを固定することができる.以下は試しに default グループをエクスポートしてみた.
$ piculet --export --output Groupfile --names default Export SecurityGroup to `Groupfile`
$ cat Groupfile # -*- mode: ruby -*- # vi: set ft=ruby : ec2 "vpc-xxxxxxxx" do security_group "default" do description "default VPC security group" ingress do permission :any do groups( "default" ) end end egress do permission :any do ip_ranges( "0.0.0.0/0" ) end end end end
Groupfile
DSL で表現されているため,直感的に理解できて可読性が高い.
- ingress : インバウンド
- egress : アウトバウンド
- permission : プロトコル&ポート
- groups : 送信元(セキュリティグループ)
- ip_ranges : 送信元(IP アドレス)
次に「1.2.3.4/32 から http & https」と「グループ名 "default" から ssh」を許可する設定をしてエクスポートしてみた.正しくエクスポートできている.
# -*- mode: ruby -*- # vi: set ft=ruby : ec2 "vpc-xxxxxxxx" do security_group "sample-web" do description "sample-web" ingress do permission :tcp, 22..22 do groups( "default" ) end permission :tcp, 80..80 do ip_ranges( "1.2.3.4/32" ) end permission :tcp, 443..443 do ip_ranges( "1.2.3.4/32" ) end end egress do permission :any do ip_ranges( "0.0.0.0/0" ) end end end end
JSON サポート
--format=json
を追加すると JSON 形式で Groupfile をエクスポートできる.Groupfile をツールで処理する場合などは DSL より JSON の方が良さそう.
$ piculet --export --output Groupfile --names default --format=json Export SecurityGroup to `Groupfile`
{ "vpc-xxxxxxxx": { "sg-11111111": { "name": "default", "description": "default VPC security group", "tags": { }, "owner_id": "111111111111", "ingress": [ { "protocol": "any", "port_range": null, "ip_ranges": [ ], "groups": [ { "id": "sg-11111111", "name": "default", "owner_id": "111111111111" } ] } ], "egress": [ { "protocol": "any", "port_range": null, "ip_ranges": [ "0.0.0.0/0" ], "groups": [ ] } ] } } }
強制上書き
--export
の挙動は強制上書きとなっていて,例えば「管理コンソール上の設定」と「Groupfile」がコンフリクトしているような場合,強制的に「管理コンソール上の設定」がエクスポートされる.まぁ実際に稼働している設定だし,適切な挙動だと思う.
CircleCI で CI をできるように
生成した Groupfile を GitHub で管理すれば,セキュリティグループ設定をバージョン管理することができる.さらに Groupfile の更新が形骸化しないように CircleCI で CI できたら良いなと思って試した.
事前準備
以下の環境変数を CircleCI 側に登録しておく.
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION
IAM は CircleCI 用に作成した.CI するだけなら以下で良さそう.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt0000000000000", "Effect": "Allow", "Action": [ "ec2:DescribeSecurityGroups", "ec2:DescribeTags", "iam:GetUser" ], "Resource": [ "*" ] } ] }
circle.yml
Piculet に diff 系のオプションは無かったため,CircleCI 上で diff 結果を判定するようにした.
machine: timezone: Asia/Tokyo ruby: version: 2.3.1 dependencies: pre: - gem install piculet test: post: - piculet --export --output Groupfile.circleci - diff Groupfile Groupfile.circleci
結果
良さ!
気になったところ
IAM ポリシーで iam:GetUser
を許可する場合と許可しない場合で DSL の groups
のエクスポート結果が異なっていた.仕様だとは思うけど,実際にコードを読んで原因を探ってみたいなと思う.
iam:GetUser 許可
「許可」の場合は「グループ名」になった.
ingress do permission :any do groups( "default" ) end end
iam:GetUser 非許可
「非許可」の場合は「グループ ID」になった.
ingress do permission :any do groups( ["111111111111", "sg-11111111"] ) end end
まとめと次回
今回は Piculet を使って以下を試してみた.セキュリティグループ設定をバージョン管理できるの最高!ただ,もう少し README にオプションの説明など,詳細なドキュメントが書かれてたら良いのになーと思った.
- セキュリティグループ設定をエクスポートした
- CircleCI で CI をできるようにした
さらに Piculet は --apply
オプションで実際に反映することもできる.次回は --apply
を試す!
関連記事
Mackerel の監視ルールを CircleCI で CI する話を前に書いた.インフラ系の設定値をバージョン管理して,プルリクエストを通してレビューできる開発プロセスはとにかく便利!