RHEL7にdockerをインストールしようとして、二年前に確認した手順でセットアップしようとしたらうまくいかず、2時間ぐらい唸っていたら、いつの間にかRHUIがバージョンアップしてレポジトリ名称がごっそり変わっていたらしい。
access.redhat.com
- 変更例
もう無駄なところでハマるから、メジャーバージョンの中でこう言う変更するのやめてほしい。
RHEL7にdockerをインストールしようとして、二年前に確認した手順でセットアップしようとしたらうまくいかず、2時間ぐらい唸っていたら、いつの間にかRHUIがバージョンアップしてレポジトリ名称がごっそり変わっていたらしい。
access.redhat.com
もう無駄なところでハマるから、メジャーバージョンの中でこう言う変更するのやめてほしい。
export PROFILE=default #利用するプロファイルに変更してください export AWS_PAGER=""
VPC内からのDNSクエリーをセキュリティーグループで許可します。
# DNS用セキュリティーグループ作成 DNS_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name DnsSG \ --description "Allow Dns" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${DNS_SG_ID} \ --tags "Key=Name,Value=DnsSG" ; # セキュリティーグループにDNSのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${DNS_SG_ID} \ --protocol tcp \ --port 53 \ --cidr ${VPC_CIDR} ; aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${DNS_SG_ID} \ --protocol udp \ --port 53 \ --cidr ${VPC_CIDR} ; #メンテナンス用にSSHのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${DNS_SG_ID} \ --protocol tcp \ --port 22 \ --cidr ${SSH_SRC_CIDR};
#最新のAmazon Linux2のAMI IDを取得します。 AL2_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; echo "AL2_AMIID = ${AL2_AMIID}"
DNSリゾルバー用のEC2インスタンスを作成します。
bindの設定は、EC2インスタンスのUserDataに定義して、起動時にスクリプト実行によりセットアップさせます。BINDのforwarding先のDNSサーバを変更する場合はforwarders { 8.8.8.8; 8.8.4.4; };
の部分を修正して下さい。
TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Dns" } ] } ]' USER_DATA='#!/bin/bash -xe yum -y update yum -y install bind bind-utils hostnamectl set-hostname dns LOCAL_IP=$(curl http://169.254.169.254/latest/meta-data/local-ipv4) cat > /etc/named.conf << EOL # アクセス制御。trustというグループに属するIPアドレスを定義する。 acl "trust" { '"${VPC_CIDR}"'; 127.0.0.1; }; options { # UDP53でDNSクエリを受け付ける自分自身のIPアドレス listen-on port 53 { 127.0.0.1; ${LOCAL_IP}; }; # IPv6は使わないのでnone listen-on-v6 port 53 { none; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; # DNSクエリはaclで設定した送信元のみ許可 allow-query { trust; }; allow-query-cache { trust; }; # 再帰問い合わせもaclで問い合わせした送信元のみ許可 recursion yes; allow-recursion { trust; }; # DNS問い合わせの転送先 # Google Public DNSを利用します。 forwarders { 8.8.8.8; 8.8.4.4; }; # 問い合わせの転送に失敗した場合は自分自身で名前解決を行う # 問い合わせ転送に失敗した際名前解決をあきらめる場合はonlyを設定する forward only; dnssec-enable yes; dnssec-validation yes; bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; # DNSクエリログ用の出力設定 channel query-log { # 以下すべてのチャネルで3世代10Mごとにログローテーションを行う file "/var/log/named/query.log" versions 3 size 10M; severity info; print-category yes; print-severity yes; print-time yes; }; # ゾーン転送ログ用の出力設定 channel xfer-log { file "/var/log/named/xfer.log" versions 3 size 10M; severity info; print-category yes; print-severity yes; print-time yes; }; # 上記以外の種類のエラーログ用の出力設定 channel error-log { file "/var/log/named/error.log" versions 3 size 10M; severity error; print-category yes; print-severity yes; print-time yes; }; # ログ種別ごとの出力先設定指定 category queries { query-log; }; category xfer-in { xfer-log; }; category xfer-out { xfer-log; }; category default { error-log; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key"; EOL #ログ用フォルダの作成 mkdir /var/log/named chown -R named:named /var/log/named/ # Bindの起動 systemctl enable named systemctl start named ' # DNSサーバの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${AL2_AMIID} \ --instance-type t2.micro \ --key-name ${KEYNAME} \ --subnet-id ${DNS_RESOLVER_SUBNET} \ --security-group-ids ${DNS_SG_ID}\ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" \ --user-data "${USER_DATA}" ;
作成したDNSリゾルバーにDNSのクエリーが飛ぶように、新しいDHCPオプションセットを作成しVPCにアタッチします。新しいDHCPオプションでは、下記を設定しています。
#DNSサーバのローカルIP取得 DnsLocalIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filter "Name=tag:Name,Values=Dns" "Name=instance-state-name,Values=running" \ --query 'Reservations[].Instances[].PrivateIpAddress' \ ) echo ${DnsLocalIP} #VPC: DHCPオプションセット作成 DHCPSET_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-dhcp-options \ --dhcp-configurations \ "Key=domain-name,Values=onprem.internal" \ "Key=domain-name-servers,Values=${DnsLocalIP}" \ "Key=ntp-servers,Values=169.254.169.123" \ --query 'DhcpOptions.DhcpOptionsId'; ) #VPC: DHCPオプションセット関連付け aws --profile ${PROFILE} \ ec2 associate-dhcp-options \ --vpc-id ${VPCID} \ --dhcp-options-id ${DHCPSET_ID} ;
# DNS用セキュリティーグループ作成 CLIENT_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name ClientSg \ --description "Allow ssh" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${CLIENT_SG_ID} \ --tags "Key=Name,Value=ClientSg" ; #メンテナンス用にSSHのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${CLIENT_SG_ID} \ --protocol tcp \ --port 22 \ --cidr ${SSH_SRC_CIDR};
#クライアントインスタンス作成 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Client" } ] } ]' #ユーザデータ設定 USER_DATA='#!/bin/bash -xe yum -y update hostnamectl set-hostname client ' #インスタンス起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${AL2_AMIID} \ --instance-type t2.micro \ --key-name ${KEYNAME} \ --subnet-id ${DNS_RESOLVER_SUBNET} \ --security-group-ids ${CLIENT_SG_ID}\ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" \ --user-data "${USER_DATA}";
ssh ec2-user@<clientのIP>
#DNS参照先確認 # /etc/resolv.confの設定確認 cat /etc/resolv.conf ; generated by /usr/sbin/dhclient-script search onprem.internal options timeout:2 attempts:5 nameserver 10.1.x.x <== DNSリゾルバーインスタンスの Private IPが設定されていることを確認 # digによるDNS参照 dig amazon.co.jp ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.amzn2.0.3 <<>> amazon.co.jp ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51709 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;amazon.co.jp. IN A ;; ANSWER SECTION: <<==DNS参照の応答が正常にあることを確認 amazon.co.jp. 46 IN A 52.119.168.48 amazon.co.jp. 46 IN A 52.119.164.121 amazon.co.jp. 46 IN A 52.119.161.5 ;; Query time: 7 msec ;; SERVER: 10.1.0.14#53(10.1.0.14) <==DNSリゾルバーインスタンスの Private IPであることを確認 ;; WHEN: 月 6月 22 17:33:12 UTC 2020 ;; MSG SIZE rcvd: 89
バケットのバージョニング設定により、オブジェクトのバージョンがどのように遷移するのかがいまいちわかっていなかったので、実際に動かして整理してみました。
null
になるnull
のままnull
になるnull
のオブジェクトが存在する場合、そのオブジェクトが更新されるnull
のオブジェクトが存在しない場合は、新規にVersionIdがnull
のオブジェクトが作成される
#プロファイル指定 PROFILE=default #他のプロファイルを利用する場合はここを変更 #検証用バケットの設定用パラメータ BUCKET_NAME="versioning-test-bucket-$( od -vAn -to1 </dev/urandom | tr -d " " | fold -w 10 | head -n 1)" REGION=$(aws --profile ${PROFILE} configure get region) #テストデータ生成 dd if=/dev/urandom of=test-data-1.dat bs=4096 count=1 dd if=/dev/urandom of=test-data-2.dat bs=4096 count=2 dd if=/dev/urandom of=test-data-3.dat bs=4096 count=3 ls -l test*
#バケット作成 aws --profile ${PROFILE} \ s3api create-bucket \ --bucket ${BUCKET_NAME} \ --create-bucket-configuration LocationConstraint=${REGION}; #バージョン設定の確認 #未設定なので何もレスポンスが無いはずです。 aws --profile ${PROFILE} s3api get-bucket-versioning --bucket "${BUCKET_NAME}" #データが空であることを確認 aws --profile ${PROFILE} s3 ls "s3://${BUCKET_NAME}"
#バージョニングを設定していない状態でS3にデータを確認 aws --profile ${PROFILE} s3 cp test-data-1.dat s3://${BUCKET_NAME}/userdata01.dat aws --profile ${PROFILE} s3 cp test-data-1.dat s3://${BUCKET_NAME}/userdata02.dat
(1) オブジェクトの一覧表示
PUTした2つのオブジェクトが表示されます。
aws --profile ${PROFILE} s3 ls "s3://${BUCKET_NAME}" 2020-05-31 18:49:51 4096 userdata01.dat 2020-05-31 18:49:52 4096 userdata02.dat
(2) オブジェクトのバージョン確認
バケットに対してバージョニングが未設定の状態でオブジェクトをPUTしているため、userdata01.dat、userdata02.datともVersionIdは"null"になります。
Object | 投入タイミング | 更新時間 | VersionID | IsLatest |
---|---|---|---|---|
userdata01.dat | Versioning設定前 | 09:49:51 | null | true |
userdata02.dat | Versioning設定前 | 09:49:52 | null | true |
aws --profile ${PROFILE} s3api list-object-versions --bucket ${BUCKET_NAME} { "Versions": [ { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata01.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-05-31T09:49:51.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-05-31T09:49:52.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } } ] }
バケットに対してバージョニングを有効にします。
aws --profile ${PROFILE} s3api \ put-bucket-versioning \ --bucket "${BUCKET_NAME}" --versioning-configuration Status=Enabled;
aws --profile ${PROFILE} s3api get-bucket-versioning --bucket "${BUCKET_NAME}" { "Status": "Enabled" }
aws --profile ${PROFILE} s3 cp test-data-2.dat s3://${BUCKET_NAME}/userdata02.dat aws --profile ${PROFILE} s3 cp test-data-2.dat s3://${BUCKET_NAME}/userdata03.dat
(1) オブジェクトの一覧表示
userdata02.datが更新され、新規にuserdata03.datが追加され、合計3つのオブジェクトが表示されます。
aws --profile ${PROFILE} s3 ls "s3://${BUCKET_NAME}" 2020-05-31 18:49:51 4096 userdata01.dat 2020-06-01 14:52:14 8192 userdata02.dat 2020-06-01 14:52:16 8192 userdata03.dat
(2) オブジェクトのバージョン確認
null
のままfalse
に変更Object | 投入タイミング | 更新時間 | VersionID | IsLatest | メモ |
---|---|---|---|---|---|
userdata01.dat | Versioning設定前 | 09:49:51 | null | true | 更新なし |
userdata02.dat | Versioning設定後(1) | 05:52:14 | 0qDa.... | true | 新規追加 |
userdata02.dat | Versioning設定前 | 09:49:52 | null | false | LsLatestがfalseに変更 |
userdata03.dat | Versioning設定後(1) | 05:52:16 | TX.M.... | true | 新規追加 |
aws --profile ${PROFILE} s3api list-object-versions --bucket ${BUCKET_NAME} { "Versions": [ { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata01.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-05-31T09:49:51.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "0qDa2pi27gEqqGOdQhK5UVJVcBj_drRr", "IsLatest": true, "LastModified": "2020-06-01T05:52:14.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "null", "IsLatest": false, "LastModified": "2020-05-31T09:49:52.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "TX.MGfR96qMJ4mrIFBT61d8.Bs5McjzB", "IsLatest": true, "LastModified": "2020-06-01T05:52:16.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } } ] }
aws --profile ${PROFILE} s3 cp test-data-3.dat s3://${BUCKET_NAME}/userdata02.dat aws --profile ${PROFILE} s3 cp test-data-3.dat s3://${BUCKET_NAME}/userdata03.dat
(1) オブジェクトの一覧表示
userdata02.datとuserdata03.datが更新され、同じく3つのオブジェクトが表示されます。
aws --profile ${PROFILE} s3 ls "s3://${BUCKET_NAME}" 2020-05-31 18:49:51 4096 userdata01.dat 2020-06-01 15:27:39 12288 userdata02.dat 2020-06-01 15:27:41 12288 userdata03.dat
(2) オブジェクトのバージョン確認
true
のオブジェクトが追加され、既存オブジェクトはLsLatestがfalse
に変更Object | 投入タイミング | 更新時間 | VersionID | IsLatest | メモ |
---|---|---|---|---|---|
userdata01.dat | Versioning設定前 | 09:49:51 | null | true | 更新なし |
userdata02.dat | Versioning設定後(2) | 06:27:39 | Um.k.... | true | 新規追加 |
userdata02.dat | Versioning設定後(1) | 05:52:14 | 0qDa.... | false | LsLatestがfalseに変更 |
userdata02.dat | Versioning設定前 | 09:49:52 | null | false | 更新なし |
userdata03.dat | Versioning設定後(2) | 06:27:41 | WZ8d.... | true | 新規追加 |
userdata03.dat | Versioning設定後(1) | 05:52:16 | TX.M.... | false | LsLatestがfalseに変更 |
aws --profile ${PROFILE} s3api list-object-versions --bucket ${BUCKET_NAME} { "Versions": [ { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata01.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-05-31T09:49:51.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "Um.kAFeAkaayk3botsDRJmyvLQp6dUZr", "IsLatest": true, "LastModified": "2020-06-01T06:27:39.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "0qDa2pi27gEqqGOdQhK5UVJVcBj_drRr", "IsLatest": false, "LastModified": "2020-06-01T05:52:14.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "null", "IsLatest": false, "LastModified": "2020-05-31T09:49:52.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "WZ8dIE4sY1OzI1h6lCzESy_.W33I4xtt", "IsLatest": true, "LastModified": "2020-06-01T06:27:41.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "TX.MGfR96qMJ4mrIFBT61d8.Bs5McjzB", "IsLatest": false, "LastModified": "2020-06-01T05:52:16.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } } ] }
バケットのバージョニングをsuspendします。
aws --profile ${PROFILE} s3api \ put-bucket-versioning \ --bucket "${BUCKET_NAME}" --versioning-configuration Status=Suspended;
aws --profile ${PROFILE} s3api get-bucket-versioning --bucket "${BUCKET_NAME}" { "Status": "Suspended" }
aws --profile ${PROFILE} s3 cp test-data-3.dat s3://${BUCKET_NAME}/userdata02.dat aws --profile ${PROFILE} s3 cp test-data-3.dat s3://${BUCKET_NAME}/userdata03.dat
(1) オブジェクトの一覧表示
userdata02.datとuserdata03.datが更新され、同じく3つのオブジェクトが表示されます。
aws --profile ${PROFILE} s3 ls "s3://${BUCKET_NAME}" 2020-05-31 18:49:51 4096 userdata01.dat 2020-06-01 15:46:08 12288 userdata02.dat 2020-06-01 15:46:10 12288 userdata03.dat
(2) オブジェクトのバージョン確認
Object | 投入タイミング | 更新時間 | VersionID | IsLatest | メモ |
---|---|---|---|---|---|
userdata01.dat | Versioning設定前 | 09:49:51 | null | true | 更新なし |
userdata02.dat | Suspended状態 | 06:46:08 | null | true | 既存のnullバージョンのものを更新 |
userdata02.dat | Versioning設定後(2) | 06:27:39 | Um.k.... | false | LsLatestがfalseに変更 |
userdata02.dat | Versioning設定後(1) | 05:52:14 | 0qDa.... | false | 更新なし |
userdata02.dat | Versioning設定前 | - | - | - | 上書き更新され消滅 |
userdata03.dat | Suspended状態 | T06:46:10 | null | true | 新規追加 |
userdata03.dat | Versioning設定後(2) | 06:27:41 | WZ8d.... | false | LsLatestがfalseに変更 |
userdata03.dat | Versioning設定後(1) | 05:52:16 | TX.M.... | false | 更新なし |
aws --profile ${PROFILE} s3api list-object-versions --bucket ${BUCKET_NAME} { "Versions": [ { "ETag": "\"dadc49ab6df3592cca0ce5edd9e03886\"", "Size": 4096, "StorageClass": "STANDARD", "Key": "userdata01.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-05-31T09:49:51.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-06-01T06:46:08.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "Um.kAFeAkaayk3botsDRJmyvLQp6dUZr", "IsLatest": false, "LastModified": "2020-06-01T06:27:39.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata02.dat", "VersionId": "0qDa2pi27gEqqGOdQhK5UVJVcBj_drRr", "IsLatest": false, "LastModified": "2020-06-01T05:52:14.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "null", "IsLatest": true, "LastModified": "2020-06-01T06:46:10.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"c3cfd43243650a7c2095f744d1ad796e\"", "Size": 12288, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "WZ8dIE4sY1OzI1h6lCzESy_.W33I4xtt", "IsLatest": false, "LastModified": "2020-06-01T06:27:41.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } }, { "ETag": "\"a41d74143fff00d45a6b9997e400a32a\"", "Size": 8192, "StorageClass": "STANDARD", "Key": "userdata03.dat", "VersionId": "TX.MGfR96qMJ4mrIFBT61d8.Bs5McjzB", "IsLatest": false, "LastModified": "2020-06-01T05:52:16.000Z", "Owner": { "DisplayName": "nobuyuf", "ID": "135708a85354d2fa2c74a4f52b3a2256c9ce912005f4677f36fd73af25be2793" } } ] }
# 削除マーカーがついているオブジェクトの削除 aws --profile ${PROFILE} --output text \ s3api list-object-versions \ --bucket ${BUCKET_NAME} \ --query 'DeleteMarkers[].{Key:Key,VersionId:VersionId}' | while read key versionid do aws --profile ${PROFILE} \ s3api delete-object \ --bucket ${BUCKET_NAME} \ --key ${key} \ --version-id ${versionid} done # それ以外のオブジェクトの削除 aws --profile ${PROFILE} --output text \ s3api list-object-versions \ --bucket ${BUCKET_NAME} \ --query 'Versions[].{Key:Key,VersionId:VersionId}' | while read key versionid do aws --profile ${PROFILE} \ s3api delete-object \ --bucket ${BUCKET_NAME} \ --key ${key} \ --version-id ${versionid} done
aws --profile ${PROFILE} \ s3api delete-bucket \ --bucket "${BUCKET_NAME}"
S3のバケットを削除する場合、まずバケットを空にする必要があります。ここではAWS CLIを利用しバケットを空にし、その後にバケットを削除する手順を記載します。
具体的には list-object-versionsでオブジェクトをリストアップし、delete-objectでオブジェクトを一つづつ削除します。なお記載する例は、バケットの中のオブジェクトが1000個未満の場合に利用できます。(list-object-versionsの1回の実行でリストされるオブジェクトの最大個数がデフォルトでは1000のため*1 )
ちなみにaws s3 rm s3://バケット名 --recursive
やaws s3 rb s3://バケット名 --force
で最初試しましたが、バージョニングが有効な場合これらのコマンドでは削除マーク
が付くだけですし、バージョニングされた古いオブジェクトは何もされず、オブジェクトが消えないため、このようなやり方をする必要がありました。(ユーザーガイド*2にもバージョニングが有効で無い場合に限ってと注釈がありますね )
PROFILE="<AWS CLIのプロファイルを指定する。デフォルトの場合はdefault>" BUCKET_NAME="<対象のバケット名を設定する>"
# 削除マーカーがついているオブジェクトの削除 aws --profile ${PROFILE} --output text \ s3api list-object-versions \ --bucket ${BUCKET_NAME} \ --query 'DeleteMarkers[].{Key:Key,VersionId:VersionId}' | while read key versionid do aws --profile ${PROFILE} \ s3api delete-object \ --bucket ${BUCKET_NAME} \ --key ${key} \ --version-id ${versionid} done # それ以外のオブジェクトの削除 aws --profile ${PROFILE} --output text \ s3api list-object-versions \ --bucket ${BUCKET_NAME} \ --query 'Versions[].{Key:Key,VersionId:VersionId}' | while read key versionid do aws --profile ${PROFILE} \ s3api delete-object \ --bucket ${BUCKET_NAME} \ --key ${key} \ --version-id ${versionid} done
aws --profile ${PROFILE} \ s3api delete-bucket \ --bucket "${BUCKET_NAME}"
m5・c5・t3などのNitroタイプのインスタンスを利用している場合にOS上で認識しているボリュームがどのEBSボリュームかを、Volume IDベースで確認する手順です。
なおXenベースのインスタンス(m4以前、c5以前、t2以前など)は調べた限りでは、残念ながらVolume IDでのボリューム特定方法は見つかりませんでした。(Xenの準仮想化ドライバ blk_frontでデバイス情報を表示する実装がそもそもなさそう)
CLIのaws ec2 describe-instances
で対象インタンスにアタッチされているEBSボリュームの情報を確認することができます。
aws ec2 describe-instances --instance-ids i-03e048ef20e38a8d7 \ --query 'Reservations[].Instances[].BlockDeviceMappings' ; [ [ { "DeviceName": "/dev/xvda", "Ebs": { "AttachTime": "2020-04-09T05:46:34.000Z", "DeleteOnTermination": true, "Status": "attached", "VolumeId": "vol-0b5cbc3d4d6d5a965" } } ] ]
nvmeのCLIをインストールしてnvmeデバイスの情報を取得します。4行目のsn
の部分に表示されますが、vol-xxxxxxxxxxx
の"-"がないのでコピーして利用する時は注意してください。
#CLIのインストール sudo yum -y install nvme-cli #ボリュームの情報取得 sudo nvme id-ctrl /dev/nvme0|head -n 5 NVME Identify Controller: vid : 0x1d0f ssvid : 0x1d0f sn : vol0b5cbc3d4d6d5a965 mn : Amazon Elastic Block Store
コマンドの中では指定したデバイスに対して、ioctlでデバイス情報の取得をしています。straceで実際に取得する部分でを表示すると以下の通りです。 ioctl()のシステムコールでオペレーションコードにNVME_IOCTL_ADMIN_CMD
を指定し情報取得をしています。
# nvmeコマンドのstrace結果(抜粋) open("/dev/nvme0", O_RDONLY) = 3 fstat(3, {st_mode=S_IFCHR|0600, st_rdev=makedev(245, 0), ...}) = 0 ioctl(3, NVME_IOCTL_ADMIN_CMD, 0x7ffc7436f9c0) = 0 fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0224788000 close(3)
ebsnvme-idはpythonで実装されており、こちらもnvmeコマンドと同様ioctl()システムコールで情報取得していますが、オペレーションコードにNVME_IOCTL_ADMIN_CMD
を指定し情報取得をしています。
# ebsnvme-idコマンドのstrace結果(抜粋) openat(AT_FDCWD, "/dev/nvme0", O_RDONLY) = 3 fstat(3, {st_mode=S_IFCHR|0600, st_rdev=makedev(248, 0), ...}) = 0 ioctl(3, NVME_IOCTL_ADMIN_CMD, 0x7ffdf50dddb0) = 0 close(3)
諸事情で、PostgreSQL11.6 クライアントとクライアントの開発環境(ECPG - C言語による埋め込みSQLのアプリ用ビルド環境)をRHEL8上で、32bitで準備する必要があって手順を確認したものです。32bitでビルドするポイントはconfigureの時にオプションで--build="i686-pc-linux-gnu" "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32"
とすることです。
bzip2はtarの解凍に、glibc-devel.i686 readline-devel.i686 zlib-devel.i686は、PostgreSQL11.7(32bit)のビルドの前提です。
sudo yum -y install gcc bzip2 make sudo yum -y install glibc-devel.i686 readline-devel.i686 zlib-devel.i686
curl https://ftp.postgresql.org/pub/source/v11.6/postgresql-11.6.tar.bz2 --output postgresql-11.6.tar.bz2 tar -jxf postgresql-11.6.tar.bz2 cd postgresql-11.6
インストール先はデフォルトは/usr/local/pgsql/
になります。ここではインストール先を--prefix=XXXX
オプションで/usr/local/pgsql-i686
に指定します。
./configure --build="i686-pc-linux-gnu" "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32" --prefix="/usr/local/pgsql-i686" make sudo make install
32bitのバイナリーが出来上がっていることを確認します。
cd /usr/local/pgsql-i686/ #ファイルの確認 file lib/libpq.so.5.11 lib/libpq.so.5.11: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=a8582904f50478302be75a9aea0174f414dc9b04, not stripped
インストールしたPostgreSQL11.6 クライアント(32bit)のコマンドが実行できるようにパスを追加します。
#プロファイルにパスを追加 echo 'PATH="$PATH:/usr/local/pgsql-i686/bin"' >> ~/.bashrc source ~/.bashrc #パスの確認 which ecpg /usr/local/pgsql-i686/bin/ecpg <-- ecpgコマンドが表示されることを確認
ECPGによるC言語による埋め込みSQLのサンプルプログラムを利用した32bitアプリケーションのビルドとDBへの接続テストを行います。
ファイル名sample.pgc
で、下記サンプルコードを書きます。
こちらのコードは、DBにコネクトして、DB名の取得とカレンと時間を取得するだけのDB接続テスト用のサンプルコードです。
#include <stdio.h> #include <string.h> #define BUFF_SIZE 1024 EXEC SQL BEGIN DECLARE SECTION; char dbname[BUFF_SIZE]; char tmpstr[BUFF_SIZE]; char target[BUFF_SIZE]; char user[BUFF_SIZE]; char pass[BUFF_SIZE]; EXEC SQL END DECLARE SECTION; int main(int argc, char **argv) { if( argc > 3 ){ strncpy(target, *(argv+1), BUFF_SIZE); strncpy(user, *(argv+2), BUFF_SIZE); strncpy(pass, *(argv+3), BUFF_SIZE); }else{ printf("Invalid argument(s): ./sample 'dbname@host:port' 'user' 'password'\n"); return(1); } printf("target=%s user=%s pass=%s\n",target, user, pass); EXEC SQL CONNECT TO :target USER :user IDENTIFIED BY :pass; EXEC SQL SELECT current_database() INTO :dbname; printf("current_database=%s \n", dbname); EXEC SQL select cast(current_timestamp as varchar) INTO :tmpstr; printf("current_timestamp=%s \n", tmpstr); EXEC SQL DISCONNECT; return 0; }
下記コマンドでビルドします。
ecpg sample.pgc gcc -o sample -m32 -I/usr/local/pgsql-i686/include/ -L/usr/local/pgsql-i686/lib/ -lecpg -lpq -Wl,--rpath=/usr/local/pgsql-i686/lib/ sample.c
下記コマンドを実行し、データベース名と現在の時刻が表示されれば接続成功です。
./sample "DBNAME@Host:Port" "UserName" "Password" current_database=データベース名が表示 current_timestamp=現在の時刻が表示
AWSが提供しているAWS Security Hubの一括設定ツールを試したのでそのメモです。
なんでこのツールを利用したかと言うと、AWS Security Hubはリージョン単位のサービスのためリージョンごとの設定が必要で、かつマルチアカウント構成の場合アカウント毎の設定になるので、作業量が「対象AWSアカウント数 x 対象リージョン数」となり手動でのセットアップは骨が折れるので、楽をしたいと言うのが発端です。
AWS Security Hubのマルチアカウント一括設定ツール
github.com
上記ツールですが、下記のマネコンAWS Security Hubの「設定」で出る「GitHubでスクリプトを実行します」のリンク先のスクリプトになります。
マルチアカウントのベストプラクティスである Landing Zoneにならい、下記アカウントがあるマルチアカウント構成を前提とします。
AWS Security Hubは、監査アカウントをMasterアカウントとして、他のアカウントはメンバーアカウントとして招待し作成したHubに所属させます。
全アカウントにツールを実行するためのIAMロールを作成します。
Gitに含まれるCloudFormation(EnableSecurityHub.yaml)で、IAMロールを作成することもできますが、ここではCLIで作成しています。
PROFILE=<auditアカウントのIAM管理可能なプロファイル>
スクリプトを実行するEC2にアタッチするインスタンスロールを作成します。
ASSUMEROLE_POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }' ROLE_POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "AssumeToManageSecurityHubRoleOfMemberAccounts", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::*:role/ManageSecurityHubRole" } ] }' #IAMロールの作成 aws --profile ${PROFILE} \ iam create-role \ --role-name "ManageSecurityHubInstanceRole" \ --assume-role-policy-document "${ASSUMEROLE_POLICY}" \ --max-session-duration 3600 #インラインポリシーのアタッチ aws --profile ${PROFILE} \ iam put-role-policy \ --role-name "ManageSecurityHubInstanceRole" \ --policy-name "ManageSecurityHubPolicy" \ --policy-document "${ROLE_POLICY}" #インスタンスプロファイルの作成 aws --profile ${PROFILE} \ iam create-instance-profile \ --instance-profile-name "ManageSecurityHubInstanceRole"; aws --profile ${PROFILE} \ iam add-role-to-instance-profile \ --instance-profile-name "ManageSecurityHubInstanceRole" \ --role-name "ManageSecurityHubInstanceRole" ; #IAMロールのARN取得 ARN_ManageSecurityHubInstanceRole=$( aws --profile ${PROFILE} --output text \ iam get-role --role-name "ManageSecurityHubInstanceRole" \ --query 'Role.Arn' ) echo ${ARN_ManageSecurityHubInstanceRole}
各アカウントに、Security Hub管理用のIAMロールを作成します。
このIAMロールは、先に作成した「監査アカウントのインスタンスIAMロール」と信頼関係を結びます。
#一連の設定をSecurity Hubを利用する全AWSアカウントに設定します。 PROFILE=<対象のAWSアカウントのIAM管理者のプロファイル> ASSUMEROLE_POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": [ "'"${ARN_ManageSecurityHubInstanceRole}"'" ] }, "Action": "sts:AssumeRole" } ] }' ROLE_POLICY='{ "Version": "2012-10-17", "Statement": [ { "Condition": { "StringLike": { "iam:AWSServiceName": [ "securityhub.amazonaws.com", "config.amazonaws.com" ] } }, "Action": "iam:CreateServiceLinkedRole", "Resource": "*", "Effect": "Allow" }, { "Action": "securityhub:*", "Resource": "*", "Effect": "Allow" }, { "Action": [ "config:DescribeConfigurationRecorders", "config:DescribeDeliveryChannels", "config:DescribeConfigurationRecorderStatus", "config:DeleteConfigurationRecorder", "config:DeleteDeliveryChannel", "config:PutConfigurationRecorder", "config:PutDeliveryChannel", "config:StartConfigurationRecorder" ], "Resource": "*", "Effect": "Allow" }, { "Action": "iam:PassRole", "Resource": "arn:aws:iam::*:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", "Effect": "Allow" }, { "Action": [ "s3:CreateBucket", "s3:PutBucketPolicy", "s3:ListBucket" ], "Resource": "arn:aws:s3:::config-bucket-*", "Effect": "Allow" } ] }' #IAMロールの作成 aws --profile ${PROFILE} \ iam create-role \ --role-name "ManageSecurityHubRole" \ --assume-role-policy-document "${ASSUMEROLE_POLICY}" \ --max-session-duration 3600 #インラインポリシーのアタッチ aws --profile ${PROFILE} \ iam put-role-policy \ --role-name "ManageSecurityHubRole" \ --policy-name "ManageSecurityHubPolicy" \ --policy-document "${ROLE_POLICY}"
auditアカウントに、スクリプト実行用のEC2環境を準備します。
PROFILE=<auditアカウントのEC2管理可能なプロファイル>
#起動パラメータ設定(環境に合わせて変更するもの) KEYNAME="CHANGE_KEY_PAIR_NAME" #環境に合わせてキーペア名を設定してください。 SUBNETID=subnet-f59858bd #"パブリックサブネットのIDを設定" SG_ID=sg-071417e793b795090 #"SSHログインできるセキュリティーグループのIDを設定" #起動パラメータ設定(固定設定) INSTANCE_TYPE="t2.micro" AL2_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; #タグ設定 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "SecurityHubMgr" } ] } ]' #ユーザデータ設定 USER_DATA=' #!/bin/bash -xe #RPM最新化&ホスト名設定 yum -y update hostnamectl set-hostname SecurityHubMgr #パッケージインストール yum -y install python2-pip python2 git #boto3インストール sudo pip install boto3 #AWS CLIアップデート curl -o "get-pip.py" "https://bootstrap.pypa.io/get-pip.py" python get-pip.py pip install --upgrade # ec2-userのAWS CLI初期設定 Region=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//') sudo -u ec2-user aws configure set region ${Region} sudo -u ec2-user aws configure set output json #スクリプトのセットアップ cd /home/ec2-user sudo -u ec2-user git clone https://github.com/awslabs/aws-securityhub-multiaccount-scripts.git ' #インスタンスの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${AL2_AMIID} \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEYNAME} \ --subnet-id ${SUBNETID} \ --security-group-ids ${SG_ID} \ --associate-public-ip-address \ --iam-instance-profile "Name=ManageSecurityHubInstanceRole" \ --tag-specifications "${TAGJSON}" \ --user-data "${USER_DATA}" \ --monitoring Enabled=true ;
MgrIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=SecurityHubMgr" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].PublicIpAddress' ) ssh ec2-user@${MgrIP}
Security Hubの有効化し、SecurityHubのMasterAccount(ここではauditアカウント)の配下のメンバーとなるAWSアカウントの一覧をCSV形式で作成します。1行1アカウントで、"AccountId,EmailAddress"形式で作成します。
CSVファイルの作成例(securityhub_account_list.csv)
111111111111,master@mail_address 222222222222,logging@mail_address 333333333333,resource1@mail_address 444444444444,resource2@mail_address
スクリプトのデフォルトではSecurityHubが利用可能な全てのリージョンで有効化をしようとします。しかし、最近開設されたリージョンは、デフォルトではリージョン自身が無効化されており、そのまま実行するとスクリプトがエラーとなります。そのため、SecurityHubを有効化するリージョンを明示的に指定する必要があります。
CLIではコマンドがないので、boto3を利用しpythonのワンライナーでSecurityHubが利用可能なリージョン一覧を取得します。
python -c "import boto3,json; print('{}'.format( json.dumps( boto3.session.Session().get_available_regions('securityhub') ) ) );"
上記で取得した一覧情報から、有効化対象のリージョンを抽出し、カンマ区切りの文字列にします。
ENABLE_REGIONS="ap-northeast-1,ap-northeast-2,ap-south-1,ap-southeast-1,ap-southeast-2,ca-central-1,eu-central-1,eu-north-1,eu-west-1,eu-west-2,eu-west-3,sa-east-1,us-east-1,us-east-2,us-west-1,us-west-2"
enablesecurityhub.pyスクリプトを利用し、対象アカウントの対象リージョンのSecurity Hub有効化を行います。
# Security Hubのマスターアカウントとして監査アカウントを指定 MASTER_ACCOUNT=$(aws sts get-caller-identity --output text --query 'Account') #その他設定 ASSUME_ROLE="ManageSecurityHubRole" CSV_FILE_NAME="securityhub_account_list.csv" #実行 python2 ./aws-securityhub-multiaccount-scripts/enablesecurityhub.py \ --master_account ${MASTER_ACCOUNT} \ --assume_role ${ASSUME_ROLE} \ --enabled_regions ${ENABLE_REGIONS} \ ${CSV_FILE_NAME} ;
下記のようにスクリプトでのAWS Config有効化に失敗したAWSアカウント/リージョンがある場合、マネージメントコンソールのAWS Configで手動でConfigの有効化をしてから、enablesecurityhub.pyを再実行してください。
SecurityHubの無効化です。
MASTER_ACCOUNT=$(aws sts get-caller-identity --output text --query 'Account') ENABLE_REGIONS="ap-northeast-1,ap-northeast-2,ap-south-1,ap-southeast-1,ap-southeast-2,ca-central-1,eu-central-1,eu-north-1,eu-west-1,eu-west-2,eu-west-3,sa-east-1,us-east-1,us-east-2,us-west-1,us-west-2" #無効化実行 python2 ./aws-securityhub-multiaccount-scripts/disablesecurityhub.py \ --master_account ${MASTER_ACCOUNT} \ --assume_role ${ASSUME_ROLE} \ --enabled_regions ${ENABLE_REGIONS} \ ${CSV_FILE_NAME} ;
Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.0.0-rc.1/PowerShell-7.0.0-rc.1-win-x64.msix -OutFile PowerShell-7.0.0-rc.1-win-x64.msix -UseBasicParsing
デフォルトのMicrosoft Store アプリ
では、PowerShell v7.0.0のインストールでエラーになるため、Windowsを開発者モード
に変更します。
管理者権限で、PowerShellを起動します。起動すると別ウィンドウでPowerShellが起動します。
Start-Process powershell.exe -Verb runas
管理者権限のPowershellで、レジストリ操作を行い、管理者モードに変更します。変更後はexit
で管理者権限のPowerShellを終了します。
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1" exit
Add-AppxPackage PowerShell-7.0.0-rc.1-win-x64.msix
タイトルの通り、Amazon Linux2、RHEL8、Windows Server2019の最新AMIのAMI IDを取得するAWS-CLIのコマンドです。(元ネタは、EC2のユーザーガイド)
AWS CLIの"ec2 describe-images"でAMI IDを確認しますが、その時に下記オプションを指定することで最新AMIのID取得を実現しています。
AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ); echo ${AMIID}
AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --filters 'Name=name,Values=RHEL-8.?.?_HVM-????????-x86_64-*-GP2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ); echo ${AMIID}
AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --filters 'Name=name,Values=RHEL-7.?_HVM-????????-x86_64-*-GP2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ); echo ${AMIID}
AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=Windows_Server-2019-Japanese-Full-Base-????.??.??' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; echo ${AMIID}
AWS Storage GatewayのファイルゲートウェイをVPCエンドポイントを利用したVPC閉塞環境を、CLIで構築する手順です。この手順ではNFS接続、SMB(ゲスト接続)、SMB(ActiveDirectory認証)の構成を作成します。またキャッシュリフレッシュ、ソフトウェアップデート、およびリフレッシュ完了やS3アップロード完了のCloud Watch Event連携のセットアップ手順も整理しています。
作業環境として、下記を準備します。
これ以降のAWS-CLIで共通で利用するパラメータを環境変数で設定しておきます。
export PROFILE=<設定したプロファイル名称を指定。デフォルトの場合はdefaultを設定> export REGION=ap-northeast-1
IGWでインターネットアクセス可能で、パブリックアクセス可能なサブネットx2、プライベートなサブネットx2の合計4つのサブネットを所有するVPCを作成します。
私が作成し利用しているVPC作成用のCloudFormationテンプレートを利用します。まず、githubからテンプレートをダウンロードします。
curl -o vpc-4subnets.yaml https://raw.githubusercontent.com/Noppy/CfnCreatingVPC/master/vpc-4subnets.yaml
ダウンロードしたテンプレートを利用し、VPCをデプロイします。
CFN_STACK_PARAMETERS=' [ { "ParameterKey": "DnsHostnames", "ParameterValue": "true" }, { "ParameterKey": "DnsSupport", "ParameterValue": "true" }, { "ParameterKey": "InternetAccess", "ParameterValue": "true" }, { "ParameterKey": "EnableNatGW", "ParameterValue": "false" }, { "ParameterKey": "VpcName", "ParameterValue": "StorageGWPoCVPC" }, { "ParameterKey": "VpcInternalDnsName", "ParameterValue": "sgwpoc.local." } ]' #CloudFormation スタック作成 aws --profile ${PROFILE} cloudformation create-stack \ --stack-name SGWPoC-VPC \ --template-body "file://./vpc-4subnets.yaml" \ --parameters "${CFN_STACK_PARAMETERS}" \ --capabilities CAPABILITY_IAM ;
必要となるVPC Endpointを作成します。この手順ではエンドポイントポリシーは設定してません。必有れば追加設定してください。
#構成情報取得 VPCID=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`VpcId`].[OutputValue]') VPC_CIDR=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`VpcCidr`].[OutputValue]') PublicSubnet1Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet1Id`].[OutputValue]') PublicSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet2Id`].[OutputValue]') PrivateSubnet1Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet1Id`].[OutputValue]') PrivateSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet2Id`].[OutputValue]') PrivateSubnet1RouteTableId=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet1RouteTableId`].[OutputValue]') PrivateSubnet2RouteTableId=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet2RouteTableId`].[OutputValue]') echo -e "VPCID=$VPCID\nVPC_CIDR=$VPC_CIDR\nPublicSubnet1Id =$PublicSubnet1Id\nPublicSubnet2Id =$PublicSubnet2Id\nPrivateSubnet1Id=$PrivateSubnet1Id\nPrivateSubnet2Id=$PrivateSubnet2Id\nPrivateSubnet1RouteTableId=$PrivateSubnet1RouteTableId \nPrivateSubnet2RouteTableId=$PrivateSubnet2RouteTableId"
#VPC Endpoint用SecurityGroup作成 VPCENDPOINT_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name VpcEndpointSG \ --description "Allow https" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${VPCENDPOINT_SG_ID} \ --tags "Key=Name,Value=VpcEndpointSG" ; aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${VPCENDPOINT_SG_ID} \ --protocol tcp \ --port 443 \ --cidr ${VPC_CIDR} ; #Storage Gateway専用のSecurityGroup作成 VPCENDPOINT_STORAGEGW_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name SGW-VpcEndpointSG \ --description "Allow https" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${VPCENDPOINT_STORAGEGW_SG_ID} \ --tags "Key=Name,Value=SGW-VpcEndpointSG" ; # AWS API通信 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${VPCENDPOINT_STORAGEGW_SG_ID} \ --protocol tcp \ --port 443 \ --cidr ${VPC_CIDR} ; #client-cp接続:Port 1026, proxy-app接続:Port1028 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${VPCENDPOINT_STORAGEGW_SG_ID} \ --protocol tcp \ --port 1026-1028 \ --cidr ${VPC_CIDR} ; #dp-1接続:Port1031 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${VPCENDPOINT_STORAGEGW_SG_ID} \ --protocol tcp \ --port 1031 \ --cidr ${VPC_CIDR} ; # Support-channel用(GWからEndpintの2222にsshする) aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${VPCENDPOINT_STORAGEGW_SG_ID} \ --protocol tcp \ --port 2222 \ --cidr ${VPC_CIDR} ; #S3用VPCEndpoint作成 aws --profile ${PROFILE} \ ec2 create-vpc-endpoint \ --vpc-id ${VPCID} \ --service-name com.amazonaws.${REGION}.s3 \ --route-table-ids ${PrivateSubnet1RouteTableId} ${PrivateSubnet2RouteTableId} #StorageGateway用VPCEndpoint作成 aws --profile ${PROFILE} \ ec2 create-vpc-endpoint \ --vpc-id ${VPCID} \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.${REGION}.storagegateway \ --subnet-id ${PrivateSubnet1Id} ${PrivateSubnet2Id} \ --security-group-id ${VPCENDPOINT_STORAGEGW_SG_ID} ; #SSM用PCEndpoint作成 aws --profile ${PROFILE} \ ec2 create-vpc-endpoint \ --vpc-id ${VPCID} \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.${REGION}.ssm \ --subnet-id ${PrivateSubnet1Id} ${PrivateSubnet2Id} \ --security-group-id ${VPCENDPOINT_SG_ID} ; aws --profile ${PROFILE} \ ec2 create-vpc-endpoint \ --vpc-id ${VPCID} \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.${REGION}.ec2messages \ --subnet-id ${PrivateSubnet1Id} ${PrivateSubnet2Id} \ --security-group-id ${VPCENDPOINT_SG_ID} ; aws --profile ${PROFILE} \ ec2 create-vpc-endpoint \ --vpc-id ${VPCID} \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.${REGION}.ssmmessages \ --subnet-id ${PrivateSubnet1Id} ${PrivateSubnet2Id} \ --security-group-id ${VPCENDPOINT_SG_ID} ;
POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }' #IAMロールの作成 aws --profile ${PROFILE} \ iam create-role \ --role-name "Ec2-StorageGW-AdminRole" \ --assume-role-policy-document "${POLICY}" \ --max-session-duration 43200 #AWS管理ポリシーのアタッチ # AWSStorageGatewayFullAccessのアタッチ aws --profile ${PROFILE} \ iam attach-role-policy \ --role-name "Ec2-StorageGW-AdminRole" \ --policy-arn arn:aws:iam::aws:policy/AWSStorageGatewayFullAccess # CloudWatch管理者権限のアタッチ aws --profile ${PROFILE} \ iam attach-role-policy \ --role-name "Ec2-StorageGW-AdminRole" \ --policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess # ReadOnlyAccessのアタッチ aws --profile ${PROFILE} \ iam attach-role-policy \ --role-name "Ec2-StorageGW-AdminRole" \ --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess #インスタンスプロファイルの作成 aws --profile ${PROFILE} \ iam create-instance-profile \ --instance-profile-name "Ec2-StorageGW-AdminRole-Profile"; aws --profile ${PROFILE} \ iam add-role-to-instance-profile \ --instance-profile-name "Ec2-StorageGW-AdminRole-Profile" \ --role-name "Ec2-StorageGW-AdminRole" ;
# SSHログイン用セキュリティーグループ作成 SSH_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name SshSG \ --description "Allow ssh" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${SSH_SG_ID} \ --tags "Key=Name,Value=SshSG" ; # セキュリティーグループにSSHのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SSH_SG_ID} \ --protocol tcp \ --port 22 \ --cidr 0.0.0.0/0 ;
# RDPログイン用セキュリティーグループ作成 RDP_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name RdpSG \ --description "Allow rdp" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${RDP_SG_ID} \ --tags "Key=Name,Value=RdpSG" ; # セキュリティーグループにRDPのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${RDP_SG_ID} \ --protocol tcp \ --port 3389 \ --cidr 0.0.0.0/0 ;
# クライアント識別用セキュリティーグループ作成 CLIENT_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name ClientSG \ --description "Allow rdp" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${CLIENT_SG_ID} \ --tags "Key=Name,Value=ClientSG" ;
# SSHログイン用セキュリティーグループ作成 MGR_SSH_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name Mgr-SshSG \ --description "Allow ssh" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${MGR_SSH_SG_ID} \ --tags "Key=Name,Value=Mgr-SshSG" ; # セキュリティーグループにSSHのinboundアクセス許可を追加 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${MGR_SSH_SG_ID} \ --protocol tcp \ --port 22 \ --cidr 0.0.0.0/0 ;
SSH_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=SshSG' \ --query 'SecurityGroups[].GroupId'); RDP_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=RdpSG' \ --query 'SecurityGroups[].GroupId'); CLIENT_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=ClientSG' \ --query 'SecurityGroups[].GroupId'); MGR_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=Mgr-SshSG' \ --query 'SecurityGroups[].GroupId'); #設定情報の表示 echo -e "SSH_SG_ID =${SSH_SG_ID}\nRDP_SG_ID =${RDP_SG_ID}\nCLIENT_SG_ID=${CLIENT_SG_ID}\nMGR_SG_ID =${MGR_SG_ID}"
KEYNAME="CHANGE_KEY_PAIR_NAME" #環境に合わせてキーペア名を設定してください。 #最新のAmazon Linux2のAMI IDを取得します。 AL2_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; WIN2019_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=Windows_Server-2019-Japanese-Full-Base-????.??.??' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; echo -e "KEYNAME=${KEYNAME}\nAL2_AMIID=${AL2_AMIID}\nWIN2019_AMIID=${WIN2019_AMIID}"
#インスタンスタイプ設定 INSTANCE_TYPE="t2.micro" #INSTANCE_TYPE="m5d.8xlarge" #タグ設定 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Linux-Client" } ] } ]' #ユーザデータ設定 USER_DATA=' #!/bin/bash -xe yum -y update yum -y install bind bind-utils hostnamectl set-hostname Linux-Client ' # サーバの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${AL2_AMIID} \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEYNAME} \ --subnet-id ${PublicSubnet1Id} \ --security-group-ids ${SSH_SG_ID} ${CLIENT_SG_ID}\ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" \ --user-data "${USER_DATA}" ;
#インスタンスタイプ設定 INSTANCE_TYPE="t2.micro" #INSTANCE_TYPE="m5d.8xlarge" #タグ設定 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Windows-Client" } ] } ]' # サーバの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${WIN2019_AMIID} \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEYNAME} \ --subnet-id ${PublicSubnet1Id} \ --security-group-ids ${RDP_SG_ID} ${CLIENT_SG_ID}\ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" ;
ファイルゲートウェイのアクティベーション作業を行う管理インスタンスを起動します。
#インスタンスタイプ設定 INSTANCE_TYPE="t2.micro" #タグ設定 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Manager-Linux" } ] } ]' #ユーザデータ設定 USER_DATA=' #!/bin/bash -xe yum -y update yum -y install bind bind-utils hostnamectl set-hostname Mgr-linux ' # サーバの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${AL2_AMIID} \ --instance-type t2.micro \ --key-name ${KEYNAME} \ --subnet-id ${PublicSubnet2Id} \ --security-group-ids ${MGR_SSH_SG_ID}\ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" \ --user-data "${USER_DATA}" \ --iam-instance-profile "Name=Ec2-StorageGW-AdminRole-Profile";
Storage Gatewayで利用するS3のバケットと、S3アクセス用にStorage Gatewayが利用するIAMロールを作成します。
# セキュリティーグループID取得 #Security Group ID取得 CLIENT_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=ClientSG' \ --query 'SecurityGroups[].GroupId'); MGR_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=Mgr-SshSG' \ --query 'SecurityGroups[].GroupId'); echo -e "CLIENT_SG_ID=${CLIENT_SG_ID}\nMGR_SG_ID =${MGR_SG_ID}" # SGW用セキュリティーグループ作成 SGW_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 create-security-group \ --group-name SGWSG \ --description "Allow gateway" \ --vpc-id ${VPCID}) ; aws --profile ${PROFILE} \ ec2 create-tags \ --resources ${SGW_SG_ID} \ --tags "Key=Name,Value=StorageGWSG" ; # セキュリティーグループにStorage Gatewayに必要となるinboundアクセス許可を追加 # gatewayへのアクティベーションコード取得のため aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 80 \ --source-group ${MGR_SG_ID} ; # gatewayへのコンソールログインのため aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 22 \ --source-group ${MGR_SG_ID} ; # クライアントとのSMB接続(1) aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 139 \ --source-group ${CLIENT_SG_ID} ; # クライアントとのSMB接続(2) aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 445 \ --source-group ${CLIENT_SG_ID} ; # クライアントとのNFS接続(1) NFS aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 2049 \ --source-group ${CLIENT_SG_ID} ; # クライアントとのNFS接続(2) rpcbind/sunrpc for NFSv3 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 111 \ --source-group ${CLIENT_SG_ID} ; # クライアントとのNFS接続(3) gensha for NFSv3 aws --profile ${PROFILE} \ ec2 authorize-security-group-ingress \ --group-id ${SGW_SG_ID} \ --protocol tcp \ --port 20048 \ --source-group ${CLIENT_SG_ID} ;
S3暗号化用のKMSのCMK(Customer Master Key)を作成します。キーポリシーはIAMロール作成後に設定します。
KEY_ID=$( \ aws --profile ${PROFILE} --output text \ kms create-key \ --description "CMK for S3 buckets" \ --origin AWS_KMS \ --query 'KeyMetadata.KeyId' ) aws --profile ${PROFILE} \ kms create-alias \ --alias-name alias/Key_For_S3Buckets \ --target-key-id ${KEY_ID}
BUCKET_NAME="storagegw-bucket-$( od -vAn -to1 </dev/urandom | tr -d " " | fold -w 10 | head -n 1)" REGION=$(aws --profile ${PROFILE} configure get region) aws --profile ${PROFILE} \ s3api create-bucket \ --bucket ${BUCKET_NAME} \ --create-bucket-configuration LocationConstraint=${REGION};
特定のCMKでの暗号化を強制するバケットポリシーを設定します。
#情報の収集 #BUCKET_NAME=<バケット名を設定> KEY_ARN=$(aws --profile ${PROFILE} --output text \ kms describe-key \ --key-id alias/Key_For_S3Buckets \ --query 'KeyMetadata.Arn' \ ) #バケットポリシーJSON生成 POLICY='{ "Version": "2012-10-17", "Id": "S3KeyPolicy", "Statement": [ { "Sid": "Force KMS Key", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::'"${BUCKET_NAME}"'/*", "Condition": { "StringNotEquals": { "s3:x-amz-server-side-encryption-aws-kms-key-id": "'"${KEY_ARN}"'" } } } ] }' #バケットポリシー設定 aws --profile ${PROFILE} s3api \ put-bucket-policy \ --bucket ${BUCKET_NAME} \ --policy "${POLICY}"
POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "storagegateway.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }' #IAMロールの作成 aws --profile ${PROFILE} \ iam create-role \ --role-name "StorageGateway-S3AccessRole" \ --assume-role-policy-document "${POLICY}" \ --max-session-duration 43200 #S3バケットアクセス用 In-line Policyの追加 POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "OperatBucket", "Effect": "Allow", "Action": [ "s3:GetAccelerateConfiguration", "s3:GetBucketLocation", "s3:GetBucketVersioning", "s3:ListBucket", "s3:ListBucketVersions", "s3:ListBucketMultipartUploads" ], "Resource": [ "arn:aws:s3:::'"${BUCKET_NAME}"'" ] }, { "Sid": "PuAndGetObject", "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:DeleteObject", "s3:DeleteObjectVersion", "s3:GetObject", "s3:GetObjectAcl", "s3:GetObjectVersion", "s3:ListMultipartUploadParts", "s3:PutObject", "s3:PutObjectAcl" ], "Resource": [ "arn:aws:s3:::'"${BUCKET_NAME}"'/*" ] } ] }' #インラインポリシーの設定 aws --profile ${PROFILE} \ iam put-role-policy \ --role-name "StorageGateway-S3AccessRole" \ --policy-name "AccessS3buckets" \ --policy-document "${POLICY}"; #CloudWatch Logs用 In-line Policyの追加 POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowLogs", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "*" ] } ] }' #インラインポリシーの設定 aws --profile ${PROFILE} \ iam put-role-policy \ --role-name "StorageGateway-S3AccessRole" \ --policy-name "PutCLoudWatchLogs" \ --policy-document "${POLICY}";
この後のStorage Gatewayのファイル共有作成時(CreateSmbFileShare)に、ファイル共有からS3にPUT/GETするためのIAMロールを指定し割り当ています。この作業時に管理者のIAM権限としてeにPassRoleのアクションを許可する必要があります。
S3AccessRole_ARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "StorageGateway-S3AccessRole" \ --query 'Role.Arn') ; POLICY='{ "Version": "2012-10-17", "Statement": [ { "Sid": "PassRole", "Effect": "Allow", "Action": [ "iam:PassRole" ], "Resource": [ "'"${S3AccessRole_ARN}"'" ] } ] }' #インラインポリシーの設定 aws --profile ${PROFILE} \ iam put-role-policy \ --role-name "Ec2-StorageGW-AdminRole" \ --policy-name "PassRole" \ --policy-document "${POLICY}";
#情報取得 ADMIN_ARN=$(aws --profile ${PROFILE} --output text \ sts get-caller-identity --query 'Arn') ACCOUNT_ID=$(aws --profile ${PROFILE} --output text \ sts get-caller-identity --query 'Account') S3AccessRole_ARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "StorageGateway-S3AccessRole" \ --query 'Role.Arn') ; STORAGEGW_ADMIN_ROLE_ARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "Ec2-StorageGW-AdminRole" \ --query 'Role.Arn') ; KEY_ARN=$( aws --profile ${PROFILE} --output text \ kms describe-key \ --key-id "alias/Key_For_S3Buckets" \ --query 'KeyMetadata.Arn') #キーポリシー用JSON作成 POLICY='{ "Version": "2012-10-17", "Id": "key-default-1", "Statement": [ { "Sid": "Administrator", "Effect": "Allow", "Principal": { "AWS": [ "'"${ADMIN_ARN}"'", "'"${STORAGEGW_ADMIN_ROLE_ARN}"'", "arn:aws:iam::'"${ACCOUNT_ID}"':role/OrganizationAccountAccessRole" ] }, "Action": "kms:*", "Resource": "*" }, { "Sid": "User", "Effect": "Allow", "Principal": { "AWS": [ "'"${S3AccessRole_ARN}"'" ] }, "Action": [ "kms:DescribeKey", "kms:Decrypt", "kms:GenerateDataKey" ], "Resource": "*" } ] }' #キーポリシー設定 aws --profile ${PROFILE} \ kms put-key-policy \ --key-id "${KEY_ARN}" \ --policy-name "default" \ --policy "${POLICY}" \ --no-bypass-policy-lockout-safety-check ;
ファイルゲートウェイに設定されているNTPサーバ(同期先)は、インターネット上のNTPサーバ(x.amazon.pool.ntp.org )です。そのためファイルゲートウェイをインターネット接続ができない環境に設置した場合、時刻同期処理を行うことができません。この手順は、Route53のPrivate Hosted Zoneを活用し、x.amazon.pool.ntp.orgのアクセス先をAWS time sync(169.254.169.123)にアクセスするようにしてます。
#設定 REGION=$(aws --profile ${PROFILE} configure get region) #Private Hosted zoneの作成 aws --profile ${PROFILE} \ route53 create-hosted-zone \ --name "amazon.pool.ntp.org" \ --caller-reference $(date '+%Y-%m-%d-%H:%M') \ --vpc VPCRegion=${REGION},VPCId=${VPCID} ; HOSTED_ZONE_ID=$(aws --profile ${PROFILE} --output text \ route53 list-hosted-zones-by-name \ --dns-name "amazon.pool.ntp.org" \ --query 'HostedZones[].Id' | sed -e 's/\/hostedzone\///') ; #レコード登録 CHANGE_BATCH_JSON='{ "Comment": "CREATE NTP records ", "Changes": [ { "Action": "CREATE", "ResourceRecordSet": { "Name": "0.amazon.pool.ntp.org", "Type": "A", "TTL": 300, "ResourceRecords": [ { "Value": "169.254.169.123" } ] } }, { "Action": "CREATE", "ResourceRecordSet": { "Name": "1.amazon.pool.ntp.org", "Type": "A", "TTL": 300, "ResourceRecords": [ { "Value": "169.254.169.123" } ] } }, { "Action": "CREATE", "ResourceRecordSet": { "Name": "2.amazon.pool.ntp.org", "Type": "A", "TTL": 300, "ResourceRecords": [ { "Value": "169.254.169.123" } ] } }, { "Action": "CREATE", "ResourceRecordSet": { "Name": "3.amazon.pool.ntp.org", "Type": "A", "TTL": 300, "ResourceRecords": [ { "Value": "169.254.169.123" } ] } } ] }' #x.amazon.poo..ntp.orgのAレコード登録 aws --profile ${PROFILE} \ route53 change-resource-record-sets \ --hosted-zone-id ${HOSTED_ZONE_ID} \ --change-batch "${CHANGE_BATCH_JSON}";
ゲートウェイを作成、アクティベーションして利用可能な状態にします。
# FileGatewayの最新のAMIIDを取得する FGW_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=aws-storage-gateway-??????????' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ); #Security Group ID取得 SGW_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=SGWSG' \ --query 'SecurityGroups[].GroupId'); #ファイルゲートウェイインスタンスの起動 INSTANCE_TYPE=c5.4xlarge TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Fgw" } ] } ]' BLOCK_DEVICE_MAPPINGS='[ { "DeviceName": "/dev/xvda", "Ebs": { "DeleteOnTermination": true, "VolumeType": "io1", "Iops": 4000, "VolumeSize": 350, "Encrypted": false } }, { "DeviceName": "/dev/sdm", "Ebs": { "DeleteOnTermination": true, "VolumeType": "io1", "Iops": 3000, "VolumeSize": 16384, "Encrypted": false } } ]' aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${FGW_AMIID} \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEYNAME} \ --subnet-id ${PrivateSubnet1Id} \ --security-group-ids ${SGW_SG_ID} \ --block-device-mappings "${BLOCK_DEVICE_MAPPINGS}" \ --tag-specifications "${TAGJSON}" \ --monitoring Enabled=true ;
#情報取得 export REGION=ap-northeast-1 GatewayInstanceID=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=Fgw" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].InstanceId' ) #AutoRecovery設定 aws --profile ${PROFILE} \ cloudwatch put-metric-alarm \ --region "${REGION}" \ --alarm-name "recover-ec2-instance-${GatewayInstanceID}" \ --alarm-description "recover-FileGateway-ec2-instance" \ --alarm-actions \ "arn:aws:automate:${REGION}:ec2:recover" \ --namespace AWS/EC2 \ --metric-name StatusCheckFailed_System \ --dimensions Name=InstanceId,Value=${GatewayInstanceID} \ --comparison-operator GreaterThanThreshold \ --unit Count \ --statistic Average \ --period 60 \ --threshold 1 \ --evaluation-periods 1
以後の作業で、Mgr-Linuxを利用するため、sshログインとセットアップを行います。
MgrIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=Manager-Linux" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].PublicIpAddress' ) ssh-add ssh -A ec2-user@${MgrIP}
以下はSSHログインした、Mgr-Linux上での作業となります。
# ec2-userログインしてからの作業となります。 #AWS Cliアップデート curl -o "get-pip.py" "https://bootstrap.pypa.io/get-pip.py" sudo python get-pip.py pip install --upgrade --user awscli echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc . ~/.bashrc # AWS cli初期設定 Region=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//') aws configure set region ${Region} aws configure set output json #動作確認 aws sts get-caller-identity #利用するプロファイル設定 export PROFILE=default
export PROFILE=default #構成情報取得 VPCID=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`VpcId`].[OutputValue]') VPC_CIDR=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`VpcCidr`].[OutputValue]') PublicSubnet1Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet1Id`].[OutputValue]') PublicSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet2Id`].[OutputValue]') PrivateSubnet1Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet1Id`].[OutputValue]') PrivateSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet2Id`].[OutputValue]') PrivateSubnet1RouteTableId=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet1RouteTableId`].[OutputValue]') PrivateSubnet2RouteTableId=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet2RouteTableId`].[OutputValue]') echo -e "VPCID=$VPCID\nVPC_CIDR=$VPC_CIDR\nPublicSubnet1Id =$PublicSubnet1Id\nPublicSubnet2Id =$PublicSubnet2Id\nPrivateSubnet1Id=$PrivateSubnet1Id\nPrivateSubnet2Id=$PrivateSubnet2Id\nPrivateSubnet1RouteTableId=$PrivateSubnet1RouteTableId \nPrivateSubnet2RouteTableId=$PrivateSubnet2RouteTableId"
ファイルゲートウェイから、 アクティベーションキーを取得します。
#構成情報取得 GatewayIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=Fgw" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].PrivateIpAddress' ) REGION=$(aws --profile ${PROFILE} configure get region) VPCEndpointDNSname=$(aws --profile ${PROFILE} --output text \ ec2 describe-vpc-endpoints \ --filters \ "Name=service-name,Values=com.amazonaws.ap-northeast-1.storagegateway" \ "Name=vpc-id,Values=${VPCID}" \ --query 'VpcEndpoints[*].DnsEntries[0].DnsName' ); echo ${GatewayIP} ${REGION} ${VPCEndpointDNSname} #アクティベーション先のURL生成 ACTIVATION_URL="http://${GatewayIP}/?gatewayType=FILE_S3&activationRegion=${REGION}&vpcEndpoint=${VPCEndpointDNSname}&no_redirect" echo ${ACTIVATION_URL}
ACTIVATION_KEY=$(curl "${ACTIVATION_URL}") echo ${ACTIVATION_KEY}
REGION=$(aws --profile ${PROFILE} configure get region) aws --profile ${PROFILE} \ storagegateway activate-gateway \ --activation-key ${ACTIVATION_KEY} \ --gateway-name SgPoC-Gateway-1 \ --gateway-timezone "GMT+9:00" \ --gateway-region ${REGION} \ --gateway-type FILE_S3 #作成したGatewayのARN取得 # atewayState"が "RUNNING"になるまで待つ #ARNがわからない場合は、下記コマンドで確認 #aws --profile ${PROFILE} storagegateway list-gateways aws --profile ${PROFILE} storagegateway describe-gateway-information --gateway-arn <GATEWAYのARN>
<参考 gateway-typeの説明>
#ローカルストレージの確認 GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') DiskIds=$(aws --profile ${PROFILE} --output text storagegateway list-local-disks --gateway-arn ${GATEWAY_ARN} --query 'Disks[*].DiskId'| sed -e 's/\n/ /') echo ${DiskIds} #ローカルストレージの割り当て aws --profile ${PROFILE} storagegateway \ add-cache \ --gateway-arn ${GATEWAY_ARN} \ --disk-ids ${DiskIds} #ローカルストレージの確認 # "DiskAllocationType"が"CACHE STORAGE"で、"DiskStatus"が"present"であることを確認 aws --profile ${PROFILE} --output text \ storagegateway list-local-disks \ --gateway-arn ${GATEWAY_ARN}
参照:https://docs.aws.amazon.com/ja_jp/storagegateway/latest/userguide/create-gateway-file.html
ファイルゲートウェイインスタンスから、Logsへのログ出力設定を行います。LogsにはS3へのDenyAccess情報などが記録されます。
#情報取得 GATEWAY_ARN=$(aws --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ match($0, /arn:aws:storagegateway:\S*/); print substr($0, RSTART, RLENGTH) }') #Region=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//') #AccuntId=$(curl -s http://169.254.169.254/latest/meta-data/identity-credentials/ec2/info|awk '/AccountId/{ i=gsub( /"/, "", $3); print $3}') echo "GATEWAY_ARN=$GATEWAY_ARN Region=${Region} AccuntId=${AccuntId}" #CloudWatch Logsログストリーム作成 LOG_GROUP_NAME=${SgPoC-Gateway-1} aws --profile ${PROFILE} \ logs create-log-group \ --log-group-name ${LOG_GROUP_NAME}; LOG_GROUP_ARN=$(aws --profile ${PROFILE} --output text \ logs describe-log-groups \ --log-group-name-prefix ${LOG_GROUP_NAME} \ --query 'logGroups[].arn' ); #ファイルゲートウェイへの出力先ロググループ設定 aws --profile ${PROFILE} \ storagegateway update-gateway-information \ --gateway-arn ${GATEWAY_ARN} \ --cloud-watch-log-group-arn ${LOG_GROUP_ARN}
NFSのファイル共有を作成し、LinuxクライアントからNFS接続します。
Linux Managerで下記設定を実行します。 上記(6)で作成したS3バケット以外のバケットを利用する場合は、(6)-(c)で作成した、"StorageGateway-S3AccessRole"ロールのリソース句に該当のS3バケットを追加してください。
#情報取得 BUCKET_NAME=<バケット名を個別に設定> BUCKETARN="arn:aws:s3:::${BUCKET_NAME}" ROLE="StorageGateway-S3AccessRole" ROLEARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "StorageGateway-S3AccessRole" \ --query 'Role.Arn') GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') CLIENT_TOKEN=$(cat /dev/urandom | base64 | fold -w 38 | sed -e 's/[\/\+\=]/0/g' | head -n 1) KEY_ARN=$( aws --profile ${PROFILE} --output text \ kms describe-key \ --key-id "alias/Key_For_S3Buckets" \ --query 'KeyMetadata.Arn') echo -e "BUCKET=${BUCKETARN}\nROLE_ARN=${ROLEARN}\nGATEWAY_ARN=${GATEWAY_ARN}\nCLIENT_TOKEN=${CLIENT_TOKEN}\nKEY_ARN=${KEY_ARN}"
#NFSデフォルト設定 #設定はこちらを参照: https://docs.aws.amazon.com/storagegateway/latest/APIReference/API_NFSFileShareDefaults.html#StorageGateway-Type-NFSFileShareDefaults-OwnerId FILE_SHARE_DEFAULT_JSON='{ "FileMode": "0666", "DirectoryMode": "0777", "GroupId": 65534, "OwnerId": 65534 }' #NFSファイル共有作成 aws --profile ${PROFILE} storagegateway \ create-nfs-file-share \ --client-token ${CLIENT_TOKEN} \ --gateway-arn "${GATEWAY_ARN}" \ --location-arn "${BUCKETARN}" \ --role "${ROLEARN}" \ --nfs-file-share-defaults "${FILE_SHARE_DEFAULT_JSON}" \ --client-list "0.0.0.0/0" \ --squash "RootSquash" \ --kms-encrypted \ --kms-key ${KEY_ARN} ;
作業端末から、Linuxクライアントに接続し、NFSマウントを実行します。
以後の作業で、Linux-Clientを利用するため、sshログインとセットアップを行います。
LinuxClinetIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=Linux-Client" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].PublicIpAddress' ) ssh-add ssh -A ec2-user@${LinuxClinetIP}
Linux-Clientにユーザ"ec2-user"でログイン完了した後に、下記コマンドでNFSマウントします。
sudo -i #情報の設定と確認 FGWIP=<ファイルGWのPrivateIPを設定> EXPORT_PATH=<ファイル共有のエクスポートパス情報を(/から始まる情報)を設定> echo -e "FGWIP=${FGWIP}\nEXPORT_PATH=${EXPORT_PATH}"
情報確認後、マウント設定を行います。
mkdir /nfs #/etc/fstabへのマウントポイント追加 $ mount実行 echo "${FGWIP}:${EXPORT_PATH} /nfs nfs nolock,hard 0 2" >> /etc/fstab mount -a df
ActiveDirectoryを利用しない、ゲストアクセスタイプのSMBのファイル共有を作成し、WindowsクライアントからSMB(ゲストアクセス)接続します。 Linux Managerで下記設定を実行します。
GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') aws --profile ${PROFILE} storagegateway \ update-smb-security-strategy \ --gateway-arn ${GATEWAY_ARN} \ --smb-security-strategy MandatoryEncryption
PASSWORD="HogeHoge@" aws --profile ${PROFILE} storagegateway \ set-smb-guest-password \ --gateway-arn ${GATEWAY_ARN} \ --password ${PASSWORD}
上記(6)で作成したS3バケット以外のバケットを利用する場合は、(6)-(c)で作成した、"StorageGateway-S3AccessRole"ロールのリソース句に該当のS3バケットを追加してください。
#情報取得 BUCKET_NAME=<バケット名を個別に設定> BUCKETARN="arn:aws:s3:::${BUCKET_NAME}" ROLE="StorageGateway-S3AccessRole" ROLEARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "StorageGateway-S3AccessRole" \ --query 'Role.Arn') GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') CLIENT_TOKEN=$(cat /dev/urandom | base64 | fold -w 38 | sed -e 's/[\/\+\=]/0/g' | head -n 1) KEY_ARN=$( aws --profile ${PROFILE} --output text \ kms describe-key \ --key-id "alias/Key_For_S3Buckets" \ --query 'KeyMetadata.Arn') echo -e "BUCKET=${BUCKETARN}\nROLE_ARN=${ROLEARN}\nGATEWAY_ARN=${GATEWAY_ARN}\nCLIENT_TOKEN=${CLIENT_TOKEN}\nKEY_ARN=${KEY_ARN}" #実行 aws --profile ${PROFILE} storagegateway \ create-smb-file-share \ --client-token ${CLIENT_TOKEN} \ --gateway-arn "${GATEWAY_ARN}" \ --location-arn "${BUCKETARN}" \ --role "${ROLEARN}" \ --object-acl bucket-owner-full-control \ --default-storage-class S3_STANDARD \ --guess-mime-type-enabled \ --authentication GuestAccess \ --kms-encrypted \ --kms-key ${KEY_ARN} ;
Windows ClinetにRDPログインし、SMB接続をします。 説明は省略します。
ファイルゲートウェイとクライアントのWindowsサーバをADに参加させ、AD認証でファイル共有する手順です。この手順ではADに AWS Directory ServiceのAWS Managed Microsoft ADを利用しています。
作業端末で作業を実施ます。
PROFILE=<プロファイルを指定> #構成情報取得 VPCID=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`VpcId`].[OutputValue]') PublicSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PublicSubnet2Id`].[OutputValue]') PrivateSubnet1Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet1Id`].[OutputValue]') PrivateSubnet2Id=$(aws --profile ${PROFILE} --output text \ cloudformation describe-stacks \ --stack-name SGWPoC-VPC \ --query 'Stacks[].Outputs[?OutputKey==`PrivateSubnet2Id`].[OutputValue]') echo -e "VPCID=$VPCID\nPublicSubnet2Id=${PublicSubnet2Id}\nPrivateSubnet1Id=$PrivateSubnet1Id\nPrivateSubnet2Id=$PrivateSubnet2Id\n"
AD_NAME="sgwpoc.local" AD_EDITION="Standard" #Enterprise or Standard KEYNAME="CHANGE_KEY_PAIR_NAME" #環境に合わせてキーペア名を設定してください。 AD_PASSWORD="$( cat /dev/urandom | base64 |tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)${RANDOM}" #パスワードを控える echo ${AD_PASSWORD} #¥表示されたパスワードは後の手順で利用するためメモしておく
MADを作成します。MADのENIに付与されるセキュリティーグループは、ADサービスが自動的に作成します。
# MAD作成 aws --profile ${PROFILE} ds \ create-microsoft-ad \ --name "${AD_NAME}" \ --short-name "SgwPoC" \ --description "AD for StorageGateway PoC" \ --password "${AD_PASSWORD}" \ --edition "${AD_EDITION}" \ --vpc-settings "VpcId=${VPCID},SubnetIds=${PrivateSubnet1Id},${PrivateSubnet2Id}" ;
KEYNAME="CHANGE_KEY_PAIR_NAME" #環境に合わせてキーペア名を設定してください。 INSTANCE_TYPE="t2.micro" #以下は自動取得 WIN2019_AMIID=$(aws --profile ${PROFILE} --output text \ ec2 describe-images \ --owners amazon \ --filters 'Name=name,Values=Windows_Server-2019-Japanese-Full-Base-????.??.??' \ 'Name=state,Values=available' \ --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' ) ; RDP_SG_ID=$(aws --profile ${PROFILE} --output text \ ec2 describe-security-groups \ --filter 'Name=group-name,Values=RdpSG' \ --query 'SecurityGroups[].GroupId'); #設定確認 echo -e "KEYNAME=${KEYNAME}\nINSTANCE_TYPE=${INSTANCE_TYPE}\nWIN2019_AMIID=${WIN2019_AMIID}\nRDP_SG_ID=${RDP_SG_ID}"
#タグ設定 TAGJSON=' [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "Windows-AD-Mgr" } ] } ]' # サーバの起動 aws --profile ${PROFILE} \ ec2 run-instances \ --image-id ${WIN2019_AMIID} \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEYNAME} \ --subnet-id ${PublicSubnet2Id} \ --security-group-ids ${RDP_SG_ID} \ --associate-public-ip-address \ --tag-specifications "${TAGJSON}" ;
Import-Module ServerManager Install-WindowsFeature -Name GPMC,RSAT-AD-PowerShell,RSAT-AD-AdminCenter,RSAT-ADDS-Tools,RSAT-DNS-Server
Get-NetAdapter | Set-DnsClientServerAddress -ServerAddresses <ADの1つ目のIPアドレス>,<ADの2つ目のIPアドレス> #設定の確認 Get-NetAdapter | Get-DnsClientServerAddress
sgwpoc.local
に参加します。#ドメインに参加させます。実行すると adminのパスワードを聞かれるので、AD作成時(create-microsoft-ad)に設定したパスワードを入力します。 Add-Computer -DomainName sgwpoc.local -Credential admin #有効にするためリブートします。 Restart-Computer
Get-ADDomain -Identity sgwpoc.local
Windows-Clientインスタンスについて、(10)-(C)と同じ手順で、ADに参加させます。
ファイルゲートウェイのDNS参照先を、ADに変更します。変更は、ファイルゲートウェイにssh接続して変更します。
#Linux-Mgrにログイン MgrIP=$(aws --profile ${PROFILE} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=Manager-Linux" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].PublicIpAddress' ) ssh-add ssh -A ec2-user@${MgrIP}
#ゲートウェイのIP取得 GatewayIP=$(aws --output text ec2 describe-instances --query 'Reservations[*].Instances[*].PrivateIpAddress' --filters "Name=tag:Name,Values=Fgw" "Name=instance-state-name,Values=running") #sshログイン ssh admin@${GatewayIP}
ファイルゲートウェイの下記メニューが表示されたら、以下の箇条書きの内容を参考にDNS設定を行います。
AWS Storage Gateway - Configuration ####################################################################### ## Currently connected network adapters: ## ## eth0: 10.1.163.138 ####################################################################### 1: HTTP/SOCKS Proxy Configuration 2: Network Configuration 3: Test Network Connectivity 4: View System Resource Check (0 Errors) 5: License Information 6: Command Prompt Press "x" to exit session Enter command:
Network Configuration
を選び、Edit DNS Configuration
を選択Available adapters
でeth0
を入力Assign by DHCP [y/n]:
は、DNSを静的設定するためn
を選択Enter primary DNS
とEnter secondary DNS
に、ADのDNSアドレス
のIPアドレスを指定Apply config [y/n]:
でy
で設定反映する#一般設定 PROFILE="default" #AD設定 AD_DOMAIN_NAME="sgwpoc.local" AD_USER="admin" AD_PASSWORD="< (10)-(a) (ii)で設定したパスワード>" #ゲートウェイID取得 GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') # 実行 aws --profile ${PROFILE} \ storagegateway join-domain \ --gateway-arn ${GATEWAY_ARN} \ --domain-name ${AD_DOMAIN_NAME} \ --user-name ${AD_USER} \ --password ${AD_PASSWORD} ;
上記(6)で作成したS3バケット以外のバケットを利用する場合は、(6)-(c)で作成した、"StorageGateway-S3AccessRole"ロールのリソース句に該当のS3バケットを追加してください。
#情報取得 BUCKET_NAME=storagegw-bucket-smb-ad #<バケット名を個別に設定> BUCKETARN="arn:aws:s3:::${BUCKET_NAME}" ROLE="StorageGateway-S3AccessRole" ROLEARN=$(aws --profile ${PROFILE} --output text \ iam get-role \ --role-name "StorageGateway-S3AccessRole" \ --query 'Role.Arn') GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') CLIENT_TOKEN=$(cat /dev/urandom | base64 | fold -w 38 | sed -e 's/[\/\+\=]/0/g' | head -n 1) KEY_ARN=$( aws --profile ${PROFILE} --output text \ kms describe-key \ --key-id "alias/Key_For_S3Buckets" \ --query 'KeyMetadata.Arn') echo -e "BUCKET=${BUCKETARN}\nROLE_ARN=${ROLEARN}\nGATEWAY_ARN=${GATEWAY_ARN}\nCLIENT_TOKEN=${CLIENT_TOKEN}\nKEY_ARN=${KEY_ARN}" #実行 aws --profile ${PROFILE} storagegateway \ create-smb-file-share \ --client-token ${CLIENT_TOKEN} \ --gateway-arn "${GATEWAY_ARN}" \ --location-arn "${BUCKETARN}" \ --role "${ROLEARN}" \ --object-acl bucket-owner-full-control \ --default-storage-class S3_STANDARD \ --guess-mime-type-enabled \ --authentication ActiveDirectory \ --kms-encrypted \ --kms-key ${KEY_ARN} ;
クライアントから接続確認します。
net use [WindowsDriveLetter]: \\10.1.163.138\storagegw-bucket-smb-ad
FILE_SHARE_ARN="<操作したいファイル共有のARNを指定する>" FOLDER_LIST='/' #リフレッシュの実行(デフォルトの動作) aws --profile ${PROFILE} storagegateway \ refresh-cache \ --file-share-arn ${FILE_SHARE_ARN} \ --folder-list ${FOLDER_LIST} \ --recursive ;
FILE_SHARE_ARN=ファイル共有のARNを設定 FOLDER_LIST='/test2 /test3' #ファイル共有のARNは、 #”aws --profile ${PROFILE} storagegateway list-file-shares”で確認 #リフレッシュの実行(デフォルトの動作) aws --profile ${PROFILE} storagegateway \ refresh-cache \ --file-share-arn ${FILE_SHARE_ARN} \ --folder-list ${FOLDER_LIST} \ --recursive ;
#構成情報の取得 GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') #アップデート状況の確認 #"NextUpdateAvailabilityDate"と、"LastSoftwareUpdate"を確認します。 #"NextUpdateAvailabilityDate"が表示されない場合、現時点で予定されているアップデートはありません。 aws --profile ${PROFILE} storagegateway \ describe-gateway-information \ --gateway-arn ${GATEWAY_ARN};
aws --profile ${PROFILE} storagegateway \ update-gateway-software-now \ --gateway-arn ${GATEWAY_ARN};
#アップデート状況の確認 #"NextUpdateAvailabilityDate"が表示されなくなり、"LastSoftwareUpdate"が直近の時間に変更されていることを確認します。 aws --profile ${PROFILE} storagegateway \ describe-gateway-information \ --gateway-arn ${GATEWAY_ARN};
以下の作業は、AdministratorAccess
のIAMポリシーがある作業端末で実行します。
EMAIL_ADDRESS='email@address' #Topicの作成 TOPIC_ARN=$(aws --profile ${PROFILE} --output text \ sns create-topic \ --name Sgw-Topic) #Sbscribeでメールを設定 aws --profile ${PROFILE} sns \ subscribe \ --topic-arn ${TOPIC_ARN} \ --protocol email \ --notification-endpoint ${EMAIL_ADDRESS} #設定したメールアドレスに、確認メールが届くので"Confirm subscription"をクリックし、承認します。 #メール送信テスト aws --profile ${PROFILE} sns \ publish \ --topic-arn ${TOPIC_ARN} \ --message 'Hello World!!' ;
Storage Gatewayのリフレッシュキャッシュの完了通知を受けて、作成したSNS Topicに連携する、Eventsのルールを作成します。
#構成情報の取得 GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') FILE_SHARE_ARNs=$(aws --profile ${PROFILE} --output text \ storagegateway list-file-shares \ --gateway-arn ${GATEWAY_ARN} \ --query FileShareInfoList[].FileShareARN ) TOPIC_ARN=$( aws --profile ${PROFILE} --output text \ sns list-topics | awk '/Sgw-Topic/{print $2}' ) ACCOUNT_ID=$(aws --profile ${PROFILE} --output text \ sts get-caller-identity --query 'Account') #ルールパターン用JSON生成 EVENT_PATTERN=' { "source": [ "aws.storagegateway" ], "resources":['"$( echo $(for i in $FILE_SHARE_ARNs;do echo '"'"${i}"'",';done)|sed -e 's/,$//')"' ], "detail-type": [ "Storage Gateway Refresh Cache Event" ] }' # Event Rule作成 aws --profile ${PROFILE} --output text events \ put-rule \ --name SgwPoc-Finish-RefleshCache \ --description "Receive notification of completion of specified file gateways RefreshCache and notify SNS topic" \ --event-pattern "${EVENT_PATTERN}" \ --schedule-expression "" \ --state ENABLED ; #ルールにターゲット設定 aws --profile ${PROFILE} events \ put-targets \ --rule SgwPoc-Finish-RefleshCache \ --targets "Id=1,Arn=${TOPIC_ARN},Input=,InputPath="; #SNS Topicのリソースポリシーにeventsのallowを追加 JSON='{ "Version": "2012-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:GetTopicAttributes", "SNS:SetTopicAttributes", "SNS:AddPermission", "SNS:RemovePermission", "SNS:DeleteTopic", "SNS:Subscribe", "SNS:ListSubscriptionsByTopic", "SNS:Publish", "SNS:Receive" ], "Resource": "'"${TOPIC_ARN}"'", "Condition": { "StringEquals": { "AWS:SourceOwner": "'"${ACCOUNT_ID}"'" } } }, { "Sid": "AWSEvents_SgwPoc-Finish-RefleshCache_1", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "'"${TOPIC_ARN}"'" } ] }' # aws --profile ${PROFILE} sns \ set-topic-attributes \ --topic-arn ${TOPIC_ARN} \ --attribute-name Policy \ --attribute-value "${JSON}"
FILE_SHARE_ARN="<操作したいファイル共有のARNを指定する>" FOLDER_LIST='/' #リフレッシュの実行(デフォルトの動作) aws --profile ${PROFILE} \ storagegateway refresh-cache \ --file-share-arn ${FILE_SHARE_ARN} \ --folder-list ${FOLDER_LIST} \ --recursive ;
(11)-(c)のリフレッシュ完了通知と同じSNS Topicを利用し、ファイルのアップロード完了通知を行います。本作業の前提として、(11)-(c)の設定済みであることとします。
#構成情報の取得 GATEWAY_ARN=$(aws --profile ${PROFILE} --output text storagegateway list-gateways |awk '/SgPoC-Gateway-1/{ print $4 }') FILE_SHARE_ARNs=$(aws --profile ${PROFILE} --output text \ storagegateway list-file-shares \ --gateway-arn ${GATEWAY_ARN} \ --query FileShareInfoList[].FileShareARN ) TOPIC_ARN=$( aws --profile ${PROFILE} --output text \ sns list-topics | awk '/Sgw-Topic/{print $2}' ) #ルールパターン用JSON生成 EVENT_PATTERN=' { "source": [ "aws.storagegateway" ], "resources":['"$( echo $(for i in $FILE_SHARE_ARNs;do echo '"'"${i}"'",';done)|sed -e 's/,$//')"' ], "detail-type": [ "Storage Gateway File Upload Event" ] }' # Event Rule作成 aws --profile ${PROFILE} --output text events \ put-rule \ --name SgwPoc-Finish-File-Upload \ --description "Receive notification of completion of specified file gateways files upload and notify SNS topic" \ --event-pattern "${EVENT_PATTERN}" \ --schedule-expression "" \ --state ENABLED ; #ルールにターゲット設定 aws --profile ${PROFILE} events \ put-targets \ --rule SgwPoc-Finish-File-Upload \ --targets "Id=1,Arn=${TOPIC_ARN},Input=,InputPath=";
#必要に応じ、FILE_SHARE_ARNを設定 FILE_SHARE_ARN="<操作したいファイル共有のARNを指定する>" #何らかファイルコピー実行と同時に、下記のnotify-when-uploadedを実行 aws --profile ${PROFILE} storagegateway \ notify-when-uploaded \ --file-share-arn ${FILE_SHARE_ARN};
Windows Subsystem for Linuxを使う必要があってPower Shellでセットアップした時のメモ。です。手順は、(1)Enable-WindowsOptionalFeatureでSubsystem for Linuxを有効かして、(2)Invoke-WebRequest でUbuntuイメージをダウンロードして、(3)Add-AppxPackageでダウンロードしたイメージをインストール、という流れです。
基本的には、Manually download Windows Subsystem for Linux distro packagesの手順に従ってセットアップしたものです。
検索でキーワードPower Shell
で探し、Power shellを起動します。
Power Shell上でEnable-WindowsOptionalFeature
コマンド*1で Subsystem for Linuxを有効化します。
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
結果は、Get-WindowsOptionalFeature
で確認することができます。
Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Invoke-WebRequest
コマンド*2で、Ubuntu18.04をUbuntu.appxというファイル名でダウンロードします。
Invoke-WebRequest -Uri https://aka.ms/wsl-ubuntu-1804 -OutFile Ubuntu.appx -UseBasicParsing
Ubuntsのイメージは下記リンク先の下にあります。(~はホームディレクトリで、Administratorの場合は、C:¥Users¥Administrator)
cd ~/AppData/Local/Packages/CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc/
ローカルドライブ(C:など)はデフォルトで、/mnt/c
のようにマウント済みであるはずです。
リモートのドライブは手動でmount -t drvfs <デバイス名> <マウントポイント>
コマンドでマウントする必要があります。例えばF:ドライブにマウントされているリモートドライブをSubsystem for Linuxでマウントする場合は以下のように操作します。
sudo mkdir /mnt/f sudo mount -t drvfs F: /mnt/f mount
検証用に、S3バケット上に1MBのファイル多量に準備したいという話があり、色々試行錯誤した経緯のメモです。
アプローチとしては、オリジナルファイルをインスタンスから都度アップロードするのはインスタンスに負荷がかかり(特にCPU、ネットワーク)効率が上がらないため、マスターデータをあらかじめS3にアップロードし、S3上にあるマスターファイルをcopy-object APIを利用し、実際のコピー処理をS3にオフロードさせるようにしています。
またCopyObject APIは、S3でのコピー完了を持って応答が帰ってくる*1ため、極力並列でAPIを実行すること処理時間の短縮を図っています。
なお検証結果から導かれるのCopyObjectによるコピーの並列実行のポイントは、以下の通りです。
マスターデータは同一プレフィクスへのアクセス集中を避けるためファイルごとに、"XXXXXXXXXX-original-data"(XXXXXXXXXXは、ランダムな文字列)というプレフィクスをつけて(フォルダに)格納します。
GETは、 「プレフィクス毎に秒間5,500 回以上の GET/HEAD リクエスト」となるので念の為それを意識した構成としています。(結果として、PUTのスロットリングが先に来ているので、ランダムな文字列は不要かもしれないです)
検証コードはこちらです。
github.com
# AWS CLIとboto3(AWS Python SDK)のセットアップ curl -o "get-pip.py" "https://bootstrap.pypa.io/get-pip.py" sudo python get-pip.py sudo pip install boto3 sudo pip install --upgrade awscli # AWS CLI設定 aws configure set aws_access_key_id <作成したIAMユーザのアクセスキー> aws configure set aws_secret_access_key <作成したIAMユーザのシークレットキー> aws configure set region ap-northeast-1 aws configure set output json # 検証用プログラムのダウンロード sudo yum -y install git git clone https://github.com/Noppy/GenerateCsvOfTestFilesList.git
#マスターファイル用のディレクトリ作成と移動 mkdir master && cd master ; pwd #マスターファイル生成 dd if=/dev/urandom of=test-001MB.dat bs=1024 count=1024 #マスターファイルのS3アップロード Profile=default MasterFileList="test-001MB.dat" Bucket=s3-100million-files-test for src in ${MasterFileList} do hash=$( cat /dev/urandom | base64 | fold -w 10 | sed -e 's/[\/\+\=]/0/g' | head -n 1 ) aws --profile=${Profile} s3 cp ${src} "s3://${Bucket}/${hash}-original-data/" done
# configration JSON用のテンプレート生成 cd ~/GenerateCsvOfTestFilesList #要件に応じて設定 NumberOfFiles="219120" StartDate="2015/1/1" EndDate="2019/12/31" Bucket=s3-100million-files-test #Jsonファイル生成 ./gen_json.sh "${NumberOfFiles}" "${StartDate}" "${EndDate}" "${Bucket}" #作成したJSONファイルの確認 cat config.json
#CSV生成 ./generate_testfiles_list.py #生成したCSVの確認 wc -l list_of_copy_files.csv #行数確認(NumberOfFilesと同じ行数が作成される)
AWS CLI(aws s3 cp)でオブジェクトごとにCLIバケット間コピーした場合と、Pythonで作成したプログラム(clinetで取得して、for文でCopyObjectを実行)した場合の実行速度のを比較します。
(1)検証用のターゲットリスト生成
NumberOfFiles="10800" StartDate="2015/1/1" EndDate="2015/3/31" Bucket=s3-100million-files-test #JSON作成 ./gen_json.sh "${NumberOfFiles}" "${StartDate}" "${EndDate}" "${Bucket}" #ターゲットリスト作成 ./generate_testfiles_list.py wc -l list_of_copy_files.csv
(2)検証実行
(2)-(a) AWS CLIでの実行
実行し、timeの"real"の時間を取得
time awk -F ',' -e '{print $1; print $2}' ./list_of_copy_files.csv | xargs -P 100 -L 2 aws s3 cp
(2)-(b) Pythonでの実行
test1_result_summary.csvに出力される実行時間を取得
./S3_CopyObject_ParallelExecution.sh 100 test1_result_summary.csv
(1)ulimitの増加設定
OSのulimitデフォルトでは、ユーザが同時実行可能なプロセス(nproc)は1024、同時オープンファイル(nofile)は4096です。このままでは、多重実行の検証中にリソース不足でエラーが発生する恐れがあるため、ulimitの設定を引き上げます。
sudo -i cat > /etc/security/limits.d/99-s3-test.conf * hard nofile 500000 * soft nofile 500000 * hard nproc 100000 * soft nproc 100000 別コンソールで、sshログインし下記コマンドで設定反映を確認 ulimit -Ha
(2)検証用のターゲットリスト生成
NumberOfFiles="219120" StartDate="2015/1/1" EndDate="2019/12/31" Bucket=s3-100million-files-test #JSON作成 ./gen_json.sh "${NumberOfFiles}" "${StartDate}" "${EndDate}" "${Bucket}" #ターゲットリスト作成 ./generate_testfiles_list.py wc -l list_of_copy_files.csv
(3)検証実行
インスタンスタイプを変更(都度再起動)しながら、下記コマンドを実行します。
検証結果は、test_3_results_summary.csvに集約
nohup ./test_3_s3tos3_python_parallels.sh &
(1) 多重度とCopyObject API実行回数
インスタンスタイプをあげても処理時間の平均3000〜3500回/秒あたりで頭打ちとなり、それ以上多重度をあげるとS3のスロットリングが発生します。*3
並列度数 | CopyObject実行数( 回/秒 ) | ||
---|---|---|---|
m5a_4xlarge(16vcpu) | m5a_8xlarge(32vcpu) | m5a_12xlarge(48vcpu) | |
100 | 654.1 | 695.6 | 672.1 |
200 | 1259.3 | 1320.0 | 1328.0 |
400 | 1767.1 | 2407.9 | 2407.9 |
800 | 1660.0 | 3043.3 | 3844.2 |
1000 | N/A | 2213.3 | 3652.0 |
1500 | N/A | 2577.9 (SlowDown発生) | 2331.1 (SlowDown発生) |
2000 | N/A | 2282.5 (SlowDown発生) | 2672.2 (SlowDown発生) |
次にその多重度800を実行するのに最適なインスタンスタイプについて、m5a.12xlarge(48vcpu)ではCPUに余力があることから、その一つ下のm5a.8xlarge(32vcpu)がもっとも効率よくインスタンスリソースを利用できていることがわかります。
この検証から「S3のAPI実行回数、3000〜3500回/秒程度」を越えるとS3スロットリング(SlowDown)が発生していることが読み取れます。この内容から検索すると、S3の開発者ガイドの「ベストプラクティスの設計パターン: Amazon S3 パフォーマンスの最適化」に以下の記載がありました。この内容から今回の検証では「プレフィックスごとに 1 秒あたり 3,500 回以上の PUT/COPY/POST/DELETE リクエスト」に合致している可能性が高いと思われます。
アプリケーションは、Amazon S3 からストレージをアップロードおよび取得する際にリクエストパフォーマンスで 1 秒あたり何千ものトランザクションを簡単に達成できます。Amazon S3 は高いリクエスト率に自動的にスケールされます。たとえば、アプリケーションでバケット内のプレフィックスごとに 1 秒あたり 3,500 回以上の PUT/COPY/POST/DELETE リクエストと 5,500 回以上の GET/HEAD リクエストを達成できます。
S3は負荷に応じて内部で自動スケーリングしますが、自動スケーリングを上手く利用しさらなる改善を図るための方策として以下のものがあります。
具体的対応については、次の検証で検討します。
参考情報
プレフィクスを「年/月/日/時」から、逆にし先頭にハッシュをつけることで分散処理するようにする対策です。
具体的にはS3格納先のプレフィクスを「XXX-時/日/月/年」とします。
手順
(1)検証用のターゲットリスト生成
NumberOfFiles="2191200" StartDate="2015/1/1" EndDate="2019/12/31" Bucket=s3-100million-files-test #JSON作成 ./gen_json.sh "${NumberOfFiles}" "${StartDate}" "${EndDate}" "${Bucket}" #ターゲットリスト作成 ./generate_testfiles_list.py --reverse wc -l list_of_copy_files.csv
(2)検証実行
nohup ./S3_CopyObject_ParallelExecution.sh 800 test_2million_summary.csv &
(3)検証結果
理由を正確には確認できないですが、プレフィクスを変更してもSlowDownの比率は大きく変わりませんでした。
もしかしたらオートスケールするまでのタイムラグがあったのかもしれませんが。
SlowDownが発生したときに再実行して対処する方策です。
アプリケーションで再実行のロジックを実装する手段もありますが、今回はAWS SDK(boto3)のコンフィグで再実行回数を引き上げて対応しています。
具体的には、client()の引数に設定します。
# Get session config = Config( retries=dict( max_attempts = args.retry ) ) s3 = boto3.client('s3', config=config)
手順
(1)検証用のターゲットリスト生成
#ターゲットリスト作成 ./generate_testfiles_list.py --reverse wc -l list_of_copy_files.csv
(2)検証実行
(2)-(a) 再実行回数デフォルト
nohup ./S3_CopyObject_ParallelExecution.sh 800 test_2million_summary.csv &
(2)-(b) 再実行回数を10回そのまま実行
nohup ./S3_CopyObject_ParallelExecution.sh 800 test_2million_summary.csv 10 &
(3)検証結果
再実行回数を10回に引き上げSDKでリトライすることで全量コピーができるようになりました。
対象数 | 再実行回数 | 実行時間 | 秒間実行回数 | 実行結果(オブジェクト数) | ||
---|---|---|---|---|---|---|
成功 | 失敗 | 合計 | ||||
2191200 | 4 | 692 | 3166.5 | 2188419 | 2781 | 2191200 |
2191200 | 4 | 698 | 3139.3 | 2190116 | 1084 | 2191200 |
2191200 | 4 | 688 | 3184.9 | 2189677 | 1523 | 2191200 |
2191200 | 10 | 562 | 3898.9 | 2191200 | 0 | 2191200 |
2191200 | 10 | 556 | 3941.0 | 2191200 | 0 | 2191200 |
2191200 | 10 | 563 | 3892.0 | 2191200 | 0 | 2191200 |
簡易的ですが、SDKの再実行回数の引き上げでSlowDownを抑えることができようになりました。
今回のS3のCopyObjectによるコピーの並列実行によるコピー時間短縮の検証のまとめです。
EC2インスタンス上に、IAMユーザのアクセスキーとキーポリシーを設定するのは、AWSのベストプラクティス(セキュリティ観点)ではバッドプラクティスとされています。
しかしインスタンスロールの場合、ロールのクレデンシャルをインスタンスのメタデータから取得*4するのですが、今回のようにプロセスを数百起動しメタデータに同時アクセスすると同時アクセスエラーが発生しクレデンシャル取得に失敗します。
本番運用向けであれば、共通機能でクレデンシャルを取得しキャッシュして必要なプロセスからの要求に応じてクレデンシャルを渡すような実装をするのがいいのかもしれないですが実装コストがかかるため、今回はアクセスキーとシークレットキーを利用する方式にしました。アクセスキーとシークレットキーの場合は、"~/.aws/credentials"ファイルに格納されておりファイルへのアクセスであれば同時アクセスがいくらあってもエラーにはならないです。
*1:copy-object APIの記載: "If the copy is successful, you receive a response with information about the copied object."
*2:オーバヘッド:プロセス生成してpythonモジュールをロードし&解析して、AWSのクレデンシャル取得して、認証&セッション取得てという、CopyObject実行までに至る前処理
*3:"ERROR:root:An error occurred (SlowDown) when calling the CopyObject operation (reached max retries: 4): Please reduce your request rate."エラーが発生。S3から"HTTP 503 Slow Down 応答があったことを示唆。
*4:インスタンスロールのクレデンシャルは"http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名"で取得できます
ACM(AWS Certificate Manager)ではなく、IAMでサーバ証明書をインポートするときのCLI手順のメモです。
PROFILE=default aws --profile ${PROFILE} iam upload-server-certificate \ --server-certificate-name hoge.com \ --certificate-body file://hoge.com.crt \ --private-key file://hoge.com.key
aws --profile ${PROFILE} iam list-server-certificates
KMS鍵(CMK)で暗号化したEBSを持つEC2インスタンスのAMIを取得し、別リージョンにコピーする場合、鍵がどうなるのかという確認をCLIで確認したエビデンスです。
結論としては、他リージョンにAMIをコピーする時にコピー先リージョンのCMKを指定することになります。
こちらのRDSの検証と同じ結果です。
nopipi.hatenablog.com
CLIに渡すパラメータのいくつかを、シェルの変数として事前設定しています。
#作業端末のプロファイル指定(デフォルトでない場合適時変更して下さい) PROFILE=ExSPoC #東京リージョンの設定 # 実際に検証する環境に合わせて、RDSをデプロイする先のVPCのIPと、サブネットのIDを変更してください。 REGION_SRC=ap-northeast-1 REGION_SRC_VPCID=vpc-8e6c5ce9 REGION_SRC_SUBNET=subnet-48cfe313 REGION_SRC_AMZL2_AMI_ID=ami-0ff21806645c5e492 REGION_SRC_EC2_KEY_PAIR=KEY_PAIR_NAME #シドニーリージョンの設定 # 実際に検証する環境に合わせて、RDSをデプロイする先のVPCのIPと、サブネットのIDを変更してください。 REGION_DST=ap-southeast-2 REGION_DST_VPCID=vpc-01cfe566 REGION_DST_SUBNET=subnet-1f292656 REGION_DST_EC2_KEY_PAIR=KEY_PAIR_NAME AWS_ACCOUNT=$( aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ sts get-caller-identity --query 'Account' )
EC2インスタンス(EBS)暗号化に利用するKMSキーを、コピー元リージョン、コピー先リージョンそれぞれで作成します。
SRC_KEY_ID=$( \ aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ kms create-key \ --description "CMK to test Ec2 instance encryption" \ --origin AWS_KMS \ --query 'KeyMetadata.KeyId' ) aws --profile ${PROFILE} --region ${REGION_SRC} \ kms create-alias \ --alias-name alias/Key_To_Test_Instance_Encription \ --target-key-id ${SRC_KEY_ID}
DST_KEY_ID=$( \ aws --profile ${PROFILE} --region ${REGION_DST} --output text \ kms create-key \ --description "CMK to test Ec2 instance encryption" \ --origin AWS_KMS \ --query 'KeyMetadata.KeyId' ) aws --profile ${PROFILE} --region ${REGION_DST} \ kms create-alias \ --alias-name alias/Key_To_Test_Instance_Encription \ --target-key-id ${DST_KEY_ID}
セキュリティーグループを作成し、EC2インスタンスを作成します。
SRC_EC2_SG_ID=$( \ aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ ec2 create-security-group \ --group-name SgForEc2 \ --description "SG for EC2 Instances" \ --vpc-id ${REGION_SRC_VPCID} \ --query 'GroupId' ) aws --profile ${PROFILE} --region ${REGION_SRC} \ ec2 authorize-security-group-ingress \ --group-id ${SRC_EC2_SG_ID} \ --protocol tcp \ --port 22 \ --cidr 0.0.0.0/0
# Block-device-mappings用のJSON作成 JsonBlockDeviceMappings=' [ { "DeviceName":"/dev/xvda", "Ebs":{ "VolumeType": "gp2", "VolumeSize":8, "DeleteOnTermination":true, "Encrypted": true, "KmsKeyId": "'"${SRC_KEY_ID}"'" } } ] ' # EC2インスタンスの起動 aws --profile ${PROFILE} --region ${REGION_SRC} \ ec2 run-instances \ --count 1 \ --instance-type t2.micro \ --image-id ${REGION_SRC_AMZL2_AMI_ID} \ --key-name ${REGION_SRC_EC2_KEY_PAIR} \ --monitoring Enabled=true \ --security-group-ids ${SRC_EC2_SG_ID} \ --subnet-id ${REGION_SRC_SUBNET} \ --associate-public-ip-address \ --block-device-mappings "${JsonBlockDeviceMappings}" \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=EC2-KMS-TEST-SRC}]' # EC2インスタンスのID取得 SRC_INSTANCE_ID=$( aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ ec2 describe-instances \ --filters "Name=tag:Name,Values=EC2-KMS-TEST-SRC" \ --query 'Reservations[*].Instances[*].InstanceId' )
作成したEC2にsshログインし、ファイルを作成します。
#sshで、RDSのあるVPC上のEC2にログインして下記を実行 echo 'Hello World!!' > test.txt
作成したEC2インスタンスのAMIを取得します。
データの静止点を取るため最初にインスタンスを停止し、AMIを取得します。
EBSが暗号化されている場合、AMI(正確にはAMI用に取得されたEBSのスナップショット)もインスタンスのEBSと同じCMKで暗号化されます。
aws --profile ${PROFILE} --region ${REGION_SRC} \ ec2 stop-instances \ --instance-ids ${SRC_INSTANCE_ID}
#AMI取得 aws --profile ${PROFILE} --region ${REGION_SRC} \ ec2 create-image \ --instance-id ${SRC_INSTANCE_ID} \ --name "SRC_INSTANCE_AMI" #取得したAMIのID取得 SRC_AMI_ID=$( aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ ec2 describe-images \ --filters "Name=name,Values=SRC_INSTANCE_AMI" \ --query 'Images[*].{ID:ImageId}' )
コピー元リージョンで取得したAMIを、コピー先リージョンにコピーします。
コピー先のシンガポールリージョンで実行しているところに注意ください。(--reogionオプション指定を見てください)
#AMIのコピー aws --profile ${PROFILE} --region ${REGION_DST} \ ec2 copy-image \ --source-image-id ${SRC_AMI_ID} \ --source-region ${REGION_SRC} \ --name COPY_AMI_FROM_SRC_REGION \ --encrypted \ --kms-key-id ${DST_KEY_ID} #コピーしたAMIのID取得 DST_AMI_ID=$( aws --profile ${PROFILE} --region ${REGION_DST} --output text \ ec2 describe-images \ --filters "Name=name,Values=COPY_AMI_FROM_SRC_REGION" \ --query 'Images[*].{ID:ImageId}' )
セキュリティーグループを作成し、コピー元リージョンからコピーしたAMIからインスタンスを起動します。
DST_EC2_SG_ID=$( \ aws --profile ${PROFILE} --region ${REGION_DST} --output text \ ec2 create-security-group \ --group-name SgForEc2 \ --description "SG for EC2 Instances" \ --vpc-id ${REGION_DST_VPCID} \ --query 'GroupId' ) aws --profile ${PROFILE} --region ${REGION_DST} \ ec2 authorize-security-group-ingress \ --group-id ${DST_EC2_SG_ID} \ --protocol tcp \ --port 22 \ --cidr 0.0.0.0/0
# EC2インスタンスの起動 aws --profile ${PROFILE} --region ${REGION_DST} \ ec2 run-instances \ --count 1 \ --instance-type t2.micro \ --image-id ${DST_AMI_ID} \ --key-name ${REGION_DST_EC2_KEY_PAIR} \ --monitoring Enabled=true \ --security-group-ids ${DST_EC2_SG_ID} \ --subnet-id ${REGION_DST_SUBNET} \ --associate-public-ip-address \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=EC2-KMS-TEST-DST}]'
作成したEC2にsshログインし、コピー元リージョンで作成したファイルがあるか確認します。
#sshで、RDSのあるVPC上のEC2にログインして下記を実行 ll cat test.txt
EBSスナップショットを他リージョンにコピーする場合も、スナップショットコピー時にコピー先リージョンのCMKを指定します。
#コピー元リージョンで、AMI作成時に作成されたEBSスナップショットを設定 #"Created by CreateImage(i-xxxxx) for ami-xxxx"という説明のスナップショット SRC_SNAPSHOT_ID=snap-06e05677d40f66db5 #EBSスナップショットを他リージョンにコピー aws --profile ${PROFILE} --region ${REGION_DST} \ ec2 copy-snapshot \ --source-snapshot-id ${SRC_SNAPSHOT_ID} \ --source-region ${REGION_SRC} \ --encrypted \ --kms-key-id ${DST_KEY_ID}
RDSをKMSの鍵で暗号化する場合、RDSインスタンスがあるそれぞれのリージョンKMS鍵(CMK:Customer Master Key)で暗号化しますが、DBスナップショットで、他リージョンにDBをコピーする場合、鍵はどうなるのかということを確認するための検証手順です。
結論としては、他リージョンにDBスナップショットをコピーする時にコピー先リージョンのCMKを指定することになります。
CLIに渡すパラメータのいくつかを、シェルの変数として事前設定しています。
#作業端末のプロファイル指定(デフォルトでない場合適時変更して下さい) PROFILE=default #東京リージョンの設定 # 実際に検証する環境に合わせて、RDSをデプロイする先のVPCのIPと、サブネットのIDを変更してください。 REGION_SRC=ap-northeast-1 REGION_SRC_VPCID="vpc-8e6c5ce9" REGION_SRC_SUBNETS="subnet-48cfe313 subnet-a2448189 subnet-0214e64a" #シンガポールリージョンの設定 # 実際に検証する環境に合わせて、RDSをデプロイする先のVPCのIPと、サブネットのIDを変更してください。 REGION_DST=ap-southeast-1 REGION_DST_VPCID="vpc-0bcdca6c" REGION_DST_SUBNETS="subnet-8307a0da subnet-1eae4578 subnet-58cdd511" #RDS設定 RDS_INSTANCE_CLASS=db.m5.large RDS_ENGIN=MySQL RDS_ENGIN_VERSION=8.0.16 RDS_DB_ADMIN=admin RDS_DB_ADMIN_PASSWD=password AWS_ACCOUNT=$( aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ sts get-caller-identity --query 'Account' )
RDS暗号化に利用するKMSキーを、東京リージョン、シンガポールリージョンそれぞれで作成します。
SRC_KEY_ID=$( \ aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ kms create-key \ --description Key_For_Source_Snapshot \ --origin AWS_KMS \ --query 'KeyMetadata.KeyId' ) aws --profile ${PROFILE} --region ${REGION_SRC} \ kms create-alias \ --alias-name alias/Key_For_Source_Snapshot \ --target-key-id ${SRC_KEY_ID}
DST_KEY_ID=$( \ aws --profile ${PROFILE} --region ${REGION_DST} --output text \ kms create-key \ --description Key_For_Source_Snapshot \ --origin AWS_KMS \ --query 'KeyMetadata.KeyId' ) aws --profile ${PROFILE} --region ${REGION_DST} \ kms create-alias \ --alias-name alias/Key_For_Destination_Snapshot \ --target-key-id ${DST_KEY_ID}
セキュリティーグループを作成とRDSのサブネットグループを作成し、RDSを作成します。
SRC_RDS_SG_ID=$( \ aws --profile ${PROFILE} --region ${REGION_SRC} --output text \ ec2 create-security-group \ --group-name SgForRdsMySQL \ --description "SG for RDS MySQL" \ --vpc-id ${REGION_SRC_VPCID} \ --query 'GroupId' ) aws --profile ${PROFILE} --region ${REGION_SRC} \ ec2 authorize-security-group-ingress \ --group-id ${SRC_RDS_SG_ID} \ --protocol tcp \ --port 3306 \ --cidr 0.0.0.0/0
aws --profile ${PROFILE} --region ${REGION_SRC} \ rds create-db-subnet-group \ --db-subnet-group-name rds_mysql \ --db-subnet-group-description "KMS TEST for RDS MySQL" \ --subnet-ids ${REGION_SRC_SUBNETS}
aws --profile ${PROFILE} --region ${REGION_SRC} \ rds create-db-instance \ --db-instance-identifier Test-RDS-MySQL \ --db-instance-class ${RDS_INSTANCE_CLASS} \ --engine ${RDS_ENGIN} \ --engine-version ${RDS_ENGIN_VERSION} \ --allocated-storage 20 \ --master-username ${RDS_DB_ADMIN} \ --master-user-password ${RDS_DB_ADMIN_PASSWD} \ --backup-retention-period 3 \ --vpc-security-group-ids ${SRC_RDS_SG_ID} \ --no-publicly-accessible \ --db-subnet-group-name rds_mysql \ --storage-encrypted \ --kms-key-id ${SRC_KEY_ID}
RDSと同じVPC上のEC2から、RDSにアクセスしテーブル作成とデータインサートを行います。
#sshで、RDSのあるVPC上のEC2にログインして下記を実行 sudo yum -y install mysql mysql -h <RDSのエンドポイントURL> -u admin -p #パスワード(password)入力 MySQL > CREATE DATABASE sampledb; MySQL > USE sampledb; MySQL > CREATE TABLE IF NOT EXISTS `sample` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL DEFAULT 'hoge', PRIMARY KEY(`id`) ); MySQL > INSERT INTO sample( name ) VALUES ( '鈴木' ); MySQL > COMMIT; MySQL > SELECT * FROM sample; MySQL > quit
RDSを作成し、DBインスタンスが起動したらスナップショットを手動取得します。
暗号化されたRDSから取得されたスナップショットは暗号されており、KMSでDBを暗号化している場合同じCMKでスナップショットも暗号化されます。
aws --profile ${PROFILE} --region ${REGION_SRC} \ rds create-db-snapshot \ --db-instance-identifier Test-RDS-MySQL \ --db-snapshot-identifier snapshot-for-cross-region-replication-src-db
東京リージョンで取得したスナップショットを、シンガポールリージョンにコピーします。
コピー先のシンガポールリージョンで実行しているところに注意ください。(--reogionオプション指定を見てください)
aws --profile ${PROFILE} --region ${REGION_DST} \ rds copy-db-snapshot \ --source-db-snapshot-identifier arn:aws:rds:${REGION_SRC}:${AWS_ACCOUNT}:snapshot:snapshot-for-cross-region-replication-src-db \ --target-db-snapshot-identifier snapshot-for-cross-region-replication-dst-db \ --source-region ${REGION_SRC} \ --kms-key-id ${DST_KEY_ID}
セキュリティーグループを作成とRDSのサブネットグループを作成し、東京リージョンからコピーしたスナップショットからRDSインスタンスを複製します。スナップショットからのインスタンスの複製には" restore-db-instance-from-db-snapshot"を利用します。
DST_RDS_SG_ID=$( \ aws --profile ${PROFILE} --region ${REGION_DST} --output text \ ec2 create-security-group \ --group-name SgForRdsMySQL \ --description "SG for RDS MySQL" \ --vpc-id ${REGION_DST_VPCID} \ --query 'GroupId' ) aws --profile ${PROFILE} --region ${REGION_DST} \ ec2 authorize-security-group-ingress \ --group-id ${DST_RDS_SG_ID} \ --protocol tcp \ --port 3306 \ --cidr 0.0.0.0/0
aws --profile ${PROFILE} --region ${REGION_DST} \ rds create-db-subnet-group \ --db-subnet-group-name rds_mysql \ --db-subnet-group-description "KMS TEST for RDS MySQL" \ --subnet-ids ${REGION_DST_SUBNETS}
aws --profile ${PROFILE} --region ${REGION_DST} \ rds restore-db-instance-from-db-snapshot \ --db-instance-identifier Test-RDS-MySQL-DST \ --db-snapshot-identifier snapshot-for-cross-region-replication-dst-db \ --vpc-security-group-ids ${DST_RDS_SG_ID} \ --db-subnet-group-name rds_mysql