20210415のAWSに関する記事は14件です。

AWS Cognitoのパスワード忘れ時のフローと設定について

AWS Cognito とは こちらのマネージドサービスを使うと非常に便利に以下のような機能をノーコードで実装することができます - ユーザ認証 - ログイン画面(ログイン認証そのものを含む) - セッション管理 - パスワード忘れの対応(検証コード送付及びパスワード再設定)※この記事はこれについて解説 パスワード忘れ時の対応 AWS CognitoはHostedUIを使って提供されてるログイン画面を使うことができます。 ログイン画面でパスワードが分からない場合に「Forgot your password?」をクリックすると、 自動で検証コードが入ったメールがユーザに送られて、 パスワードを再設定することが可能です。 以下、パスワード忘れのフローを使えるようにする設定等について解説します。 なお、こちらの記事は現時点(2021/04/15)のものになります。 ユーザ登録で必要な設定 ユーザを登録する時に「Eメールを検証済みにしますか?」にチェックを入れる Cognito>ユーザーとグループ>ユーザの作成 ※こちらはEmailアドレスをユーザーIDに設定した場合の登録方法です。 メールアドレスが検証済みになる Cognito>ユーザーとグループ>登録したユーザ 以下のように登録内容に「email_verified true」となっていること 「email_verified true」という状態になっていなければ、ログイン画面で「Forgot your password?」を押して、 パスワード忘れのフローを行っても、実際には検証コードが送られてこないので、必ず検証済みにする必要があります。 パスワード忘れ(Forgot your password?)時に送付されるメッセージの登録箇所 Cognito>メッセージのカスタマイズ>「E メール検証メッセージをカスタマイズしますか?」 ※改行は反映されないので改行を入れるなら<br/>を入れよう パスワード忘れのときのフロー(UIは初期設定のまま) ※この一連の画面は英語のみで日本語に変更することはできない ログイン画面>「Forgot your password?」をクリック Emailの入力欄に登録しているメールアドレスを入力 検証コードと新しいパスワードを登録する AWS Cognitoのメールに関する制限 AWS Cognitoで使えるリソース(ユーザの登録、ユーザのデータ参照等)はすべて制限値があります。 以下メールとパスワード忘れ時に関するデフォルトの設定です。 ※ものによっては上限を上げる希望を出せる AWS アカウントごとに 1 日に送信される E メールメッセージの最大数は50件 パスワードを忘れた場合のコードの有効期限 1 時間 パスワード忘れ等は1秒あたり30リクエストまで UserAccountRecovery(パスワード忘れ、パスワード変更等) Service Quotas>AWS のサービス>Amazon Cognito User Pools>「UserAccountRecovery」で検索 こちらで実際の利用状況をモニタリングできる 参照 Use Cognito Forgot password cannot receive any code with Email のクォータAmazon Cognito(Quotas in Amazon Cognito) ※機械翻訳なので日本語のタイトルが非常に味のあるものになっている
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

終わった雑談ロボットを救ってみた

前書き 実家の掃除を手伝っていたらこんなものが見つかりました タカラトミーが開発したコミュニケーションロボット『OHaNAS』でございます。このロボットの特長は、なんと『ドコモ雑談API』の技術が使われており、雑談会話が可能となっているという点ですね。 多人数会話、言語処理系の研究経験がある方やその方面の知識がある方、お察しの通りです。 『ドコモ雑談API』、サービス終了しています。よって、このロボットはもう喋ることはありません。 けど、喋れなくなったからゴミ箱へポイって可哀そうじゃないですか、でも喋らなくなったらもうただの文鎮だしなぁ1 ということで、このロボットがまた雑談できるように、スマートスピーカーの機能を埋め込んでまた喋ってもらいます。 スマートスピーカーを作る まず、実際に埋め込むスマートスピーカーを選定しようと思いましたが、意外とスマートスピーカーって大きいんですね。外装とかを外して小型化したとしても入りそうにないですね。 ということで、今回は最近電子工作界隈で話題のあれを埋め込みます。 M5Stack社のESP32デバイス『M5stack Core2 for AWS』2でございます。 M5stackとAmazonのコラボ商品で、なんとBOTTOM部分にMicrochip社製のATECC608A Trust&GOセキュアエレメントが内蔵されているためAWSを使ったIoTのアプリケーション構築が比較的簡単にできるといった商品となっています。 今回はこの『M5stack Core2 for AWS』にアレクサを突っ込んでスマートスピーカーの代用とします。 M5stack Core2 for AWSのチュートリアルをある程度こなす まずは、このデバイスの仕様を把握するために、すこしチュートリアルを進めましょう。 ついこの間公式のチュートリアルページが日本語化されたようなので、日本語版のURLを貼っておきます。 https://edukit.workshop.aws/jp 全部やると結構ボリュームがあるので、そうですね、第2章【Blinky Hello World(Lチカ)】まで進めておくといいかもしれません。 多少誤訳や誤植も見られますが、見た感じ2章までは致命的な誤訳誤植は無かったので問題なく進められると思います。 M5Stackをアレクサにする デバイスの仕様をある程度把握出来たら、次はいよいよAlexaを実装していきます。 手順は一応先ほどのチュートリアルページにも掲載されてはいますが、情報が古いまま和訳されたのか、それとも誤植なのかわかりませんが正しい手順になっていないので執筆時点(2021年3月)での正しい手順を説明します。 1) チュートリアル用のリポジトリをクローンする  チュートリアルをLチカまで進めていれば既にクローン済みだと思うのでスキップしても大丈夫です。 git clone https://github.com/m5stack/Core2-for-AWS-IoT-EduKit.git 2) 証明書生成用データをダウンロード  AWS IoT証明書の生成に必要なデータをダウンロードします。公式ページにメールアドレスを打ち込むとメールで必要なデータが届きます https://espressif.github.io/esp-va-sdk/#/  メールに7つほどデータが添付されてると思うので、わかりやすい階層に『espcredentials』というフォルダ(ディレクトリ)を作りそこに入れておいてください。 3) 証明書を生成しM5Stackに書き込む  espcredentialsフォルダ内に移動した『mfg_config.csv』に証明書生成に必要なデータのpathが書かれているので、正しいpathに修正します。 mfg_config.csv key,type,encoding,value device,namespace,, device_id,file,binary,/path/to/device.info //ここにdevice.infoのpath account_id,file,binary,/path/to/account.info //ここにaccount.infoのpath mqtt_host,file,binary,/path/to/endpoint.info //ここにendpoint.infoのpath client_cert,file,binary,/path/to/device.cert //ここにdevice.certのpath client_key,file,binary,/path/to/device.key //ここにdevice.keyのpath server_cert,file,binary,/path/to/server.cert //ここにserver.certのpath (解説のためにコメントアウト入れましたが、データ形式がCSVなのでコメントアウトは消しておいてください)  mfg_config.csvを修正後、以下のコマンドを実行することで証明書が生成されます。 python %IDF_PATH%\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py generate 《mfg_config.csvのpath》 mfg.bin 0x6000  証明書が無事生成されたら、M5Stackに書き込みましょう。 python %IDF_PATH%\components\esptool_py\esptool\esptool.py --chip esp32 --port 《COM番号》 write_flash 0x10000 mfg.bin 4)Alexaのプログラムを書き込む  これでようやくAlexaのプログラムを書き込む準備ができました。あと一息です。  クローンしたチュートリアルのリポジトリ内の『Alexa_For_IoT-Intro』フォルダ(ディレクトリ)にcdコマンド等を使用して移動した後、以下のコマンドで書き込みます  idf.py build flash monitor -p 《COM番号》 5)Alexaの動作確認  ESP Alexaアプリ(iOS/android)をインストールしてデバイス登録を行い、あとは普通のAlexaと同様に会話ができればOKです。お疲れ様でした。 OHaNASを改造する とりあえずOHaNASを分解してみましたが、だいぶスカスカですのでM5Stackは問題なく入りそうです。 ただ、ざっくりと見た感じですと、このロボットにM5Stackを組み込むには以下の問題を解決する必要がありそうですね。 ・LEDがメインボードに内蔵されているため、代わりのLED周りの回路を製作してメインボードと取り換える必要がありそう ・マイクが既存の位置には付けられそうもないため、目立たない位置に穴をあけて対応する ということで、上から順に解決していきます。 LED周りの回路を製作する LED周りの回路はOHaNAS由来の物をそのまま載せることはできませんので、少し工夫が必要です。 あまり凝った回路にしてしまうとプログラム側の改修が必要になってとても面倒くさいので、M5GO BOTTOM2内のLED回路を改造して何とかします。 今回は、LEDを2つほど外して、代わりにケーブルを伸ばしました。 OHaNASのメインボードの代わりになる基板は、業務でも使用しているEAGLE3 4を使用して設計を行いました。 基板レイアウトはOHaNASについていたメインボードを実測して再現します。 今回製作した基板データはこちらです EAGLE 軽く動作確認もしましょう。できればPCBにする前にブレッドボードとかで試作したほうが良いのですが、時間が無いのでPCBにした後に動作確認をしています。 やっと目が光った pic.twitter.com/CjjTQphQpt— 樋口グッピー (@Guppy_T_Higuchi) April 12, 2021 ※PCB化したLED基板をOHaNASの顔に取り付けて動作確認を取っている図 マイクの検討 マイクを取り付ける位置を決め、マイク穴を適当に開けます。あまり目立たないようにメッシュを貼ったり穴を小さくする等、工夫をした方がよさそうですね。 M5stack自体にもマイクは内蔵されていますが、ロボットの内部だと反響して音声がきれいに取得できないので、少しでも条件をよくするため外付けのマイクを使用しました。 https://www.switch-science.com/catalog/6620/ 当初はそのままGROVE端子経由で接続しプログラムの修正をして対応するかとのんきに考えていましたが、 どうやらマイクとスピーカーのアンプが同じピンに割り当てられているらしくピン宣言を弄ったら盛大に音割れしたので、M5Stack用プロトモジュールを使ってマイクのピンであるG0とG34ピンを引き出して接続しました。 (注:そのまま取り付けるとマイクが二つ接続されてしまうので、BOTTOMの方のG0,G34ピンは物理的に導通しないよう外しておいてください) M5Stackを取り付けるための検討をする M5Stackを取り付けるために必要な追加パーツの検討をします。必要ならば3DプリンターやCNCで作るのもありです。 とりあえず今回は小さめの板のようなものとそれなりに固定できる接着剤で何とかなりそうなので、逸般の誤家庭(いっぱんのごかてい)で余りがちな捨て基板を板の代わりとして使いました。 また、M5stack本体をそのままロボット内部に収めてしまうと電源ボタンが押せないので、OHaNASの頭頂部にあるボタンの線をM5stackの電源ボタンのランドにはんだ付けして電源を入れる手段を確保します。 あとこれは必須ではありませんが、ついでにスピーカーの線も伸ばしておいて組み込み時にOHANAS本体のスピーカーと接続しましょうかね。 組み込む あとは組み込むだけです。試行錯誤しながらがんばって組み込みましょう。 以上で完成です。お疲れ様でした。 動作確認 完成品はこちらになります。 (とりあえず急いで撮ったものを仮でおいておきますが、後日撮影しなおして差し替えます) やっと完成したので仮組みして動作確認。後でしっかりした場所で撮り直します pic.twitter.com/rB3LGlcseR— 樋口グッピー (@Guppy_T_Higuchi) April 15, 2021 というのは建前で、大学卒論で思いっきりこのロボットを例に出していたので少し愛着があるだけです ↩ https://www.switch-science.com/catalog/6784/ ↩ https://www.autodesk.co.jp/products/eagle/free-download ↩ EAGLEを使ったことのない人向けの解説書はこちら https://shortlovers.booth.pm/items/2646682 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】マネーシド型とアンマネーシド型

プログラミング勉強日記 2021年4月15日 AWSの仕組み  こちらの記事でも述べているように、パーツを組み合わせてインフラのアーキテクチャを設計・構築できる。AWSのアンマネーシド型とマネーシド型がある。 アンマネーシド型  スケーリング・耐障害性・可用性をユーザ側で設定して管理する必要がある。  メリットとしては、設定を柔軟に変更することができる。デメリットは、管理が面倒という点である。  代表的なサービスとしては、AWS側で仮想サーバを作るサービスのEC2がある。EC2は、サーバーを作ったらその設定はユーザ側が行う。 マネーシド型  スケーリング・耐障害性・可用性がサービスに組み込まれて、AWS側で管理されている。  メリットとしては、管理が楽という点である。デメリットは、設定を行える範囲が限られていることである。  AWSのほとんどのサービスがマネーシド型だが、代表的なサービスとしてRoute53がある。冗長性や可用性とか全てAWS側で管理されていて、サーバーが落ちることのない100%の稼働率をAWS側が保証している。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpeedPizzaのインフラ

インフラ Frontend(SSR) CloudFront → ApiGateway → Lambda(nuxt) deploy CloudFormation CodePipeline ServerlessFramework template.yaml AWSTemplateFormatVersion: 2010-09-09 Description: serverless framework deploy pipeline example Parameters: ServiceName: Description: serverless framework deploy pipeline example Type: String Default: serverless-deploy-example Env: Type: String Default: dev AllowedValues: - dev - prod GithubOwner: Type: String Description: The github owner or org name of the repository. GithubRepoName: Type: String Description: The name of the github repository. GithubRepoSecretId: Type: String Default: speed_pizza/GithubRepoAccess Description: The name/ID of the SecretsManager secret that contains the personal access token for the github repo. GithubRepoSecretJSONKey: Type: String Default: OAuthToken Description: The name of the JSON key in the SecretsManager secret that contains the personal access token for the github repo. Mappings: EnvParams: dev: GitBranchName: develop prod: GitBranchName: main Resources: # ビルド成果物を格納するS3バケット ArtifactsBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ServiceName}-artifacts-${Env} LifecycleConfiguration: Rules: - Id: DeleteRule Status: Enabled ExpirationInDays: 7 # CodeBuild CodeBuildProject: Type: AWS::CodeBuild::Project Properties: Name: !Sub ${ServiceName}-${Env} Artifacts: Type: CODEPIPELINE Source: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/standard:3.0 PrivilegedMode: true Type: LINUX_CONTAINER EnvironmentVariables: - Name: DEPLOY_ENV Value: !Sub ${Env} ServiceRole: !GetAtt CodeBuildServiceRole.Arn # CodeBuildのIAMロール CodeBuildServiceRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ServiceName}-CodeBuildServiceRole-${Env} Policies: - PolicyName: !Sub ${ServiceName}-CodeBuild-ServiceRolePolicy-${Env} PolicyDocument: Version: '2012-10-17' Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DeleteLogGroup - logs:DescribeLogGroups Resource: - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}-${Env}:* - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/lambda/* - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group::log-stream:* Effect: Allow - Action: - codebuild:CreateReportGroup - codebuild:CreateReport - codebuild:UpdateReport - codebuild:BatchPutTestCases Resource: - !Sub arn:aws:codebuild:ap-northeast-1:${AWS::AccountId}:project/${ServiceName}-${Env} Effect: Allow - Action: - s3:CreateBucket - s3:DeleteBucket - s3:PutBucket - s3:GetObject - s3:GetObjectVersion - s3:GetBucketAcl - s3:GetBucketLocation - s3:PutObject - s3:ListBucket - s3:SetBucketEncryption - s3:GetEncryptionConfiguration - s3:PutEncryptionConfiguration - s3:PutBucketPolicy - s3:PutBucketCORS - s3:DeleteBucketPolicy Resource: - '*' Effect: Allow - Action: - cloudformation:DescribeStackEvents - cloudformation:DescribeStackResources - cloudformation:DescribeStackResource - cloudformation:DescribeStacks - cloudformation:ValidateTemplate - cloudformation:CreateStack - cloudformation:UpdateStack - cloudformation:DeleteStack - cloudformation:ListStackResources Resource: - '*' Effect: Allow - Action: - iam:CreateRole - iam:DeleteRole - iam:DeleteRolePolicy - iam:PutRolePolicy - iam:GetRole - iam:PassRole Resource: - '*' Effect: Allow - Action: - apigateway:* Resource: - '*' Effect: Allow - Action: - lambda:UpdateFunctionCode - lambda:GetFunction - lambda:GetFunctionConfiguration - lambda:CreateFunction - lambda:DeleteFunction - lambda:ListVersionsByFunction - lambda:PublishVersion - lambda:AddPermission - lambda:UpdateFunctionConfiguration - lambda:CreateAlias - lambda:DeleteAlias - lambda:PutProvisionedConcurrencyConfig - lambda:GetProvisionedConcurrencyConfig - lambda:RemovePermission - lambda:UpdateAlias Resource: - '*' Effect: Allow - Action: - cloudfront:CreateCloudFrontOriginAccessIdentity - cloudfront:DeleteCloudFrontOriginAccessIdentity - cloudfront:GetCloudFrontOriginAccessIdentity - cloudfront:GetCloudFrontOriginAccessIdentityConfig - cloudfront:ListCloudFrontOriginAccessIdentities - cloudfront:UpdateCloudFrontOriginAccessIdentity Resource: - '*' Effect: Allow AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Sid: '' Effect: Allow Principal: Service: codebuild.amazonaws.com Action: sts:AssumeRole # CodePipeline CodePipelineProject: Type: AWS::CodePipeline::Pipeline Properties: Name: !Sub ${ServiceName}-${Env} RoleArn: !GetAtt CodePipelineServiceRole.Arn Stages: - Name: Source Actions: - Name: SourceAction ActionTypeId: Category: Source Owner: ThirdParty Version: 1 Provider: GitHub OutputArtifacts: - Name: SourceArtifact # デプロイもとのCodeCommitのリポジトリとブランチ Configuration: Owner: !Ref GithubOwner Repo: !Ref GithubRepoName OAuthToken: !Join - '' - - 'resolve:secretsmanager:' - !Ref GithubRepoSecretId - 'SecretString:' - !Ref GithubRepoSecretJSONKey Branch: !FindInMap [EnvParams, !Ref 'Env', GitBranchName] PollForSourceChanges: true RunOrder: 1 - Name: Build Actions: - Name: BuildAction InputArtifacts: - Name: SourceArtifact OutputArtifacts: - Name: BuildArtifact ActionTypeId: Category: Build Owner: AWS Version: 1 Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProject RunOrder: 2 ArtifactStore: Type: S3 Location: !Ref ArtifactsBucket # CodePipelineのIAMロール CodePipelineServiceRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ServiceName}-CodePipelineServiceRole-${Env} Policies: - PolicyName: !Sub ${ServiceName}-CodePipelineServiceRolePolicy-${Env} PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject - s3:GetObjectVersion - s3:GetBucketVersioning - s3:PutObject Resource: - arn:aws:s3:::codepipeline* Effect: Allow - Action: - codecommit:CancelUploadArchive - codecommit:GetBranch - codecommit:GetCommit - codecommit:GetUploadArchiveStatus - codecommit:UploadArchive Resource: - '*' Effect: Allow - Action: - codebuild:BatchGetBuilds - codebuild:StartBuild Resource: - '*' Effect: Allow - Action: - codedeploy:CreateDeployment - codedeploy:GetApplication - codedeploy:GetApplicationRevision - codedeploy:GetDeployment - codedeploy:GetDeploymentConfig - codedeploy:RegisterApplicationRevision Resource: - '*' Effect: Allow - Action: - codestar-connections:UseConnection Resource: - '*' Effect: Allow - Action: - s3:* Resource: - '*' Effect: Allow - Action: - cloudfront:CreateCloudFrontOriginAccessIdentity Resource: - '*' Effect: Allow AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - codepipeline.amazonaws.com Action: - sts:AssumeRole buildspec.yaml version: 0.2 phases: install: runtime-versions: nodejs: 12 commands: - cd speed_pizza - npm install - cd $CODEBUILD_SRC_DIR build: commands: - cd speed_pizza - npm run build:${DEPLOY_ENV} - npm run deploy:${DEPLOY_ENV} - cd $CODEBUILD_SRC_DIR serverless.yml service: speed-pizza-${opt:stage} plugins: - serverless-s3-sync - serverless-apigw-binary - serverless-dotenv-plugin package: individually: true excludeDevDependencies: true provider: name: aws lambdaHashingVersion: 20201221 runtime: nodejs12.x stage: ${opt:stage} region: ap-northeast-1 apiKeys: - ${self:custom.apiKey.${self:provider.stage}} custom: ####################################### # Unique ID included in resource names. # Replace it with a random value for every first distribution. # https://www.random.org/strings/?num=1&len=6&digits=on&loweralpha=on&unique=on&format=html&rnd=new stackId: SpeedPizza-${opt:stage} ####################################### env: stg: development prod: production apiKey: stg: UECpdNb9TM2dcBQd2nZi2rXhUYfu9Fks prod: UkuLUDnSZR5eBAnUATchpH6KJGQkNuwE buckets: ASSETS_BUCKET_NAME: ${self:service}-assets STATIC_BUCKET_NAME: ${self:service}-static s3Sync: - bucketName: ${self:custom.buckets.ASSETS_BUCKET_NAME} bucketPrefix: _nuxt/ localDir: .nuxt/dist/client - bucketName: ${self:custom.buckets.STATIC_BUCKET_NAME} localDir: src/static apigwBinary: types: - '*/*' functions: renderer: name: ${self:service}-${self:custom.stackId}-${self:provider.stage}-renderer handler: server/lambda.handler memorySize: 512 timeout: 30 environment: NODE_ENV: ${self:custom.env.${self:provider.stage}} package: include: - .nuxt/** - server/** - node_modules/autoprefixer/** exclude: - .** - .**/* - src/** - test/* - README.md - package.json - package-lock.json - test/* - node_modules/babel**/** - node_modules/caniuse-db/** - node_modules/prettier/** - node_modules/yargs/** - node_modules/xxhashjs/** - node_modules/jschardet/** - node_modules/**/*.md - node_modules/**/bin/** - node_modules/typescript/** events: - http: path: / method: any private: true - http: path: /{proxy+} method: any private: true resources: Resources: ClientAssetsBucket: Type: AWS::S3::Bucket Properties: BucketName: ${self:custom.buckets.ASSETS_BUCKET_NAME} ClientAssetsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: ClientAssetsBucket PolicyDocument: Version: '2012-10-17' Statement: [ { Action: [ 's3:GetObject' ], Effect: 'Allow', Resource: { Fn::Join: [ '', [ 'arn:aws:s3:::', { Ref: 'ClientAssetsBucket' }, '/*' ] ], }, Principal: '*' } ] ClientStaticBucket: Type: AWS::S3::Bucket Properties: BucketName: ${self:custom.buckets.STATIC_BUCKET_NAME} ClientStaticBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: ClientStaticBucket PolicyDocument: Version: '2012-10-17' Statement: [ { Action: [ 's3:GetObject' ], Effect: 'Allow', Resource: { Fn::Join: [ '', [ 'arn:aws:s3:::', { Ref: 'ClientStaticBucket' }, '/*' ] ], }, Principal: '*' }, ] Backend CloudFront → ApiGateway → Lambda(chalice) deploy CloudFormation CodePipeline Chalice pipeline.json { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "ApplicationName": { "Default": "SpeedPizzaApi", "Type": "String", "Description": "Enter the name of your application" }, "CodeBuildImage": { "Default": "aws/codebuild/amazonlinux2-x86_64-standard:3.0", "Type": "String", "Description": "Name of codebuild image to use." }, "GithubOwner": { "Type": "String", "Description": "The github owner or org name of the repository." }, "GithubRepoName": { "Type": "String", "Description": "The name of the github repository." }, "GithubRepoSecretId": { "Type": "String", "Default": "speed_pizza/GithubRepoAccess", "Description": "The name/ID of the SecretsManager secret that contains the personal access token for the github repo." }, "GithubRepoSecretJSONKey": { "Type": "String", "Default": "OAuthToken", "Description": "The name of the JSON key in the SecretsManager secret that contains the personal access token for the github repo." }, "Env": { "Description": "System Environment", "AllowedValues": [ "stg", "prod" ], "Type": "String" } }, "Conditions": { "IsProduction": { "Fn::Equals": [ { "Ref": "Env" }, "prod" ] }, "IsStaging": { "Fn::Equals": [ { "Ref": "Env" }, "stg" ] } }, "Mappings": { "EnvParams": { "stg": { "TableName": "pizza-stg", "OgpBucketName": "speed-pizza-stg", "ApplicationBucketName": "speed-pizza-application-bucket-stg", "GitBranchName": "stg", "ArtifactBucketName": "speed-pizza-artifact-bucket-store-stg", "LambdaRoleName": "SpeedPizzaStg" }, "prod": { "TableName": "pizza", "OgpBucketName": "speed-pizza-prod", "ApplicationBucketName": "speed-pizza-application-bucket-prod", "GitBranchName": "main", "ArtifactBucketName": "speed-pizza-artifact-bucket-store-prod", "LambdaRoleName": "SpeedPizzaProd" } } }, "Resources": { "ApplicationTable": { "Type": "AWS::DynamoDB::Table", "Properties": { "TableName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "TableName" ] }, "AttributeDefinitions": [ { "AttributeName": "id", "AttributeType": "S" }, { "AttributeName": "created_year", "AttributeType": "N" }, { "AttributeName": "created_at", "AttributeType": "S" } ], "KeySchema": [ { "AttributeName": "id", "KeyType": "HASH" } ], "GlobalSecondaryIndexes": [ { "IndexName": "created_at_index", "KeySchema": [ { "AttributeName": "created_year", "KeyType": "HASH" }, { "AttributeName": "created_at", "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "ALL" } } ], "BillingMode": "PAY_PER_REQUEST" } }, "OgpBucket": { "Type": "AWS::S3::Bucket", "Properties": { "BucketName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "OgpBucketName" ] } } }, "ApplicationBucket": { "Type": "AWS::S3::Bucket", "Properties": { "BucketName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "ApplicationBucketName" ] } } }, "CodeBuildRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" ], "Effect": "Allow", "Principal": { "Service": [ { "Fn::Sub": "codebuild.${AWS::URLSuffix}" } ] } } ] } } }, "CodeBuildPolicy": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyName": "CodeBuildPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:PutObject" ], "Resource": "arn:*:s3:::*", "Effect": "Allow" } ] }, "Roles": [ { "Ref": "CodeBuildRole" } ] } }, "AppPackageBuild": { "Type": "AWS::CodeBuild::Project", "Properties": { "Artifacts": { "Type": "CODEPIPELINE" }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", "Image": { "Ref": "CodeBuildImage" }, "Type": "LINUX_CONTAINER", "EnvironmentVariables": [ { "Name": "APP_S3_BUCKET", "Value": { "Ref": "ApplicationBucket" } }, { "Name": "Env", "Type": "PLAINTEXT", "Value": { "Ref": "Env" } }, { "Name": "Arn", "Type": "PLAINTEXT", "Value": { "Fn::GetAtt": [ "LambdaRole", "Arn" ] } } ] }, "Name": { "Fn::Sub": "${ApplicationName}Build" }, "ServiceRole": { "Fn::GetAtt": "CodeBuildRole.Arn" }, "Source": { "Type": "CODEPIPELINE" } } }, "AppPipeline": { "Type": "AWS::CodePipeline::Pipeline", "Properties": { "Name": { "Fn::Sub": "${ApplicationName}Pipeline" }, "ArtifactStore": { "Type": "S3", "Location": { "Ref": "ArtifactBucketStore" } }, "RoleArn": { "Fn::GetAtt": "CodePipelineRole.Arn" }, "Stages": [ { "Name": "Source", "Actions": [ { "Name": "Source", "ActionTypeId": { "Category": "Source", "Owner": "ThirdParty", "Version": "1", "Provider": "GitHub" }, "RunOrder": 1, "OutputArtifacts": [ { "Name": "SourceRepo" } ], "Configuration": { "Owner": { "Ref": "GithubOwner" }, "Repo": { "Ref": "GithubRepoName" }, "OAuthToken": { "Fn::Join": [ "", [ "{{resolve:secretsmanager:", { "Ref": "GithubRepoSecretId" }, ":SecretString:", { "Ref": "GithubRepoSecretJSONKey" }, "}}" ] ] }, "Branch": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "GitBranchName" ] }, "PollForSourceChanges": true } } ] }, { "Name": "Build", "Actions": [ { "InputArtifacts": [ { "Name": "SourceRepo" } ], "Name": "CodeBuild", "ActionTypeId": { "Category": "Build", "Owner": "AWS", "Version": "1", "Provider": "CodeBuild" }, "OutputArtifacts": [ { "Name": "CompiledCFNTemplate" } ], "Configuration": { "ProjectName": { "Ref": "AppPackageBuild" } }, "RunOrder": 1 } ] }, { "Name": "Deploy", "Actions": [ { "ActionTypeId": { "Category": "Deploy", "Owner": "AWS", "Version": "1", "Provider": "CloudFormation" }, "InputArtifacts": [ { "Name": "CompiledCFNTemplate" } ], "Name": "CreateBetaChangeSet", "Configuration": { "ActionMode": "CHANGE_SET_REPLACE", "ChangeSetName": { "Fn::Sub": "${ApplicationName}ChangeSet" }, "RoleArn": { "Fn::GetAtt": "CFNDeployRole.Arn" }, "Capabilities": "CAPABILITY_NAMED_IAM", "StackName": { "Fn::Sub": "${ApplicationName}Deploy" }, "TemplatePath": "CompiledCFNTemplate::transformed.yaml" }, "RunOrder": 1 }, { "RunOrder": 2, "ActionTypeId": { "Category": "Deploy", "Owner": "AWS", "Version": "1", "Provider": "CloudFormation" }, "Configuration": { "StackName": { "Fn::Sub": "${ApplicationName}Deploy" }, "ActionMode": "CHANGE_SET_EXECUTE", "ChangeSetName": { "Fn::Sub": "${ApplicationName}ChangeSet" }, "OutputFileName": "StackOutputs.json" }, "Name": "ExecuteChangeSet", "OutputArtifacts": [ { "Name": "AppDeploymentValues" } ] } ] } ] } }, "ArtifactBucketStore": { "Type": "AWS::S3::Bucket", "Properties": { "BucketName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "ArtifactBucketName" ] }, "VersioningConfiguration": { "Status": "Enabled" } } }, "LambdaRole": { "Type": "AWS::IAM::Role", "Properties": { "RoleName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "LambdaRoleName" ] }, "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" ], "Effect": "Allow", "Principal": { "Service": [ { "Fn::Sub": "lambda.${AWS::URLSuffix}" } ] } } ] }, "Policies": [ { "PolicyName": "DefaultPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:*:logs:*:*:*", "Effect": "Allow" }, { "Effect": "Allow", "Action": [ "dynamodb:List*", "dynamodb:DescribeReservedCapacity*", "dynamodb:DescribeLimits", "dynamodb:DescribeTimeToLive", "dynamodb:CreateTable" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "dynamodb:BatchGet*", "dynamodb:DescribeStream", "dynamodb:DescribeTable", "dynamodb:Get*", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchWrite*", "dynamodb:CreateTable", "dynamodb:Delete*", "dynamodb:Update*", "dynamodb:PutItem" ], "Resource": [ { "Fn::Sub": [ "arn:aws:dynamodb:*:*:table/${TableName}", { "TableName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "TableName" ] } } ] }, { "Fn::Sub": [ "arn:aws:dynamodb:*:*:table/${TableName}/index/*", { "TableName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "TableName" ] } } ] } ] }, { "Effect": "Allow", "Action": [ "s3:ListBucket" ], "Resource": [ { "Fn::Sub": [ "arn:aws:s3:::${OgpBucketName}", { "OgpBucketName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "OgpBucketName" ] } } ] } ] }, { "Effect": "Allow", "Action": "s3:*Object", "Resource": [ { "Fn::Sub": [ "arn:aws:s3:::${OgpBucketName}/*", { "OgpBucketName": { "Fn::FindInMap": [ "EnvParams", { "Ref": "Env" }, "OgpBucketName" ] } } ] } ] } ] } } ] } }, "CodePipelineRole": { "Type": "AWS::IAM::Role", "Properties": { "Policies": [ { "PolicyName": "DefaultPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketVersioning", "s3:CreateBucket", "s3:PutObject", "s3:PutBucketVersioning" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "codecommit:CancelUploadArchive", "codecommit:GetBranch", "codecommit:GetCommit", "codecommit:GetUploadArchiveStatus", "codecommit:UploadArchive" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "cloudwatch:*", "iam:PassRole" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "lambda:InvokeFunction", "lambda:ListFunctions" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "cloudformation:CreateStack", "cloudformation:DeleteStack", "cloudformation:DescribeStacks", "cloudformation:UpdateStack", "cloudformation:CreateChangeSet", "cloudformation:DeleteChangeSet", "cloudformation:DescribeChangeSet", "cloudformation:ExecuteChangeSet", "cloudformation:SetStackPolicy", "cloudformation:ValidateTemplate", "iam:PassRole" ], "Resource": "*", "Effect": "Allow" }, { "Action": [ "codebuild:BatchGetBuilds", "codebuild:StartBuild" ], "Resource": "*", "Effect": "Allow" } ] } } ], "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" ], "Effect": "Allow", "Principal": { "Service": [ { "Fn::Sub": "codepipeline.${AWS::URLSuffix}" } ] } } ] } } }, "CFNDeployRole": { "Type": "AWS::IAM::Role", "Properties": { "Policies": [ { "PolicyName": "DeployAccess", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "*", "Resource": "*", "Effect": "Allow" } ] } } ], "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" ], "Effect": "Allow", "Principal": { "Service": [ { "Fn::Sub": "cloudformation.${AWS::URLSuffix}" } ] } } ] } } } }, "Outputs": { "S3ApplicationBucket": { "Value": { "Ref": "ApplicationBucket" } }, "CodeBuildRoleArn": { "Value": { "Fn::GetAtt": "CodeBuildRole.Arn" } }, "S3PipelineBucket": { "Value": { "Ref": "ArtifactBucketStore" } }, "CodePipelineRoleArn": { "Value": { "Fn::GetAtt": "CodePipelineRole.Arn" } }, "CFNDeployRoleArn": { "Value": { "Fn::GetAtt": "CFNDeployRole.Arn" } } } } buildspec.yaml artifacts: files: - transformed.yaml type: zip phases: build: commands: - cd src/speed_pizza - sed -i -e "s@<ARN>@$Arn@g" .chalice/config.json - chalice package --stage ${Env} /tmp/packaged - cd $CODEBUILD_SRC_DIR - aws cloudformation package --template-file /tmp/packaged/sam.json --s3-bucket ${APP_S3_BUCKET} --output-template-file transformed.yaml install: commands: - cd src/speed_pizza - pip install -r requirements.txt - cd $CODEBUILD_SRC_DIR runtime-versions: python: '3.7' version: '0.2' config.json { "version": "2.0", "app_name": "speed_pizza", "stages": { "prod": { "api_gateway_stage": "api", "manage_iam_role": false, "iam_role_arn": "<ARN>", "lambda_memory_size": 512, "lambda_timeout": 900, "environment_variables": { "DYNAMODB_TABLE": "pizza", "S3_BUCKET_NAME": "speed-pizza-prod", "LOG_LEVEL": "ERROR", "LOCAL": "false", "CLOUD_FRONT_URL": "https://s-pizza.ninja/" } }, "stg": { "api_gateway_stage": "api", "manage_iam_role": false, "iam_role_arn": "<ARN>", "lambda_memory_size": 512, "lambda_timeout": 900, "environment_variables": { "DYNAMODB_TABLE": "pizza-stg", "S3_BUCKET_NAME": "speed-pizza-stg", "LOG_LEVEL": "DEBUG", "LOCAL": "false", "CLOUD_FRONT_URL": "https://stg.s-pizza.ninja/" } }, "dev": { "api_gateway_stage": "dev", "environment_variables": { "DYNAMODB_TABLE": "pizza", "S3_BUCKET_NAME": "minio-s-pizza-dev", "LOG_LEVEL": "DEBUG", "LOCAL": "true" } } } } Frontend(Static) /data/* - 3d models /_nuxt/* - static nuxt source and image and css /ogp/* - ogp images
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

40代おっさんIAMを深堀して勉強してみた

本記事について 本記事はAWS初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。 もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。 ポリシーをJSON形式で記述 *IAMのことをサラッと知りたい方は↓を https://qiita.com/kou551121/items/5adf2241f0e106e18e50 { "Version": "2012-10-17", "Statement": [ { "Sid": "ListBucketRstIP", "Effect": "Allow", "Principal": "*", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::sample-bucket", "Condition": { "StringEquals": { "aws:SourceIP": "12.34.56.78" } } } ] } こちらがJSON形式のドキュメントになりますがわからないですよね・・・ 詳しく細分化してみたいと思います。 "Version" こちらはバージョン情報になります。 "Statement" 大事になるのがStatementの中の情報になります。 こちらも細分化して説明します。 "Sid" IDになり名前のようなもの(省略もできる) "Effect" 許可するポリシーだったら"Allow" 拒否する(無効にする場合は)"Deny" "Principal" プリンシパルはリソースにアクセスする情報を記載します上の*はすべてのアカウント対しての記述になります。 そのほかに "Principal":{"AWS":"arn:aws:iam::123456789012:root"} これで特定のアカウントを指定 "Principal":"AWS":"arn:aws:iam::123456789012:user/username" これで特定のIAMユーザーを指定 "Principal":{"Federated":"www.amazon.com"} "Principal":{"Federated":"graph.facebook.com"} これでフェデレーティッドウェブ ID ユーザーを指定 "Principal":{"Service":"ec2.amazonaws.com"} これでEC2を指定 "Action" ActionはあらかじめAWS決められた形式で何のサービスでどのような操作かを指定 ListBucketはバケットの中身をList(lsやdir)するアクション そのほかに "Action":"ec2:StartInstances" ec2のインスタンスをスタートするアクション "Action":"iam:ChangePassword" IAMユーザーのパスワードを変更するアクション "Action":"s3:GetObject" S3のオブジェクトを取得するアクション "Action":["sqs:SendMessage","sqs:ReceiveMessage"] [,]カンマ区切りで複数のアクションを指定できる "Action":"iam: *AccessKey* " アクションの一部に*(ワイルドカード)を入れることもできる "Resource" どのリソースに対してのポリシーかを指定します AWSでリソースを作成すると arn と言う固有の文字列が割り振られます。 上だとリソースにs3のsample-bucket指定していることになります。 そのほかに "Resource": ["arn:aws:dynamodb:us-west-2:123456789012:table/books_table", "arn:aws:dynamodb:us-west-2:123456789012:table/magazines_table"] 上のように[,]カンマ区切りで複数指定できることできます。 "Resource": "arn:aws:ec2:us-east-1:123456789012:instance/*" こちらだと123456789012アカウントのus-east-1リージョン内のec2インスタンスすべてと指定しています。 "Condition" こちらはIPアドレスの接続元を制限したり、ポリシーの有効期限(何時から何時まで有効など) "Condition" : { "DateGreaterThan" : {"aws:CurrentTime" : "2015-10-08T12:00:00Z"}, "DateLessThan" : {"aws:CurrentTime" : "2015-10-08T15:00:00Z" }, "InAddress" : {"aws:SourceIp" : ["192.0.2.0/24", "203.0.113.0/24"]} 上のような場合 縦はAND条件 [,]カンマ区切りはOR条件になります その他に NotPrincipal NotAction NotResource とNotがあり、意味は指定した物以外ある アイデンティティベースのポリシーについて IAMユーザーや、IAMロールなどのなどの認証主体に付与するポリシー ↓アイデンティティベースのポリシー記述例 { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "ec2:*", "Resource": "*" } ] } アイデンティティベースのポリシーでは基本、Principalは書きません なぜならポリシーをアタッチする対象が明確だから リソースベースのポリシーについて 上とは逆に操作される側であり、Amazon S3やAmazon SNSなどのAWSリソース側にアタッチするポリシー 最後に またこの記事は AWS 初学者を導く体系的な動画学習サービス「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ソートキーのあるDynamoDBのテーブルにCSVファイルを一括アップロードする方法

したかったこと DynamoDBに一括でCSVファイルの内容をアップロードしたい テーブルにはソートキーを設定したい プライマリキーだけの場合の記事はいっぱいあったが、ソートキーのあるものはみなかった。 方法 CloudFormationに「CSVをDynamoDBに入れる」スタックを作成 以下の一括アップロードの方法をベースにして、テンプレートファイルの中身だけ少し変える。 一括アップロードの方法はここが参考になった。 ソートキーのあるテーブルの作成方法はここが参考になった テンプレートファイル テンプレートファイルにソートキーの情報を足す。 データ型はStringなら "S" にする。 "Resources": { "DynamoDBTable":{ "Type": "AWS::DynamoDB::Table", "Properties":{ "TableName": {"Ref" : "DynamoDBTableName"}, "BillingMode": "PAY_PER_REQUEST", "AttributeDefinitions":[ { "AttributeName": "【パーティションキー名】", "AttributeType": "【データ型】" }, { "AttributeName": "【ソートキー名】", "AttributeType": "【データ型】" } ], "KeySchema":[ { "AttributeName": "【パーティションキー名】", "KeyType": "HASH" }, { "AttributeName": "【ソートキー名】", "KeyType": "RANGE" } ], "Tags":[ { "Key": "Name", "Value": {"Ref" : "DynamoDBTableName"} } ] } }, 備考 bucket already existエラーが出た -> 一意でなければならないよう スタックを削除して、一意なバケット名を入れて、もう一度作り直した。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails6] Heroku上でCarrierwave(Rmagick) + fogを使いAWS S3にファイルをアップロードする

最初に HerokuでRailサイトを作る時ストレージを別途用意しなければなりません。 Herokuでは時間が立つとアップロードした画像ファイルなどが消えてしまうので 今回は対応策としてAWS S3を使います。 S3とAWSのアカウントは作成した前提ですのでまだ済んでいない方は以下を参照ください S3の設定 AWSアカウントの作成方法 環境 Ruby 2.6.6 Rails 6.0.3.6 AWS S3の設定済 Rmagick設定済 Gem Gemは以下を使います gem "rmagick" gem "carrierwave" gem "fog-aws" モデル作成 画像をアップロードするモデルを作ります。 今回はユーザーに持たせるプロフィール画像を想定して作ります。 $ rails g model User name:string image:string $ rails db:migrate Uploaderの設定 Uploaderクラスを作成します。 (Imageの所は好きに置き換えてください) rails g uploader Image 作成されたらimage_uploder.rbに以下を追加します。 app/uploaders/image_uploader.rb include CarrierWave::RMagick if Rails.env.production? storage :fog        # 本番時にS3にファイルを保存する else storage :file # 開発・テスト時にはローカルにファイルを保存する end モデルとImageUploaderを関連付けるためにモデルに以下を追加します app/models/user.rb class User < ApplicationRecord mount_uploader :image, ImageUploader end CarrierWaveの設定 Herokuで画像の保存先をAmazon S3に保存できるように設定する config/initializers/carrierwave.rb require 'carrierwave/storage/abstract' require 'carrierwave/storage/file' require 'carrierwave/storage/fog' CarrierWave.configure do |config| if Rails.env.production? config.fog_provider = 'fog/aws' config.fog_credentials = { provider: 'AWS', aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], #awsのIAMのアクセスキー aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], #awsのIAMのシークレットアクセスキー region: 'ap-northeast-1' #バケットの作成で設定した地域(東京で設定した場合は左と一緒) } config.fog_directory = "ENV['AWS_BUCKET_NAME']" #バケット名 config.cache_storage = :fog # 本番時はS3にファイルを保存する else config.storage = :file # 開発・テスト時はローカルにファイルを保存する end end Herokuへの環境変数登録 $ heroku config:set AWS_ACCESS_KEY_ID="IAMのAccess key IDを入力" $ heroku config:set AWS_SECRET_ACCESS_KEY="IAMのSecret access keyを入力" $ heroku config:set AWS_S3_BUCKET="S3のバケット名を入力" Herokuの環境変数の確認方法 $ heroku config 以上でHerokuにデプロイ後、画像を投稿してS3にバケット保存できました。 これで反映されない時はIAMのアクセスキーを再度発行して改めて環境変数を設定すると上手くいく場合もあるようです。 また今回は設定に1日中かかり、かなり試行錯誤して上手く実装することができました。 たくさん記事を見ましたので上手くいかない方は私が参照した記事も合わせて確認していただければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon SNS の料金

Amazon SNS の料金 通常の使い方ではそれほど大きくならないところなので気にしないことも多いかもしれませんが、特に FIFO の料金、これを読んで理解できます? 僕はできませんでした。 共通の料金 具体的な料金は、すべて東京リージョンの2021年3月現在ののものです。 Publish API リクエスト : 後述 Publish 以外の API リクエスト : 100 万リクエストあたり 0.50 USD 配信 : 配信先の種別による。(ここではこの部分には触れません) Publish の料金 標準トピック 100 万リクエストあたり 0.50 USD ペイロードが 64 KB を超える場合、64 KB ごとに 1 リクエストとしてカウントされる。 Subscriber の数は関係ない。 Publish 以外の API リクエストも含む最初の 100 万リクエストは無料。 FIFO トピック FIFO トピックの場合は、Publish のリクエスト数だけでなく、そのトピックに対する Subscriber の数やペイロードデータ量に応じて加算した金額になります。Publish リクエスト自体の料金が標準トピックより安く見えますが、ペイロードデータのサイズや Subscriber の数に応じて高くつく計算。 100 万リクエストあたり 0.39 USD + (0.013 USD × Subscription 数) ペイロードが 64 KB を超える場合でも、1 リクエストとしてカウントする。 メッセージのペイロードデータ 1 GB あたり 0.0221 USD + (0.0013 USD × Subscription 数) ペイロードデータのサイズは純粋に Publish した本文のサイズのみで、ヘッダ等は含まない。 Subscriber がフィルタリングポリシーを設定して受信するメッセージを絞っても、すべてのペイロードが課金対象となる。 FIFO トピックへの Publish リクエストは、無料枠対象外。 例 100 万回 Publish した場合の比較です。 1 メッセージサイズ Subscription 数 標準トピックの場合 FIFO トピックの場合 1 KB 1 0.50 USD 0.43 USD 1 KB 4 0.50 USD 0.47 USD 64 KB 1 0.50 USD 1.90 USD 64 KB 4 0.50 USD 2.19 USD 256 KB 1 2.00 USD 6.39 USD 256 KB 4 2.00 USD 7.43 USD ※この他に、配信先によって配信料金およびデータ転送料金がかかります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudWatch ログの監視

目的 ログの監視をCloudWatchで設定 EC2にインストールされたApacheのアクセスログをCloudWatchログに送信し、確認まで行います。 Apache(アパッチ) →HTTPリクエストを受け取ったら何かしらのレスポンスを返すソフトウェアのこと 注意 EC2を立ち上げた時点でCPU使用率やネットワーク入出力など、基本的なメトリクス項目など値の変化のグラフはデフォルトでCloudWatchに送られているが、ログ監視の方はユーザーが設定する必要があります。 CloudWatchエージェント CloudWatchエージェントをEC2にインストールする EC2にIAMロールをアタッチする 適切なネットワークルートを設定する(パブリックサブネット) ※プライベートサブネットはVPCエンドポイントを設定する必要あり 実装 準備 EC2インスタンス(Test-EC2)を起動、Apacheをインストールした状態まで進め、Test-EC2にec2-userでssh接続(ログイン)します CloudWatch Logs インストールコマンド sudo yum install awslogs インストールが完了したら設定ファイル(awscli.conf、awslogs.conf)を開く cd /etc/awslogs/ sudo vi awscli.conf # regionをap-northeast-1に変更し更新(esc → :wq) sudo vi awslogs.conf 以下を[/var/log/messages]のlog_group_nameの下に貼り付けし更新 [HttpAccessLog] file = /var/log/httpd/access_log log_group_name = HttpAccessLog log_stream_name = {instance_id} datetime_format = %b %d %H:%M:%S [HttpErrorLog] file = /var/log/httpd/error_log log_group_name = HttpErrorLog log_stream_name = {instance_id} datetime_format = %b %d %H:%M:%S ※awslogs.confの簡単な説明 この設定ファイルはCloudWatch Logs Agentによって設定されています。 どのようなログをどのようにCloudWatchに送るか設定されています。 このファイルを修正する事でさまざまな変更ができる。 変更した際はCloudWatch Logs Agentを再起動する必要がある。 ドキュメントのリンク、Agentコマンドの説明 [ラベル(名前)] file = どのファイルをCloudWatch Logsに送りつけるか指定 log_group_name = ロググループの名前 log_stream_name = {instance_idという変数を使用してどのEC2のログかラベルをつける} datetime_format = 日時をどのように出力するか buffer_duration = 送りつける間隔(5000=500秒) initial_position = start_of_file (ログファイルの上から読み込んでいく設定、下からも設定できる) # EC2インスタンスが再起動しても自動的にawslogsdが立ち上がる設定 sudo systemctl enable awslogsd # 起動 sudo systemctl start awslogsd 補足 以下をEC2のユーザーデータに設定することでEC2作成時に自動でCloudWatch Logsにログ送信が可能となります。 #!/bin/bash yum -y update yum -y install httpd php systemctl enable httpd.service systemctl start httpd.service mkdir /var/awslogs mkdir /var/awslogs/state yum -y install awslogs cat > /etc/awslogs/awslogs.conf <<EOF [general] state_file = /var/awslogs/state/agent-state [HttpAccessLog] file = /var/log/httpd/access_log log_group_name = HttpAccessLog log_stream_name = {instance_id} datetime_format = %b %d %H:%M:%S [HttpErrorLog] file = /var/log/httpd/error_log log_group_name = HttpErrorLog log_stream_name = {instance_id} datetime_format = %b %d %H:%M:%S EOF REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -n 's/.$//p') sed -i "s/us-east-1/$REGION/g" /etc/awslogs/awscli.conf systemctl enable awslogsd systemctl start awslogsd IAMポリシーをアタッチ 先にIAM<IAM ロール作成 1、一般的なユースケースの選択(EC2) 2、ポリシーを検索(CloudWatchAgentServerPolicy)してチェックを入れる 3、タグは必要に応じて付与(今回はなし) 4、ロール名(CloudWatchAgentServerPolicy)、説明も同じ → 作成 EC2<インスタンス<インスタンスを選択し、右クリック<セキュリティ<IAMロールを変更を選択 先ほど作成したCloudWatchAgentServerPolicyに変更して保存する ※awslogsdがスタートするタイミングでIAMロールがついていないとログが送られない可能性があるので、awslogsdがスタートした後にIAMロールを設定した順番なら一旦再起動すると正常に送られる。 ログを実際に確認 CloudWatch<ログ<ロググループ /var/log/messages、HttpAccessLog、HttpErrorLogそれぞれ出力されている事を確認できます。 中身を確認すると、ログストリームがinstance_id(変数)で保存されてます。 更に開くとシステムログが確認できます。 参考 この記事はAWS初学者を導く体系的な動画学習サービス 「AWS CloudTech」の課題カリキュラムで作成しました。 https://aws-cloud-tech.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAA合格体験記(知識ゼロからの学び方)

きっかけ 新卒1年目3月頃、インフラ実務未経験でしたが、徐々に案件の中でAWSに触ることが増えてきて、AWSの知識を横断的に学びたいと思ったので、AWS認定ソリューションアーキテクトアソシエイトを受けることにしました。 知識ゼロから合格するまでに行ったことを体験記として記して行きますー。 勉強し始めから合格までの概要 筆者のレベル 理系出身新卒1年目AWSは案件で少し触った程度で勉強したことはない。 2020年2月に勉強を始める(週に5時間程度) 1. 基礎を学ぶ 2. SAAの参考書読む 3. 問題ひたすら解く 2021年4月に合格 具体的にやったこと 基礎を学ぶ AWSはSAAより難易度の低いクラウドプラクティショナーという資格があり、今回はその試験を飛ばして、 SAAを受けるため、基礎を学ぶために最初にクラウドプラクティショナーの参考書を読むことにしました。 その参考書がこちら SAAの参考書読む 問題ひたすら解く こちらのゴールドプラン
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Route53でDDNSみたいなことをする(ための準備)

IAMでRoute53レコード更新用のグループとユーザを作成 グループの作成(説明は最小) ポリシーは「AmazonRoute53AutoNamingRegistrantAccess」を選択。多分これが一番権限が少ないと思います。 最後に確認画面でグループを作成。(このSSではポリシーは設定されていません) ユーザの作成 先程作成したグループを割り当て タグは自由に。 忘れないようにアクセスキーとシークレットキーが記載されているcsvをダウンロードしておきましょう。 オンプレLinux上での操作(今回はubuntu) AWSユーザの登録 AWSCLIとJQがインストールされていること。 ここでアクセスキーとシークレットキーを使ってユーザを作成。 $ aws configure --profile route53ddns AWS Access Key ID [None]: ACCESS_KEY AWS Secret Access Key [None]: SECRET_KEY Default region name [None]: #入力無し Default output format [None]: #入力無し $ aws configure list --profile route53ddns Name Value Type Location ---- ----- ---- -------- profile route53ddns manual --profile access_key ******************** shared-credentials-file secret_key ******************** shared-credentials-file region <not set> None None IP更新用JSONのテンプレートを作成 "//"はJSON上ではコメントにならないので削除してね☆ { "Changes": [ { // 更新なのでUPSERT "Action":"UPSERT", "ResourceRecordSet": { // 更新したいレコードの設定(今回はAレコードなので以下) "Name":"{%HOST%}.example.net", "Type":"A", "TTL":300, "ResourceRecords": [ { // 取得をどこから行うかによるが、 // 今回は取得したJSONにダブルクォーテーションがついているのでこっちはつけない。 "Value":{%IP%} } ] } } ] } グローバルIPを取得してファイルに保存 httpbin.org/ipからjson形式で取得可能。 取得出来るならどこから取得してもヨシ $ curl httpbin.org/ip > globalip.json $ cat globalip.json { "origin": "MY_GLOBAL_IP" } jqで抽出して変数にセット。 $ test=$(jq ".origin" globalip.json) sedで作っていたテンプレートの値を置き換えて、別ファイルに出力。 sed -e "s/{%IP%}/${test}/g;s/{%HOST%}/test/g" dyndns.tmpl > update.json ファイルを指定して更新を実行 $ aws route53 change-resource-record-sets --profile route53ddns --hosted-zone-id HOST_ZONE_ID --change-batch file:///UPDATE_JSON_LOCAL_PATH { "ChangeInfo": { "Id": "/change/*********************", "Status": "PENDING", "SubmittedAt": "2021-04-15T02:54:55.544Z" } } $ Route53のコンソールで対象にしたレコードの値が更新されていれば成功。 これをcronなりを使って自動化すれば多分出来る。たぶん。(まだやってない) 主に参考にさせていただいた記事:Route53でダイナミックDNS
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS DocumentDBのステータスを通知するLambda関数

タイトル通りのLambda関数を作ろうと思いましたがPythonだとrequestsモジュール等をレイヤーにして 読み込まないといけないとか色々面倒に感じたのでボツに。 (結局のところ、Rubyで書きました、aws-sdk読み込むだけで特に面倒な手順はないので・・・) 自分の思い出としてこちらに残します。 ※動作確認はしていないので、参考程度にお願いします。 ※ご指摘、改善点あればコメントください。 仕様 大雑把に説明するとDocumentDBクラスターとDocumentDBクラスターに紐づくDocumentDBインスタンスのステータスをチェックし、「available」以外のステータスのものがあればメールを送信します。 事前準備 本筋ではないので割愛します。 Lambda関数の作成 Lambda関数のロールにポリシー追加(AmazonDocDBReadOnlyAccess, AmazonSNSFullAccess) requestsモジュールを動作させるためにレイヤーを作る(こちらの方の記事が参考になります) Amazon SNSのトピック作成 Amazon SNSのトピックにサブスクリプション追加(メールの送信先) 今時メールじゃなくてもSlackやTeams連携の方が利便性は高いかもしれませんね。 実際のソース lambda_function.py # -*- coding: utf-8 -*- import os import boto3 import requests import logging # Lambda関数の環境変数に設定した値を取得 # AWS SNSトピックのARN(メール送信先) TOPIC_ARN = os.environ['TOPIC_ARN'] # DocumentDBクラスター識別子(ステータス取得対象のクラスターを指定) DB_CLUSTER_IDENTIFIER = os.environ['DB_CLUSTER_IDENTIFIER'] def lambda_handler(event, context): # ロガーの設定 logger = logging.getLogger() logger.setLevel(logging.INFO) # DocumentDBのクライアント docdb_client = boto3.client('docdb') # AWS SNSのクライアント sns_client = boto3.client('sns') # ステータスの結果保存のための配列 db_statuses = [] try: logger.info('Start >>> get DocumentDB status.') # dbクラスターの情報取得 cluster_info = docdb_client.describe_db_clusters(DBClusterIdentifier=DB_CLUSTER_IDENTIFIER) cluster_status = cluster_info['DBClusters'][0]['Status'] db_statuses.append( { DB_CLUSTER_IDENTIFIER : cluster_status } ) instances = cluster_info['DBClusters'][0]['DBClusterMembers'] for instance in instances: instance_id = instance['DBInstanceIdentifier'] instance_info = docdb_client.describe_db_instances(DBInstanceIdentifier=instance_id) status = instance_info['DBInstances'][0]['DBInstanceStatus'] db_statuses.append( { instance_id : status } ) # 1件でも'available'以外の場合、通知処理実行 # ※'available'以外にも通知しないステータスを追加する場合は、in以降の配列にステータスの文字列を追加する is_notify = not all(list(i.values())[0] in ['available'] for i in db_statuses) if is_notify: # 通知処理の実行 # メールに記載する内容を作成 subject = '【AWS DocumentDB】An instance with an abnormal status has been detected.' message = '' for status_info in db_statuses: key = list(status_info.keys())[0] value = status_info[key] message += f'{key}: {value}\n' # メール送信 sns_client.publish( TopicArn = TOPIC_ARN, Subject = subject, Message = message, ) logger.info('DocumentDB status list↓') logger.info(message) logger.info('Completed successfully.') except Exception as e: logger.error(e) finally: logger.info('End >>> get DocumentDB status.') ※作成したレイヤーの追加は忘れずに! あとはCloudWatch Eventsにルール追加 例えばcron式に「*/10 * * * ? *」を設定することで10分毎にDocumentDBのステータスをチェックします。 もし異常があればメールが飛んでくるはずです。 「available」以外という条件では、定期メンテナンスの場合もメールが飛んでくることがあると思うので 定期メンテナンスの場合の「maintenance」も足して is_notify = not all(list(i.values())[0] in ['available', 'maintenance'] for i in db_statuses) とするのもいいかもしれません。 ターゲットとして、監視対象のクラスター識別子を渡してあげるようにすれば、Lambda関数内の引数eventで参照することができるのでLambda関数はそのままにルールを追加して環境毎に監視することも可能です。 参考 Amazon DocumentDB インスタンスのステータスのモニタリング Boto3/Docs/Available services/DocDB Boto3/Docs/Available services/SNS
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Inspector とは

勉強前イメージ Inspector : 監査人 監査のチェック? 調査 AWS Inspector とは EC2インスタンスの脆弱性の診断を自動的に行なってくれるサービスになります。 脆弱性の診断とはサイバー攻撃でよく使われるような手法のパケットなど送信し、セキュリティレベルを判定することです。 こちらを使うことで、実際に現状使用しているEC2インスタンスのセキュリティレベルを確認することが出来ます。 使用できるリージョン・OS ※2021/04現在になります。 詳細は Amazon Inspector でサポートされているオペレーティングシステムとリージョン をごらんください 使用できるリージョンは以下で、 米国東部 (オハイオ) us-east-2 米国東部(バージニア北部) us-east-1 米国西部 (北カリフォルニア) us-west-1 米国西部 (オレゴン) us-west-2 アジアパシフィック (ムンバイ) ap-south-1 アジアパシフィック (ソウル) ap-northeast-2 アジアパシフィック (シドニー) ap-southeast-2 アジアパシフィック (東京) ap-northeast-1 欧州 (フランクフルト) eu-central-1 欧州 (アイルランド) eu-west-1 欧州 (ロンドン) eu-west-2 欧州 (ストックホルム) eu-north-1 AWS GovCloud (米国東部) gov-us-east-1 AWS GovCloud (US-West) gov-us-east-2 使用できる主要OSは以下になります Amazon Linux 2 Ubuntu (20.4 LTS、18.04 LTS、16.04 LTS、14.04 LTS) Debian (10.x、9.0~9.5、8.0~8.7) Red Hat Enterprise Linux (8.0x、7.2~7.x、6.2~6.9) CentOS (7.2 ~ 7.x、6.2 ~ 6.9) 基本的なリージョンやOSは使用できるので、対応していなくて困るといったことはあまりないのではないかと思います。 メリット アプリケーションのセキュリティの問題点を識別 アプリケーションのデプロイ前とデプロイ後のセキュリティチェックを行い、対処することで アプリケーションに対するセキュリティを強化出来ます セキュリティを DEVOPS に統合 既存のDevOpsプロセスに評価を組み込むことで脆弱性の評価を自動化出来ます AWS のセキュリティについての専門知識を活用する 評価とルールのナレッジ更新を継続的に行っており それに関してサービスの形で活用でき、また適応するまでのプロセスを簡略化出来ます 勉強後イメージ EC2インスタンス単体の脆弱性が見れるって感じかな。 雰囲気わかるけど一回試してみたい、どうやって出るのか。 参考 Amazon Inspector 【Amazon Inspector とは?】初心者にもわかりやすく解説 AWS再入門ブログリレー Amazon Inspector編
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

APIGatewayでカスタムドメイン利用時に繋がらない問題で同じ轍を踏んだのでメモしておく

あ〜もう。むっちゃやることたくさんあるのにつまんないことでハマったのでメモしておきます。これ絶対また同じ轍を踏むので。 現象 APIGatewayでカスタムドメイン利用時、何度設定を見直しても正しく繋がっているはずなのにAPI叩くと 403 Forbiddenが返ってくる。しかも認証もしていないAPIなのにMissing Authentication Tokenってなんだよ・・・ どのAPI叩いても403ですよ。。。とほほ。 原因 調べてみるとDevelopers.ioの2015年!の記事にあたりました。 (本来は入力必須ではありませんが、後述の理由から必ず入力してください) もうClassmethodさんには足向けて寝ません。 API Gatewayの独自ドメイン設定で、ベースパスマッピングを指定しないとAPIに繋がらないというバグ仕様でした 上記赤丸で囲った箇所を省略すると403が返ってきますorz ってかこれ2015年からずっとあるからもう仕様だよね。(オプション)って書いてあるけど必須項目だよね・・・ ってなわけで、ここには値を設定してください。絶対に!! 設定場所 最近またコンソールの画面が変わったので迷える子羊ちゃんたちのためにも今現在(2021年4月15日現在)のスクショで設定場所を貼っておきます。 APIGateway→カスタムドメイン APIマッピングタブを押す APIマッピングを設定 パス(オプション)欄に値を設定しましょう。 この手順で設定を行い、APIのデプロイを忘れずに実行すると https://customdomain/パス(オプション欄に設定した値)/apiリソース でアクセスできます。 昔リリースしたシステムの設定を見てみたらちゃんと設定してあったので多分数年前の自分も同じ轍を踏んでいたと思います。 仲間募集! 株式会社ONE WEDGEでは元気なエンジニア募集中です!一緒に「おもしろい」を作りましょう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む