Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Inside of awspec -AWSをテストする方法。そしてその中のはなし-

Inside of awspec -AWSをテストする方法。そしてその中のはなし-

JAWS Festa 東海道 2016

Ken’ichiro Oyama

October 22, 2016
Tweet

More Decks by Ken’ichiro Oyama

Other Decks in Technology

Transcript

  1. Inside of awspec
    -AWSをテストする⽅法。そしてその中のはなし-
    Kenʼichiro Oyama
    Fusic Co.,Ltd.
    2016.10.22
    1
    JAWS Festa 2016

    View Slide

  2. Who
    2
    JAWS Festa 2016

    View Slide

  3. k1LoW
      Kenʼichiro Oyama
      @k1LoW
      Fusic Co.,Ltd. エンジニア
      基盤ユニット テックリード
      フクオカ カラ キマシタ
      JAWS-UG福岡に出没します
      GitHub organizations
      fukuokarb / dotcake / emacs-jp / etc.
      好きなAWSサービス
    3
    JAWS Festa 2016

    View Slide

  4. AWSをテストする
    4
    JAWS Festa 2016

    View Slide

  5. の前に
    5
    JAWS Festa 2016

    View Slide

  6. AWS”で”テストする話を
    6
    JAWS Festa 2016

    View Slide

  7. CM
    7
    JAWS Festa 2016

    View Slide

  8. ٙࣅσʔλͰ*P5։ൃΛՃ଎͢Δ
    ࣄલЌొ࿥ड෇த

    IUUQTNPDLNPDLDPNQSF

    View Slide

  9. /CM
    9
    JAWS Festa 2016

    View Slide

  10. 10
    JAWS Festa 2016

    View Slide

  11. awspec
      AWSリソースの構成テストツール
      http://github.com/k1LoW/awspec
      構築したAWSリソースをRSpecなDSLでテストが可能
    11
    JAWS Festa 2016

    View Slide

  12. ec2
     describe ec2('my-ec2-tag-name') do
      it { should be_running }
      its(:instance_id) { should eq 'i-ec12345a' }
      its(:instance_type) { should eq ’t2.small' }
      its(:public_ip_address) { should eq '123.0.456.789' }
      it { should have_security_group('my-sg-name') }
      it { should belong_to_vpc('my-vpc') }
      it { should belong_to_subnet('subnet-1234a567') }
      it { should have_eip('123.0.456.789') }
      it { should be_disabled_api_termination }
     end
    12
    JAWS Festa 2016

    View Slide

  13. route53_hosted_zone
     describe route53_hosted_zone('example.com.') do
      it { should exist }
      its(:resource_record_set_count) { should eq 5 }
      it { should have_record_set('example.com.').a('123.456.7.890') }
      it { should have_record_set('example.com.').mx('10 mail.example.com') }
      it { should
    have_record_set('mail.example.com.').a('123.456.7.890').ttl(3600) }
      ns = 'ns-123.awsdns-45.net.
     ns-6789.awsdns-01.org.
     ns-2345.awsdns-67.co.uk.
     ns-890.awsdns-12.com.'
      it { should have_record_set('example.com.').ns(ns) }
      it { should have_record_set('s3.example.com.').alias('s3-website-us-
    east-1.amazonaws.com.', 'Z2ABCDEFGHIJKL') }
     end
    13
    JAWS Festa 2016

    View Slide

  14. Resource Types (v.0.57.1)
      ami
      autoscaling_group
      cloudtrail
      cloudwatch_alarm
      cloudwatch_event
      directconnect_virtual
      nterface
      ebs
      ec2
      elasticache
      elasticache_cache_par
    ameter_group
      elasticsearch
      elb
      iam_group
      iam_policy
      iam_role
      iam_user
      kms
      lambda
      launch_configuration
      nat_gateway
      network_acl
      network_interface
      rds
      rds_db_cluster_para
    meter_group
      rds_db_parameter_gr
    oup
      route53_hosted_zone
      route_table
      s3_bucket
      security_group
      ses_identity
      subnet
      vpc
      cloudfront_distributio
    n
      elastictranscoder_pipe
    line
      waf_web_acl
    14
    JAWS Festa 2016

    View Slide

  15. has 36 resource types
    15
    JAWS Festa 2016

    View Slide

  16. awspec generate
     ~ > awspec generate
     Commands:
      awspec generate cloudwatch_alarm # Generate cloudwatch_alarm spec
      awspec generate cloudwatch_event # Generate cloudwatch_event spec
      awspec generate directconnect # Generate directconnect spec
      awspec generate ebs # Generate attached ebs spec
      awspec generate ec2 [vpc_id] # Generate ec2 spec from VPC ID (or VPC "Name" tag)
      awspec generate elasticsearch # Generate elasticsearch spec
      awspec generate elb [vpc_id] # Generate elb spec from VPC ID (or VPC "Name" tag)
      awspec generate help [COMMAND] # Describe subcommands or one specific subcommand
      awspec generate iam_group # Generate iam_group spec
      awspec generate iam_policy # Generate attached iam_policy spec
      awspec generate iam_role # Generate iam_role spec
      awspec generate iam_user # Generate iam_user spec
      awspec generate kms # Generate kms spec
      awspec generate lambda # Generate lambda spec
      awspec generate nat_gateway [vpc_id] # Generate nat_gateway spec from VPC ID (or VPC "Name" tag)
      awspec generate network_acl [vpc_id] # Generate network_acl spec from VPC ID (or VPC "Name" tag)
      awspec generate network_interface [vpc_id] # Generate network_interface spec from VPC ID (or VPC "Name" tag)
      awspec generate rds [vpc_id] # Generate rds spec from VPC ID (or VPC "Name" tag)
      awspec generate route53_hosted_zone [example.com.] # Generate route53_hosted_zone spec from Domain name
      awspec generate route_table [vpc_id] # Generate route_table spec from VPC ID (or VPC "Name" tag)
      awspec generate s3_bucket [backet_name] # Generate s3_bucket spec from S3 bucket name. if NO args, Generate all.
      awspec generate security_group [vpc_id] # Generate security_group spec from VPC ID (or VPC "Name" tag)
      awspec generate subnet [vpc_id] # Generate subnet spec from VPC ID (or VPC "Name" tag)
      awspec generate vpc [vpc_id] # Generate vpc spec from VPC ID (or VPC "Name" tag)
    16
    JAWS Festa 2016

    View Slide

  17. can generate 23 type spec
    17
    JAWS Festa 2016

    View Slide

  18. Inside of awspec
    18
    JAWS Festa 2016

    View Slide

  19. 19
    JAWS Festa 2016

    View Slide

  20. awspec written by Ruby
      aws-sdk-rubyの開発が活発だった
      re:Invent中の発表とSDKの新機能リリースがほぼリアル
    タイム
      Serverspecの良さを感じていた
      Serverspec本も相当勉強になる
      同じようなDSLでテストをしたかった
      Fukuoka.rbがあった
      事実、内部実装でかなり助けてもらった
      http://k1low.hatenablog.com/entry/2015/12/11/185728
    20
    JAWS Festa 2016

    View Slide

  21. tree -d awspec/
    !"" bin
    !"" doc
    # $"" _resource_types
    !"" exe
    !"" lib
    # $"" awspec
    # !"" command
    # !"" ext
    # !"" generator
    # # !"" doc
    # # # $"" type
    # # $"" spec
    # !"" helper
    # # $"" finder
    # !"" matcher
    # !"" stub
    # $"" type
    $"" spec
    21
    JAWS Festa 2016

    View Slide

  22. awspec toolbox
    22
    JAWS Festa 2016

    View Slide

  23. bundle exec bin/toolbox template ec2
    23
    JAWS Festa 2016

    View Slide

  24. bundle exec bin/toolbox template
      awspecに新しいリソースタイプを追加するときに利⽤
    するコマンド
      $ bundle exec bin/toolbox template redshift
      リソースタイプ作成に最低限必要なファイルが⽣成される
      ⽣成されたファイルを他のリソースタイプの書き⽅をマネて
    修正すればだいたいOK
    24
    JAWS Festa 2016

    View Slide

  25. bundle exec bin/toolbox docgen
    25
    JAWS Festa 2016

    View Slide

  26. bundle exec bin/toolbox docgen
      awspecのソースコードからドキュメントを作成するコ
    マンド
      awspecはドキュメントジェネレータまで内包している
    っ!!
      Awspec::Generator::Doc::Type:*
      doc/_resource_types/*.md
      ドキュメントもプログラムで⽣成することでaws-sdk-
    rubyのリリーススピードについていく
    26
    JAWS Festa 2016

    View Slide

  27. つまり
    27
    JAWS Festa 2016

    View Slide

  28. I want your contribution!!
    28
    JAWS Festa 2016

    View Slide

  29. “AWS”をテストする
    29
    JAWS Festa 2016

    View Slide

  30. “AWS”をテストするわけではない
      “AWS上で⾃分たちが構築したリソース構成”をテスト
    する
      意図した構成で構築できているか?
      リソース構成
      セキュリティ
      運⽤中も意図した構成のままでいるか?
      リソース構成に対しての外形監視に近い
      チェック
    30
    JAWS Festa 2016

    View Slide

  31. AWSのリソース構成を
    チェックする⽅法
    31
    JAWS Festa 2016

    View Slide

  32. AWS Config / AWS Config Rules
    32
    JAWS Festa 2016

    View Slide

  33. AWS Config / AWS Config Rules
    AWS Config は完全マネージド型のサービスで、セキュリティとガバナンス
    のため、AWS リソースインベントリ、設定履歴、および設定変更通知とい
    った機能が⽤意されています。Config Rules を使⽤して、AWS Config によ
    って記録された AWS リソース設定を⾃動的にチェックするルールを作成で
    きます。(AWS公式サイトより)
      AWS謹製!
      AWS Configの対応リソース
      ALB、ACM、EC2、RDS、S3、VPC、IAM、EBS、
    CloudTrail
      アカウントにつき最⼤25のルール
    33
    JAWS Festa 2016

    View Slide

  34. Codenize.tools
    34
    JAWS Festa 2016

    View Slide

  35. Codenize.tools
      “Codenize.tools manege any services by DSL.”
      独⾃のDSLでべき等性を担保した形で構成を構築・管
    理できる
      リソースの種類ごとにツールが分かれている
      チェックだけではなく、構築ができる。むしろ構築⽤
      --dry-runでDSLの内容と構築済の構成を⽐較チェック
      AWS版のChefやAnsibleに近い
      既存の構成からDSLをエクスポートができる
      対応リソース
      Route53、Security Groups、ELB、IAM、CloudFormation、EIP、
    CloudWatch Alarm、CloudWatch Logs、VPC Route table、S3
    Bucket Policy、ECR Repository Policy、CloudFront
    35
    JAWS Festa 2016

    View Slide

  36. Terraform
    36
    JAWS Festa 2016

    View Slide

  37. Terraform
      HashiCorp社が提供するオーケストレーションツール
      対象はAWSだけではない
      チェックだけではなく、構築ができる。むしろ構築⽤
      terraform planでDSLの内容と構築済の構成を⽐較チェッ

      既存の構成からDSLをエクスポートができる
      さらにterraformingという強⼒なexport gemもある
      対応リソース
      多すぎて数えたくない
    37
    JAWS Festa 2016

    View Slide

  38. 私的使い分け表
    ※個⼈の⾒解です!
    38
    JAWS Festa 2016
    ⽤途
    エクスポー

    AWSリソー
    スを操作す
    るか
    AWS Config
    AWS Config
    Rules
    AWSマネージドで監視したいとき。
    構成変更のイベントトリガーで動か
    したいとき
    - しない
    Codenize.tools AWSリソース1種類について⼀括し
    て管理したいとき(特にIAM、
    Route53など)
    ◯ する
    Terraform 構成新規構築時(リソースの種類が
    全てある場合)
    ◯ する
    awspec ⼿動で作った環境のチェック
    リソース構成が多い環境での外形監

    ◯ しない

    View Slide

  39. 実際は?
    テストしているの?どんなときにするの?
    どうやっているの?どうなの?なんなの?
    39
    JAWS Festa 2016

    View Slide

  40. わかりません。。
    AWSリソース構成の監視管理事例とかでてこない。。
    40
    JAWS Festa 2016

    View Slide

  41. awspecのPull Requestからみる
    AWSリソース構成テストの
    ユースケース
    41
    JAWS Festa 2016

    View Slide

  42. Pull Request
      Pull Request(PR)… (ざっくり⾔うと)機能追加申請
      AWSリソース構成のテスト⽬的を主とするawspecの
    PRを⾒れば「どういうところで使いたいのか」「どう
    いうユースケースで使っているのか」が⾒えてくるの
    ではないか?
      PRをウォッチしているとできそう
      あ、ちょうどawspecの作者でした
      awspecの中(機能追加)と使う⼈の頭の中(ユースケ
    ース)(想像)を同時にご紹介
    42
    JAWS Festa 2016

    View Slide

  43. Add tag matching support.
    43
    JAWS Festa 2016

    View Slide

  44. Add tag matching support
    44
    JAWS Festa 2016
      各リソースにおいて、タグの保持をテストするマッチ
    ャの追加
      #119 PR by igorlg
     describe ec2('my-ec2') do
      it { should have_tag('Name').value('my-ec2') }
     end

    View Slide

  45. Add ability to search
    for network interface by name
    45
    JAWS Festa 2016

    View Slide

  46. Add ability to search for network interface by name
    46
    JAWS Festa 2016
      Network Interfaceリソースでもタグの保持をできるよ
    うにする修正
      #191 PR by mdolian
     describe network_interface(’eni-12ab3cde') do
      it { should have_tag('Name').value('my-eni') }
     end

    View Slide

  47. タグの活⽤
      みんなタグを活⽤しているっぽい
      役割(ロール)でわけたり
      設定を記述したり
      AMIバックアップ頻度設定とか
      network_interfaceのhave_tagとか忘れていた
      タグが重要だからタグの保持のチェックをしたいので
    は?
    47
    JAWS Festa 2016

    View Slide

  48. Add opened_only matcher
    for security groups.
    48
    JAWS Festa 2016

    View Slide

  49. Add opened_only matcher for security groups.
    JAWS Festa 2016 49
      Security Groupの「このポートだけオープンしている
    こと」をテストするマッチャの追加
      #121 PR by ceaess
     describe security_group('my-sg') do
      its(:outbound) do should be_opened_only(50_000)
      .protocol('tcp')
      .for(%w(100.456.789.012/32 200.567.890.123/32))
      end
     end

    View Slide

  50. 過不⾜ないかを確認したい
      セキュリティグループの「ポートが開いている」だけ
    のテストでは⼼もとない
      セキュリティの設定数のカウントのチェックとの組み合わせ
    で上記を満たすことはできていたが、⾒やすさという点で欲
    しかったのでは?
    50
    JAWS Festa 2016

    View Slide

  51. Add ec2 `have_event()` and
    `have_events()`.
    51
    JAWS Festa 2016

    View Slide

  52. Add ec2 `have_event()` and `have_events()`
    52
    JAWS Festa 2016
      EC2にイベント(再起動イベントなど)があるか確認
    するマッチャの追加
      #131 PR by k1LoW
     describe ec2('my-ec2') do
      it { should have_event('system-reboot') }
     end
     describe ec2(’other-ec2') do
      it { should_not have_events }
     end

    View Slide

  53. イベント通知怖い
      AWSから通知されるスケジュールイベント
      メール⾒過ごしていきなりリブートは怖い
      イベント通知が「無いこと」を確認しておきたい
      should_not
      弊社では⼀部CIで外形監視として利⽤している
      他に気楽な⽅法があれば知りたい。。。
    53
    JAWS Festa 2016

    View Slide

  54. Add ec2
    `have_classiclink_security_group()`
    54
    JAWS Festa 2016

    View Slide

  55. Add ec2 `have_classiclink_security_group()`
    55
    JAWS Festa 2016
      EC2-ClassicがClassicLink先のSecurity Groupをもっ
    ているかどうかを確認するマッチャの追加
      #150 PR by matsuzj
     describe ec2('my-classic-ec2') do
      it { should have_classiclink_security_group('sg-2a3b4cd5') }
      it { should have_classiclink_security_group('my-vpc-security-
    group-name') }
     end

    View Slide

  56. EC2-Classicからの脱却
      おそらく移⾏時のTDD的な活⽤⽅法では?
      EC2-ClassicをEC2 on VPCへ
      コードで管理されていない⼿動で作られた構成
    にテストの恩恵を
    56
    JAWS Festa 2016

    View Slide

  57. Add CloudTrail support to check
    if logging is enabled.
    57
    JAWS Festa 2016

    View Slide

  58. Add CloudTrail support to check if logging is
    enabled.
    58
    JAWS Festa 2016
      CloudTrailでロギングが有効になっているかをテストす
    るマッチャの追加
      #164 PR by arimbun
     describe cloudtrail('my-trail') do
      it { should be_logging }
     end

    View Slide

  59. そもそも
      CloudTrailが動いていればAPIコールは管理で
    きる
      「そもそも」そのCloudTrailが動いていなかっ
    たら?
      ⼼配はつきない
    59
    JAWS Festa 2016

    View Slide

  60. Add shared_context to specify
    region by context
    60
    JAWS Festa 2016

    View Slide

  61. Add shared_context to specify region by context
    61
    JAWS Festa 2016
      複数のリージョンをまたいだテストができるようにす
    る修正
      #187 PR by takaishi
     describe ec2('my-ec2’), region: 'us-east-1' do
      it { should exist }
     end

    View Slide

  62. Tokyoリージョンにない(なかった)サービス
      AWSのサービスのリリースはだいたい北⽶か

      その時から稼働しているus-east-1のサービス
    とap-northeast-1のサービス両⽅共管理した

    62
    JAWS Festa 2016

    View Slide

  63. Pull Requestを⾒た感想
    •  awspecを使ってでも「しっかり」テストしたいんだろ
    うなということがにじみ出ていました
    •  かつてより、より⼤きく複雑な構成のものがAWS上に展
    開されているんだろうな。。。
    •  構成要素は多いのに求められる管理体制もより厳しく
    •  既に職⼈芸は通⽤しないっぽい
    63
    JAWS Festa 2016

    View Slide

  64. 今後やりたいこと
    64
    JAWS Festa 2016

    View Slide

  65. AWSアカウント⾃体のテスト
    •  awspecは基本的に1つのインスタンス、1つのVPCなどAWS
    リソース1つ1つに対してテストが可能
    •  最近はさらに上位のレベルでテストを書いておきたいことが
    多発している
    •  「このリージョンで起動しているRDSインスタンスは5台」
    •  「EC2のスケジュールドイベントは現在0件」
    •  「このアカウントではIAMの数は4つ」
    •  なぜ作らないのか?
    •  具体的な実装デザインが決まっていない
    •  リソースタイプ名が決まらない(aws? account? resources?)
    •  だれか決めて欲しい
    65
    JAWS Festa 2016

    View Slide

  66. なぜawspecなのか
    66
    JAWS Festa 2016

    View Slide

  67. awspecの存在意義
    •  Codenize.toolsやTerraformなど、使いやすい構成管理
    ツールが出てきたため、AWSリソース⾃体がコードで管
    理されるようになってきた
    •  わざわざ別にテストいらない
    •  「⼿作業で構築したAWSリソースの管理にはawspecが
    良い」
    •  http://inokara.hateblo.jp/entry/2016/02/21/120657
    •  AWSのリソース構成をいじらないという安⼼感で、カジ
    ュアルにspecをgenerateしてチェック
    •  Yet Another AWS Config Rules
    67
    JAWS Festa 2016

    View Slide

  68. さらに今後やりたいこと
    68
    JAWS Festa 2016

    View Slide

  69.  $ cat < Gemfile
     source "https://rubygems.org"
     gem "awspec"
     EOF
     $ bundle install --path=vendor/bundle --binstubs=bundle_bin
     ...
     Bundle complete! 1 Gemfile dependency, 25 gems now
    installed.
     Bundled gems are installed into ./vendor/bundle.
     $ du -mcs ./
     22 ./
     22 total
    69
    JAWS Festa 2016

    View Slide

  70. 22MB
    70
    JAWS Festa 2016

    View Slide

  71. わかりますよね?
    71
    JAWS Festa 2016

    View Slide

  72. 72
    JAWS Festa 2016

    View Slide

  73. awspec on AWS Lambda(切望)
      RubyがAWS Lambdaで動けばawspecも動くはず
      CloudTrail -> S3 -> AWS Lambda -> awspec
      Rubyistにとって使いやすいAWS Config Rules
      CI for AWS on AWS
      2回⽬の訴え
    73
    JAWS Festa 2016

    View Slide

  74. まとめ
      awspecを作っています
      AWSのリソース構成管理について試⾏錯誤中で
    す。
      みなさんのAWSのリソース構成管理⼿法事例を
    是⾮聞きたいです
      特に形式⼿法でAlloyを採⽤して実戦投⼊して幸せになっている事
    例が聞きたいです
    74
    JAWS Festa 2016

    View Slide

  75. Thank you!
     Fusicはテクノロジーが
     好きなエンジニアを募集しています
     https://fusic.github.io 75
    JAWS Festa 2016

    View Slide

  76. Omake Deep Dive
    76
    JAWS Festa 2016

    View Slide

  77. aws-sdk-ruby
    77
    JAWS Festa 2016

    View Slide

  78. aws-sdk-ruby
    •  リソースを操作するクラスは、以下の2種類
    •  Seahorse::Client::Baseを継承したAws::*::Client
    •  (Aws::EC2::Clientなど)
    •  Resources::Resourceを継承したAws::*::Somename
    •  (Aws::EC2::Instanceなど)
    •  Clientはaws-cliのコマンド名とメソッド名が似ている
    •  Clientのほうが早くSDKに実装される
    •  Resourceのほうがリソースをオブジェクトとして綺麗に操作
    できる
    78
    JAWS Festa 2016

    View Slide

  79. awspecはClientベース
    •  できるだけ多くのAWSリソースを実装できたほうがよい
    •  awspecはリソースのREADが基本なのでそこまで難しいこ
    とはしていないのでいける
    •  でも、Resourceも使いたいよね
    •  でも、Resourceにはリソースの操作(READ以外)もあるの
    で安易に組み込めない
    •  「awspec使ったら書き⽅間違えてインスタンスが削除され
    た」は洒落にならない
    79
    JAWS Festa 2016

    View Slide

  80. 80
    Awspec::ResourceReader
    JAWS Festa 2016

    View Slide

  81. Awspec::ResourceReader
    •  awspecは内部でResourceを呼び出すときは必ず
    Awspec::ResourceReaderを経由する
    •  Awspec::ResourceReaderでAWSリソースを操作しそ
    うなメソッドを潰している
    •  ブラックリスト⽅式
    •  これでほぼ安全にawspecが使える
    •  Resourceが使えるawspecのリソースタイプはドキュメント
    に”Advanced Use”の節がある
    81
    JAWS Festa 2016

    View Slide

  82. vpc
     describe vpc('vpc-ab123cde') do
      it { should exist }
      its(:resource) { should
    be_an_instance_of(Awspec::ResourceReader) }
      its('resource.route_tables.first.route_table_id')
    { should eq 'rtb-a12bcd34' }
      its('route_tables.first.route_table_id') { should eq
    'rtb-a12bcd34' }
     end
    82
    JAWS Festa 2016

    View Slide

  83. aws-cliとかのprofileの管理
    •  .aws/configと.aws/credentialsに分かれている
    •  なぜ?歴史的な理由?
    •  環境変数も使える
    •  awspecもaws-cliと同じようにprofileやENVを利⽤したい
    •  AWSなコマンドを⾃作する際もaws-cliと同じようにprofile
    やENVを利⽤したい
    83
    JAWS Festa 2016

    View Slide

  84. awsecrets
    84
    JAWS Festa 2016

    View Slide

  85. awsecrets
    •  Ruby製コマンドラインツール内でaws-cliと同じように認証
    情報をAws.configに設定することを⽬指しているgem
    •  awspecとkumomeで利⽤
    •  kumome: CloudWatchメトリクスをCLIでみれるツール
    •  http://k1low.hatenablog.com/entry/2016/02/01/083747
    •  正直aws-sdk-rubyでやって欲しいし、Issueが上がっていたはず
    85
    JAWS Festa 2016
     #!/usr/bin/env ruby
     require 'awsecrets'
     Awsecrets.load
     ec2_client = Aws::EC2::Client.new
     puts ec2_client
      .describe_instances({ instance_ids: [ARGV.first] })
      .reservations.first.instances.first

    View Slide