のぐそんブログ

暗いおじさんがシコシコ書くブログです。

AWSのEC2のインスタンスメタデータについて

インスタンスメタデータとは

インスタンスメタデータは、インスタンスに関するデータで、実行中のインスタンスを設定または管理するために使用します。

docs.aws.amazon.com

取得方法

curlコマンドで取得

[ec2-user@ip-XX-X-X-115 XX~]$ curl http://169.254.169.254/latest/meta-data
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hibernation/
hostname
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups

ami-idを取得したい場合は、

[ec2-user@ip-XX-X-X-115 XX~]$ curl http://169.254.169.254/latest/meta-data/ami-id
ami-0ce107ae7af2e92b5

ec2-metadataコマンドで取得

[ec2-user@ip-XX-X-X-115 XX~]$ ec2-metadata --help
ec2-metadata v0.1.2
Use to retrieve EC2 instance metadata from within a running EC2 instance.
e.g. to retrieve instance id: ec2-metadata -i
         to retrieve ami id: ec2-metadata -a
         to get help: ec2-metadata --help
For more information on Amazon EC2 instance meta-data, refer to the documentation at
http://docs.amazonwebservices.com/AWSEC2/2008-05-05/DeveloperGuide/AESDG-chapter-instancedata.html

Usage: ec2-metadata <option>
Options:
--all                     Show all metadata information for this host (also default).
-a/--ami-id               The AMI ID used to launch this instance
-l/--ami-launch-index     The index of this instance in the reservation (per AMI).
-m/--ami-manifest-path    The manifest path of the AMI with which the instance was launched.
-n/--ancestor-ami-ids     The AMI IDs of any instances that were rebundled to create this AMI.
-b/--block-device-mapping Defines native device names to use when exposing virtual devices.
-i/--instance-id          The ID of this instance
-t/--instance-type        The type of instance to launch. For more information, see Instance Types.
-h/--local-hostname       The local hostname of the instance.
-o/--local-ipv4           Public IP address if launched with direct addressing; private IP address if launched with public addressing.
-k/--kernel-id            The ID of the kernel launched with this instance, if applicable.
-z/--availability-zone    The availability zone in which the instance launched. Same as placement
-c/--product-codes        Product codes associated with this instance.
-p/--public-hostname      The public hostname of the instance.
-v/--public-ipv4          NATted public IP Address
-u/--public-keys          Public keys. Only available if supplied at instance launch time
-r/--ramdisk-id           The ID of the RAM disk launched with this instance, if applicable.
-e/--reservation-id       ID of the reservation.
-s/--security-groups      Names of the security groups the instance is launched in. Only available if supplied at instance launch time
-d/--user-data            User-supplied data.Only available if supplied at instance launch time.

ami-idを取得したい場合は、

[ec2-user@ip-XX-X-X-115 XX~]$ ec2-metadata -a
ami-id: ami-0ce107ae7af2e92b5

curlコマンドとec2-metadataの使い分け

curlコマンドは値だけ取得できるのでプログラムで利用するのに向いている。
ec2-metadataコマンドはデータのkeyも取得されるので、プログラムで利用する場合は不便。
ただ、ec2-metadata --allなので、値を確認するのに便利。

なので、

  • curlコマンド     ・・・プログラムで利用
  • ec2-metadataコマンド・・・EC2の情報を確認するのに使用

パーミッションについて

パーミッション

ファイルの実行権限のこと。
どの種類のオーナーが、このファイルに対して何ができるのか。

以下のコマンドで確認することができる。

ls -la

パーミッションは以下のように9桁で表示される。

-rwxrwxrwx 1 root root

f:id:nogson2:20210118222628p:plain

権限 説明
r Read 読み込み権限
w Write 書き込み権限
x Execute 実行権限
- 権限なし

パーミッションの変更

パーミッション変更時は、「読み込み」「書き込み」「実行可能」を3ビットの2進数で表し、8進数へ変換したものを利用します。

8進数 権限
1 --x
2 -w-
3 -wx
4 r--
5 r-x
6 rw-
7 rwx

フル権限である-rwxrwxrwxにする場合は、以下を実行する。

chmod 777 ファイル名

所有者が読み取りのみできる-r-------のようにするには、以下を実行する。

chmod 400 ファイル名

Laravel Passportをやってみるメモ

Laravel Passportを利用した場合のメモ。

ライブラリインストール。

$ composer require laravel/passport

マイグレーションを実行。

$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (83.67ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (55.75ms)
Migrating: 2016_06_01_000001_create_oauth_auth_codes_table
Migrated:  2016_06_01_000001_create_oauth_auth_codes_table (68.58ms)
Migrating: 2016_06_01_000002_create_oauth_access_tokens_table
Migrated:  2016_06_01_000002_create_oauth_access_tokens_table (103.69ms)
Migrating: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrated:  2016_06_01_000003_create_oauth_refresh_tokens_table (119.95ms)
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrated:  2016_06_01_000004_create_oauth_clients_table (73.17ms)
Migrating: 2016_06_01_000005_create_oauth_personal_access_clients_table
Migrated:  2016_06_01_000005_create_oauth_personal_access_clients_table (37.69ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (58.61ms)

安全なアクセストークンを生成するのに必要な暗号キーを作成します。
さらにアクセストークンを生成するために使用する、「パーソナルアクセス」クライアントと「パスワードグラント」クライアントも作成します。

Clientはユーザではなくアクセストークンを利用するアプリケーションのこと。

生成された情報はoauth_clientsテーブルに保存されます。

$ php artisan passport:install
Personal access client created successfully.
Client ID: 1
Client secret: Pn1hA2F8ngjZwPxcmYb3aZ9CqqRRM9zWJNwPtNqZ
Password grant client created successfully.
Client ID: 2
Client secret: hDdQbSAX484FRtCQpHafotaMEfBv0ryuWCn7kvUN

Personal access clientPassword grant clientが作成されます。

Laravel標準のusersテーブルをPassport認証に使用する。

◎ app/Models/User.php

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens; // 追加

class User extends Authenticatable
{
    use HasFactory;
    use Notifiable;
    use HasApiTokens; // 追加

    ...
}

◎ app/Providers/AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * アプリケーションのポリシーのマップ
     *
     * @var array
     */
    protected $policies = [
        'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * 全認証/認可サービスの登録
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
    }
}

Passport::routes()を追加したあと、`php artisan route:listをするとルーティングが追加されている。 f:id:nogson2:20201130225222p:plain

テストユーザーを作成

Seederを作成。

◎ database/seeders/UsersTabaleSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class UsersTabaleSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $param = [
            'name' => 'taro',
            'email' => 'taro@example.com',
            'password' => Hash::make('test')
        ];

        DB::table('users') -> insert($param);
    }
}

database/seeders/DatabaseSeeder.phpにも以下を追加。

public function run()
{
    $this->call(UsersTabaleSeeder::class);
}

php artisan db:seedを実行。

リクエストしてみる(Personal Access Token)

とりあえず、いきなりtokenが発行されるPersonal Access Tokenで試してみます。

routers/apiに以下を追加。

Route::get('/test', function(){
    $user = App\Models\User::find(1);
    $token = $user->createToken('')->accessToken;
    return response()->json(['token' => $token]);
});

http://localhost/api/testを実行。

Bearer tokenが発行される。

{
  "token": "eyJ0eXAiOiJKV1QiL..."
}

リクエストヘッダーにAuthorization : Bearer eyJ0eXAiOiJKV1QiL...をつけて、
http://localhost/api/userを実行。

user情報が返却される。

{
  "id": 1,
  "name": "taro",
  "email": "taro@example.com",
  "email_verified_at": null,
  "created_at": null,
  "updated_at": null
}

リクエストしてみる(Password Grant Token)

パスワードを送信してTokenが発行される、よくある認証方式です。

php artisan passport:installで作成したPassword grant clientを利用します。

認可サーバhttp://localhot/oauth/token(Laravel)に POSTリクエストを送信します。

リクエストパラメータはこちら。

{
    "grant_type": "password",
    "client_id": "2",
    "client_secret": "hDdQbSAX484FRtCQpHafotaMEfBv0ryuWCn7kvUN",
    "username": "taro@example.com",
    "password": "test",
    "scope": ""
}

アクセストークンが返却される。

{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
}

リクエストヘッダーにAuthorization : Bearer eyJ0eXAiOiJKV1QiL...をつけて、
http://localhost/api/userを実行。

user情報が返却される。

{
  "id": 1,
  "name": "taro",
  "email": "taro@example.com",
  "email_verified_at": null,
  "created_at": null,
  "updated_at": null
}

続く ...

composer require実行時にAllowed memory size of 1610612736 bytes exhausted エラーが発生する

composer require実行時に以下のエラーが発生。

Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes)

memory_limitの設定値を確認。

 $ php -r "echo ini_get('memory_limit').PHP_EOL;"
128M

php.iniの場所を確認する。

$ php -i | grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php/7.4
Loaded Configuration File => /usr/local/etc/php/7.4/php.ini

php.iniを編集。

$ vi /usr/local/etc/php/7.4/php.ini
; memory_limit = 128M 
memory_limit = -1 ←こちらに変更

取りあえずの対処の場合

とりあえずで良い場合の以下のコマンドできるようでした。

$ COMPOSER_MEMORY_LIMIT=-1 composer require xxxx/xxxx

CodeDeployと CodePipelineを使ってEC2に自動デプロイのメモ

自動でEC2にソースをデプロイにチャレンジです。
次回やるときの為ののメモです。

自動デプロイの流れ

違うかもしれませんが、やりたいことはこんなイメージです。

  1. githubにpush
  2. CodePipelineをが起動
  3. codeDeployがEC2にpush

EC2の設定

CodeDeploy エージェントをインストールする

そのままではCodeDeployからEC2が操作できないのでAgentを追加する必要がある。

Amazon Linux 用または RHEL 用の CodeDeploy エージェントをインストールする - AWS CodeDeploy

$ sudo yum update
$ sudo yum install ruby
$ sudo yum install wget
$ cd /home/ec2-user
// アジアパシフィック (東京)の場合
// wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
$ wget https://{bucket-name}.s3.{region-identifier}.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto

サービスが正しく実行されているかは以下のコマンドで確認。

$ sudo service codedeploy-agent status

実行されていない場合、デプロイ時に以下のようなエラーが発生する。

The overall deployment failed because too many individual instances failed deployment, too few healthy instances are available for deployment, or some instances in your deployment group are experiencing problems.

クライアント側の設定

CodeDeployにはappspec.ymlが必要で、同期させるファイルのルートに配置する必要がある。

version: 0.0
os: linux
files:
    - source: /index.html
      destination: /var/www/html/
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies
      timeout: 300
      runas: root
    - location: scripts/start_server
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server
      timeout: 300
      runas: root
  • files
    • source : 同期元
    • destination : 同期先
  • hooks
    • BeforeInstall(例) : イベント名
      • location : イベントで実行するファイル(場所)
      • timeout : 実行時間
      • runas : ユーザー
scripts/install_dependencies

apacheをインストールする。

 #!/bin/bash
yum install -y httpd
scripts/start_server

apacheを起動する。

#!/bin/bash
service httpd start
scripts/stop_server

apacheを停止する。

#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  $isExistApp ]]; then
    service httpd stop        
fi

イベントフック

デプロイは アプリケーションの停止 アプリケーションファイルのダウンロード アプリケーションファイルのインストール アプリケーションの起動 という順で実行され、 次のデプロイライフサイクル図において、オレンジ背景の箇所が実際にフック処理を割り込めるイベントです。

f:id:nogson2:20201029202126p:plain

参考:CodeDeployのApplicationStopイベントフックはどう実行される?

※ ApplicationStopは2回目のデプロイ移行実行される

CodeDeployの設定

アプリケーションとデプロイグループを作成

CodeDeploy > アプリケーション > 「アプリケーションの作成」ボタンを押す。

アプリケーション名を入力して、コンピューティングプラットフォームに「EC2/オンプレミス」を選択。

f:id:nogson2:20201029202105p:plain

デプロイグループを作成する。

f:id:nogson2:20201029223758p:plain f:id:nogson2:20201029223906p:plain

githubを接続

CodeDeploy > アプリケーション > codedeploy-test > codedeploy-group-test > 「デプロイ作成」を押す。

必要項目を入力する。

f:id:nogson2:20201029234233p:plain

デプロイする。

f:id:nogson2:20201029234616p:plain

CodePipelineの設定

CodePipeline > パイプライン > 「パイプラインを作成する」ボタンを押す。

パイプラインの設定

「パイプライン名」を入力。

ソースステージを追加する

ソースプロバイダーに「Github」。 リポジトリ、ブランチに対象のものを設定。

ビルドステージを追加する

Dockerイメージを作成する必要がある場合や、javaなどのコンパイル言語の場合に利用します。
phpやrubyのソースを配置するだけであれば、ビルドが必要ないのでスキップします、

デプロイステージを追加する

デプロイプロバイダーはCodeDeployを選択。
その他の項目もCodeDeployで作成したものを設定する。

パイプラインを作成

codepipelineが作成されて、デプロイが実行されます。

f:id:nogson2:20201030230541p:plain

CodePipelineを利用する場合はEC2にS3にアクセスする権限を与える必要があります。
権限がない場合は以下のようなエラーが発生します。

f:id:nogson2:20201030231050p:plain

S3への権限を追加する。

f:id:nogson2:20201030232013p:plain

クロスドメインでBasic認証を自動ログインさせるメモ

あまり無いと思いますが、クロスドメインでベーシック認証をする必要があったので、
忘れないようにメモしておきます。

仕組みとしては以下のイメージ。

  1. クライアント(表示元)にiframeを埋める。
  2. iframeのsrcにベーシック認証先のサーバーに配置したcgiファイルを指定する
  3. cgiでクライアント(表示元)のjsを呼び出す。
  4. クライアント(表示元)のjsでベーシック認証を行う。

※ 手順3のcgiでベーシック認証を行っても良いかも

f:id:nogson2:20201015155310p:plain

CGIを追加

/etc/httpd/conf/httpd.confに以下を追加。

ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options None
   Order allow,deny
   Allow from all
</Directory>

/var/www/cgi-binにcgiファイルを配置。

vi /var/www/cgi-bin/authentication.cgi

中身はこんな感じ。

#!/usr/bin/perl --
print "Content-type: text/html\n\n";
print "<html><head>\n";
print "<script type=\"text/javascript\" src=\"http://hoge.co.jp/authentication.js\"></script>\n";
print "</head></html>\n";
exit;

該当のcgiファイルの権限を変更。

chmod 755 authentication.cgi

クライアント(http://hoge.co.jp)にjsフィアルを用意。 ベーシック認証用のスクリプトを用意する。 ※第3引数のasyncはtrue (非同期) or false (同期)は要件によって。

(function () {
  const xhr = new XMLHttpRequest()
  xhr.open("GET", "http://fuga.com",
    false, "user", "password")
  xhr.send(null);
}());

ただし、上記だと通信内容にログイン情報が出てしまうので、リクエストヘッダーのAuthorizationを利用することで少し隠蔽することができます。

(function() {
  const xhr = new XMLHttpRequest()
  const authorizationBasic = window.btoa('user' + ':' + 'password')
  xhr.open('GET', 'http://fuga.com"', false)
  xhr.setRequestHeader('Authorization', 'Basic ' + authorizationBasic)
  xhr.send(null)
})()