AWS認定プレミアコンサルティングパートナーのcloudpack、『Trend Micro Deep Security(TM) 運用 …

AWS環境のセキュリティベストプラクティスの導入~運用をドキュメント化~ アマゾン ウェブ サービス(AWS)を基盤とした24時間365日のフルマネージドサービス … 続きを読む

AWS認定プレミアコンサルティングパートナーのcloudpack、『Trend Micro Deep Security™ 運用ホワイト …

アマゾン ウェブ サービス(AWS)を基盤とした24時間365日のフルマネージドサービスを提供するcloudpack(クラウドパック、運営:アイレット株式会社、本社:東京 … 続きを読む

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

Fresh Install bitnami redmine stack on AWS, then migrate old data and database from old instance.

目的: Redmine のバージョンアップ と HTTPS化

ですが、新環境の構築手順のみやっていただければ新規構築手順としても使えます。

  • 前回書いた記事から1年ちょっと経過しました。
  • bitnami redmine stack AMI のバージョンも以下のように変化しました。(2017/06/21 現在)
    • Old version 3.2.1
    • New version 3.3.3
  • 前回は GUI でぽちぽち作成しましたが、今回は AWS CLI を中心に進めます。
  • ついでに前回書いてなかった HTTPS化 についても簡単に追記します。
  • 以下の AWS の機能を利用します。
    • Route53: ドメイン名取得、名前解決(DNS)
    • ACM(Amazon Certificate Manager): 証明書発行
    • ELB(Elastic Load Balancer): 本来は複数インスタンスをバランシングする用途に使うものですが今回は EC2 インスタンス 1台 をぶら下げ、ACM で取得した証明書を配布し外部との HTTPS通信 のために利用します。

注意と免責

  • 無料枠でない部分は料金が発生します。
  • データの正常な移行を保証するものではありません。

前提

  • 現環境が正常に動作していること。
  • 新環境を同一リージョン、同一VPC、同一サブネット内に新たにたてます。
    • インスタンス間のデータ転送を SCP で簡易に行いたいと思います。
    • 適宜セキュリティグループを解放してください。
  • aws cli version
% aws --version
aws-cli/1.11.47 Python/2.7.12 Darwin/16.6.0 botocore/1.5.10

段取り

  • 大まかに以下の順序で進めます
  1. Version 3.3.3 の AMI を使って EC2 インスタンスを起動
  2. Version 3.2.1 のデータバックアップ
    • Bitnami Redmine Stack の停止
    • MySQL Dump 取得
  3. Version 3.3.3 へのデータ復元
    • Bitnami Redmine Stack の停止
    • MySQL Dump 復元
    • Bitnami Redmine Stack の開始
  4. 動作確認

参考資料

作業手順

1. Newer Bitnami redmine stack インスタンス作成

以下の条件で作成します。

  • Common conditions

    • AMI: ami-15f98503
    • Type: t2.micro
    • Public IP: あり
  • User defined conditions
    • Region: N.Virginia
    • Subnet: subnet-bd809696
    • Security Group: sg-5b5b8f2a
    • Keypair: aws-n.virginia-default001
    • IAM Role: ec2-001
    • EBS: 20GB

WEB GUI から作るも良し、AWS CLI から作るも良し
以下コマンド実行例

set-env
KEY_NAME=aws-nvirginia-default001.pem
echo $KEY_NAME
check-ami
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503"
check-ami-name
aws ec2 describe-images \
    --filters "Name=image-id,Values=ami-15f98503" \
    | jq ".Images[].Name" \
    | grep --color redmine-3.3.3
create-instance
aws ec2 run-instances \
    --image-id ami-15f98503 \
    --count 1 \
    --instance-type t2.micro \
    --key-name aws-n.virginia-default001 \
    --security-group-ids sg-5b5b8f2a \
    --subnet-id subnet-bd809696 \
    --block-device-mappings "[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"VolumeSize\":20,\"DeleteOnTermination\":false}}]" \
    --iam-instance-profile Name=ec2-001 \
    --associate-public-ip-address
set-env
INSTANCE_ID=i-0f8d079eef9e5aeba
echo $INSTANCE_ID
add-name-tag-to-instance
aws ec2 create-tags --resources $INSTANCE_ID \
    --tags Key=Name,Value=redmine-3.3.3

注意書きにもありますが以下に表示される MySQL Database の root パスワードは初期起動時にしか表示されません。
このときに保管しておくか MySQL のお作法にしたがって変更しておいても良いでしょう

check-instance-created
aws ec2 describe-instances --filter "Name=instance-id,Values=$INSTANCE_ID"
wait-running-state
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].State["Name"]'
get-redmine-password
aws ec2 get-console-output \
    --instance-id $INSTANCE_ID \
    | grep "Setting Bitnami application password to"
get-publicip
aws ec2 describe-instances \
    --filter "Name=instance-id,Values=$INSTANCE_ID" \
    | jq '.Reservations[].Instances[].NetworkInterfaces[].Association'
set-env
PUBLIC_IP=54.243.10.66
echo $PUBLIC_IP
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)
ssh-connect
ssh -i .ssh/$KEY_NAME bitnami@$PUBLIC_IP
first-login
bitnami@new-version-host:~$ sudo apt-get update -y
bitnami@new-version-host:~$ sudo apt-get upgrade -y
bitnami@new-version-host:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
bitnami@new-version-host:~$ sudo ./stack/ctlscript.sh help
usage: ./stack/ctlscript.sh help
       ./stack/ctlscript.sh (start|stop|restart|status)
       ./stack/ctlscript.sh (start|stop|restart|status) mysql
       ./stack/ctlscript.sh (start|stop|restart|status) php-fpm
       ./stack/ctlscript.sh (start|stop|restart|status) apache
       ./stack/ctlscript.sh (start|stop|restart|status) subversion

help       - this screen
start      - start the service(s)
stop       - stop  the service(s)
restart    - restart or start the service(s)
status     - show the status of the service(s)

2. 旧バージョンのバックアップ取得

login_to_oldversion
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-74-generic x86_64)
       ___ _ _                   _
      | _ |_) |_ _ _  __ _ _ __ (_)
      | _ \ |  _| ' \/ _` | '  \| |
      |___/_|\__|_|_|\__,_|_|_|_|_|

  *** Welcome to the Bitnami Redmine 3.2.0-1         ***
  *** Bitnami Wiki:   https://wiki.bitnami.com/      ***
  *** Bitnami Forums: https://community.bitnami.com/ ***
Last login: Sun May 29 07:33:45 2016 from xxx.xxx.xxx.xxx
bitnami@old-version-host:~$
check-status
bitnami@old-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running
stop
bitnami@old-version-host:~$ sudo stack/ctlscript.sh stop
/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@old-version-host:~$ sudo stack/ctlscript.sh start mysql
170621 10:04:34 mysqld_safe Logging to '/opt/bitnami/mysql/data/mysqld.log'.
170621 10:04:34 mysqld_safe Starting mysqld.bin daemon with databases from /opt/bitnami/mysql/data
/opt/bitnami/mysql/scripts/ctl.sh : mysql  started at port 3306
check-available-filesystem-space
bitnami@old-version-host:~$ df -h /
Filesystem                                              Size  Used Avail Use% Mounted on
/dev/disk/by-uuid/6cdd25df-8610-4f60-9fed-ec03ed643ceb  9.8G  2.7G  6.6G  29% /
load-env-setting
bitnami@old-version-host:~$ . stack/use_redmine
bitnami@old-version-host:~$ echo $BITNAMI_ROOT
/opt/bitnami
dump-mysql
bitnami@old-version-host:~$ mysqldump -u root -p bitnami_redmine > redmine_backup.sql
Enter password:
bitnami@old-version-host:~$ ls -ltrh
  • scp 準備

手元の作業PCから新Redmine環境へssh接続するときに使用した証明書(pem)ファイルを旧Redmine環境にも作成します。

  • 今回は作業PC上で cat で表示させておいて旧環境のコンソール上にコピペしました。
example
bitnami@old-version-host:~$ vi .ssh/aws-nvirginia-default001.pem
bitnami@old-version-host:~$ chmod 600 .ssh/aws-nvirginia-default001.pem
  • ファイル転送
file_transfer
bitnami@old-version-host:~$ scp -i .ssh/aws-nvirginia-default001.pem redmine_backup.sql <new-version-host-ipaddr>:~
  • 新バージョン側にファイルが届いているか確認
check-transfered-files
bitnami@new-version-host:~$ ls -alh redmine*

3. 新バージョンへの復元

stop-stack
bitnami@new-version-host:~$ sudo stack/ctlscript.sh status
subversion already running
php-fpm already running
apache already running
mysql already running

bitnami@new-version-host:~$ sudo stack/ctlscript.sh stop

/opt/bitnami/subversion/scripts/ctl.sh : subversion stopped
Syntax OK
/opt/bitnami/apache2/scripts/ctl.sh : httpd stopped
/opt/bitnami/php/scripts/ctl.sh : php-fpm stopped
/opt/bitnami/mysql/scripts/ctl.sh : mysql stopped
start-mysql
bitnami@new-version-host:~$ sudo stack/ctlscript.sh start mysql
initial-database
bitnami@new-version-host:~$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.35 MySQL Community Server (GPL)

(snip)

mysql> drop database bitnami_redmine;

mysql> create database bitnami_redmine;

mysql> grant all privileges on bitnami_redmine.* to 'bn_redmine'@'localhost' identified by 'DATAB
ASE_PASSWORD';

mysql> quit
restore-dumpfile
bitnami@new-version-host:~$ mysql -u root -p bitnami_redmine < redmine_backup.sql
Enter password:
bitnami@new-version-host:~$
edit-line-18
bitnami@new-version-host:~$ vi /opt/bitnami/apps/redmine/htdocs/config/database.yml

    18    password: "DATABASE_PASSWORD"
db-migrate
bitnami@new-version-host:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake db:migrate RAILS_ENV=production
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:cache:clear
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:sessions:clear
stack-restart
bitnami@new-version-host:/opt/bitnami/apps/redmine/htdocs$ cd
bitnami@new-version-host:~$ sudo stack/ctlscript.sh restart

bitnami@new-version-host:~$ exit
site-check
curl -I http://$PUBLIC_IP/
HTTP/1.1 200 OK
(snip)

ブラウザでも http://$PUBLIC_IP/ でアクセスして旧環境のユーザー名とパスワードでログイン出来ることを確認してください。

この時点で旧環境のインスタンスを停止させておいて良いでしょう。
いらないと判断した時に削除するなりしてください。

4. おまけ HTTPS化

  • 4-1. Route53 でドメイン名を取得してください

    • .net で 年額 11 USドル程度ですので実験用にひとつくらい維持しておくと便利
  • 4-2. Certificate Manager で証明書を取得します
    • コマンドでリクエストしてます
aws acm request-certificate --domain-name redmine.hogefuga.net
check-status-pending
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"PENDING_VALIDATION"
  • 4-3. 承認する

    • ドメインに設定しているアドレスにメールが飛んできます
  • 4-4. ステータス確認
check-status-ISSUED
aws acm describe-certificate \
    --certificate-arn "arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    | jq ".Certificate.Status"
"ISSUED"
  • 4-5. Classic タイプの HTTPS ELB をつくる
example
aws elb create-load-balancer \
    --load-balancer-name redmine-elb1 \
    --listeners "Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80,SSLCertificateId=arn:aws:acm:us-east-1:942162428772:certificate/fdf099f9-ced7-4b97-a5dd-f85374d7d112" \
    --availability-zones us-east-1a \
    --security-groups sg-3c90f343
  • 4-6. インスタンスをくっつける
example
aws elb register-instances-with-load-balancer \
    --load-balancer-name redmine-elb1 \
    --instances i-0f8d079eef9e5aeba
  • 4-7. State が InService になるまで待ちます
example
aws elb describe-instance-health \
    --load-balancer-name redmine-elb1
  • 4-8. DNS Name を確認する(4-10. で使います)
example
aws elb describe-load-balancers \
    --load-balancer-name redmine-elb1 \
  | jq ".LoadBalancerDescriptions[].DNSName"
  • 4-9. 今の設定を確認
example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE | jq .
  • 4-10. 投入用の JSON をつくる
example
vi change-resource-record-sets.json
example
{
  "Comment": "add CNAME for redmine.hogefuga.net",
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "redmine.hogefuga.net",
        "Type":"CNAME",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": <DNSName>
          }
        ]
      }
    }
  ]
}

4-11. 設定投入

example
aws route53 change-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE \
    --change-batch file://change-resource-record-sets.json

4-12. 設定確認

example
aws route53 list-resource-record-sets \
    --hosted-zone-id Z3UG9LUEGNT0PE

4-13. ブラウザ確認

https://redmine.hogefuga.net

4-14. EC2 インスタンスのセキュリティグループ再設定

  • グローバルの TCP:80 削除
  • サブネット内の TCP:80 許可
check
aws ec2 describe-security-groups --group-ids sg-b7d983c8
change
aws ec2 modify-instance-attribute \
    --instance-id i-0f8d079eef9e5aeba \
    --groups sg-b7d983c8

4-15. 再度ブラウザからアクセス可能か確認

続きを読む

AWS API Gateway + Lambda Proxy で苦労した話

API GATEWAY PROXYって?

API GATEWAYから Lambdaなどにリンクする場合URIなどを具体的に設定しないといけないのだけど、 PROXYモードでまとめて全部Proxyされているサービスに投げることが可能なのだが。。。

例えば 
Link : https://<api ID>.execute-api.ap-southeast-2.amazonaws.com/<stage name>/`

API IDが abcdef, stage が development とすると。

Link : https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/

で、これに例えば IDとPhoneを追加したい場合、 普通は リソースに IDとPhoneを追加して

/{id}/{phone}
https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/1234/81-50-1234-1234

これを PROXYサービスに変えると

https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/user?id=1234&phone=81-50-1234-1234

すげーべんりじゃん?! ってのは、ふつーにだれでもわかるんだけど・・

テストでハマった

最初にCORSが面倒、LAMBDAにPROXYしてるんだけど、LAMBDAでも CORSの設定が必要とか 
下の例は、headers の アクセスコントロールとかを追加。

const returnvalue = {
                            statusCode: 200, 
                            headers: {
                                'Access-Control-Allow-Origin' : '*',
                                'Access-Control-Allow-Headers':'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
                                'Access-Control-Allow-Credentials' : true,
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify(response) 
                    };
callback(null, returnvalue);

テストをしてみたけど えらーばかり リソースをヒットしていないのがテストが不可能な状態、 JqueryではHTTP OPTION, CORSではじかれ、CURLでも 403でおかしい。

なんで 403エラー?

パラメータのパスで問題だったのだが、なにせAWSのガイドを読んでもちんぷんかんぷん。ここでかなり無駄な時間。

jqueryで テストってことで ?ID=123  

$.ajax({ url: "https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/?id=123",
        type: "GET",
        dataType: 'json',
        crossDomain: true,
        contentType: 'application/json',
        success: function(data){
           console.log(data);
        }});

をなげてたのが403で弾かれまくり、 CURLでも同じく403、いろいろ検索したら リソースにヒットしてないのでは?ってことで、やっとわかったのが

https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/?id=1234

では だめで

https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/user?id=1234

USERってのが必要。。 (なんでやねんってかんじ)

これがちゃんと動くサンプル

$.ajax({ url: "https://abcdef.execute-api.ap-southeast-2.amazonaws.com/development/user?id="+id,
        type: "GET",
        dataType: 'json',
        crossDomain: true,
        contentType: 'application/json',
        success: function(data){
           console.log(data);
        }});

さいごに・・・

AWSさん・・ 文章をもっとちゃんとしてくれ。 なにもかんでも403ってなんだよ。

続きを読む

DeepSecurity のクロスアカウントロールを CloudFormation で

[Deep Security] AWSアカウント連携をIAM Roleで設定する を CloudFormation でやるには

<account_id>公式ドキュメント を参照

---
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  ExternalId:
    Type: 'String'

Resources:
  DeepSecurityDelegationRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Condition:
              StringEquals:
                'sts:ExternalId':
                  Ref: 'ExternalId'
            Principal:
              AWS:
                - 'arn:aws:iam::<account_id>:root'
            Action:
              - 'sts:AssumeRole'

  DeepSecurityAWSIntegrationPolicy:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Action:
            - 'ec2:DescribeImages'
            - 'ec2:DescribeInstances'
            - 'ec2:DescribeRegions'
            - 'ec2:DescribeSubnets'
            - 'ec2:DescribeTags'
            - 'ec2:DescribeVpcs'
            - 'iam:ListAccountAliases'
            Resource: '*'
      Roles:
        - Ref: 'DeepSecurityDelegationRole'

Outputs:
  RoleArn:
    Value:
      'Fn::GetAtt':
        - 'DeepSecurityDelegationRole'
        - 'Arn'

  ExternalId:
    Value:
      Ref: 'ExternalId'

DeepSecurity 側の画面で CloudFormation の Outputs で出力された RoleArnクロスアカウントロールのARNExternalId外部ID へ入力。

スクリーンショット 2017-06-16 14.18.21.png

続きを読む

AWS ソリューションアーキテクトプロフェッショナル 受けてきました&勉強法(2017/6版)

前書き

image.png

 前回 の続きです。ソリューションアーキテクトアソシエイト(SAA)に受かったので今度はプロフェッショナル(SAP)に挑戦しました。

AWS の資格試験はわかりにくい

ワークショップについて

 公式サイトから読み取れないので補足。以下のクラスがありますが、

レベル/分野 アーキテクト 開発 運用
アソシエイト取得済み Advanced Architecting on AWS DevOps Engineering on AWS 同左
アソシエイト未取得向け Architecting on AWS Developing on AWS Systems Operations on AWS
AWS 未経験者向け Amazon Web Services 実践入門 1 / 2 同左 同左

 前提事項は記載ありるものの、いきなり Advanced などを受けてもいいし、受けずに受験に挑んでも大丈夫です。アソシエイト未取得向けのを2つ受ける必要はなさそうなので、Architecting 受けてから Developing 受けたりするのは、けっこう内容の重複がある ので、お金がもったいない。
 その他のクラスは試験に出てくる頻度が低いので、興味があれば受ければいいやつです。

 ソリューションアーキテクトアソシエイト(SAA) だけは試験対策として半日のワークショップがありますので、時間とお金があれば受けるといいかと。

認定試験について

 おさらいですが。
image.png

 ワークショップと同じく、範囲がかぶっているので アソシエイト取れたらほかのアソシエイトもいけそう なので、資格の数を増やすにはよさそうです、プロフェッショナルはそう簡単にいかないですが。英語版の資格として Advanced Networking 、Big Dataが追加となっています。Security(Beta) もあった気がしますが、 Beta が取れていないのかな。いずれさらに上の階級にある Master が提供されるかもしれないという噂があったりします。

試験概要

 概要をざっくり記載します。アソシエイトの倍の時間でついでに受験料も倍です。合格ラインはやはり65%という噂です。1問あたり2分ちょっとで解き、3時間集中し続ける というなかなかヘビーな内容です。

TOPIC DATA
試験時間 170分間
問題数 80問
合格ライン 非公開
受験料 ¥32,400

出題範囲

 出題範囲を確認すると、アソシエイトでは高可用性がほとんどでしたが、Pro では求められるものが変わっていることがわかります。そのほか試験ガイドをざっと読みました。

TOPIC 出題率
高可用性および事業継続性 15%
原価計算 5%
デプロイメントマネージメント 10%
ネットワーク設計 10%
データストレージ 15%
セキュリティ 20%
拡張性と伸縮自在性 15%
クラウド移行およびハイブリッドなアーキテクチャ 10%

学習

セミナーを受講する

 前述の Advanced Architecting on AWS を受講しました。
 セミナーには AWS 社員の方や、AWS をすでに実務で利用されているかたが多くいて、私のような素人も半分くらいいる印象でした。私は実業務で AWS に触れたことが実はほとんどなく、本気の AWS 運用に必要な知識を持ち合わせていなかったので次のような観点が非常に勉強になりました。

  • ユーザ管理:IAM と ADやフェデレーションでの連携を考慮し、大規模運用を考える
  • コスト観点:一括請求やスポットインスタンスの選び方で、大幅なコスト削減を考える
  • 運用・監査:KMSを使用した暗号化、CloudLogs でのロギング、ClodWatch でのモニタリングで運用・監査への対応を考える
  • 可用性・セキュリティ:大規模&複数VPCのデザイン、MultiAZ、MultiRegion で可用性向上を実現する、DDoS からインフラを保護する

AWS 活用資料集(BalckBelt)、WhitePaper を読む

 アップデートもあるので、改めて時間を見つけて読みました。時間があるときは Webinar にも参加しました。 Webinar だと日々疑問に思っていることの質問を AWS の SA に直接質問できるので、すごくおトクです。

  • BlackBelt

    • Amazon EC2
    • Elastic Load Balancing
    • Auto Scaling
    • Amazon EC2 Container Service
    • AWS Elastic Beanstalk
    • AWS Lambda
    • Amazon EBS
    • Amazon S3
    • Amazon CloudFront
    • Amazon Glacier
    • AWS Storage Gateway
    • Amazon Elastic File System
    • AWS CloudTrail & AWS Config
    • AWS Support & Trusted Advisor
    • AWS Directory Service
  • WhitePaper

    • セキュリティのベストプラクティス
    • セキュリティプロセスの概要
    • リスクとコンプライアンス
    • AWS を用いた故障耐障害性の高いアプリケーションの構築
    • 新しいリージョンへの AWS リソースの移行
    • 災害対策目的での AWS の使用

本読む

 AWS 事例全集 といった AWS が配っている冊子もありますが数がひたすら多いので、勉強用としてこちらの本で一般的なアーキテクチャを学びました。

image
Amazon Web Services 定番業務システム12パターン 設計ガイド

試験に向けて

 以下、結果もあわせて書いていきます。

サンプル問題集にチャレンジ

ソリューションアーキテクト プロフェッショナル

 サンプル問題を解いた結果、微妙でした。アソシエイトは本試験とくらべて非常に簡単だったので、先が思いやられます。

結果

4/6問 正解

ソリューションアーキテクト以外もやってみる

 SysOpsアソシエイト、DevOpsアソシエイトのサンプル問題もやってみました。ソリューションアーキテクトとはちょっと毛色の違うサービス(CloudFormationとかSQSとか)が出てくるので復習になります。Pro は回答が書いていなかったのでやっていません。

SysOps結果

6/10問 正解

DevOps結果

6/9問 正解

模擬試験

 データ書いておきます。なお、アソシエイト合格者はバウチャーコードが利用できますので活用しましょう。問題文はコピーできます。

TOPIC DATA
試験時間 90分間
問題数 40問
合格ライン 明記なし
受験料 ¥4,320

結果

得点: 27%
結果: 不合格

 時間足りなさすぎました。結果を分析しますが全体的に悪すぎて手のうちようがない感じでした。。。

TOPIC 出題率 正解率(模擬結果) 模擬出題数(予測) 誤答数(予想)
高可用性および事業継続性 15% 33% 6 4
原価計算 5% 0% 2 2
デプロイメントマネージメント 10% 0% 4 4
ネットワーク設計 10% 50% 4 2
データストレージ 15% 50% 6 3
セキュリティ 20% 25% 8 6
拡張性と伸縮自在性 15% 16% 6 5
クラウド移行およびハイブリッドなアーキテクチャ 10% 25% 4 3

出題傾向を抑える

 ベストプラクティスが複数書いてあって、どれも正解だけどよりベストなものを選ぶという問題や、コスト/可用性/移行期間/既存システムとの連携 のどれが求められているのかといった、真の目的を把握しないと答えられない問題が多くありました。
 また、昔の AWS 構成を最新のサービスで置き換えるような問題もあるため、古くなった知識はアップデートが必要です。

模擬試験の復習と弱点克服

 CloudHSM とかの暗号化系、DirectConnect/StorageGateway などの低レイヤー系、TrustedAdvisor など課金系、STS/IAMロールなどの認証系、StepFunctions や SWF などフロー系、Redshift や Kinesis などのBigData系 は、アソシエイトでも踏み込んだ問題が出なかったので個人的に苦手でした。これらは BlackBeltで復習しました。
 また、コピーした模試の問題はを1つづつ調べ、答え合わせをしました。模擬試験については本試験でも出ることがあるので暗記するつもりで復習しました。英語で回答を解説しているサイトがあるので大いに活用しました。

本試験

結果

合格!

image.png

内訳

総合スコア: 66%

トピックレベルのスコア:
1.0 High Availability and Business Continuity: 91%
2.0 Costing: 75%
3.0 Deployment Management: 62%
4.0 Network Design: 37%
5.0 Data Storage: 91%
6.0 Security: 56%
7.0 Scalability & Elasticity: 69%
8.0 Cloud Migration & Hybrid Architecture: 28%

所感

 なんとかギリギリセーフでした。本試験、すごい疲れます。。。
 実務半年程度のペーペーなので試験勉強と実務知識が比例するわけじゃなく、試験としては問題数こなすのが一番という気がしました。本試験のほうが模試より簡単だったので絶望せずがんばりましょう。

 次は DevOps に挑戦したいです。

続きを読む

IAMユーザーのAWSコンソール・CLIでの操作をSlackに通知する

概要

AWSコンソール、AWS CLIでの作業はオペミスがつきものです。
IAMで実行権限を制限する、手作業を減らすなどの対策も大切ですが、不正な変更をいち早く検知する仕組みがあるとより安心です。
今回は、次のような仕組みを実現してみたいと思います。

IAMユーザーのAWSコンソール・CLIでの操作をSlackに通知する

次の記事を参考にさせてもらいました。
セキュリティーグループが変更されたらSlackに通知する -ハンズラボエンジニアブログ

CloudTrailの設定

有効化

まずは、CloudTrailを有効化します。
AWSコンソールにログインし、CloudTrailのメニューを開きます。
まだCloudTrailの設定を行っていな環境では、以下のような画面が表示されるので、「今すぐ始める」を選択します。

start_imidiatory.png

CloudTailの有効化では、任意の「追跡名」を設定します。
※今回はすべてのリージョンを対象に適用します

enable_cloudtail.png

保存先の設定

CloudTrailで取得した追跡情報はログファイルとしてS3に保存されます。次のように保存先バケットを設定を行います。
ストレージの場所で、新しいS3バケットを作成しますかを「はい」にし「S3バケット」の名称を設定します。
※今回はプレフィックスの設定は省略し、その他の項目はデフォルトのまま進めます
スクリーンショット 2017-06-10 16.17.05.png

作成

最後に「作成」を選択してCloudTrailの作成は完了です。

CloudWatch Logsの設定

前記までで作成した追跡情報をCloudWatch Logsへ配信するように設定します。

設定

CloudTrailのメニューを開き、先ほど作成した追跡情報を選択します。
スクリーンショット_2017-06-10_16_19_26.png

CloudWatch Logsの項目にある「設定」を選択します。

スクリーンショット 2017-06-10 16.36.54.png

ロググループ名を入力し「次へ」を選択します。
スクリーンショット 2017-06-10 16.36.54.png

IAMロールの設定を求められるので、適切なロール選択するか新規で作成します。
スクリーンショット 2017-06-10 16.37.27.png

「許可」を選択してCloudWatch Logsの設定は完了です。

Lambdaの設定

CloudWatchのログストリームを受けて、Slackに内容を通知するLambda functionを用意します。
今回は、Serverless Frameworkを使ってLambda functionのデプロイを行いました。
開発環境構築は→ serverlessでLambdaのローカル開発環境を整える

プロジェクトの作成

次のコマンドでプロジェクトを初期化します。

$ sls create --template aws-nodejs --path CloudTrail-Slack

必要パッケージもインストールしておきましょう。

$ npm install async
$ npm install request

functionの作成

プロジェクト作成の手順で、プロジェクトフォルダに作成されたhandler.jsを編集します。

handler.js
'use strict';
const zlib = require('zlib');
const async = require('async');
const request = require('request');

// set slack setting
const slack_endpoint = 'https://slack.com/api/chat.postMessage';
const slack_token = process.env.SLACK_TOKEN;
const slack_channel = process.env.SLACK_CHANNEL;
const slack_user = process.env.SLACK_USERNAME;

module.exports.notify = (event, context, callback) => {
    const payload = new Buffer(event.awslogs.data, 'base64');
    zlib.gunzip(payload, (err, res) => {
        if (err) {
            return callback(err);
        }
        const parsed = JSON.parse(res.toString('utf8'));
        console.log('Decoded payload:', JSON.stringify(parsed));

        async.map(parsed.logEvents, (data, callback) => {
          notifySlack(data, callback);
        }, (err, results) =>{
          if (!err) {
            console.log(results);
            callback(null, 'success');
          }
        });
    });
}

let notifySlack = (data, callback) => {
  let log = JSON.parse(data.message);

  let attachment = {
    "fallback": log.eventName + " by " + log.userIdentity.userName,
    "color": "#36a64f",
    "author_name": log.userIdentity.userName,
    "title": log.eventName,
    "fields": [
      {
        "title": "awsRegion",
        "value": log.awsRegion,
        "short": false
      },
      {
        "title": "eventSource",
        "value": log.eventSource,
        "short": false
      },
      {
        "title": "eventId",
        "value": log.eventID,
        "short": false
      }
    ],
    "thumb_url": "https://d0.awsstatic.com/security-center/KMS_Benefit_100x100_Compliance.png",
    "ts": new Date(log.eventTime).getTime() / 1000
  }

  let payload = {
    form: {
      token: slack_token,
      channel: slack_channel,
      username: slack_user,
      attachments: JSON.stringify([attachment])
    }
  }
  // post slack message
  request.post(slack_endpoint, payload, (error, response, body) => {
        if (error) {
          console.log(error)
        } else {
          callback(null, 'slack api call success');
        }
      }
  )
}

serverlessの設定

プロジェクト作成の手順で、プロジェクトフォルダに作成されたserverless.yamlを編集します。
Slackの投稿先に関する設定は環境変数から取得するようになっています。(AWSのコンソール上から設定変更可能)
また、必要に応じてリージョンの設定なども行います。

serverless.yml
service: cloudtail-lambda # NOTE: update this with your service name

provider:
  name: aws
  runtime: nodejs6.10

functions:
  notify:
    handler: handler.notify

#    Define function environment variables here
    environment:
      SLACK_TOKEN: <すらっくのAPIとーくん>
      SLACK_CHANNEL: cloudtrail-test
      SLACK_USERNAME: CloudTrail

デプロイ

次のコマンドでデプロイします。

$ sls deploy

AWS コンソール上からもデプロイしたLambda functionが確認できました。
スクリーンショット_2017-06-10_19_02_35.png

Slackの設定

API Tokenの取得

以下の記事を参考にさせてもらいました。
Slack APIのTokenの取得・場所

チャンネルの作成

「serverlessの設定」でSLACK_CHANNELに設定したチャンネルを事前に作成しておきます。
スクリーンショット 2017-06-10 17.24.39.png

SNSとの連携

ストリームの開始

AWSコンソールから、CloudWatchのメニューを開きます。
「ログ」のメニューを開き、ロググループ一覧から今回作成したロググループを選択し、「アクション」から「Lambdaサービスへのストリーミングの開始」を選択します。
スクリーンショット_2017-06-10_17_27_52.png

ストリーム先の選択

今回作成したLambda functionを選択した後、「次へ」を選択します。
スクリーンショット_2017-06-10_18_31_49.png

フィルタ設定

ログの形式には「AWS CloudTrail」を選択した後、サブスクリプションフィルターのパターンを設定します。
スクリーンショット_2017-06-10_18_00_32.png

{ ($.userIdentity.type = "IAMUser") && (($.eventSource = "ec2.amazonaws.com") || ($.eventSource = "s3.amazonaws.com") || ($.eventSource = "iam.amazonaws.com") || ($.eventSource = "rds.amazonaws.com") || ($.eventSource = "signin.amazonaws.com"))}

$.userIdentity.type = "IAMUser"では、通知するユーザーの範囲をIAMユーザーに絞っています。これにより、Rootユーザー、IAMロールからのAPIコールは対象外となります。

$.eventSource = "<サービス名>.amazonaws.com"では、通知するサービスの範囲を絞っています。上記フィルタ設定では

  • EC2
  • S3
  • IAM
  • RDS
  • ログイン関連

のみに絞っています。

確認

IAMユーザーでAWSコンソールにログイン。S3バケットの作成を行いました。
Slackには次のような通知が確認できました。
スクリーンショット 2017-06-10 18.59.21.png

以上です。
簡単に実現できました:baby_chick:

続きを読む