時点tにおける連続で結果xが出た回数(結果yが出たら回数はリセットされる)を出すSQLを書いた

カンムでCOOをしています、achikuです。

ニッチすぎて誰に話しても「?」となるが、とにかく理解できて嬉しかったSQLの話をする。

話しを簡単にする為にコイントスを用いた例題で説明する。

問題

複数回のコイントスの結果(試行ID、裏が出たか表が出たか、トスした時間)を記録したデータがある。このデータを用いて試行回数t回目において何回連続で表が出たかを出力したい。なお、一度裏が出たら連続で表が出た回数は0にリセットされる。

問題を表で表現する

最終形からイメージすると、大体以下のような事がしたい。試行回数t回目において連続でhead=trueである回数を出す。とにかく時系列に並べた際に時点tにおける連続表が出た回数が欲しい。

  • consecutive_head : 連続で表が出た回数

f:id:kanmu-tech:20210622213228p:plain
取得したい集合とコメント

解く為の考え方

まず完成形の集合を眺める。連続で表が出た回数は裏が出たらリセットされる。つまり、「裏が出る」というレコードでパーティションを作れれば良さそうな気がする。裏が出た累積回数と定義するとちょうど良さそう。ということで、Window関数を利用して良い感じにリセット出来ないかというところに行き着く。図で表すと以下のようなイメージ。

  • cumulative_tail : 累積裏が出た回数

f:id:kanmu-tech:20210622213316p:plain
青のラインがパーティション

小さく作って試す

CTEで小さく作って試すとアイディアが正しいのかどうかを手を動かしながら試しながら確認していけるのでとても良い。複雑なものを小さく分けて結果の正しさを確認していく行いはプログラムを書く際にとても役に立つ。以下はPostgreSQLで書いたがBigQueryでも少し修正すればいけるはず。

with

coin_toss(id, head, tossed_at) as (
  values
    (1, FALSE, '2021/06/22 10:00:00'::timestamp)
    , (2, FALSE, '2021/06/22 10:01:00'::timestamp)
    , (3, TRUE, '2021/06/22 10:02:00'::timestamp)
    , (4, FALSE, '2021/06/22 10:03:00'::timestamp)
    , (5, TRUE, '2021/06/22 10:04:00'::timestamp)
    , (6, TRUE, '2021/06/22 10:05:00'::timestamp)
    , (7, TRUE, '2021/06/22 10:06:00'::timestamp)
    , (8, FALSE, '2021/06/22 10:07:00'::timestamp)
    , (9, FALSE, '2021/06/22 10:08:00'::timestamp)
    , (10, TRUE, '2021/06/22 10:09:00'::timestamp)
    , (11, TRUE, '2021/06/22 10:10:00'::timestamp)
)

select
  c.id
  , c.head
  , c.tossed_at
  , sum(case when c.head = false then 1 else 0 end) over (order by c.id) as cumulative_tail
from coin_toss as c

これで上に乗せた図の cumulative_tail が出せる事は分かった。後は cumulative_tailパーティションを切って表が出た回数を試行順に累積していけば良い。

回答

with

coin_toss(id, head, tossed_at) as (
  values
    (1, FALSE, '2021/06/22 10:00:00'::timestamp)
    , (2, FALSE, '2021/06/22 10:01:00'::timestamp)
    , (3, TRUE, '2021/06/22 10:02:00'::timestamp)
    , (4, FALSE, '2021/06/22 10:03:00'::timestamp)
    , (5, TRUE, '2021/06/22 10:04:00'::timestamp)
    , (6, TRUE, '2021/06/22 10:05:00'::timestamp)
    , (7, TRUE, '2021/06/22 10:06:00'::timestamp)
    , (8, FALSE, '2021/06/22 10:07:00'::timestamp)
    , (9, FALSE, '2021/06/22 10:08:00'::timestamp)
    , (10, TRUE, '2021/06/22 10:09:00'::timestamp)
    , (11, TRUE, '2021/06/22 10:10:00'::timestamp)
)

, coin_toss_with_cumulative_tail as (
  select
    c.id
    , c.head
    , c.tossed_at
    , sum(case when c.head = false then 1 else 0 end) over (order by c.id) as cumulative_tail
  from coin_toss as c
)

select
  t.id
  , t.head
  , t.tossed_at
  , t.cumulative_tail
  , sum(case when t.head = true then 1 else 0 end) over (partition by t.cumulative_tail order by t.id) as consecutive_head
from coin_toss_with_cumulative_tail as t

どういう場合に使うのか

頻繁にツボから紅白の玉を取り出すことがある人達は便利に利用出来るSQLになっていると思う。それ以外にも例えばゲームを連続で何回成功したらその後n回の継続率に影響があるのか、連続何日サイトを訪れることでその後n日継続率に影響があるのか、等を調べる際にも使えるかもしれないが、ニッチな集計要件なので是非この機会にこのSQLを起点に分析を考えてみてみるのはいかがでしょう。

採用してます

「現場にある迫真の具体性を明らかにし、現状の課題を言語化/定量化し、チームの課題認識を揃える」という職を募集しています。データアナリストやマーケターと呼ばれることが多い職種なのですが、人によって定義がブレるので「現場にある迫真の具体性を明らかにし、現状の課題を言語化/定量化し、チームの課題認識を揃える」職としか言いようがないなと最近感じております。そのためにはそれぞれの専門領域はあれでも、定性調査だろうと、定量調査だろうと、効果検証だろうと、SQLを書くだろうと、Notebookを書くだろうと、なんでもやるチームです。以下を読むとやっていることがもう少し具体的になるかもしれません。

「あぁぁこのクエリ確かに面白いな!」と思ったら、achiku までお声掛けください!一緒にニッチな集計要件の話で盛り上がりましょう。

カンムにおけるインフラの考え方をまとめた「インフラマニフェスト」のご紹介

カンムでバンドルカードのバックエンドやインフラを担当している summerwind です。

バンドルカードではスマホ上で Visa のプリペイドカードを発行して決済に使える機能を提供しており、クレジットカード情報を扱っていることから、インフラの観点では高いセキュリティを維持することが重要になっています。バンドルカードのシステムは API や国際カードブランドと接続している決済システムなどの複数のコンポーネントで構成されていますが、システムが構築された時期によって構成や設定の方針などが異なるため、より高いセキュリティを達成するためにシステム構成の変更や整理、設定の見直しを日々進めています。

構成や設定の見直しを進めていく中で、全体的な方針や目指している姿を言語化しておいた方が周囲のエンジニアにも理解が得られやすいのではないかと感じたため、インフラに対する考え方や方針を言語化した「インフラマニフェスト」を定義することとしました。この記事では社内に公開しているマニフェストの一部を抜粋して紹介したいと思います。なお、日常的に AWSGCP を活用されているエンジニアの方には当然の内容だと思われるかもしれませんが、今回は「あえて言語化する」ことを目的としているので、その点はご了承ください。


このインフラマニフェストではカンムのインフラを「こうしていくんや!」という方針的なものを言語化しています。 これは2021年のカンムのインフラの状況に基づいて定義されており、今後の改善などにより将来的には大きく方針が変更される可能性があります。

対象

このマニフェストが対象とする「インフラ」には以下が含まれます。

ワークロードとストレージを分離する

アプリケーションやバッチなどのワークロードとそのデータを保存するストレージは明確にリソースを分離し、ワークロードとデータが同居しない構成や設計を採用します。

例えば、Redash を動かすための EC2 インスタンスがあり、そこで Redash、Redis、PostgreSQL を実行していたとします。これらは以下のようにリソースを分離できます。

  • Redash: ECS コンテナ (ワークロード)
  • Redis: ElastiCache (ストレージ)
  • PostgreSQL: RDS (ストレージ)

このように分離するのは、ワークロードは一般的に高速に動作しスケーラブルであることが求められ、また比較的短命であることに対し、ストレージは安定的に稼働し続けることが求められるなど、それぞれの要件が大きく異なるためです。複数の要件を達成しようとすると、どうしてもトレードオフが発生してしまい全ての要件を達成するのが困難になります。ワークロードとストレージを明確に分離すればそれぞれの役割における要件が達成しやすくなります。

なお、ストレージは一般的に運用負荷が高くなりがちなので、積極的にマネージドサービスを活用していきます。

ペットではなく家畜へ

ワークロードを実行するリソースは、ペットのように長時間稼働させて可愛がるのではなく、家畜のように使い捨てます。常に「私が死んでも代わりはいるもの」と言えるよう、デプロイのたびにリソースが入れ替わり続けるような状況を目指します。

これは、リソースを長時間稼働させればさせるほど、設定ドリフトが発生して設定や構成の変更がしにくくなったり、脆弱性の発見によりセキュリティが低下したりすることが背景にあります。長時間稼働により、設定ドリフトやセキュリティの低下に対応するための運用負荷も同時に高まっていきます。もしリソースを頻繁に使い捨てることが前提となっていれば、設定ドリフトは発生せず、最新のセキュリティを組み込むことも可能になり、アプリケーションやシステムの構成変更もしやすくなります。

ペットと家畜の話は以下の文書も参考してください。

メタデータで管理する

ワークロードやストレージなどの全てのリソースは名前のような一意の識別子に加え、メタデータを付与して管理します。

これは、インフラの運用ではリソースを様々な軸で集約して扱うシーンが多いためです。例えば、以下のようなシーンでは名前のような識別子だけでリソースを管理するには限界があります。集約したい軸ごとにメタデータを付与し、その値ごとに集約できると運用上の様々な課題を効率化できます。

  • サービス A とサービス B の API インスタンスのメトリクスだけを集約して見たい
  • 本番環境で稼働中の全ての RDS インスタンスのエラーログだけを集約して見たい

リソースには次のようなメタデータを必ず付与し、項目単体あるいは複数の項目を組み合わせてリソースの管理を可能にします。またこのようなメタデータを付与できるサービスやツールなどを積極的に採用することとします。

メタデータ 概要
環境 リソースがどの環境用 (本番環境、ステージング環境など) のものなのかを示す
サービス どのサービスあるいはプロダクトに属しているかを示す
役割 サービスの中での役割を示す (API、管理ツールなど)

データにより宣言的に管理する

全てのリソースの設定や状態はデータファイルに構造化データとして定義し、専用のツールを使用してその定義内容を実際のリソースと一致させることで管理します。構造化データには JSONYAML、HCL2 形式のいずれかを採用し、それらの形式でリソースを宣言的できるツールを積極的に採用します。

これまで一般的なインフラのリソースの多くは手順書などの「命令的」な定義により管理されてきましたが、これは順序に依存する仕組みであり、手順の変更などによって設定を再現できなくなったりする問題があります。古いドキュメントの手順に従って作業を実施したら環境を再現できなかったという経験がある方は多いのではないでしょうか。

この問題を解決するために、手順ではなく以下のようなデータファイルにリソースのあるべき状態を定義し、その定義に基づいてリソースの状態を一致させるツールを積極的に採用します。この例では ECS クラスタprdメタデータ付与された状態である、ということを Terraform 向けの HCL2 形式で定義しています。これらのデータファイルは Git などで管理することにより、変更のレビューやテスト、特定時点のリソースにロールバックする、といったことが可能になります。

resource "aws_ecs_cluster" "prd" {
  name = "prd"

  tags = {
    Name        = "prd"
    Service     = "A"
    Environment = "prd"
  }
}

なお、ここではクラウドサービスのリソース管理を例に挙げましたが、Linux などのインスタンスのシステム構成や、ルーター機器の設定などについても同様に可能な限り宣言的にデータファイルで管理します。

継続的にテストをする

インフラのリソースをデータとして宣言的に定義すると、次のようなテストが可能になります。これらのテストは CI サービスを利用して、バージョン管理システムに変更を追加する毎に実行し、レビュー時にはその検証結果が妥当なものであるかを評価します。

  • ツールを使用して定義の内容とリソースの実際の設定の差分を検証する
  • ポリシーツールを使用して、意図しない設定の定義が含まれていないかを検証する

これらのテストを継続的に実行することで、意図しない変更に早期に気付けたり、データファイル以外で発生した設定ドリフトを検出できるようになります。

本番環境、ステージング環境、開発環境を使い分ける

リソースは本番環境、ステージング環境、開発環境の3つの環境に用意して使い分けます。使用する環境とその用途は次の通りです。ステージング環境は本番環境と同等の環境として維持し、リリース前の最終的な動作確認や検証にのみ使用します。レビューを受けていない開発中のコードなどは開発環境に対してのみデプロイします。

環境名 用途
本番環境 利用者にサービスを提供するための環境
ステージング環境 本番環境と同じ構成でテストを実行するための環境であり、リリース用のコードのみをデプロイする
開発環境 開発中のコードの動作を検証するための環境であり、開発中のコードをデプロイする

これらの環境は全て独立したものとして管理し、各環境のリソースが他の環境のリソースに影響しないようにします。また、AWS などのクラウドプロバイダーについては、環境ごとにアカウントを分離します。

シンプルにする

リソースの構成は可能な限りシンプルにします。リソースが少なければ少ないほど運用上の負荷が減るため、少人数で開発と運用をしているカンムにおいてシンプルさを選択することはとても重要だと考えます。具体的には次のような選択をします。

  • クラウドサービスの機能を積極的に活用する
  • 自前で実装せず、オープンソースソフトウェアを活用し、その結果をコミュニティにフィードバックする
  • 最小限のリソースで構成する

いかがでしたでしょうか。社内のマニフェストにはより多くの項目について記載していますが、ここでは紹介しきれないのでまた機会を見つけてご紹介したいと思います。

カンムではセキュアでモダンなクレジットカード決済インフラを作りたいエンジニアを積極的に採用しています!

カンムを支える技術 ~機械学習編~

バックエンドエンジニアの吉田です。カンムでは機械学習を用いた機能開発を担当しています。 バンドルカードでは後払い機能であるポチっとチャージで機械学習が使われています。 去年のAdvent Calendarで石澤さんが カンムを支える技術2020 という記事を書いてくれていましたがそこではあまり触れられていなかった機械学習まわりの取り組みについて簡単にご紹介します。 バンドルカードのサービスはAWSで構築されているので基本的にはAWSに寄せつつも機械学習ではGCPも活用しマルチクラウドで運用しています。

f:id:kanmu-tech:20210610153614p:plain

Data Preparation

DWHとしてBigQueryを利用しています。BigQueryにはバンドルカードのトランザクションデータやFirebaseで取得したアプリのイベントログ、サーバのアプリケーションログ等が集約されておりデータ分析やA/Bテストの集計、障害調査等に使われています。 機械学習においては、時系列データの各種統計量やラグ特徴量の追加といった特徴量エンジニアリングや前処理にもBigQueryを使っています。SQLで処理できるものは基本的にBigQueryに任せて学習用のデータセットを作成しています。

RDSに保存されているバンドルカードのデータは日次でBigQueryに同期しています。 ここでは単純にPostgreSQLのテーブルをほぼそのままBigQueryに転送しているだけで複雑なワークフローは必要なかったことと、GUIも必要なかったのでシンプルなDigdag/Embulkを採用しECS/FargateのScheduled tasksで実行時のみコンテナを立ち上げて処理するような構成にしています。エラーのときは最低限Slackに通知しているのと容易にリトライができるように同期処理が冪等になるようにだけは気をつけています。

続いてGCPではCloud SchedulerからCloud Dataflowのジョブが起動されます。 ここではBigQueryからデータを取得し特徴量エンジニアリングや前処理を行った後、CSVファイルでCloud Storageにアップロードされます。 これも同様に日次で実行されますが、トリガーはCloud Schedulerによる定時実行なので先ほどのBigQueryの同期処理の完了時間からバッファを持たせて実行させています。本当はBigQueryへのデータ同期の正常終了に続けてジョブ実行されるようにフローを組みたいところですが同期に失敗していても大きな問題はないのとそもそもほぼ失敗することはなく実運用上困ってはいないのでよしとしています。ここで作成されたデータセットがモデルの学習で使われます。

Training & Serving

本番で稼働するモデルの再学習は新しく学習データが追加されるタイミング (ポチっとチャージでは月初) や特徴量の追加、パラメータの変更などモデルが更新されるタイミングで行われます。

モデルの学習とサービングはSageMakerを利用しています。学習/推論用のコンテナだけ用意しておけば、データセット、モデル/メトリクス等の成果物、推論用のエンドポイントを一元管理してくれるので非常に便利です。 推論コンテナはGunicorn/Flaskを使ったシンプルなREST APIとなっています。

モデルの学習からサービングまではStep Functionsによって実行されています。すべてのタスクが完了したら、学習結果のログやメトリクスから性能に問題がないことを確認します。 Lambdaから呼び出す推論エンドポイントは環境変数で管理されているので、まず検証環境のエンドポイントを書き換えてテストデータでリクエストを投げてみて想定どおりの結果が返ってくることを確認します。問題がなければ本番環境も切り替えます。モデルの更新はそこまで頻繁に行われるわけではないのでこの辺は自動化せずに慎重に人間が確認をするようにしています。

推論のリクエストパラメータが変更されるような場合にAPIのバージョニングが必要となりますがこれもLambdaで解決するようにしています。

Inference & Monitoring

バンドルカードからはリアルタイムで推論しています。アプリからのユーザの操作であったりバッチ処理であったりトリガーは様々ですが、推論及びその後処理には多少時間を要するので非同期で処理をしています。 RDSにジョブをenqueueすることでWorkerが推論処理を行い、その結果をRDSに書き込みます。

モニタリングに関してはエラーやレイテンシ等の各種メトリクスのMackerelによる監視やRDSのジョブキューの監視を行い異常があった場合はslackやPagerDutyで通知をしています。 また、推論のリクエストと結果に異常がないか、後処理の結果が想定どおりであるかRedashのダッシュボードなどを用意して確認をしています。

推論時の特徴量のデータドリフトの監視の為にSageMaker Model Monitorなども検討しましたがサービスの特性上急にinput/outputの分布が変わったりすることもないし継続的にモデルを学習させているのでそのタイミングで性能劣化や分布に変化がないか確認すれば充分なので見送っています。

Development

開発はローカルマシンで行うことが多いですが、モデルの学習などコンピューティングリソースが必要な場合はGCPインスタンスも使います。 開発環境は基本的にすべてコンテナ化してローカルでもクラウドでも同じ環境で開発ができるようにしています。 パッケージ管理はpoetryを使い、linter/formatterにpysenを使っています。 実験管理はMLflow Trackingを使っています。GitHub issue, データセット, モデル等の成果物, メトリクスを一元管理して過去の実験をすぐに再現できるようにしています。

まとめ

機械学習の立ち上げ当初はモデルや推論APIの開発, バンドルカードへのインテグレーションまですべてひとりで開発していたので、パイプラインの整備までは手が回らず手動でEmbulkを実行して、SageMaker Notebookを使ってモデルを学習させて、、みたいな最低限の状態からスタートしてそこから少しづつ自動化したり改善を行って今のような構成になりました。まだまだ改善したいところはたくさんあります。エンジニア積極採用中です。

kanmu.co.jp

Twitterのフォロワーに一様分布を依頼してみた

はじめに

こんにちは、カンムでバンドルカードの機械学習部分を担当しているfkubotaです。先日、Twitterでこんな感じのアンケートを取ってみました。

f:id:kanmu-tech:20210528204802p:plain

このアンケートの面白いところは、回答者は回答しないと現在の投票成績が見えないというところです。参加者は、「1を取る人が多いハズ、、、であれば2,3,4か?」とか裏を取ろうとします。裏の裏を取ろうとする人もいるでしょう。我ながらTwitterの投票システムを利用した面白い実験だったと思います。

結果はこんな感じ。

951票もいただきました。ありがとうございます。m(_ _)m

そんでもって

もちろん、面白い実験をして、あー面白かったで終わらせるつもりはなく、結果を考察するまでがこの実験の目的です。ちなみにみなさんは、上の結果を見て一様分布だと思いますか? 「全ての数字が同じではないから一様分布ではないよ」という意見もあれば、「まあこの程度の違いなら誤差だと思うよ」という意見もあるでしょう。このあたりどう議論すればいいでしょうか? 多少の誤差とは言いますが、どこまでが許せてどこまでが許せないのでしょうか? やっぱり定量的に賢くやりたいですよね。こういったときに使えるのがいわゆる統計学です。いろいろ手段はあると思うのですが今回は、統計的仮説検定というやつを使ってみます。統計的仮説検定がよくわからない人は、「検定 サイコロ」とか「検定 コイン」とかでググると簡単な例が出てくるので目を通すと良いかもしれません。この記事では、できるだけ検定がわからない人にもわかるようにも書きますが、事前に勉強しておくとより読みやすいと思います。 一様分布っぽさがふわふわしていて定量的にあつかえないもどかしさは、検定という手続きをつかえば定量的に扱えるという事が伝えられたら嬉しいです。

適合度検定

適合度検定(解説はこの記事とか)というのを使います。この検定はある事象がa:b:c:dで起こる時に実験値とのズレが誤差の範囲内であるかどうかを検証する時に使います。今回の場合は、アンケートの結果が一様分布になるはずだという仮説1:1:1:1に対して、実験結果は%で25:18:26:30になっており、投票数は238:181:247:285となっています。これが誤差の範囲なのかそれ以上に意味のある結果なのかを検証します。

計算するにあたりこちらのサイトを利用しました。
今回の条件数は4、観測度数はそれぞれ、238, 181, 247, 285であり、帰無仮説(一様分布である)のもとでの確率は1/4, 1/4, 1/4, 1/4となっているので、そのように入力して計算しました。また、有意水準は5%としています。 結果は以下のようになりました。

統計検定量χ2 = 23.2965
有意水準に相当するχ2の値 = 7.81743
p値 = 0.000035025

適合度検定はχ2検定で片側検定ですので、統計検定量χ^2有意水準に相当するχ^2の値 を上回っていることにより帰無仮説は棄却されます。p値についてちょっと解説すると(怖い...) 、今回の「アンケート結果は一様分布に従う」という帰無仮説が正しいとした場合、今回の結果は、0.0035%程度の確率で起こるよということを示しています。一様分布が正しい分布の場合でも今回の実験結果は起こり得る、ただし「0.0035%という低い確率」でということになります。あまりにも起こる低い確率で起こるのであればそれは仮説が間違っていると考えるのが自然だよね。であれば、5%までは許して5%以下の確率で起こる場合は、仮説が間違っていると考えようということで、有意水準5%を設定しています。

今回の結果としては、仮説が棄却されたので、検定の手続き上ではアンケート結果はどうやら一様分布ではないようです。「一様分布にして」とお願いしたので、一様分布にしようと参加者がいろいろ戦略を立てて投票しその戦略が偏った(似たような戦略を取る人が多かった?)結果なのかなと考えてみたりしました。ただこれ以上のことは今回の検証では何も言えません。今回の適合度検定で言えることは、「一様分布ではなさそう」というところまでです。「適当に投票して」というアンケートだと結果は変わったのかな?と思ったりもしました。

ちなみにどの程度であれば棄却されなかったのかと数字を少し変えて遊んでみたところ、 238, 181, 247, 285238, 230, 247, 285 にしたところ棄却されませんでした。
僕には285の数字がまだ大きく見えて一様分布には見えないなぁと思うのですが、適合度検定にはこれが一様分布に見えるようです。黙って従います。

今回の実験の背景

今回、なぜこのような実験をしようと思ったのか少し話ます。
弊社カンムはバンドルカードというサービスを開発していて、日々新しいデータが大量に入ってきます。僕自身、機械学習を担当しているということもありあらゆるデータに日々触れています。その時、もっとこうしたら良いんじゃないか?とかこれはどう説明できるだろうかなど仮説を立てて検証をしたくなることがあります。しかし僕自身この辺りの知識・業務経験に乏しくて、うまく扱えず歯痒い思いをよくしています。目の前にこれだけ質の高いデータがあるのに自分の力不足のために活用できないのはもったいないなと思い、最近はもっぱら統計的因果推論とか言われる分野を勉強しています。そして、ただ本を読むだけだと退屈だということで第一弾として簡単にできる検定をやってみたという次第です。アンケートご協力頂いた方、とても楽しかったです。ありがとうございました。

次回は、もう少し複雑な統計学の知識を使った分析をやりたいと思います。

お決まりですが

上記にもあるように、もっともっと輝けるのに力を発揮できずに眠ってしまっているデータが弊社には大量にあります。そのデータを統計学などのデータ分析の知識を生かしてさばけるデータアナリストを募集しています。僕もたくさん勉強してこのあたりも少しずつできるようになりたい。
一緒にやりませんか?

https://kanmu.co.jp/jobs/data-analyst/

僕は、2021年2月に入社してからもうすぐ4ヶ月が経ちますがとても入社してよかったなと日々思います。
なによりデータ、テクノロジーに対するリテラシーが高くデータ分析をする身としては、非常に働きやすく何より楽しいです。
社内のほとんどの人がSQL書けちゃったりします(参考記事)。 もちろんエンジニア以外の人もです。
他には、月に一度の TechDayでは、エンジニア・非エンジニアが日頃の業務の非効率をテクノロジーで解決するというイベントがあります。非エンジニア同士がGASがどうだとかSlackのbotがどうだとか議論したりするんです。僕より遥かにGASに詳しい非エンジニアがかなりいます。これは少し悔しい。

上記は一例ですが、こんな感じで企業文化がマッチすれば、楽しく働けることは少なくとも僕は保証しますので興味ある方は、データアナリストに限らず応募してください!!:)

https://kanmu.co.jp/jobs/

サイバーセキュリティ攻撃を学ぶことで防御を学ぶ

カンムでセキュリティを担当している12banです。といっても、つい最近までコーポレートエンジニアをやっていました。 一応、セキュリティはいろんな業務の中の1つとして、10年以上関わってきました。

セキュリティと一言に言っても実はものすごく幅広いです。 そんな中でPenetration Testingと呼ばれるセキュリティテストの分野があります。 これは一般的にはセキュリティ会社のペンテスターと言われる職種の人が学習する分野なのですが、 事業会社で攻撃を防御することにも役に立つのではと考え、今回チャレンジしてみました。

TryHackMeとは

今回チャレンジしてみたのはTryHackMeというサービスです。 このサイトはペンテスト(侵入攻撃)を手を動かして学べるサービスです。

全部で5つのコースがあるのですが、面白そうだなって思ったのは、 Offencive Pentesting と Cyber Defenceのラーニングパスです。

f:id:kanmu-tech:20210518190308p:plain
TryHackMeのラーニングパス例

このうち、攻撃を学びたかったため、Offencive Pentestingのパスを選んでやってみました。 下記の画像がOffcencive Pentestingの序盤です。

f:id:kanmu-tech:20210518190432p:plain
Offencive Pentesting序盤

難易度Easyの4つの部屋があり、最初のTutorial以外の3つの部屋で実際に攻撃対象となるマシンがあり、 それを攻撃して、特権(管理者権限)を取っていきます。

このうちvulnversityという部屋の攻略について記事をここに書きたいところですが、かなり内容が専門的になる、 かつ、かなり長文になるため、個人のブログに書きました。興味がある方はそちらを読んでみてください。

note.com

パズルのようで面白い

現時点で難易度Easyを4つ、難易度Mediumを1つ終わらせています。かなり面白く毎日少しずつやってます。 まだちょっとの経験しかないですが、攻撃はパターン化されているなと感じました。 言うなれば高校数学の解法パターンみたいな感じでしょうか。 最終的にはOffencive Pentesting と Cyber Defenceの2つのラーニングパスを最後までやってみようと思っています。ここまでやりきればもっと見えてくるものはありそうだと感じてます。

ちなみに今まで経験したパターンは、だいたい下記の流れです。

  • nmapを使って空きポート、使ってるサービスやアプリケーション名、バージョンを調査する
  • 脆弱性などを突いて、対象マシンに侵入する
  • 侵入後、同様に脆弱性などを突いて特権を取る

学び

今のところ、脆弱性を突いて対象マシンに侵入することが多いので、脆弱性管理の重要性を肌感として感じてます。 今までは脆弱性管理は重要と知っていても、ちょっとぐらい大丈夫という気持ちがあったような気がします。 特に従業員が使用するデバイスの方はモチベーションが上がらなかったり...

しかし、今は脆弱性管理をきっちりやりたいって気持ちでいっぱいです。脆弱性をついた攻撃は自動化されてるので、 使ってるアプリケーションとバージョンがわかってしまえば、簡単に脆弱性をついて侵入できることを実感として知ることができました。

攻撃を学ぶことで防御を学ぶことができる、というのは正しかったようです。またセキュリティ対策を会社全体で実行する時に、攻撃を知っていることで納得感のある説明ができる気がします。

事業会社のセキュリティエンジニアの良さ

このようにペンテストの経験は攻撃者の手法を知り、防御に活かすという点で、事業会社のセキュリティエンジニアにも有用だと感じました。

ちなみにこの学びは誰かから強制してやったわけではありません。業務に活かすことができるのでは?と自分で考えて行動しただけです。 事業会社のセキュリティエンジニアが扱うセキュリティ範囲は幅広いです。PCI DSSなどの第三者認証、IdPやMDMなどのエンドポイントセキュリティ、IaaSセキュリティ、プロダクトセキュリティ、リスクマネジメント、規定や監査など幅広い。 そんな中で今までの経験を活かせるところは活かし、足りないところは自分で考えて学んで活かす。そして顧客や企業、ビジネス、従業員を守ることで競合優位性を高めていけるのは事業会社のセキュリティエンジニアならではかなと思います。

最後に

セキュリティエンジニアに限らず、下記のように他にもセキュリティに関われるポジションがあるので、 まずは気軽にカジュアル面談してみませんか?

新しい環境にdotfilesをワンライナーで反映させる

はじめに

こんにちは、カンムでバンドルカードの機械学習を担当しているfkubotaです。テックブログ初参加なので今回はライトな内容で投稿させていただきます。イケイケ機械学習記事はいずれ...

この記事では、最近ちょっとだけ改善した dotfiles の管理について紹介したいと思います。
dotfiles とは、ホームディレクトリ($HOME) 下にある、.vimrc, .bashrc などの設定ファイル群を指します。
最終的には、コマンド1つでこのdotfilesが新しい環境に反映されます
魔法のコマンド:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/fkubota/dotfiles/master/install.sh)"

このコマンドでdotfilesが反映されると、
これが f:id:kanmu-tech:20210520111556p:plain

こうなります f:id:kanmu-tech:20210520111616p:plain

結論だけ見たい方は、方法紹介 から見ると良いと思います。

  • こんな人が想定読者
    • dotfiles 管理しなきゃと思っているけど、何もしてません...TT
    • dotfiles をまとめたリポジトリはあるよ。でも新しい環境に反映させるのは少し面倒...。

上記に該当する人に有用な記事になるように頑張って書きます。

参考記事

基本的にはこの記事を参考にしています。
この記事の作者ほどヘビーユーザではない&もう少し気軽に使いたいのでちょっとコードを変更しています。

dotfilesを管理するモチベーション

機械学習をやっている人は、新しい環境で作業を行うという経験が多いのではないでしょうか?
会社の計算サーバーにssh接続して使うとか、GCPAWSのマシンを借りるとか。その都度、そこで自分の開発環境を構築するはずです。僕の場合であれば、vim, tmux, fish のオレオレ設定を普段使っているので新しい環境でもそれを構築しています。

僕自身、以前はめちゃくちゃしんどい管理の仕方をしていました。
歴史としてはこんな感じです。

  1. 新しい環境で作業するたびにdotfilesをコピペ
    • この管理だとどの環境が最新状態なのかわからなくなります
  2. gitで管理して、シンボリックリンクを作る
  3. シンボリックリンクを行うシェルスクリプトを作成
    • これで大分楽になった
  4. git cloneからシンボリックリンク作成までを ワンライナー
    • NOW!!

方法紹介

まずは、dotfilesリポジトリgithubで作成してください。
ちなみに僕のリポジトリこちら

今回は簡単のために、.vimrc のみを管理対象とします。
dotfiles リポジトリ内に、.vimrc を作成します。

touch dotfiles/.vimrc

次に、シンボリックリンクを行うためのシェルスクリプトをdotfilies下に作成します。
ファイル名は、install.sh としてください。
install.sh の中身は以下のようにします。

DOT_DIR={dotfilesリポジトリをクローンするディレクトリ}

# clone
git clone https://github.com/{your account name}/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

上記の {dotfilesリポジトリをクローンするディレクトリ} と {your account name} をそれぞれ適切な値に設定してください。
僕の場合であれば、

DOT_DIR="$HOME/Git/dotfiles"

# clone
git clone https://github.com/fkubota/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

となります。これで準備完了です。
このスクリプトを実行すれば、DOT_DIR で指定したディレクリにdotfilesリポジトリがクローンされ、.vimrcシンボリックリンクされます。lnコマンドに-fオプションが指定されているので、すでにある場合に上書きされてしまうので困る場合は外してください。

あとは、ワンライナーを叩くだけ!! です!
どこのディレクトリ下でもいいので、

bash -c "$(curl -fsSL https://raw.githubusercontent.com/{your account name}/dotfiles/main/install.sh)"

と叩いてみてください。指定した場所にリポジトリがクローンされ、シンボリックリンクが、~/.vimrc に作成されるはずです。 (デフォルトブランチ名がmainではなく、masterである場合は、mainmaster に変更してください)

ホームディレクトリ下で

ls -la

などで確認できます。僕の場合は、

.vimrc -> /home/fkubota/Git/dotfiles/vim/.vimrc

と出力されていました。

以上が簡単な紹介です。これを基本として追加したい項目を増やしていくだけです。 僕の場合は、 vim, tmux, fish のdotfilesを管理する以外にも必要なものを追加しています。
後はお好みで楽しんでください。
dotfiles、育てるとかわいくなっていきますよ。

おわりに

今回の記事で弊社のテックブログとしては、3本目。
今後も続々と楽しい記事をあげていく予定です。
カンムに少しでも興味ある方はぜひこちらから応募してください!!!

採用 | 株式会社カンム

PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を使う

カンムでバンドルカードのバックエンドやインフラを担当している summerwind です。

バンドルカードはスマホ上で Visa のプリペイドカードを発行して決済に使える機能を提供しているため、クレジットカードのデータを安全に取扱うことを目的として策定された、クレジットカード業界のセキュリティ基準である PCI DSS に準拠しています。

PCI DSS にはセキュリティ基準として様々な要件が定義されており、中には次のようなものがあります。

11.3.4.1 Additional requirement for service providers only: If segmentation is used, confirm PCI DSS scope by performing penetration testing on segmentation controls at least every six months and after any changes to segmentation controls/methods.

これは、ネットワークセグメンテーションを使用してカードデータを扱う環境を分離している場合は、少なくとも6ヶ月ごとにそのセグメンテーション制御に対するテストを行ない、意図した状態になっているかをテストすることが求めています。実際には、カードデータを扱わないシステムとカードデータを扱うシステムの間の通信が必要なプロトコルやポートに制限されていることをテストします。

これまでカンムでは Nmap などのツールを利用してこのネットワークセグメンテーションのテストを行なってきましたが、以下のような課題がありました。

  • テストの実行手順が明確に定義されていない
  • Nmap などのツールの実行には時間がかかる

もうちょっと簡単に素早くテストできないかと考えて見つけたのが、2020年末にリリースされた VPC Reachability Analyzer です。これは AWS VPC 内の2つのエンドポイント間で通信の到達性を検証してくれる機能で、まさにセグメンテーションテストの要件にぴったりです。

VPC Reachability Analyzer の実行は AWS コンソールから簡単に行えます。VPC Reachability Analyzer のページにアクセスしたら、Create and analyze path ボタンを押して、Path を作成します。Path はテストしたい2つのエンドポイント間の経路を示すものになるので、送信元と送信先および通信に使用するプロトコルを指定します。

f:id:kanmu-tech:20210511131831p:plain
Create and analyze path

Path を作成すると初回の検証が自動実行され、これが完了すると、到達性について結果が表示されます。Not reachable であれば到達不可であることが確認できたこととなり、セグメンテーションが有効であることが分かります。

f:id:kanmu-tech:20210511131909p:plain
Path

後日同じ経路で改めて検証を実行したい場合は、作成した Path の画面にある Analyze path ボタンを押すだけですぐに検証ができるので便利です。PCI DSS の要件 11.3.4 では開発者以外の第三者的な立場でこのテストを実行することを求めているので、そういった観点でも VPC Reachability Analyzer を活用するのがよいのではないかと考えています。

今回は PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を活用する方法を紹介しました。今後も PCI DSS の要件を達成する方法などを紹介できればと思っています。

カンムではセキュアでモダンなクレジットカード決済インフラを作りたいエンジニアを積極的に採用しています!