freeeの品質トゥギャザー:リスク洗い出し編

ども。皆のQAアニキ、freeeをテストするおっさん*1ことコヤマンです。

この記事はfreee Developers Advent Calendarの16日目です。※22日公開予定だったのですが、諸事情により記事公開を早めさせていただきました。

12/8(土)に弊社にて開催したシステムテスト自動化カンファレンス2018において「freeeの品質トゥギャザー」と題して弊社の品質への取り組みの発表があったのですが、そこで伝えきれなかった素敵な取り組みの1つである「リスク洗い出し」についてエントリーさせていただきました。

テストの目的

さて。リスク洗い出しのご紹介の前に改めて「テストの目的」とはなんぞや、というのをご紹介したいと思います。

JSTQBというソフトウエアテストの資格*2があり、ソフトウエアテストの広義の目的が4つ定義されています。

  1. 欠陥を摘出する
  2. 対象ソフトウェアの品質レベルが十分であることを確認する
  3. 意思決定のための情報を示す
  4. 欠陥の作りこみを防ぐ

この目的は、開発におけるシーンによって何が主目的なのか、という点が変わってきます。

DevOpsでのテストとシフトレフト

f:id:koyatest:20181211164636p:plain
DevOpsサイクル
※上図はeBayのHead of TestであるDan Ashby氏の記事の画像を元に加工のため書き起こしています

freeeは所謂DevOpsをしていると言えるのですが、DevOpsでは「継続的テスト」をするのが一般的です。

上記で箇条書きしたテストの主目的をDevOpsサイクルに当てはめると、以下のようになります。

f:id:koyatest:20181211234056p:plain
継続的テストとテストの主目的
※目的3の「意思決定のための情報を示す」は主目的にはありませんが、常に実施します

テストは「知ること」なので、フィードバック(情報提供)は早い方が良いです。 フィードバックが早ければ早いほど問題の解決が安上がりになりますので*3、テストの原則*4としてテストは早ければ早いほど良い(=効果が高い)と言われています。

そのため、開発の初期であるPlan,Branch,Codeのあたりでは目的4の「欠陥の作りこみを防ぐ」が主目的になります。 このように開発の初期にテスト活動することを「シフトレフト」と呼んでさまざまな取り組みがなされています。

freeeはリスク洗い出しでシフトレフト

freeeが扱うお客様のデータはクリティカルなものが多いため、品質を疎かにできません。 しかしながら品質を上げる、保つ活動をDevOpsの中でスピード感を持ちながら実施することが要求されるためにシフトレフトな活動をしています。

その中で代表的な活動が「リスク洗い出し会」(そのまんま)です。

リスク洗い出しでトゥギャザー

リスク洗い出し会を一言で表現すると 「みんなの"ヤバい"を共有して方針を決める会」です。

開発の初期段階からプロジェクトやプロダクトの情報を皆で共有して理解し、エンジニア以外の目線でもヤバいところ、不安なところを洗い出して方針を決めます。

具体的には以下のステップで進めます。

  1. 人を集める
  2. ヤバい、不安だを共有する
  3. 方針と担当を決める
  4. プロジェクトを進めるにあたり都度確認する
  5. 新たに気づいたら追加して共有する
  6. 最後に振り返りする

QA(テストするおっさん)の役割

おっさんは以下の活動をします。

  • トゥギャザーする人を集める(セールス、サポート、マーケティング、PM、Engなどなど)
  • 開催までに仕様・データ構造・アーキテクチャや連携する対象などをできる限り理解する
  • ヤバいと思うところを予めリストアップしておく
  • テストしようと思うことを予めリストアップしておく
  • 洗い出し会を設定する
  • リスク洗い出し会をファシる(みんなのヤバいを引き出す)
  • プロジェクト中に都度リスク表を確認する

このトゥギャザーによりコードを書く前あるいは書いている最中にフィードバックすることが可能になり、以下のような効果が早い段階で得られます。

  • 優先順位やセリングポイントの共有
  • マイルストンと熱量の共有
  • みんなが困ることとその対策
  • 構造・仕様の共有
  • 頑張るところ、頑張らなくていいところ*5の明確化
  • ヤバいの未然防止・手戻りの予防
  • いつまでに何をしないといけないのか
  • 各人が何をした方がいいのか
  • 何からテストをした方がいいのか、どの程度徹底的にやればよいか

集まった人全員に対し早めにフィードバックをすることが可能になります。

さらなる取り組み

freeeでは先日発表したDevOpsサイクルのMerge時におけるE2E per PullrequestやPlan,Branch,Code時に効果のあるリスク洗い出し、タイミングによってさまざまなシーンに効果のあるUX主導のユーザーテストなどによるシフトレフトだけでなく、Monitorとしてバグ分析やOperate時に専門家によるTesting in Productionなどシフトライトなどにも取り組んでいます。 その他、私はあまりトゥギャザーできていませんがサービス品質などの知覚品質を上げるための活動も動き始めています。

このような活動をできるのも、先日素晴らしいエントリーを裏freee Developers Advent Calendarに上げてくれた同僚のスーパーマサキさんをはじめとする素敵なメンバーがいてこそ、だと思っています。 このようにfreeeのエンジニアは品質トゥギャザーしながら、お客様にマジ価値を届けるために日々活動しています!

さて明日のfreee Developers Advent Calendarは自作キーボードの変態 伝道師こと id:foostan の記事です。 自作キーボード部の私も今から楽しみです!

*1:アジャイルチームに入ってテストしたり時々自動テスト書いたり色々やってます

*2:実は筆者はトレーニングコースの講師もしております

*3:不具合修正はコードに埋め込まれてから早いほうが安い、というのはWatts S. Humphreyさんの書籍でおなじみ

*4:JSTBにも「初期テスト」という原則があります

*5:エンジニアがやるべきところ、やらなくていいところなど

標的型攻撃と多層防御にAWS Security Hub + DeepSecurity はどうして嬉しいのか。

この記事はfreee Developers Advent Calendar 2018 15日目の記事です。 adventar.org

freee CSIRT専属エンジニアのEiji Sugiuraです。 早いもので、freeeにjoinしてから1年が経過しました。

前職では、UTM*1を使ったMSSP*2を作って運用していたので、SaaS*3はどちらかというとブラックボックスとして扱っていました。 それが、何の因果かSaaSのなかにどっぷり浸かっています。人生って何が起きるかわからないもんです。

自分から「セキュリティエンジニアです。」なんて名乗るのは眉唾ものだと思っています。他人からセキュリティエンジニアと呼ばれれば本物ですね。 自分は果たしてどうなんだ? という点はさておき、この1年間、どんなことを考えてセキュリティを無理なく無駄なく担保しようしてきたかを、まとめておきます。

ざっくりいうと、立場は変わっても、考えることは普遍ですという話です。

攻撃と防御

標的型攻撃

その昔、インターネットで報告される攻撃といえば、わかりやすく同時多発的に被害が生じるもので、愉快犯が犯人であることがほとんどでした。 しかし、2010年代に入ってから、金儲けの手段として攻撃や侵入を行い、実際に利益を得る組織の存在が知られるようになりました。 そうした組織は、標的型攻撃と呼ばれる洗練された手法を用いていました。

標的型攻撃に限らず、こうした攻撃手法は常に進化していて、APT*4攻撃と呼ばれる手法に変化しています。 この攻撃は、7つの段階を経て行われると言われています。

最も知られているのは、標的型メール攻撃なので、それを例にとると、こんな感じです。

  1. 偵察 Reconnaissance
    攻撃者は餌食となる標的を物色します。最も都合が良いのは、防御が脆くて、足がつきにくい宝物を持っている組織です。検索エンジンやSNS、メールなどから簡単に標的の情報を手に入れられるので、組織に属する人のリスト、組織構造、予定されているイベント、取引先、取引内容など、集められるものをすべて揃えておき、最も割りの良い標的を選び出します。
  2. 武器の準備 Weaponization
    標的が決まったら、malwareの作成ツールやbotnetを調達し、特定の人物に開いてもらえそうなメールのタイトルと文面を推敲し、組織が利用しているセキュリティ対策製品に検知されないことを確認したmalwareを添付ファイルやリンクとして添えたメールを用意します。
  3. 輸送 Delivery
    そして、メールを送付します。 メールは暗号化された通信路で配送されるため、配送途中にmalwareが検知されることはありません。
  4. 侵入、展開 Exploit
    組織内の誰か一人がメールを開く、もしくは開かなくてもメールを受信した時点で、パソコンのOSにmalwareが侵入します。AntiVirusには検知されません。なぜなら、検知されないことを確認済みのものを送付したからです。
  5. 潜伏 Installation
    malwareは侵入したOS上で、自らをまっとうなプロセスであるかのように偽装し、OSの管理者権限を奪取します。そして、C2C serverとの通信路を確保します。
  6. C&C->探索 Command&Control
    その後は、C&C serverからの指令に従って、周囲のパソコンやネットワーク機器への侵入を試します。
  7. 目標の奪取、掃除 ActionsOnObjectives
    探索の結果、取得したかった情報が見つかった場合、頃合いを見計らって奪取したら、自らの痕跡を消して攻撃は終了です。

APT攻撃は、標的型攻撃と比べて以下の点で進化しています。

  • 明確に目的がある
    攻撃者は、APT攻撃を仕事として取り組んでいるので、利益を得る、情報を手に入れる、もしくは、標的の評判を貶めるなど、明確な意図を持っています。
  • 見つけられない
    間欠的にしか動作しない。長期間潜伏する。ファイルを残さずにメモリ内にのみ存在する。既存のプロセス内で動作する。プロセス一覧に表示されない。などなど、様々な手法を凝らして、とにかく痕跡を残しません。
  • 技術レベルが非常に高い
    自ら攻撃ツールを作成できる専門家が組織として行動していると考えられています。標的側の兼務のセキュリティ担当なんて相手になりません。
  • 粘り強いこと
    うまくいかなければ別の方法を探り、ツールを自動でアップデートし、プラグインによる機能拡張を行う、なんてこともやってのけます。

防御する側が圧倒的に不利な状況ですね。 防御側は一つも間違いを許されないのに、攻撃側は蟻のひと噛みでどこか一つでも穴を見つければ勝ったも同然というのも困ったところです。

標的型攻撃やAPT攻撃は、日本では企業や公的機関の情報漏洩ばかりに注目が集まってしまい、あまり報道されませんでしたが、2015年12月にはウクライナにおいて戦争の手段として用いられ、基幹インフラである送電網に物理的な被害が生じました。

www.wired.com https://ics.sans.org/media/E-ISAC_SANS_Ukraine_DUC_5.pdf

この攻撃は、1年後、2年後、そして今年も継続して行われている、と考えられています。

多層防御

標的型攻撃やAPTの対処策として広く知られているのは、2009年にLockheed Martinが提唱したCyber Kill Chain = 多層防御です。

多層防御の基本的な考えは、攻撃の段階全てで、まずログを記録し、その中から異常を検知することです。 その上で、攻撃を直接的に止める、動作を妨害し時間稼ぎをする、情報を略取されたとして意味がわからないものに加工しておく、偽物を掴ませる、最終手段として攻撃元を破壊する、の全ての手段を用いて攻撃が成立しない状況を維持することを目指します。

例えば、標的型メール攻撃に対して、多層防御で対策を練った場合、以下のような対処が考えられます。 社内LAN内のサーバが、機微なデータを保持している想定です。 なお、偵察や武器を準備している段階については、一般企業では対処は難しいため省略しています。

-
攻撃段階
Discover
記録
Detect
検知
Deny
禁止
Disrupt
妨害
Degrade
矮小化
Deceive
撹乱
Destroy
破壊
3. 輸送 Internet Gateway上での対策
NetFlow IPS*5 Firewall、URL Filter、WAF*6 Rate Limit
4. 侵入 PC上でのメモリアクセスでの対策
EventLog HostIPS、LogInspection Package Update ASLR*7 Sandbox
5. 潜伏 PC上のファイルアクセスでの対策
FileIntegrity*8 AntiMalware FileAccessControl
6. 探索 社内LAN機器での対策
NetFlow IPS NetworkFirewall NetworkSegmentation RateLimit
7. 奪取 サーバ上での対策
AccessLog HostIPS、DLP HostFirewall、FileAccessControl ASLR HoneyPot

これを、AWS上に構築されたサービスシステムに適用した場合を考えてみます。 こちらは、S3 BucketやDatabaseに機微なデータを保持している想定です。

f:id:eiji-sugiura:20181215002300p:plain
AWSに構築したシステム

-
攻撃段階
Discover
記録
Detect
検知
Deny
禁止
Disrupt
妨害
Degrade
矮小化
Deceive
撹乱
Destroy
破壊
3. 輸送 ELB周りでの対策
ELB AccessLog AWS Shield、AWS WAF ELB Security Group AWS WAF Rate Limit
4. 侵入 EC2 instance上でのメモリアクセスでの対策
AuditLog、AccessLog HostIPSLogInspection Package Update ASLR Sandbox
5. 潜伏 EC2 instance上のファイルアクセスでの対策
FileIntegrity AntiMalware FileAccessControl
6. 探索 VPC内での対策
FlowLog IPS SecurityGroup NetworkSegmentation RateLimit
7. 奪取 BucketやDB周りでの対策
QueryLog、ObjectLog ObjectIPSDLP SecurityGroup、ObjectAccessControl HoneyPot

青字で示した部分は、AWSに用意されているサービスや機能によって対策が可能な部分です。

赤字で示した部分は、AWSでは提供されない機能です。EC2 Instance自身を守るには、別途仕組みを導入する必要があることが分かるかと思います。そして、この不足した機能をそのまま提供してくれるのがDeepSecurityだと考えています。

DeepSecurityの他にも、同様の機能を提供する製品は存在しますが、IPSやFile Integrity、Log Inspectionについては、signatureを編集することが可能な点がお気に入りです。

SIEM

多層防御を張り巡らせれば、仕事は終わりというわけではありません。

実は、多層防御では、各段階で膨大なログが発生します。 例えば、WebServiceに関連するものだけに絞ったとしても、以下のように様々なログが挙げられます。

ログ種別 記載される内容
Detect Log Firewall、WAF、IPS、AntiMalwareなど、セキュリティ上の異常を検知したことを報告するログ
Web Error Log nginx/apacheでのエラーが記載される
Web Access Log Layer 7のログ、nginx/apacheが出力する、AWS WAFも全てのアクセスを記録するログを出力します
Application Log WebApplicationの動作を記録する
Flow Log Layer4までのログ、AWSのFlowLogはNetFlow v5に相当します

Detect Logや、Error Logが発生した場合に、それらの原因を調査し、対処を行うのは、誰でも行なっていると思います。 Detect LogでWAFであるIPから一定以上の頻度で繰り返される攻撃を検知したら、IP reputationを検討するでしょうし、IPSで誤検知が判明したらsignatureを修正するといった具合です。

でも、間違いが起きる前にproactiveに対処するためには、通常運用時のログである、Access Log、Application Log、Flow Logを解析して、間違いが起きる予兆を掴み、対処を自動的に実施しなくてはなりません。

しかし、通常運用時のログは膨大です。 ログを解析するためのシステムを構築して運用していくのは、かなりのコストが必要です。下手をすると、お客様向けサービスを構築する費用の半額以上をかける事態に陥りかねません。

こうした、ログを集積し、相関分析を行い、予兆を検知したら、自動的に対処を行う仕組みは、SIEM*9と呼ばれています。 オンプレミスでシステムを構築している場合、SIEMの導入は、もう一つ別の高価な箱を買ってくることを意味したのですが、AWS上では箱を持ってくるのは無理そうです。

SIEMを自前で構築するとなると、AWSが提供するGuardDutyのようなサービスや、DeepSecurityのように3rd partyが提供するサービスのログを集めるところか始めなければなりません。

AWS Security Hub + DeepSecurity

で、今回何が嬉しいかというと、まずは、AWSがログを集積する箱を用意してくれた!、という点です。 AWSが提供するサービスのうち、GuardDuty、Inspector、Macieについては、Security Hubを有効化するだけで、集積してくれます。

さらに、3rd partyのログを受け付けるAPI = Findingsも用意されました。 DeepSecurityは、Findingsにeventを投げるための実装もTrendMicroが用意してくれたみたいです。

ということで、早速使ってみました。

AWS Security Hubの有効化

詳しくは、以下のサイトに記載されていますが、 Security Hubを有効化し、CISベンチマークを有効化しておきます。

dev.classmethod.jp

DeepSecurityのsubscribe

[Settings]->[Providers]で、TrendMicro DeepSecurityを[Subscribe]しておきます。

実行ロールの作成

  1. AWS マネジメントコンソール にサインインし、IAM コンソールを開きます。
  2. [Create Role]をクリックして、ロールの作成を開始します。
  3. [Select Role Type] で、[AWS Service Roles] を選択して [AWS Lambda] を選択します。
  4. [Attach Policy] で、AWSLambdaBasicExecutionRole という名前のポリシーを選択します。
  5. Tagは今回は利用しません。
  6. [Role Name]は、今回はlambda-ds-agent-security-hubとしました。

後で用いるので、以下の形式の[Role Arn]をメモしておきます。 arn:aws:iam::XXXXXXXXXXXX:role/lambda-ds-agent-security-hub

SecurityHubBatchImportポリシーの作成

lambdaからSecurityHubへFindingsをBatchImportするためのポリシーをAWS CLIを用いて作成します。 以下の内容で、security-hub-batch-import-policy.json を作成しておきます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "securityhub:BatchImportFindings",
            "Resource": "*"
        }
    ]
}

以下を実行して、ポリシーを作成します。

aws iam create-policy --policy-name SecurityHubBatchImport \
    --policy-document file://security-hub-batch-import-policy.json

実行ロールへのSecurityHubBatchImportポリシーの追加

以下を実行して、実行ロールにポリシーを追加しておきます。

aws iam attach-role-policy --role-name lambda-ds-agent-security-hub \
    --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/SecurityHubBatchImportOnly

Lambdaの作成

修正済みのソースコードを、lambda-function.pyとして作成しておきます。

本家の実装は、以下の点の修正が必要でした。

  1. HostAssetValueが、AntiMalwareのeventの場合は存在せず、IPSのeventの場合は数字の配列でやってくる状態だったので、ひとまずコメントアウトしています。
  2. DeepSecurityからのeventを受け取るSNSを管理しているAWS accountと、SecurityHubを管理しているAWS accountが、別の場合にも対応できるように組まれているのですが、そのままだと動作しません。 コメントアウトせずに、assume role時の例外を拾って、処理をそのまま継続しています。cross accountで処理する場合にも対応しているつもりです。
  3. 他にも、例外を捕捉していない箇所がほとんどだったので、debugしやすいように例外を捕捉してerrorの内容を出力するようにしています。

github.com

ソースコードをzip fileにまとめておきます。

zip -r ds-agent-security-hub.zip lambda_function.py

以下を実行して、Lambda関数を作成します。

aws lambda create-function --function-name DeepSecurity2SecurityHub \
--zip-file fileb://ds-agent-security-hub.zip \
--role arn:aws:iam::XXXXXXXXXXXX:role/lambda-ds-agent-security-hub \
--handler lambda_function.lambda_handler --runtime python3.6

Lambda関数の一覧から、作成したDeepSecurity2SecurityHubのDesignerを参照すると、以下のような状態となっているはずです。

f:id:eiji-sugiura:20181214222642p:plain
Lambdaが作成された

Triggerの設定

予め、DeepSecurityからSNSにeventを飛ばすように設定しておきます。
まだ、設定を行なっていない場合は、DeepSecurityのSNS設定マニュアルを参考にDeepSecurity用のIAMユーザを作成し、ACCESS KEY、SECRETを設定し、SNS topicを作成しておきます。

今回は、deepsecurity-eventという名前でSNS topicを作成しました。

そして、SNS topicからeventをLambda関数に通知するためのsubscriptionを作成します。 DeepSecurityからSNSへのeventの全体的な手順は、こちらが参考になると思います。

DeepSecurity2SecurityHubのDesignerに戻り、Triggerを追加します。 左側に並んでいるTrigger一覧から[SNS]を選択し、SNS topicには、deepsecurity-eventを指定します。

f:id:eiji-sugiura:20181214222652p:plain
LambdaにTriggerが追加された

この時点でTriggerを有効化すると、以下のようなエラーがCloudWatchLogsに記録されます。

securityhub: Unknown service: 'securityhub'. Valid service names are: ....<アクセス可能なサービスが羅列される...>

これは、Lambdaが利用しているboto3が古く、securityhubに対応していないために発生するエラーです。 ということで、最新のboto3を利用するためにLayerを利用します。

Lambda Layerの追加

詳しくは、こちらを参考にしていただくとして、

qiita.com

手元で以下を実行し、layerにuploadするためのboto3のzipファイルを作成します。

$ mkdir python
$ pip install -t ./python boto3
$ zip -r boto3-1.9.62.zip python

執筆時点のboto3のversionは、1.9.62でした。

Lambdaコンソールで

  1. [Layer]を選択し、[Create Layer]で新しいLayerの作成を行います。
  2. [Name] python-boto3、 [Description] 1.9.62、 [Compatible Runtime]には、python2.7 python3.6 python3.7を指定しておきます。
    f:id:eiji-sugiura:20181214222038p:plain
    Lambda Layerの作成
  3. 先ほど作成したboto3-1.9.62.zipをuploadし、[Create]を実行します。
    f:id:eiji-sugiura:20181214221623p:plain
    lambda Layerが作成された

DeepSecurity2SecurityHubのDesignerに戻り、[Layer]を選択し、[Add a layer]を実行して、python-boto3を追加します。

f:id:eiji-sugiura:20181214221235p:plain
Lambda layerが追加された!

動作確認

DeepSecurityのAntiMalware機能でReal-Time scanを有効にしていれば、EICAR文字列をテキストファイルに書き込むだけで、eventを発生させることができるので、これで動作試験を行えます。

DeepSecurityが動作しているEC2 instanceにloginし、ds-agentが動作していて、かつ、Real-Time scanが有効になっていることを確認しておきます。

$ sudo /opt/ds_agent/dsa_query -c GetComponentInfo
...
Component.AM.scan.Realtime: 1
...

以下のようにEICARを用いて、動作確認を行えます。 EICAR文字列には、"EICAR test file"で検索すると出てくる文字列をいれて下さい。

$ echo 'EICAR文字列' > test.txt

Real-Time scanが正常に動作していれば、test.txtは作成されません。 syslog出力を有効にしていれば、以下のようなログが確認できます。

Dec 14 00:16:03 ip-10-XX-YY-ZZ CEF: 0|Trend Micro|Deep Security Agent|1X.0.0.XXXX|4000000|Eicar_test_1|6|cn1=...... cn1Label=Host ID dvc=10.XX.YY.ZZ TrendMicroDsTenant=...... TrendMicroDsTenantId=..... cn2=144 cn2Label=Quarantine File Size filePath=/tmp/test.txt msg=Realtime TrendMicroDsMalwareTarget=N/A TrendMicroDsMalwareTargetType=N/A TrendMicroDsFileSHA1=CF8BD9DFDDFF007F75ADF4C2BE48005CEA317C62 act=Quarantine

もちろん、DeepSecurityのWebU/Iでもeventは確認できます。

f:id:eiji-sugiura:20181214220910p:plain
DeepSecurityでのevent表示

そして、EICARを検知したeventは、AWS Security Hubでも確認できます。

f:id:eiji-sugiura:20181214222703p:plain
Security HubにDeepSecurityのeventが表示された!

まとめ

多層防御を適用すると膨大なログが発生しますが、それを運用で回していく仕組みに使えそうなものをAWSが用意してくれたので、使ってみました。

AWS Security Hub + DeepSecurity の使い方だけであれば、以下ですでに解説されていますが、背景も含めて理解できるようにしたつもりです。

dev.classmethod.jp

Future Work

AWS Security Hub Findingsで、一覧性は確保できそうですが、まだ、統合されていないものもあります。AWS WAFのeventも集約したいなぁ。

今回は、EC2 instance構成での話でしたが、AWS + Kubernetes構成にも応用できますが、まだ足りない部分が多々あります。それについては別の機会に。

新たに開発するサービスに構想、設計段階からセキュリティを織り込んでいくのは、人であるエンジニアの仕事です。 また、すでに稼働しているサービスに合わせてWAFやIPSのsignatureやparameterを調整したり、取捨選択するのも、エンジニアの仕事です。 セキュリティエンジニアという職業がなくなって、エンジニア皆がセキュリティを身につけた世界が理想です。

freeeでは、一緒に働く仲間を募集しています。

jobs.freee.co.jp

CSIRTのエンジニアとして、隣で働いてもらえる人も募集中です。

www.wantedly.com

さて、明日12/16(日)は、freeeが誇るQAの達人コヤマンさんです。

*1:Unified Threat Management system: ルータにFirewall、IPS、AntiMalware、AntiSPAMなどのセキュリティを担保する機能を詰め込んだもの、アプライアンスとして提供されることが多い

*2:Managed Security Service Provider : network securityのdesign、deploy、management、incident responseを丸投げできる便利なサービス

*3:Software as a Service

*4:Advanced Persistent Threat:直訳すると、より進化し継続して行われる攻撃

*5:Intrusion Prevention System : trafficに対してsignature matchを行い不正な通信を検知する

*6:Web Application Firewall : www serverへのHTTP requestのfilteringを行う

*7:Address Space Layout Randomization

*8:ファイル改ざん検知

*9:Security Information and Event Management

Elastic StackによるKubernetesモニタリングシステムの紹介

まえがき

SREの河村(at-k)です。freeeにjoinしたのは今年1月なので、そろそろ1年。前職は組み込み分野の研究屋だったのもあって、扱う技術も仕事の進め方もガラッと変わり、なかなか刺激的な1年でした。ひたすら詰め込みな日々ですが、最近はようやくこの分野における自分なりの目標がぼんやり見えてきた感じです。しかし、理想は高く、道は遠い。来年も頑張っていきます、よろしくお願いします。

さて自分語りはこのくらいにして。

年末ですね。

この時期になるとみな無駄に忙しく、つい周囲に目が行かなくなり、足元がおろそかになります。そんなときに事故はつきもの。そうならないためにも、日々冷静に自分を見つめ、絶えず変化を監視する必要があります。つまりモニタリングです。

この記事はfreee Developers Advent Calendar 2018の14日目です。

Elastic StackでKubernetesクラスタをモニタリングしてみた

タイトル通りです。freeeでのKubernetesクラスタのモニタリングシステムを紹介します。

構成です。

構成図

Kubernetesのモニタリング方法として、巷ではDatadogやPrometheus + Grafanaなどがありますが、ここではログの収集・分析基盤からデータストアまでをElastic Stackで統一しています。理由はいくつかありますが、

  • Elastic Stackで統一することで、豊富な連携・効率的な運用を期待
  • 様々なログ・メトリクスの収集をサポートする軽量ログシッパーなElastic Beatsが良さそう
  • 開発が活発で、頻繁にバージョンアップしている
  • もともと社内でElasticsearch + Kibanaを使っていたのでノウハウがある

などが挙げられます。

続いて、各コンポーネントについてざっくりと説明します。

まずFilebeat/Metricbeatですが、これはElastic社の開発するLightweight Data ShippersであるElastic Beatsのファミリーソフトウェアです。 Filebeatは各コンテナのログを収集します。以下は一例です。

f:id:atkmr:20181214024506p:plain

MetricbeatはCPU、Memory、StorageやNetwork等のメトリックを収集します。以下は一例です。

f:id:atkmr:20181214024525p:plain

各レコードにはKubernetes由来のメタデータ(kubernetes.*)が自動で付加されます。また、Filebeatのレコード例でmessage-jsonというフィールドがありますが、これはログフォーマットがjson形式の場合に、自動で検出 & パースする機能を使っています。デフォルトでは有効で無いので、例えば以下のように設定します、詳しくは公式のマニュアルをあたってください。

config:
  filebeat.prospectors:
  <snip>
  - containers.ids:
    - '*'
    processors:
    - add_kubernetes_metadata:
        in_cluster: true
    - decode_json_fields:
         fields: ["message"]
         process_array: false
         max_depth: 5
         target: "message-json"
         overwrite_keys: true
    - drop_fields:
        when:
          has_fields: ["message-json"]
        fields: ["message"]
    type: docker

Filebeat/Metricbeatともにhelm chartが用意されているので、環境に合わせてvalue.yamlを書いてhelm installすれば大体OKです。

また、Filebeat/MetricbeatにはKibanaのセットアップコマンドが用意されており、例えばMetricbeatを使ってKibanaをセットアップすると、インデックスマップやダッシュボードをいい感じに作成してくれます。弊社における作例を貼ろうと思いましたが、黒塗りだらけで絵面が大変よろしくなかったので、どんな感じかは公式を参照ください。

ログは一度Kinesisに集めて、ここからS3とElasticsearchに同報しています。これにより、ログ送付の安定化を実現し、今後の発展的活用(ログ加工・転送先追加等)の余地を残しています。なおBeatsはデフォルトではKinesisを送付先に指定できないので、OSSのプラグインであるawsbeatsを使用しています。

ElasticsearchはAWS Elasticsearch Serviceを使っています。自前運用に比べてかなり楽ですが、Elasticsearchの最新バージョンにすぐに追従できなかったり、Kibanaに自前でpluginを入れられなかったりと、ある程度の制約が課せられます。

ログの監視としてはelastalertというツールを用いています。Elasticsearchのログを監視し、指定のログパタンにマッチしてSlackなどにメッセージを飛ばす仕組みです。またルールを管理しやすいように、Kubernetesに自前のOperatorを入れています。この辺は別記事で詳細を書くかもしれません。

トラブル集

モニタリングシステムにおいて重要なのは、途切れなくログを収集・格納することです。しかし、この世に絶対というものはなく、本システムもちらほらトラブルに見舞われました。厄払いも兼ねて、いくつか紹介します。

大きなサイズのログが壊れる

Filebeatはログファイルをtailして送付します。何のファイルを監視しているかは$ROOT_DIR/data/registryで管理されており、例えば以下のような形式です。

kubectl exec  filebeat-xyz cat data/registry |  jq . 
[
  {
    "source": "/var/lib/docker/containers/xxxxx.log",
    "offset": xxx,
    "timestamp": "2018-12-13T03:51:12.090061457Z",
    "ttl": -1,
    "type": "docker",
    "meta": null,
    "FileStateOS": {
      "inode": 1044114,
      "device": 51721
    }
  },

sourceが対象ファイルです。一定のサイズになったら別ファイルに切り替わってローテートするのですが、ログのレコード(改行区切り)がファイルをまたがった場合、別々のログとして分割されて送付され、結果、予期しない形式のログになってKibana上で見つからない、という問題がありました。 この問題については以下のissueで議論され、現在は対策済みで、ファイルをまたがってもうまいこと連結してくれます。

バージョンを上げたらログ採取エラー

ログ分割の問題解決、と思いきや、バージョンを上げるとログが送付されなくなりました。Filebeatのログを調べたところ、以下のようなエラー。

Read line error: invalid CRI log

こちらも公式で解決済み参考ですが、先のissueの対策と既存の制御方式のアンマッチで、ファイルの読み出し位置(offset)の不整合が置きたことが原因だった模様です。

ログサイズが大きすぎてKinesisで詰まる

先に書いたとおり、Kinesisを中継する仕組みになっていますが、Kinesisの制限でログのサイズは最大1MB/レコード(参考)です。巨大なログがこの制限に引っかかり、無限リトライして他のログが一切届かないという問題がおきました。filebeat側の設定で最大ログサイズを1MBに制限し、また、極端に大きいログは分割するように周知しました。

Elasticsearchに投入されたログがマッピング不一致でdropされる

Elasticsearchの仕様ですが、登録されているdata typeと異なるfieldを持つログを渡すとdropされます。それは良いのですが、各コンテナが思い思いにログを出力して、それが一律message-json.xxにパースされると、型の衝突が容易に発生します。つまり、message-json.idが、数値だったり文字列だったりして、エラーになる、という感じですね。dynamic templateでdata typeを文字列に寄せておくといったやり方で対応しますが、やや面倒なので、よいベストプラクティスを模索中。

こんな感じで時々地雷を踏みながら運用を続けています。ただBeatsに関しては未報告のバグは踏んだことがなく、また割とすぐに公式による修正が入る印象です。活発なコミュニティの恩恵ですね。

今後

健全なシステムを維持するためにもモニタリングは非常に重要ですので、より堅牢なモニタリングシステムを目指し、例えばモニタリングシステムの監視強化や冗長化を検討していきます。さらに、今回紹介した内容以外にも、Heartbeatで死活監視、Elastic apmで分散トレーシング、などがElastic社から提供されており、適宜組み込むことでモニタリング対象のさらなる充実に取り組んでいきます。また、他の監視システム、例えば最近AWS reInventで紹介されたCloudwatch Insightsなども、今のシステムの代替になりうるか試してみたいですね。

まとめ

以上、freeeにおけるKubernetesクラスタの監視システムを一部ご紹介しました。監視なきシステム運用は夜道を明かり無しで進むようなもの。安心して年の瀬を過ごせるよう、この機会にご自身のモニタリングシステムを見直してみてはいかがでしょうか。

それでは皆さん、ご安全に。

明日は、プロダクトを陰から守る、freeeセキュリティの要、CSIRT杉浦さんによる記事です!

御社では GitHub の Organization アカウントによるメンバー管理をどのように行っていますか?

まえがき

年に一回の外向け記事を公開する日がやってきてしまいました。仙波です。

この記事はfreee Developers Advent Calendar 2018 の13日目です。

adventar.org

例年ちょっとエモい記事ばかり書いているので、今年はちょっと渋い(他社さんがどうやっているか気になる)ところを書いていきたいと思います。

さて、まずは本業である今年の蕎麦ですが、得意先の粉屋によると相次ぐ災害により不作で、夏の北海道産はもとより、新そばの本命である信州産もよろしくない状況だそうです。悲しいですね。

f:id:inage782:20181213114642j:plain
打ち立ての新蕎麦。例年よりちょっと香りが薄いかな。

蕎麦以外のエンジニア業についてですが、自分はいまSREチームからエンジニアの生産性を向上するチームに移動しています。

相方は各マイクロサービスの Rails の Major Version Up やら ChatOps 用の Bot を扱っており、自分の方は開発環境の初期セットアップを超高速化したりとか、開発・レビュー向けの asset の build を10倍速にしたりとか、DBの初期データ投入を10倍速にしたりとか、おおよそ一人チームに近い様相を呈しつつ、それぞれが自分なりに考えた生産性上がりそうな Hack をしています。

今回は GitHub の Organization アカウントによるメンバー管理を自動化したりした知見を書いていきます。

本題

優秀なエンジニアと対面する上で避けて通れない問題がありますよね。

そう、アカウント管理(名寄せ)です。

ただでさえネットとリアルで異なる人格を持つ我々エンジニアは、愛称・あだ名とはまた別に、パーソナルリアリティの体現たるハンドルネーム/IDを持っています。

また、ほとんどの Web サービスでは ID の重複が許されず早いもの勝ちなので、各サービスごとに微妙に異なる ID を使用している可能性があります。名前とアカウント名が異なると、このアカウントは誰のもの?と捜索依頼を出すことも…。

弊社では OneLogin の事例にも載っているとおりたくさんの SaaS を利用していますが、 GitHub はまだ IdP の管理対象外です。それというのも弊社はいろいろな Web サービスのアーリーアダプターでもあるので、今やモダンな Web 開発に必須の GitHub のプランも旧プランであり、 SAML/SCIM に対応していませんでした。

GitHub のアカウント管理をするためには、プランをアップグレードするか、温かみのある手作業で対応するか、自前で自動化するしかありません。

とはいえ BtoE のサービスに関しては社員数によっては使用しているプランを上げると、いきなり数百万、数千万のコスト増になってしまったりで、これはよっぽどインセンティブが働かないとすぐには導入できないのが営利企業です。

また、プランをアップグレードして対応するにしても、どういったフローで適切な権限を個々人に付与し、管理するかといった制度設計としての部分はおざなりにできるものではありません。GitHub さんの SAML/SCIM でのアカウント管理方法がこちらの要件とあっていないという情報もあるため、管理運営を行っている諸兄につきましては現状について知見をいただきたい次第です。

そういったわけで、今回は直近でおこなった GitHub のアカウント管理フローの設計と運用について書きます。

GitHub のアカウント管理フローの設計と運用について

いままで

メンバー招待
  • (たくさんいる)Owner 権限を持っているメンバーが手動で Organization に招待
  • エンジニアチームの総務が各方面に連絡を取って手動で Organization に招待

主に上記の2パターンでした。

権限管理
  • (たくさんいる)Owner や Team メンテナが手動で Team に所属させる
  • 各リポジトリごとに直接 collaborator に追加

といった感じで 200をゆうに超えるアカウントが運用されており、これをエンジニアチームの総務が頑張って GitHub から SpreadSheet に転記して入退社情報と照らし合わせながら個別に退職処理をしたり棚卸しを行っていました。

また、アクセス権限は必要に応じて追加する方式で明文化されたルールはなく、社員エンジニアの良識によって運用されていました。

現在

メンバー招待

誰も彼もが勝手に招待する手段があるのがあかんのや。という訳で Owner 権限をガッツリ絞って各リポジトリごとに Team 単位で権限をきちんと割り振りました。 エンジニアの入社フロー自体に手を加えることで、オンボーディングメンバーが各自の判断で開発に必要な適切な権限を割り振ることが出来るようになってます。

  • Organization への招待は Google Form 経由
    • Team への追加も同時に行う
    • 手動で触らない
    • 在籍確認先を同時に入力してもらう
  • 在籍確認はレポートラインと招待者が責任を負う
  • 利用者は雇用形態に関係なく Organization に所属する

このあたりは Google Form から Google Apps Scirpt と GitHub API を利用して手動で招待を行う場面を無くし、すべての履歴が監査可能な形で残るようにできました。

developer.github.com

権限管理

アカウント棚卸しの共通ルールを設定して API で自動化しました。 30日ルールというわかりやすい運用方針で、30日間 Pull Requestを作らなかったアカウントを自動的に Organization から remove しています。

GitHub には過去メンバーだった人を再招待するさいに直前の権限を簡単に復元する機能が付いているので、長期的に使用を止める場合は remove したほうが安全です。

  • 在籍確認をしてから30日間 Pull Requestを作らなかったアカウントは自動的に棚卸し
    • 在籍確認日の更新フォームを提供
    • QAやUX、支払いアカウントに machine user などレビューや管理が主体的なアカウント用の AllowList の提供
    • 業務委託さんの招待者向け在籍確認メールの運用
      • 業務委託さんの在籍状況を一括更新
  • 所属メンバー一覧のスナップショット取得
  • 棚卸しボットによるお知らせの強化

上記の対応のために Owner 権限の削減とあわせて Team の整理も進めたおかげで、メンバー招待から利用までがスムーズに行えるようになり、事業側が管理するプロジェクトについても、運用の管理下に置くことが出来るようになりました。

remove や所属メンバー一覧の取得も Organization Members API を使用しています。

振り返り

ここまでのアカウント管理はエンジニア総務の方が管理しやすいように、すべて SpreadSheet に記録されるようになっています。操作ログが残るし。

Google Apps Script & TypeScript に GitHub API のおかげで大きなコストを掛けること無く動くものを短い期間で提供できたのは良かったと思います。GASの認証と権限管理が出来るところ、すごく楽でよいです。実装より運用の周知の方が大変でした。

あと、事前のアカウント整理と確認を手作業で行っていた際にオペミスででかい Team を消してしまって真っ青になりました。 ワンオペ手作業ほんとよくない。駆逐してやる。

これから

導入の効果が大きそうなところは運用が開始されたので、以降も空き時間を使って Team 管理の provisioning を自動化したりしようかなと言った感じです。

実務的なアカウント管理をしていると、外部サービスやオフィスの入退室管理の権限も含めてライフサイクルすべてを管理するための組織マスタ欲しい!ってなりますよね。

今回は実装コストを小さくするために GSuite に乗っかりましたが、細やかな権限管理となると人事労務 freee と連携させたい…。

もっと柔軟でわかりやすく監査可能な仕組みをバックオフィスに導入して最適化を行いたい方、蕎麦を肴に自分と飲みましょ。

jobs.freee.co.jp

というわけで今回はあらためてバックオフィス業務のもどかしさを体感しました。ベストプラクティス的なものが出来たら積極的に公開していきたいと思います。

また、こういった業務の改善は広く知見を共有し合うことが大切だと思うので、こういった方法があるよといった情報も大歓迎です。

オフィスに遊びにきてもらうもよし、ボードゲーム会に遊びに来るもよし。

https://www.facebook.com/freeeboardgame/

よろしくお願いします。

最後に

明日は新進気鋭のSRE id:atkmr による「くーべるねいてぃす」こと K8s の記事です!お楽しみに!