Quantcast
Channel: 技術 –サーバーワークスエンジニアブログ
Viewing all 1210 articles
Browse latest View live

ラジオ体操の時間にファイル転送したいんだよねぇ 〜AWS Transfer for SFTP〜

$
0
0

あ〜た〜らし〜い、朝が〜きた〜

おはようございます。技術1課の木次です。いっちに〜
皆さんラジオ体操してますか?さんし〜

今週1週間はリモートワーク勤務が推奨されています。(2019年もテレワーク・デイズに参加いたします)
ずーっと自宅だと体に悪いので、期間中はなるべくラジオ体操をやっています。いっちに〜 さんし〜

SFTP で AWS 側にファイル転送

古いシステムやパッケージ連携などで、ファイル転送に SFTP を利用するケースがあります。
SFTP とは SSH File Transfer Protocol の略で、文字通り SSH 経由でファイル転送をするため、従来の FTP に比べてセキュアな通信が可能です。

この SFTP で AWS 側にファイル転送する場合、EC2 インスタンスをたてて、というやり方もありますが、可用性を考えるとやりたくないですよね。
そのような場合、AWS Transfer for SFTP を利用すると幸せになれます。

AWS Transfer for SFTP

昨年の re:Invent 2018 で発表されたマネージドな SFTP サービスです。
転送したファイルは S3 に保存してくれるので、やろうと思えばサーバーレスな環境を構築できます。

気になる金額ですが、1時間ごとの料金になります。(それ以外にデータアップロードとダウンロードの転送料金も発生)
東京リージョンだと、1 時間あたり 0.3USD。常時稼働した場合、1日で 7.2 USD。1月だと約 216 USD です。

特定の時間だけ利用したい

いやー、ファイル転送するのは朝方だけなんだよねぇ。1時間だけでいいんだよ。

オンプレなら難しいですが、AWS なら 1時間だけ 大丈夫です。スケジュール実行した Lambda から AWS Transfer for SFTP を作成・削除してみましょう。
せっかくなので、ラジオ体操中にファイル転送を試してみます。いっちに〜 さんし〜

おおまかな流れは以下になります。

  1. 【CloudWatch】AM 6:00 スケジュール実行
  2. 【Step Functions】Transfer Server を作成
  3. 【Step Functions】50分待機
  4. 【クライアント】AM 06:35 ファイル転送
  5. 【Step Functions】Transfer Server を削除

ポイントは Step Functions。
2 で作成した Transfer Server のサーバーID をステートとして保持し、4 で削除のために利用します。

AWS Step Functions

AWS Step Functions は、視覚的なワークフローを使用して、分散アプリケーションとマイクロサービスのコンポーネントを調整できるマネージドなサービスです。ASL (Amazon States Language) と呼ばれる JSON 形式の言語でワークフローを定義できます。

このワークフロー内で、タスクを定義して Lambda を呼び出します。
Lambda 自身はステートレスなので状態(ステート) を保持できせん。ですが、Step Functions を利用すると、ワークフロー内で値を引き渡すことができます。

ワークフローを下記のように定義します。状態遷移はシンプルに上から下へ流れるだけです。

{
  "StartAt": "CreateServer",
  "States": {
    "CreateServer": {
          "Type": "Task",
          "Resource": "arn:aws:states:::lambda:invoke",
          "Parameters": {
              "FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:create-transfer-server:$LATEST",
              "Payload": {
                "Input.$": "$"
              }
          },
          "OutputPath": "$",
          "Next": "WaitForRadioExercises"
      },
    "WaitForRadioExercises": {
      "Type": "Wait",
      "Seconds": 3000,
      "Next": "DeleteServer"
    },
    "DeleteServer": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:delete-transfer-server:$LATEST",
        "Payload": {
          "Input.$": "$"
        }
      },
      "End": true
    }
  }
}

StartAt 項目では、最初に起動するステートを設定し、Next 項目で次に実行するステートを設定します。最後のステートには End 項目に true を設定します。

処理詳細

細かく見ていきましょう。

1. AM 6:00 スケジュール実行

CloudWatch Events で 日本時間 AM 6:00 (0 21 * * ? *) に起動するルールを作成します。UTCなので、そこは注意です。
起動するターゲットとして作成した Step Functions ステートマシン を選択し、入力値として 定数(JSON) を渡します。

{
    "HostedZoneId": "Route53 ホストゾーンID",
    "UserName": "SFTPユーザー名",
    "UserRoleArn": "arn:aws:iam::xxxxxxxxxxxx:role/SFTPユーザーロール名",
    "UserDirectory": "S3バケット保存先",
    "SubDomain": "サブドメイン",
    "LoggingRoleArn": "arn:aws:iam::xxxxxxxxxxxx:role/CloudWatchログ用ロール名"
}

この入力値は Lambda 内で利用します。

2. Transfer Server を作成

CreateServer ステートでは、ステートタイプに Task を指定して Transfer Server を作成する Lambda を呼び出します。

Transfer は比較的新しいサービスのため、boto3 モジュールと一緒にデプロイしてください。
対応していない場合は [ERROR] UnknownServiceError: Unknown service: 'transfer' と表示されます。

import os
import boto3


transfer = boto3.client('transfer')
route53 = boto3.client('route53')


def create_server(logging_role_arn):
    response = transfer.create_server(
        EndpointType='PUBLIC',
        IdentityProviderType='SERVICE_MANAGED',
        LoggingRole=logging_role_arn
    )
    return response.get('ServerId')


def upsert_cname_record(hosted_zone_id, server_id, sub_domain):
    res1 = route53.get_hosted_zone(
        Id=hosted_zone_id
    )
    host_name = res1['HostedZone']['Name']

    record = sub_domain + '.' + host_name
    region_name = boto3.session.Session().region_name
    target = f'{server_id}.server.transfer.{region_name}.amazonaws.com'

    res2 = route53.change_resource_record_sets(
        HostedZoneId=hosted_zone_id,
        ChangeBatch={
            'Comment': f'{record} -> {target}',
            'Changes': [
                {
                    'Action': 'UPSERT',
                    'ResourceRecordSet': {
                        'Name': record,
                        'Type': 'CNAME',
                        'TTL': 300,
                        'ResourceRecords': [
                            {
                                'Value': target
                            }
                        ]
                    }
                }
            ]
        }
    )
    return res2


def lambda_handler(event, context):
    logging_role_arn = event['Input']['LoggingRoleArn']
    hosted_zone_id = event['Input']['HostedZoneId']
    sub_domain = event['Input']['SubDomain']
    user_name = event['Input']['UserName']
    user_role_arn = event['Input']['UserRoleArn']
    user_directory = event['Input']['UserDirectory']
    ssh_pub_key = os.environ['SSH_PUB_KEY']

    # サーバー作成
    server_id = create_server(logging_role_arn)

    # CNAMEレコード作成
    upsert_cname_record(hosted_zone_id, server_id, sub_domain)

    # ユーザー作成
    transfer.create_user(
        ServerId=server_id,
        UserName=user_name,
        Role=user_role_arn,
        HomeDirectory=user_directory,
        SshPublicKeyBody=ssh_pub_key
    )

    return {
        'Transfer': {
            'ServerId': server_id,
            'HostedZoneId': hosted_zone_id,
            'SubDomain': sub_domain
        }
    }

  • create_server
    • SFTP サーバーを作成します。戻り値のサーバーID は削除時にも利用します。
    • CloudWatch Logs にログ保存するためのロールを指定します。
  • upsert_cname_record
    •  クライアント側からのエンドポイントを固定するため、CNAME レコードセットを作成します。
    • 事前に Route 53 にホストゾーンを作成しておきます。
  • create_user
    •  クライアントから接続するために、SFTP にユーザーを作成します。
    • サンプルのため SSH 公開鍵は環境変数から取得しています。実際には SSM パラメータストア や Secrets Manager を検討した方がいいでしょう。

3. 50分待機

ステートタイプに Wait を指定して、待機する秒数を設定しています。

4. AM 06:35 ファイル転送

他サーバーに sftp を 実行するシェルを用意して、AM 6:35 (35 21 * * *) に実行されるように cron を仕掛けます。

#!/bin/bash

sftp -i 秘密鍵 -o 'StrictHostKeyChecking no' -oPort=22 -b バッチファイル ユーザー名@ホスト名
exit 0

バッチファイルの中身では PUT コマンドを記述します。

5. Transfer Server を削除

import boto3


transfer = boto3.client('transfer')
route53 = boto3.client('route53')


def delete_server(server_id):
    response = transfer.delete_server(
        ServerId=server_id
    )
    return response


def delete_cname_record(hosted_zone_id, server_id, sub_domain):
    res1 = route53.get_hosted_zone(
        Id=hosted_zone_id
    )
    host_name = res1['HostedZone']['Name']
    print(host_name)

    record = sub_domain + '.' + host_name
    region_name = boto3.session.Session().region_name
    target = f'{server_id}.server.transfer.{region_name}.amazonaws.com'

    res2 = route53.change_resource_record_sets(
        HostedZoneId=hosted_zone_id,
        ChangeBatch={
            'Changes': [
                {
                    'Action': 'DELETE',
                    'ResourceRecordSet': {
                        'Name': record,
                        'Type': 'CNAME',
                        'TTL': 300,
                        'ResourceRecords': [
                            {
                                'Value': target
                            }
                        ]
                    }
                }
            ]
        }
    )
    return res2


def lambda_handler(event, context):
    args = event['Input']['Payload']['Transfer']
    server_id = args.get('ServerId')
    hosted_zone_id = args.get('HostedZoneId')
    sub_domain = args.get('SubDomain')

    # サーバー削除
    delete_server(server_id)

    # レコードセット削除
    delete_cname_record(hosted_zone_id, server_id, sub_domain)

  • delete_server
    • SFTP サーバーを削除します。作成したユーザーも一緒に削除されます。
  • delete_cname_record
    • 作成した CNAME のレコードセットを削除します。

実際にラジオ体操やってきた

ということで、ラジオ体操をやっている公園にやってきました。自宅から徒歩30分くらい。程よい距離で散歩にも適しています。

ラジオ体操は 6:30 スタート。
最初は第一体操から始まり、第二体操へ。そして40分頃に終了となります。

1日目

恥ずかしくて端っこから参加。
おいおい結構しんどいぞ、汗だらだら。そしてラジオ体操第二をすっかり忘れてる。。。

2日目

勇気を出して輪の中へ。いつか、あの真ん中のステージに立ちたい。いっちに〜 さんし〜

3日目

より前進。
3日目には恥ずかしさはなくなり、第二体操も8割くらい出来るように。気持ちいい〜。いっちに〜 さんし〜

結果は

さて、ファイルは届いているでしょうか。まずは Step Functions ワークフローの結果を確認します。

実行ステータスは成功 。開始と終了時間も想定通りです。

指定した S3 バケットにファイルが届いていました。更新日時も想定通りです。
やったね。

最後に

ラジオ体操はテレワーク・デイズ期間だけと思っていましたが、体と脳が刺激されて、その後の仕事がはかどるような気がしました。
せっかくなので、リモートワークの日は積極的に行こうと思います。

今日はこのへんで失礼します。いっちに〜 さんし〜


AWSのコスト配分タグを正しく理解する

$
0
0

CS課 佐竹です。

皆さん、AWSのリソースにはタグ付けされてますでしょうか。今回はタグ及びコスト配分タグについて、整理を目的に記載します。

はじめに

「コスト配分タグ」とは何でしょうか?英語では「Cost Allocation Tags」と記載されますこのタグは、AWS利用明細において、タグ別に利用料金を出力したい場合に利用します。例えばEC2 Instanceが100台構築されている場合でも、1台1台別のNameタグを付与しておけば、それぞれNameタグ別に利用料を出力することができます。非常に便利ですね。これは Cost Explorer においても有効であり、AWS利用料を正しく把握し運用するためには、タグの付与はもはや必須であると言えるでしょう。上の画像では、赤枠の中がコスト配分タグによって出力された明細になります。

今回は、正しくコスト配分タグをAWS利用料の明細に出力するにあたり、前提として理解しておくべき情報をお伝えします。

公式ドキュメントのリンク

先に「コスト配分タグ」に関する、AWS公式ドキュメントのURLリンクをご紹介します。


AWS ドキュメント » AWS Billing and Cost Management » ユーザーガイド » 使用状況とコストのモニタリング » コスト配分タグの使用

https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html

AWSのタグを理解する

さっそく、詳しく説明していきます。

リソースにタグを付与する

AWSリソースには、ユーザ独自のタグを付与することができます。今回は、代表的なサービスとしてEC2を例にとってご説明します。

上図のように、EC2 Instanceには、マネジメントコンソールからタグが付与可能です。タグは「Key」と「Value」のセットで定義されます。今回の例では

  • Key = Name
  • Value = WinServ2019Japanese(OraClient) 

というタグを1つ付与しています。今回は1つだけ付与していますが、タグは複数の付与が可能です。タグの利用においては制限がありますので、以下の公式ドキュメントをご参照ください。

タグの制限
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/Using_Tags.html#tag-restrictions

最初にご理解いただきたいポイントは以下の通りです。

  1. AWSのリソースには、ユーザ独自のタグを付与する機能がある
  2. タグはKeyとValueのセットで定義される

タグKeyをコスト配分タグとして有効化する

先ほどEC2に設定したタグですが、このままではAWSの請求明細には表示されません。請求レポートに設定したタグを表示するには、以下の対応が必要です。またこの対応を行うAWSアカウントは「請求を司るアカウント」である必要があります。つまり一括請求における「マスターアカウント」で設定が必要です。

マネジメントコンソールのBillingのページにおいて、左端のナビゲーションペインで「Cost allocation tags」 を選択しますと、上図の画面に遷移します。東京リージョンの場合「URLリンクはこちら」です。「User-Defined Cost Allocation Tags」の一覧に表示されているタグKeyから、アクティブにしたいタグKeyを選択し、「Activate」ボタンでアクティブ化します。なお、はじめてリソースに付与したばかりのタグKeyはこの一覧に表示されるまで時間がかかる場合もありますので、時間をおいてから再度実行してください。

ここで重要なのは、「一覧に表示されているタグから、アクティブにしたいタグKeyを選択する」という箇所です。つまり、コスト配分タグは「既に付与されているタグのKey」から選択することになりますので、全く利用されていないタグKeyをここで設定することはできません。先に「何らかのAWSリソースにタグを一度付与してから」設定をして頂く必要があります。

なお、Active化されているタグKeyはこのように表示されます。また参考までに公式ドキュメントのURLリンクを掲載します。

使用状況とコストのモニタリング » コスト配分タグの使用 » ユーザー定義のコスト配分タグ » ユーザー定義のコスト配分タグのアクティブ化
https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/activating-tags.html

なお、弊社 pieCe をご契約の場合は、特殊な場合を除きコスト配分タグのタグKeyは固定で以下が利用可能です

  1. Name
  2. Application
  3. Owner
  4. Category1
  5. Category2
  6. Category3

詳しくは、カスタマーポータルのヘルプページより「コスト配分タグの設定方法」をご確認ください。

ここでご理解いただきたいポイントは以下の通りです。

  1. 請求レポートにコスト配分タグを表示するには、マスターアカウントでタグKeyの有効化が必要である
  2. タグKeyの有効化では既存のタグKeyを選択するため、有効化したいタグKeyは予め付与しておく必要がある

コスト配分タグの種類

ここまでご説明してきましたのが、実は2種類あるコスト配分タグのうちの1つ「ユーザー定義のコスト配分タグ」と言われる機能です。コスト配分タグと言えば「ユーザー定義のコスト配分タグ」を指すことが大半だと思いますので、ここからも「コスト配分タグ=ユーザー定義のコスト配分タグ」という認識で記載を続けていきます。

念のためもう1つのコスト配分タグについてご説明しますと、「AWS 生成コスト配分タグ」という機能で、先ほどもご紹介しました設定画面より「Active」とすることが可能です。

ポイントです。

  1. コスト配分タグは2種類(AWS 生成コスト配分タグ / ユーザー定義のコスト配分タグ)存在する

タグ付与の対応可否

ここまで、AWSリソースにはタグの付与が可能であるという前提でお話をしてきました。しかし、実際にはAWSリソースにおいてはタグの付与が不可能なものもあります。どのサービスとリソースがタグの付与に対応をしているのか?というまとまった公式ドキュメントはありませんが、それに近い情報は以下で把握が可能です。

AWS Billing and Cost Management » ユーザーガイド » 使用状況とコストのモニタリング » コスト配分タグの使用 » ユーザー定義のコスト配分タグ
https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/custom-tags.html

上記URLリンク先に、以下の記述があります。

タグの実装は、AWS のサービスごとに異なります。これらの実装を個々に使用するか、タグエディターを使用してこのプロセスを簡素化することができます。タグをサポートするサービスの完全リストについては、「タグベースのグループでサポートされているリソース」およびリソースグループ タグ付け API リファレンスを参照してください。

この2つのURLリンク先を確認すれば、おおよそタグ付けが可能なリソースの把握が可能です。

具体的な確認方法ですが、まずは1つ目のURLリンクである、「タグベースのグループでサポートされているリソース」を確認します。この一覧には「サービス」だけではなく、各サービスの中の「リソース」まで言及し記載されているのが特徴です。この一覧にあるものは確実にタグの付与が可能です。ただし、この一覧にも抜けが現状存在します。例えば、Directory Serviceは掲載されていません。しかしDirectory Serviceへのタグの付与は「リソースグループ タグ付け API リファレンス」を見れば可能なことがわかります。しかし、「リソースグループ タグ付け API リファレンス」では「サービス」のみの記載となっており「リソース」が記載されていません。よって、各サービスのどのリソースが付与可能なのか、後者の資料だけでは判断できませんが、「タグベースのグループでサポートされているリソース」に未掲載のものがあった場合は、合わせて確認してみてください。
これらの資料に掲載されていないものにつきましては、実際に付与を試みてみるか、AWSサポートに確認が必要になります。

関連して記載しますと、マネジメントコンソールからタグの付与ができないものの、APIであれば付与可能なリソースもあります。先にあげたDirectory ServiceのDirectoryにはタグの付与が可能ですが、マネジメントコンソールからタグが付与できません。ちなみに、EC2のReserved Instanceも同様です。そのため、マネジメントコンソールからタグが付与できない=タグが付与できないと判断するのではなく、APIリファレンス等もあわせてご確認ください。

ここでご理解いただきたいポイントは以下の通りです。

  1. AWSリソースにはタグの付与が可能なものと不可能なものが存在する
  2. マネジメントコンソールからタグが付与できなくてもAPIであれば付与できるものがある

コスト配分タグの対応可否

先に「タグ付与の対応可否」について記載しましたが、「コスト配分タグの対応可否」という視点も必要です。理由ですが「タグが付与できるものの、コスト配分タグには対応していない」リソースが存在するためです。例えば「Tagging Your Amazon EC2 Resources」には以下の記載があります。

Elastic IP addresses that are tagged do not appear on your cost allocation report.

つまり、Elastic IPは「タグは付与できる」のですが「コスト配分タグ」には対応していないため「請求レポートには掲載されない」ということになります。このため「タグを付与したのに請求レポートに掲載されない」という場合は「コスト配分タグに対応しているかどうか」も確認が必要となります。なお、「コスト配分タグに対応しているかどうか」をまとめた公式ドキュメントは残念ながら存在せず、各サービスのドキュメントやAPIリファレンスを追う必要があるのが実情です。

ポイントです。

  1. AWSリソースにはタグの付与が可能だがコスト配分タグに対応していないリソースが存在する

タグ付与/コスト配分タグの対応可否 まとめ

先に記載しました2点をまとめて表にしますと以下の通りになります。

リソースにタグの付与が可能 リソースがコスト配分タグに対応 請求レポートへの反映
不可能 ×
可能 未対応 ×
可能 対応済

よくある質問

ここでは、コスト配分タグに関連した「よくある質問」について回答します。

質問1

Q. コスト配分タグを正しく設定したつもりですが、請求レポートに掲載されません

請求レポートに対応しているリソースにタグを付与しても、正しく請求レポートに掲載されない場合は以下の項目について確認をお願いします。

  • タグは大文字小文字を区別します。そのため、設定したタグKeyの大文字小文字が正しいかご確認ください。例えば「Name」タグKeyと「name」タグKeyは別のタグKeyとして判断されます。
  • 半角スペースがタグKeyの最後に含まれている場合、別のタグKeyとして判断されます。例えば「Name」タグKeyと「Name 」タグKeyは別のタグKeyとして判断されます。半角スペースがタグKeyに含まれていないかご確認ください。
  • 「ユーザー定義のコスト配分タグ」に「user:」というプレフィックスが付与されますが、これはAWSが請求レポートにおいて付与している表記です。タグKeyの設定においては「user:Name」ではなく「Name」をご利用ください。

質問2

Q. コスト配分タグを付与しましたが、請求明細が「タグが付与されていないもの」と「タグが付与されたもの」と2つに分離しています。何故ですか?

  • コスト配分タグは、タグを付与したタイミングから有効になります。そのため、利用月の途中から付与した場合は「タグが付与されていないもの」と「タグが付与されたもの」と2つに分離されることになります。また、月の途中に付与したとしても、月初に遡って利用料金にコスト配分タグが付与されることはありません。タグの付与を行った翌月からは「タグが付与された項目1つ」にまとまります。
  • 月の途中にタグを変更した場合、その月の請求明細は「変更前のタグが付与されたもの」と「変更後のタグが付与されたもの」とに分離されることになります。

質問3

「ユーザー定義のコスト配分タグ」の対応タグKeyに、新しいタグKeyを追加したいですがどのようにすればいいですか?

  • お客様がマスターアカウント管理されている場合は、マスターアカウントから設定の追加が可能です。「タグKeyをコスト配分タグとして有効化する」の章をご確認ください。
  • pieCe をご利用の場合は先に記載しました「6つタグKey」のみが対応しております。場合によっては追加が可能な場合もございますため、担当営業までご連絡ください。

質問4

リソースを管理する部署名が変更になり、多くのリソースのタグ値をまとめて修正する必要が出ました。タグをまとめて編集する方法はありますか?

  • タグエディタ」をご利用ください。タグエディタでは、リソースに付与されたタグの値をまとめて編集が可能です。タグエディタの実際の画面は以下の通りです。

マネジメントコンソールのリソースグループから、タグエディタを起動します。

変更したいリソースを表示し、全て選択した状態で「タグの編集」を実行すると、上図の通り「選択された全てのリソースのタグを一括編集する」画面が表示されます。こちらの画面より一括編集を実施ください。

質問5

タグの付与を強制するにはどのようにすればいいですか?

  • Cloud Automatorの「構成レビュー」を利用することでタグ付与を行っていない場合に通知を行う設定が可能です。例えば「全てのEC2インスタンスは指定されたキーのタグが付与されていること」や「全てのDBインスタンスは指定されたキーのタグが付与されていること」などの設定が簡単に行えます。詳細は「構成レビュー」のURLリンク先をご確認ください。
  • AWSで同設定を行う場合、AWS Configにて設定を行います。具体的には「マネージドルール」内の「required-tags」を利用します。Rulesからrequired-tagsを検索し、設定を行ってください。詳細な設定方法はこちらでは割愛致しますが、CloudWatch EventsとLambda、そして修正アクションを紐づけることで自動的にリソースの修正までを行うことも可能です。

AWS Config ルールを使用してコンプライアンス違反のリソースを修正する
https://aws.amazon.com/jp/about-aws/whats-new/2019/03/use-aws-config-to-remediate-noncompliant-resources/

まとめ

今回の記事ではコスト配分タグについて詳しく記載しました。また、よくある質問の回答も記載しておりますので、合わせてご参考ください。このようにコスト配分タグ1つとりましても、理解すべき前提条件が多く、活用には少々ハードルがある印象かもしれませんが「タグを制するものは請求を制する(佐竹談)」ということでAWSの請求状況を正しく把握されるためには是非ご理解頂きたい機能となっております。

最後に、今回の記事で記載しましたポイントを以下にまとめました。

  1. AWSのリソースには、ユーザ独自のタグを付与する機能がある
  2. タグはKeyとValueのセットで定義される
  3. 請求レポートにコスト配分タグを表示するには、マスターアカウントでタグKeyの有効化が必要である
  4. タグKeyの有効化では既存のタグKeyを選択するため、有効化したいタグKeyは予め付与しておく必要がある
  5. コスト配分タグは2種類(AWS 生成コスト配分タグ / ユーザー定義のコスト配分タグ)存在する
  6. AWSリソースにはタグの付与が可能なものと不可能なものが存在する
  7. マネジメントコンソールからタグが付与できなくてもAPIであれば付与できるものがある
  8. AWSリソースにはタグの付与が可能だがコスト配分タグに対応していないリソースが存在する
リソースにタグの付与が可能 リソースがコスト配分タグに対応 請求レポートへの反映
不可能 ×
可能 未対応 ×
可能 対応済

ここまでお読みいただきありがとうございました。
これから毎日暑い日々が続くようですが、体調にはお気をつけください。

SwitchRoleは円滑に

$
0
0

はじめに

技術課の森です。梅雨も開けて、ジメジメモードからアツアツモードになってきましたね。
そんなときに、作業効率を上げて仕事していきたいなと思ったところにいい、Extensionがあったのでご紹介します。
普段、複数のアカウントを使って作業することが多く、その度にSwitchRoleをするのがすごく面倒でした。
そんなときに出会ったのが、 AWS Extend Switch Rolesです。
Chrome用Firefox用があるので、お使いのブラウザ次第でご利用ください。

インストールと動作確認

まずはExtensionをインストールしてきます。
今回はChromeを利用しておりますので、Chrome版のExtensionをインストールと動作確認をします。

1.サイトへアクセス & Chromeに追加

最初にサイトへアクセスします。
アクセスしたら、右上の「Chromeに追加」ボタンをクリックします。

2.確認

確認画面が出ますので、「拡張機能を追加」をクリックします。

3.追加完了

追加が完了した画面が出ますので、「x」をクリックします。

4.アイコン確認

追加が終わるとChromeのツールバーに緑色の鍵マークが表示されますので、そこをクリックします。

5. Configuration

以下のような表示になるので、「Configuration」をクリックします。

6. 設定画面

設定画面が表示されます。「Configuration」枠内にSwitchRoleするための設定情報を記載します。
記載する内容としては、「Configuration」枠の右下にある「About ~/.aws/config file」をクリックしてください。
configファイルに書くフォーマットで記入すればOKのようです。
設定が終わったら、「Save」ボタンをクリックします。

7. 設定のサンプル

Extensionの追加画面にもサンプルが表示されています。
このような感じで設定を書いていきます。

8. 動作確認

設定が完了したので、AWSマネージメントコンソールにログインして、SwitchRoleします。
すると以下のように一覧が表示されるようになりました。
この図でピンク色になっている部分は既にSwitchRoleしたことのあるアカウントで、グレーになっているところが今回設定したアカウント。
これで、対象のアカウントをクリックすれば見事SwitchRoleできるということになります。

さいごに

これまで下の画面のように毎度入力しなければならないのがかなり時間の無駄でしたが、これを先に設定しておくことでかなり効率化できます。
作業効率が上がると他のことがいっぱいできるので本当にいいことですよね。
さぁ、次の仕事をしよっ。

SSH Session ManagerをAssumeRoleで利用する方法

$
0
0

技術一課の杉村です。2019年7月、AWS Systems Manager Session ManagerでSSH/SCPセッションを利用できる機能が発表されました。
Session Manager launches tunneling support for SSH and SCP

この機能を利用すれば「踏み台インスタンス対してSession ManagerでSSHセッションを確立し、Private Subnetにいる他のEC2インスタンスに対してポートフォワードでアクセスする」のような、より柔軟な使い方できるようになります。

もちろん、SSH対象のEC2インスタンスのセキュリティグループではSSH用のポートを許可する必要はありません。
EC2インスタンスから443ポートでSystems ManagerのAPIエンドポイントに対してHTTPS通信ができさえすればいいのです。

この機能を利用する方法については、多くの方が既にブログを書かれていますので、今回のブログではさらに一歩進んで「AssumeRoleを使ってSSH Session Managerを使ってみる」という検証をしてみます。

AssumeRoleでSSH Session Managerって??

多数のAWSアカウントを管理している企業では、IAM Userを中央の管理用AWSアカウントに集約し、各AWSアカウント(サブシステムや部署、グループ会社など)にはスイッチロール(AssumeRole)させて利用している、ということがよくあります。

今回のブログではその構成に合わせて、以下のような利用方法を考えてみます。

※以下便宜上、IAM Userを集約するAWSアカウントを「中央AWSアカウント」と呼び、スイッチ(AssumeRole)先のAWSアカウントを「システム用AWSアカウント」と呼びます

1. システム用AWSアカウント(EC2の存在するAWSアカウント)にIAM Roleを作成。対象EC2にStartSessionできる権限を付与
2. 中央AWSアカウントに利用者用IAM Userを作成。前述のIAM RoleをAssumeRoleできる権限を付与
3. 利用者は中央AWSアカウントに作成したIAM UserのCredentialを使ってSSHセッションを確立する

これにより、中央AWSアカウントにIAM Userを集約するという運用を崩すことなく、SSH Session Managerを利用することができます。
構成は下記の図のようになります。

なお、これから記載する手順では、EC2側の手順(SSM AgentのインストールやIAM Roleの付与)は完了している前提で記載します。※下記リンクのStep1 & Step2が該当
Getting Started with Session Manager

1. システム用AWSアカウント(EC2の存在するAWSアカウント)にIAM Roleを作成

IAM Roleを作成し、以下のポリシーをアタッチします。
※<System-AWS-Account-ID>と<EC2-Instance-ID>の部分は任意の値に書換え。アスタリスクが利用可能

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:StartSession"
            ],
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:<System-AWS-Account-ID>:instance/<EC2-Instance-ID>",
                "arn:aws:ssm:ap-northeast-1::document/AWS-StartSSHSession"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:TerminateSession"
            ],
            "Resource": [
                "arn:aws:ssm:*:*:session/${aws:username}-*"
            ]
        }
    ]
}

信頼関係ポリシーでは以下のように、IAM Userのいる中央AWSアカウントからAssumeRoleできるよう記述します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::<Central-AWS-Account-ID>:root",
        ]
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}

RoleのARNは後ほど使うため、メモします。

2. 中央AWSアカウントに利用者用IAM Userを作成

中央AWSアカウントに利用者用のIAM Userを作成します。
同IAM Userには、下記のようなポリシーをアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::<System-AWS-Account-ID>:role/<Role-Name>"
        }
    ]
}

つまり、IAM Userに与える権限は、RoleをAssumeする権限だけです。

3. クライアントPC側の設定

クライアントPCがWindowsマシンである前提です。

3-1. AWS CLIとSession Manager Pluginのインストール

下記の手順でAWS CLIをインストールします。既にインストール済の場合でもバージョンが1.16.12以降である必要がありますので、必要があればアップデートします。
Windows に AWS CLI をインストールする

その後、下記の手順でSession Manager Plugin for the AWS CLIをインストールします。
(オプション) AWS CLI 用の Session Manager Plugin をインストールする

3-2. IAMクレデンシャル情報の設定ファイル

IAM UserのCredential (AccessKeyとSecret AccessKey)を、ファイル”C:\Users\<ユーザ名>.aws\credential“に記述します。

[default]
aws_access_key_id = AKIA****************
aws_secret_access_key = <Secret AccessKey>

そしてファイル”C:\Users\<ユーザ名>.aws\config“に以下のように記載します。

[profile assumeRoleProfile]
region = ap-northeast-1
role_arn = arn:aws:iam::<System-AWS-Account-ID>:role/<Role-Name>
source_profile = default

※プロファイル名は任意です
これらの設定ファイルの記述により、AWS CLIのコマンド実行時にプロファイル”assumeRoleProfile”を指定することで、AssumeRoleで得た一時認証情報でAPIコールを実行することができるようになります。

3-3. SSHクライアントのインストールと設定ファイル準備

コマンドプロンプトでsshコマンドが利用できるよう、OpenSSHコマンドをインストールします。
(方法は当ブログではご紹介しませんが、ググるとたくさんでてきます)

その後、ファイル”C:\Users\<ユーザ名>.ssh\config“に以下を記述します。

# SSH over Session Manager
host i-* mi-*
    ProxyCommand C:\Program Files\Amazon\AWSCLI\bin\aws.exe --profile assumeRoleProfile ssm start-session --target %h --document-name AWS-StartSSHSession --parameters "portNumber=%p"

ポイントは、awsコマンドをフルパスで記述すること、また –profileにて先ほど~.aws\configファイルに設定したプロファイル名を記述することです。

これで準備が整いました。

4. SSHセッションの確立

以下のコマンドを実行し、ログインします。

ssh -i <Path-to-Secret-Key> <OS-User-Name>@<EC2-Instance-ID>

例: ssh -i C:\Users\hogehoge.ssh\secretKey.pem ec2-user@i-1234567890abcdefg

参考まで、SSHトンネリングを利用してポートフォワードをすることもできます。
クライアントPCから踏み台まではSSHトンネルを張り、踏み台から先のPrivate Subnetに存在するEC2インスタンスにSSHやRDPをすることが可能です。

ssh -i C:\Users\hogehoge\.ssh\secretKey.pem -L 13389:10.10.0.4:3389 -L 23389:10.10.0.15:3389 ec2-user@i-1234567890abcdefg

※上記コマンドでSSHすれば、localhost:13389で10.10.0.4に、localhost:23389で10.10.0.15にRDPできます。
 -Lを複数並べることで、複数のリモートホストに対するポートフォワードが設定できます。

AWS Backupつかってみた

$
0
0

最近、暑いですね。

こんな暑い日はAWS Backupをつかってみたいですよね。

というわけで、今回はAWS Backupをつかってみました。

AWS Backupとは?

その名の通りのサービスです。

スケジュールを設定してAWS上のリソースのBackupが取れます。

AWS Backup とは

↑のドキュメントを見ると2019/07/31時点で対応しているのは以下のサービスのようです。

  • EBS ボリューム
  • RDS データベース(Auroraを除く)
  • DynamoDB テーブル
  • EFS
  • Storage Gateway ボリューム

現時点でAMI取得やAurora/RedShiftスナップショット取得には対応してないので弊社製品のCloud Automatorをつかってください。また、EBSやRDSでもCloud Automatorならスナップショットに独自命名も使用できますし、スケジュール以外のトリガーも使用できます!!!!!ぜひお試しあれ!!!!!

つかってみた

つかってみました。

お試しでEBSボリューム・RDS・DynamoDBテーブルを1つずつ用意しました。

タグ

なぜタグをつけるかは後でわかります。

EBSとRDSにタグをつけます。今回は「Backup」をキーとし、「01」をつけました。NameタグはEBSに「AWS-Backup-Test」、RDSに「aws-backup-test」を付与しました。


DynamoDBにもRDSと同様のタグを付けました。

バックアッププラン作成

AWS Backupにてバックアッププランを作成します。

ここの設定でバックアップするリソースとスケジュールを設定します。

起動オプションは「新しいプランを立てる」を選択。バックアッププラン名を入力します。

バックアップルール名を入れます。このバックアップルールがスケジュールの設定となります。今回は毎日PM2:50(UTC)で設定しました。このブログを書いている1時間後の時刻です。画像はPM6:00(UTC)になってますが気にしないでください。「数時間以内に以内にバックアップを開始」はバックアップウィンドウが続く時間です。最小の1時間としました。つまりPM2:50(UTC)-PM3:50(UTC)がバックアップウィンドウとなります。

ライフサイクルは設定せず、バックアップボールトはデフォルトとしました。

「プランを作成」をポチっとするとプランの詳細画面へ移ります。「リソースを割り当てる」をさらにポチっとしてバックアップするリソースを設定していきます。

リソースはタグで割り当てることができます。今回は先ほどEBS・RDSへ付与したBackupタグを設定します。タグを指定した場合、対応しているサービスの中で指定のタグが付与されているすべてのリソースでバックアップが実行されるようです。DynamoDBはリソースID指定でバックアップを設定します。

「リソースを割り当てる」をポチっとすると割り当て完了です。

1時間後

バックアップが取得されているか確認します。

EBS

取れてました。タグは元のEBSボリュームのものが引き継がれ、プラスAWS Backupのタグが付与されています。

RDS

おや?ない?いえ、あります。画像のように「バックアップサービス」を選択すると…

ありました。画像にはないですが、こちらもタグは元のRDSインスタンスのものが引き継がれていました。

DynamoDB

こちらもあります。バックアップタイプはAWSとなっています。DynamoDBのバックアップはタグがつけられないためか、タグは引き継がれてないようです。

まとめ

いかがでしたでしょうか?

タグを指定して、対応サービスの中でそのタグのついた全てのリソースのバックアップが取れるのは個人的に気に入りました。

バックアップするサービスによっては通常の手動スナップショットとは別の扱いになってしまいます。弊社のCloud Automatorであれば手動スナップショットと同じ扱いなるので、そちらが良ければぜひCloud Automatorをお使いください。

Amazon EC2にリタイア通知!どうやって対応するの?

$
0
0

このブログではとてもお久しぶりです。
法人営業課の生井です。

最後に書いたブログはどれだったかなと調べてみました。
…もう3年前なんですね。時が経つのは早いです。

今日はAmazon EC2にリタイア通知が届いた時の対応手順を紹介しようとおもいます。

Amazon EC2 リタイア通知とは

Amazon EC2を利用していると時々リタイア通知がきます。

通知例

EC2 has detected degradation of the underlying hardware hosting your Amazon EC2 instance (instance-ID:XXX) associated with your AWS account (AWS Account ID: XXXX) in the ap-northeast-1 region. Due to this degradation your instance could already be unreachable. We will stop your instance after 2020-03-01 09:00 UTC.

You can find more information about maintenance events scheduled for your EC2 instances in the AWS Management Console (https://console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#Events)

リタイア通知とは、インスタンスをホストしている基盤のハードウェアで回復不可能な障害が検出されたときに通知されます。
予定されたリタイア日になると、インスタンスは AWS によって停止または削除されますので、対応は必須になります。
対応方法は対象インスタンスを停止・起動のみです。さすがクラウドですね。簡単です。
インスタンスを停止・起動です。再起動ではダメですよ★

手順のご紹介

1.まず自身のAWSアカウントに入り、「Amazon EC2」で検索

2. インスタンスを選択

3. 対象インスタンスIDを検索

↑こんな表示がされているのを確認しましょう。

4. アクションをクリック→インスタンスの状態→停止を選択

5. 停止する

6. 停止を見守ります
7. インスタンスの状態がstoppedになったのを確認

8. アクション→インスタンスの状態→開始を選択
9. 開始する

10. インスタンスの状態がrunningになっているのを確認

以上で、リタイア対応完了です。

AWSマスターの一歩

これでリタイア通知が来てももう怖いもの知らずですね。
作業時間はざっと10分程度です。
本番環境の場合は停止する時間をしっかりと検討してからやりましょう。

ちなみに弊社製品Cloud AutomatorでEC2の起動・停止を時間で予約することもできますので深夜に対応しなければいけないときはこちらを利用するのもいいですよ。
睡眠は大事ですから。

Amazon EC2さんお疲れさまでした。

Amazon AuroraのDB インスタンスクラス変更方法まとめ

$
0
0

CS課佐竹です。
最近暑いので、色が青いRDSでも弄って涼を取ろうと思い、RDSについて記載します。

はじめに

「Amazon Aurora の DB Instance classを変更したい」そう思った時、どのようなシナリオ・手順が考えられるでしょうか。ここでは一般的なModifyで実施する方法から、可能な限り停止時間を短くするような方法、そしてAurora本体のアップグレードにも対応するような方法と、合わせて5つの方法をご紹介したいと思います。

ところで、皆さんRDSのインスタンスタイプはDB インスタンスクラスと呼ばれていることはご存じでしょうか。EC2ではインスタンスタイプと言われているものが、RDSになるとDB インスタンスクラスになります。しかし、公式ページでも「インスタンスタイプ」と表記されていたりして、よくわかりません。よくわかりませんが、このブログでは一貫して「DB インスタンスクラス」と記載します。ただ、勢いでインスタンスタイプと書いてしまう場合もあるかもしれませんが、見逃してください。

Amazon AuroraのDB インスタンスクラス変更方法

最初に、説明の元ネタとなります構成図をご紹介します。以下の図のように、EC2とRDS(Aurora)が1台ずつで構築されている環境があるとします。EC2とAurora間にはコネクションが存在しています。

今回、この「r4.large」のAuroraを「r5.large」に変更したいとします。ではパターン別に見てみましょう。

1: Modifyパターン

最初にご紹介するのは、最も一般的な変更方法です。Amazon Auroraの機能である「Modify」コマンドを利用してDB インスタンスクラスを変更します。

Amazon Relational Database Service (RDS) » Aurora のユーザーガイド » Amazon Aurora DB クラスターの管理 » Amazon Aurora DB クラスターの変更
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.Modifying.html

ModifyのコマンドはマネジメントコンソールもしくはAPIで実行するのみです。Modifyコマンドを実行し、DB インスタンスクラスを変更するとAuroraはシャットダウンされ、DB インスタンスクラスが変更された後に起動します。図で表すと、以下のように「一時的にコネクションは切断」されます。

Modify が問題なく完了すると、Auroraは Available 状態に戻り再度利用可能となります。

この変更方法ですが、適用タイミングのオプションが2種類あり、タイミングを選択可能です。

  1. 「Apply during the next scheduled maintenance window」で次回のメンテナンスウィンドウで実行をする
  2. 「Apply immediately」で即時実行する

1を選択した場合、変更は即時適用されず、次回のメンテナンスウィンドウに持ち越されます。土日や夜間に変更(シャットダウンを伴う)を行いたい場合はこの方法を選択可能です。2を選択した場合は即時実行されるため、DB インスタンスクラスの変更時においては即時シャットダウンが実行されます。静止時間はインスタンスクラスやDBの状況に応じて変わるため一概に何分とは明言できませんが、5分から20分程度はかかるであろうというのが私の経験則です。実際に静止している時間を見積もられたい場合は、検証環境を複製頂き実際の作業にて静止時間を測定頂くのがより正確です。

本パターンのメリットデメリット、そしてシナリオを以下に記載します。

  • メリット
    • シングル構成のためシンプル
    • シングル構成のため低コスト
  • デメリット
  • この手法が向いているシナリオ
    • 検証環境 もしくは ある程度の静止点が許容可能な本番環境

2: Failoverパターン

次にご紹介するのは、ベストプラクティスと言えるであろうFailover(フェイルオーバー)パターンです。

まずはAmazon AuroraにReader(Read Replica)を追加します。

Amazon Relational Database Service (RDS) » Aurora のユーザーガイド » Amazon Aurora DB クラスターの管理 » DB クラスターに Aurora レプリカを追加する
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-replicas-adding.html

追加を行うRead Replicaは変更予定の「r5.large」で作成します。念のため記載しますと、AuroraのRead ReplicaはマスターであるWriterと別のDB インスタンスクラスでも問題ありません。
追加しましたら、AuroraでFailoverを手動で実行します。

Failover中は一時的にAuroraに接続ができなくなりますが、非常に短い時間で済みます。Failoverのダウンタイムについては「よくある質問」のページに記載があるため、こちらより引用します。

Q: フェイルオーバー中はどのようなことが起き、どのくらいの時間がかかりますか?
 
フェイルオーバーは Amazon Aurora によって自動的に処理されるため、アプリケーションは管理上の手動介入なく、可能な限り迅速にデータベースオペレーションを再開することができます。
 

  • 同一、または異なるアベイラビリティーゾーンに Amazon Aurora レプリカを作成している場合、障害が発生すると、Aurora は DB インスタンスの正規名レコード (CNAME) を反転させ、正常なレプリカを指定します。指定されたレプリカは新しいプライマリに昇格します。フェイルオーバーは開始から終了まで通常 30 秒以内に完了します。

Failover は、30秒以内に完了と記載がある通り非常に短時間で完了します。私が検証した限りでは15秒程度で完了していました。

Failover が完了しますと、先ほどとDB インスタンスクラスが入れ替わった状態になります。これでインスタンスクラスの変更は完了です。

あとは不要となったRead Replicaを削除することでコストを削減することも可能です。

先にこの手法がベストプラクティスと記載しましたが、以下もその理由の1つです。これもまた「よくある質問」からの引用ですがご紹介します。

機能 Amazon Aurora レプリカ MySQL レプリカ
レプリケーション数 最大 15 最大 5
レプリケーションタイプ 非同期的 (ミリ秒単位) 非同期的 (秒単位)
プライマリへのパフォーマンスの影響
レプリカのロケーション リージョン内 クロスリージョン
フェイルオーバーターゲットとして機能 はい (データ損失なし) はい (数分間データ損失の可能性)
自動フェイルオーバー はい いいえ
ユーザー定義のレプリケーション遅延サポート いいえ はい
プライマリに対する異なるデータまたはスキーマのサポート いいえ はい

「フェイルオーバーターゲットとして機能」に記載がありますが、AuroraのRead Replicaではデータ損失はありません。この点がAuroraのFailoverの素晴らしい点です。

本パターンのメリットデメリット、そしてシナリオを以下に記載します。

  • メリット
    • ダウンタイムが30秒以内である
    • Read Replicaが作成された時点でインスタンスの確保が完了しているため、キャパシティ不足による影響を受けない
  • デメリット
    • 一時的にRead Replicaを作成するため、コスト増となる
    • Modifyよりも手順としては手間がかかる(Read Replicaの作成、Failover、Read Replicaの削除という3ステップ)
  • この手法が向いているシナリオ
    • 30秒程度の静止点が許容される本番環境

3: Aurora複製パターン

少々特殊な事情がある場合に検討の余地があるAurora複製パターンのご紹介です。

今回は、Read Replicaの追加ではなく、新しいDB インスタンスとしてAuroraクラスターをもう1台作成します。作成元は前環境のSnapshot(バックアップ)を利用しますが、実際は「Restore to point in time」を利用し直前の状態で複製するのが最も良い手法です。なお同じEndpoint名は記載ができませんため、別のEndpointを利用する点に注意してください。また、Snapshotを利用して新しいAuroraを作成しはじめてからはデータベースに差分が発生してしまう点にも十分注意が必要です。可能なら、EC2 インスタンスは停止してしまうか、書き込みをやめて読み込みだけにするのが良いでしょう。

新しいAuroraの作成が完了したら、向き先を新しいAuroraのEndpointに切り替えます。手順としてはこれだけになります。

もし同じEndpoint名を引き継ぎたい場合は「前のAuroraクラスター」の名称を上図のように変更してから書き換えることが可能です。こうすることで元の環境を一時的に保持することができます。

もちろん、元の環境がいらなければ最初から消してしまい、空いたEndpoint名を引き継ぐという手も可能です。

この手法は通常通りDB インスタンスクラスを変更するという点だけを見れば、パターン2の「Failoverパターン」より劣ります。しかし「別のDBインスタンス」になっている点がメリットになる場合があります。例えば「Auroraのアップグレードを合わせて行いたい」場合です。他にもパラメータグループを変更したい場合なども有用です。

本パターンのメリットデメリット、そしてシナリオを以下に記載します。

  • メリット
    • 別のDBインスタンスとして構築するため、Auroraのアップグレードやパラメータグループの更新を合わせて行ってから切り替えができる
    • 以前のDBインスタンスを保持することが可能
  • デメリット
    • 複製したAuroraでは構築後からデータの差分が発生する問題を回避する必要がある
    • Endpoint名の引継ぎを行う場合は一度前の環境のEndpointを解放する必要がある
  • この手法が向いているシナリオ
    • データの差分を吸収可能な状態で、Auroraのアップグレード等を行ってから切り替えたい場合

4: Replicationパターン

基本的には、先に紹介しました「Aurora複製パターン」と同様です。ただし複製した後、複製元と複製先でレプリケーションを行います。

このレプリケーションの実装方法は以下の公式ドキュメントをご参考ください。

Aurora と MySQL との間、または Aurora と別の Aurora DB クラスターとの間のレプリケーション
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.MySQL.html

先の手法ではSnapshotから複製した後はひたすら差分が発生してしまうため、それを何らかの方法で回避する必要がありましたが、レプリケーションを行うことでこれを回避可能です。

上図ですが、切り替えを行うタイミングではレプリケーションを止めると同時にEC2からのアクセスも止めることになるでしょう。

あとは先ほどと同様に別のEndpoint名に接続します。

元の環境がいらなくなれば削除します。このパターンでは、運用が非常にシビアな本番環境にてダウンタイムをほぼ0で切り替えを行う場合に有効です。また、先ほどと同様にAuroraのアップグレードを挟み込むこともできるのがメリットになります。

本パターンのメリットデメリット、そしてシナリオを以下に記載します。

  • メリット
    • 別のDBインスタンスとして構築するため、Auroraのアップグレードやパラメータグループの更新を合わせて行ってから切り替えができる
    • 以前のDBインスタンスを保持することが可能
    • ダウンタイムがほぼ0で切り替えが可能
  • デメリット
    • Endpoint名を引き継がず(基本的には)切り替えを許容する必要がある
    • 手順が(非常に)複雑であり、また時間がかかる
  • この手法が向いているシナリオ
    • ダウンタイムが許容されない環境でDB インスタンスクラスを変更しながらAuroraのアップグレード等も行いたい場合

5: Cross-region Read Replicaパターン

最後は、使っている例を見たことがないのですが実現が可能と想像しているパターンです。先ほどまで記載しましたパターンの1~4は全て実際に行われたことがあるパターンとなっておりますがこちらのパターンは私の想像で記載しております。これは2016年6月にリリースされました「Cross-region Read Replica」を利用したパターンです。

まず、別のRegion(今回はシンガポールリージョン)にRead Replicaを作成します。

この時点で少しだけ何かおかしい気がしますが、このまま続けます。

そして Cross-region Read Replica の場合のみ、そのRead Replicaはマスターに昇格(Promote)ができます。そしてスタンドアロンのDBクラスターとなったのが上図です。これは以下のドキュメントにも記載があります。

AWS リージョン間での Amazon Aurora MySQL DB クラスターのレプリケート
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.CrossRegion.html#AuroraMySQL.Replication.CrossRegion.Promote

最後にEndpoint名を新しいEndpoint名に切り替えて完了です。

この手法はAuroraが持つ基本的な機能のみで「Auroraを複製しかつ特定のポイントでレプリケーションを停止しスタンドアロンに昇格できる」という点で優れています。ただし、Regionを超えてしまうという最大のデメリットがあり、こればかりはどうしようもありません。Inter-regionでもRead Replicaが昇格できるようになればこの手法もどこかで日の目を見ることがあるかもしれませんが、現状Cross-regionでしか実現できないため、このような形でのご紹介となりました。ちなみにですが、昇格をさせるとDB インスタンスは再起動されるとのことです。

  • メリット
    • Auroraの機能だけでスタンドアロンの複製環境を生み出せる
  • デメリット
    • Regionを跨ぐためにEndpoint名が変更される点を許容する必要がある
    • Regionを跨ぐためにRegion超えのネットワーク通信料が発生する
    • 別Regionの利用準備が必要となる
  • この手法が向いているシナリオ
    • 募集中

まとめ

今回はAmazon AuroraのDB インスタンスクラスを変更する手法をまとめてみました。各パターン名は以下の通りです。

  1. Modifyパターン
  2. Failoverパターン
  3. Aurora複製パターン
  4. Replicationパターン
  5. Cross-region Read Replicaパターン

現実的に採用されるのは、多くの場合 [1] か [2] だと考えておりますが、この2つをとってもよく理解して使い分けが必要だとご理解頂けたかと思います。また、独立した環境を先に用意してから切り替えるという [3] または [4] のパターンが望まれる場合もありますので、合わせて紹介しております。 [5] は「Cross-region Read Replicaなんて機能があったのか」とだけでも思って頂けたら嬉しいです。

それでは、暑い夏が続きますが皆さんくれぐれも体調には気を付けてください。

[初心者向け]SSM Automationをやってみる

$
0
0

AWSを触り始めて4ヵ月になったのですが、AWS Systems Manager(SSM)のAutomationについてよく聞くけど何ができるか分からない状態だったため、実際に触ってみました。
「承認者に確認後、EC2を起動する」という処理をAutomationを使って実施してみます。

AWS Systems Manager(SSM)とは

まずSSMがどういったサービスかざっくり押さえておきます。
AWSドキュメントからの引用です。

AWS Systems Manager は、Amazon EC2 インスタンス、オンプレミスサーバーと仮想マシン (VM) や他の特定の AWS リソースを設定および管理する機能のコレクションです。Systems Manager には、AWS リソース間で運用データを簡単に一元化し、タスクを自動化できる統一されたインターフェイスが含まれています。Systems Manager はインフラストラクチャで運用上の問題を検出して解決するための時間を短縮します。Systems Manager は、インフラストラクチャのパフォーマンスと設定についての詳細を提供し、リソースとアプリケーションの管理を簡素化することで大規模なインフラストラクチャの運用と管理を簡単にします。

できること

  • 繰り返しタスクの自動化
  • サーバの構成検証、監査
  • EC2やオンプレサーバの管理

などサーバを管理・運用する際に実施することはSSMで対応可能です。

機能

SSMには下記にあるように、メンテナンスウィンドウやパラメータストアといった多岐にわたる機能があります。
各機能の詳細はAWSドキュメントを参照ください。
本記事では、Automationという運用作業フロー(インスタンスへのパッチ適用など)を自動化できる機能を使ってみます。

やってみる

「承認者に確認後、EC2を起動する」という一連の処理をAutomationを使って、行いたいと思います。

1.EC2にロール付与

Automationを使って起動させるEC2を作成します。
作成したEC2には、AmazonSSMAutomationRoleのポリシーをアタッチしたロールを付与します。

2.Automationの設定と実行

SSMのページへ移動します。「オートメーション」を選択し、「オートメーションの実行」ボタンを押下します。

まず、ドキュメントを選択していきます。
今回実行したい「承認者に確認後、EC2を起動する」という処理を実行できるドキュメントがAWSから提供されているので、そちら(「AWS-StartEC2InstanceWithApproval」)を選択します。
今回はAWSが提供しているドキュメントを使用していますが、実施したいことに合わせてドキュメントを作成することも可能です。(Automationドキュメント)

「Amazonが所有」を選択します。

「AWS-StartEC2InstanceWithApproval」を選択して、「次へ」を押下します。

ドキュメントを実行するために必要なパラメータを設定していきます。
承認者のIAMユーザと承認依頼通知をするためのSNSトピックが入力必須ですので、ない場合は作成してください。
パラメータ入力後、画面下部にある「実行」ボタンを押下します。

3.実行結果

実行を開始すると下記画面になり、Automationで実行しているステップとそのステータスを確認できるようになります。
今回実行している「承認者に確認後、EC2を起動する」だと、ステップ1がapprove(承認処理)で、ステップ2がEC2インスタンスの起動となります。
下記画面は承認待ち状態のため、ステップ1の承認処理が待機中、ステップ2のEC2の起動は処理中となっています。

承認者宛に下記画面のようなメールが送信されますので、メール本文内のリンクを押下して承認または却下を選択します。

承認後、EC2起動まで完了しました!

おまけ

承認を却下した場合は実行ステータスが失敗になりました。同じ実行IDでの再実行はできなかったため、再度ドキュメントの選択から実行する必要があるようです。

さいごに

AWS定義のAutomationドキュメントは他にも「Windows AMI にパッチを適用する」など多くのドキュメントがあります。
是非使ってみてください。


AWS CLI のコマンド実行を補助する「aws-shell」の紹介

$
0
0

技術2課の多田です.

AWS CLI 使っていて予測変換機能やパラメータをドキュメントを都度確認せずとも実行できたら楽だなと思っていたのですが, AWS Labsを漁っていたところ「aws-shell」というツールを見つけましたので今回の記事ではこのツールについて紹介します.なお,このツールは現時点で開発者プレビューのツールとなりますのでその点は注意ください.

The aws-shell is currently in developer preview. We welcome feedback, feature requests, and bug reports. There may be backwards incompatible changes made in order to respond to customer feedback as we continue to iterate on the aws-shell.

aws-shell の概要

aws-shell」は,AWS CLI のコマンド入力をインタラクティブに支援してくれるツールです.

awslabs/aws-shell

普段は,コマンドを入力するときはドキュメントを確認しつつ入力しています.ただこのツールは画像のように「どんなコマンドがあるか」「どんなパラメータがあるか」をターミナルに表示しながらナビゲート(インタラクティブ)してくれるところが特徴的です.

また,過去の実行したコマンドをナビしてくれたり,パラメータを提案してくれたりもします.便利な機能ですよね.

ツールの導入方法

導入方法は簡単でpip install aws-shellのみで導入できてしまいます.なお,実行環境の Python には以下の制約があるため注意が必要です.また,当然 AWS CLIは導入しておくのはお忘れなく.

The aws-shell works on the same python versions supported by the AWS CLI:
2.6.5 and greater
2.7.x and greater
3.3.x and greater
3.4.x and greater

AWS CLI の導入のドキュメント

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html

ツール導入後はaws-shellと打てば起動完了です.

$ aws-shell
aws>

 aws-shell 利用方法

aws-shell」を導入したら実際に使ってみましょう.AWS CLI との違いはawsコマンドを入力が不要という点です.例えば,S3 関連コマンドを実行したい場合はいきなりs3 lsといった形で実行可能です.あとはツールが補完してくれるコマンドやオプションに沿ってコマンドを入力すればよいのですが,その他のツールの利用方法を以下でまとめます.

 profile の切り替え

AWS CLIではコマンド実行時にアカウントや権限を分けたい場合は--profile オプションをつけて実行しますが「aws-shell」では以下のコマンドを使うことで切り替え可能です.

※profile の切り替えは2パターンある
【パターン1】
$ aws-shell --profile <profile名>

【パターン2】
aws> .profile <profile名>

※現状の profile の確認コマンド
aws> .profile
Current shell profile: admin

Liunx コマンドの利用

Linux コマンドを一緒に使いたい場合や Linux コマンド単体で実行したい場合があると思います.基本的には!catのように「!」をコマンドの前につけます.一部のコマンドは.cd(ディレクトリ移動コマンド),.exit/.quit(「aws-shell」終了のコマンド),.edit(エディタ起動コマンド)は定義されたコマンドもあります.なお,パイプやリダイレクト時は「!」は不要のようです.

aws> !ls /tmp/
foo.txt bar.txt
aws> dynamodb list-tables --output text | head -n 1
TABLENAMES First
aws> dynamodb list-tables --output text > /tmp/foo.txt

コマンド履歴の確認

過去に実行したコマンドを確認したい場合は,~/.aws/shell/historyファイルに格納されています.

aws> !cat ~/.aws/shell/history
# 2019-08-09 17:58:50.770101
+ec2 describe-regions

# 2019-08-09 17:59:00.594925
+s3 ls

aws-shell を終了する

aws-shell」を終了したい場合は.exitまたはF10,CTRL-Dを実行します.

aws> .exit
$

その他のツールオプション

aws-shell」にはツールオプションが用意されていて,現状以下の利用が可能です.

F2 toggles between fuzzy and substring matching
F3 toggles between VI and Emacs key bindings
F4 toggles between single and multi column auto completions
F5 shows and hides the help documentation pane
F9 toggles focus between the cli and documentation pane
F10 or Ctrl-D exits the aws-shell

まとめ

AWS CLI 補助ツールの「aws-shell」の概要,導入方法とツールの利用例を紹介しました.AWS CLI を使うときにドキュメントを都度確認したりすることに煩雑さを感じる方は本ツールを使ってみてはいかがでしょうか? 普段使いでも使っていって改善点などあればフィードバックを行なってよりよくしていくようリクエスト出していきたいと思います.

GuardDuty のマルチアカウント運用で使うべきアカウント管理機能

$
0
0

技術2課の多田です.

Amazon GuardDuty(以下, GuardDuty)をマルチアカウントで有効化している場合, 各アカウントの GuardDuty のイベントを管理・運用のためにアカウント管理機能を試す機会があったので今回はその内容をまとめていきます.

GuardDuty のサービス概要

そもそも GuardDuty とは機械学習を用いたフルマネージドのセキュリティ脅威検知のためのサービスです.様々な機能がありますが,資料の37ページ以降で今回の機能が紹介されています.

アカウント管理機能の概要

本機能は GuardDuty を有効化しているアカウントのイベントを統合管理するための機能です.マスターアカウントという管理アカウントと,被管理アカウントのメンバーアカウントで構成されます.

Amazon GuardDuty の AWS アカウントの管理

本機能のメリット

本機能のメリットは, 各メンバーアカウントのイベントをマスターアカウントで一元管理可能です.なお,メンバーアカウント上ではメンバーアカウントのイベントのみ表示されます.マスターアカウントの管理イメージとしては下の画像のような表示がされます.

マスターアカウントのイベント管理

また,各メンバーアカウントで発生したセキュリティ脅威イベントをマスターアカウントの CloudWatch Events に統合して通知も可能なため Lambda などと組み合わせてアカウントごとに検知イベントを管理するのも個々でイベント管理するより管理負担が少ないです.

Amazon CloudWatch Events を使用した Amazon GuardDuty 結果のモニタリング

 

設定方法

GUI での設定方法

マルチアカウントでの GuardDuty の管理にメリットしかない本機能ですが,設定もマネジメントコンソール間で2ステップで簡単に設定可能です.

1. マスターアカウントでメンバーアカウントに対して関連付けの有効化を行うための招待を送る
2. メンバーアカウントでマスターアカウントからの招待を承認する.

複数のアカウントで同時に GuardDuty を有効にする

AWS 提供されているソリューションでの設定方法

ただ,多数のメンバーアカウントの設定がある場合は以下の2つの方法があります.

1.Python スクリプトによる有効化

スクリプトの詳細は下記リンク先にあります.
aws-samples/amazon-guardduty-multiaccount-scripts

2.CloudFormation の StackSets 機能を使って有効化

StackSets 機能を使うためにはあらかじめ準備が必要ですが,CloudFormation テンプレートを用意する必要なく標準機能として提供されているため, Python に慣れていない方はこちらの選択肢を使うのがオススメです.ただ,StackSets 機能がないリージョンでは個別の設定が必要な点は注意です.2019年8月30日時点ではストックホルムリージョンの GuardDuty は StackSets による有効化ができないため個別に マスターアカウント機能をする必要があります.

 まとめ

GuardDuty のアカウント管理機能の概要と設定方法および運用上の注意点をまとめました.マスターアカウントでの操作が中心になる動作仕様を理解できていれば,メリットが多い機能なのでマルチアカウントでの運用を行う場合は有効化するのがオススメです.

ケース別 VPC ピアリングの実装の考慮点

$
0
0

技術2課の多田です.

複数のサブシステムを設計,実装する時に VPC ピアリングを使って相互にネットワーク疎通可能にすることがあると思います.VPC ピアリングを使ったネットワーク設計に関わってきました.VPC ピアリングは VPC 間の連携には欠かせない機能ですが,他の AWS サービスと組み合わせる時に注意すべきことがあると感じたので紹介したいと思います.

参考情報

VPC ピアリングの基本
VPC ピア機能とは

サポートされてない VPC ピア接続設定
サポートされていない VPC ピア接続設定

FAQ
Amazon VPC のよくある質問

20190313 AWS Black Belt Online Seminar Amazon VPC Basic

他の AWS サービスと組み合わせる時の注意点

今回は,業務で遭遇した VPC ピアリングを他の AWS サービスと組み合わせて使うときに感じた注意点をケース別に3点まとめます.

Case1. EFS をピアリング越しでマウントする場合

EFS を VPC ピアリング経由でマウントしたい要件があった場合,EFS のエンドポイントを DNS 名前解決ができなくなります.対策として Route53 のプライベートホストゾーンとリソースレコードセットを使って EFS マウントターゲット IPアドレスを定義する必要があります.

プライベートホストゾーンとして、「fs-xxxx.efs.ap-northeast-1.amazonaws.com」を定義し、A レコードとして EFS の IPアドレスを定義するような形です.

別の VPC で EFS マウントポイントに DNS 名前解決を使用することはできません。EFS ファイルシステムをマウントするには、対応する可用性ゾーンのマウントポイントの IP アドレスを使用します。また、DNS サービスとして Amazon Route 53 を使用できます。Route 53 で、プライベートホストゾーンとリソースレコードセットを作成して、別の VPC から EFS マウントターゲット IP アドレスを解決できます。

参考情報

別のアカウントまたは VPC から EFS ファイルシステムをマウントする

Case2. Route 53 プライベートホストゾーンを 別アカウントのVPC ピアリング経由で利用する場合

Route 53 のプライベートホストゾーンを 別アカウントのVPC ピアリング経由で利用したい場合の設定は AWS マネジメントコンソールから直接行えません.というのもプライベートホストゾーンと関連づける VPC は同一アカウント内であれば Route 53 の管理コンソール上より参照可能なのですが別アカウントの VPC は参照できないため AWS CLIなどで設定が必要になります.

参考情報

プライベートホストゾーンの使用

作成済みの Amazon VPC と、別の AWS アカウントで作成したプライベートホストゾーンを関連付ける

この記事では AWS CLI の設定例を書きます.設定作業は2ステップで完了します.

1. Route 53 プライベートホストゾーンが存在するアカウントで create-vpc-association-authorization を実行する

まず,別アカウントの VPC をプライベートホストゾーンに関連付けるためのリクエストを送信することを送信する許可を プライベートホストゾーンが存在するアカウントの権限でcreate-vpc-association-authorization実行します.

$ aws route53 create-vpc-association-authorization \
--hosted-zone-id <プライベートホストゾーンの ID> \
--vpc <別アカウントの VPC ID>

 

2. 別アカウントの VPC ピアリングが存在するアカウントで  associate-vpc-with-hosted-zone を実行する

次に別アカウントの権限で associate-vpc-with-hosted-zoneを実行します.

$ aws route53 associate-vpc-with-hosted-zone \
--hosted-zone-id <プライベートホストゾーンの ID> \
--vpc <別アカウントの VPC ID>

Case3. VPC ピアリング越しのエンドポイントを DNS 名前解決したい

RDS のエンドポイントなど AWS のマネージドサービスは DNS 名前解決を行なってアクセスする必要があります.その際は, VPC ピアリングのオプションで DNS 名前解決を有効化して対応します.

オプションを有効化したい VPC ピアリングを選択してチェックボックスを有効化して保存すれば DNS 名前解決オプションを有効化できます.簡単ですね!

参考情報

VPC ピアリング接続のオプションの変更

まとめ

業務で直面した VPC ピアリングの他の AWS サービスと組み合わせる時に注意すべきと感じたポイントを3点まとめました.

VPC ピアリングは大規模システムになればなるほど利用機会が増えるサービスのため,気に掛けるポイントは把握しておく必要があります.この記事で紹介しきれてない考慮点があればまたこの記事を更新かけていきたいと思います.

「AWS Cloud Development Kit」に対応した Python コードを実践!

$
0
0

技術2課の多田です.

以前,「AWS Cloud Development Kit」(以下、CDK)の記事を書きました.当時は対応言語に Python がサポートされてませんでしたが, Amazon Web Services ブログで Python 対応アナウンスがありましたので,早速, Python で CDK を使ってみます。

Amazon Web Services ブログ記事

AWS クラウド開発キット (CDK) – TypeScript と Python 用がご利用可能に

関連記事

オンラインワークショップでAWS CDK を体験する

チュートリアルプロジェクトの実行

初期設定

下記のチュートリアルに沿って CDK を実行します. プロジェクトを初期化し、pip install -r requirements.txtでライブラリをインストールします.

Hello World Tutorial

$ mkdir hello-cdk && cd hello-cdk
$ cdk init --language python sample-app
Applying project template sample-app for python
Initializing a new git repository...
Executing Creating virtualenv...

# Welcome to your CDK Python project!

You should explore the contents of this template. It demonstrates a CDK app with two instances of
a stack (`HelloStack`) which also uses a user-defined construct (`HelloConstruct`).

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

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

To manually create a virtualenv on MacOS and Linux:

$ python3 -m venv .env

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

$ source .env/bin/activate

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

% .env\Scripts\activate.bat

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

$ pip install -r requirements.txt

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

$ cdk synth

You can now begin exploring the source code, contained in the hello directory.
There is also a very trivial test included that can be run like this:

$ pytest

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

# Useful commands

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

Enjoy!
$ python3 -m venv .env
$ source .env/bin/activate
(.env) $ pip install -r requirements.txt
Obtaining file:///Users/tada/work/cdk_python_sample (from -r requirements.txt (line 1))
Collecting pytest (from -r requirements.txt (line 2))
〜中略〜
uccessfully installed atomicwrites-1.3.0 attrs-19.1.0 aws-cdk.assets-0.31.0 aws-cdk.aws-autoscaling-api-0.31.0 aws-cdk.aws-cloudwatch-0.31.0 aws-cdk.aws-ec2-0.31.0 aws-cdk.aws-events-0.31.0 aws-cdk.aws-iam-0.31.0 aws-cdk.aws-kms-0.31.0 aws-cdk.aws-lambda-0.31.0 aws-cdk.aws-logs-0.31.0 aws-cdk.aws-s3-0.31.0 aws-cdk.aws-s3-notifications-0.31.0 aws-cdk.aws-sns-0.31.0 aws-cdk.aws-sqs-0.31.0 aws-cdk.aws-stepfunctions-0.31.0 aws-cdk.cdk-0.31.0 aws-cdk.cx-api-0.31.0 aws-cdk.region-info-0.31.0 cattrs-0.9.0 hello jsii-0.10.5 more-itertools-7.0.0 mypy-extensions-0.4.1 pluggy-0.11.0 publication-0.0.3 py-1.8.0 pytest-4.4.2 python-dateutil-2.8.0 six-1.12.0 typing-extensions-3.7.2
You are using pip version 19.0.3, however version 19.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

因みにプロジェクトを作ると以下のようなディレクトリ構造が作成されます.Python のコードで構成されているのがわかります.

$ tree
├── README.md
├── app.py
├── cdk.json
├── hello_cdk
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ └── hello_cdk_stack.cpython-37.pyc
│ ├── hello_cdk.egg-info
│ │ ├── PKG-INFO
│ │ ├── SOURCES.txt
│ │ ├── dependency_links.txt
│ │ ├── requires.txt
│ │ └── top_level.txt
│ └── hello_cdk_stack.py
├── requirements.txt
└── setup.py

デプロイ

次にデプロイをしていきます。まずcdk synthで CloudFormation テンプレートを合成し,次にcdk deployでデプロイをします.

$ cdk synth
Resources:
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Modules: aws-cdk=0.30.0,@aws-cdk/cdk=0.31.0,@aws-cdk/cx-api=0.31.0,jsii-runtime=Python/3.7.3

$ cdk deploy
HelloCdkStack: deploying...
HelloCdkStack: creating CloudFormation changeset...
0/2 | 09:18:25 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata
0/2 | 09:18:28 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated
1/2 | 09:18:29 | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata
2/2 | 09:18:31 | CREATE_COMPLETE | AWS::CloudFormation::Stack | HelloCdkStack

✅ HelloCdkStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxx:stack/HelloCdkStack/6ef54dd0-744b-11e9-aada-0e842c318628

CloudFormationのスタックが完成していました.バージョニングと暗号化したS3バケットを作るのみですがサクッと作れました.

後片付け

作成したリソースの削除はcdk destroyで完結します.

cdk destroy
Are you sure you want to delete: HelloCdkStack (y/n)? y
HelloCdkStack: destroying...
0 | 01:27:57 | DELETE_IN_PROGRESS | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
0 | 01:27:59 | DELETE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata
0 | 01:27:59 | DELETE_SKIPPED | AWS::S3::Bucket | HelloCdkBucket (HelloCdkBucketA63BB9B1)

✅ HelloCdkStack: destroyed

 

Pulumi との利用比較

CDK」と似たようなツールとして「Pulumi」があります.「Pulumi」も JavaScript,Golang,TypeScriptの他に Python に対応したプログラミング言語でのプロビジョニングツールです.最後に2つのツールを使い分けていくにあたって利用比較を自分なりに調べてみたものをまとめます。

関連記事

Infrastructure as Codeのホープ、Pulumiを試す

Pulumi と CDK の比較

  • Pulumi」のプロビジョニングはマルチクラウド対応しているが, 「CDK」のプロビジョニングは AWS対応のみ
  • Pulumi」は利用形態に応じて利用料がかかるが, 「CDK」は利用料不要で利用可能
  • Pulumi」には独自 GUI 管理の画面があるが, 「CDK」は管理画面はなくターミナルでの操作中心

自分はAWS を普段使うため引き続き「CDK」でのプロビジョニングの勉強をしていきます.

まとめ

CDK」の Python 対応したコードを試してみました.Python のコードの情報が出てきているのでこれは Python で AWS を利用している人にとっては朗報かと思います.僕もしっかり使いこなして Python でアプリケーションの開発,デプロイまで完結できるようにドキュメントを読み込んだり,実践していきたいです!

CDK の関連情報

公式ドキュメント(Get Started)

Getting Started With the AWS CDK

リファレンスドキュメント

AWS CDK Reference Documentation

Python のサンプルコード

aws-samples/aws-cdk-examples

AWS CDK CLI のバージョンアップを行う方法

$
0
0

技術2課の多田です.

AWS CDK が一般利用可能となり, バージョンv1.6.1がリリースされました(2019/08/31時点).

https://github.com/aws/aws-cdk/releases/tag/v1.6.1

 AWS CDK CLI のバージョンアップ方法

ローカルの「AWS CDK CLI」のバージョンが1.0.0になっていたのですが,今回はバージョンアップの対応方法をまとめます.

バージョンアップ前の情報

$ cdk --version
1.0.0 (build d89592e)

npm-check-updates を使ってバージョンアップ方法を確認する

AWS CDK CLI」はnpmを使ってインストールしました.そのため npm パッケージの更新方法を確認していたところnpm-check-updatesを使うのが良さそうだと思い使ってみました.

npm-check-update

npm-check-updatesの導入は以下の通りです.

$ npm i -g npm-check-updates
/usr/local/bin/ncu -> /usr/local/lib/node_modules/npm-check-updates/bin/ncu
/usr/local/bin/npm-check-updates -> /usr/local/lib/node_modules/npm-check-updates/bin/npm-check-updates
+ npm-check-updates@3.1.9
added 154 packages from 80 contributors in 10.035s

npm-check-updatesncuコマンドを使ってパッケージのアップデート確認が可能です.実行してみるとnpm -g install aws-cdk@1.6.1 でバージョンアップ可能なことが確認できます.

$ ncu -g aws-cdk
[====================] 1/1 100%

aws-cdk 1.0.0 → 1.6.1

ncu itself cannot upgrade global packages. Run the following to upgrade all global packages:

npm -g install aws-cdk@1.6.1

ncuコマンドで確認したようにコマンドを実行しアップデートをかけてみます.バージョンが1.6.1になったことを確認できました.

$ npm -g install aws-cdk@1.6.1
npm -g install aws-cdk@1.6.1
/usr/local/bin/cdk -> /usr/local/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.6.1
added 4 packages from 1 contributor, removed 34 packages and updated 34 packages in 58.072s
$ cdk --version
1.6.1 (build a09203a)

これで楽しい「AWS CDK CLI」ライフ実現に一歩近づきました.

まとめ

初めて「AWS CDK CLI」のバージョンアップ対応を行なったのでその方法をまとめました.npm-check-updates 使うとアップデート方法がすぐわかって簡単に対応できました.今後アップデート予定の方の何か参考になれば幸いです!

関連記事

GuardDuty のマルチアカウント管理機能有効化を省力化する

$
0
0

技術2課の多田です.

GuardDuty のマルチアカウント管理機能を紹介した記事を書きました.マルチアカウントで GuardDuty を運用するなら有効化すべき機能ですが,多数のアカウントを AWS マネジメントコンソールの操作で有効化するのは煩雑なため, CloudFormation と AWS CLI を使って省力化してみます.

省力化可能な部分の検討

今回,省力化できる箇所は以下のものと考えました.

1. メンバーアカウントに対してマスターアカウントからアカウント管理機能の招待を送る処理
2. メンバーアカウントでマスターアカウントからの招待を受ける処理
3. GuardDuty の DetectorID を取得する処理

それぞれの処理ごとで省力化した箇所とコード例を記載していきます.

1. メンバーアカウントに対してマスターアカウントからアカウント管理機能の招待を送る処理

マスターアカウントがメンバーアカウントのイベントを管理するためには, メンバーアカウントへマスターアカウントに統合するための招待を送る必要があります.なお, AWS では利用可能なリージョン全てで GuardDuty を有効化することが推奨されておりますので本記事では,マスターアカウントの全リージョンからメンバーアカウントに招待通知を出す処理を CloudFormation で省力化するコードを紹介します.

GuardDuty は、サポートされているすべての AWS リージョンで有効にすることが強く推奨されています。このように設定することで、お客様が能動的に使用していないリージョンでも、許可されていないアクティビティや異常なアクティビティに関する検索結果を GuardDuty で生成できます。

関連ドキュメント

Amazon GuardDuty でサポートされているリージョン

CloudFormation テンプレート例

CloudFormation の StackSets 機能を使ってマスターアカウントの全リージョンに対して下記のテンプレートを実行することで指定のメンバーアカウントに対して招待通知を出せます.AWS::GuardDuty::MemberStatus: "Invited"で設定するとメンバーアカウントに招待通知を出す処理まで一気に設定可能ですので,この設定は定義しておくと良いでしょう.

AWSTemplateFormatVersion: 2010-09-09
Description: Creates an AWS::GuardDuty::Detector resource and optionally an AWS::GuardDuty::Master resource in a set of accounts and regions.

Mappings:
GuardDutyMembers:
us-east-1: 
DetectorId: xxxx
us-east-2:
DetectorId: xxxx
us-west-1:
DetectorId: xxxx
us-west-2:
DetectorId: xxxx
ca-central-1:
DetectorId: xxxx
eu-central-1:
DetectorId: xxxx
eu-west-1:
DetectorId: xxxx
eu-west-2:
DetectorId: xxxx
eu-west-3:
DetectorId: xxxx
ap-northeast-1:
DetectorId: xxxx
ap-northeast-2:
DetectorId: xxxx
ap-southeast-1: 
DetectorId: xxxx
ap-southeast-2: 
DetectorId: xxxx
ap-south-1:
DetectorId: xxxx
sa-east-1:
DetectorId: xxxx

Parameters:
MemberAccountId:
Description: Type Member Account Number.
Type: String
MemberAccountEmail:
Description: Type Member Account Email.
Type: String


Resources:
Member:
Type: AWS::GuardDuty::Member
Properties: 
Status: "Invited" 
MemberId: !Ref MemberAccountId
Email: !Ref MemberAccountEmail
DetectorId: !FindInMap [GuardDutyMembers,!Ref "AWS::Region", DetectorId]
DisableEmailNotification: True

なお,CloudFormation の StackSets 機能が使えないリージョンでは手動でメンバーアカウントの招待を行う必要があります.多数のアカウントに対して招待を出す場合,CSVファイルに次のようにメンバーアカウントの AWS アカウント番号とメールアドレスを記載したものを読み込ませるとスムーズです。

Account ID,Email
111111111111,user@example.com

CloudFormation ドキュメント

AWS::GuardDuty::Member

2. メンバーアカウントでマスターアカウントからの招待を受ける処理

マスターアカウントからメンバーアカウントへアカウント統合の招待を出した後は,メンバーアカウントでその招待を承認しなければなりません.その承認処理を CloudFormation で省力化します.マスターアカウントからの招待通知同様に全リージョンで承認処理を行うためのテンプレート例を紹介します.

CloudFormation テンプレート例

このテンプレートもメンバーアカウントで StackSets 機能を使って全リージョンの招待通知を一度に承認する処理を省力化しています.

AWSTemplateFormatVersion: 2010-09-09
Description: Approve Invitation From GuardDuty Master Account.

Mappings:
GuardDutyMasters:
us-east-1: 
DetectorId: xxxx
us-east-2:
DetectorId: xxxx
us-west-1:
DetectorId: xxxx
us-west-2:
DetectorId: xxxx
ca-central-1:
DetectorId: xxxx
eu-central-1:
DetectorId: xxxx
eu-west-1:
DetectorId: xxxx
eu-west-2:
DetectorId: xxxx
eu-west-3:
DetectorId: xxxx
ap-northeast-1:
DetectorId: xxxx
ap-northeast-2:
DetectorId: xxxx
ap-southeast-1: 
DetectorId: xxxx
ap-southeast-2: 
DetectorId: xxxx
ap-south-1:
DetectorId: xxxx
sa-east-1:
DetectorId: xxxx

Parameters:
MasterAccountNumber:
Type: String

Resources:
Master:
Type: AWS::GuardDuty::Master
Properties:
DetectorId: !FindInMap [GuardDutyMasters,!Ref "AWS::Region", DetectorId]
MasterId: !Ref MasterAccountNumber

 

CloudFormation ドキュメント

AWS::GuardDuty::Master

3. GuardDuty の DetectorID を取得する処理

最後に, 1,2 のCloudFormation テンプレートの定義で必ず必要な GuardDuty の DetectorID 取得を AWS CLI で全リージョン分取得する処理を紹介します.マスターアカウントでもメンバーアカウントでも必ず必要なため同様の処理を検討している方の参考になれば嬉しいです.

AWS CLI コード例

以下の2行で取得可能です.最初にリージョンのエンドポイントをソートして取得し,次に GuardDuty の DetectorID をリージョンごとに取得しています.

# リージョン全取得して配列に格納(-r をつけるとダブルクオーテーションを削除可能)
declare -a REGIONS=( $(aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | sort) )

# GuardDutyのDetectorIDをリージョンごとに表示する
for i in ${REGIONS[@]}; do echo "$i = $( aws guardduty list-detectors --region $i | jq -r '.DetectorIds[]')";done

シェルスクリプト化してこんな感じに一気に取得することができます.

AWS CLI ドキュメント

describe-regions

list-detectors

まとめ

GuardDuty のマルチアカウント管理機能有効化を省力化するために行った CloudFormation と AWS CLI の意図とコードを紹介しました.他にもいろんな方法があるかと思いますが次はAWS CDKでも同様のことを実現できないかをトライしてみたいと思います.

CloudWatch Logs Insights で大量なログ分析も手軽に行う

$
0
0

技術2課の多田です。

運用フェーズになるとトラブルシュートや定常運用時にログを確認することがよくあると思います.僕もそんな時に最近は CloudWatch Logs Insights をを使うようにしています.CloudWatch Logs Insightsは CloudWatch Logs に保管されたログに対してクエリを発行してログを表示したり、クエリの結果をグラフに出すことも可能な機能です.

新機能 – Amazon CloudWatch Logs Insights – 高速でインタラクティブなログ分析

これまでは CloudWatch Logs の画面から検索することも可能でしたが,CloudWatch Logs Insights の登場によって検索で正規表現や条件をつけたりすることで検索しやすいです.今回は CloudWatch Logs Insights を使うにあたって必要なクエリの使い方と料金を整理します.

クエリについて

クエリのコマンド

クエリには1つ以上のクエリコマンドを Unix 形式のパイプ文字をで区切って定義可能で,使えるコマンドは以下の6種類です.

  • fields : 1つ以上のログフィールドを取得する
  • filter : ログフィールドを1つ以上の条件に基づいて絞り込む
  • stats : ログフィールドに対し集計計算(sum,avg,count,min,max,percentile)を行う
  • sort : 昇順,降順でログイベントをソートする
  • limit : クエリで返されるログイベントの数を制限する
  • parse : ログフィールドからデータを取り出す

参考情報

CloudWatch Logs Insights クエリ構文

サンプルクエリ

実際にどうやってクエリを定義していいか,をすぐにわからない人も安心してください.以下のようなサンプルクエリが用意されています.CloudTrail は利用されている方も多いかと思うので,まずはこちらから始めてみるのも良いかもしれません.

  • Lambda
  • VPC Flow Logs
  • Route53
  • AppSync
  • CloudTrail
  • 一般的なログ

参考情報

サンプルクエリ

利用料金

料金は,クエリごとに走査したログデータの量に対してかかるのですが,GB あたり $0.005 になります.ログ容量に応じた課金体系になっています.

まとめ

今回は, CloudWatch Logs Insights の基本であるクエリコマンドの種類とサンプルクエリ,利用料金をまとめました.今の所はログをソートしたり,filter で条件を絞ったりなどを使っていますが,もっと使いこなせてログ分析を得意になっていきたいです.


CloudWatch Logs のログをアカウントまたぎで共有する

$
0
0

技術2課の多田です.

CloudWatch Logs のログをアカウントまたぎで共有し,ログ分析に活用する要件がありました.そのための検証を行なったので,まとめていきます.

実現方法

実現するには,CloudWatch Logs のログを送信先アカウントで, Kinesis Data Streams の設定が必要です.仮に,アカウント A(111111111111)からアカウント B(999999999999)にログを連携する場合で考えます.

以下が手順です.

1. アカウント B で, Kinesis Data Streams の送信先ストリーム,データ入力を行うサービスロールの作成と送信先ストリームへの適用
2. アカウント A で,連携するログのサブスクリプションフィルターを作成
3. アカウント B で, Kinesis Data Streams のシャードにログが送信されているかを確認

参考情報

今回の手順は下記のドキュメントに記載があるため,手順に則って検証を行いました.

クロスアカウントのログデータをサブスクリプションと共有する

1.Kinesis Data Streams の送信先ストリーム,データ入力を行うサービスロールの作成と送信先ストリームへの適用

まず,ログの送信先のアカウントの設定を行いますが,AWS CLI を使って実施していきます.

最初に, Kinesis Data Streams に送信先ストリームを作ります.ストリームが有効化されるまで1,2分ほどかかります.

aws kinesis create-stream --stream-name "RecipientStream" --shard-count

続いて,サービスロールの作成を行います.なお,サービスロールと適用するポリシーの中身は以下の通りです.

# サービスロール
{
"Statement": {
"Effect": "Allow",
"Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" },
"Action": "sts:AssumeRole"
}
}

# ポリシー
{
"Statement": [
{
"Effect": "Allow",
"Action": "kinesis:PutRecord",
"Resource": "arn:aws:kinesis:ap-northeast-1:999999999999:stream/RecipientStream"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::999999999999:role/CWLtoKinesisRole"
}
]
}

サービスロールの作成と,ポリシーの適用は以下の通りです.

# サービスロールの作成
aws iam create-role \
--role-name CWLtoKinesisRole \
--assume-role-policy-document file://TrustPolicyForCWL.json

# サービスロールへのポリシーアタッチ
aws iam put-role-policy \
--role-name CWLtoKinesisRole \
--policy-name Permissions-Policy-For-CWL \
--policy-document file://PermissionsForCWL.json

# CloudWatch Logs の書き込み先の作成
aws logs put-destination --destination-name "testDestination" --target-arn "arn:aws:kinesis:ap-northeast-1:999999999999:stream/RecipientStream" --role-arn "arn:aws:iam::999999999999:role/CWLtoKinesisRole"
{
"destination": {
"roleArn": "arn:aws:iam::999999999999:role/CWLtoKinesisRole",
"creationTime": 1555918710180,
"destinationName": "testDestination",
"accessPolicy": "{\n \"Version\" : \"2012-10-17\",\n \"Statement\" : [\n {\n \"Sid\" : \"\",\n \"Effect\" : \"Allow\",\n \"Principal\" : {\n \"AWS\" : \"111111111111\"\n },\n \"Action\" : \"logs:PutSubscriptionFilter\",\n \"Resource\" : \"arn:aws:logs:ap-northeast-1:999999999999:destination:testDestination\"\n }\n ]\n}\n\n",
"targetArn": "arn:aws:kinesis:ap-northeast-1:999999999999:stream/RecipientStream",
"arn": "arn:aws:logs:ap-northeast-1:999999999999:destination:testDestination"
}
}

# CloudWatch Logs の書き込み先のポリシー作成
aws logs put-destination-policy \
--destination-name "testDestination" \
--access-policy file://AccessPolicy.json

 

2. アカウント A で,連携するログのサブスクリプションフィルターを作成

続いて,ログの送信元アカウントで Kinesis Data Streams にログを共有するためのサブスクリプションフィルターを作成します.今回は, CloudTrail のログに記録された「tada」に関するログを送る例を書きます.

aws logs put-subscription-filter \
--log-group-name "test-trail" \
--filter-name "RecipientStream" \
--filter-pattern "{$.userIdentity.type = tada}" \
--destination-arn "arn:aws:logs:ap-northeast-1:999999999999:destination:testDestination"

3. アカウント B で, Kinesis Data Streams のシャードにログが送信されているかを確認

最後に,Kinesis Data Streams のシャードにログが送信されているかを確認します.

# シャードのイテレーター情報を取得する
aws kinesis get-shard-iterator \
--stream-name RecipientStream \
--shard-id shardId-000000000000 \
--shard-iterator-type TRIM_HORIZON

# 出力例(ShardIterator の情報をメモしておきます)
{
"ShardIterator": "AAAAAAAAAAE8Lco6O3cLC0izP1f5u1D1UT01g5ojvj035Tb/XuvIMH+mnthnrGr6MDNi7fSAFVnJnrF2gtGWyn7Qi/dGf+5eOO0iriz8y3K3iBHaBMX9ESB3Zg2nnC2CGntkUyOCQZxRez5BSWmWqrhp1WtvQXvICCbhjIrtTPLRMpPcKyXPIqVa9X4n/f99l8IR9cSQ0+t7Ev1mzFclVD0Lat2EGcn+"
}

# シャードのデータ情報を取得する
aws kinesis get-records \
--limit 10 \
--shard-iterator "AAAAAAAAAAE8Lco6O3cLC0izP1f5u1D1UT01g5ojvj035Tb/XuvIMH+mnthnrGr6MDNi7fSAFVnJnrF2gtGWyn7Qi/dGf+5eOO0iriz8y3K3iBHaBMX9ESB3Zg2nnC2CGntkUyOCQZxRez5BSWmWqrhp1WtvQXvICCbhjIrtTPLRMpPcKyXPIqVa9X4n/f99l8IR9cSQ0+t7Ev1mzFclVD0Lat2EGcn+"

# 出力例(Data の情報をメモしておきます)
{
"Records": [
{
"Data": "H4sIAAAAAAAAADWOTQuCQBRF/8ow64jMPsBdiLXIEjJoERKTvvSRzsi8MYnwvzdqLQ/3cu/58AqIRA7ndw3c4350PJ+i8HYI4nizC/iEq1aC7pNSNVkrTFqEKicblCrfadXUNhspNhpENSI1d0o11gaV3GJpQBP3rsnQC14gTY8fjtlYN2g1jKjsmLNcrty1u5jNXceZ/PV6gUvIfnrsp+cxv4D0iTJnBYjSFEw9WGaXUIr+me1RAiExGtSmvEu6Lwa4ORDyAAAA",
"PartitionKey": "3e21f5e8240cbb048271af4fdb892a1c",
"ApproximateArrivalTimestamp": 1556373403.028,
"SequenceNumber": "49595189074146188426156213207759355357749573689819529218"
}
],
"NextShardIterator": "AAAAAAAAAAGBjdvkN0Th99yo7tnUiLUxwXX7dgG4TinEGCRQrpVR7Y+2euYlNhuDA7KvfYOwC9LdS+ZNj8sSA5boHkLhWsdsLNuo/+Cn2qtzBeJkE1JtcYlhCr7qZowctmxtNHU3qfPSTF/ywSqEjstCEaPoxs083K+AKrj+OvHHNC6fqxkKjeoi51GodxIhnkyRWL3E12ib6teL0JwXSVYg9iUIUc15",
"MillisBehindLatest": 0
}

# Data の中身を確認する(Base64 でエンコードされているためデコードする.ドキュメントに書いている,「base64 -d」ではデコードできなかったので注意です)
echo -n "H4sIAAAAAAAAADWOTQuCQBRF/8ow64jMPsBdiLXIEjJoERKTvvSRzsi8MYnwvzdqLQ/3cu/58AqIRA7ndw3c4350PJ+i8HYI4nizC/iEq1aC7pNSNVkrTFqEKicblCrfadXUNhspNhpENSI1d0o11gaV3GJpQBP3rsnQC14gTY8fjtlYN2g1jKjsmLNcrty1u5jNXceZ/PV6gUvIfnrsp+cxv4D0iTJnBYjSFEw9WGaXUIr+me1RAiExGtSmvEu6Lwa4ORDyAAAA" | base64 -D | zcat

# 出力例(確認する段階が早すぎたのか,テストメッセージが表示されました)
{"messageType":"CONTROL_MESSAGE","owner":"CloudwatchLogs","logGroup":"","logStream":"","subscriptionFilters":[],"logEvents":[{"id":"","timestamp":1556373402311,"message":"CWL CONTROL MESSAGE: Checking health of destination Kinesis stream."}]}

上記の設定で Kinesis Data Streams にログデータが共有されるようになりました.これでログを Kinesis Data Firehose と連携して S3に出力する構成も可能になりました.

まとめ

CloudWatch Logs のログを Kinesis Data Streamsを使った共有する方法を紹介しました.通常の業務システムのアカウントとログ分析基盤のアカウントを分離したり,ログアーカイブや統合するためのアカウントのような場合に検討できる設定かと思います.何か役に立てば幸いです.

特定のリージョンのみのリソース制御するための IAM ポリシー設定

$
0
0

9月ですね,多田です.

IAM 権限の制御としてリージョンレベルで制御したい要件が出てきたので調べてみたところ, aws:RequestedRegionで制限できるようなので検証した結果をブログにまとめます.なお,今回東京リージョンとソウルリージョンに EC2 を起動している状況で読み取り権限は全リージョン有効ではあるが, EC2 への変更権限や起動,停止といった権限は東京リージョンのみに限定する IAM ポリシーを設定して検証しました.

検証イメージ図

検証した IAM ポリシー

検証で使った IAM ポリシーは以下の通りです.このポリシーを IAM ユーザーに関連づけて東京とソウルの EC2 を起動,停止してみます.期待する結果は 東京リージョンのサーバーは起動と停止はうまくいき,ソウルリージョンのサーバーは停止も起動もできない,です.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InstanceConsoleReadOnly",
"Effect": "Allow",
"Action": [
"ec2:Describe*"
],
"Resource": "*"
},
{
"Sid": "InstanceWriteRegionRestricted",
"Effect": "Allow",
"Action": [
"ec2:ModifyInstancePlacement",
"ec2:TerminateInstances",
"ec2:ImportInstance",
"ec2:StartInstances",
"ec2:MonitorInstances",
"ec2:RunScheduledInstances",
"ec2:ResetInstanceAttribute",
"ec2:RunInstances",
"ec2:ModifyInstanceAttribute",
"ec2:StopInstances",
"ec2:AssociateIamInstanceProfile",
"ec2:ModifyReservedInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"ap-northeast-1" <= 東京リージョンのみ指定
]
}
}
}
]
}

 

AWS ドキュメント

AWS グローバル条件コンテキストキー – aws:RequestedRegion

EC2 の起動と停止での検証

東京リージョンの場合

東京リージョンで IAMTESTインスタンスが起動しているので,停止の操作を行なってみると無事に停止まで操作可能なことが確認できました.

次に,起動してみます.起動も問題なく完了しました.東京リージョンは期待通りの操作ができることを確認できました.

ソウルリージョンの場合

ソウルリージョンでも IAMTESTインスタンスが起動しているので,停止の操作を行なってみると停止処理が失敗することを確認できました.

なお,エラー文をデコードするのは下記の AWS CLI で確認可能です.

$aws sts decode-authorization-message --encoded-message <エラー文>

次に,事前に違う権限を持つユーザーで停止しておいたサーバーを起動してみます.起動も失敗したのでソウルリージョンは期待通りの操作ができることを確認できました.

まとめ

リソース制御をリージョンレベルで設定する IAM ポリシーの紹介とIAMポリシー制御の検証を EC2 の操作で確かめてみた結果をまとめました.AWS のドキュメントページにも注意事項として記載がありますが,リージョンレベルで制御することで動作しないサービスの操作もあるため設定を行う際は十分に注意し,テストした後設定を行うようにしましょう.


aws:RequestedRegion 条件キーを使用すると、呼び出されるサービスのエンドポイントを制御できますが、オペレーションの影響を制御することはできません。一部のサービスではリージョン間の影響があります。たとえば、Amazon S3 にはリージョン間レプリケーションを制御する API オペレーションがあります。1 つのリージョン (s3:PutBucketReplication の条件キーの影響を受ける) で aws:RequestedRegion を呼び出すことはできますが、他のリージョンはレプリケーションの構成設定に基づいて影響を受けます。

Serverless FrameworkでCORSに対応しつつ、認証にCustom Authorizerを使ってみる

$
0
0

業務改善の中でChromeExtensionを作成中に、API GatewayのCORS対応をしたのでその内容をご紹介します。

CORSとは?

CORSとはCross Origin Resource Sharingのことで、とあるWebアプリケーションから、そのアプリケーションとは異なるドメインにリクエストを行うときの取り決めです。
今回は、ユーザーが表示しているWebページ(google.com)から自分が作成したAPI(xxx.execute-api.ap-northeast-1.amazonaws.com)を叩く、というようなChromeExtensionを開発していました。
このケースの場合、WebページのドメインとAPIのドメインは異なるのでCORS対応を行わない場合には、ブラウザによってレスポンスが捨てられます。

こんなときは、アクセスされる側(今回のケースではAPI Gateway)からレスポンスを返す時に、Headerに Access-Control-Allow-Origin や、Access-Control-Allow-Headers を含めることで「このドメインからの、このヘッダーを含むリクエストなら受けてもOK」を示すことができ、これによりブラウザとAPI間で正しい通信ができるようになります。

Custom Authorizerとは?

Custom Authorizerとは、AWSのAPI Gatewayに用意されている認証・認可の仕組みです。API Gatewayのリクエストの処理が行われる前に、CognitoまたはLambdaによる認証・認可の処理を実装することができます。今回はLambdaで実装しました。

本題

というわけで、今回はServerless Frameworkを使った時のCORSとCustom Authorizerの実装方法のサンプルです。
リポジトリは以下です。

https://github.com/galactic1969/serverless-auth-cors-sample

serverless.ymlの抜粋を記載します。

functions:
  sampleGet:
    name: ${self:provider.stage}-${self:service}-sample-get
    handler: src/get.main
    timeout: 30
    events:
      - http:
          path: /sample/
          method: get
          authorizer:
            name: custom-authorizer
            identitySource: method.request.header.Authorization, context.identity.sourceIp
            type: request
          integration: lambda
          cors:
            origin: '*'
            headers:
              - Authorization
  samplePost:
    name: ${self:provider.stage}-${self:service}-sample-post
    handler: src/post.main
    timeout: 30
    events:
      - http:
          path: /sample/
          method: post
          authorizer:
            name: custom-authorizer
            identitySource: method.request.header.Authorization, context.identity.sourceIp
            type: request
          integration: lambda
          cors:
            origin: '*'
            headers:
              - Authorization
              - Content-Type
  custom-authorizer:
    name: ${self:provider.stage}-${self:service}-custom-authorizer
    handler: src/custom_authorizer.main
    timeout: 30
    environment:
      API_AUTH_KEY: ${self:custom.confFile.${self:provider.stage}.api.auth_key}
      API_ALLOW_IP: ${self:custom.confFile.${self:provider.stage}.api.allow_ip_address}

CORS対応については、 cors: 以下にorigin(Access-Controll-Allow-Origin)とheader(Access-Controll-Allow-Headers)を書けばOKです。
なお、CORS対応を行うと、API Gatewayのリソースにpreflight用のOPTIONSメソッドが実装されます。これはMOCKで実装されているため、OPTIONSメソッド用のLambdaがデプロイされるようなことはありません。

Custom Authorizerについては、Functionにauthorizerの設定を記載し、別途authorizer用のFunctionもserverless.ymlに追加します。

import logging

from src.utils.env import get_secret_env

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

valid_token = get_secret_env('API_AUTH_KEY')
valid_ip_address = list(map(lambda ip: ip.strip(), get_secret_env('API_ALLOW_IP').split(',')))


def main(event, context):
    valid = False
    source_ip = event['headers']['X-Forwarded-For'].split(',')[0].strip()
    token = event['headers']['Authorization']

    if valid_token == token and source_ip in valid_ip_address:
        valid = True
        logger.info('request is valid')
    else:
        logger.info('request is not valid')

    if valid:
        return {
            'principalId': 1,
            'policyDocument': {
                'Version': '2012-10-17',
                'Statement': [
                    {
                        'Action': 'execute-api:Invoke',
                        'Effect': 'Allow',
                        'Resource': 'arn:aws:execute-api:*:*:*/*/*/*'
                    }
                ]
            }
        }
    else:
        return {
            'principalId': 1,
            'policyDocument': {
                'Version': '2012-10-17',
                'Statement': [
                    {
                        'Action': '*',
                        'Effect': 'Deny',
                        'Resource': 'arn:aws:execute-api:*:*:*/*/*/'
                    }
                ]
            }
        }

今回のサンプルでは、IP制限とアクセスキーの2つの要素で認証を実装してみました。なお、source_ipを代入するところで、 event['headers']['X-Forwarded-For'].split(',')[0].strip() としているのは、X-Forwarded-For にはClientのIPアドレスと、CloudFrontのIPアドレスの2つが入っているためです。

APIのテスト

※このテスト(リポジトリ)では access-control-allow-origin が * となっていますが、実際は環境に応じて適切なoriginに書き換えてください

まずはGET。問題ありません。

curl --request GET \
  --url 'https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sample?param1=foo&amp;param2=bar' \
  --header 'authorization: xxxauthxxx' \
  --dump-header -
HTTP/2 200 
content-type: application/json
content-length: 50
date: Thu, 29 Aug 2019 07:47:09 GMT
x-amzn-requestid: xxxxxxxxxxx
access-control-allow-origin: *
access-control-allow-headers: Authorization
x-amz-apigw-id: xxxxxxxx=
x-amzn-trace-id: Root=xxxxxxxxx;Sampled=0
x-cache: Miss from cloudfront
via: 1.1 xxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: xxxxx-xx
x-amz-cf-id: xxxxxxxxxxxxxxxxx==

{"result": "ok", "param1": "foo", "param2": "bar"}

次にPOST。ちゃんと返ってきてます。GETと違って、access-control-allow-headers にContent-Typeが入っています。(これは、Lambdaからレスポンスを返す時に指定しています。)

curl --request POST \
  --url https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sample \
  --header 'authorization: xxxauthxxx' \
  --header 'content-type: application/json' \
  --data '{"param1": "foo","param2": "bar"}' \
  --dump-header -
HTTP/2 200 
content-type: application/json
content-length: 50
date: Thu, 29 Aug 2019 07:45:27 GMT
x-amzn-requestid: xxxxxx
access-control-allow-origin: *
access-control-allow-headers: Authorization, Content-Type
x-amz-apigw-id: xxxxxxxxxx=
access-control-allow-methods: POST
x-amzn-trace-id: Root=xxxxxxxxxxxxxxxxxxxxxx;Sampled=0
x-cache: Miss from cloudfront
via: 1.1 xxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: xxxxx-xx
x-amz-cf-id: xxxxxxxxxxxxxx==

{"result": "ok", "param1": "foo", "param2": "bar"}

最後に、OPTIONSです。Webアプリケーションから行うリクエストの内容によっては、preflight requestというものをOPTIONSメソッドで直前に投げ、期待する結果が返れば本来のリクエストが投げる、という手順を踏む必要があります。preflight requestの詳細については、 こちら をご確認ください。

curl --request OPTIONS \
  --url https://hj78zzynmb.execute-api.ap-northeast-1.amazonaws.com/dev/sample \
  --dump-header -
HTTP/2 200 
content-type: application/json
content-length: 0
date: Fri, 23 Aug 2019 09:37:41 GMT
x-amzn-requestid: xxxx
access-control-allow-origin: *
access-control-allow-headers: Authorization,Content-Type
x-amz-apigw-id: xxx=
access-control-allow-methods: OPTIONS,POST,GET
access-control-allow-credentials: false
x-cache: Miss from cloudfront
via: 1.1 xxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT51-C3
x-amz-cf-id: xxxx==]

最後に、認証失敗のケースです。ちゃんとレスポンスヘッダーに「access-control-allow-origin」と「access-control-allow-headers」が入っていることが確認できます。 これは、 apigw.yml にてAPI Gatewayのレスポンスタイプを定義しているため、これらのヘッダーがレスポンスに含まれています。レスポンスタイプを定義しない場合、400系や500系のエラーの際にレスポンスにCORS系のヘッダーが入らず、クライアント側での切り分けが難しくなります。(サーバー側は400系や500系を返しているが、CORSに準拠していないレスポンスをブラウザ側が受け取る際に拒否してしまうため)

curl --request POST \
  --url https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sample \
  --header 'authorization: xxxauthxxxx' \
  --header 'content-type: application/json' \
  --data '{"param1": "foo","param2": "bar"}' \
> --dump-header -
HTTP/2 403 
content-type: application/json
content-length: 60
date: Fri, 30 Aug 2019 01:12:47 GMT
x-amzn-requestid: xxxxxxx
access-control-allow-origin: *
access-control-allow-headers: *
x-amzn-errortype: AccessDeniedException
x-amz-apigw-id: xxxxx=
x-cache: Error from cloudfront
via: 1.1 xxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: xxxx-xx
x-amz-cf-id: xxxxxxxxxxxxxxx=

{"message":"User is not authorized to access this resource"}

まとめ

というわけで、Serverless FrameworkでCORSに対応しつつ、認証にCustom Authorizerを使ってみる話でした。
Serverless Frameworkはプラグインや設定が多く中々使いこなすのが大変ですが、その分いろいろな事ができるので便利ですね!
今後も色々な設定を試していってみたいと思います。

Backlog API(V2)のPython3ラッパー “python-backlog”を作った

$
0
0

当社ではプロジェクト管理ツールとして全社的にNulab社のBacklogを使いまくっているのですが、社内の研修課題やお客様へのヒアリング課題を一斉登録したり、昔のプロジェクトで作ったwikiを新しいプロジェクトに移管したりとか、何かとAPIが使えたらいいなぁ、というシーンに遭遇します。

そういうときに使える道具として、ごく簡単なPythonラッパーを作ってみましたのでご紹介します。

※詳しくは以下のPyPIプロジェクトページやGitHubをご覧ください。

使い方

PyPIには python-backlog という名称で登録しています。以下のコマンドで利用可能です。

pip install python-backlog

backlog.base.BacklogAPI がAPIオブジェクトです。引数としてspace, api_keyを受け取ります。

READMEにも書いていますが、 backlog.util.load_conf() でyamlから認証の設定を引っ張ることも可能です(これを実装するために本質的な機能とは無関係なPyYAMLへの依存が発生してしまっています。執筆時点ではこの依存をあまりポジティブに捉えておらず、将来的には消すかもしれません)。

from backlog.util import load_conf
from backlog.base import BacklogAPI

conf = load_conf("conf.yml")["backlog"]
api = BacklogAPI(conf["space"], conf["api_key"])

例えばwikiのリストが欲しい場合は以下のように書きます。

import json

# list wikis
wikis = api.wiki.list("SampleProject")
print(json.dumps(wikis[0], indent=2))

API Clientオブジェクトの配下にBacklogリソースの名前空間があり、そのリソースに関連する操作、例えばwikiのリストは backlog_client.wiki.list() のように wiki のメソッド呼び出しとして利用します。パラメータの仕様はBacklogのAPIリファレンスに準拠します。

メソッドのdocstringには対応するBacklog APIのリファレンスのリンクを記述していますので、メソッドが要求するパラメータを確認したければ対象メソッドのdocstringを参照してください。

注意

  • MacOS(or Linux) + Python3.6を前提としています。Python2.xだと(たぶん)動かないです
  • Windowsも多分動きません。現状ではdocker上の環境で利用するくらいかなと思います
  • サポートしていないリソースもまだまだ多いです。リソースオブジェクト自体が未定義であるか、あるいはメソッドが NotImplemented を吐いて落ちるような仕様になっています

まとめ

自作パッケージをPyPIに公開するところまでやったのは初でしたが、色々と勉強になることが多かったです。まだBetaバージョンではありますが是非使ってみていただけると嬉しいです。

最終形のイメージはこれを更にラップしたCLIツールなので、そちらも(最近サボってるけど)開発中です。

こんな感じ↓で使えたらいいなぁと妄想しています

# あるプロジェクト配下のwikiをリスト表示
backlog wiki ls --project xxx

# プロジェクトA配下のwikiをプロジェクトBに移行
backlog wiki cp backlog://project-A/* backlog://project-B/

反響あれば再開するかも。。。拙作ではありますが、python-backlogをよろしくお願いします。

【Ansible入門】EC2環境でAnsibleを実行してみよう

$
0
0

こんにちは、CI部の柿﨑です。
先日、洗濯槽の掃除をしようと専用の洗剤を入れたところ、黒い物体がたくさん浮いてきました。
どうやらn年間の汚れが溜まっていたようです。。。猛省。
つまり、何事も定期的なメンテナンスが必要ということですね!

と、いうことで!
定期的なメンテンスといえば、そう!!
Infrastructure as Code(以下Iac)ですね!
今回はIaCの中でも代表的なツールである、Ansible入門を題材にします。
なるべくシンプルな構成にしていますので、是非、ご一読いただければと思います。

本記事の対象者

  • AWS環境にてサクッとAnsibleに触りたい方
  • 初っ端Ansibleのベストプラクティスを見て、やる気を失った方

本記事のコンセプト

  • なるべくシンプルに
  • 最低限使えるディレクトリ構成でAnsibleの動作を理解する
  • 今回はリモートにログインユーザーを作成し、パスワード認証でSSH接続します

前提条件

  • 下記、構成図の環境を構築
  • SSH接続にはteratermを使用
  • 今回使用したAMIはami-0ff21806645c5e492(Amazon Linux 2)
  • AnsibleサーバーはSSH接続、インターネット接続が可能なこと
  • Client01サーバーはSGにてAnsibleサーバーからのSSH接続許可、秘密鍵名はansible-key.pem、IPアドレスは192.168.20.4/32 

目次

  1. Ansibleとは
  2. インストールからPlaybook実行
  3. さいごに

1.Ansibleとは

インフラ環境をコード化し、インフラ構成を管理するツール。→ 公式ドキュメント
Ansible用にコード化されたファイル群をPlaybookと呼び、Playbookを1度でも何度でも実行しようが、同じ結果が得られる冪等性という特徴がある。
対象ホストが多ければ多いほど、実行したPlaybookの処理が成功したときに気持ち良くなれる。(失敗したときは知りません。)

2.インストールからPlaybook実行

  1. Ansibleサーバーにec2-userでSSH接続
  2. Ansibleサーバーにて以下コマンドを実行し、Ansibleをインストール
    sudo yum -y install python-devel openssl-devel gcc git
    sudo easy_install pip
    sudo pip install ansible
    ansible --version
    ※最後にAnsibleのバージョンが表示されたら成功です。
  3. Client01サーバーの秘密鍵をAnsibleサーバーの/home/ec2-user/.ssh/配下に格納

    以下のとおり、ansible-key.pemを確認できれば準備完了。
    [ec2-user@ip-192-168-10-33 ~]$ ls -la .ssh/
    total 8
    drwx------ 2 ec2-user ec2-user 52 Sep 6 08:33 .
    drwx------ 4 ec2-user ec2-user 90 Sep 6 08:23 ..
    -rw-r--r-- 1 ec2-user ec2-user 1696 Sep 6 08:30 ansible-key.pem
    -rw------- 1 ec2-user ec2-user 394 Sep 6 08:02 authorized_keys
    [ec2-user@ip-192-168-10-33 ~]$
  4. 急いでる人用 (急いでいない人は、この手順を飛ばして5.の手順へお進みください。)
    急いでいる人用にPlaybookをgitに上げましたので、そちらをAnsibleサーバーに格納して、Playbookを実行。
    cd
    git clone https://github.com/ikayarou/hands-on-01.git
    cd hands-on-01
    sudo ansible-playbook -i inventory/hosts site.yml
    ※SSHの接続確認をされるので、yesと入力しEnter

    Playbookの実行に成功すると以下のように結果が出力される。
    このPlaybookでは、Client01にパスワード認証でログインするユーザーを作成しました。
    早速、接続確認を行ってみます。
    ssh hands-on-user01@192.168.20.4
    ※SSHの接続確認をされるので、yesと入力しEnter
    パスワード:hands-on を入力

    SSH接続に成功出来たら完了です。
    急いでいる人向けの内容は、ここで終わりです。
  5. 急いでいない人向け手順
    以下のようなディレクトリ構造を順次作成していきます。まずはインベントリファイルから作成。
    mkdir -p hands-on-01/inventory
    cd hands-on-01
    cat << EOF > inventory/hosts
    [client_node]
    Clinet01 ansible_ssh_host=192.168.20.4
    
    [client_node:vars]
    ansible_ssh_user=ec2-user
    ansible_ssh_private_key_file=/home/ec2-user/.ssh/ansible-key.pem
    EOF

    [client_node]はグループ名です。
    グループ名を使うことで対象ホストをグルーピングすることができます。
    この項目で対象ホストのIPアドレスを記述しています。

    こちらに記載のansible_ssh_host=はホスト変数と呼ばれ、このホストにのみ適用されます。
    [client_node:vars]は、[client_node]グループに適用する変数を指定しています。
    これをグループ変数と呼びます。
    ansible_ssh_user=では対象ホストにSSH接続するユーザー名、ansible_ssh_private_key_file=ではSSH接続に使用する秘密鍵を指定しています。
    このように設定することで、グループごとにSSH接続するユーザーを変えたり、パスワード認証でSSH接続したりすることが可能です。
    続いて、site.ymlファイルを作成します。
    cd ~/hands-on-01
    cat << EOF > site.yml
    ---
    - hosts: client_node
      become: True
      roles:
        - hands-on
    EOF

    hosts:では、Playbook実行対象のグループを指定します。
    先ほど、hostsファイルに記述した[client_node]ですね。
    become:を有効化することにより、リモートユーザーでの処理をsudo権限で実行してくれます。
    roles:では、実行するロールを指定します。今回はhands-onロールを実行します。
    続いて、hands-onロールのtasksファイルを作成していきます。
    cd ~/hands-on-01
    mkdir -p roles/hands-on/tasks
    cat << EOF > roles/hands-on/tasks/main.yml
    ---
    - name: create user
      user:
        name: hands-on-user01
        createhome: yes
        state: present
        password: "{{ 'hands-on' | password_hash('sha512') }}"
    
    - name: modify sshd_config
      lineinfile:
        dest: /etc/ssh/sshd_config
        state: present
        backrefs: yes
        regexp: '^PasswordAuthentication no'
        line: 'PasswordAuthentication yes'
        backup: yes
      notify:
        - restart sshd
    EOF

    tasksファイルでは、リモートユーザーで実行したい処理を記述します。
    ここで重要になってくるのが、user:およびlineinfile:です。
    これらはモジュールと呼ばれ、各モジュールごとにAnsibleの処理が実装されています。
    今回であれば、userモジュールでユーザーを作成し、lineinfileモジュールでsshd_configファイルの編集を行っています。
    基本的には、各モジュールのドキュメントでパラメーターの内容を参照しつつ、Playbookを書いていきます。
    userモジュールのドキュメントはこちらlineinfileモジュールのドキュメントはこちら
    ※細かいパラメーターの説明は公式ドキュメントにおまかせします。

    といいますのも、今回注目していただきたいパラメーターはnotify:だからです。
    このnotify:が記述されているタスクが実行され、設定が変更された場合、notify:に記述されているrestart sshdが実行されます。
    restart sshdは後述するhandlersにて定義されている処理です。
    つまり、notify:を記述することにより、sshd_configファイルの設定変更を契機として、handlersファイルの処理を呼び出すことが可能となります。

    それでは、最後にhandlersファイルを作成します。

    cd ~/hands-on-01
    mkdir -p roles/hands-on/handlers
    cat << EOF > roles/hands-on/handlers/main.yml
    ---
    - name: restart sshd
      service:
        name: sshd
        state: restarted
        enabled: yes
    EOF

    前述したrestart sshdの正体がこのファイルになります。
    serviceモジュールにより、sshdをリスタートすることで設定を反映させています。serviceモジュールのドキュメントはこちら
    今回はディレクトリを分けましたが、1つのファイル内に記述することも可能です。
    さて、これでPlaybookが完成しました。
    早速、実行してみましょう。

    cd ~/hands-on-01
    sudo ansible-playbook -i inventory/hosts site.yml
    ※SSHの接続確認をされるので、yesと入力しEnter

    ansible-playbookがPlaybookの実行コマンドで、-iでインベントリファイルを指定、そしてPlaybookの起点となるsite.ymlを指定して実行しています。
    エラーがなく正常に実行されたら、SSH接続の確認をして完了となります。

    ssh hands-on-user01@192.168.20.4
    ※SSHの接続確認をされるので、yesと入力しEnter
    パスワード:hands-on を入力

    hands-on-user-01ユーザーで、パスワード:hands-onを入力してSSH接続に成功すればハンズオンは完了です。
    ちなみにですが、リモートユーザーでls -la /etc/sshと叩くと以下のようなファイルが存在するかと思われます。
    -rw------- 1 root root 3957 Sep 9 08:06 sshd_config.3699.2019-09-09@08:11:41~
    これは、lineinfileモジュールのbackup: yesとすることで、ファイル編集時に元ファイルのバックアップを作成してくれたりします。
    便利ですね♪

3.さいごに

AnsibleはモジュールをベースにPlaybookを書いていきますので、コードが標準化されるという利点がございます。
そのため、誰が見てもコードが理解しやすく、IaCやコードに不慣れな方の入口として最適だと思われます。
逆をいえば、複雑に書かないでくださいということですね!
Ansibleの思想として、チームでコードを管理するために分かりやすい記述を心がける必要があります。
もし、複雑な処理を実行したい場合は、AnsibleではなくほかのIaCツールをご検討いただくのが無難です。

Ansibleのベストプラクティスについては、こちらの方が分かりやすく書いてくれています。
今回作成したPlaybookと見比べると、ずいぶん違いますね!
ベストプラクティスの方は、最初から手をつけるにはいろいろと知らなければいけないことが多いです。
そのため、今回のPlaybookを理解しつつ、改善を積み重ねていくことでベストプラクティスへの理解も深まっていくものと思われます。
例えばここで、変数を使っていったり・・・というのを書こうと思っていましたが、どうやら時間切れのようです。
また、機会がありましたら続きを書きます。
最後に簡単な課題としまして、余っているプライベートサブネットにサーバーを作成して、今回作成したサーバーと2台同時にPlaybookを実行してみてください。
これができますと、いくつものサーバーに対してPlaybookを実行するのも容易になるものと思われます。

本記事が、皆様のお役に立てれば幸いでございます。

Viewing all 1210 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>