久しぶりにBlackbeltを見たので勉強になった点をメモ (X-Ray, Cognito, API Gateway, KMS, CloudFormation)

# X-Ray

マイクロサービスは、

* 各サービスで独立した開発・デプロイが行える
* 各サービスで独立したスケーリングが行える
* 障害範囲が各サービス内

という利点があるが、

* ログ集約・フォーマットの違い
* 依存し合う多数・多様なサービス
* ボトルネックが見つけづらい
* 異論関係が変化し続ける

という点が課題となっている。

X-Rayを利用することで、アプリの実行状況や問題の検出、パフォーマンスの計測が可能になる。

X-Rayは大きく3つの区分がある

* トレース
    * 1リクエスト全体
* セグメント
    * Lambdaなどの、リソース名、リクエストの詳細、行った作業の詳細が記録される
* サブセグメント
    * DynamoDBなどの、AWSのサービス、外部HTTP APIの実行状況が記録される

* トレースIDとセグメントIDで実行を記録していく
* トレースヘッダーにX-Amazn-Trace-Idという値にトレースID;親セグメントID;サンプルデシジョンが記録される
* 注釈はフィルタ式（検索）で使うキーバリュー形式の値
* メタデータは注釈と違って検索では使えないが、オブジェクトやリストなどが入れられる
* グループはフィルタ式で定義されるトレースのコレクション
* アナリティクスはフィルタリングされたトレースセット（時間帯や所要時間など）
* メトリクステーブルは200, 500のカウントや％など

サンプリングルールについて、
課金額やパフォーマンスのため、デフォルトでは毎秒最初のリクエストは必ず記録、＋以降は5%のみ。
リザーバーサイズ: 1秒間で必ず記録するトレース
固定レート: リザーバーサイズを超えたリクエストのうち何%記録するか

使い方について、
アプリ (SDK) -> X-Rayデーモン(ECSの場合はサイドカー、Lambda, Beankstalkはコンソール) -> API

Lambda: コンソールで有効化。ただし起動だけしかトレースされないので他のイベントはSDKを使って手動で記録する
ECS: サイドカーでX-Rayデーモンを動かす。ブリッジ接続（デフォルト）の場合は、環境変数のAWS_XRAY_DAEMON_ADDRESSが必要。awsvpcの場合は不要
App Mesh: 環境変数ENABLE_ENVOY_XRAY_TRACE = 1の定義が必要
SQS, SNS: パッシブ計測がデフォルトで有効化済み（何もする必要はない）
CloudWatch Lens: CloudWatchとX-RAYが統合
CloudWatch Synthetics: Canaryを作成してエンドポイントを監視。定期的にロード時間やUIスクリーンショットを取得

注意するべきこと
過去30日しか保持されない。


→ X-Ray使ったことないからあまり知らなかった…実際に使ってみたい。またCloudWatch Syntheticsとかも

# Cognito

APIベースで実装されるモバイルアプリやWebアプリにユーザー認証機能を作成

* ユーザープール: アプリへのアクセスに利用できるトークンを提供
* IDプール: ユーザープール+外部IDプロバイダのログインに基づき、AWSクレデンシャルを提供
* グループ: IAMロールやAppSyncの権限設定ができる

* Cognito Identity Provider API
    * パスワードの再発行など
    * カスタム認証などができる
* Cognito Auth API / Hosted UI
    * カスタム認証は設定できない
    * ビルドインのUIが存在するが、日本語対応なし
    * OAuth2.0のフロー
    * Authorization Code Grant or Implicit Grant(非推奨）がある
        * 認可コードが返ってくるので、APIに投げるとトークンが帰ってくる

ALB, API Gateway, サーバー, App Syncが利用

InitiateAuth -> GetId -> GetCredentialsForIdentityでAWSの一時クレデンシャルが手に入る
アダプティブ認証: リスクに応じてMFAを必須にしたりできる
PinpointやCloudTrail(Cognito Auth API)とも連携している

-> Cognioもぜひ使ってみたい。1から作るより断然容易だけど個人開発にしては重いかも？

# API Gateway

WebAPIのサービス

* インフラの監理
* APIの監理
* 認証と認可
* 流量制御と保護

RESTとWebSocketに対応している。
RESTの場合はエッジ最適化（CloudFront), リージョン（リージョンに直接アクセス、CFも可）, プライベート（PrivateLinkのみ）が選べる。

ステージごとにデプロイが必要。

リソースを入れ子にしてURLを表現。各リソースごとにHTTPメソッドを指定し、フロー処理の定義を行う。

またSwaggerのインポート・エクスポートが可能。API Gateway固有定義の場合はx-amazon-apigateway-*で指定する

WebSocketの場合はルート選択式を使って各イベントの処理を定義する

メソッドリクエスト（REST), ルートリクエスト（WebSocket)のフローでは認証設定が行える。認証設定は下記の3種類

* IAMアクセス制限
* Lambdaオーソライザー
* Cognitoオーソライザー

統合タイプのフローでは処理を実際に行う先を指定できる。最長29秒の制限がある。

* Lambda
* HTTP
* Mock
* AWS サービス
* VPCリンク

Lambda, HTTP, VPCリンクの場合はプロキシ統合の設定が可能。設定が簡単になるがフォーマットが固定になる。

統合レスポンスのフローではマッピングテンプレートを使って処理結果を返すフォーマットを設定できる。
Json Schemaを使ってモデルにすることもできる。

使用量プラン
ステージに関連付けることでスロットリングができる。

キャッシュ
ステージごとにキャッシュを設定できる

カナリアリリースとクライアント証明書も可能。

リソースポリシー
アクセス元の制限など、S3バケットポリシー的な制限ができる。

クライアントSDK
APIステージ単位でREST API呼び出しクライアントをSDKとして生成可能

-> X-Rayと同様こちらも実際に使ってみたい…

# Key Management Service (KMS)

* 鍵をどこに保管
* 鍵をどこで使うか
* 鍵を誰が使うか
* 確かなセキュリティ

KMI (Key Management Infrastructure)

* 鍵の管理・保管

AWS KMS
暗号化鍵の作成、管理、運用のためのサービス


* CMK
    * 最上位
    * KMSのHMS上のみ平文
    * 最大4KB
* CDK
    * 実際の暗号化・復号化に使用

* Envelope Encryption
    * マスターキーをデータ暗号化に利用するのではなく、マスターキーで暗号化した暗号キーで対象オブジェクトを暗号化・復号化する
    * 暗号化したデータとCMKで暗号化されたデータキーを一緒に保管
* Key Policy
    * 暗号化キーに対してリソースレベルのポリシー
    * IAMユーザーとポリシーの両方評価
* 許可
    * CMKの使用をクライアントによって他のAWSプリンシパルに委任できる
* Encryption Context
    * 暗号化を利用する際にKMSにわたすことのできるKey/Valueペア
    * 暗号化の時に指定すると復号化の時に同じペアが必要
    * CloudTrailに平分で乗るので注意
* 暗号化・復号化のAPI
    * Encrypt API
        * 暗号化のAPI
        * ヘッダが付与される
    * Decrypt API
        * 復号化のAPI
        * ヘッダからCMKが自動で特定される
    * GenerateDataKey API
        * 暗号化に使うCDKを生成
        * 平文の鍵とEncrypt APIで暗号化された鍵を返す

暗号化の手順

1. データキーを生成 (平文と暗号化されたデータキーが返る)
2. 平文のデータキーを使って暗号化
3. 平文のデータキーの削除＆暗号化済みデータキーと共にデータを保存

復号化の手順

1. 暗号化されたデータキーをKMSに送信
2. 返ってきた平文のデータキーでデータを復号化
3. 平文のデータキーを削除

最小権限・権限分離
発見的統制
パフォーマンスとサービス制限
鍵をどの単位で分離するか（データクラス、インシデントなど）
インシデント対応の明確化と自動化（不正なアクセスが有ればLambdaで自動的にDisableにするなど）

-> KMS今までよく知らなかったけど概要が理解できた！

# CloudFormation

テンプレート → スタック → AWSリソース

* Parameters
    * ユーザーに指定させる
* Resources
    * 必須
* Outputs
    * 他スタックとの連携

former2(非公式）でyamlの作成ができる

開発

* cnf-lint
    * 入力した値の整合性チェックできるコマンドラインツール
* CloudFormation template schema
    * 自動補完をしてくれるプラグイン (VSCode, Pycharm)

テスト

* cnf-lint
    * 使われていなかったり型が違うなどの警告を出してくれる
* taskcat
    * マルチリージョン・マルチアカウントのテスト
* cnf-nag
    * 潜在的なセキュリティ問題の警告（CIDRが0.0.0.0/0になっているなど)
* CloduFormation Guard
    * テンプレート検証
    * ルールを記述してそれにそぐわない項目をリスト

デプロイ

* CodePipelineでデプロイ
    * 自動化
    * 安全
    * 繰り返し可
    * デプロイ先に手動アクセス阻止
* ChangeSetsで確認してからデプロイ
    * 変更箇所が事前に確認できる
* StackSetsでデプロイ（マルチリージョン・マルチアカウント向け）
    * 1回の操作で複数のアカウントやリージョンへスタックを作成、更新、削除できるCloudFormationの機能

スタックとリソースの保護

* IAMポリシー
* スタックのスタック保護
    * スタックポリシー（Ex. RDSの変更を禁止など）
* リソースのDeletation Policy

ライフサイクルごとのスタック

* スタックをレイヤとライフサイクルで分割
* スタックを環境ごとに再利用

設計観点

以下でスタックを分けてそれぞれをCross Stack Referenceで参照し合う

* 依存関係
* ライフサイクル
    * 更新頻度と寿命
* 所有権
    * 管理するチームごと

依存度が小さく、またライフサイクルが短い順に、次のようにスタックを分割するといい

* Application Layer
    * Application
        * ECS, ELB, AutoScalingなど
    * Data
        * S3, RDS, SQSなど
    * Shared Service
        * Route53, EC2(共通）、Directory Serviceなど
* Security Layer
* Network Layer

この時、各Roleはそれぞれのスタックで定義して、セキュリティグループはまとめるといい。かつセキュリティグループのスタックはVPCやサブネットなどのスタックとも別にしたほうがいい。

スタックのリファクタリングにはResource Importを使うといい。

ヘルパースクリプト

* cnf-init
    * Systems ManagerのState Managerを推奨
* cfn-get-metadata
    * メタデータ取得（Ex. EC2起動サービスなど）
* cnf-signal
    * EC2リソースが正常にできたか
* cfn-hup
    * EC2の再起動をせずにCloudFormationの変更時にアプリケーションに設定を適用
    * 作成されたリソースのメタデータを検知し、カスタムフックを実行するためのデーモン

Dynamic Reference
Systems Managerのパラメータストアに格納されたデータを動的に取得



→スタックポリシーを使えばIAMやdeletation policyとは違った方向でリソースを保護できる。
また開発やテスト時に使える便利なツールやプラグインがあることが分かった。
スタックの分割基準も分かってよかった。
様々なヘルパースクリプトも利用できることが分かったし、Dynamic Referenceも知れてよかった。
Terraformから移行する日も近い？