kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Piculet の動作を詳細に確認して運用フローを考えてみた

前回は Piculet を使ってセキュリティグループ設定と Groupfile の比較を CircleCI でチェックできるところまで試した.興味があったら是非以下の記事を見てもらえると!

kakakakakku.hatenablog.com

今回は前回の続きで,主に --apply オプションを使った反映を試してみた.最後に Piculet を運用に活用するならどんなフローになるか?を考えてみた.

新規セキュリティグループを反映してみる

まず,以下のような Groupfile を用意した."dev-web" という名前のセキュリティグループで,特定の IP アドレス(今回は 1.2.3.4)から http アクセスを許可する設定にしている.

# -*- mode: ruby -*-
# vi: set ft=ruby :
ec2 "vpc-xxxxxxxx" do
  security_group "dev-web" do
    description "web for dev env"

    ingress do
      permission :tcp, 80..80 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

反映する前に --apply オプションと合わせて使える --dry-run オプションを使って検証をしてみた.ちなみに --dry-run オプションは Piculet 独自のオプションではなくて AWS SDK for Ruby の API で用意されたオプションだ.以下のように意図した通りにセキュリティグループが反映されるようなログが出力された.

$ piculet --apply --dry-run --names dev-web
Apply `Groupfile` to SecurityGroup (dry-run)
Create SecurityGroup: vpc-xxxxxxxx > dev-web (dry-run)
Create Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 80..80 (dry-run)
  authorize 1.2.3.4/32 (dry-run)
No change

次に実際に反映してみた.成功!

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
Create SecurityGroup: vpc-xxxxxxxx > dev-web
Create Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 80..80
  authorize 1.2.3.4/32

正しく反映されていた.

f:id:kakku22:20161127171913p:plain

ちなみに Piculet では冪等性の考慮がされていて,全く同じ DSL であれば何度反映してもスキップとなる.ただし,後述する通り,グループ名とグループ説明を修正する場合は新規作成となるため,注意が必要になる.

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
No change

ルールを変更してみる

次に Groupfile を修正して 80443 にして反映してみた.

# -*- mode: ruby -*-
# vi: set ft=ruby :
ec2 "vpc-xxxxxxxx" do
  security_group "dev-web" do
    description "web for dev env"

    ingress do
      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

既存ルール 80 は削除されて,新規ルール 443 が反映された.グループ ID は同じで,副作用なく反映できていた.

$ piculet --apply --dry-run --names dev-web
Apply `Groupfile` to SecurityGroup (dry-run)
Delete Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 80..80 (dry-run)
  revoke 1.2.3.4/32 (dry-run)
Create Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443 (dry-run)
  authorize 1.2.3.4/32 (dry-run)
No change

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
Delete Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 80..80
  revoke 1.2.3.4/32
Create Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443
  authorize 1.2.3.4/32

ingress にグループ名を指定してみる

次に groups を使ってグループ名を指定してみる.ちなみに default は存在するグループ名で,known_group は存在しないグループ名とした.

# -*- mode: ruby -*-
# vi: set ft=ruby :
ec2 "vpc-xxxxxxxx" do
  security_group "dev-web" do
    description "web for dev env"

    ingress do
      permission :tcp, 443..443 do
        groups(
          "default",
          "known_group"
        )
      end
    end

    egress do
      permission :any do
        ip_ranges(
          "0.0.0.0/0"
        )
      end
    end
  end
end

恐らく AWS SDK for Ruby の仕様(バグ?)だとは思うが,存在しないグループ名を指定しても --dry-run だと検知できなかった.よって,実際に反映する際にエラーになってしまった.--dry-run で検知できれば良いのに...!

あと1点気になったのは,複数のセキュリティグループを一括で反映するときに一部にエラーが発生しても,全体をロールバックする機能はないということ.ようするにエラーが発生するまでの反映はそのまま apply されてしまう.CloudFormation とは違うという認識を持っておく必要がありそう.

$ piculet --apply --dry-run --names dev-web
Apply `Groupfile` to SecurityGroup (dry-run)
Update Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443 (dry-run)
  authorize default, known_group (dry-run)
  revoke 1.2.3.4/32 (dry-run)
No change

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
Update Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443
  authorize default, known_group
[ERROR] Can't find SecurityGroup: 111111111111/known_group in vpc-xxxxxxxx

テンプレート機能

Piculet にはテンプレート機能があり,共通の DSL を定義しておいて,再利用することができる.管理コンソールでセキュリティグループを管理するときにツライと感じるのは IP アドレスに別名(コメント)を付与することができないところで,特に複数オフィスの IP アドレスを登録しているとパッと見で判断できなくなる.テンプレートにコメントを書いて GitHub で管理しておけば,運用的に助かるし便利機能だと思った.以下のように書ける.

# -*- mode: ruby -*-
# vi: set ft=ruby :
template "https_from_office" do
  permission :tcp, 443..443 do
    ip_ranges(
      "1.2.3.4/32"
    )
  end
end

ec2 "vpc-xxxxxxxx" do
  security_group "dev-web" do
    description "web for dev env"

    ingress do
      include_template "https_from_office"
    end

    egress do
      permission :any do
        ip_ranges(
          "0.0.0.0/0"
        )
      end
    end
  end
end

ただし,テンプレート機能を使う場合,Groupfile をマスタとして管理していく必要がある.もし一時的に管理コンソールで直接修正をして,もう一度 Piculet でエクスポートをするとテンプレートは消えてそのまま展開されてしまう.運用フロー次第かなと.

グループ名とグループ説明を変更してみる(冪等性が保証されない)

webweb2 に修正して反映してみる.

# -*- mode: ruby -*-
# vi: set ft=ruby :
template "https_from_office" do
  permission :tcp, 443..443 do
    ip_ranges(
      "1.2.3.4/32"
    )
  end
end

ec2 "vpc-xxxxxxxx" do
  security_group "dev-web2" do
    description "web2 for dev env"

    ingress do
      include_template "https_from_office"
    end

    egress do
      permission :any do
        ip_ranges(
          "0.0.0.0/0"
        )
      end
    end
  end
end

まず,既存の dev-web セキュリティグループを EC2 に紐付けた状態にした.

$ aws ec2 describe-instances --instance-ids i-xxxxxxxx | jq '.Reservations[].Instances[].SecurityGroups'
[
  {
    "GroupName": "dev-web",
    "GroupId": "sg-11111111"
  }
]

すると,ルールは全て削除されてしまった.ただし,セキュリティグループ自体は [ERROR] resource sg-11111111 has a dependent object のエラーが出て削除されなかった.インスタンスに紐付いている場合,セキュリティグループは残るものの,ルールは全て消えてしまうため,意図的に反映しないと大規模障害の引き金となってしまいそう.

$ piculet --apply --dry-run --names dev-web
Apply `Groupfile` to SecurityGroup (dry-run)
Delete Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443 (dry-run)
  revoke 1.2.3.4/32 (dry-run)
Delete Permission: vpc-xxxxxxxx > dev-web(egress) > any  (dry-run)
  revoke 0.0.0.0/0 (dry-run)
Delete SecurityGroup: vpc-xxxxxxxx > dev-web (dry-run)
No change

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
Delete Permission: vpc-xxxxxxxx > dev-web(ingress) > tcp 443..443
  revoke 1.2.3.4/32
Delete Permission: vpc-xxxxxxxx > dev-web(egress) > any
  revoke 0.0.0.0/0
Delete SecurityGroup: vpc-xxxxxxxx > dev-web
[ERROR] resource sg-11111111 has a dependent object

またグループ説明だけを修正した場合はエラーになる.これは良かった.グループ説明だけを修正した場合に新規セキュリティグループが反映されたら障害になってしまうし.

$ piculet --apply --dry-run --names dev-web
Apply `Groupfile` to SecurityGroup (dry-run)
[WARN] `description` cannot be updated: vpc-xxxxxxxx > dev-web (dry-run)
No change

$ piculet --apply --names dev-web
Apply `Groupfile` to SecurityGroup
[WARN] `description` cannot be updated: vpc-xxxxxxxx > dev-web
No change

運用を考えた

Piculet を活用する運用フローを考えてみた.ただし EC2 や RDS の運用を自動化してるかどうかによっても大きく違うと思うので,あくまで参考まで.

案1. 管理コンソールでの反映を禁止し,全て Piculet を使う場合

基本的に運用メリットが大きいフローだと思う.ただし,既に本番稼働中のサービスに導入するには Piculet の仕様をちゃんと理解して,適切に活用する必要がある.

  • メリット
    • 全ての運用を自動化できる(CircleCI で master にマージされたら反映したり)
    • プルリクベースで反映内容を事前にレビューできる
    • Piculet のテンプレート機能が使える
    • 新規プロジェクトに導入し易い
      • 新規プロジェクトなら部分最適 < 全体最適 だから CloudFormation / Terraform の方が良いかも
  • デメリット
    • 一時的に管理コンソールで変更をしてしまうと簡単に Groupfile との差が生じてしまう
      • 変更を検知できる別の仕組みが必要そう

案2. 管理コンソールでの反映を許容し,部分的に Piculet で反映する場合

  • メリット
    • Piculet で反映する場合は --names オプションを指定して部分的に反映できる
    • 管理コンソールでの反映も許容することである程度自由度を残した運用が可能になる
      • 管理コンソールで反映した場合はすぐに Groupfile をエクスポートして GitHub を最新にする必要がある
      • 前回試した CircleCI で CI するフローを徹底する必要がある
    • 本番稼働中のサービスに導入し易い
  • デメリット
    • 反映を完全に自動化できないため,運用カバーな部分が残ってしまう
    • Groupfile の運用が暗黙知になってインフラ担当が権威的になってしまう可能性がありそう

案3. 全ての反映を管理コンソールで実施し,常に最新の Groupfile を GitHub でバージョン管理する

  • メリット
    • 管理コンソールを使っていた場合に,今までの運用を大きく変えずにセキュリティグループ設定をバージョン管理できる
    • 前回試した CircleCI で CI するフローを徹底することで差分を検知することができる
    • 本番稼働中のサービスに導入し易い
  • デメリット
    • 自動化とは程遠い運用になってしまう

まとめ

前回 と今回で Piculet を一通り試した.とにかく素晴らしい!ただ前回も書いた通り,もう少し README が充実してると導入し易いとは思う.特に反映時の冪等性のあたりなど,仕様を理解しておかないと不安な部分だしなーとは思った.

ちなみに僕が担当してる現場の話で言うと,現在はまだセキュリティグループの運用を全て管理コンソールで行っていて,管理面に課題を感じていた(だからこそ今回 Piculet を試していた).現実的に今回考えた「案2」or「案3」になりそうだけど,提案してみようと思う.

同時に Piculet を運用で使ってる人の話を聞いてみたいと思ってて,タイミング良く 12/08 に Codenize Meetup が開催される!絶対参加したいし抽選に当たることを祈ってる...!!!

codenize.connpass.com