そのAWS Lambdaの.NET Core、1.0から2.0にアップデートしませんか?

概要

  • 2018年1月15日、とうとうAWS Lambdaでの.NET Coreで2.0がサポートされるようになりました🎉
  • 早速バージョンアップしてみましょう。

ソリューションのアップデート

細かいことはおいておいて、まずはアップデートしてみましょう。

題材はこれです。

CloudWatch Logsに書き込まれた内容をSlackとGoogle Homeで通知するAWS Lambda using dotnet

がんばった割に鳴かず飛ばずだったこの記事で紹介している、CloudWatch Logsを監視してSlackとGoogle Homeに通知するLambdaです。

https://github.com/toshi0607/ErrorNotificationLambda

プロジェクト構成

ErrorNotificationLambda/
├ErrorNotificationLambda/
│ ├Properties/
│ ├aws-lambda-tools-defaults.json
│ ├ErrorNotificationLambda.csproj
│ ├Function.cs
│ └Readme.md
└ErrorNotificationLambda.Tests/
  ├Properties/
  ├ErrorNotificationLambda.Tests.csproj
  ├FunctionTest.cs
  └LaunchSettingsFixture.cs
“`

変更箇所

csprojを変更します。

ErrorNotificationLambda.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp1.0</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <WarningLevel>0</WarningLevel>
  </PropertyGroup>

  <PropertyGroup>
    <OutputType>Library</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.CloudWatchLogsEvents" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="1.8.0" />
  </ItemGroup>

</Project>

これを

<TargetFramework>netcoreapp1.0</TargetFramework>

こう

<TargetFramework>netcoreapp2.0</TargetFramework>

以上。

Visual Studio 2017から編集する場合は、該当プロジェクトを右クリックすると「[プロジェクト名].csprojの編集」が選択できます。

4csproj.PNG

aws-lambda-tools-defaults.jsonにデフォルトのデプロイ設定を書いている場合、そちらもお忘れなく。

Publish to Lambdaするときに設定を保存しても書き換わってくれます。

また、Serverless Applicationのテンプレートからプロジェクトを作成した場合はCloudFormationのリソースもdotnetcore2.0に変更しましょう。

AWS Toolkit for Visual Studio 2017のアップデート

AWS Toolkit for Visual Studio 2017はVisual Studioからデプロイしたり、テンプレートを選択したりできるようにする拡張機能です。

今回.NET Core 2.0系対応が入った拡張機能のバージョンは1.14.0.0ですが、僕のVisual Studioにはまだ更新が降ってきていなかったので、マーケットプレースから直接.vsixをダウンロードし、インストールしました。

現在インストールされているバージョンは「ツール」->「拡張機能と更新プログラム」->「インストール済み」の中にあるAWS Toolkit for Visual Studio 2017を選択すると確認することができます。

61.14.PNG

バージョンアップすることで変更される大事なポイントは次の二点でしょう。

  • Language Runtimeで.NET Core v2.0が選択できる
  • Memoryが3008MBまで選択できる

メモリはまた上限上がったんですねw 年末のLambda共通のアップデート時点ではポータルで選択できる上限が上がっているにもかかわらず、「Upload Lambda Function」ではそれが反映されていませんでした。

72.0.PNG

8memory.PNG

動作確認

ローカルでテスト通るか?

デプロイ後ポータルでのバージョンが2.0になっているか?

82.0.PNG

本番環境のLambdaに対してテストイベントを発行した期待した結果になるか?

9vs.PNG

9slack.PNG

特に問題はなかったです。

アップデートの詳細

You can now develop AWS Lambda functions in C# using the .Net Core 2.0 runtime! Get started easily with the AWS Toolkit for Visual Studio. https://t.co/uxmrKodaUY pic.twitter.com/h442a6DwEZ

— Amazon Web Services (@awscloud) 2018年1月16日

AWS Lambda Supports C# (.NET Core 2.0)

AWS Lambda .NET Core 2.0 Support Released

一番下のが実際に開発してる人が書いた記事です。

aws-lambda-dotnetは大体この人が書いていると言っても過言ではないし、PRを出すととても丁寧に対応してくれます。

https://github.com/aws/aws-lambda-dotnet/graphs/contributors

VSTSのAWS周りタスクがリリースされた記事も英語版が出て2週間後くらいに日本語版が出たので、今回もきっとそのうち日本語版が出ることでしょう。

とても雑にまとめると、

  • .NET Core 2.0サポートすると、.NET Standard 2.0ベースでライブラリを作成するときより多くの.NET APIを利用できるので、既存の.NET資産をより使い回しやすくなる
  • テンプレはもう2.0ベースにアップデートしているので、AWS Toolkitのテンプレート使ってVisual Studioからデプロイしてしまうのが一番楽
  • Amazon.Lambda.Toolsも2.0がリリースされ、パッケージングするにあたって2.0ランタイムで必要となるファイルも生成できる
  • Amazon.Lambda.Templatesも2.0.0(同日に2.0.1がリリースされていた…!)がリリースされ、Visual Studioがなくてもすべてのテンプレがコマンドで利用できるようになった
  • プログラミングモデルは変わっていたいので、既存の1.0系プロジェクトもシュッとアップデートできる
  • AWS Tools for VSTSもアップデートされて2.0対応されたが既存のタスクを更新する必要はない

まとめ

「.NET Core 2.0対応」が目につきますが、実際は周辺のツールのアップデートがとてもとてもいい感じです。

続きを読む

ほー、つまりAWSとかと比べてパフォーマンスインパクトが小さかったりするのかな? – daikikoharaの …

はてなブックマーク · テクノロジー · Protecting our Google Cloud customers from new … daikikoharaのコメント. Twitterでシェア · Facebookでシェア; ブックマークする. ほー、つまりAWSとかと比べてパフォーマンスインパクトが小さかったりするのかな? google · vulnerability · daikikoharaのコメント2018/01/12 03:07. 続きを読む

Cognitoの説明に使われている言葉を整理する

はじめに

Cognitoを使ってみようと思って色々読んだけど、認証周りは全くど素人なのでわからない言葉を調べてみたメモです。

Cognitoとは何か

AWSのAmazon Cognito とはに書いてある通り。この中で

  • Amazon Cognito とは
  • Amazon Cognito の機能

に書いてある言葉でわからなかったものを整理する。こちらも参考にさせていただきました。

ユーザディレクトリとは何か

大きめな会社でWindowsを使ったりしていると「Active Directory」という名前を聞いたことがあるかもしれないが、似たようなもの、と理解した。前述のAWSのAmazon Cognito とはにもあるが、ユーザディレクトリは以下の機能を提供、管理する。

  • ユーザの追加方法を提供する(サインアップ)
  • サインアップに必要な情報、ステップを定義できる
  • ユーザの認証方法を定義できる(サインイン)
  • サインアップ/サインイン処理の代替をさせるCognito以外のサービスを設定できる(外部IDプロバイダー)

Amazon Cognito User Poolとは何か

ユーザディレクトリを実現するための機能の名称。Connection Poolとかと同じ、ユーザをpoolする。コンソールでUserPoolを作ってみるとわかるが、作成時に上記のユーザディレクトリで提供、管理するパラメタの設定を行う。あとから編集も可能。

外部IDプロバイダとは何か

これも前述のCognitoの説明ページにある通り、FacebookやTwitterやAmazonなどのCognitoの外部にあるアカウント情報を提供するサービスをAWSの説明ではこう呼んでいる様子。自社システムですでにアカウント管理を実装済みの場合、それも「Cognitoからみたら外」になるので外部IDプロバイダになるが、SAMLに対応していないと外部IDプロバイダーとして登録できない。

移行したいときどうするんだろう?要調査。

注意

CognitoコンソールでUser Poolの設定画面に「フェデレーション」メニューと「IDプロバイダー」という項目があるが、後述の「Amazon Cognito フェデレーテッドアイデンティティ」とは別もの。「外部IDプロバイダー」を設定するだけであり、フェデレーテッドアイデンティティ側の設定には何も影響しない。(はず)

スクリーンショット 2018-01-03 13.06.22.png

Amazon Cognito フェデレーテッドアイデンティティとは何か

ふぇでれーてっどって何??ということでアルクで調べた。

federation 【名】
連邦[連合・連盟]化[加入]◆【用法】不可算名詞
連邦、連合、連盟◆国家や組合などが独自の組織を維持しながら構成する連合体。
federated 【形】
連合[連盟]した、連邦制になった

ふむ。JAFのFやFIFAの最初のFの「Federation」の形容詞か。

で、これはCognito UserPoolまたは外部のアカウント情報を提供するサービス(FBやTwitterなど)の認証情報を使い、一意なIDを割り当てる&そのID任意のアクセス権限(=IAMロール)を付与することができる機能の様子。認証前と後で異なるアクセス権限を割り当てることができる。
Federated Identityの1つ1つを管理する器を「ID Pool」と呼んでおり、ID pool単位で以下を提供、管理する。

  • 認証前後に与えるロールの設定
  • 「認証済/未済」をどの「認証プロバイダー」に提供してもらうかの設定
  • 「プッシュ型」データ同期の要否(未対応言語あり。注意。)
  • Kinesisストリームとの連携(Cognitoストリーム。よくわかってない)
  • Sync Trigger時のLambdaの呼び出し設定

注意

Federated IDの認証プロバイダーはUser Poolの外部IDプロバイダーよりも選択肢が広い。こちらの場合、自社サービスの認証情報を流用するにあたってSAMLなどに対応する必要はない。(「カスタム」認証プロバイダーでは、クライアントアプリ側の実装で責任を持ってtoken発行を行うのでSAML対応などは不要になる)

Amazon Cognito Syncとは何か

Federated IDに紐づいた データの同期を行える機能。UserPoolのユーザ単位ではない。AWSのCognito Syncの説明ではFederated ID=Cognito IDとして書かれているので注意! :(

key-value型のデータセットを同期させることができ、1セット1MB, 20個まで1つのFederated IDに紐づけることができる。AWSのCognitoサービスをマスターとし、インターネットに繋がっているクライアント同士でデータ同期することができる。同期トリガーは同期メソッドを各クライアントから呼び出す。AWS側からプッシュするパターンの同期もID Poolの設定によっては可能だが、対応していない言語があるので注意。オフライン時のデータ更新も考慮されている。

よもやま

名前分かりにくいなぁ

名前 意味
外部IDプロバイダー Cognito User Pool においてCognito以外で認証機能を提供するサービス
Federated Identity (Federated ID) 前述の機能名、またはそれで発行したID1つ1つ
ID pool Federated IDを管理、設定するPool
認証プロバイダー Federated IDの付与に使われる「認証済/未済」を提供するサービス

続きを読む

Amazon CognitoとFacebookとの連携

FacabookやTwitter、Googleなどの外部認証プロバイダーやユーザープールと連携し、ユーザーごとにIDを作成し、権限を制限したAWSの認証情報を取得することができます。 これにより、次に説明するCognito Syncによるデータの同期をしたり、S3やDynamoDbなどの各サービスにユーザーがアクセスしたりできます。 続きを読む

AWS CodeStar と Cloud9 の連携

はじめに

AWS CodeStar がついに東京リージョンにやってきました!
https://aws.amazon.com/jp/about-aws/whats-new/2017/12/aws-codestar-is-now-available-in-asia-pacific-tokyo-and-canada-central-regions/

早速CodeStarとCloud9の連携を試すぞ!と思ったのですが、よくよく考えればCloud9が東京リージョンに来ていませんでした。
今回はシンガポールリージョンで検証した内容でお伝えします。。。

CodeStar プロジェクトの作成

プロジェクトのテンプレートを選択します。
ここではNode.js(AWS Lambda)を選択します。

image.png

CodeStartのプロジェクト名を入力します。
リポジトリにはCode Commitを使用します。リポジトリ名にはプロジェクト名が反映されています。

image.png

プロジェクトを作成します。

image.png

表示名、メールアドレスを入力してIAMユーザに紐づくCodeStarユーザを作成します。

image.png

コードの編集方法の選択で、AWS Cloud9を選択します。
2017年12月時点では東京リージョンではCloud9がGAしていないため、選択肢として表示されません

image.png

Cloud9 のインスタンスも CodeStarのプロジェクト作成の中で出来ます!
今回はすべてデフォルトの設定で作成しました。

image.png

Cloud9のセットアップが完了するまでしばらく待ちます。
またCodeStarによって自動的にPipelineの作成まで行われており、CodeCommitへのInitial commitによって
サンプルアプリケーションがデプロイされています。
image.png

アプリケーションのエンドポイントにアクセスするとサンプルページが表示されました。
image.png

Cloud9 での作業

コーディングの開始を選択すると アプリケーションコードが既にチェックアウトされ、gitのクレデンシャルも
設定された状態でCloud9が立ち上がります。楽ちん!

image.png

Cloud9のコンソール上で git config しておきます

$ git config --global user.name YOUR_USER_NAME
$ git config --global user.email YOUR_EMAIL_ADDRESS

サンプルのindex.htmlを編集して、変更を反映させてみたいと思います。

public/index.html
        <div class="message">
            <a class="twitter-link" href="http://twitter.com/home/?status=I%20created%20a%20project%20with%20AWS%20CodeStar!%20%23AWS%20%23AWSCodeStar%20https%3A%2F%2Faws.amazon.com%2Fcodestar"><img src="assets/img/tweet.svg" /></a>
            <div class="text">
                <h1>Congratulations!</h1>
                <h2>You just created a Node.js web application</h2>
                <h2>AWS CodeStar と Cloud9 の連携</h2> ★追記
            </div>
        </div>

ファンクションやAPI Gatewayの設定は変更していませんが、ローカルで実行してみます。

image.png

当然ですが、変更内容が反映され正常終了しました。

image.png

変更内容をCodeCommitに反映します。
コンソール上のgit操作です。

$ cd codestar-test
$ git add .
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   .gitignore
        modified:   public/index.html
$ git commit -m "編集テスト"
$ git push

※ローカル実行時に lambda-payloads.json が作成されるので、.gitignore に追加しています

CodeCommitへのプッシュを契機にPipelineが起動しました。

image.png

デプロイ(CloudFormationスタックの更新)が完了すると、修正内容が反映されていることを確認できました。

image.png

さいごに

今回 Lambda + API Gateway の環境で検証しましたが、CodeStar と Cloud9の連携により、
プロジェクトの作成、コーディング、テスト、継続的デプロイがここまで簡単に行えることに感動しました。
Cloud9 の東京リージョン登場が待ち遠しい。。
参考になれば幸いです。

続きを読む

AWS Glue is Now Available in the EU (Ireland) AWS Region

おもしろ · エンタメ · アニメとゲーム · はてなブックマーク · テクノロジー; AWS Glue is Now Available in the EU (Ireland) AWS Region. Twitterでシェア · Facebookでシェア …. 【AWS発表】AWS Management Consoleがアップデート。タブレットとモバイルもサポート! – Amazon Web Services ブログ · 23 usersaws.typepad. 続きを読む

はじめてのAWS Cognito!!

:santa:「Amazon Web Services Advent Calendar 2017」20日目の記事です

はじめに

今回、Advent Calendarへの投稿が「Qiita」デビューです。
あと、どうでも良い情報として、本日は、私の誕生日:birthday:です(四十路です・・)。

先日、「AWS SDK for JavaScript」を使用してCognitoを使用したのですが、諸々の用語や抑えどころが分からずに悩んだ点がいくつかあったので、「はじめてのAWS Cognito」と題してポイントをまとめてみました。

私自身も手探り感満載だったので、コメントやご助言頂けると嬉しいです!
Cognito Syncについては、まとめてないので、こちらを期待されている方は、スルーしてくださいw。

1.そもそもCognitoとは?

・ AWSが提供する認証・認可基盤です。通常は、IAMユーザーのアクセスキーや、インスタンスに対するIAMロールを使用して認証します。

2.なぜCognitoを使うのか?

・クライアントアプリ(SPAやスマホのネイティブアプリ)より直接AWSリソースへアクセスしたい要件が増えてきている中で、扱いに困るのがIAMユーザーのアクセスキーシークレットキーの扱いです。

特に、SPAのようなJavaScriptを使用したアプリケーションは、容易にブラウザのデバックツールより抜き取ることが可能なため、セキュリティ上問題があります。
また、仮になんらかの方法で、ファイルを難読化したとしても、永続的に権限を付与し続けることになるため、健全な運用ではありません。

そこで、Cognitoを使用してクライアントアプリからの認証を行い、IAMロールを使用して権限を払い出す仕組みを実現しています。

3.用語について

Cognitoで使用される用語を私なりにまとめてみました。

  • フェデレーティッドアイデンティティ
    どのようにして、認証を行うかの設定を行います。ソーシャルIDプロバイダー(FB、Twitter etc)の指定や、認証後の使用可能なAWSリソースのIAMロール設定等を行います。
     

  • ユーザプール
    「フェデレーティッドアイデンティティ」で作成されたIDプールに対してユーザの紐付けを行います。その際に使用するのが、ユーザプールです。
    どのアプリケーションに対して、どのような認証を行い(メール認証の有無や、MFA等)、パスワードポリシーの設定や、ユーザのアクティベーション等もあります。


4.どうやって使うのか

AWS SDK for JavaScriptを使用して、Cognito経由でDynamoDBへアクセスしてみます。

未認証でとりあえず使ってみる

まずは、フェデレーティッドアイデンティティを新規に作成して、未認証でも権限の払い出しをしてもらい、どんな感じになるか試します。

1. フェデレーテッドアイデンティティを作成する

  • 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」

    • ID プール名: 今回は、demo_cognito_unauthenticated
    • 「認証されていない ID に対してアクセスを有効にする」をチェックし、「プールの作成」
    • 「Your Cognito identities require access to your resources」は「許可」

スクリーンショット 2017-12-07 0.17.09.png


2. IAMロールの編集
DynamoDBへのアクセス許可の設定を追加します。
IAMから、ロールをクリックすると、以下のようなIAMロールが作成されて
いるはずです。

oneClick_Cognito_[ID プール名]Auth_Role_XXXXXXXXXXX
oneClick_Cognito_[ID プール名]UnAuth_Role_XXXXXXXXXXX

編集するロールを選択 -> 「ポリシーの編集」で以下のようにDynamoDBの権限を追加してください。
ここでは、
oneClick_Cognito_demo_cognito_unauthenticatedAuth_Role_XXXXXXXXXXX
を指定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {   // 追加します。(コメントは追加時には削除しましょう。書式チェックで怒られます)
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/demo_cognito_table", // DynamoDBのARNを指定
            ]
        }       
    ]
}

3. DynamoDBにアクセスする

「AWS SDK for JavaScript」を使用すると、IdentityIdを取得することが出来ます。こちらのIDは、SDKがよろしく保持してくれるので、こちらで管理する必要はありません。

poolIdには、「フェデレーテッドアイデンティティ」のプールIDを指定します。プールIDにはユーザプールIDもあるので、ちょっと紛らわしいですね・・

以下は、DynamoDBのテーブルからのデータ取得例です。


var aws = require('aws-sdk');
var config = {
    poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    region: 'ap-northeast-1'        
};

aws.config.region = config.region;
aws.config.credentials = new aws.CognitoIdentityCredentials(
                                {IdentityPoolId: config.poolId});

aws.config.credentials.get(function(err) {
    if (!err) {
        console.log("Cognito Identify Id: " + aws.config.credentials.identityId);                

        // DynamoDBへ接続
        var dynamoDB = new aws.DynamoDB();
        var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});

        var params = {
            TableName : 'demo_cognito_table',
            Key: {
                'id': '1'
            }
        };  

        docClient.get(params, function(err, data) {
            if (!err){
                console.log(data);
            } else {
                console.log(err);
            }
        });        
    }
}); 

実行するとDynamoDBにアクセスして、データ取得できました。:v_tone1:

$ node unauth.js 
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }

DynamoDB周りのAPI仕様は別途ご確認ください。

未認証アクセスの用途としては、認証画面が存在しないアプリケーションで直接クライアントからAWSリソースに対してアクセスした場合等に使用することになると思います。

Cognitoユーザによる認証

ソーシャルIDプロバイダー(FB、Twitter etc)で認証することが実際の用途としては多いかなと思いますが、今回は、Cognitoの認証プロバイダを使用してみます。

Cognitoの認証プロバイダは、メールやSMSを使用したアクティベーションも可能です(アクティベーションメールのテンプレートもあります)が、諸々用意するのが大変なので、今回はnodeから直接認証のみを実施してみます(こちらを参考にさせて頂きました)。

1. Cognitoユーザーを作成
上記、記事の「2.AWS cognitoでユーザー作成」に沿って作成します。

スクリーンショット 2017-12-16 18.11.32.png

スクリーンショット 2017-12-16 18.13.20.png

2. フェデレーテッドアイデンティティを作成する
– 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」
– ID プール名: 今回は、demo_cognito_authenticated
– 「認証されていない ID に対してアクセスを有効にする」をチェックを外し、「プールの作成」
– 「Your Cognito identities require access to your resources」は「許可」

3. Amazon Cognito Identity SDK for JavaScriptのインストール
AWS SDK for JavaScriptと合わせて、
Amazon Cognito Identity SDK for JavaScriptを使用します。

$ npm install amazon-cognito-identity-js --save

4. DynamoDBにアクセスする
先程のDynamoDBアクセスを認証ありで行います。

var aws = require('aws-sdk');
var aws_cognito = require('amazon-cognito-identity-js');

var config = {
    poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    region: 'ap-northeast-1'        
};

// ユーザープール設定
var user_pool = new aws_cognito.CognitoUserPool({
    UserPoolId : 'xxxxxxxx', // 1.で作成したユーザプールID
    ClientId : 'XXXXXXXXXXXXXXXXXXXX' // 1.で作成したアプリクライアント ID
});

// ユーザー決定
const cognito_user = new aws_cognito.CognitoUser({
    Username: 'XXXXX', // 1.でユーザに作成したユーザ名
    Pool: user_pool,
});

// パスワードの設定
const authentication_details = new aws_cognito.AuthenticationDetails({
    Password: 'XXXXXX', // 1.でユーザに設定した仮パスワード
});

// ユーザープール/ユーザー/パスワードを使って認証
cognito_user.authenticateUser(authentication_details, {
    // 成功時
    onSuccess(result){
        aws.config.region = config.region;
        aws.config.credentials = new aws.CognitoIdentityCredentials(
                                        {IdentityPoolId: config.poolId,
                                            Logins: {
                                                'cognito-idp.ap-northeast-1.amazonaws.com/<YOUR_USER_POOL_ID>': result.getIdToken().getJwtToken()
                                            }                                                                                    
                                        });

        // DynamoDBへ接続
        var dynamoDB = new aws.DynamoDB();
        var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});

        var params = {
            TableName : 'demo_cognito_table',
            Key: {
                'id': '1'
            }
        };  

        docClient.get(params, function(err, data) {
            if (!err){
                console.log(data);
            } else {
                console.log(err);
            }
        });    
    },
    onFailure(err){
        console.error(err);     
    },

    // 初回認証時のパスワード変更を仮パスワードで使いまわす。
    newPasswordRequired(user_attributes, required_attributes){
        cognito_user.completeNewPasswordChallenge(authentication_details.password, user_attributes, this);
    },
});

実行すると無認証時と同じく、DynamoDBにアクセスして、データ取得できました。:v_tone1:

$ node auth.js 
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }

意外と、Cognitoで認証後に取得したトークンと、IAMからCredentialを払い出すために繋ぎ込みが分からず、ハマりましたが、AWSのドキュメントにちゃんとありましたね・・

まとめ

ポイントを絞って初心者の方に分かりやすいようにまとめてみましたが、如何でしたでしょうか?
(‥‥というか、半分は自分への覚書ですが:sweat_smile:

Cognitoは、非常に使用用途が多いサービスですが、慣れないと用語が多く一度に理解するのは厳しいと感じました。色んな方が、書かれている優良な記事を参考にさせて頂きながら、やりたいことを整理して少しづつ小出しに理解していくのが良いように感じました。

続きを読む

Fargateについて世間の反応を見てみる

fargate.png

はじめに

こちらはAWS Fargate Advent Calendar 2017の12/18の記事です。
本記事では北米”google.com”で検索してFargateに関する巷のブログ、ニュース記事などを適当に選んで読み漁り、所感をコメントしていきます。
※新しい記事を読み次第、2017年中は本記事を更新していきます


Choosing your container environment on AWS with ECS, EKS, and Fargate

本AdventCalendarを立てたriywoさんにご紹介頂きました!ありがとうございますm(_ _)m。Mediumより元(?)AWSエバンジェリストのNATHAN PECKさんの記事です。ECS,EKS,Fargateそれぞれの特徴を紹介しており、最後のまとめ(summary)で3サービスの選択のポイントについて言及されています。

ざっくりなまとめ

  • ECSはツールも充実していて、CloudFormationはもちろんOSSのcoldbrew-cliもあるよ
  • EKSはk8s自体を管理するリソースのない小規模の企業にも向いている
  • ECSはAWSの他サービスと連携する最高のコンテナ運用を提供する
  • EKSは既にオンプレやAWS上でk8sを運用している場合に共通の運用体験を提供できる
  • Fargateは管理不要な簡単なコンテナ運用を提供できる(EC2を使うのが最も柔軟にコンテナを運用できるけど)

ECS, Fargate and EKS (Kubernetes on AWS) compared and explained in a nutshell

“sysdig”というコンテナモニタリングツール&サービスのブログより、Jorge Salamero Sanzさんの記事です。11/29のサービス発表直後に書かれています。自前k8s運用との比較や、コスト面、運用者・開発者目線での評価といった幅広い内容になっており、読み応えがありました。またsysdig monitorというコンテナ監視のsaasも気になります。

ざっくりなまとめ

  • コストについて、ECSやk8sの運用負荷がなくなるメリットと、Fargateのようなマネージドサービスの利用コストは各社で天秤にかける必要がある
  • 運用者目線からみて、ECSや自前のk8s on AWSに対し、EKSやFargateのカスタマイズ性には疑問がある
  • 開発者目線からみて、ECSを使っている現在のFargateはあまり変化が無いはず
  • Lambdaとの比較で、似ているがLambda特有の制限が無くなる(ただしコストはかかる)

Azure Container Instances vs. AWS Fargate

Hackernoonからvamp.ioのファウンダーTim Noletさんの記事です。
Azure Container Instances(ACI)とAWS Fargateを比較しているのですが、全体を通して「ACI上げ、Fargate下げ」な調子でFargateに対する煽りが入り、個人的には面白く読めました。

ざっくりなまとめ

  • ACIのコンテナ起動はわずか2行のコマンドでできる
  • Fargateのコンテナ起動はクラスタ作ってタスク定義してコンテナ定義してサービス…多いわ!
  • 性能測定結果はACIもFargateもそれほど違いはない
  • 価格はACIが割高(単純に1月連続利用を前提)に見えるが、AWSはLBとか他のサービスも必要になるから気をつけろ
  • ACIはシンプルでHerokuのようなサービス
  • FargateはDC/OSやk8sに位置するサービス

Say Hello to AWS Fargate & Amazon Elastic Container Service for Kubernetes (EKS)

Mediumからtiffany jerniganさんの記事です。AWSの中の方です。Fargateとk8sの基本的なサービス内容を記載されています。記事のはじめに過去のTwitterを引用して「あなたの願いは今叶いました!それがFargate、そしてEKSです!!」という流れは嫌いではないです。
「To learn more」として各種ドキュメントやre:Inventの動画へのリンクがまとめられているのは嬉しいですね。

ざっくりなまとめ

  • 詳しいことを知りたければリンク先(公式ドキュメントなど)を参照して欲しいとのこと

EKS and Fargate Announced at AWS re:Invent 2017

caylentというDevOps基盤を提供するサービス(?)のブログよりJP LA TORREさんの記事です。EKSとFargateについて機能を紹介しています。他記事にはでてこなかったContainers-as-a-Service(CaaS)という表現を使っているのが印象に残りました。

ざっくりまとめ

  • Fargateはゲームを変える可能性を持っている(欧米的な言い回し)
  • 簡単に言ってしまえばFargateはAWSにおけるHerokuである
  • FargateはCaaS市場でAmazonがより成長する鍵となりそうだ

さいごに

本記事を書き始める前に今日までのAWS Fargate Advent Calendar 2017の記事をすべて拝見しましたが、上質&興味深い情報が多く大変勉強になりました。闇雲にgoogle.comで情報を探すよりも学ぶ効率が良かったです。皆様ありがとうございます。

上で紹介した記事の中では”Azure Container Instances vs. AWS Fargate“がお気に入りです。AzureのACIとの比較という面白い切り口ですのでオススメです。

※12/19 Choosing your container environment on AWS with ECS, EKS, and Fargateを追記

続きを読む

AWSのPaaS, SaaSを利用して開発を効率化する

はじめに

  • AWSにはサーバやネットワークを提供するIaaSだけでなく、様々なPaaSやSaaSが提供されている
  • これらを利用することで開発効率を上げることが出来る
  • 今後の指針とするためにも、まずはどんなものがあるのか、どんな使い方が出来るのかを列挙してみる

対象

  • AWSって名前を聞いたことはあるけど実際よくわかってない人
  • クラウドっていうのはネット上にサーバがあるだけだと思ってる人

そもそもIaaS, PaaS, SaaSとは

IaaS

  • Infrastructure as a Service
  • サーバやストレージ、ネットワークといったインフラを提供するサービス
  • レンタルサーバなどのホスティングサービスと違い、サーバのスペックやOS等をユーザが選択することが出来る
  • AWSのEC2やGCPのComputeEngineなどが該当

PaaS

  • Platform as a Service
  • OSやミドルウェアを含めたプラットフォームを提供するサービス
  • インフラを管理する必要がなくなり、アプリケーションの構築に集中できるという特徴がある
  • AWSのLambdaやElastic Beanstalk、GCPのAppEngineなどが該当

SaaS

  • Software as a Service
  • アプリケーションまで含めたソフトウェア全体を提供するサービス
  • 利用者はインターネット上で利用するだけでいい
  • AWSのS3やCloudWatch, GoogleAppsのGmailやGoogleDriveが該当

分類方法

  • TomcatやNginxなどのミドルウェアを用意する必要があるのはIaaS
  • ソースコードなどのアプリケーションだけ用意すればいいのはPaaS
  • 設定するだけですぐ使えるようになるのがSaaS
  • 割と使い方によって変わる
    • 例えばS3を直接クラウドストレージとして使えばSaaSといえる
    • が、アプリケーションのバックエンドとして使うとPaaSっぽい
    • なので、あまり分類に意味はない気がする

AWSの代表的なPaaS, SaaS

Lambda

  • サーバの設定などなく、コードをデプロイするだけで実行可能になる
  • ElasticBeanstalkは構築をしてくれるサービスだが、こっちはサーバを意識する必要は全くない
  • PaaSではなくFaaS(Function as a Service)とも呼ばれる

S3

  • 主に画像や動画などの静的ファイルを置いておくクラウドストレージ
  • 一般的にはアプリのバックエンドなどで利用するためPaaSと言えるが、別に単体でも使えるのでSaaSとも言える

Cognito

  • ユーザーの認証や管理、デバイス間の情報同期を行える
  • TwitterやGoogleなどのOpenID Connectプロバイダーとの連携も可能

API Gateway

  • 簡単にRESTfulAPIを作成、公開、管理できる
  • モニタリングやアクセス権の管理まで可能

CloudFront

  • ContentsDeliveryNetwork(CDN)サービス
  • キャッシュサーバーを利用したレイテンシの高速化やSSL通信、DDos対策などのセキュリティ設定が可能

DynamoDB

  • フルマネージドのKVS
  • テーブルを作成するだけですぐにスケーラブルなDBが利用できる

STS

  • AWSのリソースに対する一時的なアクセス権を管理できる
  • OAuth2.0でいう認可サーバの役割

ユースケース

バックエンドなしでSPAを作る

  • バックエンドのコーディングをすることなくユーザ認証を備えたSPAを作成出来る
  • 一部の仕様がAWSに縛られるので普通よりSPAのコード量は増えるかもしれない
  • が、自分でユーザ管理やアクセス管理を作るよりだいぶ楽かつ安全
    SPA.PNG

  • やっていることは

    1. Route53で独自ドメインを設定
    2. CloudFrontで高速化&SSL化
    3. S3で作成したSPAを配信
    4. Cognitoでユーザの認証を実施
    5. STSでユーザの認可を実施
    6. アクセス権にしたがってDynamoDBへアクセス

サーバを立てずにユーザ統合をする

  • 別々にユーザ管理を行っていたサービスのユーザ統合を行うような場合を想定
  • 普通にやると、各サービスとは別にユーザ管理用のサーバを立てる必要がある
  • AWSを利用すると、簡単にサーバレスな認証APIを作ることができる
    serverless.PNG
  • やっていることは
    • Cognitoを利用してユーザの管理、認証を行う

      • 外部からのユーザ取り込みにも対応している
    • Cognitoを利用するための処理をLambdaを利用して共通化する
    • API Gatewayを利用してRESTfulAPIとして公開
  • これによって、各サービスからRESTfulAPIを呼び出すだけで認証を行うことが出来るようになる
    • Cognitoの仕様上の制約は諸々あるので、サービス側の修正は多少必要

まとめ

  • とりあえずざっと書き出してみました
  • この辺を手がかりに何を勉強すればいいのか考えると良いと思います

続きを読む

動画を探して自動ツイートしてくれるPython製botをAWSに載せてみた(前編)

TL;DR

  • YouTubeから動画を拾ってTweetするbotをPythonで開発し、AWS Lambdaに載せてみました
  • 全2記事です。前編のこちらでは、主にPythonでの開発周りのトピックにフォーカスします
    • TwitterAPIを使ってプログラムからツイートしてみます
    • YouTubeのページを構文解析し、文字列操作を使って動画URLを抽出してみます

動機

新しい職場にて初めてAWSを触ることになったので、これを機にと個人アカウントを取ってみました。チュートリアルだけというのももったいないので、何か自分のためのサービスを作って載せると面白そうです。

で、Twitterのbot開発にはもともと興味があったので、これも前から興味を持ちつつ触ってなかったPythonでbotを作り、lambdaを使って運用してみようと思い立ちました。AWS lambdaは2017年4月からPython3系を扱えるようになったので、心置き無く最新バージョンで書けそうだなー、というのも狙いです。

ユーザーストーリー

毎日の退勤をもう少し楽しみにするために、定時になると自分が興味ありそうなYouTube動画をbotが勝手に検索して、自分のTwitterアカウントに届けてくれるようにしたい。
スクリーンショット 2017-12-06 23.30.33.png

前提

  • 開発にはMacを使用します
  • Pythonは3.6系を使用します
  • pyenvもvirtualenvも使用しません。議論はあろうかと思いますが、個人開発なので。。
  • で、開発環境構築はこちらの記事等を参照しました
  • bot化したいTwitterアカウントはあらかじめ用意してあるものとします

TwitterAPIを使ってプログラムに呟かせる

アクセスキーの取得

bot化したいアカウントでTwitter Application Managementにログインすると、アプリケーションの作成とConsumer Key、及びAccess Tokenの取得ができます。

なお、Appの作成にはTwitterアカウントが電話番号認証済みである必要があります。認証済みでないと怒られるので、エラーメッセージ中のリンクからさらっと済ませておきましょう。

  • Consumer Key
  • Consumer Key Secret
  • Access Token
  • Access Token Secret

以上の4パラメータがあればプログラムからのツイートができます。コピーしてこんな感じのファイルを作っておきましょう。

config.py
CONSUMER_KEY        = "xxxxxxxxxxxxxxxxx"
CONSUMER_SECRET     = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ACCESS_TOKEN        = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
ACCESS_TOKEN_SECRET = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"

複数の外部ユーザーからアクセスがあるようなアプリケーションの場合(=「このアプリケーションとの連携を許可しますか?」など出るやつ)はそれぞれの役割についてもう少し説明が必要ですが、今回はある程度一緒くたに考えてしまっても実装に支障ありません。

PythonでOAuth認証

ライブラリの導入と管理

Pythonのライブラリは、パッケージ管理ツールであるpipでインストールできます。仮想環境がない場合、オプション無しで勝手にglobalに入るのがうーん、という感じですがまあそれは置いておいて。

PythonでHttp通信を行うライブラリとしては、requestsがポピュラーなようです。また、今回はTwitterAPIを使うための認証が必要なので、OAuth認証を扱えるライブラリも必須です。ここはrequestsと同じところが公開しているrequests_oauthlibを使用しました。

pip3 install requests requests_oauthlib

さて、インストールはできましたが、今度は開発するプロジェクトがこれらのライブラリに依存していることを表明しておくのがマナーです。js界隈で言うところのpackage.jsonですね。

Pythonでは依存関係を記したrequirements.txtなどを作っておくケースが多いようです。

requirements.txt
requests==2.18.4
requests-oauthlib==0.8.0

ちなみに、pip3 freeze > requirements.txtでインストールされた依存関係をrequirements.txtに吐き出せます。

逆に.txtファイルを元に一括インストールする場合は、-rオプションを用いてpip3 install -r requirements.txtなどと書けます。結構便利です。

つぶやいてみる

first_tweet.py
from requests_oauthlib import OAuth1Session
import config, json

twAuth = OAuth1Session(
  config.CONSUMER_KEY,
  config.CONSUMER_SECRET,
  config.ACCESS_TOKEN,
  config.ACCESS_TOKEN_SECRET)
apiURL = "https://api.twitter.com/1.1/statuses/update.json"
params = { "status": "プログラムにツイートさせてみるテスト" }

res = twAuth.post(apiURL, params = params)
print(json.loads(res.text))

先ほど作ったconfig.pyimportして、これだけ。思ったよりだいぶ手軽です。Twitterにアクセスして実際にツイートされたことを確認しましょう!

また、せっかくなのでレスポンスをjsonライブラリでロードして吐き出してみます。

{'created_at': 'Wed Dec 06 14:00:00 +0000 2017', 'id': 9384076800000000, 'id_str': '9384076800000000', 'text': 'プログラム
にツイートさせてみるテスト', 'truncated': False, 

...(中略)...

'retweeted': False, 'lang': 'ja'}

思ったよりいろんな属性があることがわかりますね。深掘りは公式のリファレンスにて。

YouTubeから動画のURLを拾ってくる

続いて、YouTubeから動画を探してくるパートです。

Webクローリング

この分野では、「クローリング」や「スクレイピング」と言った言葉が有名です。

クローリングとスクレイピング

クローリングはウェブサイトからHTMLや任意の情報を取得する技術・行為で、 スクレイピングは取得したHTMLから任意の情報を抽出する技術・行為のことです。

たとえば、あるブログの特徴を分析したい場合を考えてみましょう。
この場合、作業の流れは

  1. そのブログサイトをクローリングする。
  2. クローリングしたHTMLからタイトルや記事の本文をスクレイピングする。
  3. スクレイピングしたタイトルや記事の本文をテキスト解析する。

というようになります。

今回は、YouTubeをクローリングし、その中から動画のURLをスクレイピングすることになりますね。

Webページのクローリングとスクレイピングを行う際は、それがどんな目的のものであれ、HTMLを構文解析することが必須となります。Pythonでは、これを強力に支援するBeautifulSoupと言うライブラリがあります。執筆時点で最新のbeautifulsoup4を導入してみます。

pip3 install beautifulsoup4

早速使ってみましょう。Qiitaのトップページから<a>タグを探し、その中に含まれるhref属性の値を取得してみます。

crawling.py
import requests
from bs4 import BeautifulSoup

URL = "https://qiita.com/"
resp = requests.get(URL)

soup = BeautifulSoup(resp.text)

# aタグの取得
a_tags = soup.find_all("a", href=True)
for a in a_tags:
    print(a["href"])

結果

/about
https://qiita.com/sessions/forgot_password
https://oauth.qiita.com/auth/github?callback_action=login_or_signup
https://oauth.qiita.com/auth/twitter?callback_action=login_or_signup

・・・(中略)

https://qiita.com/api/v2/docs
https://teams.qiita.com/
http://kobito.qiita.com

いい感じです!

HTMLパーサーについて

さて、先のコードを実際に試すと、HTMLパーサーが明示されていないために警告が出ます。これは実際の解析時に使われるパーサーが実行時の環境に依存するためです。異なる環境下で同じ振る舞いを期待するには、使用するHTMLパーサーを明示してあげる必要があります。

デフォルトではhtml.parserが使われますが、lxmlかhtml5libを導入してこちらを明示してあげるのが無難なようです。このあたりの情報は下記の記事をだいぶ参考にさせていただきました。パーサーの選択だけでなくスクレイピング全般の情報が非常によくまとまっているエントリなので、オススメです。

PythonでWebスクレイピングする時の知見をまとめておく – Stimulator

パーサの良し悪しを考えるとlxmlでチャレンジしてダメならhtml5libを試すのが良さそう。

今回はこの1文に愚直に従ってみます。事前にpip3 install lxml html5libも忘れずに。


import requests
from bs4 import BeautifulSoup

URL = "https://qiita.com/"
resp = requests.get(URL)

+try:
+  soup = BeautifulSoup(resp.text, "lxml")
+except:
+  soup = BeautifulSoup(resp.text, "html5lib")
-soup = BeautifulSoup(resp.text)

# ...以下は先ほどと同様

Crawlerクラスを作ってみる

すでにPythonでオブジェクト指向な書き方を経験している方はこの辺りを飛ばしていただいて構いません。せっかくHTMLを解析してくれるコードができたので、クラスとして書き換えてみます。

crawler.py
import requests
from bs4 import BeautifulSoup

class Crawler:
    def hrefs_from(self, URL):
        a_tags = self.soup_from(URL).find_all("a", href=True)
        return set(map(lambda a:a["href"], a_tags))

    def soup_from(self, URL):
        res_text = requests.get(URL).text
        try:
            return BeautifulSoup(res_text, "lxml")
        except:
            return BeautifulSoup(res_text, "html5lib")

個人的にはインスタンスメソッドの第1引数が常にselfでなければならないのは書く量が増えるので少しもどかしいですね。ハマりポイントにもなりかねない…。

ちなみに、ここではラムダ式を使用し、hrefs_fromメソッドの戻り値の型をsetにしてみました。これは、今回のユースケースを鑑みてリンク先URLの重複を排除した方が便利と判断したためです。出現頻度など解析したい場合はまた改めて設計を考える必要があるでしょう。

継承と、YouTubeへのアクセス

YouTubeをクローリングするにあたって、「検索文字列を与えたら検索結果のページをクローリングし、動画を探してくる」などの機能があると便利そうです。先ほどのクラスを継承して、実装してみます。

tube_crawler.py
import random
import re
from crawler import Crawler

class TubeCrawler(Crawler):

    URLBase = "https://www.youtube.com"

    def hrefs_from_query(self, key_phrase):
        """
        検索文字列を与えると検索結果ページに含まれるhref属性の値を全て返す
        """
        return super().hrefs_from(self.URLBase + 
            "/results?search_query=" + key_phrase.replace(" ", "+"))



    def movies_from_query(self, key_phrase, max_count = 10):
        """
        検索文字列を与えると検索結果ページに含まれる動画のビデオIDを返す
        """
        return self.__select_movies(self.hrefs_from_query(key_phrase), max_count)



    def __select_movies(self, hrefs, max_count):
        """
        privateメソッド。href属性の値のsetからビデオIDのみを返す
        """
        filtered = [ re.sub( "^.*/watch?v=", "", re.sub( "&(list|index)=.*$", "", href )) 
            for href in hrefs if "/watch?v=" in href ]
        return filtered[:min(max_count, len(filtered))]



    def choose(self, movie_ids, prefix = "https://youtu.be/"):
        """
        渡した文字列のリスト(ビデオIDのリストを想定)から1つを選び、prefixをつけて返す
        """
        return prefix + random.choice(movie_ids)

文法的には継承とprivateメソッドの書き方あたりが新しい話題となります。この記事の主題ではないので特段の説明は省きます。

実際に試すとわかるのですが、検索結果のページにノイズとなるリンクが多いばかりか、再生リストへのリンクなど紛らわしいものも多く、その辺を適切に弾いていくのに手こずりました。おかげでfilter関数や正規表現に少し強くなれた気がします。

正規表現についてはこちらの記事をだいぶ参考にしました。

Pythonの正規表現の基本的な使い方

繋げてみる

準備が整ったので検索->ツイートの流れを試してみます。

main.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from tube_crawler import TubeCrawler
from tweeter import Tweeter
import config

def main():
    t = TubeCrawler()
    movies = t.movies_from_query("Hybrid Rudiments")
    chosen = t.choose(movies)

    # ツイートする部分をクラス化したもの
    tw = Tweeter()
    tw.reply(config.REPLY_TO, chosen)

if __name__ == '__main__':
    main()

エントリーポイントとなる関数が必要かなー、と思ったので何気なく(そう、本当に何気なく。これで良いと思っていたんですLambdaを使うまでは…)main関数を作成。

直接./main.pyでも呼べるようにこの辺からShebangを記述し始めました。また、末尾はファイル名で直接実行した場合にmain()を呼ぶためのおまじない。Rubyにも似たやつがありますね。あとはターミナルから呼んで動作確認するだけです。

$ ./main.py

実行したところ問題なく動きそうだったので、次回はAWS Lambdaに載せていきます。それなりの尺となったのでこのページはここまでです。お読みいただきありがとうございました。

リンク

続きを読む