20210910のAWSに関する記事は18件です。

Amazon CloudWatch LogsのデータをS3にExportする時にハマった

はじめに AWSのログサービスである「Amazon CloudWatch Logs」内のテキストログをダウンロードするためにS3にエクスポートしようとした際に、しょーもないことでハマったので共有します。 TL;DR Exportするログの期間をちゃんと指定しよう。 ハマったこと CloudWatch Logsのコンソールから Export data to Amazon S3 を選択すると上記のような画面に飛び、ここでログのExportの設定ができる。各設定項目は以下の通り 項目 内容 Stream prefix ExportするLog stream名 S3 bucket name Export先のS3のバケット名 S3 bucket prefix Export先のS3のルートからのパス(実際にはただのprefix) これらの項目を設定してExport先のS3バケットを確認してみると、 aws-logs-write-testというファイルが増えているだけで、肝心のログデータが見つかりません。 原因 先にも述べましたが、Exportするログの期間をデフォルトのままにしていたことが原因でした。上図で言うと Define data to Amazonのセクションの一番上の項目です。 気づいてみれば「なんだそんなことかww」という感じですが、自分はこれに気づくのに10分くらいかかりました。一番上にあるのに気づいかないなんて不思議なものですね。自分がアホなだけかもしれませんが。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

cloudwatch agent と logs の違い

勉強前イメージ agentはEC2にインストールしてとるやつ logsはただ単にログ監視?それともagentからとってくる値??? 調査 cloudwatch agent とは cloudwatchではCPUなど見れますが、 メモリやディスク容量などは見ることが出来ません。 その際に使用されるのが、clodwatch agentになります。 こちらはエージェントをEC2インスタンスにインストールし、データを取得します。 cloudwatch logs とは EC2やCloudTrail、Route53などから ログファイルをモニタリングし、保存することが出来ます。 cloudwatch logsで使用中のサービスの各ログを一元管理することが出来ます。 また、ダッシュボードでのログデータのし可視化も出来ます。 勉強後イメージ 詳細まで見てないし、表面上しか見てないけど agent → サーバ内に入って詳細を取得 logs → サービス全体からログを収集 って感じがする。 これ見てて、cloudwatch の標準・詳細・カスタムがあやふやになってきた・・・ 今度確認する 参考 【初心者向け】Amazon CloudWatch Logs とは
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Data WranglerをAWS Access keyとSecret Access Keyを使う方法

AWS Data WranglerでAWS アクセスキーとシークレットアクセスキーを使う方法が見つからなかったので、コード見てみました。 s3.read_parquet() や athena.read_sql_query() など、だいたいのメソッドのには boto3.Session を引数で渡せます。 def read_sql_query( # ----省略 ---- boto3_session: Optional[boto3.Session] = None, # ----省略 ---- ) -> Union[pd.DataFrame, Iterator[pd.DataFrame]]: 引用元 : https://github.com/awslabs/aws-data-wrangler/blob/2.11.0/awswrangler/athena/_read.py#L607 例えば athena.read_sql_query() で言えば以下のように書けばAWS Access KeyとAWS Secret Access Key使ってAWS Data Wranglerを使えます。 import awswrangler as wr from boto3.session import Session # AWS認証設定 ACCESS_KEY = "Axxxxxxx" SECRET_ACCESS_KEY = "xxxxxxx" AWS_REGION = "ap-northeast-1" # boto3.Session取得 session = Session( aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_ACCESS_KEY, region_name=AWS_REGION, ) # クエリ情報 db_name = "my_db" table_name = "my_table" sql = f""" SELECT * FROM {table_name} WHERE year = '2021' AND month = '9' AND day = '1'; """ # AWSへリクエスト df = wr.athena.read_sql_query( sql = sql, database=db_name, boto3_session=session, )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ServerlessFrameworkを触ってみた

ServerlessFrameworkのインストールから基本的な設定・操作方法を確認していきたいと思います。 今回はAWSをプロバイダとしてPython3でサービスを作成します。 ■ インストール # Serverless Frameworkのインストール node.jsのインストールはnvmで行います。 # nvm インストール # https://github.com/nvm-sh/nvm#installing-and-updating curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash # 最新のltsをインストールしてグローバルに設定 nvm install --lts nvm use --lts # インストールされているか確認 node -v npm --version # serverless frameworkのインストール sudo npm install -g serverless sls --version # dockerのインストール Pythonの外部ライブラリを利用する場合に必要になるのでインストールしておきます。 Amazon ECS における Docker の基本 - Dockerのインストール | aws # Pythonの外部ライブラリをパッケージングするときに必要になる sudo amazon-linux-extras install docker sudo systemctl enable docker.service sudo systemctl start docker.service # ec2-userをdockerグループに追加してsudoなしでdockerを操作できるようにする sudo usermod -a -G docker ec2-user # 一度ログアウトして再ログイン # プロバイダアカウントのセットアップ AWSのコンソールからServerlessFramework用のIAMユーザーを発行します。 一応何でもできるように AdministratorAccess ポリシーをつけておきます。 ■ 基本的な操作 # プロジェクトの作成 # --template: AWSをプロバイダとしてPython3でプロジェクトを作成する場合は aws-python3 を指定 # --name: 命名規則は ^[a-zA-Z][0-9a-zA-Z-]+$ # --path: プロジェクトを作成するパスを指定します。 sls create --template aws-python3 --name translator --path translator # ローカルでのファンクションの実行 デプロイ前の関数をローカルで実行します。 # --function <FUNCTION_NAME>: 実行する関数名を指定します。 # -p <EVENT_FILE>: ファンクション実行時に引数にわたるevent(json形式)を指定することができます。 sls invoke local --function hello -p event.json # デプロイ # --stage <STAGE_NAME>: servers.ymlのprovider.stageをデプロイ時に指定することができます。(default=dev) # --region <REGION>: servers.ymlのprovider.regionをデプロイ時に指定することができます。 sls deploy --stage prod --region ap-northeast-1 # ファンクション単位でデプロイしたい場合 sls deploy function -f <yourfunction> # デプロイした関数をターミナルから実行 デプロイした関数をターミナルから実行します。 # --function <FUNCTION_NAME>: 実行する関数名を指定します # -p <EVENT_FILE>: ファンクション実行時に引数にわたるevent(json形式)を指定することができます sls invoke --function hello -p event.json # ログ 指定した関数のログを閲覧します。 # --function <FUNCTION_NAME>: 対象の関数名を指定します # -t: ログをtailします sls logs --function hello # Github上のサービスをローカルにインポート # ふつうにgit cloneしてもOK sls install -u <GITHUB URL OF SERVICE> cd <PROJECT> npm install # プラグインのインストール sls plugin install -n <PLUGIN_NAME> # サービスの削除 sls remove -v ■ Pythonの外部ライブラリを利用したい場合 serverless-python-requirements プラグインを利用します。 Serverless Python Requirements | Serverless # serverless-python-requirements のインストール # インストール sls plugin install -n serverless-python-requirements インストールしたら下記設定を追記します。 serverless.yml plugins: - serverless-python-requirements custom: PythonRequirements: # deploy時のパッケージングの際にpythonライブラリのビルドをdockerコンテナ上で行う設定です。 dockerizePip: true # venvのセットアップ ServerlessFramework自体の仕組みとしてvenvでPythonライブラリを管理する必要はないですが、管理がしやすくなるのでPythonライブラリはvenvで管理します。 venv仮想環境をactivateしておけば sls invoke local でローカルで関数を実行することもできます。 cd <PROJECT_NAME> # .venvディレクトリに仮想環境を作成して、仮想環境を有効化します。 python3.8 -m venv .venv source .venv/bin/activate # ライブラリをインストールして、requirements.txtに書き込見ます。 pip install numpy boto3 pip freeze > requirements.txt # デプロイ あとは、デプロイコマンドを実行するだけで、requirements.txtに書かれているライブラリを良しなにパッケージングしてデプロイしてくれます。 ※ numpyみたいなバイナリのビルドが必要なパッケージはdockerコンテナ上(最初にインストールしたやつ)でビルドされて、Lambda上でも問題なく動作します。 sls deploy ■ serverless.yml ファイルの設定項目 # service サービス名を定義します。初期状態のままでOKです。 servers.yml service: translator # frameworkVersion フレームワークのバージョンを定義します。初期状態のままでOKです。 servers.yml frameworkVersion: '2' # provider プロバイダ名やランタイムやリージョンなど、プロジェクトの基本的な情報を定義します。 serveless.yml provider: name: aws runtime: python3.8 lambdaHashingVersion: 20201221 region: ap-northeast-1 # デプロイするリージョンを定義します。deployコマンドの--regionでデプロイ時に指定することも可能 stage: dev # デプロイするステージ情報を定義します。deployコマンドの--stageでデプロイ時に指定することも可能 # package パッケージに含めるファイルをパターンで定義します。 定義されたパターンは後勝ちなので、最初にすべてのファイルを除外して、必要なファイルだけ指定すると使いやすそうです。 servers.yml package: patterns: - '!**' # すべてのファイルをexclude - 'static/**' # staticディレクトリは以下をinclude - 'handler.py' # handler.pyをinclude # functions 関数の実行の起点となるイベントと、イベントが発生したときに実行する関数を定義します。 handler ファイル名.関数名 形式で関数を指定します。 events API Gatewayを使用したhttpイベントや、S3の操作をトリガーとしたイベントなどいろいろなイベントを定義することができます。 https://serverless.com/framework/docs/providers/aws/events serverless.yml functions: translate: handler: handler.translate # handler.pyのtranslate関数を呼び出します。 role: TranslateRole # resourceセクション(後述)で作成したIAMロールをlambdaに設定します。(未指定の場合はデフォルトのロールが利用されます) events: - http: # API Gatewayを利用したhttpイベントを設定します。 path: /translate # /translateにPOSTアクセスされたときに関数を実行します。 method: post cors: true # CORSを許可するオプションみたいですが、効いていない気がします、、、 static: handler: handler.static # handler.pyのstatic関数を呼び出します。 role: BaseRole events: - http: path: "/static/{any+}" # {hoge} でプレースホルダを設定できます。{hoge+} とするとワイルドカードになります。 method: get # resources CloudFormationのテンプレートをそのまま記述することができます。 今回はLambda関数用のIAMロールを定義しています。 serverless.yml resources: Resources: BaseRole: # handler.static関数にアタッチするロール Type: AWS::IAM::Role Properties: RoleName: translator-role-lambda-base ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - lambda.amazonaws.com TranslateRole: # handler.translate関数にアタッチするロール Type: AWS::IAM::Role Properties: RoleName: translator-role-lambda-translate ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole - arn:aws:iam::aws:policy/TranslateFullAccess AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - lambda.amazonaws.com # plugins 利用するプラグインを定義します。 sls plugin install コマンドでプラグインをインストールすると自動的に追記されます。 serverless.yml plugins: - serverless-python-requirements # custom Documentに項目が見当たらないが、プラグインなどの個別設定を記述するセクションだろうか、、、 servers.yml custom: pythonRequirements: dockerizePip: true ■ 簡単な翻訳アプリ 学習した内容を元にちょっとした翻訳アプリを作ってみました。 ■ 参考記事 https://serverless.com/ https://serverless.co.jp/blog/25/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LambdaでS3のPDFを画像化して保存(Docker,Python)

はじめに LambdaでPdfを画像化します。windowsであればpopplerのstatic buildがあるので比較的簡単にできますが、Lambdaの環境ではコンテナを使わないとその方法では実行できません。コンテナの勉強を兼ねて作りました。 前提 Dockerの実行環境 AWS CLIとaws configureの設定 やること Dockerイメージの準備 ECRの準備 Lambdaの作成 Dockerイメージの準備 以下のようなファイル構成です。 CreatePdfThumbnail │ app.py │ Dockerfile │ env.txt └─ requirements.txt Dockerfileは以下のようになっています。 FROM public.ecr.aws/lambda/python:3.6 # ベースイメージはPython3.6環境を使いたいのでpublic.ecr.aws/lambda/python:3.6 RUN yum -y install poppler-utils # poppler-utilsをインストール # apt-getは使えないので注意 COPY app.py ${LAMBDA_TASK_ROOT} COPY requirements.txt . RUN pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" # 必要なライブラリのインストール CMD ["app.lambda_handler"] 以下のapp.pyがLambdaの本体です。 app.py import json import os, io from pathlib import Path from pdf2image import convert_from_bytes, convert_from_path import boto3 import PIL import requests def lambda_handler(event, context): pdf_name = event['queryStringParameters']['pdfName'] # queryStringParamtersはAPI Gateway用 bucket_name = 'my-bucket' s3 = boto3.client('s3') response = s3.get_object(Bucket=bucket_name, Key=pdf_name) data = response['Body'].read() pages = convert_from_bytes(data) # pagesはPILのImageリストなのでbyteに変換 img_bytes = io.BytesIO() pages[0].save(img_bytes, format='PNG') img_bytes = img_bytes.getvalue() base = os.path.splitext(os.path.basename(pdf_name))[0] s3.put_object(Body=img_bytes,Bucket=bucket_name,Key=base+'.png') return { 'statusCode': 200, 'body': 'DONE!' } pdfの一ページ目を画像にしてS3に保存します。pdf2imageを使ってます(これにpopplerが必要)。 requirements.txtでは必要なライブラリを記述します(boto3はいらないかも)。 requirements.txt pdf2image boto3 requests ローカルでテストするときは、Dockerfileのあるディレクトリで以下のコマンドでイメージをビルドしてrunしてください。 docker build -t test . docker run -p 9000:8080 test:latest コードでboto3などを使っていてcredentialが必要な場合は、env.txtに以下のように記述して実行時に渡します。 env.txt AWS_DEFAULT_REGION=ap-northeast-1 AWS_ACCESS_KEY_ID=IAMで発行する適切な権限を持つアクセスキー AWS_SECRET_ACCESS_KEY=そのシークレットキー docker run --env-file ./env.txt -p 9000:8080 test あとはhttp://localhost:9000/2015-03-31/functions/function/invocationsにPOSTリクエストを投げてあげるとテストができます。↓Pythonの例 import requests data = { 'queryStringParameters': { 'pdfName': 'test.pdf' } } response = requests.post("http://localhost:9000/2015-03-31/functions/function/invocations",json=data) ECRの準備 ECRは基本的にボタンをポチポチするだけです。すごく便利。 ↓次にECR側です。コンソールからElastic Container Registryを選択し、リポジトリを作成をクリック。 ↓リポジトリ名を入力し、下にスクロールしてリポジトリを作成をクリック。 ↓プッシュコマンドの表示をクリック。 ↓出てきたコマンドをDockerfileのある場所でコマンドプロンプトからたたけばイメージがECRにpushされる(WindowsでもmacOS/LinuxタブのコマンドでOK)。 ↓こんな感じでpushされてればOK。 Lambdaの作成 コンソールからLambdaを開いて関数の作成をクリック。以下の画像のように「コンテナイメージ」を選択し、関数名と先ほど作成したコンテナイメージURIを入力したあと関数の作成をクリック。関数名はECRのリポジトリ名と同じにする。 S3やDynamoDBにアクセスする際には、設定タブの「一般設定」→「編集」→「IAMコンソールで~~~のロールを表示します」からS3やDynamoDBの適切なポリシーをアタッチしてください。 以上。コードのプレビューはできませんが、テストタブからテストはできます。エイリアスやバージョンの設定も触っていきたい。 おわりに OpenGL対応のFaaSってないですか。間違い等ありましたらご指摘よろしくお願いします。 参考 コンテナイメージで Python Lambda 関数をデプロイする Lambda コンテナイメージをローカルでテストする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】Amazon Pollyでテキストを生きた音声に変換してみた

はじめに みなさんYoutubeや仕事でテキストを音声に変えることってありますか? 自分で声を収録してもよいですが、恥ずかしいし・・・ ネット上にはテキストを音声に変えてくれるサービスはいろいろありますが、正直どれもいまいち。 AWSのAmazon Pollyではテキストを「生きた音声」に変換することができます。 私が触った感触では他のどの変換サイトより「生きた音声」だと思います。 (特に英語はすごい) 是非みなさんも試してみて下さい。 AWSは1年間は無料期間なのでどんどん試してみましょう! 手順 1.AWSマネジメントコンソールにログインします。(登録は済ませておいて下さい) 上部の検索バーで[Amazon Polly]と検索して下さい。 2.[入力テキスト]欄に音声に変換したいテキストを入力して[音声を聴く]をクリックします。 それだけです。とても簡単に音声化出来ます。出来上がった音声は[ダウンロード]をクリックすると取得できます。 なお現時点では、日本語のエンジンは残念ながら[スタンダード]しかありません。 音声は男性と女性から選べます。  Mizuki,女性  Takumi,男性 個人的には[Takumi,男性]の方がよりスムーズな印象です。 ちなみに エンジン[ニューラル]で言語を[英語(米国)]にしてみて下さい。 特に以下は個人的にとてもすごいと思います。(TOEICの問題くらい自然)    Matthew,男性  Salli,女性 日本語にも早く対応して欲しいですね。 ご参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon GuardDutyでTrojan:EC2/DGADomainRequest.Bが発生したが、そこまで驚異ではなかった話。

結論 GuardDutyがトロイと認定しているドメインをforwardさせるSSH接続の総当たり攻撃があり、SSHDが気を利かせてドメインの情報を照会した為に起きていた。実際にトロイの木馬に感染しているわけでは無かった。 SlackにGuardDutyからヤバい通知がきた EC2 instance i-xxxxxxxxxxxx is querying algorithmically generated domains. Such domains are commonly used by malware and could be an indication of a compromised EC2 instance. アルゴリズム的に作られたドメインにクエリを送ったから、トロイ感染しているんじゃね?という通知だ。しかも重要度(Severity)は高いと。 一次対策に失敗? 該当のインスタンスを終了、再度立ち上げた。しかし、数時間後にまた別のインスタンスで同じ通知が来るの繰り返し。 グローバルIPV4割当をしていないサブネット内のインスタンス(ElasticIPでグローバルIPは持つ)でも起きていた。 また、サブネットを跨いで起きている。 いったいどうなっているのかと。VPC単位で全てが感染した可能性すら考えられて、戦々恐々。 とはいえ、回数は1〜2回が数時間に1回と、それ程多くない。ガチでトロイに感染していたら、これが数百、数千のオーダーで発生するはずだ。 一体何が起きているのか、我々はその答えを探しにAmazon(Web Services)の奥地まで飛んだ。 ログの中から手がかりになるものを探してみた GuardDutyのログの最後を見ると、何れも特定のドメインへのアクセスがあった。 このドメインを該当インスタンスにSSH接続して/var/log/secureからgrepしてみた $ cat /var/log/secure |grep hitquckbulck.live Sep x xx:xx:xx ip-xxx-xxx-xxx-xxx sshd[16860]: reverse mapping checking getaddrinfo for hitquckbulck.live [xxx.xxx.xxx.xxx] failed - POSSIBLE BREAK-IN ATTEMPT! と該当ログがあり、最初に書いた結論に至った。 GuardDutyのログを見ても、ここ数日の間、UnauthorizedAccess:EC2/SSHBruteForceが増えており、その中のfowardのドメインの1つに、トロイとして検出されるドメインが含まれていたようだ。 ドメイン名は違うが、同様の事象がこちらの記事にもあった。 下記記事と同様に、我々も該当のドメインをdigしたら、GuardDutyに検出され、問題ないとの確信に至った。 https://vamdemicsystem.black/aws/%E3%80%90aws%E3%80%91garudduty%E3%81%A7%E3%80%8Cfinding-type-trojanec2-dgadomainrequest-b%E3%80%8D%E3%81%8C%E5%87%BA%E3%81%9F
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws cliでcloudfrontのオブジェクトの無効化

参考 (今後変わるかもしれないので参考程度に:)一ヶ月に無効化の回数が1000件超えると支払いが発生し始めるようなので注意しましょう。 手順 以下のコマンドで invalidationを作成できます。 $ aws cloudfront create-invalidation --distribution-id xxxxx --paths /past-payments/index. html このようなレスポンスが返ってきます。 { "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/xxx/invalidation/xxxx", "Invalidation": { "Id": "xxxxx", "Status": "InProgress", "CreateTime": "2021-09-10T07:08:03.775000+00:00", "InvalidationBatch": { "Paths": { "Quantity": 1, "Items": [ "/past-payments/index.html" ] }, "CallerReference": "cli-xxx-139143" } } } すべて無効化したい場合は以下を使うといいです。 aws cloudfront create-invalidation --distribution-id EW1BES0CR1BM0 --paths "/*"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SageMaker同じロールを被る場合CloudTrailにインスタンス名を残す方法

タイトルの件はAWSオフィシャルQAには記載されています。 解決案 すべてのインスタンスが同じ IAM ロールを使用する場合、どの SageMaker ノートブックインスタンスが特定の API 呼び出しを行ったかを判断するにはどうすればよいですか? 注意点 上記の記事は解決案になっていますが、幾つの注意点があります。 1、コピペーは#!/bin/bashから始めてください。 2、改行コードはCRLFからLFに変換してください。 3、インスタンスはPrivateSubnetにいる場合、STSのVPCエンドポイントを設定すること。 4、デフォールトJupyterユーザーはsudo権限を持っているためスクリプトの改ざんは可能。 4番の補足 SageMakerでノートブックインスタンスを作成するときに「ルートアクセスー無効化」を設定しすれば改ざんできなくなりますが、コンソールでyumコマンドは使えなくなります。システムにライブラリをインストールできないけれど、pipは正常に使えます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2にアタッチしたIAMロールが変更できない場合の対処法

はじめに ある検証のために特定のEC2に対してIAMロールのつけ外しを行っていたのですが、急にIAMロールのアタッチができなくなったので、解決までの手順を書いておきます。 事象 元々アタッチしていたIAMロールを一旦外そうとした際、以下のようにエラーが出力されて、IAMロールのつけ外しができなくなりました。 尚、これが表示される直前に1度違うIAMロールから変更しています。 調査 調べてみると以下のページを見つけました。 https://www.fixes.pub/program/207318.html このページを見る限りだと、IAMロールを付け替えした際にEC2に紐づくインスタンスプロファイルも当然変更されますが、その関連付けが中途半端に設定された状態であることが原因のようです。 対応方法 参考ページの内容から 1."aws ec2 describe-iam-instance-profile-associations"コマンドでプロファイルとインスタンスの関連付けを確認 2.インスタンスが複数のプロファイルと関連付けられている場合、"aws ec2 disassociate-iam-instance-profile --association-id [ASSOCIATION ID]"コマンドで関連付けを解除 3.EC2コンソールからIAMロールを変更 という手順で解決しそうですので、試してみます。 実施 以下のコマンドを実行してみると確かに関連付けが複数ありました。 aws ec2 describe-iam-instance-profile-associations 以下のコマンドでIAMロールの関連付けを削除します。 aws ec2 disassociate-iam-instance-profile --association-id [ASSOCIATION ID] 再度関連付けを確認してみるとちゃんと解除されているようです。 IAMロールを解除してみます。 まだダメでした。 同じ手順でもう一つの関連付けを解除するとデタッチができました。 恐らくですが、最初に設定したロール名がxxx_role、次に設定したロール名がxxx_s3_roleだったのですが、EC2には最初のロールが関連付けられていたのが原因だと思います。 最後に 無事IAMロールをデタッチできたので、この記事が同じ原因で詰まっている方の助けになれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSでACM証明書を発行し、https化したのにフォーム送信でセキュリティ保護されていないメッセージがでるときの対処法

個人アプリの作成で、ALBを使用しACMで証明書を取得。 https化までできたところでフォームを送信すると、、、 このようなエラーが。。。 httpで通信が行われるようになっていたため、 ALBのリスナーの設定がまずいのかといじってみたが改善せず。 対処法 Laravel側でAWSのロードバランサ用のプロキシ設定が必要でした。 App\Http\Middleware\TrustProxies <?php namespace App\Http\Middleware; use Illuminate\Http\Middleware\TrustProxies as Middleware; use Illuminate\Http\Request; class TrustProxies extends Middleware { /** * このアプリケーションで信頼できるプロキシ * * @var string|array */ protected $proxies = '*' /** * プロキシを検出するために使用すべきヘッダ * * @var int */ protected $headers = Request::HEADER_X_FORWARDED_AWS_ELB; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambda 関数を Docker コンテナを使ってビルド & デプロイ

概要 記事 第一回 コンテナ Lambda の”いろは”、AWS CLI でのデプロイに挑戦 ! を参考に windows10 で AWS Lambda 関数を Docker コンテナを使ってビルド & デプロイ する方法を書きました AWS Lambda 関数を Docker コンテナを使ってビルド & デプロイ するには以下の3ステップが必要です 1.Docker イメージを作成する 2.Docker イメージを Amazon ECR リポジトリ にプッシュする 3.Lambda関数に Amazon ECR リポジトリ(の Docker イメージ) から ビルドする 前提条件 Docker Desktop がインストールされていること この記事は Windows10 上で Docker を用いて操作しています。 この記事の作業はローカル環境に Docker Desktop がインストールされていることを前提で進めます。インストールされていない場合は、インストールしてから進めてください。 Amazon CLI がインストールされていること Amazon CLI https://aws.amazon.com/jp/cli/ aws configure (初期化) が済んでいること > aws configure AWS Access Key ID [None]: ATI********CS AWS Secret Access Key [None]: ***erg***sdfg***bs1sderg** Default region name [None]: ap-northeast-1 Default output format [None]: json 実装 1.Docker イメージを作成する手順 手順1-1: 2つのテキストファイルを用意する 作業するフォルダを決めて 以下の2つのテキストファイルを作成しましょう それぞれのファイルの中身は以下の通りとします。 app.py import json def handler(event, context): return { "statusCode": 200, "body": json.dumps( { "message": "hello world", } ), } Dockerfile FROM public.ecr.aws/lambda/python:3.8 COPY app.py ./ CMD ["app.handler"] 解説 FROM 命令で public.ecr.aws/lambda/python:3.8 と ECR の AWS 公式の公開イメージを指定していますが、amazon/aws-lambda-python:3.8 のように docker hub のイメージを参照することも可能です。   COPY コマンドでローカルに配置されている Lambda 関数本体である app.py ファイルをイメージにコピーしています。そして CMD で Lambda 関数のハンドラーを渡しています。 手順1-2: Dockerfile 元にビルド Dockerfile を元にビルドしてみましょう。 コマンド docker build -t func1 . を実行します。 > docker build -t func1 . [+] Building 19.2s (7/7) FINISHED => [internal] load build definition from Dockerfile ・・・<中略>・・・ => => extracting sha256:d79191d95889cb243767819f51824443759d257388bb5ef05babed549d31a2c4 => [2/2] COPY app.py ./ => exporting to image => => naming to docker.io/library/func1 Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them ビルド成功しました 2.Docker イメージを Amazon ECR にプッシュする手順 手順2-1: Amazon ECR に今回作成する Lambda 関数のイメージ用のリポジトリを作成します。 さて、ここから Amazon ECR に今回作成する Lambda 関数のイメージ用のリポジトリを作成します。 Amazon ECR とは Elastic Container Registry の略で Dockerのコンテナイメージを保存しておくためのレジストリで、 Dockerコンテナイメージを保存・管理・デプロイが簡単に出来ます。 手順2-2: Docker に リポジトリの URI を含めたタグを付与します。 ECR 上にリポジトリが作成されたら、リポジトリの URI を含めたタグを付与します。 docker tag func1:latest ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1:latest Docker Desktop の Images に追加されます。 手順2-3:リポジトリに push する前に、ECR にログインします。 > aws ecr get-login-password | docker login --username AWS --password-stdin ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com Login Succeeded 手順2-4:リポジトリに push リポジトリに push しましょう。 PS> docker push ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1:latest The push refers to repository [${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1] 29fe8a4ae381: Pushed 20b4eff3dd4d: Pushing 68.11MB/92.13MB 11284767d41d: Pushing 87.48MB/199.7MB d6fa53d6caa6: Pushed b09e76f63d5d: Pushed 0acabcf564c7: Pushed f2342b1247df: Pushing 125.9MB/294.9MB latest: digest: sha256:123*************************************789 push が完了すると、ダイジェストが発行されるので、覚えておく AWS コンソールで確認すると cocker イメージが Amaxon ECR リポジトリ にアップロードされたのが確認できる 3.Lambda関数に Amazon ECR リポジトリ(の Docker イメージ) から ビルドする手順 手順3-1: AWS Lambda ダッシュボードから 関数作成 ボタンをクリックする 手順3-2: コンテナイメージから作成 ここから、Lambda 関数をコンテナイメージを利用して作成していきますが、AWS Lambda のコンテナサポートで、—package-type を指定できるようになりました。 できました 今回の Lambda関数名 は, docker_test としました 手順3-3:作成された関数を実行確認 そしていよいよ実行することができます。作成された関数を実行してみましょう。 > aws lambda invoke --function-name docer_test output ; cat output 正常に返ってきました!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CyberduckでPrivate EC2へファイル転送

これは何 WinSCPがMacで使えなさそう(使えるけど設定が面倒くさそう)、ということで、Cyberduckを使ってファイル転送してみました。のメモです。 前提 踏み台EC2からPrivate EC2へ、Cyberduckを使ってファイル転送します。 ローカルマシンのポートをリモート先に転送します。 早速やってみた 踏み台にSSHポートフォワーディングを張る $ ssh -f -N -L 10220(任意):Private EC2のPrivate IP or ドメイン:22 -i 秘密鍵 OSユーザー名@踏み台EC2のPublic IP -f : バックグラウンドで動作 -N : コマンド実行無し -L : Localのことを表す CyberduckでCMSのアクセス情報入力 サーバー名 : localhost ポート名 : 10220(任意) ユーザー名 : Private EC2のOSユーザー名 SSH Private Key : 秘密鍵のFull Path これで接続できました。 あとは適当にファイル転送します。 一応、CLIでも見てみます。 総括 使う前は、CLIでファイル転送に慣れてしまっているので、GUIはかえって面倒くさいのでは? と思っていましたが、使ってみると思いのほか便利ですね。 ローカルマシンから、ドラッグ&ドロップで転送できるのがこんなに楽とは… 参考 https://qiita.com/Ayaka14/items/449e2236af4b8c2beb81 https://ja.stackoverflow.com/questions/49344/scp%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E8%B8%8F%E3%81%BF%E5%8F%B0%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E7%B5%8C%E7%94%B1%E3%81%A7%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 参考にさせていただきました。ありがとうございます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2の起動直後のCloudWatchアラームを抑止する

起動直後のCloudWatchアラームの通知を抑止したいという要望があったので、AWSサービスを組み合わせて実現してみました。 構成 EventBridge + Lambdaで実現します。 EC2起動直後の一定時間を待つために、起動時にはStep FunctionsからLambdaを呼び出します。 EventBridgeやStep Functionsは応用の幅が広いので、その一例としても役立ちそうです。 Lambdaコード まずはLambdaコードから見ていきます。 import boto3 target = { "test-instance" : ['test-alarm'] } def lambda_handler(event, context): client = boto3.client('cloudwatch') if event["Action"] == 'enable': response = client.enable_alarm_actions( AlarmNames=target[event["Target"]] ) if event["Action"] == 'disable': response = client.disable_alarm_actions( AlarmNames=target[event["Target"]] ) EventBridgeからキーバリューを受け取ることを前提としたコードです。 Actionキーでアラームの有効or無効を切り替えます。TargetキーでEC2を識別します。ここではインスタンス名(test-instance)とします。あらかじめインスタンス名に対応したアラーム名(test-alarm)を辞書型のtargetで定義しておきます。 これにより、EventBridgeで指定したインスタンスに対応するアラームの有効化or無効化を実行することができます。 IAMポリシー Lambda用のIAMポリシーです。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "cloudwatch:EnableAlarmActions", "cloudwatch:DisableAlarmActions", "logs:CreateLogGroup", "logs:PutLogEvents" ], "Resource": "*" } ] } 標準で付与されるログ周りを除くと、EnableAlarmActionsとDisableAlarmActionsが必要です。 これらのアクションはAWSコンソールからは実行できず、LambdaやCLIで実行する必要があるようです。 Step Functionsステートマシン EC2起動時に実行するステートマシンを定義します。 { "StartAt": "Wait", "States": { "Wait": { "Type": "Wait", "Seconds": 60, "Next": "MainTask" }, "MainTask": { "Type": "Task", "Resource": "arn:aws:lambda:リージョン名:アカウントID:function:AlarmSwitch", "End": true } } } リージョン名とアカウントIDは置き換えてください。ステートマシン内で前述のLambdaを呼び出します。ここでは実行までに1分間待つことにします。 IAMポリシー ステートマシン用のIAMポリシーです。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": [ "arn:aws:lambda:リージョン名:アカウントID:function:AlarmSwitch:*" ] }, { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": [ "arn:aws:lambda:リージョン名:アカウントID:function:AlarmSwitch" ] }, { "Effect": "Allow", "Action": [ "xray:PutTraceSegments", "xray:PutTelemetryRecords", "xray:GetSamplingRules", "xray:GetSamplingTargets" ], "Resource": [ "*" ] } ] } リージョン名とアカウントIDは置き換えてください。xray周りは標準で付与されるものです。前述のLambdaの実行権限を付与しておきます。 EventBridge あとはEventBridgeで対象のEC2の起動停止をトリガーにして、先ほどのLambdaとステートマシンを実行します。 EC2起動 イベントパターン { "source": ["aws.ec2"], "detail-type": ["EC2 Instance State-change Notification"], "detail": { "state": ["running"], "instance-id": ["インスタンスID"] } } インスタンスIDは置き換えてください。 ターゲット 先ほどのステートマシンを選択します。Lambdaに引き渡すキーバリューをJSONで指定します。 IAMポリシー EC2起動EventBridge用のIAMポリシーです。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "states:StartExecution" ], "Resource": [ "arn:aws:states:リージョン名:アカウントID:stateMachine:AlarmSwitchStateMachine" ] } ] } リージョン名とアカウントIDは置き換えてください。先ほどのステートマシンの実行権限が必要です。 EC2停止 イベントパターン { "source": ["aws.ec2"], "detail-type": ["EC2 Instance State-change Notification"], "detail": { "state": ["stopped"], "instance-id": ["インスタンスID"] } } ターゲット 停止時は待機しないので、直接Lambdaを呼び出します。AWSコンソールで作成すれば、実行権限はLambdaパーミッションで自動的に付与されます。CloudFormationで作成する際はLambdaパーミッションの設定に注意です。キーバリューもEC2起動と同じ形式で入力します。 実行結果 準備が整ったら、対象のEC2インスタンスを起動および停止します。 停止すると、インスタンスに対応したアラームが無効になります。 起動すると、ステートマシンが実行され、指定した時間(1分間)待機した後、Lambdaを実行してアラームを有効化します。 これにより、起動後の任意の一定時間、CloudWatchアラームを無効化することができるので、アラームの抑止を実現できました。 今回は停止と起動のセットで動作する構成になりますが、再起動時にも抑止したい場合を考えると、起動時のみをトリガーとしてアラームの有効無効を切り替えるようにするなどの工夫が必要そうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Angular×AWSでWorldにHello!したい

はじめに 言語やフレームワークの勉強をしていてはじめに出力する内容は決まって「Hello World!」だと思います。ただ、私は実行してみていつも思います。 いや、localにはHello!出来てるけどWorldにはHello!出来てなくない? ということで今回はAngular×AWSでWorldにHello!するまでの流れを記載しました。 目指すアーキテクチャ アーキテクチャとしてはS3に入れたAngularのアプリをCloudFrontでホスティングする仕組みをゴールとします。 まずはlocalにHello! WolrdにHello!する前にまずはlocalにHello!出来てないと始まらないので、まずはlocalにHello!します。 これに関しては、Angularの公式のセットアップを見るのをおすすめしますが、ざっくりと手順をまとめました。 Angular公式 環境構築 まずはNode.jsをインストールします。 ※Node.jsのバージョンを管理されたい方はnvm経由でインストールするようにしましょう。 インストールするとNode.jsと共にnpmパッケージマネージャーがインストールされるのでnpmを使ってAngularをインストールしていきます。 npm install -g @angular/cli これでAngularがインストール出来ました。 次にAngularのアプリを作成していきます。 ng new my-app これで新しいAngularアプリケーションが作成されました。簡単ですね。 それでは、作成されたアプリケーションを実行してみましょう。 cd my-app ng serve --open これでlocalにHello!は完了です。 ビルドしてみよう これまでの処理でアプリケーションの実行までは出来ました。しかし、これをホスティングするためにはビルドする必要があります。 ビルドは下記のコマンドで出来ます。 ng build --aot このコマンドを実行するとアプリケーションのルートディレクトリにdistというディレクトリが出来ていると思います。 dist/my-app配下のファイルがホスティングするべきファイル群になります。 これをS3に配置することでどこからでもアプリケーションを見ることが出来るようになります。 AWS周りの設定をしよう 上までの手順でアプリケーション本体のファイルは作成することが出来ました。 それでは次に基盤周りの設定をしていきましょう。 今回は作成をより簡略化するためにCloudFormationのテンプレートでリソースを作っていきます。 テンプレートはyaml形式で記載しています。 パラメータ設定 まずは、パラメータを設定します。 S3のバケット名やアプリを入れるディレクトリ名は自由に変えたいケースが多いのでパラメータ化しておきます。 template.yml Parameters: AngularBucketName: Type: String Default: "angular-app-bucket" Description: "S3 bucket to Create" AllowedPattern: "[a-zA-Z][a-zA-Z0-9_-]*" DirName: Type: String Default: "app" Description: "S3 bucket to Create" AllowedPattern: "[a-zA-Z][a-zA-Z0-9_-]*" S3の作成 次にS3のバケットを作成します。 今回アプリはバケット内にディレクトリを切ってその中に入れたいと思っているので、ディレクトリ作成までテンプレートで行います。 まずはバケット作成です。 template.yml ... 省略 ... Resources: AngularBucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref AngularBucketName これでS3にバケットが作成できます。 それでは次にバケット内にディレクトリを作成します。 ディレクトリはテンプレートで直接作ることが出来ないのでカスタムリソースでLambdaを作成してそのLambdaでディレクトリを作成していきます。 template.yml ... 省略 ... AngularDir: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt AWSLambdaFunction.Arn the_bucket: !Ref AngularBucket dir_to_create: !Ref DirName AWSLambdaFunction: Type: "AWS::Lambda::Function" Properties: Description: "Work with S3 bucket" FunctionName: !Sub '${AWS::StackName}-${AWS::Region}-lambda' Handler: index.handler Role: !GetAtt AWSLambdaExecutionRole.Arn Timeout: 360 Runtime: python3.6 Code: ZipFile: | import boto3 import cfnresponse def handler(event, context): # Init ... the_event = event['RequestType'] print("The event is: ", str(the_event)) response_data = {} s_3 = boto3.client('s3') # Retrieve parameters the_bucket = event['ResourceProperties']['the_bucket'] dir_to_create = event['ResourceProperties']['dir_to_create'] try: if the_event in ('Create', 'Update'): print("Requested folders: ", str(dir_to_create)) print("Creating: ", str(dir_to_create)) s_3.put_object(Bucket=the_bucket, Key=(dir_to_create + '/')) elif the_event == 'Delete': print("Deleting S3 content") b_operator = boto3.resource('s3') b_operator.Bucket(str(the_bucket)).objects.all().delete() print("Operation successfull") cfnresponse.send(event,context,cfnresponse.SUCCESS, response_data) except Exception as e: print("Operation failed...") print(str(e)) response_data['Data'] = str(e) cfnresponse.send(event, context, cfnresponse.FAILED, response_data) AWSLambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com Version: '2012-10-17' Path: "/" Policies: - PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: arn:aws:logs:*:*:* Version: '2012-10-17' PolicyName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambda-CW - PolicyDocument: Statement: - Action: - s3:PutObject - s3:DeleteObject - s3:List* Effect: Allow Resource: - !Sub arn:aws:s3:::${AngularBucket}/* - !Sub arn:aws:s3:::${AngularBucket} Version: '2012-10-17' PolicyName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambda-S3 RoleName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambdaExecutionRole 非常に長いコードになっていますが、やっていることとしては三つです。 CloudFormationが実行されるたびに実行されるカスタムリソースを定義 実行されるラムダの定義 実行されるラムダのRoleの定義 CloudFrontの作成 これまでの処理でS3バケットとディレクトリまで作成できました。 それでは次にディレクトリに入っているデータをホスティングするCloudFrontを作っていきましょう。 template.yml ... 省略 ... AngularBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref AngularBucket PolicyDocument: Statement: - Action: s3:GetObject Effect: Allow Resource: !Sub arn:aws:s3:::${AngularBucket}/${DirName}/* Principal: AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity} CloudForntDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Origins: - DomainName: !GetAtt AngularBucket.DomainName Id: AngularOrigin OriginPath: !Sub /${DirName} S3OriginConfig: OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity} Enabled: 'true' DefaultRootObject: index.html DefaultCacheBehavior: AllowedMethods: - GET - HEAD TargetOriginId: AngularOrigin ForwardedValues: QueryString: 'false' ViewerProtocolPolicy: allow-all PriceClass: PriceClass_200 CloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref AWS::StackName 最初にAngularBucketPolicyがあり、「おや?」と思った方もいらっしゃるかもしれません。 こちらは、CloudFrontからS3にアクセスするための設定です。 S3のデータは公開設定にしていない限り外部から見ることが出来ないのでOriginAccessIdentityを設定する必要があります。 これでテンプレートの準備は出来ました。 template.yamlの全体 template.yml Parameters: AngularBucketName: Type: String Default: "angular-app-bucket" Description: "S3 bucket to Create" AllowedPattern: "[a-zA-Z][a-zA-Z0-9_-]*" DirName: Type: String Default: "app" Description: "S3 bucket to Create" AllowedPattern: "[a-zA-Z][a-zA-Z0-9_-]*" Resources: AngularBucket: Type: AWS::S3::Bucket Properties: BucketName: !Ref AngularBucketName AngularBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref AngularBucket PolicyDocument: Statement: - Action: s3:GetObject Effect: Allow Resource: !Sub arn:aws:s3:::${AngularBucket}/${DirName}/* Principal: AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity} AngularDir: Type: Custom::S3CustomResource Properties: ServiceToken: !GetAtt AWSLambdaFunction.Arn the_bucket: !Ref AngularBucket dir_to_create: !Ref DirName AWSLambdaFunction: Type: "AWS::Lambda::Function" Properties: Description: "Work with S3 bucket" FunctionName: !Sub '${AWS::StackName}-${AWS::Region}-lambda' Handler: index.handler Role: !GetAtt AWSLambdaExecutionRole.Arn Timeout: 360 Runtime: python3.6 Code: ZipFile: | import boto3 import cfnresponse def handler(event, context): # Init ... the_event = event['RequestType'] print("The event is: ", str(the_event)) response_data = {} s_3 = boto3.client('s3') # Retrieve parameters the_bucket = event['ResourceProperties']['the_bucket'] dir_to_create = event['ResourceProperties']['dir_to_create'] try: if the_event in ('Create', 'Update'): print("Requested folders: ", str(dir_to_create)) print("Creating: ", str(dir_to_create)) s_3.put_object(Bucket=the_bucket, Key=(dir_to_create + '/')) elif the_event == 'Delete': print("Deleting S3 content") b_operator = boto3.resource('s3') b_operator.Bucket(str(the_bucket)).objects.all().delete() print("Operation successfull") cfnresponse.send(event,context,cfnresponse.SUCCESS, response_data) except Exception as e: print("Operation failed...") print(str(e)) response_data['Data'] = str(e) cfnresponse.send(event, context, cfnresponse.FAILED, response_data) AWSLambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com Version: '2012-10-17' Path: "/" Policies: - PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: arn:aws:logs:*:*:* Version: '2012-10-17' PolicyName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambda-CW - PolicyDocument: Statement: - Action: - s3:PutObject - s3:DeleteObject - s3:List* Effect: Allow Resource: - !Sub arn:aws:s3:::${AngularBucket}/* - !Sub arn:aws:s3:::${AngularBucket} Version: '2012-10-17' PolicyName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambda-S3 RoleName: !Sub ${AWS::StackName}-${AWS::Region}-AWSLambdaExecutionRole CloudForntDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Origins: - DomainName: !GetAtt AngularBucket.DomainName Id: AngularOrigin OriginPath: !Sub /${DirName} S3OriginConfig: OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity} Enabled: 'true' DefaultRootObject: index.html DefaultCacheBehavior: AllowedMethods: - GET - HEAD TargetOriginId: AngularOrigin ForwardedValues: QueryString: 'false' ViewerProtocolPolicy: allow-all PriceClass: PriceClass_200 CloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref AWS::StackName このテンプレートでCloudFormationを使ってリソースを作ると基盤は完成です。 Hello World! アプリも基盤もそろったのでいよいよWorldにHello!しましょう。 まず、作成したS3のバケットのディレクトリにAngularでビルドした成果物を入れます。 そして、CloudFrontのディストリビューションドメイン名にブラウザからアクセスするとアプリが表示されると思います。 これでHello World!達成です。 まとめ 最近では、IaCが流行ってきているので大変かもしれませんがCloudFormationのテンプレートでリソースを作っていくのが大事になるのかなと思います。 また、基本的にオプションなどは外しているので実際にお試しいただく時は色々なオプションを付けて試してもらえるといいかなと思います。 参考 Amazon CloudFront テンプレートスニペット CloudFormation の Amazon S3 バケットでカスタムリソースを使用する方法を教えてください。 CloudFormation で OAI を使った CloudFront + S3 の静的コンテンツ配信インフラを作る
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambdaで独自にログを出力したい(標準のログを出したくない)

問題 Lambda標準のログを抑止してCloudWatchLogsのコストを節約したい。けど、特定の場合にはログを出力したいといった問題を解決します。 Lambdaコード 早速ですが、このような関数を用意してlambda_handler内で使用します。 必要な権限(IAMポリシー)は後で解説します。標準のログを出さないようにするのも、IAMポリシーの定義で行います。 import boto3 import time import datetime logs_client = boto3.client('logs') lgn = '/aws/lambda/PutLog' def lambda_handler(event, context): put_log('test') put_log('テスト') def put_log(message): # ロググループがない場合作成 res = logs_client.describe_log_groups( logGroupNamePrefix=lgn ) if not res['logGroups']: res = logs_client.create_log_group( logGroupName=lgn ) # putするログストリームを取得 lsn = datetime.datetime.now().strftime("%Y/%m/%d") + '[PutLog]' res = logs_client.describe_log_streams( logGroupName=lgn, logStreamNamePrefix=lsn, ) # ログストリームがない場合作成し、取得 if not res['logStreams']: res = logs_client.create_log_stream( logGroupName=lgn, logStreamName=lsn ) res = logs_client.describe_log_streams( logGroupName=lgn, logStreamNamePrefix=lsn, ) # シーケンストークンがある場合指定する if 'uploadSequenceToken' in res['logStreams'][0]: seq_token = res['logStreams'][0]['uploadSequenceToken'] res = logs_client.put_log_events( logGroupName=lgn, logStreamName=lsn, logEvents=[ { 'timestamp': int(time.time()) * 1000, 'message': message }, ], sequenceToken=seq_token ) # ない場合指定しない else: res = logs_client.put_log_events( logGroupName=lgn, logStreamName=lsn, logEvents=[ { 'timestamp': int(time.time()) * 1000, 'message': message }, ] ) コード解説 コードはこちらの記事を参考にしました。 Lambda標準のログと同じような感覚で使いたかったので、ロググループ作成とログストリーム作成を追加しました。これにより、あらかじめそれらを作成する必要がなくなります。 Lambda内の変数lgnでロググループ名の指定と、変数lsnでログストリーム名の指定をします。ここでは、ロググループ名は標準のログと同じ、ログストリーム名は日付+[PutLog]にしています。ログストリーム名を調整すれば、任意の単位でまとめることができると思います。 そして、少し理解が難しいのがシーケンストークンの指定です。参考記事でも触れられていますが、2回目以降同じログストリームに書き込むためには、シーケンストークンの指定が必要です。 IAMポリシー { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Resource": "arn:aws:logs:リージョン名:アカウントID:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:リージョン名:アカウントID:log-group:/aws/lambda/PutLog:log-stream:*[PutLog]" ] } ] } ポリシー解説 ポリシーの内容も前述の記事を参考にしています。リージョン名とアカウントIDは置き換えてください。 CreateLogStreamおよびPutLogEventsを独自に指定することで、標準のログが出力されるのを回避しています。 ここでは、関数内で指定している日付+[PutLog]に対応させるために*[PutLog]で、ワイルドカードの指定をしています。 実行結果 通常であればこのような文字列が付与されたログストリームが作成され、開始終了のログやprint等で指定した文字列が出力されます。前述のポリシーを定義することで、このような標準のログ出力を抑止します。 こちらがテスト結果です。print等の代わりに、作成したput_log関数で任意の文字列を指定します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ポートフォリオ紹介(INTELIST)【Ruby on Rails / AWS】

はじめに 業界・実務未経験者がエンジニア転職を目指して独学で約半年間プログラミング学習を行い、このたび転職用にポートフォリオを作成したため紹介していきたいと思います。 今後もアップデートをしていく予定なので、何かあれば本記事のコメント等にフィードバックをいただけますと助かります! アプリ概要 気になるものを何でもかんでもリスト化して管理・シェアするためのSNSアプリ「INTELIST(いんたりすと)」を作成しました。 気になるものをジャンル問わず投稿し、友人とシェアできる リスト化しておくことで後から確認できる 他のユーザーの興味をランキングで確認し、トレンドを把握できる といった特徴があります。 下記のURLにて公開中ですので、よろしければご覧ください! https://inte-list.com(PCでの閲覧推奨です) GitHubリポジトリ 製作背景 このご時世の中、「落ち着いたら〇〇行ってみよう」「〇〇って漫画がおすすめ」といったような会話をすることが増えたのですが、いかんせん増えすぎたせいで 「行きたいって話してたのどこだっけ…」 「勧められたのなんだっけ…」 「この話誰としたんだっけ…」 とド忘れしてしまうものが出てきました。そのような会話自体もLineやDiscordなどの様々な媒体を使用していたり、通話で話しただけだったりと後から拾いなおすのが難しく、せっかくの楽しみな情報が抜け落ちてしまうのがもったいなかったので、このド忘れを解消する方法として製作したのがINTELISTです。 記録するにあたり、飲食店、読書、音楽などに特化したサービスは比較的すぐ見つかったのですが、ざっくばらんに何でもかんでも記録&シェアするというサービスは見当たらないようだったので自分で製作してみた次第です。 アプリの機能紹介 機能一覧 # 機能名 説明 1 ユーザー機能 新規登録、登録内容変更、アバター画像設定、ログイン、ログアウト。 2 ゲストログイン機能 登録せずゲストとしてアプリを使用可能。ゲストユーザーは削除/編集不可。 3 フォロー機能     ユーザーをフォロー可能(Ajax)。原則はフォローしているユーザーのみを自身のタイムラインに表示。 4 投稿機能 投稿、編集、削除。投稿にはアイテム/コメント/参考URL/タグを登録可能。参考URLを入力した場合は外部APIを使用してリンクサムネイルを自動作成。 5 投稿へのいいね機能 投稿をいいねが可能(Ajax)。いいねした投稿をマイページで一覧表示。 6 投稿へのコメント機能 投稿へのコメント追加/削除が可能(Ajax)。コメントした投稿をマイページで一覧表示。 7 タグ付け機能 投稿へのタグ登録/編集/削除が可能。タイムライン等で表示されているタグをクリックすると、同じタグを含むアイテム一覧を表示。 8 マイアイテム機能 自分の投稿したアイテムを一覧表示。完了/未完了を登録し、ステータスで絞り込みが可能(Ajax)。 9 検索機能 ユーザー一覧、アイテム一覧、マイアイテム一覧の絞り込み検索が可能(Ajax)。 10 ランキング機能 全ユーザーorフォローのみ、期間を指定した投稿数上位10位のランキングを一覧表示。 使用イメージ(一部機能抜粋。番号は一覧のNo) 4. 投稿機能 「新規投稿」ボタンから投稿画面を開き、気になるアイテムを登録します。 (投稿画面はBootstrapのモーダル機能を利用しています。) 投稿にはアイテム名、投稿内容(コメント)、参考URL、タグ名を登録できます。 参考URLを入力した場合、投稿完了時に自動的にサムネイルを作成します。 タグはエンターを入力することでバッチ化します(tagsinputを使用)。 7. タグ付け機能 前述の通り、投稿時にはタグを登録でき、タグを利用することで似たジャンルのアイテムを探すことができます。 画面に表示されているタグバッチをクリックすると同名タグを含むアイテム一覧を表示します。 (上のgifではボドゲ→ゲームの順でタグをクリックし、絞り込みを行っています) 投稿作成時にはタグ名称でTagテーブルを検索し、同名タグがあれば既存レコードを使用、なければ新規に作成します。 8. マイアイテム機能 ヘッダー → アカウント → 「マイアイテム一覧画面」 からは、自分が登録したアイテムをリストで確認できます。 アイテムごとに完了済/未完了のステータスを設定することができ、実際に行ってみた場合などには完了済にできます。 マイアイテム一覧ではステータスごとで絞り込みを行えるため、まだ行っていないアイテムだけを確認することもできます。 9. 検索機能 ユーザー一覧/アイテム一覧/マイアイテム一覧では複数ワードによる絞り込み検索ができます。 (上のgifではアイテム一覧ページにて、タグ:ボドゲ、アイテム名:魔女、にて絞り込みを行っています。例ではあえて2ステップ踏んでいますが、もちろん1ステップでも可能です。) 検索はLike検索で、複数ワードがある場合はAND検索します。 リセットボタンを押すと検索が解除されます。 10. ランキング機能 ランキングページで他のユーザーに人気のものをチェックできます。 全ユーザー/フォローのみ、週間/月間/全期間での条件ごとで絞り込んだランキングを表示できます。 (上のgifでは「全ユーザー&週間」→「全ユーザー&月間」→「フォローのみ&月間」と切り替えています。) 使用技術/設計等 フロントエンド HTML Sass JavaScript(jQuery3.6.0) Bootstrap4.6.0 バックエンド Ruby3.0.2 Ruby on Rails 6.1.4 MySQL8.0.23 各種gem gem名 用途(記載している#は機能一覧の#を表します) devise #1のユーザー機能に使用。 carrierwavemini_magickfog-aws #1のアバター画像設定に使用。fog-awsを使用し保存先をS3バケットに設定。 httparty #4のサムネイル作成機能において、外部APIへのデータ送信およびレスポンスのHash変換に使用。 kaminari 各種ページのページネーションに使用。 counter_culture 一部モデルの件数を取得する際のN+1問題回避のため使用。 bullet N+1問題の検出に使用。 better_errorsbinding_of_caller エラー画面を見やすくするために使用 rspecfactory_bot_railsrubocop テストに使用 インフラ 本番環境 AWS(VPC、EC2、RDS、S3、Route53、ALB、ACM、IAM) Nginx1.20.0 Unicorn6.0.0 Capistrano3.16.0 CircleCI2.1 開発環境 Docker20.10.8 docker-compose1.29.2 その他のツール git2.25.1 / GitHub インフラ構成図 ローカルではWSL2とDocker、docker-composeを使用して開発しています。 ローカルで開発した内容をGitHubへpush→CircleCIで自動テスト(RuboCop&RSpec)→CapistranoでEC2上に自動デプロイという流れを経て公開しています。 ユーザーからの接続はRoute53を使用して独自ドメイン化、ALBとACMを使用して常時SSL接続を使用するよう設定しています。 EC2内ではwebサーバーにNginx、アプリケーションサーバーにUnicornを使用しています。 ユーザーのアバター画像用にS3バケットを使用しています。 投稿時のサムネイル作成用に外部サービスlinkpreviewのAPIを使用しています。 ER図 投稿時にはアイテム名を入力しますが、入力されたアイテム名でItemテーブルを検索し、同名アイテムが見つかれば既存レコードを使用、見つからなければ新規レコードを作成します。 投稿時にはタグ名を入力できますが、PostTagMapテーブルを中間テーブルとたTagテーブルを入力されたタグ名で検索し、同様に既存レコード使用or新規レコード作成を行います。 どちらのテーブルも同名のレコードが存在する場合はそれを引用、同名が見つからない場合のみ新規レコードを作成することでデータ数が無駄に増加するのを抑えています。 工夫した点 非同期通信(Ajax) 各種ページに非同期通信を採用し、リロードによるストレスを軽減するよう心がけました。 フォロー・いいね・コメントのAjax化 各種ページのタブ切替のAjax化 検索結果表示のAjax化 サムネイルの自動生成(外部API) 投稿作成時に入力した参考URLをもとに、サムネイルを自動生成する機能を実装しました。 背景として、アイテム名を見ただけでは他のユーザーが面白そうかイメージがわかないため、何か画像が欲しいと考えました。 とはいえ投稿者がいちいち画像を用意して添付するのは手間が増えすぎるため、linkpreviewという外部APIを利用しています。 このAPIでは投稿者が入力したURLをもとにサムネイル用のデータをJSONで返す機能が利用できるため、メソッドに組み込んでPostテーブルにサムネイル関連情報を保存→viewで表示できるよう実装しました。 小さな工夫として、サムネイル作成に少し時間がかかるためローディングサークルを表示して待機時間と分かるようにしました。 ランキング機能 利用者に人気のあるアイテムのトレンドが知れるようランキング機能を設けました。 タイムラインだけではフォローしている知人の興味しかわかりませんが、ランキングにより全く別傾向のものにも出会えます。 全ユーザー/フォローのみ、週間/月間/全期間での条件ごとでランキングを表示できます。 ここから気になったユーザーをフォローするなどして、面白いものをどんどん見つけられます。 今後の課題 転職活動をしつつ、下記のような改善を加えていければと考えています。 公開範囲の指定:投稿をフォロワーにのみ公開する設定 通知機能:フォロー、いいね、コメント等の通知 ソート機能:アイテムやユーザーの一覧ページにソート機能を追加(現在はID順のみ) インクリメンタルサーチ:検索結果を即時表示できるように 日程調整機能:ユーザー間で共通のものに興味を持っている際、複数ユーザー間でプライベートに日程を調整できる機能 評価機能:気になったものを実際に試した後に★などでランク付け GoogleChrome拡張機能:少し趣向が変わりますが、外部のページを開いている際にそのページ上で投稿できる拡張機能があるとものすごく便利になりそうです 感想 自分で考えたものがどんどん形になっていくため、製作していてとても面白かったです。 また、転職活動自体への有効性は別としても、ポートフォリオを作ることで自分の好きな領域や苦手な領域がだんだんわかってくるのも今後のキャリアプラン検討の糧にできそうです。 ポートフォリオ作成前の学習段階においては様々な書籍やサービス・記事を参考にさせていただきましたが、現在は独学でエンジニアを目指す方も増えているようで、ある程度学習のロードマップが確立されていることもあり助かりました。 とはいえ、勉強を一通り終えていざポートフォリオ作成!となると何から手を付けるのか分からなかったり、エラーが多発したりと苦労の連続でしたが、乗り越えた時の快感はたまらないものがありますね。 前述の本ポートフォリオの改善しかり、引き続き精進します! ここまで読んでいただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS CloudFormation】ロール作成を通してポリシーとロールの関係を理解する

CloudFormationでRoleを作成しようとしたところ、かなりハマってしまったので、ポリシーとロールの現状の理解をまとめておこうと思います。 ■ ポリシーとは ポリシーとは、だれが 、 どんな操作を 、 どのリソースに対して 行えるかを定義する仕組みです。 ポリシーの定義は主に下記の要素で構成されています。 Principal 誰が に相当する項目。IAMユーザー(ロール)やAWSサービスを指定します。 Action どんな操作を に相当する項目。 s3:GetObjec のようにAWSサービスとその操作を : 区切りで指定します。 Resource どのリソースに対して に相当する項目。 arn:aws:s3:::DOC-EXAMPLE-BUCKET/* のように操作対象のリソースを指定します。 Effect 操作を許可する( Allow )か、許可しない( Deny ) かを指定します。 例えば、S3の読み込み専用ポリシー( AmazonS3ReadOnlyAccess )の定義はこんな感じ AmazonS3ReadOnlyAccess { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:Get*", // *はワイルドカード "s3:List*" ], "Resource": "*" } ] } ◎ ポリシータイプ そんなポリシーにはいくつか種類があります。。。が、今回は必要な2に絞って理解していきます。 アイデンティティベースのポリシー リソースベースのポリシー ◎ 1. アイデンティティベースのポリシー IAM アイデンティティ (ユーザー、ユーザーのグループ、ロール)にアタッチするポリシーで、アタッチされたIAMアイデンティティが どのリソースに対して(Resource) 、 どんな操作を(Action) 行えるのかを定義します。 誰が(Principal) はアタッチされたIAMアイデンティティであるため、 Principal のセクションは指定しません。 アイデンティティベースのポリシーには次のような分類があります。 AWS管理ポリシー AWSが用意している再利用可能なポリシー カスタマー管理ポリシー ユーザー側で作成した再利用可能なポリシー インラインポリシー 各IAMアイデンティティに直接追加するポリシー ※ 管理ポリシーとインラインポリシーの比較 例) S3のフルアクセスポリシー AmazonS3FullAccess { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] } ◎ 2. リソースベースのポリシー リソースベースのポリシーはAWSリソースにアタッチするポリシーで、リソースが 誰に(Principal) 、 どんな操作を(Action) 許可するのかを定義します。 どのリソースに対して(Resource) はアタッチされたリソースであるため、 Resource セクションは指定しません。 リソースベースのポリシーにはS3のバケットポリシーやIAMロールの信頼ポリシーがあります。 今回理解しておかなければならないのは IAMロールの信頼ポリシー です。 # IAMロールの信頼ポリシー IAMロールの信頼ポリシーとはIAMロールにアタッチするポリシーで、アタッチされたIAMロールが保有する権限をIAMアイデンティティやAWSサービスに移譲することができます。 例えば、このポリシーはIAMロールが保有する権限をAWS Lambdaに移譲できます。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { // "AWS": ["arn:aws:iam::AWS-account-ID:user/user-name-1"] のようにIAMアイデンティティを指定してもOK "Service": ["lambda.amazonaws.com"] }, "Action": "sts:AssumeRole", } ] } ■ ロールとは IAMロールはアイデンティティベースのポリシー(Policies) と IAMロールの信頼ポリシー(AssumeRolePolicyDocument) から成り立っており、アイデンティティベースのポリシー の権限を IAMロールの信頼ポリシー で指定したIAMアイデンティティやAWSサービスに移譲することができます。 ■ CloudFormationでロールを作成 ポリシーとロールを理解したところで、CloudFormationでロールを作成していきます。 ◎ 設定項目 RoleName: 任意のロール名を指定します。 AssumeRolePolicyDocument IAMロールの信頼ポリシーを定義します。 IAMロールの権限を Principal に移譲するための信頼ポリシーを指定します。 Version: 2012-10-17 が現行 Statement: ポリシーを定義します。(配列形式) Effect: 操作の許可( Allow )・不許可( Deny )を指定します。 Action: s3:GetObject のように、どのAWSサービスの何の操作を対象とするのかを配列形式で指定します。 Principal: ポリシーを適用するIAMアイデンティティ、AWSサービスなどを指定します。 IAMユーザー: "AWS": ["arn:aws:iam::AWS-account-ID:user/user-name-1"] IAMロール: "AWS": "arn:aws:iam::AWS-account-ID:role/role-name" AWSサービス: "Service": ["ecs.amazonaws.com"] ManagedPolicyArns: 管理ポリシー(アイデンティティベースのポリシー)のARNを配列形式で指定します。 Policies: インラインポリシー(アイデンティティベースのポリシー)を配列形式で定義します。 PolicyName: ポリシー名を指定します。 PolicyDocument Version: 2012-10-17 が現行 Statement: ポリシーを定義します。(配列形式) Effect: 操作の許可( Allow )・不許可( Deny )を指定します。 Action: s3:GetObject のように、どのAWSサービスの何の操作を対象とするのかを配列形式で指定します。 Resource: 操作対象のリソースを指定します。 ◎ テンプレート 管理ポリシーを利用するパターンと、インラインポリシーを利用するパターン、2種類の定義を作成します。 AWSTemplateFormatVersion: '2010-09-09' Resources: # 1. 管理ポリシーを利用してRoleを定義 SampleRole01: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: # IAMロールの信頼ポリシーの定義 Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - lambda.amazonaws.com # AWS Lambdaにロールを適用できるように設定 ManagedPolicyArns: # 管理ポリシー(アイデンティティベースのポリシー)の指定 - arn:aws:iam::aws:policy/TranslateFullAccess RoleName: sample-role-01 # 2. インラインポリシーを利用してRoleを定義 SampleRole02: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: # IAMロールの信頼ポリシーの定義 Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - lambda.amazonaws.com # AWS Lambdaにロールを適用できるように設定 Policies: # インラインポリシーを定義 - PolicyName: hoge PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - translate:* - comprehend:DetectDominantLanguage - cloudwatch:GetMetricStatistics - cloudwatch:ListMetrics - s3:ListAllMyBuckets - s3:ListBucket - s3:GetBucketLocation - iam:ListRoles - iam:GetRole Resource: '*' RoleName: sample-role-02 ■ 参考記事 【初心者向け】IAMポリシー(JSON)の見方 AWS IAMポリシーを理解する | DevelopersIO IAMロール徹底理解 〜 AssumeRoleの正体 | DevelopersIO IAM でのポリシーとアクセス許可 | aws 管理ポリシーとインラインポリシー | aws IAM JSON ポリシーの要素のリファレンス | aws AWS::IAM::Role | aws
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む