RDSとS3でファイルのやり取りを行う

データベースサーバ上にファイルを置いて、PL/SQLのUTL_FILE経由で読み書きするような処理があった場合、RDSに移行しようとすると、データベースサーバにファイルが置けないなあ・・・などという場合に、S3を間に置く方法があります。

前提

EC2 <-file-> S3 <-file-> RDS上のファイル
というやり取りについて記載しています。
また、以下の情報は2017年8月時点のものです。

Oracle on Amazon RDSでの制限

前提として、Oracle on RDSでできることを整理しましょう。S3にアクセスするにはUTL_HTTPパッケージが必要です。ユーザーガイドの「utl_http、utl_tcp、utl_smtp の使用」にサポートされる旨が記載されています。
次に、UTL_FILEによるアクセスです。UTL_FILEを用いるにはディレクトリオブジェクトを扱える必要があります。こちらについてもユーザーガイドの「主要データストレージ領域で新しいディレクトリを作成する」にて、rdsadmin.rdsadmin_util.create_directoryプロシージャを使用して可能なことが記載されています。

使用するライブラリ

UTL_HTTPを使ったS3へのアクセスを全て自分で書くのは大変なので、alexandria-plsql-utilsのAMAZON_AWS_S3_PKGを用いることにします。

準備手順

EC2, S3のバケット、RDSをすべて新規で構成する手順を見ていきましょう。順序としては以下のようになります。
1. RDSを作成する。
2. S3にバケットを作成する。
3. バケットに含まれるオブジェクトへのアクセス権を持つポリシーを作成する。
4. 3で作成したポリシーを持つロールを付与したEC2を作成する。
5. 3で作成したポリシーを持つユーザを作成する。
6. RDSにディレクトリを作成し、S3へのアクセスに必要な権限と5で作成したユーザのアクセス情報を設定する。
7. EC2とS3のやり取りを行ってみる。
8. RDSとS3のやり取りを行ってみる。

1. RDSの作成

まず、いきなりRDSを作成するのではなく、先にRDSのメニューから「オプショングループ」を選択し、「apex」という名前でAPEX及びAPEX-DEVを含むオプショングループを作成して下さい。これは、AMAZON_AWS_S3_PKGが内部でデコード関連でAPEXのライブラリを使用しているためです(APEXを実際に起動する必要はありません)。以下のようになります。
スクリーンショット 2017-08-19 17.32.40.png

apexオプショングループを用いてRDSを作成して下さい。指定箇所はパラメータグループの下にあります。次のようになります。
スクリーンショット 2017-08-19 17.34.53.png
あとは通常のRDSの作成と同様です。RDSの作成については以下を参照して下さい。
RDSユーザーガイド-Oracle DB インスタンスを作成して Oracle DB インスタンス上のデータベースに接続する

2. S3バケットの作成

特に特筆すべきことはありません。グローバルで一意になる名前でS3にバケットを作成しましょう。
S3入門ガイド-バケットの作成

3. ポリシーの作成

IAMから2で作成したバケットに含まれるオブジェクトへのアクセス権限を持つポリシーを作成します。
IAM -> ポリシーで「ポリシーの作成」を押したら、「独自のポリシーの作成」を選びましょう。
スクリーンショット 2017-08-19 17.46.37.png
ポリシー名には「allow-rds-s3-policy」などとし、ポリシードキュメントには以下のJSONを記述します。

S3-rds-policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::<手順2で作成したS3バケットの名前>"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::<手順2で作成したS3バケットの名前>/*"
            ]
        }
    ]
}

このポリシーは2で作成したS3バケット、及びオブジェクトに対する権限を付与します。これをEC2、及びRDSのPL/SQLアクセス時に有効にすれば、EC2 <-> S3 <-> RDS上のPL/SQLでファイルをやり取りできます。

4. EC2インスタンスの作成

3の手順で作成したポリシーを付与したEC2用のIAMロールを作成します。IAMサービスから
ロール -> 新しいロールの作成 -> EC2ロールタイプ と選択し、
スクリーンショット 2017-08-20 0.33.30.png

3の手順で作成したポリシーを付与して
スクリーンショット 2017-08-20 0.34.37.png

名前をつければ完了です。
スクリーンショット 2017-08-20 0.37.17.png

あとはこのロールを指定してEC2インスタンスを作成します。
スクリーンショット 2017-08-20 0.39.29.png
1の手順で作成したRDSに1521ポートで接続可能なサブネットに作成して下さい。
EC2インスタンスの作成については以下も参照して下さい。
インスタンスの作成

5. PL/SQL用IAMユーザの作成

PL/SQLにIAMロールは付与できないので3の手順で作成したポリシーを付与したユーザをPL/SQL用に作成します。IAMサービスから
ユーザー -> ユーザーの追加
を選択し、ユーザー名を入力して「プログラムによるアクセス」を有効にします。
スクリーンショット 2017-08-20 0.45.29.png
アクセス権限の設定画面では、「既存のポリシーを直接アタッチ」を選択し、3の手順で作成したポリシーをチェックします。
スクリーンショット 2017-08-20 0.48.06.png
作成が完了した際に得られる「アクセスキー ID」と「シークレットアクセスキー」をPL/SQL側で使用することになります。

6. RDS上での設定

RDS上ではディレクトリの作成と、アクセス権限の設定を行います。
設定を行う前に、4の手順で作成したEC2インスタンスにログインし、必要なツールを入れます。

SQL*Plus

OTNのInstant Client Downloads for Linux x86-64から、basic及びsqlplusの2つのパッケージをブラウザ経由でダウンロードし、EC2インスタンスに転送してインストールして下さい(オラクル社のSSOログインが要求されますので、ブラウザで実施する必要があります)。
以下のように12.2のrpmをインストールした場合には、OCIライブラリやSQL*Plusのバイナリは/usr/lib/oracle/12.2/client64にインストールされています。

SQL*Plusのインストール
$ sudo rpm -i oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
$ sudo rpm -i oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
$ ls /usr/lib/oracle/12.2/client64/bin/
adrci  genezi  sqlplus
$ ls /usr/lib/oracle/12.2/client64/lib/
glogin.sql             libmql1.so       libocijdbc12.so   libsqlplusic.so
libclntsh.so.12.1      libnnz12.so      libons.so         ojdbc8.jar
libclntshcore.so.12.1  libocci.so.12.1  liboramysql12.so  xstreams.jar
libipc1.so             libociei.so      libsqlplus.so
$

以下のように.bash_profileを設定しておきましょう。これでいつでもRDSにログインできます。

~/.bash_profile
...
ORACLIENT=/usr/lib/oracle/12.2/client64
export PATH=$PATH:$HOME/.local/bin:$HOME/bin:$ORACLIENT/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLIENT/lib

alias sql="sqlplus '<DBユーザー>@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<DB名>.<エンドポイント>.ap-northeast-1.rds.amazonaws.com)(PORT=1521))(CONNECT_DATA=(SID=<DBのSID>)))'"

alexandria-plsql-utils

Gitでクローンし、AMAZON_AWS_S3_PKGをインストールします。

alexandria-plsql-utilsのインストール
$ sudo yum install git
...
完了しました!
$ git clone https://github.com/mortenbra/alexandria-plsql-utils.git
Cloning into 'alexandria-plsql-utils'...
remote: Counting objects: 447, done.
remote: Total 447 (delta 0), reused 0 (delta 0), pack-reused 447
Receiving objects: 100% (447/447), 382.00 KiB | 0 bytes/s, done.
Resolving deltas: 100% (184/184), done.
Checking connectivity... done.
$ cd alexandria-plsql-utils/
$ ls
README.md  alexandria-logo.jpg  demos  doc  extras  ora  setup
$ ls setup/
$ sql      #前節で設定したエイリアスでRDSへ接続
...
SQL> @install_core
...
SQL> show errors
No errors
SQL> @install_inet
...
SQL> show errors
No errors
SQL> @install_amazon
...
SQL> show errors
No errors
SQL> exit
$

ACLの設定

明示的にACLを設定しない限りUTL_HTTPによるアウトバウンドのアクセスはOracleにより全て拒否されます。次のようにDBMS_NETWORK_ACL_ADMINパッケージを用いて自ユーザから手順2で作成したs3バケットに対してのみアクセスを許可します。

create_acl.sql
declare
   l_myuser varchar(32);
begin
   select user into l_myuser from dual;
   dbms_network_acl_admin.create_acl(
     acl         => 's3',
     description => 's3 acl',
     principal   => l_myuser,
     is_grant    => true,
     privilege   => 'connect'
   );
   dbms_network_acl_admin.add_privilege(
     acl         => 's3',
     principal   => l_myuser,
     is_grant    => true,
     privilege   => 'resolve'
   );
   dbms_network_acl_admin.assign_acl(
     acl         => 's3',
     host        => '<手順2で作成したバケット名>.s3.amazonaws.com'
   );
end;
/

ディレクトリの作成

RDS側の格納先であるメインデータストレージ領域上のディレクトリを作成します。以下では2つ作成しています。テーブル名などと同じく、Oracleのデータベース・オブジェクト名となるので引用符で囲まなければ大文字となります。
データベース・オブジェクト名および修飾子

create_directory.sql
begin
  rdsadmin.rdsadmin_util.create_directory('EC2');
  rdsadmin.rdsadmin_util.create_directory('S3');
end;
/

アクセス

EC2からS3へのアクセス

テスト用ファイルとしてAWSのEC2オファーファイルを使い、EC2とS3のオファーファイルをそれぞれ異なるディレクトリに配置しておきましょう。

テスト用ファイルのダウンロード
$ mkdir ~/files
$ cd ~/files
$ mkdir ec2 s3
$ wget -O ec2/ec2-price.csv https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/index.csv
...
ec2/ec2-price.csv   100%[===================>]  92.92M  29.9MB/s    in 3.1s    
...
$ wget -O s3/s3-price.csv https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonS3/current/index.csv
...
s3/s3-price.csv     100%[===================>] 870.02K  --.-KB/s    in 0.05s   
...
$

EC2からS3へのコピー

EC2ではAWS CLIが使え、手順4でS3への権限をロールで与えているので、以下のコマンドを打てば完了です。

S3へのupload
$ cd ~/files
$ aws s3 cp ec2/ec2-price.csv s3://<手順2で作成したバケット名>/ec2/ec2-price.csv
upload: ec2/ec2-price.csv to s3://<手順2で作成したバケット名>/ec2/ec2-price.csv
$ aws s3 cp s3/s3-price.csv s3://<手順2で作成したバケット名>/s3/s3-price.csv
upload: s3/s3-price.csv to s3://<手順2で作成したバケット名>/s3/s3-price.csv
$

S3からEC2へのコピー

以下のコマンドを打てば完了です。

S3からのdownload
$ cd ~/files
$ rm -R */*.csv #ファイルを消しておきます
$ aws s3 cp s3://<手順2で作成したバケット名>/ec2/ec2-price.csv ec2/ec2-price.csv
download: s3://<手順2で作成したバケット名>/ec2/ec2-price.csv to ec2/ec2-price.csv
$ aws s3 cp s3://<手順2で作成したバケット名>/s3/s3-price.csv s3/s3-price.csv
download: s3://<手順2で作成したバケット名>/s3/s3-price.csv to s3/s3-price.csv       
$ ls -R
.:
ec2  s3

./ec2:
ec2-price.csv

./s3:
s3-price.csv
$

RDSからS3へのアクセス

AMAZON_AWS_S3_PKGはBLOBとS3オブジェクトをインタフェースします。
認証とやり取りのためのBLOBとして1つテーブルを用意しておきます。

rds_s3_config.sql
create table rds_s3_config (
  key varchar2(32) primary key,
  value varchar2(128),
  tmpblob blob
);
insert into rds_s3_config (key, value) values ('aws_id', '<手順5で得たアクセスキーID>');
insert into rds_s3_config (key, value) values ('aws_key', '<手順5で得たシークレットアクセスキー>');
insert into rds_s3_config (key, value) values ('aws_s3_bucket', '<手順2で作成したS3バケット名>');
insert into rds_s3_config (key, tmpblob) values ('temporary_blob', empty_blob());
commit;
実行結果
SQL> @rds_s3_config

Table created.


1 row created.


1 row created.


1 row created.


1 row created.


Commit complete.

SQL> 

S3からRDSへのコピー

S3からオブジェクトをBLOBで取り出し、BLOBをファイルに書き込みます。次のようなプロシージャを作成しておきます。

copy_s3_to_local.sql
create or replace procedure copy_s3_to_local(
  p_s3_bucket varchar2,
  p_s3_key varchar2,
  p_local_dir varchar2,
  p_local_file varchar2
) is
  l_aws_id      varchar2(128);
  l_aws_key     varchar2(128);

  l_blob        blob;
  l_length      integer;
  l_index       integer := 1;
  l_bytecount   integer;
  l_tempraw     raw(32767);
  l_file        utl_file.file_type;
  l_dir         varchar2(128);
begin
  select value into l_aws_id from rds_s3_config where key = 'aws_id';
  select value into l_aws_key from rds_s3_config where key = 'aws_key';
  amazon_aws_auth_pkg.init(l_aws_id, l_aws_key);

  l_blob := amazon_aws_s3_pkg.get_object(p_s3_bucket, p_s3_key);
  -- エラーレスポンスかどうかを粗く判定
  if utl_raw.cast_to_varchar2(dbms_lob.substr(l_blob,256,1)) like '%<Error>%' then
    raise NO_DATA_FOUND;
  end if;

  l_length := dbms_lob.getlength(l_blob);
  l_file  := utl_file.fopen(p_local_dir, p_local_file, 'wb', 32767);

  while l_index <= l_length
  loop
      l_bytecount  := 32767;
      DBMS_LOB.read(l_blob, l_bytecount, l_index, l_tempraw);
      utl_file.put_raw(l_file, l_tempraw);
      l_index      := l_index + l_bytecount;
  end loop;
  utl_file.fflush(l_file);
  utl_file.fclose(l_file);
end;
/
show errors

実行結果
SQL> @copy_s3_to_local

Procedure created.

No errors.
SQL> 

テストしてみましょう。

copy_s3_to_local_test.sql
set serveroutput on
begin
  copy_s3_to_local('<手順2で作成したS3バケット名>', 'ec2/ec2-price.csv', 'EC2', 'ec2-price.csv');
  copy_s3_to_local('<手順2で作成したS3バケット名>', 's3/s3-price.csv', 'S3', 's3-price.csv');
end;
/
テスト:S3からRDSへのダウンロード
SQL> @copy_s3_to_local_test

PL/SQL procedure successfully completed.

SQL> 

RDSからS3へのコピー

ファイルからテーブル上のBLOBに書き込み、S3にアップロードします。次のようなプロシージャを作成しておきます。

copy_local_to_s3.sql
create or replace procedure copy_local_to_s3(
  p_local_dir varchar2,
  p_local_file varchar2,
  p_s3_bucket varchar2,
  p_s3_key varchar2
) is
  l_aws_id      varchar2(128);
  l_aws_key     varchar2(128);

  l_blob        blob;
  l_handle      bfile;
  l_dir         varchar2(128);
  l_doffset     pls_integer := 1;
  l_soffset     pls_integer := 1;
begin
  select value into l_aws_id from rds_s3_config where key = 'aws_id';
  select value into l_aws_key from rds_s3_config where key = 'aws_key';
  amazon_aws_auth_pkg.init(l_aws_id, l_aws_key);

  select tmpblob into l_blob from rds_s3_config where key = 'temporary_blob' for update;
  l_handle := bfilename(p_local_dir, p_local_file);
  dbms_lob.fileopen(l_handle, dbms_lob.file_readonly);
  dbms_lob.loadblobfromfile(l_blob, l_handle, dbms_lob.getlength(l_handle), l_doffset, l_soffset);
  -- このサンプルはContent-TypeをCSVに固定
  amazon_aws_s3_pkg.new_object(p_s3_bucket, p_s3_key, l_blob, 'text/csv');
  dbms_lob.fileclose(l_handle);
  rollback;
end;
/
show errors

テストしてみましょう。

copy_local_to_s3_test.sql
set serveroutput on
begin
  copy_local_to_s3('EC2', 'ec2-price.csv', '<手順2で作成したS3バケット名>', 'ec2/ec2-price.csv');
  copy_local_to_s3('S3', 's3-price.csv', '<手順2で作成したS3バケット名>', 's3/s3-price.csv');
end;
/
テスト
$ aws s3 rm s3://<手順2で作成したS3バケット名>/ec2/ec2-price.csv #ファイルを削除
delete: s3://<手順2で作成したS3バケット名>/ec2/ec2-price.csv
$ aws s3 rm s3://<手順2で作成したS3バケット名>/s3/s3-price.csv   #ファイルを削除
delete: s3://<手順2で作成したS3バケット名>/s3/s3-price.csv
$ aws s3 ls s3://<手順2で作成したS3バケット名>/ec2/ #空であることを確認
$ aws s3 ls s3://<手順2で作成したS3バケット名>/s3/  #空であることを確認
$ sql
... 
SQL> @copy_local_to_s3_test

PL/SQL procedure successfully completed.

SQL> exit
...
$ aws s3 ls s3://<手順2で作成したS3バケット名>/ec2/ #アップロードされたことを確認
2017-08-21 13:44:18   97438744 ec2-price.csv
$ aws s3 ls s3://<手順2で作成したS3バケット名>/s3/  #アップロードされたことを確認
2017-08-21 13:44:20     890903 s3-price.csv
$

まとめ

以上、EC2とS3のファイルのやり取り、そしてS3とRDSのファイルのやり取りについて見てきました。
より本格的に処理するには、特に紹介したPL/SQLプロシージャにおいて、S3へのアップロードのContent-Typeを適切に選択したり、エラーレスポンス(XMLドキュメントが返される)の判定を厳密にしたりなどが必要となるでしょう。

続きを読む

【合格しました!】AWS 認定ソリューションアーキテクト アソシエイト 受験記

AWS認定ソリューションアーキテクト アソシエイトを受験しました。
受験に向けてどんな事をしたのか、そんな勉強をしたのかをまとめます。

結果

合格しました!
得点は74%でした。
試験中に手ごたえがあまりなくドキドキでしたが、無事合格できてうれしいです!

所感

今回、認定取得を目指して学習したことで、AWSの知識が相当増えたと感じます。
具体的には

  • AWSのサービスを使用してシステムをどう構成すればよいのか
  • AWSのおのおののサービスの得意なこと不得意なこと
  • AWSにおけるベストプラクティス

というようなことが学べ、業務にいかすことができると感じています。

認定をとりたい、という方はもちろん、業務で使えるAWSの知識をもっと増やしたい、という方にもおすすめの認定です。

受験記です。

受験前のAWS歴

AWSを本格的に使っているのはここ1年ほどです。使用しているサービスは、EC2、RDS、S3などの基本的なサービスです。
構築するときは、調べながら&先輩に聞きながら、というのがほとんどでした。

勉強期間

約1カ月です。

学習前に行ったこと

1.受験要綱の確認
AWS認定ソリューションアーキテクト アソシエイトから「試験ガイドのダウンロード」ができます。ここを読みます。

2.AWS クラウドサービス活用資料集の「AWS認定試験準備に向けて」という部分を読む
AWS認定試験準備に向けて
AWS公式で、受験に向けてどのようなことをすればよいか公開されています。
ここを読んで参考にしました。
ですが、ここに書いてあることすべてを行ったわけではありません。
たとえば、「QwikLABS」は行いませんでした。中身を見たところ、いままでやったことがあるものだったのでやりませんでした。
また、「認定試験準備ワークショップの受講」も行っていません。

3.ほかの方の体験記を読みあさる
他のかたの体験記を読みあさり、何をもとに勉強すればよいかの参考にさせていただきました。

学習(1) ~対策本を読む~

※以下、学習(1)~と数字がついています。一応数字順に私は行っていきましたが、途中で(3)の途中で(1)もう一回やったりみたいなこともしました。

まずは唯一出ている対策本を読みました。

合格対策 AWS認定ソリューションアーキテクト – アソシエイト

こちらがとても勉強になりました。
ポイントがまとまっており、これを読んだだけでAWSの知識がだいぶ増えました。
これのおかげで業務でAWSを扱うときに自信を持てるようになったと思います。
この対策本は結局3回ほど読み直しました。
合わせて以下の本も読みました。

Amazon Web Services実践入門 (WEB+DB PRESS plus)

1冊目は対策本という位置づけなこともあり、各サービスがものすごく詳しく書かれているわけではありません。2冊目の本もあわせて読むことで知識を補っていきました。

学習(2) ~サンプル問題~

AWS認定ソリューションアーキテクト アソシエイトから「サンプル問題のダウンロード」ができます。
対策本を1周した時点で解いてみました。間隔をつかむためにもやっておいたほうがよいと思われます。
(あまりわからず衝撃を受けます。。。)

学習(3) ~クラウドデザインパターンを知る~

クラウドデザインパターンについて学びました。Webでも見れますし、書籍も出ています。

Amazon Web Services クラウドデザインパターン設計ガイド 改訂版

ユースケースを学ぶ、という意味でとても勉強になります。
50以上のデザインパターンがあり数は多いのですが、一つ一つのボリュームはそんなに多くないので、サクサク読めました。
知らないサービスもできてきますので、その時は調べながら進めました。

学習(4) ~各サービスについて知る~

AWS クラウドサービス活用資料集
ここに一番時間を割きました&とても勉強になりました。
各サービスの詳細な知識はここで補完しました。

EC2、ELB、Auto Scaling、
EBS、S3、RDS、DynamoDB、ElastiCache、
VPC、Route 53、
CloudWatch、CloudTrail、CloudFormation、
IAM、
SNS/SQS、
のサービスは何度も読みました。
また、上記のサービス以外については、AWS クラウドサービス活用資料集のページをざっとながめて、全然知らないサービスについては、概要とユースケースを確認するようにしました。

学習(5) ~活用事例やベストプラクティスを知る~

各サービスの知識はもちろん重要なのですが、AWSの考え方や実際の事例も重要です。

AWS クラウドサービス活用資料集の、以下の活用事例を読みました。

  • Web サービス StartUP 向け スケーラブルな構成例
  • AWS上の暗号化ソリューション
  • AWSにおけるセキュリティとコンプライアンス
  • AWS 上での DDoS 対策
  • クラウドのためのアーキテクチャ設計 -ベストプラクティス-

また、AWS Summitの資料も参考になりました。
AWS Summit Tokyo 2017 セッション資料・動画一覧
「AWS Well-Architected フレームワークによるクラウド ベスト プラクティス」など参考になります。

学習(6) ~ホワイトペーパーを読む~

AWS ホワイトペーパー
英語のものが多いのですが、日本語のものはいくつか読みました。
対策本を一度読んだあとにもいくつか読んだのですが、知らないサービスがあったり、知らない考え方があったりでなかなか読み進められませんでした。
各サービスについて知ったり、ベストプラクティスを知った後に読んだことでさくさく読めました。
ホワイトペーパーを読むことで知識を再確認したり、定着させることができたと思います。

学習(7) ~模擬試験~

模擬試験を受けることができます。
本試験と同じ操作をすることができるので、有料ですが、受験しておいたほうがよいと思います。
問題の雰囲気もつかめると思います。わからなかったところは復習しました。
アカウントを登録する必要がありますが、本試験でも必要になるアカウントです。
模擬試験の場合は、模擬試験の購入後、好きなタイミングで自分のパソコンで受験することができます。
時間、問題数ともに本試験より少ないです。

学習(番外編) ~有料セミナーやトレーニング~

私はArchitecting on AWSを受講しました。
最初に書いた「QwikLABS」も無料で受けられる範囲と有料で受けられる範囲とがあります。

前日

当日受験するテストセンターの場所と持ち物の確認をしました。

当日

最後に合格対策 AWS認定ソリューションアーキテクト – アソシエイトについている各章末問題をもう一度見直して、不安なところをググったりしていました。

学習法番外編 ~実家での勉強~

(大したことではないのですが・・・)
ちょうどお盆で実家に帰省する、した、という方も多いのではないでしょうか?
私も帰省後、東京に戻ってすぐ試験、という日程でした。
実家にいるとなかなか勉強できない!と思いましたので、

  • 友達と会う時間の2時間前に出かけて、外で勉強する
  • 家では寝る前等にさくっとこなせることをする(深く考えることは外で)
    • 問題といたり、クラウド活用集のスライドぱらぱらと見たり

最初はなかなか勉強できなさそうだし、どうしよう・・・と思っていましたが、思いのほか勉強できました。
やはり限られた時間で集中して行ったことがよかったと思います。
上記以外の時間は家族と出かけたりくっちゃべったり友達と会ったりと充実して過ごせたのではと思います。

いままで休日は「丸一日勉強するぞー」なんて意気込んで、結局集中できないことがたくさんありました(丸一日集中なんて無謀ですよね・・・)。
今後は丸一日勉強スタイルはやめようと思います。
思いもよらず、勉強のスタイルも見直すことができました。

続きを読む

[2017夏版] AWS Start-up ゼミ参考資料リンク集をマークダウンに起こしました

TL;DR

こんにちは。AWSリハビリ中のnntsuguです。

[AWS Start-up ゼミ] よくある課題を一気に解説!〜御社の技術レベルがアップする 2017 夏期講習〜

先日参加させていただいたAWS Stat-upゼミ、講師のSA塚田さんの資料がとても良かった。
AWS上でサービスを構築運用する上での勘所がユースケースベースで整理されていて、モヤモヤしていた部分がかなりスッキリししました。

資料内にある参考資料や動画へのLink、とても勉強になるのですが、

  • PDFやSlideShareだとスマホから参照しづらい
  • 未読管理をしやすくするため

マークアップに起こしました。

毎朝ジムで走りながら参考資料の動画を見て聞いています。とても捗ります。

参考資料は主にBlack Beltの資料&動画アーカイブ、AWS Summit/Dev Dayの資料で構成されています。

ユーザ動向を分析したい

CI/CDをちゃんとしたい

コンテナを使いたい

運用監視ちゃんとしたい

システム負荷下げたい

(モバイルアプリの)Growth Hackしたい

コスト下げたい

  • AWS Black Belt Online Seminar資料&動画

    • クラウドのためのアーキテクチャ設計-ベストプラクティス-(資料|動画)
    • Auto Scaling (資料 | 動画)
    • Amazon EC2 Spot Instances (資料 | 動画)
    • サーバーレスによるアーキテクチャパターンのご紹介 (資料 | 動画)
  • AWS Summit/Dev Day講演資料 (2016 | 2017)
    • AWS のコスト最適化入門 (2017)(資料 | 動画)
    • [インティメート・マージャー様] AWS Summit 2017 講演資料 Amazon ECS と SpotFleet を活用した低コストでスケーラブルなジョ
      ブワーカーシステム(資料 | 動画)
    • AWS Well-Architected フレームワークによるクラウド ベスト プラク
      ティス (2017) (資料 | 動画)

その他

IPOとBuy Out、デューデリジェンス

続きを読む

IAMポリシーをAnsibleで管理する

はじめに

以前、AnsibleでIAMユーザおよびグループを管理するPlaybookをご紹介しましたが、今回はAnsibleでIAMポリシーを管理してみたいと思います。

やること

  • グループにインラインポリシーアタッチ
  • グループに管理ポリシーアタッチ

ポイント

  • Ansibleのモジュールは管理ポリシーの操作に対応していないので、AWS CLIにて実装

注意

ポリシーのデタッチには対応していません。
ユーザへのアタッチ、ロールについては今回はフォローしていません。

前提

  • AWS関連のモジュール実行にはbotoが必要です。
  • AWS CLIが必要です。
  • credential情報は環境変数かaws configureでセットしてある必要があります。

sample

以下のグループにインラインポリシーとAWS管理ポリシーをアタッチします。
ポリシー内容はサンプルなので適当です。

  • ansible

    • インラインポリシー

      • SourceIpを制限したAdminポリシー
    • AWS管理ポリシー
      • CloudWatchReadOnlyAccess
      • AmazonEC2ReadOnlyAccess

ディレクトリ構成

ディレクトリ構成
site.yml
roles/
|--iam/
|  |--tasks/
|  |  |--main.yml
|  |--templates/
|  |  |--admin_policy.json.j2
group_vars/
|--group.yml

vars

こんな感じに変数を定義します。

group_vars/group.yml
---
my_vars:
  aws:
    iam:
      inline_policies:
        - group_name: ansible
          policy:
            - name: admin_ip_restricted
              template: admin_policy.json.j2
              params:
                condition: '{"IpAddress": {"aws:SourceIp": ["XX.XX.XX.XX/32"]}}'
      managed_policies:
        - group_name: ansible
          policy:
            - arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
            - arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess

Role

インラインポリシーは、jsonのテンプレートを読み込んで定義します。

管理ポリシーのアタッチについては、shellモジュールでAWS CLIを実行しています。
重複実行してもエラーとはなりませんが、毎回ステータスがchangedになってしまうので、アタッチ済みポリシーと突き合わせます。

aws iam list-attached-group-policiesによりターゲットグループにアタッチされている管理ポリシーのARNを取得し、結果のjsonをfrom_jsonフィルタを通してset_factモジュールに渡すと、そのままグループごとに<<グループ名>>_policiesというARNのリストが生成されます。

whenにより、上記リストに追加したい管理ポリシーARNがあるかどうかを判定しています。

roles/iam/tasks/main.yml
---
- name: IAM Inline-Policy作成
  iam_policy:
    profile: "{{ lookup('env', 'AWS_DEFAULT_PROFILE') }}"
    iam_type: group
    iam_name: "{{ item.0.group_name }}"
    policy_name: "{{ item.1.name }}"
    state: present
    policy_json: "{{ lookup( 'template', item.1.template ) }}"
  with_subelements:
    - "{{ my_vars.aws.iam.inline_policies }}"
    - policy

- name: Get managed-policy list
  shell: >-
    aws iam list-attached-group-policies 
     --group-name {{ item.group_name }} 
     --query 'AttachedPolicies[].PolicyArn'
  changed_when: no
  with_items: "{{ my_vars.aws.iam.managed_policies }}"
  register: iam_managed_policies

- name: Create managed-policy list
  set_fact:
    "{{ item.item.group_name }}_policies": "{{ item.stdout | from_json }}"
  with_items: "{{ iam_managed_policies.results }}"
  when: not ansible_check_mode

- name: Attach managed-policy
  shell: >-
    aws iam attach-group-policy 
     --group-name {{ item.0.group_name }} 
     --policy-arn {{ item.1 }}
  with_subelements:
    - "{{ my_vars.aws.iam.managed_policies }}"
    - policy
  when: "'{{ item.1 }}' not in {{ item.0.group_name }}_policies"

templates

roles/iam/templates/admin_policy.json.j2
{% set params = item.1.params %}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
{% if params.condition is defined %}
      "Resource": "*",
      "Condition": {{ params.condition }}
{% else %}
      "Resource": "*"
{% endif %}
    }
  ]
}

まとめ

これでマネコンからだと分かりづらいポリシーを管理しやすくなるかと思います。
こちらのRoleの後ろに連結して一つのRoleとしても使えますのでお試しください。

参考

AnsibleでAWSリソースを管理するシリーズ

続きを読む

AWS SDK for Java がデフォルトで参照する credential

aws-sdk-java 1.11.179 を参照して書いています。

AWS SDK for Java はデフォルトでいろんな場所から認証情報を読み込みます。
DefaultAWSCredentialsProviderChain の JavaDoc を見ると結構書いてあります。これと各 Provider の実装を見ながらどうなっているか見ていきます。

次のものを順番に試して最初に見つかった認証情報を利用するようになっています。

  1. 環境変数 EnvironmentVariableCredentialsProvider

    • AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 環境変数 (Java 以外の SDK でも利用しているのでこちらのほうがオススメ)
    • AWS_ACCESS_KEYAWS_SECRET_KEY 環境変数
    • AWS STS を利用する場合は AWS_SESSION_TOKEN 環境変数
  2. Java システムプロパティ SystemPropertiesCredentialsProvider
    • aws.accessKeyIdaws.secretKey システムプロパティ
    • AWS STS を利用する場合は aws.sessionToken システムプロパティ
  3. プロファイル認証情報 ProfileCredentialsProvider
    • デフォルトのファイルは ~/.aws/credentials
    • ファイルの場所は AWS_CREDENTIAL_PROFILES_FILE 環境変数で指定できる
    • 昔使われていた ~/.aws/config も一応読みこまれる
    • ファイル内には複数の認証情報を記載できる。デフォルトでは default プロファイルが読み込まれる
    • AWS_PROFILE 環境変数、あるいは aws.profile システムプロパティでプロファイルを指定できる
    • 再読込ロックが獲得できれば5分に一度再読込される
    • 再読込ロックが獲得できなくても10分に一度再読込される
  4. EC2コンテナ内で利用可能な認証情報 EC2ContainerCredentialsProviderWrapper

環境変数やシステムプロパティを使ってかなりの設定ができるので、ほとんどの場合でデフォルトのままで十分です。自前で Credentials provider chain を作ると却って柔軟性が落ちて辛いということになりかねません。環境変数やシステムプロパティが利用できず、どうしてもカスタムしたいときは DefaultAWSCredentialsProviderChain を鎖の最後につなげておけば良いでしょう。

続きを読む

[個人メモ]IAMの情報をAWS CLIで確認する

はじめに

AWS CLIでIAMを操作する場合、コマンドがいろいろあって混乱するので、個人的によく使うものを用途に応じてまとめてみました。

ユーザ関連

一覧取得

command
aws iam list-users 
--query 'Users[].UserName' 
result
[
    "user1",
    "user2",
    "user3"
]

所属グループ取得

command
aws iam list-groups-for-user 
--user-name USERNAME 
--query 'Groups[].GroupName' 
result
[
    "group1",
    "group2",
    "group3"
]

グループ関連

一覧取得

command
aws iam list-groups 
--query 'Groups[].GroupName' 
result
[
    "group1",
    "group2",
    "group3"
]

ポリシー関連

管理ポリシー

AWS管理ポリシー一覧

command
aws iam list-policies --scope AWS
result
{
    "Policies": [
        {
            "PolicyName": "AWSDirectConnectReadOnlyAccess",
            "CreateDate": "2015-02-06T18:40:08Z",
            "AttachmentCount": 0,
            "IsAttachable": true,
            "PolicyId": "ANPAI23HZ27SI6FQMGNQ2",
            "DefaultVersionId": "v1",
            "Path": "/",
            "Arn": "arn:aws:iam::aws:policy/AWSDirectConnectReadOnlyAccess",
            "UpdateDate": "2015-02-06T18:40:08Z"
        },
        {
            "PolicyName": "AmazonGlacierReadOnlyAccess",
            "CreateDate": "2015-02-06T18:40:27Z",
            "AttachmentCount": 0,
            "IsAttachable": true,
            "PolicyId": "ANPAI2D5NJKMU274MET4E",
            "DefaultVersionId": "v2",
            "Path": "/",
            "Arn": "arn:aws:iam::aws:policy/AmazonGlacierReadOnlyAccess",
            "UpdateDate": "2016-05-05T18:46:10Z"
        },

...snip...

カスタマー管理ポリシー一覧

command
aws iam list-policies --scope Local
result
{
    "Policies": [
        {
            "PolicyName": "CUSTOMER_POLICY",
            "CreateDate": "2016-02-22T08:32:23Z",
            "AttachmentCount": 1,
            "IsAttachable": true,
            "PolicyId": "XXXXXXXXXXXX",
            "DefaultVersionId": "v1",
            "Path": "/",
            "Arn": "arn:aws:iam::XXXXXXXXXXXX:policy/CUSTOMER_POLICY",
            "UpdateDate": "2016-02-22T08:32:23Z"
        }
    ]
}

なんらかのリソースにアタッチされている管理ポリシー

command
aws iam list-policies --only-attached
result
{
    "Policies": [
        {
            "PolicyName": "AmazonRDSFullAccess",
            "CreateDate": "2015-02-06T18:40:52Z",
            "AttachmentCount": 1,
            "IsAttachable": true,
            "PolicyId": "ANPAI3R4QMOG6Q5A4VWVG",
            "DefaultVersionId": "v2",
            "Path": "/",
            "Arn": "arn:aws:iam::aws:policy/AmazonRDSFullAccess",
            "UpdateDate": "2015-12-16T21:02:23Z"
        },
        {
            "PolicyName": "AmazonS3FullAccess",
            "CreateDate": "2015-02-06T18:40:58Z",
            "AttachmentCount": 1,
            "IsAttachable": true,
            "PolicyId": "ANPAIFIR6V6BVTRAHWINE",
            "DefaultVersionId": "v1",
            "Path": "/",
            "Arn": "arn:aws:iam::aws:policy/AmazonS3FullAccess",
            "UpdateDate": "2015-02-06T18:40:58Z"
        },
    ]
}

グループにアタッチされている管理ポリシー

command
aws iam list-attached-group-policies 
--group-name GROUPNAME 
--query 'AttachedPolicies[].PolicyArn'
result
[
    "arn:aws:iam::aws:policy/AdministratorAccess"
]

グループにアタッチされている管理ポリシードキュメント

command
aws iam get-policy-version 
--version-id v1   #管理ポリシーのバージョン
--policy-arn POLICYARN 
--query 'PolicyVersion.Document'
result
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "*",
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

インラインポリシー

ユーザにアタッチされているインラインポリシー

command
aws iam list-user-policies 
--user-name USERNAME
result
{
    "PolicyNames": [
        "INLINE_POLICY"
    ]
}

ユーザにアタッチされているインラインポリシードキュメント

command
aws iam get-user-policy 
--user-name USERNAME 
--policy-name INLINE_POLICY 
--query 'PolicyDocument'
result
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "*",
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

グループにアタッチされているインラインポリシー

command
aws iam list-group-policies 
--group-name GROUPNAME
result
{
    "PolicyNames": [
        "INLINE_POLICY"
    ]
}

グループにアタッチされているインラインポリシードキュメント

command
aws iam get-group-policy 
--group-name GROUPNAME 
--policy-name INLINE_POLICY 
--query 'PolicyDocument'
result
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "*",
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

続きを読む

serverless frameworkを使ってデプロイ

serverless frameworkってなんなん

YAMLに設定を書いておくと、CLIでAWSのデプロイ/設定が行えます。
簡単に言うと、デプロイの自動化ができます。

環境

項目 version
node 6.10.2
serverless framework 1.19.0

インストール

serverless frameworkをglobalにインストール。

npm install -g serverless

config credentials

serverless framework docs AWS – Config Credentials

プロジェクト作成

serverless frameworkのコマンドを使用してプロジェクトを作成します。

mkdir serverless-sample
serverless create -t aws-nodejs

以下内容のファイルが作成されます。試してみたら見れますがw

handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
serverless.yml
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: serverless-sample

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
  name: aws
  runtime: nodejs6.10

# you can overwrite defaults here
#  stage: dev
#  region: us-east-1

# you can add statements to the Lambda function's IAM Role here
#  iamRoleStatements:
#    - Effect: "Allow"
#      Action:
#        - "s3:ListBucket"
#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
#    - Effect: "Allow"
#      Action:
#        - "s3:PutObject"
#      Resource:
#        Fn::Join:
#          - ""
#          - - "arn:aws:s3:::"
#            - "Ref" : "ServerlessDeploymentBucket"
#            - "/*"

# you can define service wide environment variables here
#  environment:
#    variable1: value1

# you can add packaging information here
#package:
#  include:
#    - include-me.js
#    - include-me-dir/**
#  exclude:
#    - exclude-me.js
#    - exclude-me-dir/**

functions:
  hello:
    handler: handler.hello

#    The following are a few example events you can configure
#    NOTE: Please make sure to change your handler code to work with those events
#    Check the event documentation for details
#    events:
#      - http:
#          path: users/create
#          method: get
#      - s3: ${env:BUCKET}
#      - schedule: rate(10 minutes)
#      - sns: greeter-topic
#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
#      - alexaSkill
#      - iot:
#          sql: "SELECT * FROM 'some_topic'"
#      - cloudwatchEvent:
#          event:
#            source:
#              - "aws.ec2"
#            detail-type:
#              - "EC2 Instance State-change Notification"
#            detail:
#              state:
#                - pending
#      - cloudwatchLog: '/aws/lambda/hello'
#      - cognitoUserPool:
#          pool: MyUserPool
#          trigger: PreSignUp

#    Define function environment variables here
#    environment:
#      variable2: value2

# you can add CloudFormation resource templates here
#resources:
#  Resources:
#    NewResource:
#      Type: AWS::S3::Bucket
#      Properties:
#        BucketName: my-new-bucket
#  Outputs:
#     NewOutput:
#       Description: "Description for the output"
#       Value: "Some output value"

region設定

regionの設定を追記します。

serverless.yml
--- 省略 ---
provider:
  name: aws
  runtime: nodejs6.10
  region: ap-northeast-1
--- 省略 ---

API Gateway設定

上記ロジックを呼ぶエンドポイントの設定を追記。

serverless.yml
--- 省略 ---
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: serverless-sample
          method: get
--- 省略 ---

デプロイ

serverless frameworkのコマンドを使用してデプロイします。
serverless.ymlに記載の内容でデプロイされます。

serverless deploy

参考

serverless

続きを読む

AWS SystemsManagerを使ってみたメモ

(WIP)まだ修正中なのでどんどん追加していく

AWS SystemsManagerを使用してみた

脆弱性検知、自動パッチ当て、構成管理などなど幅広く使用できるAWSマネージドサービスと聞いて使ってみた。
とりあえずAWSマネジメントコンソールのEC2のサイドバーの上から実施していく。

サマリ

  1. コマンドの実行
  2. ステートマネージャー
  3. 自動化
  4. Patch Compliance
  5. パッチベースライン

コマンドの実行

ここではランコマンドなるものの実行ができるらしい
ただし前準備が色々必要そうなのでまとめてみる…
1. IAMロール作成(EC2インスタンス用、ユーザー用)
まずはEC2インスタンス用から作成
IAMロール作成画面から作成する
  image.png

  image.png

image.png

次に現在サインインしているIAMユーザーに設定されているロールに対して下記ポリシーをアタッチする
– AmazonSSMFullAccess
– AmazonSSMReadOnlyAccess

  1. SSMエージェントのインストール
    インストールコマンドを実行していく(AmazonLinux201703)
mkdir /tmp/ssm
cd /tmp/ssm
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
  1. ドキュメント選択
    適当なドキュメントを選択する
    今回はansibleでyum updateとかしてみようと思ったので、ansibleのplaybookを実行できるドキュメントを使用する
    image.png

playbookを書いていざ実行してみると、、、
ansibleがインストールされていないとのこと(笑)
image.png

なのでansibleをインストールして再度実行してみる、すると、、、
image.png

無事成功!

ステートマネージャー

自動化

Patch Compliance

パッチベースライン

参考

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-setting-up.html?icmpid=docs_ec2_console

続きを読む