20200805のAWSに関する記事は16件です。

デプロイ方法①(AWS/EC2)

※デプロイの方法の手順① 今後の自分のメモ用に

EC2インスタンスを作成

AWSアカウントにログイン。トップページに遷移したら、左上の「サービス」から「EC2」を選択。
1.png

操作画面を旧バージョンに切り替えるため、左上のスイッチのアイコンをクリック。「New EC2 Experience」
2.png

アンケート用のダイアログが開くのでキャンセルを選択。
3.png

以下の画像の「インスタンスの作成」をクリック。
4.png

AMIの選択

AMIとは、「Amazon Machine Image」の略語で、サーバのデータをまるごと保存したデータのこと。
この中には、OSやWEBサーバなどが事前にインストールされているものもあり、自分でゼロからインストールする手間を削減することができます。

「 Amazon Linux AMI 」という、AWSが独自にカスタマイズしたAMIを利用しましょう。

5.png
・「AMIの選択」になっていることを確認
・「クイックスタート」を選択
・Amazon Linux AMIを選択
※「 Amazon Linux2 AMI 」ではなく、「 Amazon Linux AMI 」を選択

EC2インスタンスのタイプ選択

EC2ではさまざまなインスタンスタイプが用意されており、CPUやメモリなどのスペックを柔軟に指定することができます。無料枠で利用できる「t2.micro」を選択。
6.png
・「インスタンスタイプの選択」になっていることを確認
・「t2.micro」になっていることを確認
・「確認と作成」をクリック

7.png
・起動をクリック

キーペアのダウンロード

内容を確認する際に、「キーペア」をダウンロードすることが出来ます。こちらはインスタンスにSSHでログインする際に必要となる「秘密鍵」です。これがないとEC2インスタンスにログインできないので、必ずダウンロードしてパソコンに保存しておきましょう。また、間違って他人に渡さないよう気をつけてください。

キーペアの名前はご自身で決めて大丈夫です。

※キーペアの名前にスペースが含まれているとこの後の作業でエラーが発生する可能性があります。 スペースを含まない名前の秘密鍵を作成するようにしましょう!
8.png
・「新しいキーペアを作成」を選択
・キーペア名の名前を入力(App名)
・「キーペアのダウンロード」クリック

・キーペアのダウンロードが完了すると、クリック出来ない状態になっていた「インスタンスの作成」が、クリックできるように変更されます。そちらをクリックして、EC2インスタンスを作成。

インスタンスの作成

インスタンス一覧画面に戻り、作成した「インスタンスID」をコピーしてメモしておきましょう。

Elastic IPの作成と紐付け

作成したEC2インスタンスには、作成時にIPアドレスが自動で割り振られています。これをパブリックIPと言います。
しかし、サーバーを再起動させるたびにこのパブリックIPが変わってしまうという欠点を持っています。IPが変わってしまうということは、設定ファイル等をその都度書き換えなければいけません。これを解決してくれるのが、Elastic IPです。

Elastic IP

Elastic IPとは、AWSから割り振られた固定のパブリックIPアドレスのこと。
このパブリックIPアドレスをEC2インスタンスに紐付けることで、インスタンスの起動、停止に関わらず常に同じIPアドレスで通信をすることが可能になります。

9.png

・Elastic IPを取得するために、「Elastic IP」を選択し、「新しいアドレスの割り当て」をクリック

10.png
・Amazonプールを選択
・「割り当て」をクリック
・ELAstic IPを確認し、「閉じる」をクリック

次に、取得したElastic IPアドレスを、作成したEC2インスタンスと紐付け
先ほど、取得したElastic IPアドレスを選択し、「アクション」から「アドレスの関連付け」へ
11.png

12.png

インスタンスを選択すると、その下にあるプライベートIPアドレスが自動で選択されます。
再びインスタンス一覧画面に戻り、作成したインスタンスの「パブリック IP」と「Elastic IP」が同じものに設定されていることを確認しましょう。

以降、このIPアドレスはあなたの所有物のようになり、意図的にAWSに返却しない限り、変更されることはありません。

13.png

ポートを開く

立ち上げたばかりのEC2インスタンスはSSHでアクセスすることはできますが、HTTPなどの他の接続は一切つながらないようになっています。そのため、WEBサーバとして利用するEC2インスタンスは事前にHTTPがつながるように「ポート」を開放する必要があります。

セキュリティグループとは

ポートの設定をするためには、「セキュリティグループ」という設定を変更する必要があります。
セキュリティグループとは、EC2インスタンスが属するまとまりのようなもので、複数のEC2インスタンスのネットワーク設定を一括で行うためのものです。

セキュリティグループのポートを設定する

セキュリティグループのポートを設定。
EC2インスタンス一覧画面から、対象のインスタンスを選択し、「セキュリティグループ」のリンク(図中では「launch-wizard-1」)をクリック。
14.png

インスタンスの属するセキュリティグループの設定画面に移動するので、「インバウンド」タブの中の「編集」をクリック。
15.png

モーダルが開くので、「ルールの追加」をクリック。
タイプを「HTTP」、プロトコルを「TCP」、ポート範囲を「80」、送信元を「カスタム / 0.0.0.0/0, ::/0」に設定。
「0.0.0.0」や「::/0」は「全てのアクセスを許可する」という意味
16.png

※必ず「ルールの追加」を行い、元の「ssh」の設定がなくならないよう注意してください

以上で、ポートの開放が完了です。

この作業が終わっていないと、WEBサーバを起動した時にアクセスできなくなるので注意してください。

EC2インスタンスへのログイン

EC2インスタンスを作成すると、ec2-userというユーザーと対応するSSH秘密鍵が生成されました。
本来はこのec2-userではなく、サービスを稼働させるためにより権限を小さくしたユーザーを作成して運用していきますが、ここでは簡易化のためにこのec2-userを使って作業を進めていきます。

ec2-userでログイン

  1. 以下の「ダウンロードした鍵の名前」の部分は、直前にご自身がダウンロードした.pemというファイルの名前に置き換えてください。
  2. pemキーが本当にDownloads以下に存在するかFinderで確認しましょう ※存在しなければ他のディレクトリを確認しましょう
$ cd ~

$ mkdir ~/.ssh
# .sshというディレクトリを作成
# File existsとエラーが表示されたとしても、.sshディレクトリは存在しているということなので、そのまま進みましょう。

$ mv Downloads/ダウンロードした鍵の名前.pem .ssh/
# mvコマンドで、ダウンロードしたpemファイルを、ダウンロードディレクトリから、.sshディレクトリに移動します。

$ cd .ssh/

$ ls
# pemファイルが存在するか確認しましょう

$ chmod 600 ダウンロードした鍵の名前.pem

$ ssh -i ダウンロードした鍵の名前.pem ec2-user@作成したEC2インスタンスと紐付けたElastic IP
#(例えばElastic IPが123.456.789であれば、ssh -i ダウンロードした鍵の名前.pem ec2-user@123.456.789 というコマンドになります)
#(ダウンロードした鍵を用いて、ec2-userとしてログイン)

Elastic IP は、AWSアカウントから確認してください。

以下の様なメッセージが表示されることがありますが、「yes」と入力して下さい。

$ ssh -i aws_key.pem ec2-user@52.68.~~~~~~
The authenticity of host '52.68.~~~~~~ (52.68.~~~~~~)' can't be established.
RSA key fingerprint is eb:7a:bd:e6:aa:da:~~~~~~~~~~~~~~~~~~~~~~~~.
Are you sure you want to continue connecting (yes/no)? 

ターミナルのコマンド待ちの際の左側の表示が、
[ec2-user| ...

となればログイン成功。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デプロイ方法(AWS/EC2)

※デプロイの方法の手順① 今後の自分のメモ用に

EC2インスタンスを作成

AWSアカウントにログイン。トップページに遷移したら、左上の「サービス」から「EC2」を選択。
1.png

操作画面を旧バージョンに切り替えるため、左上のスイッチのアイコンをクリック。「New EC2 Experience」
2.png

アンケート用のダイアログが開くのでキャンセルを選択。
3.png

以下の画像の「インスタンスの作成」をクリック。
4.png

AMIの選択

AMIとは、「Amazon Machine Image」の略語で、サーバのデータをまるごと保存したデータのこと。
この中には、OSやWEBサーバなどが事前にインストールされているものもあり、自分でゼロからインストールする手間を削減することができます。

「 Amazon Linux AMI 」という、AWSが独自にカスタマイズしたAMIを利用しましょう。

5.png
・「AMIの選択」になっていることを確認
・「クイックスタート」を選択
・Amazon Linux AMIを選択
※「 Amazon Linux2 AMI 」ではなく、「 Amazon Linux AMI 」を選択

EC2インスタンスのタイプ選択

EC2ではさまざまなインスタンスタイプが用意されており、CPUやメモリなどのスペックを柔軟に指定することができます。無料枠で利用できる「t2.micro」を選択。
6.png
・「インスタンスタイプの選択」になっていることを確認
・「t2.micro」になっていることを確認
・「確認と作成」をクリック

7.png
・起動をクリック

キーペアのダウンロード

内容を確認する際に、「キーペア」をダウンロードすることが出来ます。こちらはインスタンスにSSHでログインする際に必要となる「秘密鍵」です。これがないとEC2インスタンスにログインできないので、必ずダウンロードしてパソコンに保存しておきましょう。また、間違って他人に渡さないよう気をつけてください。

キーペアの名前はご自身で決めて大丈夫です。

※キーペアの名前にスペースが含まれているとこの後の作業でエラーが発生する可能性があります。 スペースを含まない名前の秘密鍵を作成するようにしましょう!
8.png
・「新しいキーペアを作成」を選択
・キーペア名の名前を入力(App名)
・「キーペアのダウンロード」クリック

・キーペアのダウンロードが完了すると、クリック出来ない状態になっていた「インスタンスの作成」が、クリックできるように変更されます。そちらをクリックして、EC2インスタンスを作成。

インスタンスの作成

インスタンス一覧画面に戻り、作成した「インスタンスID」をコピーしてメモしておきましょう。

Elastic IPの作成と紐付け

作成したEC2インスタンスには、作成時にIPアドレスが自動で割り振られています。これをパブリックIPと言います。
しかし、サーバーを再起動させるたびにこのパブリックIPが変わってしまうという欠点を持っています。IPが変わってしまうということは、設定ファイル等をその都度書き換えなければいけません。これを解決してくれるのが、Elastic IPです。

Elastic IP

Elastic IPとは、AWSから割り振られた固定のパブリックIPアドレスのこと。
このパブリックIPアドレスをEC2インスタンスに紐付けることで、インスタンスの起動、停止に関わらず常に同じIPアドレスで通信をすることが可能になります。

9.png

・Elastic IPを取得するために、「Elastic IP」を選択し、「新しいアドレスの割り当て」をクリック

10.png
・Amazonプールを選択
・「割り当て」をクリック
・ELAstic IPを確認し、「閉じる」をクリック

次に、取得したElastic IPアドレスを、作成したEC2インスタンスと紐付け
先ほど、取得したElastic IPアドレスを選択し、「アクション」から「アドレスの関連付け」へ
11.png

12.png

インスタンスを選択すると、その下にあるプライベートIPアドレスが自動で選択されます。
再びインスタンス一覧画面に戻り、作成したインスタンスの「パブリック IP」と「Elastic IP」が同じものに設定されていることを確認しましょう。

以降、このIPアドレスはあなたの所有物のようになり、意図的にAWSに返却しない限り、変更されることはありません。

13.png

ポートを開く

立ち上げたばかりのEC2インスタンスはSSHでアクセスすることはできますが、HTTPなどの他の接続は一切つながらないようになっています。そのため、WEBサーバとして利用するEC2インスタンスは事前にHTTPがつながるように「ポート」を開放する必要があります。

セキュリティグループとは

ポートの設定をするためには、「セキュリティグループ」という設定を変更する必要があります。
セキュリティグループとは、EC2インスタンスが属するまとまりのようなもので、複数のEC2インスタンスのネットワーク設定を一括で行うためのものです。

セキュリティグループのポートを設定する

セキュリティグループのポートを設定。
EC2インスタンス一覧画面から、対象のインスタンスを選択し、「セキュリティグループ」のリンク(図中では「launch-wizard-1」)をクリック。
14.png

インスタンスの属するセキュリティグループの設定画面に移動するので、「インバウンド」タブの中の「編集」をクリック。
15.png

モーダルが開くので、「ルールの追加」をクリック。
タイプを「HTTP」、プロトコルを「TCP」、ポート範囲を「80」、送信元を「カスタム / 0.0.0.0/0, ::/0」に設定。
「0.0.0.0」や「::/0」は「全てのアクセスを許可する」という意味
16.png

※必ず「ルールの追加」を行い、元の「ssh」の設定がなくならないよう注意してください

以上で、ポートの開放が完了です。

この作業が終わっていないと、WEBサーバを起動した時にアクセスできなくなるので注意してください。

EC2インスタンスへのログイン

EC2インスタンスを作成すると、ec2-userというユーザーと対応するSSH秘密鍵が生成されました。
本来はこのec2-userではなく、サービスを稼働させるためにより権限を小さくしたユーザーを作成して運用していきますが、ここでは簡易化のためにこのec2-userを使って作業を進めていきます。

ec2-userでログイン

  1. 以下の「ダウンロードした鍵の名前」の部分は、直前にご自身がダウンロードした.pemというファイルの名前に置き換えてください。
  2. pemキーが本当にDownloads以下に存在するかFinderで確認しましょう ※存在しなければ他のディレクトリを確認しましょう
$ cd ~

$ mkdir ~/.ssh
# .sshというディレクトリを作成
# File existsとエラーが表示されたとしても、.sshディレクトリは存在しているということなので、そのまま進みましょう。

$ mv Downloads/ダウンロードした鍵の名前.pem .ssh/
# mvコマンドで、ダウンロードしたpemファイルを、ダウンロードディレクトリから、.sshディレクトリに移動します。

$ cd .ssh/

$ ls
# pemファイルが存在するか確認しましょう

$ chmod 600 ダウンロードした鍵の名前.pem

$ ssh -i ダウンロードした鍵の名前.pem ec2-user@作成したEC2インスタンスと紐付けたElastic IP
#(例えばElastic IPが123.456.789であれば、ssh -i ダウンロードした鍵の名前.pem ec2-user@123.456.789 というコマンドになります)
#(ダウンロードした鍵を用いて、ec2-userとしてログイン)

Elastic IP は、AWSアカウントから確認してください。

以下の様なメッセージが表示されることがありますが、「yes」と入力して下さい。

$ ssh -i aws_key.pem ec2-user@52.68.~~~~~~
The authenticity of host '52.68.~~~~~~ (52.68.~~~~~~)' can't be established.
RSA key fingerprint is eb:7a:bd:e6:aa:da:~~~~~~~~~~~~~~~~~~~~~~~~.
Are you sure you want to continue connecting (yes/no)? 

ターミナルのコマンド待ちの際の左側の表示が、
[ec2-user| ...

となればログイン成功。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS] CDKで、API Gateway + Lambda + DynamoDBなサンプルを作成してみる

はじめに

以前投稿した「[AWS] Serverless Application Model (SAM) でAPI Gateway + Lambda + DynamoDBなサンプルを作成してみる」のCDK版だと思ってください。

CDKとは?

AWS Cloud Development Kitで。クラウドアプリケーションリソースをモデル化、およびプロビジョニングするためのフレームワークです。
SAMは、Serverless Applicationに重きを置いたフレームワークだったのに対し、CDKはIaC(Infrastructure As Code)の要素が強い開発フレームワークということになります。
さらに特徴的なのは、それをYAMLやJsonではなく、複数の言語で記述できる、ということです。

対応言語

以下の言語に対応しています。

  • JavaScript
  • TypeScript
  • Python
  • Java
  • C#

前提条件

CDKを導入するうえで、まずnpmを事前に使用できる状態にしておいてください。
また、今回は言語にPythonを使用するのでpipも事前に使用できる状態にしておいてください。
あと、言わずもがなですが、AWSアカウントのご用意も忘れずに。

インストール

$ npm install -g aws-cdk
/Users/******/.nodebrew/node/v12.13.1/bin/cdk -> /Users/******/.nodebrew/node/v12.13.1/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.56.0
added 24 packages from 10 contributors, removed 12 packages and updated 22 packages in 4.342s

確認

$ cdk --version
1.56.0 (build c1c174d)

サンプルコード作成

プロジェクト作成

まず、適当な作業ディレクトリを作成し、そのディレクトリに移動します。

$ mkdir cdk
$ cd cdk

次に、プロジェクトの作成ですが、今回はpythonでプロジェクトを作成してみます。

$ cdk init --language=python
Applying project template app for python

# Welcome to your CDK Python project!

This is a blank project for Python development with CDK.

The 'cdk.json' file tells the CDK Toolkit how to execute your app.

This project is set up like a standard Python project.  The initialization
process also creates a virtualenv within this project, stored under the .env
directory.  To create the virtualenv it assumes that there is a 'python3'
(or 'python' for Windows) executable in your path with access to the 'venv'
package. If for any reason the automatic creation of the virtualenv fails,
you can create the virtualenv manually.

To manually create a virtualenv on MacOS and Linux:

'''
$ python3 -m venv .env
'''

After the init process completes and the virtualenv is created, you can use the following
step to activate your virtualenv.

'''
$ source .env/bin/activate
'''

If you are a Windows platform, you would activate the virtualenv like this:

'''
% .env\Scripts\activate.bat
'''

Once the virtualenv is activated, you can install the required dependencies.

'''
$ pip install -r requirements.txt
'''

At this point you can now synthesize the CloudFormation template for this code.

'''
$ cdk synth
'''

To add additional dependencies, for example other CDK libraries, just add
them to your 'setup.py' file and rerun the 'pip install -r requirements.txt'
command.

## Useful commands

 * 'cdk ls'          list all stacks in the app
 * 'cdk synth'       emits the synthesized CloudFormation template
 * 'cdk deploy'      deploy this stack to your default AWS account/region
 * 'cdk diff'        compare deployed stack with current state
 * 'cdk docs'        open CDK documentation

Enjoy!

Initializing a new git repository...
Please run python3 -m venv .env'!
Executing Creating virtualenv...
✅ All done!

一応、コマンド実行後に、上記のように手順が紹介されますが、一つずつ実行してみましょう。

まずは、Pythonの実行環境を仮想化します。

$ python3 -m venv .env

そして、シェルに環境変数を適用させます。

$ source .env/bin/activate

モジュールの追加

続いて、setup.pyに必要なモジュールを追加します。

変更前
    install_requires=[
        "aws-cdk.core==1.56.0",
    ],
変更後
    install_requires=[
        "aws-cdk.core==1.56.0",
        "aws-cdk.aws-apigateway",
        "aws-cdk.aws-lambda",
        "aws-cdk.aws-dynamodb"
    ],

この状態で、依存関係を追加します。

$ pip install -r requirements.txt
Obtaining file:///Users/hirtsuru/cdk (from -r requirements.txt (line 1))
Collecting aws-cdk.core==1.56.0
  Downloading aws_cdk.core-1.56.0-py3-none-any.whl (988 kB)
     |████████████████████████████████| 988 kB 985 kB/s
Collecting aws-cdk.aws-apigateway
  Downloading aws_cdk.aws_apigateway-1.56.0-py3-none-any.whl (675 kB)
     |████████████████████████████████| 675 kB 3.0 MB/s
Collecting aws-cdk.aws-lambda
  Downloading aws_cdk.aws_lambda-1.56.0-py3-none-any.whl (370 kB)
     |████████████████████████████████| 370 kB 5.1 MB/s
Collecting aws_cdk.aws_dynamodb
  Downloading aws_cdk.aws_dynamodb-1.56.0-py3-none-any.whl (167 kB)
     |████████████████████████████████| 167 kB 5.6 MB/s
Collecting constructs<4.0.0,>=3.0.2
  Downloading constructs-3.0.4-py3-none-any.whl (76 kB)
     |████████████████████████████████| 76 kB 3.5 MB/s
Collecting jsii<2.0.0,>=1.9.0
  Downloading jsii-1.9.0-py3-none-any.whl (265 kB)
     |████████████████████████████████| 265 kB 3.3 MB/s
Collecting publication>=0.0.3
  Downloading publication-0.0.3-py2.py3-none-any.whl (7.7 kB)
Collecting aws-cdk.cloud-assembly-schema==1.56.0
  Downloading aws_cdk.cloud_assembly_schema-1.56.0-py3-none-any.whl (116 kB)
     |████████████████████████████████| 116 kB 3.3 MB/s
Collecting aws-cdk.cx-api==1.56.0
  Downloading aws_cdk.cx_api-1.56.0-py3-none-any.whl (117 kB)
     |████████████████████████████████| 117 kB 5.2 MB/s
Collecting aws-cdk.aws-certificatemanager==1.56.0
  Downloading aws_cdk.aws_certificatemanager-1.56.0-py3-none-any.whl (248 kB)
     |████████████████████████████████| 248 kB 4.0 MB/s
Collecting aws-cdk.aws-s3-assets==1.56.0
  Downloading aws_cdk.aws_s3_assets-1.56.0-py3-none-any.whl (50 kB)
     |████████████████████████████████| 50 kB 4.3 MB/s
Collecting aws-cdk.aws-s3==1.56.0
  Downloading aws_cdk.aws_s3-1.56.0-py3-none-any.whl (272 kB)
     |████████████████████████████████| 272 kB 3.5 MB/s
Collecting aws-cdk.assets==1.56.0
  Downloading aws_cdk.assets-1.56.0-py3-none-any.whl (22 kB)
Collecting aws-cdk.aws-iam==1.56.0
  Downloading aws_cdk.aws_iam-1.56.0-py3-none-any.whl (345 kB)
     |████████████████████████████████| 345 kB 6.6 MB/s
Collecting aws-cdk.aws-logs==1.56.0
  Downloading aws_cdk.aws_logs-1.56.0-py3-none-any.whl (111 kB)
     |████████████████████████████████| 111 kB 7.5 MB/s
Collecting aws-cdk.aws-ec2==1.56.0
  Downloading aws_cdk.aws_ec2-1.56.0-py3-none-any.whl (926 kB)
     |████████████████████████████████| 926 kB 4.1 MB/s
Collecting aws-cdk.aws-elasticloadbalancingv2==1.56.0
  Downloading aws_cdk.aws_elasticloadbalancingv2-1.56.0-py3-none-any.whl (379 kB)
     |████████████████████████████████| 379 kB 5.3 MB/s
Collecting aws-cdk.aws-efs==1.56.0
  Downloading aws_cdk.aws_efs-1.56.0-py3-none-any.whl (76 kB)
     |████████████████████████████████| 76 kB 8.2 MB/s
Collecting aws-cdk.aws-events==1.56.0
  Downloading aws_cdk.aws_events-1.56.0-py3-none-any.whl (143 kB)
     |████████████████████████████████| 143 kB 5.9 MB/s
Collecting aws-cdk.aws-codeguruprofiler==1.56.0
  Downloading aws_cdk.aws_codeguruprofiler-1.56.0-py3-none-any.whl (35 kB)
Collecting aws-cdk.aws-sqs==1.56.0
  Downloading aws_cdk.aws_sqs-1.56.0-py3-none-any.whl (77 kB)
     |████████████████████████████████| 77 kB 8.6 MB/s
Collecting aws-cdk.aws-cloudwatch==1.56.0
  Downloading aws_cdk.aws_cloudwatch-1.56.0-py3-none-any.whl (230 kB)
     |████████████████████████████████| 230 kB 2.9 MB/s
Collecting aws-cdk.aws-kms==1.56.0
  Downloading aws_cdk.aws_kms-1.56.0-py3-none-any.whl (78 kB)
     |████████████████████████████████| 78 kB 3.8 MB/s
Collecting aws-cdk.aws-applicationautoscaling==1.56.0
  Downloading aws_cdk.aws_applicationautoscaling-1.56.0-py3-none-any.whl (122 kB)
     |████████████████████████████████| 122 kB 8.5 MB/s
Collecting aws-cdk.custom-resources==1.56.0
  Downloading aws_cdk.custom_resources-1.56.0-py3-none-any.whl (151 kB)
     |████████████████████████████████| 151 kB 11.6 MB/s
Collecting typing-extensions~=3.7.4
  Downloading typing_extensions-3.7.4.2-py3-none-any.whl (22 kB)
Collecting python-dateutil
  Using cached python_dateutil-2.8.1-py2.py3-none-any.whl (227 kB)
Collecting attrs~=19.3.0
  Using cached attrs-19.3.0-py2.py3-none-any.whl (39 kB)
Collecting cattrs~=1.0.0
  Downloading cattrs-1.0.0-py2.py3-none-any.whl (14 kB)
Collecting aws-cdk.aws-route53==1.56.0
  Downloading aws_cdk.aws_route53-1.56.0-py3-none-any.whl (122 kB)
     |████████████████████████████████| 122 kB 6.2 MB/s
Collecting aws-cdk.region-info==1.56.0
  Downloading aws_cdk.region_info-1.56.0-py3-none-any.whl (59 kB)
     |████████████████████████████████| 59 kB 4.4 MB/s
Collecting aws-cdk.aws-ssm==1.56.0
  Downloading aws_cdk.aws_ssm-1.56.0-py3-none-any.whl (151 kB)
     |████████████████████████████████| 151 kB 6.1 MB/s
Collecting aws-cdk.aws-autoscaling-common==1.56.0
  Downloading aws_cdk.aws_autoscaling_common-1.56.0-py3-none-any.whl (30 kB)
Collecting aws-cdk.aws-sns==1.56.0
  Downloading aws_cdk.aws_sns-1.56.0-py3-none-any.whl (84 kB)
     |████████████████████████████████| 84 kB 4.9 MB/s
Collecting aws-cdk.aws-cloudformation==1.56.0
  Downloading aws_cdk.aws_cloudformation-1.56.0-py3-none-any.whl (112 kB)
     |████████████████████████████████| 112 kB 6.2 MB/s
Collecting six>=1.5
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Installing collected packages: publication, typing-extensions, six, python-dateutil, attrs, cattrs, jsii, constructs, aws-cdk.cloud-assembly-schema, aws-cdk.cx-api, aws-cdk.core, aws-cdk.region-info, aws-cdk.aws-iam, aws-cdk.aws-cloudwatch, aws-cdk.aws-logs, aws-cdk.aws-kms, aws-cdk.aws-events, aws-cdk.aws-s3, aws-cdk.aws-ssm, aws-cdk.aws-ec2, aws-cdk.aws-route53, aws-cdk.assets, aws-cdk.aws-s3-assets, aws-cdk.aws-efs, aws-cdk.aws-codeguruprofiler, aws-cdk.aws-sqs, aws-cdk.aws-lambda, aws-cdk.aws-certificatemanager, aws-cdk.aws-elasticloadbalancingv2, aws-cdk.aws-apigateway, aws-cdk.aws-autoscaling-common, aws-cdk.aws-applicationautoscaling, aws-cdk.aws-sns, aws-cdk.aws-cloudformation, aws-cdk.custom-resources, aws-cdk.aws-dynamodb, cdk
  Running setup.py develop for cdk
Successfully installed attrs-19.3.0 aws-cdk.assets-1.56.0 aws-cdk.aws-apigateway-1.56.0 aws-cdk.aws-applicationautoscaling-1.56.0 aws-cdk.aws-autoscaling-common-1.56.0 aws-cdk.aws-certificatemanager-1.56.0 aws-cdk.aws-cloudformation-1.56.0 aws-cdk.aws-cloudwatch-1.56.0 aws-cdk.aws-codeguruprofiler-1.56.0 aws-cdk.aws-dynamodb-1.56.0 aws-cdk.aws-ec2-1.56.0 aws-cdk.aws-efs-1.56.0 aws-cdk.aws-elasticloadbalancingv2-1.56.0 aws-cdk.aws-events-1.56.0 aws-cdk.aws-iam-1.56.0 aws-cdk.aws-kms-1.56.0 aws-cdk.aws-lambda-1.56.0 aws-cdk.aws-logs-1.56.0 aws-cdk.aws-route53-1.56.0 aws-cdk.aws-s3-1.56.0 aws-cdk.aws-s3-assets-1.56.0 aws-cdk.aws-sns-1.56.0 aws-cdk.aws-sqs-1.56.0 aws-cdk.aws-ssm-1.56.0 aws-cdk.cloud-assembly-schema-1.56.0 aws-cdk.core-1.56.0 aws-cdk.custom-resources-1.56.0 aws-cdk.cx-api-1.56.0 aws-cdk.region-info-1.56.0 cattrs-1.0.0 cdk constructs-3.0.4 jsii-1.9.0 publication-0.0.3 python-dateutil-2.8.1 six-1.15.0 typing-extensions-3.7.4.2

Lambdaコード作成

まず、コード用のディレクトリを作成して、その下に以下コードを作成してみましょう。

$ mkdir lambda
lambda/app.py
import json
import boto3
import os
from datetime import datetime

def lambda_handler(event, context):
    try:
        event_body = json.loads(event["body"])
        if "local" in event_body and event_body["local"] == True:
            dynamodb = boto3.resource("dynamodb", endpoint_url="http://dynamodb:8000")
        else:
            dynamodb = boto3.resource("dynamodb")

        table = dynamodb.Table("Demo")
        table.put_item(
            Item={
                "Key": event_body["key"],
                "CreateDate": datetime.utcnow().isoformat()
            }
        )

        return {
            "statusCode": 200,
            "body": json.dumps({
                "message": "succeeded",
            }),
        }
    except Exception as e:
        return {
            "statusCode": 500,
            "body": json.dumps({
                "message": e.args
            }),
    }

このコードは「[AWS] Serverless Application Model (SAM) でAPI Gateway + Lambda + DynamoDBなサンプルを作成してみる」と同じものにしてあります。

デプロイとプロビジョニングコードの作成

プロジェクト直下にあるapp.pyを以下のように修正してください。

app.py
#!/usr/bin/env python3

from aws_cdk import (
    aws_apigateway,
    aws_lambda,
    aws_dynamodb,
    core
)

from aws_cdk.aws_dynamodb import (
    Table,
    Attribute,
    AttributeType
)

class LambdaSampleStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        handler = aws_lambda.Function(
            self, "backend",
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler="app.lambda_handler",
            code=aws_lambda.AssetCode(path="./lambda"))

        api = aws_apigateway.LambdaRestApi(self, "SampleLambda", handler=handler, proxy=False)
        api.root.add_resource("ddb").add_method("POST")

        table = Table(
            self, "ItemsTable",
            table_name="Demo",
            partition_key=Attribute(
                name="Key",
                type=AttributeType.STRING
            ),
            sort_key=Attribute(
                name="CreateDate",
                type=AttributeType.STRING
            )
        )
        table.grant_write_data(handler)

app = core.App()
LambdaSampleStack(app, "LambdaSampleStack")

app.synth()

この中で一つ重要な点があります。それは

table.grant_write_data(handler)

です。ここで、Lambda関数に、このテーブルへの書き込みの権限を与える宣言を行っています。
他にも読み出しや一覧など、権限がありますが、同様にLambda関数に適用してあげないと、Lambda関数からDynamoDBにアクセスすることができないので、ご注意を。

デプロイの準備

まず、デプロイ用のS3バケットを作成するために、以下のコマンドを実行してください。

$ cdk bootstrap
 ⏳  Bootstrapping environment aws://767054379442/ap-northeast-1...
CDKToolkit: creating CloudFormation changeset...



 ✅  Environment aws://767054379442/ap-northeast-1 bootstrapped.

デプロイ

ここまできたら、デプロイを実行してみます。

$ cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬───────────────┬────────┬───────────────┬───────────────┬────────────────┐
│   │ Resource      │ Effect │ Action        │ Principal     │ Condition      │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${ItemsTable. │ Allow  │ dynamodb:Batc │ AWS:${backend │                │
│   │ Arn}          │        │ hWriteItem    │ /ServiceRole} │                │
│   │               │        │ dynamodb:Dele │               │                │
│   │               │        │ teItem        │               │                │
│   │               │        │ dynamodb:PutI │               │                │
│   │               │        │ tem           │               │                │
│   │               │        │ dynamodb:Upda │               │                │
│   │               │        │ teItem        │               │                │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${SampleLambd │ Allow  │ sts:AssumeRol │ Service:apiga │                │
│   │ a/CloudWatchR │        │ e             │ teway.amazona │                │
│   │ ole.Arn}      │        │               │ ws.com        │                │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${backend.Arn │ Allow  │ lambda:Invoke │ Service:apiga"ArnLike": {   │
│   │ }             │        │ Function      │ teway.amazona │   "AWS:SourceA │
│   │               │        │               │ ws.com        │ rn": "arn:${AW │
│   │               │        │               │               │ S::Partition}: │
│   │               │        │               │               │ execute-api:${ │
│   │               │        │               │               │ AWS::Region}:$ │
│   │               │        │               │               │ {AWS::AccountI │
│   │               │        │               │               │ d}:${SampleLam │
│   │               │        │               │               │ bdaB2FF4FA1}/$ │
│   │               │        │               │               │ {SampleLambda/ │
│   │               │        │               │               │ DeploymentStag │
│   │               │        │               │               │ e.prod}/POST/d │
│   │               │        │               │               │ db"            │
│   │               │        │               │               │ }              │
│ + │ ${backend.Arn │ Allow  │ lambda:Invoke │ Service:apiga"ArnLike": {   │
│   │ }             │        │ Function      │ teway.amazona │   "AWS:SourceA │
│   │               │        │               │ ws.com        │ rn": "arn:${AW │
│   │               │        │               │               │ S::Partition}: │
│   │               │        │               │               │ execute-api:${ │
│   │               │        │               │               │ AWS::Region}:$ │
│   │               │        │               │               │ {AWS::AccountI │
│   │               │        │               │               │ d}:${SampleLam │
│   │               │        │               │               │ bdaB2FF4FA1}/t │
│   │               │        │               │               │ est-invoke-sta │
│   │               │        │               │               │ ge/POST/ddb"   │
│   │               │        │               │               │ }              │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${backend/Ser │ Allow  │ sts:AssumeRol │ Service:lambd │                │
│   │ viceRole.Arn} │        │ e             │ a.amazonaws.c │                │
│   │               │        │               │ om            │                │
└───┴───────────────┴────────┴───────────────┴───────────────┴────────────────┘
IAM Policy Changes
┌───┬────────────────────────────────────┬────────────────────────────────────┐
│   │ Resource                           │ Managed Policy ARN                 │
├───┼────────────────────────────────────┼────────────────────────────────────┤
│ + │ ${SampleLambda/CloudWatchRole}     │ arn:${AWS::Partition}:iam::aws:pol │
│   │                                    │ icy/service-role/AmazonAPIGatewayP │
│   │                                    │ ushToCloudWatchLogs                │
├───┼────────────────────────────────────┼────────────────────────────────────┤
│ + │ ${backend/ServiceRole}             │ arn:${AWS::Partition}:iam::aws:pol │
│   │                                    │ icy/service-role/AWSLambdaBasicExe │
│   │                                    │ cutionRole                         │
└───┴────────────────────────────────────┴────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
LambdaSampleStack: deploying...
[0%] start: Publishing b9d168908db593714198e01540eb08c015540d19881e7e2b8f58191486447226:current
[100%] success: Published b9d168908db593714198e01540eb08c015540d19881e7e2b8f58191486447226:current
LambdaSampleStack: creating CloudFormation changeset...










 ✅  LambdaSampleStack

Outputs:
LambdaSampleStack.SampleLambdaEndpoint9FAA5D96 = https://q63ljmbsf4.execute-api.ap-northeast-1.amazonaws.com/prod/

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:767054379442:stack/LambdaSampleStack/5e354230-d722-11ea-b846-0aec1eafc950

DynamoDBのテーブルアクセスに関するRoleが作成されていることが確認できると思います。

テスト

デプロイ時に、API Gatewayのエンドポイントが出力されるので、それを使ってURLを発行してみます。

$ curl -X POST -H "Content-Type: application/json" -d '{"key": "demo-data"}' https://q63ljmbsf4.execute-api.ap-northeast-1.amazonaws.com/prod/ddb
{"message": "succeeded"}

きた!!

ddb.png

完璧!!

まとめ

個人的には、「Infrastructure As Code」という観点だと、SAMよりCDKです。
ただ、LambdaへのDynamoDBの書き込み権限の設定など、若干癖がありますね。
これは、うまい具合にハイブリッドで使用した方がいいかもしれないです。

どちらも一長一短あると思うので、ケースに応じてどちらを使うかをチョイスしていく必要がありますね。
今回は、CDKでもSAM同様のことがある程度できた、ということが検証できました。

サンプルコードリポジトリ

https://github.com/hito-psv/cdk-demo-001

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SAA】ゲートウェイ に関する備忘録

はじめに

AWS SAAの問題でゲートウェイの理解を問うような問題が頻出だが、様々なゲートウェイがあり構成がわかりにくいため、この記事を通してゲートウェイに対する理解を深めたい。

そもそもゲートウェイとは?

英語で「出入り口」を意味する。コンピュータネットワークにおいて、通信プロトコルが異なるネットワーク同士がデータをやり取りする際、中継する役割を担うルータのような機能を備えた機器やそれに関するソフトウェアのこと。AWSでは物理的なルーターではなく、ソフトウェア的にルーティングを行なっている。ルーティングはルートテーブルに従って行われる。

試験に出題されるゲートウェイ

ゲートウェイにはインターネットゲートウェイ・仮想プライベートゲートウェイ・カスタマーゲートウェイ・NATゲートウェイが主にある。その中でも試験に出題されるものとして「インターネットゲートウェイ」と「NATゲートウェイ」が挙げられる。

・インターネットゲートウェイ

インターネットと接続するためのゲートウェイ。例えばVPC内にあるEC2インスタンスがプライベートIPアドレスしか設定できない場合、インターネットゲートウェイがリクエストとEC2インスタンスの結びつきの情報を持ち、宛先をパプリックIPアドレスからプライベートIPアドレスに変換し、該当のEC2インスタンスにリクエストを送る。

・NATゲートウェイ

プライベートサブネットからインターネットにアクセスする際に、プライベートIPアドレスからパブリックIPアドレスにアドレス変換を行う。サブネットからインターネットに接続できるが、インターネットからサブネットに接続できないようにすることが可能。

この記事のようにインターネットゲートウェイの配置場所=VPC, NATゲートウェイの配置場所=サブネットのように覚えるとわかりやすいかも。

ちなみに...NATインスタンスとNATゲートウェイの違い

・NATインスタンス

EC2>コミュニティAMI>ami-vpc-natを選択してインストールすると、NAT機能付きEC2インスタンスが作成できる。NATゲートウェイとは違い、通常のEC2インスタンスのように利用していない時は停止が可能。

・NATゲートウェイ

NAT専用に構成された仮想的なコンポーネント。配置するサブネットを選ぶだけで構成できる。NATインスタンスとは違って負荷に応じてスケールアップする。

参考

この1冊で合格! AWS認定ソリューションアーキテクト - アソシエイト テキスト&問題集
AWS しくみと技術がしっかりわかる教科書
Amazon Web Services 基礎からのネットワーク&サーバー構築
https://ejje.weblio.jp/content/gateway
https://www.keyence.co.jp/ss/general/iot-glossary/gateway.jsp

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws s3 cp コマンドでファイル結合する

s3に置いてあるファイルについて、複数ファイルをまとめたい時があります。
ファイルをダウンロードせずにファイル結合をできないものかとやってみました。

結論から言うと cp の標準入力と標準出力を駆使してみました。

aws s3 cp - s3://... : 標準入力から書き込める
aws s3 cp s3://... - : 標準出力から表示できる

こちらのclassmethod様の記事を大いに参考にさせていただいております。
https://dev.classmethod.jp/articles/aws-cli-s3-streaming/

以降にサンプルコードを書いたので参考にしてみてください。

サンプルファイル

分割されたファイルとしてこのようなファイルがあるとします。

aaa.text
aaa
aaa
aaa

bbb.txt
bbb
bbb
bbb

ccc.txt
ccc
ccc
ccc

上記のファイルが下記にあるとします。

aws s3 ls s3://hoge.bucket/concatenate_test/
2020-08-05 18:44:01         12 aaa.txt
2020-08-05 18:44:10         12 bbb.txt
2020-08-05 18:44:18         12 ccc.txt

ファイル結合

そんでこんなシェルスクリプトを実行してみます。

#!/bin/bash
(
aws s3 cp s3://hoge.bucket/concatenate_test/aaa.txt -;
aws s3 cp s3://hoge.bucket/concatenate_test/bbb.txt -;
aws s3 cp s3://hoge.bucket/concatenate_test/ccc.txt -;
) | aws s3 cp - s3://hoge.bucket/concatenate_test/abc.txt

中身を見てみると結合できてます。

aws s3 cp s3://hoge.bucket/concatenate_test/abc.txt - 
aaa
aaa
aaa
bbb
bbb
bbb
ccc
ccc
ccc

ファイル結合して圧縮

それでは圧縮しながらコンカチもやってみます。

#!/bin/bash
(
aws s3 cp s3://hoge.bucket/concatenate_test/aaa.txt -;
aws s3 cp s3://hoge.bucket/concatenate_test/bbb.txt -;
aws s3 cp s3://hoge.bucket/concatenate_test/ccc.txt -;
) | gzip | aws s3 cp - s3://hoge.bucket/concatenate_test/abc.txt.gz
aws s3 cp s3://hoge.bucket/concatenate_test/abc.txt.gz - | zcat
aaa
aaa
aaa
bbb
bbb
bbb
ccc
ccc
ccc

圧縮ファイルをファイル結合

もともとのファイルがgz圧縮されていればそのままパイプしてしまえばいですね。

#!/bin/bash
(
aws s3 cp s3://hoge.bucket/concatenate_test/aaa.txt.gz - ;
aws s3 cp s3://hoge.bucket/concatenate_test/bbb.txt.gz - ;
aws s3 cp s3://hoge.bucket/concatenate_test/ccc.txt.gz - ;
) | aws s3 cp - s3://hoge.bucket/concatenate_test/abc.txt.gz
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws-amplify? 突然 TypeError: Cannot read property 'configure' of undefined が出て何も表示されなくなった

前提条件

React + Next.js + TypeScript 環境で next start

事象

以下のコンソールエラーが出て表示は真っ白になる。ちなみに開発環境(next コマンド実行時)では問題なし。

TypeError: Cannot read property 'configure' of undefined

configure というメソッドはうちのプロダクトだと Amplify.configure しか心当たりがなかったため、そのあたりを調査。

対応

yarn add @aws-amplify/core # or npm install @aws-amplify/core
pages/_app.tsx
- import Amplify from 'aws-amplify';
+ import Amplify from '@aws-amplify/core';

これで治った。
公式ドキュメントでもどちらでも良いと記載してある。
https://github.com/aws-amplify/amplify-js#configuration

あとがき

特に aws 系のパッケージのアップデートをしたわけでもなく突然発生。
それも開発環境では発生せずステージング環境だけで発生したためやや焦った。
ビルド時に変数名とかメソッド名が圧縮されてエラーになってるのかなと推測したが原因まではつかめず。
aws-amplify だけの原因でなく、他のパッケージや環境との兼ね合いがあるかも。

ググってもあまり情報が出なかったため記しておく。
もし同様のエラーでお悩みの方はお試しあれ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AzureAD→AWS SSOへのSSO、プロビジョニング、プロビジョニング解除

これは

AzureADからAWS SSOへのSSO、プロビジョニング、プロビジョニング解除についての技術的な記事です。
プロジェクト全体の話はこちら

目次

  1. やりたいこと
  2. SSO設定
  3. プロビジョニング設定
  4. SSOテスト
  5. プロビジョニングテスト
  6. 参考
  7. 運用を考えてみる

1. やりたいこと

  • AzureADからAWS SSOへSSO、プロビジョニング、プロビジョニング解除を行う
  • AWSの権限設定はAWS SSOから行うことを想定

2. SSO設定

AzureADサイド

  1. Azure ADでエンタープライズアプリケーション登録を作成する
    ギャラリー以外のアプリケーションを選択する

  2. シングルサインオン > SAMLを選択する

  3. フェデレーション メタデータ XMLをダウンロードしておく
    スクリーンショット 2020-07-14 14.35.26.png

AWS SSOサイド

  1. AWS SSOを有効化する
  2. 設定-IDソースからIDソースをAADに変更する
  3. AWS SSO SAML メタデータをダウンロードしつつ、IdP SAML メタデータにAADでダウンロードしたメタデータXMLをアップロードする スクリーンショット 2020-07-14 14.37.31.png

AzureADサイド

  1. シングルサインオン > SAMLを選択する
  2. メタデータファイルをアップロードするから、AWS SSOでダウンロードしたSAMLメタデータをアップロードする

スクリーンショット 2020-07-14 14.41.51.png

  1. テストをクリックして問題なければ終了

3. プロビジョニング設定

AWS SSOサイド

  1. 自動プロビジョニングを有効化して、SCIMエンドポイントアクセストークンを取得する

AzureADサイド

  1. プロビジョニングを選択して、前の手順で取得した情報をテナントURLシークレットトークンに入力する
    スクリーンショット 2020-07-14 14.48.11.png

  2. テスト接続して問題ないことを確認する

  3. マッピング > AADユーザプロビジョニングを選択

  4. 下記2つの属性は使用しないため、削除する
    facsimileTelephoneNumber属性
    mobile属性

  5. mailNickname属性を編集して、ソースをObjectIDに変更
    スクリーンショット 2020-07-14 14.54.01.png

  6. ユーザ、もしくはグループを割り当てて同期を開始する
    スクリーンショット 2020-07-14 16.41.42.png

4. SSOテスト

  1. AWS SSOポータルにアクセスして、Microsoftの認証画面にリダイレクトされることを確認する

スクリーンショット 2020-07-15 11.54.17.png

  1. 認証完了したらSSOポータルにログイン完了
    スクリーンショット 2020-07-15 11.56.49.png

  2. AWS CLI SSOの初期設定

~# aws configure sso                                   
SSO start URL [None]: https://XXXXXXXX.awsapps.com/start                    
SSO Region [None]: ap-southeast-1                                               
Attempting to automatically open the SSO authorization page in your default browser.
If the browser does not open or you wish to use a different device to authorize this request, open the following URL:

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

Then enter the code:

GDRN-CPLB
The only AWS account available to you is: XXXXXXXX
Using the account ID XXXXXXXX
The only role available to you is: AdministratorAccess
Using the role name "AdministratorAccess"
CLI default client Region [ap-southeast-1]:                                     
CLI default output format [text]:                                               
CLI profile name [AdministratorAccess-XXXXXXXX]:                            

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

aws s3 ls --profile AdministratorAccess-XXXXXXXX
~# 

例としてS3一覧を表示してみる & SSOプロファイルを確認(IAMユーザ13banを使用)

~# aws2 s3 ls --profile AdministratorAccess-XXXXXXXX
2020-05-25 14:13:25 cf-templates-85l05w5jl33g-ap-southeast-1
~#
~# aws2 sts get-caller-identity
XXXXXXXX    arn:aws:iam::XXXXXXXX:user/13ban    AIDA53625ATMJMVMYDQJW
~# 

5. プロビジョニングテスト

  1. グループ参加させたらプロビジョニングできた
  2. グループから削除したらAWS SSOユーザは無効化された

6. 参考

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-sso.html
https://aws.amazon.com/jp/blogs/developer/aws-cli-v2-now-supports-aws-single-sign-on/

7. 運用を考えてみる

新規

  • 入社時にAzureADでエンジニアグループに入れる
    • アカウントの属性値を設定するとこで、自動でグループ参加させる
  • 自動でAWS SSOユーザが作成される
    • 現在、AWSユーザ持っていない人も作成されるが権限設定しなければ問題なし
  • AWS SSOサイドで権限を設定

利用

  • AWS SSOポータル使用
  • AWS CLIから使用

変更

  • 権限の変更
    • AWS SSOから権限を変更
  • ID棚卸し
    • AzureAD
    • SSOユーザ

停止

  • AzureADでグループからメンバー削除

廃止

  • AzureADでアカウント削除
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アプリケーションの設定情報をどのAWSサービスから取得すべきか

1.はじめに

先日公開したこちらの記事では、AWS AppConfigの使いどころについて考えを書いてみました。サービスに対して安全に設定を注入するツールとしてAWS AppConfigは適したサービスだと考えています。
 とはいえ、AWS AppConfig以外にもアプリケーションが設定情報を取得する方法はいくつかあります。当記事では、そのあたりを整理したいと思います。

2. サマリ

  • 設定情報のライフサイクルを考慮した格納先の決定が重要
  • 安全なデプロイを推進する場合はAWS AppConfig
  • シークレット情報が必要な場合はParameter Store or Secrets Manager

3.アプリケーションの設定情報とは

アプリケーションを動かす上で必要な情報は様々あります。例えば、AWS Lambdaのようなサービスを利用すると、「インフラ」という部分をAWSのマネージドなサービスとして提供されて、アプリケーション開発者がすべてを実装できるケースもでてきます。すると、アプリケーションの設定情報としてAWS Lambdaの設定情報(メモリサイズ、タイムアウト値やアクティブトレーシング(AWS X-Rayへの連携)等)も含めてアプリケーションの設定情報と考えられる方もいるかもしれません。ただ、当記事では、プログラムのコード内で扱う情報で、コードに埋め込みたくない変数化された値をアプリケーションの設定情報と位置付け、AWS Lambdaのメモリサイズやタイムアウト値等の設定情報は当記事の対象外とします。

3.1 アプリケーションの設定情報

アプリケーションを動かす上で必要な情報とは・・・と考えてみると色々あります。ここでは以下の5種類を例に挙げ、当記事で対象とする設定情報の認識合わせをしたいと思います。

No. 説明 値の例
1 他のサービスに接続するためのエンドポイント情報 URL,ポート
2 他のサービスに接続するためのCredential情報 ID,Password
3 多言語対応等で必要な方法 メッセージ、ラベル、エラーメッセージ
4 アプリケーション内の制御で使う閾値 アプリ内のスロットリングの閾値等,ホワイトリスト/ブラックリスト用のID(*1)機能の有効/無効フラグ

*1 サービスを提供する中で、特定のユーザーだけ利用できるようにするためのIDリストをイメージしました。

これらの情報はアプリケーションのフェーズによっても変わりますし、実行時にも定期的、または、不定期で変化していくものと考えられます。設定情報のライフサイクルも様々で、例えば、Credential 情報は短い有効期限のものもあれば、数十日単位にローテーションさせるようなものもあるでしょうし、メッセージやラベルといったものは変化の頻度が不定で、かつ、変更頻度が低い可能性もあります。
では、これらの設定情報はどこで保持しておくとよいのでしょうか?どこで保持しておくとアプリケーションから使いやすいのでしょうか?

3.2 アプリケーションの設定情報の格納先

AWS AppConfigの記事でも書きましたが、アプリケーションの設定情報は様々な場所に格納して利用することできます。
例えば、以下の4つについては、次の観点でザックリとまとめてみました。

  • 値を設定(変更)のタイミング
  • 値を変更したい場合のビルドの必要性
  • 値を変更したい場合のデプロイの必要性
  • 値取得時のレイテンシ
No. 格納先 設定タイミング ビルド デプロイ レイテンシ 適用ケース
1 実行モジュール内に同梱するファイル ビルド前 必要 必要 設定値がコードのライフサイクルと同じ場合
2 実行モジュール外に配置し ランタイムから参照できるファイル デプロイ前 不要 必要 コードとは別のライフサイクルで設定を反映する場合
3 環境変数 デプロイ前 不要 必要 コードとは別のライフサイクルで設定を反映する場合
4 データストア 任意のタイミング 不要 不要 任意のタイミングで変更する場合

当記事では、アプリケーションの設定情報を「データストア」に格納するケース、つまり、設定情報が頻繁に変更されるようなケースでアプリケーションモジュールのデプロイをいちいち実施しなくてもよい格納先について検討します。

4. 設定情報をデータストア

4.1 データストアの種類と特徴

ここでは、アプリケーションの設定情報を格納するデータストアに該当するAWSサービスを例に挙げます。

No. 格納先 説明 設定方法 取得時のrps上限 履歴保持 型チェック 暗号化
1 AWS AppConfig アプリケーションで利用する設定をより安全にデプロイすることを支援するサービス API 記載なし なし※1 可能 なし※1
2 Parameter Store システムで取り扱う設定情報を保持するサービス。、設定データ管理と機密管理のための安全な階層型ストレージを提供。 API スループット: 40rps 最大100履歴 なし SecureStringを利用可能
3 Secrets Manager IT リソースへのアクセスに必要なシークレットの保護を支援。シークレット(パスワード)のローテーションを自動で実施。 API スループット: 取得 2000rps 更新 40 rps およそ100 なし 可能
4 Amazon DynamoDB 低レイテンシーでアクセス可能なKey-Value Store API 記載なし なし なし なし※2
5 Amazon RDS マネージドなリレーショナルデータベース SQL/RDBMSのコマンド 記載なし なし スキーマレベル なし※2

※1 AppConfigのパラメータの格納先としてParameter Storeを利用可能でその場合は履歴や暗号化も可能
※2 個々の行、列、項目を個別に暗号化するという点では暗号化機能はないため、なしと表記。

4.2 データ取得の計測

ここでは、上記の1~4のAWSサービスについて実際にアプリケーションでデータを取得して計測してみたいと思います。

A. データ取得の計測の環境

  • 取得用にAWS Lambda関数を利用(東京リージョン)。AWS Lambda(VPC内リソースにアクセスするLambdaで計測(NAT Gateway 経由でAWS APIにアクセス)
  • 取得回数は100回。
  • X-Rayを利用した取得時間で計測
  • 2020年8/18に計測

B. X-Rayの計測結果

今回利用したLambda関数は下図の「ConfigTestStac2-AppConfigTest」であり、この関数内からAWS AppConfig, Parameter Store, Secrets Manager, そして、Amazon DynamoDBに対してデータ取得のAPIを呼び出し取得を実施しました。
実施した結果、下表のとおりの取得時間となった。前回作成したAppConfigの記事では、AppConfigが遅い結果が出たが今回はなぜか速くなっており、原因はわからないです。前回と違いがあるとすれば、Configに格納したデータ量が小さいということはあるが、それでも20-30バイト程度の差であり誤差のはずなんですが・・・・。今回はこの点に対するDive Deepはやめておきます。

No. 格納先 取得時のレイテンシ(計測結果)
1 AWS AppConfig 54 ms
2 Parameter Store 81 ms
3 Secrets Manager 55 ms
4 Amazon DynamoDB 47 ms

image.png

こうした設定情報は、呼び出し頻度や必要とする応答時間に依存しますが、アプリケーションの起動時等にデータストアから取得しメモリ上にキャッシュして保持し、一定期間経過したら再度データストアから取得するのが常套手段かと思います。そうすることで、設定情報取得のレイテンシーの最小化、API呼び出し回数の最小化によるAWSサービス利用料の最小化が実現できます。ということで、そうした使い方をする場合はレイテンシーに基づいたデータストアの選定はあまり重要ではなくなります。

5.どのAWSサービスを利用すべきか。

前述した通り、私は、アプリケーションが都度、設定情報をデータストアに取りに行くことは応答時間やAWSサービス利用料、そして、スロットリングの観点からおすすめしません。もちろん、たまにしか呼ばれないアプリケーションであれば、スロットリング、応答時間、AWSサービス利用料の影響よりも、最新の設定情報を取得するほうが実装はシンプルでよいという判断もあります。今回は、頻繁に利用されるアプリケーションであるという前提で、アプリケーション内、例えばAWS Lambda関数であれば、そのグローバル変数にて設定情報を一定期間、たとえば5秒程度、保持し、取得後その時間が経過したらデータストアに問い合わせを実施する場合を想定し、考えたいと思います。

5.1. 安全なデプロイが必要ですか?

設定情報の型チェック、設定情報のデプロイ時のカナリアリリースや自動ロールバックが必要であれば、AWS AppConfigをお勧めします。AppConfigでは、前述した通り履歴管理をする機能はありませんが、ただ、CodeCommitやCodePipelineと連携することでCodeCommitで履歴を管理しデプロイプロセスもCodePipelineで記録されます。これは、こちらのブログを参照してみてください。簡単に実装可能です。AppConfigを利用することで、カナリアリリースやリニアなデプロイも可能です。もちろん、設定上の不具合が発生したらロールバックも可能です。これを利用することで、エンドユーザーへの影響を極力最小化したデプロイの実現を自動化できます。AWS AppConfigを利用しCodeCommitとCodePipelineを利用するケースは、前述の「3.2 アプリケーションの設定情報の格納先」の表に対して下表のとおりNo.5を追加した以下の形になることを意味します。アプリケーションモジュールのデプロイメントパイプラインとは別のパイプラインで設定情報をデプロイするということになります。

No. 格納先 設定タイミング ビルド デプロイ レイテンシ 適用ケース
1 実行モジュール内に同梱するファイル ビルド前 必要 必要 設定値がコードのライフサイクルと同じ場合
2 実行モジュール外に配置し ランタイムから参照できるファイル デプロイ前 不要 必要 コードとは別のライフサイクルで設定を反映する場合
3 環境変数 デプロイ前 不要 必要 コードとは別のライフサイクルで設定を反映する場合
4 データストア 任意のタイミング 不要 不要 任意のタイミングで変更する場合
5 データストア 任意のタイミング 不要 必要 任意のタイミングで変更する場合

5.2. 設定情報はシークレット等のセキュアな情報ですか?

設定情報はシークレットやセキュアな情報であれば、Parameter Store または、Secrets Managerが候補となります。もし、RDS等のパスワードでローテーションが必要なのであれば、その場合は、Secrets Mangerを利用してAWS Lambdaと連携したローテーションをすることにより、パスワード運用の手間やパスワード漏洩のリスクが軽減されるでしょう。もちろん、DynamoDBを利用し、シークレット情報設定時に設定側でAWS KMS(Key Management Service)を利用して暗号化しておけば、KMSのCMK(Customer Master Key)の利用権限がないアプリケーションは復号できないためDynamoDBでも同様のことは可能でし、AppConfig内の設定についても前述したCodeCommitに格納する際にKMSで暗号化しておけば取得後、復号して利用する際にKMSの利用権限がないアプリケーションは復号できないためアクセス制御が可能となります。

5.3.DynamoDBやParameter Storeは?

アプリケーションプログラム内の設定情報を保持する先として、DynamoDBやParameter Storeももちろん利用可能です。
先ほど安全なデプロイでおすすめしたAppConfigではおそらく複数の情報をまとめて設定することになるとおもいます。例えばあるサービスで利用する情報をJSON形式でまとめて1つの設定ファイルとして設定可能です。ただ、その設定ファイル内の個々の設定項目を個別に管理し、個別にアクセス制御したいという場合は、AppConfigでは1つの設定ファイル単位で取得・アクセスになるため、IAMで細かな設定はできません。ですから個々の設定項目単位にアクセス制御をしたい、デプロイをしたいという場合は、設定情報を階層化したパスで定義しIAMによるアクセス制御が可能なParameter Storeも利用できますし、属性単位にIAMでアクセス制御を指定可能なDynamoDBも候補になるかと思います(FGAC:Fine Grained Access Control)。

6.まとめ

アプリケーションプログラムから参照する設定情報はいろいろな特徴があると思います。デプロイ時から変更が発生しない設定情報もあれば状況に応じて設定値を変えて動作制御をするような設定情報まで様々です。設定情報のライフライクル、デプロイの独立性・しやすさ、セキュリティ等を考慮して適切なサービスを選択いただければと思います。全てを完全にカバーするサービスというものはなく、結局のところ、アプリケーションの特性や運用に求められる要件で選択することが必要ということです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【今日から始めるAWS】Amplifyを使ってReactアプリをデプロイする

はじめに

30代未経験からエンジニア転職をめざすコーディング初学者のYNと申します。お読みいただきありがとうございます。
今回ご紹介するAmplifyでは、AWSのサービスを組み合わせて、驚くほど簡単に、サーバレスなwebアプリをデプロイし、かつCI/CDパイプラインまで作ることができます。
本記事では、チュートリアルに従って進めることで、Amplifyの基本的な仕組みの理解を備忘録としてまとめさせていただきました。
また、チュートリアルの通りに進めると、(2020年8月現在)ビルドエラーによりデプロイが失敗しますので、対処法も併せてまとめておきたいと思います。

今回やったこと

チュートリアルに従い、Amplifyを使って、下記AWSサービスを組み合わせてReactアプリをデプロイしました。

  • DynamoDB
  • Cognito
  • AppSync
  • S3
  • CloudFront

スクリーンショット 2020-08-02 17.39.04.png
*上記アーキテクチャ図はこちらの記事から拝借いたしました。

1. Reactアプリをデプロイし、パイプラインを作成

チュートリアル#1に従い、githubレポジトリにcommit(masterブランチにマージ)すると自動的にデプロイされるパイプラインを作ります。
Amplifyでは、CloudFrontというAWSのCDNサービスと自動的に連携して、サーバレスにwebサイトをデプロイできます。

2. Amplifyの初期設定を行う

チュートリアル#2をに従い、Amplifyの初期設定を行います。
やることは下記3つです。

  • AmplifyCLIをローカルPCにグローバルインストール
$ npm install -g @aws-amplify/cli
$ amplify configure
  • AWSバックエンドのセットアップ
$ amplify init --appId [your-app-id]

3. Cognitoを使ってwebページにログイン機能を実装する

チュートリアル#3をに従って進めていきます。
Amplifyを使ってReactアプリをCognitoと連携させ、驚くほど簡単にユーザー管理機能を実装することができます。

やることは下記3つです。

  • Amplifyライブラリのインストール(ルートディレクトリでnode_modulesに追加)
$ npm install aws-amplify @aws-amplify/ui-react
  • Amplifyを使って認証機能の追加
$ amplify add auth
$ amplify push --y

上記の操作により、バックエンド設定ファイルが生成され、/srcaws-exports.jsが追加されます。

  • Reactに認証機能コンポーネントを追加

aws-exports.jsをフロントエンドで読み込むことにより、AmplifyのバックエンドとReactアプリをつなぐことができます。

src/index.js
// 下記をimport
import Amplify from 'aws-amplify';
import config from './aws-exports';
Amplify.configure(config);
src/app.js
import React from 'react';
import logo from './logo.svg';
import './App.css';

// 下記lコンポーネントをinportしてwrapする
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react'

function App() {
  return (
    <div className="App">
      <header>
        <img src={logo} className="App-logo" alt="logo" />
        <h1>We now have Auth!</h1>
      </header>
      <AmplifySignOut />
    </div>
  );
}

export default withAuthenticator(App);

ここで実装したユーザー管理情報は、Cognitoのコンソール画面で操作することができます。

この後、リモートのmasterブランチにマージすると自動的に変更が反映されてwebページがデプロイされます。
が、この状態ではビルドエラーが発生しますので、次に対処法をまとめます。

3-2. ビルドエラーを解決する

チュートリアルの通りに進めるとビルドエラーによりデプロイが失敗しますので、ここに対処法をまとめます。
console画面より、ビルドに関して下記3点の追加設定が必要です。

  • フロントエンドでバックエンドをデプロイする

下記のようにビルドのYML設定を追記します。
スクリーンショット 2020-08-05 11.05.28.png
上記により、フロントエンドを構築するまえに適切なバックエンド環境を構築し、内部でaws-exports.jsを生成します。これをしないと、フロントエンドのビルド時にaws-exports.jsが見つからずエラーになってしまいます。

  • フロントエンドでバックエンドリソースをデプロイするためのアクセス許可

上記のように、フロントエンドでバックエンドをデプロイするためには、ユーザーガイドに従い、サービスロールを作成する必要があります。
スクリーンショット 2020-08-05 11.44.36.png

  • ビルド設定をAmplify CLIの最新版に更新

ビルド設定のBuild image settingsを編集し、Amplify CLIのversionを最新のものに更新します。これをしないと、デフォルトのruntimeに設定されているnodeのversionが古いため、ビルドが失敗します。
スクリーンショット 2020-08-05 11.49.39.png

4. GraphQL-APIを使ってReactアプリとデータベースを連携させる

チュートリアル#4をに従い、GraphQLの初期設定、およびデータベースとの連携を行います。

*GraohQLはfacebookが開発したwebAPIで、クエリ定義の自由度が高く、一度のリクエストで効率的に多くのデータを得ることができます。stateとの連携が容易でReactと相性がよく、とても使いやすいAPIです。
やることは下記3つです。

  • GraphQL-APIとデータベースの設定
$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: notesapp
? Choose the default authorization type for the API: API Key
? Enter a description for the API key: demo
? After how many days from now the API key should expire: 7 (or your preferred expiration)
? Do you want to configure advanced settings for the GraphQL API: No, I am done.
? Do you have an annotated GraphQL schema?  No
? Do you want a guided schema creation?  Yes
? What best describes your project: Single object with fields
? Do you want to edit the schema now? Yes
  • GraphQL-APIをApp-Syncにデプロイ
$ amplify push --y

上記の操作により、AWSのApp-SyncDynamo-DBのバックエンド自動的に構築されます。また、クエリーやミューテーションの設定ファイルが自動で生成されて/src/graphqlに追加されます。(すごい)

  • GraphQLをつかってReactアプリとデータベースを連携させる
src/app.js
import React, { useState, useEffect } from "react";
import "./App.css";
import { API } from "aws-amplify";
import { withAuthenticator, AmplifySignOut } from "@aws-amplify/ui-react";
import { listNotes } from "./graphql/queries";
import {
  createNote as createNoteMutation,
  deleteNote as deleteNoteMutation,
} from "./graphql/mutations";

const initialFormState = { name: "", description: "" };

function App() {
  const [notes, setNotes] = useState([]);
  const [formData, setFormData] = useState(initialFormState);

  useEffect(() => {
    fetchNotes();
  }, []);
  async function fetchNotes() {
    const apiData = await API.graphql({ query: listNotes });
    setNotes(apiData.data.listNotes.items);
  }

  async function createNote() {
    if (!formData.name || !formData.description) return;
    await API.graphql({
      query: createNoteMutation,
      variables: { input: formData },
    });
    setNotes([...notes, formData]);
    setFormData(initialFormState);
  }

  async function deleteNote({ id }) {
    const newNotesArray = notes.filter((note) => note.id !== id);
    setNotes(newNotesArray);
    await API.graphql({
      query: deleteNoteMutation,
      variables: { input: { id } },
    });
  }
  return (
    <div className="App">
      <h1>My Notes App</h1>
      <input
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        placeholder="Note name"
        value={formData.name}
      />
      <input
        onChange={(e) =>
          setFormData({ ...formData, description: e.target.value })
        }
        placeholder="Note description"
        value={formData.description}
      />
      <button onClick={createNote}>Create Note</button>
      <div style={{ marginBottom: 30 }}>
        {notes.map((note) => (
          <div key={note.id || note.name}>
            <h2>{note.name}</h2>
            <p>{note.description}</p>
            <button onClick={() => deleteNote(note)}>Delete note</button>
          </div>
        ))}
      </div>
      <AmplifySignOut />
    </div>
  );
}

export default withAuthenticator(App);

5. S3を使ってReactアプリに写真を保存する

チュートリアル#5をに従い、ReactアプリとS3を連携させて、写真をストレージに保存できるようにします。

やることは下記3つです。

  • GraphQLスキーマの更新
amplify/backend/api/notesapp/schema.graphql
type Note @model {
  id: ID!
  name: String!
  description: String
  image: String
}
  • S3によるストレージ機能の追加
$ amplify add storage
$ amplify push --y
  • ReactアプリとS3を連携させる
src/app.js
import React, { useState, useEffect } from "react";
import "./App.css";
import { API, Storage } from "aws-amplify";
import { withAuthenticator, AmplifySignOut } from "@aws-amplify/ui-react";
import { listNotes } from "./graphql/queries";
import {
  createNote as createNoteMutation,
  deleteNote as deleteNoteMutation,
} from "./graphql/mutations";

const initialFormState = { name: "", description: "" };

function App() {
  const [notes, setNotes] = useState([]);
  const [formData, setFormData] = useState(initialFormState);

  useEffect(() => {
    fetchNotes();
  }, []);

  async function fetchNotes() {
    const apiData = await API.graphql({ query: listNotes });
    const notesFromAPI = apiData.data.listNotes.items;
    await Promise.all(
      notesFromAPI.map(async (note) => {
        if (note.image) {
          const image = await Storage.get(note.image);
          note.image = image;
        }
        return note;
      })
    );
    setNotes(apiData.data.listNotes.items);
  }

  async function createNote() {
    if (!formData.name || !formData.description) return;
    await API.graphql({
      query: createNoteMutation,
      variables: { input: formData },
    });
    if (formData.image) {
      const image = await Storage.get(formData.image);
      formData.image = image;
    }
    setNotes([...notes, formData]);
    setFormData(initialFormState);
  }

  async function deleteNote({ id }) {
    const newNotesArray = notes.filter((note) => note.id !== id);
    setNotes(newNotesArray);
    await API.graphql({
      query: deleteNoteMutation,
      variables: { input: { id } },
    });
  }

  async function onChange(e) {
    if (!e.target.files[0]) return;
    const file = e.target.files[0];
    setFormData({ ...formData, image: file.name });
    await Storage.put(file.name, file);
    fetchNotes();
  }

  return (
    <div className="App">
      <h1>My Notes App</h1>
      <input
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        placeholder="Note name"
        value={formData.name}
      />
      <input
        onChange={(e) =>
          setFormData({ ...formData, description: e.target.value })
        }
        placeholder="Note description"
        value={formData.description}
      />
      <input type="file" onChange={onChange} />
      <button onClick={createNote}>Create Note</button>
      <div style={{ marginBottom: 30 }}>
        {notes.map((note) => (
          <div key={note.id || note.name}>
            <h2>{note.name}</h2>
            <p>{note.description}</p>
            <button onClick={() => deleteNote(note)}>Delete note</button>
            {note.image && <img src={note.image} style={{ width: 400 }} />}
          </div>
        ))}
      </div>
      <AmplifySignOut />
    </div>
  );
}

export default withAuthenticator(App);

これで、Cognito AppSync S3を組み合わせてReactアプリをデプロイすることができました。

最後に

Amplifyを使うことで、モダンなサーバーレスアプリを簡単にデプロイすることができます。コーディング初学者には敷居が高く感じられるAWSですが、とても親近感を感じることができました。
チュートリアルには、「50分で終わる」と書かれていましたが、コーディング初心者でもその程度で出来ました。如何にAmplifyが素晴らしいサービスであるかが納得いただけるかと思います。(ただし、ビルドエラーの対処には3日かかりました。苦笑)

お読みいただきありがとうございました。

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ターミナルでインスタンスへログインできなかった

AWSにアプリケーションをデプロイしようと思い
インスタンスへ下記のようにログインしたらエラーになる

.ssh % ssh -i sample01.pem ec2-user@54.196.78.41 

と入力すると

.ssh/config: line 5: Bad configuration option: idenityfile
.ssh/config: terminating, 1 bad configuration options

このようなエラーが・・・
sshの5行目の設定がおかしいと言われているので設定ファイルを開く

.ssh % vi /.ssh/config

下記のような設定ファイルが開く

Host sample01_key_rsa
  HostName パブリックIP
  Port 22
  User ユーザ名
  IdenityFile ~/.ssh/sample01_key_rsa

自分の場合は5行目に正しくは
IdentityFile と記載するところを
IdenityFile とスペルが間違っていた

これを正しく書き換えるとログインできた

※ちなみにこの設定ファイルはiで編集モードに入れて終わったら
Esc → Shift+zzで保存できる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSサービスを利用した際、Kubenetesで起こりうるアクセス管理の問題への対処方法

image.png

はじめに

Kubernetesは、マシンを最大限に活用できるオープンソースのコンテナオーケストレーションシステムです。 ただし、Kubernetesを使用すると、ポッドのさまざまなAWSへのアクセスを管理する際に問題が発生します。 この記事では、特定のツールを使用した際のこれらの問題を解決する方法について説明します。 情報を整理する方法は次のとおりです。

  • アクセス管理が問題になる理由
  • Kube2iamによるアクセスの管理
  • KIAMによるアクセスの管理
  • サービスアカウントのIAMロール(IRSA)

AWSサービスへのアクセスの管理が問題になるのはなぜなのか?

想像してみてください。Kubernetesノードは、AWS DynamoDBテーブルへのアクセスを必要とするアプリケーションポッドをホストしています。一方、同じノード上の別のポッドは、AWS S3バケットにアクセスする必要があります。両方のアプリケーションが正しく動作するためには、KubernetesワーカーノードがDynamoDBテーブルとS3バケットの両方に同時にアクセスする必要があります。

これが数百のポッドで起こっていることを考えてみてください。すべてのポッドがさまざまなAWSリソースへのアクセスを必要とします。ポッドは、いくつかの異なるAWSサービスに同時にアクセスすることが必要とされKubernetesクラスターで常にスケジュールされています...このことがたくさん起こっているのですの!

これを解決する1つの方法は、Kubernetesノード、つまりポッドにすべてのAWSリソースへのアクセスを許可することです。ただし、これによりシステムは潜在的な攻撃者の標的となることを意味します。単一のポッドまたはノードが侵害された場合、攻撃者はAWSインフラストラクチャ全体にアクセスできます。これを回避するには、Kube2iam、Kiam、IAM IRSAなどのツールを使用して、KubernetesポッドからAWSリソースへのアクセスを改善します。最良の部分?すべてのアクセスAPI呼び出しと認証メトリックは、Prometheusによってプルされ、Grafanaで視覚化できます。 Prometheus / Grafanaパーツを自分で試したい場合は、MetricFire無料トライアルにアクセスして、ご使用を開始してみてください。

Kube2iamを使用した実装に飛び込む

全体的なアーキテクチャ

Kube2iamは、クラスターのDaemonSetとしてデプロイされます。 したがって、Kube2iamのポッドは、Kubernetesクラスターのすべてのワーカーノードで実行されるようにスケジュールされます。 別のポッドがAWS API呼び出しを行ってリソースにアクセスすると、その呼び出しはそのノードで実行されているKube2iamポッドによってインターセプトされます。 次に、Kube2iamは、ポッドにリソースにアクセスするための適切な認証情報が割り当てられるようにします。

また、ポッド仕様でIdentity and Access Management(IAM)ロールを指定する必要があります。 内部では、Kube2iamポッドが呼び出し元のIAMロールの一時的な認証情報を取得し、それらを呼び出し元に返します。 基本的に、すべてのAmazon Elastic Compute Cloud(EC2)メタデータAPI呼び出しはプロキシになされます。 (Kube2iamポッドは、EC2メタデータAPI呼び出しを行えるように、ホストネットワークを有効にして実行する必要があります。)

実装

IAMロールの作成とアタッチ
必要なAWSリソース(AWS S3バケットなど)にアクセスできるmy-roleという名前のIAMロールを作成します。
次の手順に従って、役割とKubernetesワーカーノードに接続されている役割との間の信頼関係を有効にします。 (Kubernetes APIワーカーにアタッチされた役割には非常に制限された権限があることを確認してください。すべてのAPI呼び出しまたはアクセスリクエストはノードで実行されているコンテナによって行われ、Kube2iamを使用して認証情報を受け取るため、ワーカーノードのIAM役割は 多数のAWSリソース。)

a. AWSコンソールで新しく作成されたロールに移動し、[Trust Relationship]タブを選択します
b. 「Edit trust relationship」をクリックします
c. 次のコンテンツをポリシーに追加します。

{
  "Sid": "",
  "Effect": "Allow",
  "Principal": {
    "AWS": "<ARN_KUBERNETES_NODES_IAM_ROLE>"
  },
  "Action": "sts:AssumeRole"
}

d. ノードプールのIAM役割に対して「Assume Role」を有効にします。 ノードのIAMポリシーに次のコンテンツを追加します。

{
        "Sid": "",
    "Effect": "Allow",
    "Action": [
        "sts:AssumeRole"
    ],
    "Resource": [
        "arn:aws:iam::810085094893:instance-profile/*"
    ]
}
  1. Add the IAM role's name to deployment as an annotation.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: mydeployment
  namespace: default
spec:
...
  minReadySeconds: 5
  template:
      annotations:
        iam.amazonaws.com/role: my-role
    spec:
      containers:
...

Kube2iamのデプロイ

Kube2iamポッドで使用するサービスアカウントClusterRoleおよびClusterRoleBindingを作成します。 ClusterRoleには、すべてのAPIグループの名前空間とポッドへの「取得」、「監視」、および「リスト」アクセス権が必要です。 以下のマニフェストを使用して作成できます。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube2iam
  namespace: kube-system
---
apiVersion: v1
kind: List
items:
  - apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: kube2iam
    rules:
      - apiGroups: [""]
        resources: ["namespaces","pods"]
        verbs: ["get","watch","list"]
  - apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: kube2iam
    subjects:
    - kind: ServiceAccount
      name: kube2iam
      namespace: kube-system
    roleRef:
      kind: ClusterRole
      name: kube2iam
      apiGroup: rbac.authorization.k8s.io
---

2.以下のマニフェストを使用して、Kube2iam DaemonSetをデプロイします。

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: kube2iam
  labels:
    app: kube2iam
  namespace: kube-system
spec:
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: kube2iam
    spec:
      hostNetwork: true
      serviceAccount: kube2iam
      containers:
        - image: jtblin/kube2iam:latest
          name: kube2iam
          args:
            - "--auto-discover-base-arn"
            - "--iptables=true"
            - "--host-ip=$(HOST_IP)"
            - "--host-interface=cali+"
            - "--verbose"
            - "--debug"
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          ports:
            - containerPort: 8181
              hostPort: 8181
              name: http
          securityContext:
            privileged: true
---

注:Kube2iamコンテナは、引数--iptables = trueおよび--host-ip = $(HOST_IP)で実行され、privilegedモードではtrueとして実行されます。

...
    securityContext:
        privileged: true
...

次の設定により、他のポッドで実行されているコンテナーがEC2メタデータAPIに直接アクセスし、AWSリソースへの不要なアクセスを取得することを防ぎます。 169.254.169.254へのトラフィックは、Dockerコンテナのプロキシにする必要があります。 別の方法として、各Kubernetesワーカーノードで次のコマンドを実行して適用することもできます。

iptables \
  --append PREROUTING \
  --protocol tcp \
  --destination 169.254.169.254 \
  --dport 80 \
  --in-interface docker0 \
  --jump DNAT \
  --table nat \
--to-destination `curl 169.254.169.254/latest/meta-data/local-ipv4`:8181

テストポッドからのアクセスのテスト

Kube2iamのデプロイとIAMの設定が機能するかどうかを確認するには、IAMの役割をアノテーションとして指定してテストポッドをデプロイします。 すべてが機能する場合、ポッドに接続されているIAMノードを確認できるはずです。 これは、EC2メタデータAPIをクエリすることで簡単に確認できます。 以下のマニフェストを使用してテストポッドをデプロイしましょう。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: access-test
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: access-test
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: access-test
      annotations:
        iam.amazonaws.com/role: my-role
    spec:
      containers:
      - name: access-test
        image: "iotapi322/worker:v4"

作成したテストポッドで次のコマンドを実行します。

curl 169.254.169.254/latest/meta-data/iam/security-credentials/

このAPIへの応答としてmyroleを取得する必要があります。

API呼び出しがいつどのようにインターセプトされるかをより深く理解するために、そのノードで実行されているKube2iamポッドのログを調整することを強くお勧めします。 セットアップが期待どおりに機能したら、ロギングバックエンドへの攻撃を避けるために、Kube2iamデプロイメントの冗長性をオフにする必要があります。

Kiam

Kube2iamは非常に役立ちますが、Kiamが解決しようとしている2つの主要な問題があります。

  • 負荷状態でのデータの競合:アプリケーションの負荷が非常に高く、クラスターにポッドがいくつかある場合、Kube2iamがそれらのポッドに誤った認証情報を返すことがあります。 GitHubの問題はここで参照できます。
  • プリフェッチ認証情報: コンテナープロセスがポッドで起動する前に、アクセス認証情報がポッド仕様で指定されたIAMロールに割り当てられます。 以前に資格情報を割り当てることにより、Kiamは開始待ち時間を減らし、信頼性を向上させます。

Kiamの追加機能は次のとおりです。

  • 構造化ロギングを使用して、ポッド名、役割、アクセスキーIDなどを使用したElacsticsearch、Logstash、Kibana(ELK)セットアップへの統合を改善します。
  • メトリックを使用して、応答時間、キャッシュヒット率などを追跡します。これらのメトリックは、Prometheusによって簡単に収集され、Grafanaでレンダリングできます。

全体的なアーキテクチャ

Kiamはエージェントサーバーアーキテクチャに基づいています。

  • Kiamエージェント:これは、ポッドがAWSメタデータAPIにアクセスできないようにするために、通常DaemonSetとしてデプロイされるプロセスです。 代わりに、Kiamエージェントは認証情報のリクエストを傍受し、その他すべてを渡すHTTPプロキシを実行します。
  • Kiamサーバー:このプロセスは、Kubernetes APIサーバーをポッドを監視するために接続し、AWS Security Token Service(STS)と通信して認証情報をリクエストする役割を果たします。 また、実行中のポッドで現在使用されているロールの認証情報のキャッシュを維持し、ポッドで必要になる前に認証情報が数分ごとに更新されて保存されるようにします。

実装

Kube2iamと同様に、ポッドがIAMロールの認証情報を取得するには、そのロールをデプロイメントマニフェストの注釈として指定する必要があります。さらに、適切なアノテーションを使用して、特定の名前空間内に割り当てることができるIAMロールを指定する必要があります。これによりセキュリティが強化され、IAMロールの制御を微調整できます。

IAMロールの作成とアタッチ
1. AWSリソースへの適切なアクセス権を持つkiam-serverという名前のIAMロールを作成します。

2.次の手順に従って、kiam-serverの役割とKubernetes master ノードにアタッチされた役割の間の信頼関係を有効にします。 (Kubernetes APIワーカーにアタッチされている役割の権限が非常に制限されていることを確認してください。すべてのAPI呼び出しまたはアクセスリクエストは、ノードで実行されているコンテナによって行われ、Kiamを使用して認証情報を受け取ります。ワーカーノードのIAM役割は多くのAWSリソース。)

a. AWSコンソールで新しく作成したロールに移動し、[Trust Relationship]タブを選択します。
b. 「Edit Trust Relationship」をクリックします。
c. 次のコンテンツをポリシーに追加します。

{
  "Sid": "",
  "Effect": "Allow",
  "Principal": {
    "AWS": "<ARN_KUBERNETES_MASTER_IAM_ROLE>"
  },
  "Action": "sts:AssumeRole"
}
  1. kiam-serverロールにインラインポリシーを追加します。
{
  "Version": "2012-10-17",
  "Statement": [
   {
     "Effect": "Allow",
     "Action": [
       "sts:AssumeRole"
       ],
       "Resource": "*"
   }
 ]
}
  1. AWSリソースへの適切なアクセス権を持つIAMロール(my-roleとしましょう)を作成します。

5.新しく作成されたロールとKiamサーバーロール間の信頼関係を有効にします。

そうするために:

a. AWSコンソールで新しく作成されたロールに移動し、[Trust Relationship]を選択します
b. 「Edit Trust Relationship」をクリックします
c. 次のコンテンツをポリシーに追加します。

{
  "Sid": "",
  "Effect": "Allow",
  "Principal": {
    "AWS": "<ARN_KIAM-SERVER_IAM_ROLE>"
  },
  "Action": "sts:AssumeRole"
}

6.マスタープールのIAM役割に対して「Assume Role」を有効にします。 マスターIAMロールにインラインポリシーとして次のコンテンツを追加します。

{
  "Version": "2012-10-17",
  "Statement": [
   {
     "Effect": "Allow",
     "Action": [
       "sts:AssumeRole"
       ],
       "Resource": "<ARN_KIAM-SERVER_IAM_ROLE>"
   }
 ]

Kiamエージェントとサーバー間のすべての通信はTLS暗号化されています。 これによりセキュリティが強化されます。 これを行うには、まずKubernetesクラスターにcert-managerをデプロイし、エージェント/サーバー通信用の証明書を生成する必要があります。

Cert Managerの導入と証明書の生成

  • カスタムリソース定義リソースを個別にインストールします。
kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml
  • cert-managerの名前空間を作成します。
kubectl create namespace cert-manager
  • cert-manager名前空間にラベルを付けて、リソース検証を無効にします。
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
  • Jetstack Helmリポジトリを追加します。
helm repo add jetstack https://charts.jetstack.io
  • ローカルのHelmチャートリポジトリキャッシュを更新します。
helm repo update
  • cert-manager Helmチャートをインストールします。
helm install --name cert-manager --namespace cert-manager --version v0.8.0 jetstack / cert-manager
  • cert-manager Helmチャートをインストールします。
helm install --name cert-manager --namespace cert-manager --version v0.8.0 jetstack / cert-manager

Kiam Agent-server TLSのCA秘密鍵と自己署名証明書を生成する

  • CRTファイルを生成します。
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=kiam" -out kiam.cert -days 3650 -reqexts v3_req -extensions v3_ca -out ca.crt
  • CA鍵ペアを秘密としてKubernetesに保存します。
kubectl create secret tls kiam-ca-key-pair \
   --cert = ca.crt \
   --key = ca.key \
   --namespace = cert-manager
  • クラスター発行者を展開し、証明書を発行します。

Kiamネームスペースを作成します。

apiVersion: v1
kind: Namespace
metadata:
  name: kiam
  annotations:
    iam.amazonaws.com/permitted: ".*"
---

クラスター発行者をデプロイし、証明書を発行します。

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: kiam-ca-issuer
  namespace: kiam
spec:
  ca:
    secretName: kiam-ca-key-pair
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: kiam-agent
  namespace: kiam
spec:
  secretName: kiam-agent-tls
  issuerRef:
    name: kiam-ca-issuer
    kind: ClusterIssuer
  commonName: kiam
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: kiam-server
  namespace: kiam
spec:
  secretName: kiam-server-tls
  issuerRef:
    name: kiam-ca-issuer
    kind: ClusterIssuer
  commonName: kiam
  dnsNames:
  - kiam-server
  - kiam-server:443
  - localhost
  - localhost:443
  - localhost:9610
---
  • 証明書が正しく発行されているかどうかをテストします。
kubectl -n kiam get secret kiam-agent-tls -o yaml
kubectl -n kiam get secret kiam-server-tls -o yaml

リソースに注釈を付ける

  • IAMロールの名前を注釈としてデプロイメントに追加します。
apiVersion: extensions/v1beta1
 kind: Deployment
 metadata:
    name: mydeployment
    namespace: default
 spec:
 ...
    minReadySeconds: 5
    template:
        annotations:
        iam.amazonaws.com/role: my-role
    spec:
        containers:
 ... 
  • ポッドが実行される名前空間にロールアノテーションを追加します。 Kube2iamでこれを行う必要はありません。
apiVersion: v1
 kind: Namespace
 metadata:
    name: default
    annotations:
        iam.amazonaws.com/permitted: ".*"

デフォルトでは、ロールは許可されていません。 上記のように正規表現を使用してすべての役割を許可するか、名前空間ごとに特定の役割を指定することもできます。

  • Kiamエージェントとサーバーのデプロイ
  • Kiamサーバー
  • 以下のマニフェストは、次のものをデプロイします。
  1. Kubernetesマスターノードで実行されるKiam Server DaemonSet(上記で作成されたTLSシークレットを使用するように構成します)
  2. Kiam Serverサービス
  3. Kiamサーバーに必要なサービスアカウント、ClusterRoleおよびClusterRoleBinding
---
kind: ServiceAccount
apiVersion: v1
metadata:
  name: kiam-server
  namespace: kiam
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: kiam-read
rules:
- apiGroups:
  - ""
  resources:
  - namespaces
  - pods
  verbs:
  - watch
  - get
  - list
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kiam-read
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kiam-read
subjects:
- kind: ServiceAccount
  name: kiam-server
  namespace: kiam
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: kiam-write
rules:
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kiam-write
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kiam-write
subjects:
- kind: ServiceAccount
  name: kiam-server
  namespace: kiam
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  namespace: kiam
  name: kiam-server
spec:
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: kiam
        role: server
    spec:
      tolerations:
       - key: node-role.kubernetes.io/master
         effect: NoSchedule
      serviceAccountName: kiam-server
      nodeSelector:
        kubernetes.io/role: master
      volumes:
        - name: ssl-certs
          hostPath:
      nodeSelector:
      nodeSelector:
        kubernetes.io/role: master
      volumes:
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs
        - name: tls
          secret:
            secretName: kiam-server-tls
      containers:
        - name: kiam
          image: quay.io/uswitch/kiam:b07549acf880e3a064e6679f7147d34738a8b789
          imagePullPolicy: Always
          command:
            - /kiam
          args:
            - server
            - --level=info
            - --bind=0.0.0.0:443
            - --cert=/etc/kiam/tls/tls.crt
            - --key=/etc/kiam/tls/tls.key
            - --ca=/etc/kiam/tls/ca.crt
            - --role-base-arn-autodetect
            - --assume-role-arn=<KIAM_SERVER_ROLE_ARN>
            - --sync=1m
          volumeMounts:
            - mountPath: /etc/ssl/certs
              name: ssl-certs
            - mountPath: /etc/kiam/tls
              name: tls
          livenessProbe:
            exec:
              command:
              - /kiam
              - health
              - --cert=/etc/kiam/tls/tls.crt
              - --key=/etc/kiam/tls/tls.key
              - --ca=/etc/kiam/tls/ca.crt
              - --server-address=localhost:443
              - --gateway-timeout-creation=1s
              - --timeout=5s
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 10
          readinessProbe:
            exec:
              command:
              - /kiam
              - health
              - --cert=/etc/kiam/tls/tls.crt
              - --key=/etc/kiam/tls/tls.key
              - --ca=/etc/kiam/tls/ca.crt
              - --server-address=localhost:443
              - --gateway-timeout-creation=1s
              - --timeout=5s
            initialDelaySeconds: 3
            periodSeconds: 10
            timeoutSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: kiam-server
  namespace: kiam
spec:
  clusterIP: None
  selector:
    app: kiam
    role: server
  ports:
  - name: grpclb
    port: 443
    targetPort: 443
    protocol: TCP

注意:

ここに配置したスケジューラー許容とノードセレクターは、KiamポッドがKiamマスターノードでのみスケジュールされることを確認します。 これが、Kiam-server IAMロールと、KubernetesマスターノードにアタッチされたIAMロール(上記)の間の信頼関係を有効にする理由です。

...
       tolerations:
       - key: node-role.kubernetes.io/master
         effect: NoSchedule 
...
      nodeSelector:
        kubernetes.io/role: master
....
  1. kiam-serverロールARNは、Kiamサーバーコンテナーへの引数として提供されます。 上記のマニフェストのフィールドを、作成したロールのARNに更新してください。
  2. Kiamサーバー用に作成されたClusterRoleおよびClusterRoleBindingは、効果的に動作するために必要な最小限の権限をそれに付与します。 変更する前に十分に検討してください。
  3. SSL証明書へのパスが、cert-manager証明書を使用して作成したシークレットに従って正しく設定されていることを確認してください。 これは、KiamサーバーとKiamエージェントポッド間の安全な通信を確立するために重要です。

Kiam エージェント

以下に提供されているマニフェストは、Kubernetesワーカーノードでのみ実行される次のKiam Agent DaemonSetをデプロイします。

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  namespace: kiam
  name: kiam-agent
spec:
  template:
    metadata:
      labels:
        app: kiam
        role: agent
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      volumes:
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs
        - name: tls
          secret:
            secretName: kiam-agent-tls
        - name: xtables
          hostPath:
            path: /run/xtables.lock
            type: FileOrCreate
      containers:
        - name: kiam
          securityContext:
            capabilities:
              add: ["NET_ADMIN"]
          image: quay.io/uswitch/kiam:b07549acf880e3a064e6679f7147d34738a8b789
          imagePullPolicy: Always
          command:
            - /kiam
          args:
            - agent
            - --iptables
            - --host-interface=cali+
            - --json-log
            - --port=8181
            - --cert=/etc/kiam/tls/tls.crt
            - --key=/etc/kiam/tls/tls.key
            - --ca=/etc/kiam/tls/ca.crt
            - --server-address=kiam-server:443
            - --gateway-timeout-creation=30s
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          volumeMounts:
            - mountPath: /etc/ssl/certs
              name: ssl-certs
            - mountPath: /etc/kiam/tls
              name: tls
            - mountPath: /var/run/xtables.lock
              name: xtables
          livenessProbe:
            httpGet:
              path: /ping
              port: 8181
            initialDelaySeconds: 3
            periodSeconds: 3

Kiamエージェントも、Kube2iamと同様に、ホストネットワークをtrueに設定して実行されることに注意してください。 また、Kiamエージェントのコンテナに対する引数の1つは、KiamサーバーにアクセスするためのKiamサービスの名前です。この場合はkiam-server:443したがって、Kiamエージェントをデプロイする前にKiamサーバーをデプロイする必要があります。

また、コンテナ引数--gateway-timeout-creationは、エージェントが接続を試みる前にKiamサーバーポッドが起動するまでの待機時間を定義します。 Kubernetesクラスターでポッドが表示されるまでの時間に応じて調整できます。 理想的には、30秒の待機期間で十分です。

テスト

KiamとKube2iamのセットアップをテストするプロセスは同じです。 テストポッドを使用してメタデータをカールし、割り当てられた役割を確認できます。 デプロイメントと名前空間の両方に適切な注釈が付けられていることを確認してください。

サービスアカウントのIAMロール(IRSA)

最近、AWSはポッドがAWSリソースにアクセスできるようにする独自のサービスをリリースしました:サービスアカウントのIAMロール(IRSA)。役割はサービスアカウントで認証されるため、そのサービスアカウントが関連付けられているすべてのポッドで共有できます。このサービスは、AWS EKSとKOPSベースのインストールの両方で利用できます。詳しくはこちらをご覧ください。

まとめ

このブログで取り上げられているツールは、KubernetesポッドからAWSリソースへのアクセスを管理するのに役立ちます。これらのツールには、それぞれ長所と短所があります。

Kube2IAMが最も簡単に実装できますが、セットアップの容易さにより効率が低下します。Kube2iamは高負荷条件下では信頼性の高いパフォーマンスを発揮できない可能性があります。これは、大規模なトラフィックの急増を経験しない非本番環境またはシナリオにより適しています。

IAM IRSAはKube2iamよりも多くの作業を必要としますが、Amazonの詳細なドキュメントを考えると、実装する方が簡単な場合があります。それが非常に最近のものであるため、この記事の執筆時点では、業界でのIRSAの実装は十分ではありません。

KIAMの実装ではcert-managerを実行する必要があり、Kube2iamとは異なり、デプロイメントとともに名前空間に注釈を付ける必要があります。いずれにしても、Kiamを使用することを強くお勧めします。証明書マネージャを実行するためのリソースがあり、マスターノードがそれらで実行されるDaemonSetを処理できるように装備されている場合は、Kiamをすべての場合に使用できるためです。この投稿で提供されているマニフェストを使用することで、セットアップはシームレスになり、本番環境で使用できるようになります。

Prometheusが提供するGrafanaダッシュボードでメトリックを視覚化してみたい場合は、MetricFire無料トライアルに今すぐ参加してください。また、デモにサインアップして、モニタリングソリューションの効果について直接お問い合わせください。(日本語受け付けております)

この記事は、ゲストブロガーのVaibhav Thakurによって書かれたものを翻訳したものです。この記事が気に入った場合は、彼のLinkedInで詳細を確認してください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS-SAA試験勉強メモ1

AWSでの負荷試験

考慮事項

  • ELBのプレウォーミング申請
    →ELBはデフォルトでのスケールアウト機能はない(要AWSへの申請)

  • サーバに負荷をかけるようサーバーの性能
    →しっかりと負荷をかけるために必要

S3を使用した静的WEBサイトの構築

必要設定

  • S3バケットポリシーを編集して、外部からのアクセスを許可

  • 静的WEBサイトのホスティング機能を有効化

IAMユーザー作成の自動化

Cloudformationを利用する
(リソースだけではなく、IAMユーザーも作成可能)

CodeDeploy

オンプレでもEC2でもエージェントのインストールは必須
逆にエージェントが入れられれば、オンプレでもEC2でも利用可能

(備忘)開発プロセスの自動化

CodeCommit(Git)
→CodeBuild(ビルド・テスティング)
→CodeDeploy(デプロイ)
のパイプラインをCodePipelineを使って自動化

AWSのキャッシュサービス

  • CloudFront(CDNサービス)
    →HTML、CSS、動画、画像などの静的コンテンツをキャッシュ

  • ElastiCache
    →DBのキャッシュ

セキュリティグループとネットワークACL

セキュリティグループ ネットワークACL
特徴 ステートフル ステートレス
紐づけ対象 EC2 サブネット

SES

メールの送受信可能
※送信できなかったメール(バウンスメール)の処理が必須。(通常のメールサーバーでも同様)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

API Gateway + Lambdaのマルチリージョン構成をServerless Frameworkで作る

概要

Amazon API Gateway + AWS Lambda で作るサーバーレスなアプリケーションを、マルチリージョン構成にする。
普段から使っているServerless Frameworkで構築してみた。

参考

以下のAWSブログの記事が参考になる。記事自体は古いが構成は変わらない。

Building a Multi-region Serverless Application with Amazon API Gateway and AWS Lambda

構成

image.png

  • プライマリリージョンを ap-northeast-1 , セカンダリリージョンを us-west-2 とする。
  • ルーティングポリシーは、フェールオーバーとする。
    • プライマリとセカンダリに対して定期的にヘルスチェックをし、プライマリのヘルスチェックが失敗したらセカンダリにルーティングする。

開発環境

言語: Python 3.8.3
デプロイ: LambdaのデプロイにはServerless Frameworkを使う

実装

事前準備

ドメインとSSL証明書を作成する。

  • ドメインの作成とDNSサーバーは「Route 53」で用意する。
    • 今回のサンプルでは example.com とする。
  • SSL証明書は「AWS Certificate Manager (ACM)」で作成する
    • リージョンごとに作成する

プロジェクト作成

テンプレートで生成

sls create --template aws-python3

serverless-multi-region-plugin プラグインをインストール

Serverless Frameworkの以下のプラグインを利用することで、マルチリージョン構成なサーバーレスアプリを構築することができる。

serverless-multi-region-plugin

バージョン固定しない場合は現時点でLatestである1.2.5-dns-3がインストールされるが、テンプレートに必要なリソースが足りない状態である。今回はバージョン1.3.3を利用する。

プラグインをインストールする。

sls plugin install --name serverless-multi-region-plugin@1.3.3

serverless.yml編集

custom属性にプラグインの設定を記述する。そのほかは通常通り。

serverless.yml
service: multiregion-example

provider:
  name: aws
  runtime: python3.8

custom:
  # 作成されるAPI GATEWAY Methodの論理id
  gatewayMethodDependency: ApiGatewayMethodHelloGet

  dns:
    # 利用するドメインのRoute 53 ホストゾーンのid
    hostedZoneId: XXXXXXXXXXXXXXXXXXXXX
    # エンドポイントとなるサブドメイン。上記ホストゾーンにレコードが作成される
    domainName: ${self:service}.example.com
    regionalDomainName: ${self:custom.dns.domainname}
    healthCheckResourcePath: /healthcheck

    # リージョンごとの設定
    ap-northeast-1:
      # ACMで作成したSSL証明書のARN
      acmCertificateArn: arn:aws:acm:ap-northeast-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      failover: PRIMARY
    us-west-2:
      # ACMで作成したSSL証明書のARN
      acmCertificateArn: arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      failover: SECONDARY

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
  healthcheck:
    handler: handler.hello
    events:
      - http:
          path: healthcheck
          method: get

plugins:
  - serverless-multi-region-plugin

プライマリリージョンへデプロイ

sls deploy --region ap-northeast-1

対象のAPI GatewayとLambdaがデプロイされ、Route 53のホストゾーンにフェールオーバールーティングポリシーを持ったPRIMARYのAレコードが追加されている。また、プライマリリージョンのAPI Gatewayのエンドポイントへのヘルスチェックも追加されている。

セカンダリリージョンへデプロイ

sls deploy --region us-west-2

対象のAPI GatewayとLambdaがデプロイされ、Route 53のホストゾーンにフェールオーバールーティングポリシーを持ったSECONDARYのAレコードが追加されている。また、セカンダリリージョンのAPI Gatewayのエンドポイントへのヘルスチェックも追加されている。

確認

デプロイ後は、エンドポイントはプライマリリージョンのAPI Gatewayに向いている。

フェールオーバーの確認として、プライマリリージョンのAPI Gateway、またはヘルスチェック用のLambdaをスロットリングさせる。

しばらくすると、プライマリへのヘルスチェックが異常状態となり、セカンダリに切り替わる。エンドポイントへリクエストを送ってもエラーとならないことが確認できる。

まとめ

Serverless Frameworkを使えば簡単にマルチリージョン構成を作ることができる。

serverless-multi-region-pluginの設定をさらに追加すれば、前段にCloudFrontを追加することもできる。
また、フェールオーバーの他にレイテンシーベースのルーティングポリシーを指定できる。 ただし、レコードセットの更新の際は一度スタック削除してから作り直す必要がある。

詳しくはserverless-multi-region-plugin参照

他のプラグインを使っている場合は、相性の悪いもの (例えば serverless-aws-alias) もあるようなので注意が必要。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2 インスタンスの情報をssh configに記載して簡単にssh接続する

目的

  • ssh configファイルにAWS EC2のインスタンス情報を記載して短いコマンドでssh接続する方法をまとめる

実施環境

  • ハードウェア環境(ssh接続元)
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2 GHz クアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • EC2インスタンス環境(ssh接続先)
項目 情報 備考
インスタンス種類 AmazonLinux2 こちらの方法で構築→AWS EC2 をMacで使ってみよう!

前提条件

  • 先に記載した方法でAWS EC2のインスタンスが起動しssh接続ができること。

前提情報

  • 今回の説明で実行するコマンドは特に記載がない場合、ssh接続元にて実行する物とする。

読後感

  • $ ssh ssh設定名のみでEC2のインスタンスにssh接続できる様になる。

概要

  1. 情報の確認
  2. ssh configファイルの作成と記載
  3. 確認

詳細

  1. 情報の確認

    1. AWSにログインしてEC2のインスタンス一覧ページを開き「接続」をクリックする。

      https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_306417_81cd75ae-66c4-7f87-ad0f-5b7c8ed2c27a.png

    2. 表示された下記画像の赤枠で囲まれた部分(HostName情報)の情報をどこかにメモしておく。

      https___qiita-image-store_s3_ap-northeast-1_amazonaws_com_0_306417_9e224e56-bffc-9e66-e6a9-348883e56b35.png

    3. 表示された下記画像の赤枠で囲まれた部分(User情報)の情報をどこかにメモしておく。

      https___qiita-image-store_s3_ap-northeast-1_amazonaws_com_0_306417_9e224e56-bffc-9e66-e6a9-348883e56b35.png

    4. 現在ssh接続する際にコマンドで指定している接続鍵が格納されているディレクトリまで移動して、下記コマンドを実行し表示されたパスの末尾に鍵の名前をくっつけた文字列(接続鍵のフルパス)をどこかにメモしておく。(例えば、出力されたパスが/Users/miriwoで接続鍵の名前がtest.pemだった場合/Users/miriwo/test.pemという文字列をメモする。)

      $ pwd
      
  2. ssh configファイルの作成と記載

    1. 下記コマンドを実行して.sshディレクトリを作成する。

      $ mkdir -p ~/.ssh
      
    2. 下記コマンドを実行してssh configファイルを作成して開く。

      $ vi ~/.ssh/config 
      
    3. 下記の内容を記載する。

      ~/.ssh/config
      Host 接続先情報名(任意の物を入力)
          HostName 先にメモしたHostName情報を記載する
      User 先にメモしたUser情報を記載する
      IdentityFile 先にメモした接続鍵のフルパスを記載する
      
    4. 例えば接続策情報名が「aws-test」、HostName情報が「ec2-13-59-146-25.us-east-2.compute.amazonaws.com」、User情報が「ec2-user」、接続鍵のフルパスが「/Users/miriwo/MyWebServer.pem」だった時の記載は下記の様になる。

      ~/.ssh/config
      Host aws-test
          HostName ec2-13-59-146-25.us-east-2.compute.amazonaws.com
      User ec2-user
      IdentityFile /Users/miriwo/MyWebServer.pem
      
    5. 記載を保存してssh configファイルを閉じる。

  3. 確認

    1. 下記コマンドを実行して接続できることを確認する。

      $ ssh 接続先情報名
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JMESPathでAWS CLIコマンドの出力結果を抽出する

はじめに

AWS CLIのコマンドで情報を出力させる際に、JMESPathを使って必要な部分だけ抽出するのに苦労しました。
この記事だけでは実用のイメージが湧きづらいかもしれませんが、JMESPathを使って抽出するやり方の参考になれば幸いです。

結局は以下のサイトを参考にすればおおよそ問題ないかと思いますが、自分がやってみたことをここに記載したいと思います。
参考:https://jmespath.org/tutorial.html#list-and-slice-projections

やりたいこと

AWS CLIのコマンド「describe-listeners」で、リスナーが2つある場合において、
出力結果に1つのみTargetGroupArnを表示させたい。
(リスナーが2つあると、リスナーごとのTargetGroupArnがそれぞれ表示されるので、1つのみ抽出する)

やってみた

まずはdescribe-listenersの引数 "--query Listeners[]"を使って、全てのリスナーをjson形式で表示してみます。
json形式でListeners[]を出力するのは、TargetGroupArnがどの配列のどこに入っているかを確認したいためです。
以下のように2つのリスナーの情報が出力されます。

$ aws elbv2 describe-listeners \
> --load-balancer-arn ***** \
> --query Listeners[] \
> --output json \
> --region ap-northeast-1
[
    {
        "ListenerArn": "*****",
        "LoadBalancerArn": "*****",
        "Port": 80,
        "Protocol": "HTTP",
        "DefaultActions": [
            {
                "Type": "forward",
                "TargetGroupArn": "*****",
                "ForwardConfig": {
                    "TargetGroups": [
                        {
                            "TargetGroupArn": "*****",
                            "Weight": 1
                        }
                    ],
                    "TargetGroupStickinessConfig": {
                        "Enabled": false
                    }
                }
            }
        ]
    },
    {
        "ListenerArn": "*****",
        "LoadBalancerArn": "*****",
        "Port": 8080,
        "Protocol": "HTTP",
        "DefaultActions": [
            {
                "Type": "forward",
                "TargetGroupArn": "*****",
                "Order": 1,
                "ForwardConfig": {
                    "TargetGroups": [
                        {
                            "TargetGroupArn": "*****",
                            "Weight": 1
                        }
                    ],
                    "TargetGroupStickinessConfig": {
                        "Enabled": false
                    }
                }
            }
        ]
    }
]

次に、"--query Listeners[0]"として、Listenersの配列の0番目のみを表示させます。
これによって、2つあるリスナーのTargetGroupArnのうちの1つに絞りこみます。

$ aws elbv2 describe-listeners \
> --load-balancer-arn ***** \
> --query Listeners[0] \
> --output json \
> --region ap-northeast-1
[
    {
        "ListenerArn": "*****",
        "LoadBalancerArn": "*****",
        "Port": 80,
        "Protocol": "HTTP",
        "DefaultActions": [
            {
                "Type": "forward",
                "TargetGroupArn": "*****",
                "ForwardConfig": {
                    "TargetGroups": [
                        {
                            "TargetGroupArn": "*****",
                            "Weight": 1
                        }
                    ],
                    "TargetGroupStickinessConfig": {
                        "Enabled": false
                    }
                }
            }
        ]
    }

では、ここからTargetGroupArnを抽出してみます。
抽出するためには"--query Listeners[0]"の後ろに配列の要素を追加します。
TargetGroupArnを抽出するには、以下の引数になります。

--query Listeners[0].DefaultActions[].TargetGroupArn

これは、Listenersの配列の中のDefaultActionsの配列の中のTargetGroupArnを出力するという記載です。

では実行してみます。json形式は抽出のための確認に使用しただけなので、最後はtext形式で出力します。

$ aws elbv2 describe-listeners \
> --load-balancer-arn ***** \
> --query --query Listeners[0].DefaultActions[].TargetGroupArn \
> --output text \
> --region ap-northeast-1
arn:aws:elasticloadbalancing:ap-northeast-1:*****:targetgroup/*****/*****

TargetGroupArnが1つだけ出力できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WindowsのイベントログをS3に保存

元々AWS CLIやAWS SDKを使ってプログラムを書いていたので、
Windowsのイベントログを月に1回 S3に保管して管理できないかふと思ってやってみた結果を記載

前提

Ⅰ AWS上にWindowsサーバを作成して、IAMのロールにてS3とSNSの適切な権限のロールを作成してWindwsサーバにIAMロールを割り当てています。
Ⅱ S3にバケットを作成しWindowsサーバからのみバケット操作できるようにバケットポリシーを作成しております。
Ⅲ 作成したWinodwsサーバには、AWS CLI v2をインストールしています。インストール手順についてはこちらを参考にして下さい。
Ⅳ S3にイベントログを保存できなかった時にエラー処理として、SNSで通知する仕様にしております。

作ったPowerShellのスクリプト

特に何か記載することはなく、各プログラムの動作を書いているので、そこまで難しくないと思います。


# 保存先のバケット名を記載
$BucketName = "********"

# 取得対象のイベントログを指定
$LogNames = @("********")

# SNS送信先のARNを指定
$Arn = "********"

# 先月時点のyyyyMM文字列を取得し作成するファイル名につける
$YYYYMM = (Get-Date).AddMonths(-1).ToString("yyyyMM")

# 出力先として「C:\temp」フォルダを指定
$DstFolder = "c:\temp\"

# イベントログを取得する対象の期間を先月1日から末日までの1ヶ月間と指定
$StartJTime = (Get-Date -Day 1 -hour 0 -minute 0 -second 0).AddMonths(-1)
$EndJTime = (Get-Date -Day 1 -hour 0 -minute 0 -second 0)

# イベントログを取得する際の日付をUTCに変換(UTCに変換しないとフィルタリング条件として使えない)
$StartUtcTime = [System.TimeZoneInfo]::ConvertTimeToUtc($StartJTime).ToString("yyyy-MM-ddTHH:mm:ssZ")
$EndUtcTime = [System.TimeZoneInfo]::ConvertTimeToUtc($EndJTime).ToString("yyyy-MM-ddTHH:mm:ssZ")

# 日付指定でフィルタリング条件作成
$Filter = @"
  Event/System/TimeCreated[@SystemTime>='$StartUtcTime'] and
  Event/System/TimeCreated[@SystemTime<'$EndUtcTime']
"@ 

# イベントログ出力用のオブジェクトを作成
$EvSession = New-Object -TypeName System.Diagnostics.Eventing.Reader.EventLogSession

# イベントログをevtx形式で出力
foreach($LogName in $LogNames){
  $OutFile = $DstFolder + "\" + $Env:COMPUTERNAME + "_" + $LogName + "_" + $YYYYMM + ".evtx"
  $Locale = [System.Globalization.CultureInfo]::CreateSpecificCulture("ja-JP")
  $EvSession.ExportLogAndMessages($LogName,"LogName",$Filter,$OutFile,$True,$Locale)
}

# エクスポートしたイベントログファイルを圧縮
$ZipFile = $OutFile + ".zip"
Compress-Archive -Path $OutFile -DestinationPath $ZipFile 

# S3バケットに保存
aws s3 cp $ZipFile s3://$BucketName/

# AWS CLIのステータスコードを取得して0以外のステータスの場合にSNSメッセージを送信
# リターンコードの詳細:https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-returncodes.html
if ($lastexitcode -ne 0){
    aws sns publish --topic-arn $Arn --message "Windows EventLog S3 Upload Fail"
}Else{
    #ファイルを削除
    Remove-Item $OutFile
    Remove-Item $ZipFile

    # エクスポートした時のMetaFileが作成されるので削除(-Recurse -Forceで、rmの-rfと同じ機能となる)
    Remove-Item -Path C:\temp\LocaleMetaData -Recurse -Force
}

作った感想

久しくPowerShellで何か書くってことがなかったので、先人の方々の技術BLOGを見たりしながら記載しましたが、
半日ぐらいである程度のものが作れて、あとは内容を少し整形するだけでそれなりのものが作れました。
GUIも確かに便利だけど、サービスとサービスをくっつけて一つの動作として動かすにはやっぱりプログラムを書くのが一番楽だなとしみじみ思いました。
またふと何かおもったらプログラム書いて投稿させて頂きます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む