継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

AppSync と関連サービスの使い方をハンズオンで学ぶ『AWS AppSync immersion day workshop』

タダです.

前回の記事で「初めてのGraphQL」を読んだ感想を書いたのですが,AWS にはマネージド GraphQL サービスの AWS AppSync があります.このサービスの概観をさらいたくて「AWS AppSync immersion day workshop」をやってみました.このワークショップを通じてやる内容や学べたことをまとめていきます.

sadayoshi-tada.hatenablog.com

ワークショップの概要

AWS AppSync immersion day workshop」の内容は大まかに以下の通りです.

  • マネジメントコンソールから AppSync の API の作成,DynamoDB へのデータ登録,検索をさらう
  • AWS CDK で AppSync や関連サービスの作成
  • Amplify のサンプルアプリと AppSync に接続したり,認証をつけたり AWS WAF を挟んだり等のハンズオン
  • AppSync のデータソースに Lambda を使うアーキテクチャの構成
  • X-Ray,CloudWatch Logs を有効化して AppSync でのモニタリングとロギング

ワークショップを通じて学べると感じたこと

マネジメントコンソールから API 作成

初めて AppSync に触る人にとってはチュートリアルパートで,勉強になります.API の作成,スキーマの作成,クエリを発行して DynamoDB のテーブルデータの中身を確認したり,スキーマを変更した場合にマッピングテンプレートを更新などといったハンズオンを行います.

CDK で AppSync を作成

マネジメントコンソールで API を作った後,次は CDK で AppSync の API を別で作っていきます.AppSync の APIcurl でアクセスしてみることもやりました.コンソールからのアクセスのときは画面上でいじった時,開発時はどういう感じで動作確認を行うのかをイメージしたかったので参考になりました.

curl -s -XPOST -H "Content-Type:application/graphql" -H "x-api-key:$API_KEY" -d '{"query": "'"$MUTATION"'","variables": '$VARIABLES'}' $API_URL | jq
{
  "data": {
    "createDataPoint": {
      "createdAt": "2022-02-12T13:57:51.023Z",
      "name": "hello-world",
      "value": 94
    }
  }
}

$ curl -s -XPOST -H "Content-Type:application/graphql" -H "x-api-key:$API_KEY" -d '{"query": "'"$QUERY"'","variables": '$VARIABLES'}' $API_URL | jq
{
  "data": {
    "queryDataPointsByNameAndDateTime": {
      "items": [
        {
          "createdAt": "2022-02-12T13:57:51.023Z",
          "name": "hello-world",
          "value": 94
        }
      ]
    }
  }
}

Amplify のサンプルアプリケーションと AppSync や関連サービスとの連携ハンズオン

サンプルアプリケーションのコードに CDK で作った AppSync の情報を記載してローカルで起動すると下記の画像のアプリケーション画面が閲覧できます.ブラウザから AppSync API へのデータ生成を自動で行えて,そのデータを閲覧もできます.

初期画面 f:id:sadayoshi_tada:20220213164141p:plain

また,AppSync の API にアクセスしたデータを画面上に表示されます.また,Cognito を入れて認証画面を設けたり,データソースの DynamoDB へのアクセス制御は認証したユーザーのみにしたり,AWS WAF を挟んで自分の使っているグローバル IP からしAPI アクセスを許可しないといったセキュリティを高めるオプションを学びました.

認証画面 f:id:sadayoshi_tada:20220213165945p:plain

WAF の有効化後の画面 f:id:sadayoshi_tada:20220213230358p:plain

AppSync のデータソースに Lambda を使うアーキテクチャの構成

AppSync のデータソースに Lambda を設定するアーキテクチャを構成するパートでは,これまでは DynamoDB に AppSync から操作を行っていたところを Lambda を介してクエリ発行するように構成していきます.1つ目が Direct Lambda Resolver という手法で,Lambda を間に挟むことで VTL マッピングテンプレートを使わずに,リクエスト情報を Lambda に渡して,Lmabda がレスポンスを GraphQL 形式に合わして整形し返却します.2つ目が Pipeline Resolver という手法で,複数のリゾルバを束ねてオペレーションを順番に実行できるといったものをハンズオンで学んでいきます.

関連情報

docs.aws.amazon.com

docs.aws.amazon.com

AppSync の X-Ray と CloudWatch Logs の連携

AppSync の運用をしていく上でログを残す場所として CloudWatch Logs,モニタリングとして X-Ray がサポートされているためこれらを有効化してログとトレース結果を確認しました.

CloudWatch Logs の有効化とログ詳細 f:id:sadayoshi_tada:20220213234924p:plain

f:id:sadayoshi_tada:20220214000539p:plain

X-Ray の有効化トレース画面 f:id:sadayoshi_tada:20220213234919p:plain

f:id:sadayoshi_tada:20220214000400p:plain

まとめ

AWS AppSync immersion day workshop」の内容や学べると感じたことをまとめていきました.AppSync を初めて触ろうとしている人や AppSync でアーキテクチャに採用を検討している人にとって参考になるワークショップだなと感じました.

GraphQL 初学者が『初めてのGraphQL』を読んだ所感をまとめる

タダです.

GraphQL の勉強の一環で「初めてのGraphQL」を読んだり写経したのですが,その感想を記事にまとめていきます.なお,自分は現状業務で GraphQL を触ったりする機会はないが,GraphQL がどんな技術なのかを知りたくて勉強しているようなレベル感です.

目次

本書はページ数が213ページで,全7章で構成されています.

  • 1章 GraphQLへようこそ
  • 2章 グラフ理論
  • 3章 GraphQLの問い合わせ言語
  • 4章 スキーマの設計
  • 5章 GraphQLサーバーの構築
  • 6章 GraphQLクライアントの実装
  • 7章 GraphQLの実戦投入にあたって

本書の概要

本書は大きく3つのパートで構成されているのかなと感じました.

  1. GraphQL の概要説明(1章~3章)
  2. GraphQL のスキーマ設計解説(4章)
  3. GraphQL の開発を体感するためのハンズオン(5章~7章)

本書で学べること

本書で学べると感じたことをまとめていきます.

  • GraphQL とはどんな技術で,言語仕様や設計原則,誕生までの歴史,専門用語といった GraphQL 自体の解説があるので,全く技術に触れてこなかった自分でも概要を掴むことができました.
  • GraphQL では型を簡単に定義できるスキーマ定義言語(SDL)を用意しています.SDL 関する以下の用語や考え方をさらえます.
  • GraphQL を使っての開発ハンズオンではサーバーサイドとクライアントサイドそれぞれの実装をハンズオンしながら解説がされていきます.
    • サーバーサイドの開発をexpressで開発し,GitHub で認証認可を行って写真投稿と写真にタグ付けするアプリケーションの開発
    • クライアントサイドの開発はReactで開発

読了後の所感

読了後の所感として GraphQL 初心者の自分でも概要をさらえました.スキーマ設計の章で勉強したことをハンズオンパートで再度触れつつ解説が進むため設計->実装はこんな感じに進むのかというイメージを持てました.また,ハンズオンを通して GraphQL を動かして行くなかでこうやって開発していくんだというのを学べました.

まとめ

初めてのGraphQL」を読んだ所感を中心に読むことで得られることをまとめていきました.AWS でも AppSync が GraphQL のマネージドサービスとしてあるので試してみたいなと思っていたらワークショップがあったので次はこっちをやってみたいと思います.

関連情報

github.com

踏み台用 ECS Fargate から Aurora へのローカル接続を実現する

タダです.

AWSコンテナ設計・構築[本格]入門」を読んでて,ECS Fargate で踏み台を作るハンズオンがあります.この踏み台コンテナを使って Eureca さんの記事で紹介されてたローカルの DB クライアントからプライベートサブネットの Aurora へ socat で TCP リレーを行い接続する検証をしてみたのでやった作業をこの記事に書いていきます.

検証概要

自分の管理している環境では AWS SSO を採用して AWS アカウントにログインしています.また各システムアカウントには踏み台用 AWS アカウントを経由して更にスイッチロールでログインしており,開発者ごとに必要な権限を渡す運用にしています.

検証では踏み台コンテナに AWS SSO 経由で許可された開発者だけアクセスさせるようにしたいので,スイッチロールを行った後 Session Manager の AWS-StartPortForwardingSession を使ってローカルからプライベートサブネットの Aurora へ接続を試みます.

検証イメージ

f:id:sadayoshi_tada:20220203220318p:plain

必要なセットアップ

今回の検証を行うために次のツールのセットアップを行います.

AWS CLI v2 の導入後の確認

 % aws --version
aws-cli/2.2.11 Python/3.8.8 Darwin/19.6.0 exe/x86_64 prompt/off

Session Manager Plugin の導入後の確認

% session-manager-plugin

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.

事前準備

事前準備として SSO 初期設定と AWS CLI の初期設定を行います.

AWS CLI 初期設定

1, ~/.aws/credentials のファイルに AWS SSO に表示されている踏み台 AWS アカウントのクレデンシャル情報を追記する

[踏み台 AWS アカウントの任意のプロファイル名]
aws_access_key_id=hoge
aws_secret_access_key=hoge
aws_session_token=hoge

[システム AWS アカウントの任意のプロファイル名]
role_arn = arn:aws:iam::12345678910:role/[スイッチロールのロール名]
source_profile = [踏み台 AWS アカウントの任意のプロファイル名]

2, ~/.aws/config のファイルに下記のように追記する

[profile システム AWS アカウントの任意のプロファイル名]
region = ap-northeast-1
output = json

SSO 初期設定

1, aws configure sso --profile [踏み台 AWS アカウントのプロファイル名] を実行してプロンプトに必要な情報を埋める

% aws configure sso --profile [踏み台 AWS アカウントのプロファイル名]
SSO start URL [None]: https://hoge.awsapps.com/start#/                                                         
SSO Region [None]: ap-northeast-1                                                                                         
Attempting to automatically open the SSO authorization page in your default browser.
If the browser does not open or you wish to use a different device to authorize this request, open the following URL:

https://device.sso.ap-northeast-1.amazonaws.com/

Then enter the code:

hoge-hoge(自動で表示される)
There are 5 AWS accounts available to you.
Using the account ID 12345678910(踏み台 AWS アカウント)
There are 5 roles available to you.
Using the role name "hoge-role"(踏み台 AWS アカウントで使っているロール名)
CLI default client Region [None]: ap-northeast-1                                                                          
CLI default output format [None]: json                                                                                    

To use this profile, specify the profile name using --profile, as shown:

aws s3 ls --profile 12345678910_bastion-switch-role <=ここまで出れば終了

2, 以下のコマンドを実行し、システム AWS アカウントのスイッチロール先 IAM ロールが表示されたら完了

% aws --profile [システム AWS アカウントのプロファイル名]sts get-caller-identity
{
    "UserId": "hoge:botocore-session-123456789",
    "Account": "12345678910",
    "Arn": "arn:aws:sts::12345678910:assumed-role/switch-role/botocore-session-123456789"
}

クライアント側から接続のためのスクリプト

DB クライアント側から接続するために開発者が実行する共通処理をスクリプトにしてみました.

#!/bin/sh
# RDS のホスト名
TARGET_HOST=hoge.ap-northeast-1.rds.amazonaws.com
# ターゲットのポート番号
PORT_NUBMER=3306
# ローカルのポート番号
LOCAL_PORT_NUMBER=3306
# 踏み台 AWS アカウントのプロファイル名
SOURCE_PROFILE=[踏み台 AWS アカウントのプロファイルを記載]
# システム AWS アカウントのプロファイル名
SYSTEM_PROFILE=[システム AWS アカウントのプロファイルを記載]

# init
aws sso login --profile ${SOURCE_PROFILE}

# オンラインステータスのコンテナIDを取得
BASTION_CONTAINER_ID=`aws --profile ${SYSTEM_PROFILE} ssm describe-instance-information --filters "Key=PingStatus,Values=Online" | jq -r '.InstanceInformationList[] | select ( .InstanceId| startswith("mi-")) | .InstanceId '`

# コマンドID取得
COMMAND_ID=`aws --profile ${SYSTEM_PROFILE} ssm send-command \
  --instance-ids ${BASTION_CONTAINER_ID} \
  --document-name [socat 実行するためのドキュメント名] \
  --parameters targetHost=${TARGET_HOST} | jq -r .Command.CommandId`

# ポートフォワード
aws --profile ${SYSTEM_PROFILE} ssm start-session \
    --target ${BASTION_CONTAINER_ID} \
    --document-name AWS-StartPortForwardingSession \
    --parameters portNumber=${PORT_NUBMER},localPortNumber=${LOCAL_PORT_NUMBER}

# RunCommand のキャンセル
aws --profile ${SYSTEM_PROFILE} ssm cancel-command --command-id ${COMMAND_ID}  

接続確認

クライアント側から接続のためのスクリプトを実行して,SSO の認証が通れば IAM の権限で Session Manager や RunCommand の権限が許可されていてかつネットワーク周りの経路が確保されていた状態であれば,Aurora への接続が成功しました.

まとめ

検証で DB クライアントからの接続が成功したので,開発メンバーにも展開しました.これで SSH 鍵の管理がなくなり,踏み台サーバーのセキュリティグループの管理からも開放されます.加えて SSO や IAM で許可した開発者だけが DB につなげるためセキュリティ向上にも資するような仕組みしていけるなと感じました.

参考にさせていただいた記事

dev.classmethod.jp

dev.classmethod.jp

medium.com

CloudWatch Events の定数を使って Lambda の処理を分岐させる

タダです.

定期イベントを CloudWatch Events で設定し,定型処理を実行する Lambda をキックすることはよくあることだと思います.今回 CloudWatch Events の定数を使って Lambda の処理を分岐させるのをやってみたのでこの記事にまとめていきます.今回は ECS タスクの数を調整する処理を作ってみました.

ECS のタスク数を調整する Lambda

Lambda のコードは以下のようなコードを書いてます.CloudWatch Events から desired_count をパラメーターとして渡し,desired_countが0ならコンテナをなくして,desired_countを1ならコンテナを1台起動させます.

import json
import boto3
import logging
from botocore.exceptions import ClientError

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    logger.info("Update ECS Task Count")
    CLUSTER_NAME = 'cluster name'
    SERVICE_NAME =  'service name'
    desired_count = event['desired_count'] 
    try:
        client = boto3.client('ecs')
        
        if desired_count == 0:
            result = client.update_service(
                    cluster = 'cluster name',
                    service = 'service name',
                    desiredCount = desired_count
                )
            return "Stop Complete."
            
        elif desired_count == 1:
            result = client.update_service(
                    cluster = 'cluster name',
                    service = 'service name',
                    desiredCount = desired_count
                )
            return "Start Complete."
            
            
    except ClientError as e:
        logger.exception("Exception.")

CloudWatch Events の定数

Lambda のコードで設定している desired_count を定数で定義していきます.イベントのターゲットを指定する箇所で定数を {"desired_count": 0(1)}と設定します.

コンテナを0台にするイベント f:id:sadayoshi_tada:20220130180916p:plain

コンテナを1台にするイベント f:id:sadayoshi_tada:20220130180902p:plain

関連情報

docs.aws.amazon.com

動作テスト

Lambda のテストイベントで次のような設定をして実行してみます.下記のテストでコンテナを起動できるか確認します.1台のコンテナ起動できました.

{
  "desired_count": 1
}

f:id:sadayoshi_tada:20220130181755p:plain

f:id:sadayoshi_tada:20220130181902p:plain

次にコンテナをなくしてみます.意図通りコンテナを消せました.

{
  "desired_count": 0
}

f:id:sadayoshi_tada:20220130182019p:plain

f:id:sadayoshi_tada:20220130182035p:plain

まとめ

CloudWatch Events の定数を使って ECS タスク数を Lambda 側で処理を分岐させました.この機能を知るまでは Lambda を処理ごとに作ってしまっていたので,管理する関数の数が少なくなるので良かったです.

Session Manager のログ出力形式をまとめる

タダです.

Session Manager のログ周りを触る機会があり,S3 と CloudWatch Logs へ Session Manager のログを出力できるのですが,それぞれの設定方法をまとめていこうと思います.

S3 に Session Manager のログを出力する場合

S3 にログを出力する場合は, セッションマネージャー > 設定よりS3 logging のセクションで設定していきます.今回は下記のように設定を行います.

f:id:sadayoshi_tada:20220126062750p:plain

上記の設定を保存後,Session Manager でターミナル作業を終了したら S3 にログが格納されます.ユーザー名-乱数.logというファイルになっており,中身はログの中身以下に記載のようなログとして記録されます.

f:id:sadayoshi_tada:20220126063133p:plain

ログの中身

Script started on 2022-01-25 06:49:24+0000
[?1034hsh-4.2$ 
[Ksh-4.2$ 
sh-4.2$ 

関連情報

docs.aws.amazon.com

CloudWatch Logs に Session Manager のログを出力する場合

CloudWatch Logs にログを出力する場合も セッションマネージャー > 設定よりCloudWatch logging のセクションで設定していきます.今回は下記のように設定を行います.

  • CloudWatch loggingEnable チェックボックスをオン
  • Choose your preferred logging optionStream session logs (Recommended) を選択
  • Enforce encryptionAllow only encrypted CloudWatch log groups チェックボックスをオン
  • リストからロググループを選択する から作成済みの暗号化済みのロググループを選択

f:id:sadayoshi_tada:20220126092931p:plain

上記の設定を保存後,Session Manager でターミナル作業中の操作が CloudWatch Logs にログが格納されます.ユーザー名-乱数というストリームになっており,中身は以下に記載のような JSON ログとして記録されます.

f:id:sadayoshi_tada:20220126093332p:plain

ログの中身

{
    "eventVersion": "1.0",
    "eventTime": "2022-01-25T12:08:12Z",
    "awsRegion": "ap-northeast-1",
    "target": {
        "id": "i-123456789101112"
    },
    "userIdentity": {
        "arn": "arn:aws:iam::123456789101112:user/ssm-test"
    },
    "runAsUser": "ssm-user",
    "sessionId": "ssm-test-123456789101112",
    "sessionData": [
        "sh-4.2$ sh-4.2$ "
    ]
}

関連情報

docs.aws.amazon.com

まとめ

Session Manager のログ保存方法について2種類あり,設定方法とログの中身を確認したのでまとめました.こういったログは監査の際に必要になったりすると思いますが,保存方法,保存期間や閲覧など要件に応じた選択をしていきたいと思います.