やーまんぶろぐ

気が向いた時にだけ書くブログ

欧州一般データ保護規則(GDPR)についての個人的解釈

いよいよ2018年5月に適用が開始されるGDPR。

GDPRとは

EU一般データ保護規則 - Wikipedia

"今回提案されたEUの新たなデータ保護制度はEUデータ保護法の対象範囲を、EU居住者のデータを処理する外国の全ての企業に拡大する。EU全域のデータ保護規制を一致させることで、欧州以外の企業が規則を遵守しやすいようにする。しかし、これを実現する代償として、データ保護を厳格に遵守させる制度、つまり全世界の売上高の4%を上限とする厳しい罰金を導入する。"欧州議会版では過料は5%に増額された。しかし欧州議会欧州委員会、欧州閣僚理事会の三者の交渉の後、GDPRの文言、および、遵守しなかった場合の金銭的罰則についても全般的な合意がなされた

罰金

全世界の売上高の4%。例えば1兆円の売り上げがある企業であれば400億円ということ。

営業利益が全て吹っ飛ぶくらいのインパクトがあるので無視はできないですね。

AWS

AWSの責任範囲については問題なさそう。
aws.amazon.com

欧州含む全世界向けサービス提供者例(ZOZOSUIT)

日本から欧州含む全世界向けにサービスを提供しようとしているZOZOSUITもGDPRが課題になりそうな記事が出ていました。(ZOZOSUITのインフラがどこで動いてるかはわかりませんが)

ZOZOSUITに死角ありーー世界のデータサービス業界の景色を一変させる「GDPR」とは | AMP[アンプ] - ビジネスインスピレーションメディア

いくつか記事から引用。

日本で包括的に世界のユーザー情報を管理する、という設計自体成り立たない。


EU圏内の個人データの処理に関して言えば、子会社をEU圏内に設立するというのが一番現実的なオプションだと思います。


法的な対策をとれば一部のデータ移転の可能性もゼロではありません。しかし、消費者一人ひとりとそのような契約を結ぶのはコスト・時間を考慮すると現実的とは言えないでしょう。


EUのユーザーに関してはEU法人が個別に管理する。


企業は付け焼き刃の対策で既存のモデルをGDPRに対応させようとするのではなく、ユーザーとなる消費者の思いを含め、ビジネスの初期段階から個人データ保護についてしっかりと考えなければいけません。

個人的解釈

消費者一人ひとりと契約を結ぶことは現実的ではないということで、
日本からEU圏内にビジネスを展開する場合は、EU法人を作ってデータを独立させるしか解決策がなさそうに見える。

解釈があってるかどうかは自信なし。

EC2Instances.info でEC2料金をCSVで出力する

EC2の料金を取得していろいろ加工したいと思ったときに、公式の情報だと加工がめんどくさい。
APIもあるけど、JSON形式なのでやっぱり加工がめんどくさい。

EC2Instances.info というサービスでCSVで出せるので、これを使うことにしたのでリンクをメモしておきます。

EC2Instances.info

Amazon EC2 Instance Comparison

AWS Amplifyを使ってAmazon Cognitoを体験してみる

メインはAmazon Cognitoの理解です。

Amazon Cognitoまわりの作成は簡単にできるのですが、挙動を確認するにはUIがあるほうが理解が進むと思ったので、AWS Amplifyを使って体験してみました。

せっかくだったのでローカルで動かすだけではなく、S3にデプロイして動かしてみたのでメモしておきます。東京リージョンで作業しています。

Amazon Cognitoとは

まずはBlackBeltを読むと良いと思います。

www.slideshare.net

続いてコンソールからアクセスすると以下の説明が出てきます。

Amazon Cognito は、ユーザーのアプリへのサインアップとサインイン、ソーシャル ID プロバイダーからの ID のフェデレーション、AWS のリソースへのセキュアなアクセス、および複数のデバイス、プラットフォーム、アプリケーションにわたるデータの同期を簡単にします。

Amazon Cognitoは「User Pools」と「Federated Identities」に分かれるので、それぞれ個人的な理解を簡潔にメモしておきます。
概要は理解はできたけど、簡潔に説明するとなると難しい。。
f:id:yamano3201:20180118173024p:plain

※「Cognito Sync」は今回触っていないので説明していません。

User Pools

  • マネージドなユーザ管理サービスです。
  • サインアップ、サインイン、サインアウトなどの認証を担当しています。
  • FacebookGoogleのような外部認証プロバイダと同列で、独自の認証プロバイダとして動作します。

認証機能だけであればUser Poolsだけでも動作可能です。

Federated Identities

  • エンドユーザに一意のIDを割り振るためのサービスです。
  • 認証プロバイダに認証されたエンドユーザに対して、AWSリソースへのアクセスを許可することができ認可を担当しています。
  • 認可OKの場合はIAM側でSTSから一時アクセスキーが発行されます。
  • FacebookGoogleのような外部認証プロバイダやUser Poolsで認証されたエンドユーザを同一IDとして一元管理できます。

AWSリソースへアクセスするためにはFederated Identitiesが必要です。
User Poolsと統合することで外部認証プロバイダを使用することなくAWSリソースへアクセスすることが可能になります。

Amazon Cognitoをコンソールから構築してみる

実際に構築することで理解を深めていきます。

以下の記事を参考に構築しました。
dev.classmethod.jp

User Pools

Amazon Cognitoの「ユーザプールの管理」からアクセスします。

ユーザープールを作成する

「ユーザープールを作成する」→プール名を埋める→「デフォルトを確認する」→「プールの作成」と進みます。
f:id:yamano3201:20180118174330p:plain

プールID(ap-northeast-1_XXXXXXXXX)が表示されるのでメモしておきましょう。

アプリクライアントの追加

「アプリクライアント」→「アプリクライアントの追加」→アプリクライアント名を埋めて、「クライアントシークレットを生成」のチェックを外す→「アプリクライアントの作成」と進みます。
f:id:yamano3201:20180118174734p:plain

アプリクライアントID(XXXXXXXXXXXXXXXXXXXXXXXXX)が表示されるのでメモしておきます。

ユーザーの作成

「全体設定」→「ユーザーとグループ」→「ユーザの作成」→ユーザ名、仮パスワード、Eメールを埋める→「ユーザーの作成」と進みます
f:id:yamano3201:20180118175442p:plain

ステータスを見ると「FORCE_CHANGE_PASSWORD」と表示されています。

作成と同時に仮パスワードが書かれた以下のメールが飛んできます。

件名 Your temporary password
宛先 no-reply@verificationemail.com

UIがないと動作確認が難しいのでいったんここまで。

Federated Identities

Amazon Cognitoの「フェデレーテッドアイデンティティの管理」からアクセスします。

User Poolsと連携したIDプールを作成する

「新しいIDプールの作成」→IDプール名を埋める→(今回は「認証されていない ID に対してアクセスを有効にする」のチェックはどちらでもよい)→「認証プロバイダー」→さきほどメモした「プールID」と「アプリクライアントID」を埋める→「プールの作成」と進みます。

f:id:yamano3201:20180123155455p:plain

ID プールの ID(ap-northeast-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) が表示されるのでメモしておきます。

UIがないと動作確認が難しいのでいったんここまで。

AWS Amplifyを使ってAmazon Cognito体験

以下の記事を参考に構築しました。
dev.classmethod.jp

nodejsのインストール、identityPoolIdの記載、S3へのデプロイ以外はほとんど参考リンク先の記述とほぼ同じになってしまいました。。

AWS Amplifyとは

AWS Amplifyは、2017年11月に公開されたAWSを利用するWebアプリケーション向けのJavaScriptライブラリです。サインアップやサインイン、MFA、追跡またはメトリクスの分析、コンテンツ管理、またはサーバーレスAPI統合などの実装が容易にできるように設計されています。

事前準備

適当にAmazon Linuxインスタンスを起動して試しました。

node jsをインストール

以下のリンクから最新版を確認。
Download | Node.js

$ wget https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-x64.tar.xz
$ xz -dv node-v8.9.4-linux-x64.tar.xz
$ tar xfv node-v8.9.4-linux-x64.tar

$ ln -s node-v8.9.4-linux-x64 node
(.profileを作成)
$ cat .profile
export NODE_HOME=$HOME/node
export NODE_PATH=$NODE_HOME/lib/node_modules
export PATH=$NODE_HOME/bin:$PATH

$ source .profile

$ node --version
v8.9.4
$ npm --version
5.6.0
yarnをインストール
$ npm install -g yarn
Reactひな形を作成

(参考リンク先コマンドのyarn global add create-react-app だとcreate-react-appが動かなかったのでnpmで実行)

$ npm install -g create-react-app
$ create-react-app amplify-react-sample
$ cd amplify-react-sample
動作確認
$ yarn start

Amazon LinuxインスタンスのSecurityGroupの3000ポートを開けて、ブラウザから以下のようなURLにアクセスするとReactが動いていることが確認できます。
http://#{Amazon LinuxインスタンスのパブリックIP}:3000/

f:id:yamano3201:20180123160656p:plain

Webアプリケーションの実装

まずは、AmplifyライブラリとAmplifyのReact拡張ライブラリのインストールを行います。

$ yarn add aws-amplify aws-amplify-react
src/App.jsの書き換え

続いてsrc/App.jsを以下に書き換えます。

import React, { Component } from 'react';
import Amplify from 'aws-amplify';
import { Authenticator } from 'aws-amplify-react';
 
Amplify.configure({
  Auth: {
    region: 'ap-northeast-1', // REQUIRED - Amazon Cognito Region
    userPoolId: 'ap-northeast-1_XXXXXXXXX', //OPTIONAL - Amazon Cognito User Pool ID
    userPoolWebClientId: 'XXXXXXXXXXXXXXXX', //OPTIONAL - Amazon Cognito Web Client ID
    identityPoolId: 'ap-northeast-1:XXXXXXXXXXXXXXXXXXXXXXXXXXX', // FederatedID連携後に追加する
  }
});

class AppWithAuth extends Component {
  render() {
    return <Authenticator />
  }
}

参考リンク先のコードにidentityPoolIdの行を追加した形になります。
詳細なシーケンスは意識せずに、裏で紐づけをやってくれるのが非常に便利だと感じました。

各種IDには以下の値を埋めます。

  • userPoolID
    • プール作成時に作られたプールID
  • userPoolWebClientId
    • アプリクライアント作成時に作られたアプリクライアントID
  • identityPoolId
動作確認
$ yarn start

さきほどと同じようにアクセスすると、Sign InやSign Upが実行できます。
http://#{Amazon LinuxインスタンスのパブリックIP}:3000/

f:id:yamano3201:20180123161844p:plain

S3にデプロイ

S3バケットの作成

まずはS3バケットを作成します。

パブリックアクセス許可

アクセスコントロールリストから、読み取りのパブリックアクセスを許可をします。

Static website hostingを有効化

「Static website hosting」を有効化して、エンドポイントをメモしておきます。
f:id:yamano3201:20180123162607p:plain

ビルド&デプロイ
$ yarn build
$ aws s3 sync build/ s3://#{S3バケツ名}

作成されたbuildディレクトリをS3にまるごとsyncすることでデプロイ完了です。

デプロイ後にブラウザからアクセスするとローカルと同じUIで動くことが確認できると思います。
http://#{S3バケツ名}.s3-website-ap-northeast-1.amazonaws.com

最後に

手を動かすことで理解が進みました。
Amazon Cognitoを動かして動作を確認するのに、CLISDKだけだとハードルが高いのでAWS Amplifyのようなライブラリを使うのは良かったと思います。

Amazon Cognitoの理解がメインでしたが、AWS Amplify自体の可能性も感じたのでもう少し触ってみたいと思います。

Amazon GuardDuty 徹底調査!

Amazon GuardDutyについて調べたのでメモしておきます。
非常に簡単に脅威検知が可能になるため、有効化必須のサービスといっても良いと思います。
東京リージョンでも利用可能です。

よくまとまったスライドがあるので一読すると概要が掴めると思います。

www.slideshare.net

目次です。

GuardDutyとは

Amazon GuardDuty とは - Amazon GuardDuty

  • Amazon GuardDuty は、VPC フローログおよび AWS CloudTrail イベントログを分析および処理する継続的なセキュリティモニタリングサービスです。

料金

Amazon GuardDuty の料金表 – アマゾン ウェブ サービス (AWS)

  • AWS CloudTrail イベントの数量 (1,000,000 イベントあたり) と分析された VPC フローログと DNS ログデータの量 (GB あたり) に基づいています。
  • 以下、Tokyoの例になります。
    • VPC フローログと DNS ログが 1.18 USD/GB
    • AWS CloudTrail イベントが 4.72 USD/1,000,000 イベント

f:id:yamano3201:20171228161411p:plain

GuardDutyのセットアップ

Amazon GuardDuty でサポートされるリージョン - Amazon GuardDuty

  • コンソールから「GuardDutyの有効化」を実施するだけです。
  • リージョンサービスのため、各リージョンで有効化を実施する必要があります。

f:id:yamano3201:20171228162950p:plain

無料トライアル

  • 30日間の無料トライアルがあります。リージョンごとに30日間無料サービスが提供されます。

IAMロールの自動作成

  • GuardDutyを有効化すると「AWSServiceRoleForAmazonGuardDuty」というIAMロールが作成されます。
  • 作成されたIAMロールはIAMからもGuardDutyからも編集は不可能になります。
  • AWSアカウントに対して1つ作成され、リージョンごとにGuardDutyを作成した場合は同じIAMロールを使用することになります。
# アクセス権限(AmazonGuardDutyServiceRolePolicy)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeImages"
            ],
            "Resource": "*"
        }
    ]
}
# 信頼関係
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "guardduty.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole"
      ]
    }
  ]
}

各種データソース

  • GuardDuty では AWS CloudTrail、VPC フローログ、DNS クエリログのデータソースを分析し結果を生成します。
  • ただし、AWS CloudTrail、VPC フローログ、DNS クエリログのイベントやログは提供しないので、AWS CloudTrailやVPCフローログのセットアップが別途必要になります。
  • VPCフローログが有効でなくてもGuardDutyの結果は生成されます。

AWS CloudTrailを有効にする必要があるかは不明であるが、全リージョンで有効にしておくことが無難だと思われる。要確認。
DNS クエリログはEC2インスタンス上から実行されたクエリログが解析対象のため、有効化は不要と思われる。要確認。

Amazon CloudWatch Events

  • GuardDutyのユーザインターフェースはCloudWatchをサポートしていませんので、CloudWatch側から設定する必要があります。
  • CloudWatchもリージョンサービスなので、リージョンごとに設定が必要になります。
  • イベントタイプにはGuardDuty Findingのみ用意されています。結果の生成をトリガーに通知が送信されます。

ex) ターゲットにSNSトピックを指定することで結果の生成をトリガーにメール通知を行うことができます。

f:id:yamano3201:20171228163024p:plain

信頼できるIPリストと脅威リスト

信頼できる IP リストと脅威リストのアップロード - Amazon GuardDuty

停止または無効化

Amazon GuardDuty の停止または無効化 - Amazon GuardDuty

  • GuardDuty停止
    • AWS 環境のセキュリティは監視されなくなり、新しい結果は生成されません。
    • 既存の結果は変更されず、GuardDuty の停止によって影響を受けることはありません。GuardDuty は後で再び有効にすることができます。
  • GuardDuty無効
    • 既存の結果と GuardDuty の設定は失われ、復旧できなくなります。
    • 既存の結果を保存する場合は、GuardDuty を無効にする前にそれらをエクスポートする必要があります。

GuardDutyの結果

  • 以下の結果タイプをサポートしています。
    • Amazon GuardDuty の結果タイプ - Amazon GuardDuty
    • BackDoor: AWSリソースが攻撃を受けていることを検出
    • Behavior: ベースラインとは異なるアクティビティやアクティビティパターンを検出
    • Crypto Currency: ビットコインイーサリアムなどの暗号通過に関連付けられたソフトウェアを検出
    • Pentest: 既知のペンテストツールで生成されたアクティビティと類似するアクティビティを検出
    • Recon: AWS環境の脆弱性を探そうとしているアクティビティを検出
    • Stealth: 攻撃アクションや形跡を隠そうとするアクティビティを検出
    • Trojan: トロイの木馬プログラムが攻撃に使用されていることを検知
    • Unauthorized Access: 不審なアクティビティまたアクティビティパターンの検出
  • 以下に結果タイプの詳細なリストが記載されています。
  • 結果タイプの説明横の四角いボタンから詳細なリストへリンクすることができます。

f:id:yamano3201:20171228164046p:plain

検出されたセキュリティ問題の修復

検証方法

  • 「全般」「結果サンプルの生成」ボタンから、サンプルを生成することができます。
  • [例]と書かれた32件のFindingsが作成されました。
  • CloudWatch Eventsも送信されるので通知先の動作確認を行うことができます。

※手軽に結果を生成させる方法がわかっていません。要確認。

エクスポート

  • JSON形式でエクスポートすることが可能です。
[
  {
    "schemaVersion": "2.0",
    "accountId": "xxxxxxxxxxxxxxxxxxxxxxxx",
    "region": "ap-northeast-1",
    "partition": "aws",
    "id": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
    "arn": "arn:aws:guardduty:ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxx:detector/xxxxxxxxxxxxxxxxxxxxxxxx/finding/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
    "type": "CryptoCurrency:EC2/BitcoinTool.B!DNS",
    "resource": {
      "resourceType": "Instance",
      "instanceDetails": {
        "iamInstanceProfile": null,
        "imageId": null,
        "instanceId": "i-99999999",
        "instanceState": null,
        "instanceType": null,
        "launchTime": null,
        "networkInterfaces": null,
        "availabilityZone": null,
        "platform": null,
        "productCodes": null,
        "tags": null
      }
    },
    "service": {
      "serviceName": "guardduty",
      "detectorId": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
      "action": {
        "actionType": "DNS_REQUEST",
        "dnsRequestAction": {
          "domain": "example.com",
          "protocol": "TCP",
          "blocked": false
        }
      },
      "resourceRole": "TARGET",
      "additionalInfo": {
        "sample": true
      },
      "eventFirstSeen": "2017-12-27T02:21:34Z",
      "eventLastSeen": "2017-12-27T02:21:34Z",
      "archived": false,
      "count": 1
    },
    "severity": 5,
    "createdAt": "2017-12-27T02:21:34.592Z",
    "updatedAt": "2017-12-27T02:21:34.592Z",
    "title": "Bitcoin-related domain name queried by EC2 instance i-99999999.",
    "description": "EC2 instance i-99999999 is querying a domain name that is associated with Bitcoin-related activity."
  }
]

アーカイブ

  • 「最近」から非表示にしたい場合は、アクションから「アーカイブ」することで「アーカイブ済み」に移すことができます。
  • 再度、「最近」に表示したい場合は、アクションから「元に戻す」ことで「最近」に移すことができます。

AWS アカウントの管理(マルチアカウント)

  • メンバーアカウントで検知した結果をマスターアカウントのGuardDutyで表示および管理することが可能になります。

※メンバーアカウントでも料金が発生するかは要確認。
※マスターアカウントでは、メンバーアカウントの料金も重複して発生するか要確認。

アカウント

  • マスターアカウント
    • 自分のアカウントおよびすべてのメンバーアカウントの GuardDuty を設定し、さらに GuardDuty の結果を表示および管理できます。GuardDuty に最大 100 のメンバーアカウントを登録できます。
  • メンバーアカウント
    • 自分のアカウントの GuardDuty を設定し、さらに GuardDuty の結果を表示および管理できます。メンバーアカウントのユーザーは、他のメンバーアカウントの結果を表示または管理することはできません。

AWS アカウントを同時に GuardDuty のマスターアカウントとメンバーアカウントにすることはできません。

マルチアカウントでの信頼できるIPリスト、脅威リスト

  • マスターアカウントで設定した信頼できるIPリスト、脅威リストはメンバーアカウントには反映されません

招待方法

Amazon GuardDuty での AWS アカウントの管理 - Amazon GuardDuty

  • ステップ 1 - アカウントを追加する
    • マスターアカウント側でアカウントIDとEメールを指定して追加します
    • CSVで一括招待することも可能です。
    • リージョンサービスになるので、リージョンごとの招待が必用です。
  • ステップ 2: アカウントを招待する
    • マスターアカウント側で「招待」をクリックします。「メッセージ」を記入して「招待の送信」ボタンを押します。
    • 日本語のメッセージは文字化けするので注意。メンバーアカウント側の通知画面からは日本語も表示されます。
    • エンタープライズサポート契約の場合、ccにTAMのアカウントが入ります。
  • ステップ 3 - 招待を受け入れる
    • メンバーアカウント側で「招待を承諾する」ボタンを押します。
    • 事前に有効化していた場合でも、招待を承諾することで各種設定やログが消えることはありません。
    • メンバーアカウント側ではアーカイブを実施することができません。

※招待を受け入れた後もメンバーアカウント側で自由に抜けることが可能です。抜けた後はアーカイブを実施することが可能になります。

最後に

組織を超えてAmazon GuardDutyの中央管理を行いたかったので、まとめてみました。

既にメンバーアカウント側でGuardDutyを有効化している場合も検知結果や設定はそのまま、マスターアカウント側で管理することが可能だったので展開自体はしやすいと感じました。

ただし、費用に関してはメンバーアカウント側でも発生して、マスターアカウント側ではメンバーアカウント側の費用も重複して発生しそうなのでコスト的にはデメリットとなるかもしれません。

また、メンバーアカウント側でアーカイブ機能に制限があり、いったんメンバーから離脱しないとメンバーアカウント側では検知されたイベントを消すことができないこともデメリットとなるかもしれません。

マルチアカウントにして、マスターアカウント側で管理することのメリットを明確にしないと、メンバーアカウントのメリットはわかりづらいというのが現時点での感想です。
ex) 社内のCSIRTと連携してインシデントレスポンスを迅速に行う。など

2017/12/14 AWS re:Invent 2017 Security re:Cap 参加レポート

今さらですが、AWS re:Invent 2017 Security re:Capの参加レポートになります。
connpass.com

公式の開催報告ブログがありました。資料もこちらから参照可能です。
aws.typepad.com

AWS Single Sign-On AWSソリューションアーキテクト 辻 義一さん


re:Inventと今後のdwangoでのAWSセキュリティについて 株式会社ドワンゴ 鈴木 栄伍さん

re InventのEBCにて、AWSの技術者に直接話を聞けるみたいですね。

re Inventの中で登壇者が一番ためになったセッションとのことです。

Amazon GuardDuty AWSパートナーソリューションアーキテクト 酒徳 知明さん


AWS re:Invent 2017振り返り SOCの立場からみたre:Invent 株式会社リクルートテクノロジーズ 安東 美穂さん


Security re:Cap 2017 トレンドマイクロ株式会社 姜 貴日 さん

資料のp10にGuardDutyとDeepSecurityの違いが載っています。

検出と遮断というのが大きく異なりますが、ポートスキャン、C&C通信、ブルーとフォースなど対応する脅威は被っているように見えますね。
多層防御なのでどっちかという話ではないかもしれないですが。

さっそくGuardDutyとDeepSecurity連携のコードが提供されていました。
AWSのマネージドIDSとDeepSecurityのIPSが連携するとセキュリティを向上させることができそうですね。

2017/10/07 脆弱性診断 初心者ハンズオントレーニング 参加レポート

今さらですが、脆弱性診断 初心者ハンズオントレーニングの参加レポートです。
pentest-web.connpass.com

XSS, SQLインジェクション 脆弱性、アクセス制御系の説明の後にBurpSuiteを使って実際に脆弱性がないかを診断していくハンズオンを実施しました。

OS, ミドルウェア脆弱性診断は機械的に実施することが多いが、アプリケーションの脆弱性診断はアプリの特性を理解する必要があるので、人がやるのが有効とのことでした。

2017/09/30 TDDBC Tokyo 2017-09 参加レポート

今さらですが、TDDBC Tokyoの参加レポートです。
tddbc.connpass.com

2011年にTDDBCに参加したときはRubyでした。

AWS Summit でTestable Lambdaのセッションを聞いてから、なるべくLambdaのテストを書くようにしています。

Lambdaの開発ではPythonを利用しているので、今回はPythonで受けてきました。

ペアプロの成果物は下の2つです。最後にpushしただけなので途中のコミットなどは残していません。
https://github.com/yamano/python_pytest/blob/with_azu1129/acme/semver.py
https://github.com/yamano/python_pytest/blob/with_azu1129/tests/acme/test_semver.py