AWSのCloudWatchのイベントルールを利用してcronでEC2の停止や開始を行う

AWSのCloudWatchのイベントルールを利用してcronでEC2の停止や開始を行う. CloudWatchのルールで「EC2 StopInstances呼び出し」というターゲットが用意されているので、これを選択し、EC2のインスタンスIDを指定して、停止されるか確かめます。(運用ではcron式で設定だと思いますが今回は確認だけのため). 続きを読む

CloudWatch Events と Systems Manager で EC2の起動/停止をスケジュール化する

はじめに

開発環境等のインスタンスは休日や夜間は停止しておくことが多いと思います。
CloudWatch Events と Lambda で実装する例も多くみかけますが、
Systems Managerと組み合わせてノンプログラミングで実装する方法もあります。

Systems Manager 単体でも Maintenance Windows を使用して設定することができますが、
これは別の記事でご紹介できればと考えています。

設定する

IAM ロールの設定と CloudWatch Events のルール作成が必要です。

IAMロールを作成する

EC2 の起動停止は SSM Automation の機能を利用します。
そのため CloudWatch Events が SSM を呼び出すための IAM ロールを作成します。

image.png

ここでは AWS 管理ポリシーの AmazonSSMAutomationRole をアタッチします。
EC2 起動停止するために必要な権限以外も含まれますので、必要に応じてカスタムポリシーを作成してください。
作成後、信頼関係から信頼されたエンティティに events.amazonaws.com を追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "events.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

image.png

CloudWatch Events を設定する

起動用ルールの作成

イベントソースの設定でスケジュールを選択し、Cron式でイベントスケジュールを設定します。
例えば平日の午前9時に指定したEC2を起動したい場合は、以下のように設定します。

0 0 ? * 2-6 *

※UTC で設定しますので、日本標準時との時差9時間を考慮する必要があります。

image.png

ルールのスケジュール式ついては以下ドキュメントにも詳細が記載されています。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html

次にターゲットの追加から SSM Automation 選択し、以下のように設定します。

  • Doclument: AWS-StartEC2Instance
  • Configure automation parameter(s)
    • InstanceId: 起動したいインスタンスのインスタンスID
  • 既存のロールの使用: 作成した IAM ロールを指定

ロールの作成手順で信頼されたエンティティに events.amazonaws.com を追加していないと、
既存のロールの選択肢に出てきませんので注意してください。

image.png

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成すれば完了です。

停止用ルールの作成

起動用ルールと同じ流れですので、画面コピーは割愛します。

ここでは平日の18時に停止を行うと想定し、UTC で以下のように設定します。

0 9 ? * 2-6 *

ターゲットの追加から SSM Automation 選択し、以下のように設定します。

  • Doclument: AWS-StopEC2Instance
  • Configure automation parameter(s)
    • InstanceId: 停止したいインスタンスのインスタンスID
  • 既存のロールの使用: 作成した IAM ロールを指定

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成します。

動作確認

設定した時刻に指定したインスタンスが起動および停止することを確認します。
Automation の実行結果については、コンソールでの確認方法は現時点で2通りあり、
EC2コンソールの 自動化 または AWS Systems ManagerコンソールのAutomation から確認することができます。

image.png

CloudWatch Events で結果を監視する

せっかくなので Automation の実行結果についても CloudWatch Events で設定してみます。
新規にルールを作成し、スケジュールではなく、イベントパターンを選択します。
ここでは Automation の失敗またはタイムアウトを監視するため、以下のように詳細を設定します。

  • サービス名: EC2 Simple Systems Manager (SSM)
  • イベントタイプ: Automation
  • Specific detail type(S)

    • EC2 Automation Execution Status-change Notification
  • 特定のステータス

    • Failed, TimedOut

image.png

コンソールで設定できるのは上記項目のみであるため、このままの設定だと今回設定した EC2 起動停止用の
Automation だけでなく、SSM で実行される全ての Automation が監視対象となってしまいます。
条件を更に絞りたい場合は、イベントパターンのプレビューから直接 JSON の編集を行うことができます。

ここでは EC2 の起動停止を行う Automation のみを監視するため、
“detail.Definition” フィールドに Automation ドキュメント名を設定しました。
“resources” フィールドに対象ドキュメントの ARN を指定した場合も同様の結果になります。

{
  "source": [
    "aws.ssm"
  ],
  "detail-type": [
    "EC2 Automation Execution Status-change Notification"
  ],
  "detail": {
    "Definition": [
      "AWS-StartEC2Instance",
      "AWS-StopEC2Instance"
    ],
    "Status": [
      "Failed",
      "TimedOut"
    ]
  }
}

その他にどのような項目を指定できるかについては、以下のドキュメントの
Automation 実行ステータス変更の通知例をご参照ください。

サポートされている各サービスからの CloudWatch イベント イベントの例
AWS Systems Manager イベント
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/EventTypes.html#ssm_event_types

ターゲットの設定では検知した内容の通知方法を設定します。
ここでは SNS の Topic に登録した Email アドレスに通知するよう設定しました。
必要に応じて入力の設定で通知内容を定義します。

image.png

設定の詳細ボタンからステップ 2:に進み、

  • ルール名称(必須)
  • 説明(任意)

を入力し、ルールを作成すれば完了です。
参考になれば幸いです。

参考: イベントパターンにおける実行ロールの指定

前述のとおり、ドキュメントに記載されているイベント例に記載されている内容であれば
イベントパターンの手動編集で条件を絞り込むことができます。

Automation 実行ステータス変更の通知例をドキュメントから抜粋すると以下のとおりです。

{
  "version": "0",
  "id": "d290ece9-1088-4383-9df6-cd5b4ac42b99",
  "detail-type": "EC2 Automation Execution Status-change Notification",
  "source": "aws.ssm",
  "account": "123456789012",
  "time": "2016-11-29T19:43:35Z",
  "region": "us-east-1",
  "resources": ["arn:aws:ssm:us-east-1:123456789012:automation-execution/333ba70b-2333-48db-b17e-a5e69c6f4d1c", 
    "arn:aws:ssm:us-east-1:123456789012:automation-definition/runcommand1:1"],
  "detail": {
    "ExecutionId": "333ba70b-2333-48db-b17e-a5e69c6f4d1c",
    "Definition": "runcommand1",
    "DefinitionVersion": 1.0,
    "Status": "Success",
    "StartTime": "Nov 29, 2016 7:43:20 PM",
    "EndTime": "Nov 29, 2016 7:43:26 PM",
    "Time": 5753.0,
    "ExecutedBy": "arn:aws:iam::123456789012:user/userName"
  }
}

最後の “detail.ExecutedBy” フィールドは実行されたユーザの ARN になっています。
今回のEC2起動停止では、”スケジュール実行で SSM Automation を実行するルール”を定義しているため、
この箇所はイベントルールに設定した実行ロールの assumed-role ARN が含まれる形になります。
これを指定すれば実行元のロールも監視条件に含めることができます。
ただし、実際の assumed-role ARN は以下の形式になります。

"arn:aws:sts::[account-id]:assumed-role/[role-name]/[role-session-name]"

ロールセッション名については、イベントルールの実行ロール設定時に AWS側で設定されるようです。
ロールセッション名がルールの実行毎に変わってしまうと、正常に監視できないことになりますが、
現状の挙動を観察する限りでは、実行ロールの変更を行わない限りは(時間によらず)変化しないようです。

ただしドキュメント等に記載されている仕様ではないため、今後予告なく挙動が変わる可能性が大いにあります。
プロダクション環境等での設定はおすすめできませんので参考情報として最後に記載させていただきました。

続きを読む

[AWS][Terraform] Terraform で Amazon Inspector を導入する

TerraformAmazon Inspector を導入して、CloudWatch Events で定期実行させるための手順。
Terraform は v0.11.2 を使っています。

Inspector の導入

Inspector を導入するには、Assessment targets (評価ターゲット) と Assessment templates (評価テンプレート) を設定する必要があります。

Assessment targets の設定

Terraform で Assessment targets を設定するには、aws_inspector_resource_group, aws_inspector_assessment_target リソースを使用します。
こんな感じです。

inspector_target.tf
variable "project" { default = "my-big-project" }
variable "stage"   { default = "production" }

resource "aws_inspector_resource_group" "inspector" {
    tags {
        project   = "${var.project}"
        stage     = "${var.stage}"
        inspector = "true"
    }
}

resource "aws_inspector_assessment_target" "inspector" {
    name               = "my-inspector-target"
    resource_group_arn = "${aws_inspector_resource_group.inspector.arn}"
}

aws_inspector_resource_group では、対象となるインスタンスを特定するための条件を記述します。
上記の例だと、以下のタグが設定されているインスタンスを対象にします。

Name Value
project my-big-project
stage production
inspector true

aws_inspector_assessment_target では、aws_inspector_resource_group で定義した条件を元に Assessment targets を作成します。

Assessment templates の設定

Terraform で Assessment templates を設定するには、aws_inspector_assessment_template リソースを使用します。
こんな感じです。

inspector_template.tf
variable "inspector-rule" = {
    type = "list"
    default = [
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-7WNjqgGu",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-bBUQnxMq",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-gHP9oWNT",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-knGBhqEu"
    ]
}

resource "aws_inspector_assessment_template" "inspector" {
    name       = "my-inspector-template"
    target_arn = "${aws_inspector_assessment_target.inspector.arn}"
    duration   = 3600

    rules_package_arns = [ "${var.inspector-rule}" ]
}

output "assessment_template_arn" {
    value = "${aws_inspector_assessment_template.inspector.arn}"
}

rules_package_arns では、利用可能な Inspector rule package の ARN を設定します。
variable にしておくと、後で rule package を変更したい時に楽ですね。
こんな感じで、使用する rule package を変更できます。

terraform.tfvars
"inspector-rule" = [
    "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-7WNjqgGu",
    "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-bBUQnxMq"
]

使用できる rule package は、aws-cli で取得してください。

# パッケージ一覧の表示
$ aws --region ap-northeast-1 inspector list-rules-packages
{
    "rulesPackageArns": [
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-7WNjqgGu",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-bBUQnxMq",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-gHP9oWNT",
        "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-knGBhqEu"
    ]
}
# 詳細を確認
$ aws --region ap-northeast-1 inspector describe-rules-packages 
  --rules-package-arns "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-7WNjqgGu"
{
    "rulesPackages": [
        {
            "description": "The CIS Security Benchmarks program provides well-defined, un-biased and consensus-based industry best practicesto help organizations assess and improve their security.nnThe rules in this package help establish a secure configuration posture for the following operating systems:nn  -   Amazon Linux version 2015.03 (CIS benchmark v1.1.0)n  n    ",
            "version": "1.0",
            "name": "CIS Operating System Security Configuration Benchmarks",
            "arn": "arn:aws:inspector:ap-northeast-1:406045910587:rulespackage/0-7WNjqgGu",
            "provider": "Amazon Web Services, Inc."
        }
    ],
    "failedItems": {}
}

参考URL: Terraform v0.8.5でAWS Inspectorに対応します

これで terraform apply すれば Assessment targets, templates が作成されます。

動作確認

実際に Inspector が実施されるか確認して見ましょう。

$ aws inspector start-assessment-run 
  --assessment-template-arn arn:aws:inspector:ap-northeast-1:************:target/0-xxxxxxxx/template/0-xxxxxxxx
{
    "assessmentRunArn": "arn:aws:inspector:ap-northeast-1:************:target/0-xxxxxxxx/template/0-xxxxxxxx/run/0-7WNjqgGu"
}

実行状況の確認は aws inspector describe-assessment-runs

$ aws inspector describe-assessment-runs 
  --assessment-run-arns arn:aws:inspector:ap-northeast-1:************:target/0-QOvPswHA/template/0-uCIUy636/run/0-n9nnWOem

CloudWatch Events Schedule による定期実行

当初は CloudWatch Events で定期実行するには Lambda から呼び出すようにしなければいけませんでした。
しかし、CloudWatch Event から直接 Inspector を実行できるようになったため、Lambda を使用しなくても aws_cloudwatch_event_targetaws_cloudwatch_event_rule だけで定期実行設定が可能です。

CloudWatch Events で使用する IAM ロールの作成

まずは、CloudWatch Events で使用する IAM ロールを作ります。

cloudwatch-events-iam-role.tf
esource "aws_iam_role" "run_inspector_role" {
    name               = "cloudwatch-events-run-inspector-role"
    assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

resource "aws_iam_policy" "run_inspector_policy" {
    name        = "cloudwatch-events-run-inspector-policy"
    description = ""
    policy      = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "inspector:StartAssessmentRun"
            ],
            "Resource": "*"
        }
    ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "run_inspector_role" {
    role       = "${aws_iam_role.run_inspector_role.name}"
    policy_arn = "${aws_iam_policy.run_inspector_policy.arn}"
}

CloudWatch Events への登録

CloudWatch Events に登録するために aws_cloudwatch_event_target リソースと aws_cloudwatch_event_rule を作りましょう。

cloudwatch-events.tf
variable "schedule"    { default = "cron(00 19 ? * Sun *)" }

resource "aws_cloudwatch_event_target" "inspector" {
  target_id = "inspector"
  rule      = "${aws_cloudwatch_event_rule.inspector.name}"
  arn       = "${aws_inspector_assessment_template.inspector.arn}"
  role_arn  = "${aws_iam_role.run_inspector_role.arn}"
}

resource "aws_cloudwatch_event_rule" "inspector" {
  name        = "run-inspector-event-rule"
  description = "Run Inspector"
  schedule_expression = "${var.schedule}"
}

schedule_expression の cron() は UTC で設定する必要があるので注意してください。
記述方法は、以下を参考に
参考URL: Rate または Cron を使用したスケジュール式

EC2 への IAM Role の設定と、ユーザーデータによる Inspector エージェントのインストール

評価ターゲットとなる EC2 には、Inspector エージェントがインストールされていて、適切なインスタンスロールが設定されている必要があります。
導入するには、こんな感じ

インスタンスロール

inspectora エージェントを使用するために必要なポリシーをアタッチしたインスタンスロールの作成はこんな感じです。

ec2-instance-role.tf
resource "aws_iam_role" "instance_role" {
    name               = "my-ec2-role"
    path               = "/"
    assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

resource "aws_iam_instance_profile" "instance_role" {
    name = "my-ec2-role"
    role = "${aws_iam_role.instance_role.name}"
}

resource "aws_iam_policy" "inspector" {
    name        = "my-ec2-iam-policy-inspector"
    description = ""
    policy      = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeCustomerGateways",
                "ec2:DescribeInstances",
                "ec2:DescribeTags",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeNatGateways",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribePrefixLists",
                "ec2:DescribeRegions",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpcEndpoints",
                "ec2:DescribeVpcPeeringConnections",
                "ec2:DescribeVpcs",
                "ec2:DescribeVpn",
                "ec2:DescribeVpnGateways",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:DescribeTags",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetHealth"
            ],
            "Resource": "*"
        }
    ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "inspector" {
    role       = "${aws_iam_role.instance_role.name}"
    policy_arn = "${aws_iam_policy.inspector.arn}"
}

ユーザーデータによる inspector エージェントのインストール

OS は Amazon Linux を想定してます。
ユーザーデータに書いておけば、インスタンス起動直後に inspector エージェントインストールできますね。
参考URL: Amazon Inspector エージェントをインストールする

ssh-key.pemssh-key.pem.pubssh-keygen で適当に作っておきましょう。

ec2.tf
## AMI
##
data "aws_ami" "amazonlinux" {
    most_recent = true
    owners      = ["amazon"]

    filter {
        name   = "architecture"
        values = ["x86_64"]
    }

    filter {
        name   = "root-device-type"
        values = ["ebs"]
    }

    filter {
        name   = "name"
        values = ["amzn-ami-hvm-*"]
    }

    filter {
        name   = "virtualization-type"
        values = ["hvm"]
    }

    filter {
        name   = "block-device-mapping.volume-type"
        values = ["gp2"]
    }
}

## SSH Key Pair
##
resource "aws_key_pair" "deployer" {
    key_name   = "ssh-key-name"
    public_key = "${file(ssh-key.pem.pub)}"
}

## EC2
##
resource "aws_instance" "ec2" {
    ami                         = "${data.aws_ami.amazonlinux.id}"
    instance_type               = "t2.micro"
    key_name                    = "${aws_key_pair.deployer.key_name}"
    iam_instance_profile        = "${aws_iam_instance_profile.instance_role.name}"

    user_data                   = <<USERDATA
#!/bin/bash
# install inspector agent
cd /tmp
/usr/bin/curl -O https://d1wk0tztpsntt1.cloudfront.net/linux/latest/install
/bin/bash install -u false
/bin/rm -f install
USERDATA

    tags {
        project   = "${var.project}"
        stage     = "${var.stage}"
        inspector = "true"
    }
}

現場からは以上です。

続きを読む

AWS Elastic Beanstalkで、デプロイ時に一つのインスタンスにだけ実行

Elastic Beanstalk へのデプロイで、一つのインスタンスにだけ実行するには container_commandsleader_only というフラグを立てれば良いと思われるが、上手く動作しなかった。しかもオートスケール時には動作しないらしい。

ので、ELB に問い合わせて自身のインスタンスIDと比較するという方法を取った。下記のスクリプトを配置すれば可能。

#!/usr/bin/env bash

if aws elb describe-load-balancers --query 'LoadBalancerDescriptions[].Instances' --region ap-northeast-1 --output text 
    | cat -n 
    | grep $(curl http://169.254.169.254/latest/meta-data/instance-id) 
    | awk '{print $1}' 
    | grep -q 3
then
    echo 'HOME=/tmp' | sudo tee /var/spool/cron/webapp
    echo '* * * * * php /var/app/current/artisan schedule:run >> /dev/null 2>&1' | sudo tee -a /var/spool/cron/webapp
fi
  • grep -q 3 は決め打ちの番号なので、環境で調整する必要あり。
  • インスタンスの中で curl http://169.254.169.254/latest/meta-data/instance-id とすると、そのインスタンス自身のIDが取得できる。
  • IAMロールの設定が別途必要。Elastic Beanstalkに振られているIAMロールに AWSElasticBeanstalkFullAccess を付与すれば良い。

参考

https://qiita.com/idaaki/items/a356d1785a59d4150358

続きを読む

27円/月で運用できるAWS Lambda を用いたウェブサイトの外形監視

ウェブサイトの外形監視とは?

 ウェブサイトがユーザーからきちんと閲覧できるかどうかを監視するという至極単純なものが「ウェブサイトの外形監視」です。外形というワードが入っているとおり、ユーザー側から名前解決を正常に行うことができ、宛先にきちんとリクエストを行え、妥当な時間内に正常なレスポンスを受け取ることができるかをチェックすることが目的になると思います。

 したがって、構築されたサーバーとはネットワーク的にも物理的にも独立した場所から監視を行えると良いのですが、そうすると外形監視サーバーのお守りをしなければならず、個人でちゃんとやろうとすると微妙に面倒ではあります。

AWS Lambda を用いたウェブサイトの外形監視

 AWS Lambda は、オンデマンドでコードの断片を実行することができるアプリケーション基盤です。あらかじめサーバーを立てて置かなくても、実行したいコードを配置しておき、実行したいときにサーバーのことなど何も考えずに呼び出すことができます。ウェブサイトの外形監視は、せいぜいリクエストを送ってステータスコードやレスポンスタイムなどを見てあげるだけの簡単な処理であるため、相性がよさそうです。

 サービスを AWS 以外のクラウドや、オンプレミスで運用している場合には物理・ネットワーク的に異なる条件から対象を監視することができます。また、AWS Lambda は複数のリージョンにデプロイすることが可能なため、AWSを利用している場合でも、世界中の様々なリージョンを利用することにより、地理的に異なる場所から対象を監視することが可能です。

 AWS には Route 53 にすでにヘルスチェッカーが存在しているのですが、色々なオプションをちまちまつけていくと少しずつお金を取られていくので(といっても大した額ではないんですが…)、 #okane_nai 勢の私は AWS Lambda の無料利用枠で同じようなことが実現できるのではないかと思い、今回試してみることにしました。

システムの全体像

 AWS Lambda の実行トリガーはイベントソースと呼ばれています。外形監視のイベントソースとしては定期的に実行できる cron のような振る舞いを実現できればよさそうです。AWS CloudWatch Events がちょうどそのようなものに該当しており、cron 式や rate 式によって以下のように簡単にイベント発行のスケジューリングが可能です。

lambda_health_check_01.png

 単純な外形監視の通知先として Slack への通知を考えるとするならば、最小構成としての AWS Lambda と AWS CloudWatch Events を用いた仕組みの全体像と稼働のイメージは以下のような図になります。

lambda_health_check_02.png

 AWS Lambda で動くコードは、自由にカスタマイズできる普通のコードですので、たとえば Twillio API と連携して異常検知時に電話を鳴らしたり、レスポンスに特定の文字列が含まれているかチェックしたりなど様々なことができます。また、Amazon SNS を利用して様々な通知連携を行ったり、DynamoDB などを用いて監視データを蓄積したりすることも可能です。個人でお遊び監視を入れるには監視サーバーをお守りする必要もなく、楽しいおもちゃになるのではないでしょうか。

AWS Lambda を用いた外形監視のコスト見積もり

2018年1月現在、AWS Lambda には以下のような無料枠が設けられています。

  • リクエスト: 月間 1,000,000 件
  • コンピューティング時間: 月間 400,000 GB-秒

したがって、リクエスト数とコンピューティング時間の2つの軸でコストを見積もる必要があります。

また AWS CloudWatch Events については単純に発行するイベント数に応じて課金がなされます。

AWS Lambda リクエスト数の見積もり

 毎分ヘルスチェックをまわすとすれば、 1 (req) * 60 (min) * 24 (hour) * 31 (day) = 44,640 (reqest) となり、無料利用枠の中に余裕を持っておさまります。もし他の用途で無料利用枠を使い切っているとすれば、課金額は 44,640 (request) * 0.0000002 (USD/request) = 0.008928 (USD) となります。

AWS Lambda コンピューティング時間の見積もり

 node.js で動く HTTP リクエストを送る単純なプログラムであるため割り当てメモリは一番小さな 128MB (= 1/8 GB) で十分です。手元で稼働させている実績からほぼ 1000ms 以内にヘルスチェックが完了しているのですが、バッファをとって平均 2000ms かかると仮定して計算するならば、 1/8 (GB) * 2 (sec) * 60 (min) * 24 (hour) * 31 (day) = 11,160 (GB-sec) となり、無料利用枠におさまります。もし他の用途で無料利用枠を使い切っているとすれば、課金額は 11,160 (GB-sec) * 0.00001667 (USD) = 0.1935387 (USD) となります。

AWS CloudWatch Events の見積もり

 AWS CloudWatch Events は $1.00/100万イベントという料金になっているため、単純に 1 (event) * 60 (min) * 24 (hour) * 31 (day) = 44,640 (event) / 1000000 (event/USD) = 0.04464 (USD) のお金が必要です。

総費用の見積もり

 無料利用枠を使っていないのであれば、AWS Lambda の費用はすべて枠内におさまっており、無料で稼働中のサーバーとは地理的に異なる場所に配置できる外形監視を導入することができます。また仮に無料利用枠を使い切っているとしても、0.008928 + 0.1925387 + 0.04464 = 0.24610677 (USD) の課金が発生します。多分 27 円くらい取られます。 お財布には厳しいですが、気合いです。

外形監視のための AWS Lambda 関数の作成

 作るものは非常に単純で、node.js で HTTP リクエストをサーバーに送り、ステータスコードが 200 番台だったらオッケーで、その他の場合は Slack の incomming webhook を利用してメンションを飛ばすだけです。Slack の設定次第では、スマホにプッシュ通知とか飛ばせるので、面倒なこと考えずに手軽に検知手段が欲しいときにこの方法はコスパが良いのではないでしょうか。

 コードなどどうでもいいので、いますぐ試してみたいという方のために、簡単にデプロイできるような形にしておきましたので、こちらの GitHub リポジトリ1 からクローンしてみてください。数ステップで AWS Lambda 上にデプロイしてお試しいただけます。

基本的なコード

 暇人の趣味なので FlowType を使ってます。request を使ってリクエストを送って、ステータスコード見てるだけなので、基本的には以下のような簡単なコードを書いてアレコレしていくだけです。

// @flow

import request from 'request-promise-native';

async getStatus(): Promise<Object> {
   const options = {
     method: 'GET',
     uri: 'https://exapmle.com',
     timeout: 3000,
     headers: {
       'User-Agent': 'Mozilla/5.0 (Oreore Health Checker;)'
     },
     resolveWithFullResponse: true
   };
   try {
     const { statusCode, statusMessage } = await request(options);
     return { statusCode, statusMessage };
   } catch (err) {
     console.log(JSON.stringify(err));
     if (err.response) {
       const statusCode = err.response.statusCode;
       const statusMessage = err.response.statusMessage;
       return { statusCode, statusMessage };
     } else {
       const statusCode = null;
       const statusMessage = err.message;
       return { statusCode, statusMessage };
     }
   }
 }

 ラムダ関数 1つで複数サイトの監視をさせるために、設定ファイルに書いた URL リストを舐めて、それぞれに対して上記のような関数を呼び出し、サービスの状態を並列に確認させています。このような仕組みで、現状手元で 10 エンドポイントくらいを監視させていますが、関数の実行時間はそれほどかわらず、結果としてはレスポンスが一番遅いエンドポイントに引きずられているような挙動に見えます。

Apex を使った AWS Lambda 関数の管理

 AWS Lambda 関数のデプロイをマネジメントコンソールからやるのは面倒なので、Serverless とか Apex などを使うと良いと思います。今回は簡単なものだったので、Apex を利用しました。適切な設定をすると次のようなワンコマンドで、AWS Lambda にデプロイすることができます。

apex deploy

ためしにデプロイした関数を実行したいときも次のようにとてもお手軽です。

apex invoke (関数名)

成果物を俺にも使わせろ

 どうぞどうぞ。こちらの GitHub リポジトリからクローンしてください。使うまでには次のような作業をしてください。

  1. 必要なもの(aws-cli, apex)をインストール
  2. git clone git@github.com:53ningen/sousie.git && cd sousie
  3. マネジメントコンソールからラムダ関数が使う IAM ロールを作る
    • 詳しくはこのあたりの資料を見てください
    • AWS CloudWatch ログ書き込み権限をアタッチする
  4. cp ./project.json.template ./project.json して role の欄に作った IAM Role の ARN を書く
  5. cp ./config.json.template ./config.json して ヘルスチェックしたいエンドポイントや Slack の設定などを行う
  6. apex deploy
  7. AWS CloudWatch Events をマネジメントコンソールから設定して、デプロイした AWS Lambda 関数が定期実行されるようにする

 今後は CLI ベースのセットアップ用ツールの作成、Amazon SNS トピックへの通知や、DynamoDB との連携によるリッチな通知閾値設定、CloudWatch カスタムメトリクスとの連携機能などを実装するつもりです。飽きなければ…。あと基本的に JavaScript 素人なのでおかしなところあったら修正 pull request いただけると嬉しみ〜という感じです。

まとめと展望

  • AWS Lambda を使うと非常に安価に外形監視を行うことができます
  • 個人運用のサービスなどではこのレベルでも十分に役に立つ監視基盤となりうるのではと思います
  • ただの簡単な JavaScript コードであるため複雑なカスタマイズも自由にできます
    • Twillio などを使えば電話も鳴らせます
    • カスタマイズすれば、状況によってなんらかのオペレーションをするみたいな自動復旧の仕組みとかも仕込めそう
  • Amazon CloudWatch カスタムメトリクスや Amazon SNS, AWS Step Functions などと連携すればかなり複雑なこともできるのではないかと思います
  • AWS の無料利用枠を使って快適な人生を送ろう

 あとここまで書いておいてアレなんですが、自分の個人サービスの一部、Route 53 の DNS フェイルオーバー設定入れているので、結局 Route 53 のヘルスチェック使ってます。

Special Thanks

 わたしは JavaScript 素人なので、このまわりのよくわからないことに関しては @nagisio 大先生にご指導いただきました。本当にありがとうございます。


  1. リポジトリの名前は「異世界はスマートフォンとともに。」のキャラクターである、スゥシィ・エルネア・オルトリンデ(CV: 山下七海)様の名前をお借りしました 

続きを読む

Linux のログイン・ログオフ履歴を Cloudwatch Logs に送信する

サマリ

Linux のログイン/ログオフの履歴(だけ)を Cloudwatch Logs に送りたかった。
rsyslog から sshd のログだけ抽出して Cloudwatch Logs Agent で送った。できた。

要件

Linux へのログイン・ログオフの履歴を Cloudwatch Logs に保存する必要があり、Cloudwatch Logs Agent をインストールして /var/log/secure を Cloudwatch Logs に送信する。
ただし、トラフィック量の都合で secure 全て送るのはよろしくないのでいい感じに絞ったものを送信したい。

SSH ログイン時に出力されるログには2種類あり、

  1. sshd プロセスが出力する rsyslog

    • /var/log/secure
  2. login プロセス出力するログ達(バイナリ形式)
    • /var/log/wtmp (ログイン成功ログ)

      • last コマンドで表示、新しいものが上で並ぶ
    • /var/log/btmp (ログイン失敗ログ)
      • lastb コマンドで表示、新しいものが上で並ぶ

送信するにはテキストである必要があるため、

  1. rsyslog からうまいこと sshd プロセスのログだけを別ファイルにする

    • rsyslog で出力されたログをCloudwatch Logs Agent で送信する
  2. last/lastbコマンドを実行し、結果をログファイルに出力するシェルスクリプトを作成する。その際、時系列降順に直す必要がある。
    • cronで定期的に実行し、ログをCloudwatch Logs Agent で送信する

の2パターン考えられるが、楽そうな前者を試す。

設定手順

環境

  • Red Hat Enterprise Linux 7.4 (HVM)
  • awscli-cwlogs 1.4.4

SSHログの抽出

適当な EC2 インスタンスを起動。

要件としては、rsyslog の secure ログ /var/log/secure| grep 'sshd'したような結果が出力できればよさそう。そのほかの secure ログはいらない。

console
$ sudo cat /var/log/secure | grep 'sshd'
略
Jan 23 19:41:46 HOSTNAME sshd[5106]: Server listening on 0.0.0.0 port 22.
Jan 23 19:41:46 HOSTNAME sshd[5106]: Server listening on :: port 22.
Jan 23 20:40:54 HOSTNAME sshd[1976]: pam_unix(sshd:session): session closed for user ec2-user
Jan 23 20:47:46 HOSTNAME sshd[4914]: Accepted publickey for ec2-user from 10.0.0.2 port 61646 ssh2: RSA SHA256:xxx
Jan 23 20:47:46 HOSTNAME sshd[4914]: pam_unix(sshd:session): session opened for user ec2-user by (uid=0)
Jan 23 20:49:12 HOSTNAME sshd[4914]: pam_unix(sshd:session): session closed for user ec2-user

rsysgにはプロパティベース フィルタというものがあり、 :property, [!]compare-operation, "value"
programname でフィルタがかけられる。これを利用すれば特定のプロセスのログだけ別ファイルに出力することが可能。
なので rsyslog の設定をしていく。secure_sshd という新しいログファイルに sshd プロセスのログだけを出力する設定を追記。

/etc/rsyslog.conf
# sshd ログを別ファイルにも出力
:programname, isequal, "sshd" /var/log/secure_sshd
console
sudo service rsyslog restart

ログイン・ログオフしてから良い感じにログが出ていること確認できた。

console
$ sudo cat /var/log/secure_sshd
Jan 24 03:08:55 HOSTNAME sshd[9308]: Accepted publickey for ec2-user from 10.0.0.3 port 60196 ssh2: RSA SHA256:xxx
Jan 24 03:08:55 HOSTNAME sshd[9308]: pam_unix(sshd:session): session opened for user ec2-user by (uid=0)
Jan 24 03:09:14 HOSTNAME sshd[9308]: pam_unix(sshd:session): session closed for user ec2-user

Cloudwatch Agent 側設定

EC2インスタンスに CloudwatchLogs 用のポリシーをアタッチ。

Send2Cloudwatch
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogStreams"
    ],
      "Resource": [
        "arn:aws:logs:*:*:*"
    ]
  }
 ]
}

パッケージ更新、awslogsインストール

console
sudo yum update -y
# ubuntu,centos,redhat はこう
curl https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py -O
sudo python ./awslogs-agent-setup.py --region us-east-1
# Amazon Linux ならこっち
# sudo yum install awslogs

バージョン確認

console
$ /var/awslogs/bin/awslogs-version.sh
略
/etc/cron.d/awslogs_log_rotate version:
# Version: 1.4.3
CloudWatch Logs Plugin Version:
You are using pip version 6.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
---
Metadata-Version: 1.1
Name: awscli-cwlogs
Version: 1.4.4
Summary: AWSCLI CloudWatch Logs plugin
Home-page: http://aws.amazon.com/cli/
Author: Amazon
Author-email: UNKNOWN
License: Amazon Software License
Location: /var/awslogs/lib/python2.7/site-packages
Requires: awscli, six, python-dateutil
AWS CLI Version

ログファイル送信設定、先ほどの secure_sshd を指定する

/var/awslogs/etc/awslogs.conf
# 元のmessageログ送信は今回使わないのでコメントアウト
# [/var/log/messages]
# datetime_format = %b %d %H:%M:%S
# file = /var/log/messages
# buffer_duration = 5000
# log_stream_name = {instance_id}
# initial_position = start_of_file
# log_group_name = /var/log/messages

# 普通にsecureログ送るならこう
# [/var/log/secure]
# datetime_format = %b %d %H:%M:%S
# file = /var/log/secure
# buffer_duration = 5000
# log_stream_name = {instance_id}
# initial_position = start_of_file
# log_group_name = /var/log/secure

[/var/log/secure_sshd]
datetime_format = %b %d %H:%M:%S
file = /var/log/secure_sshd
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/secure_sshd

必要に応じてプロキシ設定

/var/awslogs/etc/proxy.conf
HTTP_PROXY=proxyserver:8080
HTTPS_PROXY=proxyserver:8080
NO_PROXY=

サービス再起動&起動設定

console
sudo service awslogs start
sudo chkconfig awslogs on

Logs への送信ログ確認するなら

console
sudo tail /var/log/awslogs.log

動きました

image.png

参考

CloudWatch Logs エージェントのリファレンス – Amazon CloudWatch ログ
クイックスタート: 実行中の EC2 Linux インスタンスに CloudWatch Logs エージェントをインストールして設定する – Amazon CloudWatch ログ
Linux環境設定/sshによる不正アクセスを確認する – Linuxと過ごす
Rsyslog – Wikinote
システム管理の基礎 syslogdの設定をマスターしよう:Linux管理者への道(3) – @IT
必読!ログファイルとディレクトリ | Think IT(シンクイット)

続きを読む

Cronから実行するEC2スナップショットスクリプト

実行条件

  • awscliがインストールされている
  • IAMロールなどでEC2周りの権限を解放しておく
#!/bin/sh

# 取得したインスタンスのidを並べる
INSTANCE_ID=(i-xxxxx1 i-xxxxx2 i-xxxxx3)

SHELLDIR=`dirname ${0}`
SHELLDIR=`cd ${SHELLDIR}; pwd`
SHELLNAME=`basename $0`

LOG_DIR="/var/log"
LOG_SAVE_PERIOD=14
LOG_FILE="${LOG_DIR}/${SHELLNAME}.log"
echo $LOG_FILE

REGION=ca-central-1
SNAPSHOTS_PERIOD=2

AWS="/usr/bin/aws --region ${REGION}"


rotate_log() {
    (( cnt=${LOG_SAVE_PERIOD} ))
    while (( cnt > 0 ))
    do
        logfile1=${LOG_FILE}.$cnt
        (( cnt=cnt-1 ))
        logfile2=${LOG_FILE}.$cnt
        if [ -f $logfile2 ]; then
            mv $logfile2 $logfile1
        fi
    done

    if [ -f $LOG_FILE ]; then
        mv ${LOG_FILE} ${LOG_FILE}.1
    fi
    touch $LOG_FILE
}

print_msg() {
    echo "`date '+%Y/%m/%d %H:%M:%S'` $1" | tee -a ${LOG_FILE}
}

create_snapshot() {
    for ID in `echo $@`
    do
        print_msg "Create snapshot Start"
        VOL_ID=`${AWS} ec2 describe-instances --instance-ids ${ID} --output text | grep EBS | awk '{print $5}'`
        if [ -z ${VOL_ID} ] ; then
            echo ${VOL_ID}
            print_msg "ERR:ec2-describe-instances"
            logger -f ${LOG_FILE}
            exit 1
        fi
        print_msg "ec2-describe-instances Success : ${VOL_ID}"
        ${AWS} ec2 create-snapshot --volume-id ${VOL_ID} --description "Created by SYSTEMBK(${ID}) from ${VOL_ID}" >> ${LOG_FILE} 2>&1
        if [ $? != 0 ] ; then
            print_msg "ERR:${SHELLDIR}/${SHELLNAME} ec2-create-snapshot"
            logger -f ${LOG_FILE}
            exit 1
        fi
        print_msg "Create snapshot End"
    done
}

delete_old_snapshot() {
    for ID in `echo $@`
    do
        VOL_ID=`${AWS} ec2 describe-instances --instance-ids ${ID} --output text | grep EBS | awk '{print $5}'`
        print_msg "Delete old snapshot Start"
        SNAPSHOTS=`${AWS} ec2 describe-snapshots --output text | grep ${VOL_ID} | grep "Created by SYSTEMBK" | wc -l`
        while [ ${SNAPSHOTS} -gt ${SNAPSHOTS_PERIOD} ]
        do
            ${AWS} ec2 delete-snapshot --snapshot-id `${AWS} ec2 describe-snapshots --output text | grep ${VOL_ID} | grep "Created by SYSTEMBK" | sort -k 11,11 | awk 'NR==1 {print $10}'` >> ${LOG_FILE} 2>&1
            if [ $? != 0 ] ; then
                print_msg "ERR:${SHELLDIR}/${SHELLNAME} ec2-delete-snapshot"
                logger -f ${LOG_FILE}
                exit 1
            fi
            SNAPSHOTS=`${AWS} ec2 describe-snapshots | grep ${VOL_ID} | grep "Created by SYSTEMBK" | wc -l`
        done
        print_msg "Delete old snapshot End"
    done
}

rotate_log

print_msg "INF:$SHELLDIR/${SHELLNAME} START"
create_snapshot ${INSTANCE_ID[@]}
delete_old_snapshot ${INSTANCE_ID[@]}
print_msg "INF:$SHELLDIR/${SHELLNAME} END"

exit 0

続きを読む

AWSのEC2で行うCentOS 7の初期設定

AWSのEC2で行うCentOS 7の最低限の初期設定をまとめてみました。まだすべき設定が残っているとは思いますので、こちらを更新していければと思ってい

開発環境

  • Mac OS X(El Capitan) 10.11.6
  • CentOS 7 (x86_64) – with Updates HVM

事前に用意しておく必要があるもの

  • 接続先EC2のパブリックDNS
  • デフォルトユーザ(CentOS 7の場合デフォルトはcentos)
  • EC2からダウンロードした秘密鍵(デフォルトは****.pem)

参考

AWSのEC2にSSH接続

秘密鍵の配置設定

以下のコマンドを実行してEC2からダウンロードした秘密鍵を【.ssh】ディレクトリに配置し、管理しやすくします。

$ mv /Users/ユーザ名/Downloads/秘密鍵名.pem ~/.ssh/

秘密鍵の権限設定

SSHを機能させるためには秘密鍵が公開されていないことが必要ですので、以下のコマンドを実行てし権限の設定をします。

$ chmod 400 ~/.ssh/秘密鍵名.pem

SSH接続

以下のコマンドを実行してAWSのEC2にSSH接続します。

$ ssh -i ~/.ssh/秘密鍵名.pem ユーザ名@パブリックDNS

ログイン完了

以下が表示がされたらログイン完了です。

[centos@ip-パブリックDNS ~]$

CentOS 7の初期設定

SELINUXの無効化

以下のコマンドを実行してSELINUXを無効化します。【Disabled】になったら無効化完了です。

# ステータス確認
$ getenforce

# 設定変更
$ sudo sed -i -e 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

# 再起動
$ sudo reboot

# SSH再接続
$ ssh -i ~/.ssh/秘密鍵名.pem ユーザ名@パブリックDNS

# 無効化確認
$ getenforce

パッケージの更新

以下のコマンドを実行してCentOS 7のパッケージを更新します。

# パッケージの更新
$ sudo yum update -y

パッケージの自動更新設定

以下のコマンドを実行してyum-cronをインストールし、パッケージの自動更新を設定します。

# インストール
$ sudo yum install yum-cron -y

# 有効化確認
$ systemctl list-unit-files | grep yum-cron

# 有効化
$ sudo systemctl enable yum-cron

# 自動更新設定
$ sudo sed -i "s/^apply_updates.*$/apply_updates = yes/g" /etc/yum/yum-cron.conf

# 起動
$ sudo systemctl start yum-cron.service

# 起動確認
$ systemctl status yum-cron.service

タイムゾーンの変更

以下のコマンドを実行してタイムゾーンを変更します。

# 現在の設定確認
$ timedatectl status

# ローカルタイムを【Asia/Tokyo】に変更
$ sudo timedatectl set-timezone Asia/Tokyo

# 現在の設定確認
$ timedatectl status

ロケールとキーマップの変更

以下のコマンドを実行してロケールとキーマップを日本語対応に変更します。

# 現在の設定確認
$ localectl status

# 選択できるキーマップの確認
$ localectl list-keymaps

# ロケールを日本語とUTF-8に変更
$ sudo localectl set-locale LANG=ja_JP.utf8

# キーマップをjp106に変更
$ sudo localectl set-keymap jp106

# 現在の設定確認
$ localectl status

不要なサービスの停止(例:postfix)

以下のコマンドを実行して不要なサービスの停止をします。

# 有効化サービス一覧確認
$ systemctl list-unit-files --type service | grep enabled

# ステータス確認
$ systemctl status postfix.service

# 停止
$ sudo systemctl stop postfix.service

# 無効化
$ sudo systemctl disable postfix.service

# ステータス確認
$ systemctl status postfix.service

ユーザーアカウント追加

ユーザーアカウント追加

以下のコマンドを実行して新規ユーザーアカウントを追加します。今回は【newuser】として作成します。

# newuserを追加
$ sudo adduser newuser

sudo権限の変更

以下のコマンドを実行してsudoersファイルを安全に編集します。

# sudoersファイルの編集
$ sudo visudo

作成したnewuserグループをsudoコマンドがパスワード無しで実行できるように追記します。

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL
+ %newuser       ALL=(ALL)       NOPASSWD: ALL

ユーザーアカウント切り替え

以下のコマンドを実行してnewuserへ切り替えます。

# newuserへ切り替え
$ sudo su - newuser

公開鍵認証設定

公開鍵認証用ファイルの作成

以下のコマンドを実行して公開鍵認証用のディレクトリとファイルを作成します。

# newuserのホームディレクトリに.sshディレクトリを作成
$ mkdir .ssh

# ファイルパーミッションを700(所有者のみ、読み取り、書き込み、削除が可能)に変更
$ chmod 700 .ssh

# authorized_keysを作成
$ touch .ssh/authorized_keys

# ファイルパーミッションを600(所有者のみ、読み取りおよび書き込みが可能)に変更
$ chmod 600 .ssh/authorized_keys

キーペアのパブリックキーをコピー

以下のコマンドを実行してパブリックキーをコンピュータから取得します。

# パブリックキーをコンピュータから取得
$ ssh-keygen -y

# キーを持つファイルのパスを指定
Enter file in which the key is (/Users/****/.ssh/id_rsa): /path_to_key_pair/my-key-pair.pem

表示されたインスタンスのパブリックキー(※以下は例)の末尾の【キーペア名】を除いてコピーします。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6V
hz2ItxCih+PnDSUaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXr
lsLnBItntckiJ7FbtxJMXLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZ
qaeJAAHco+CY/5WrUBkrHmFJr6HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3Rb
BQoQzd8v7yeb7OzlPnWOyN0qFU0XA246RA8QFYiCNYwI3f05p6KLxEXAMPLE

取得したキーペアのパブリックキーをペースト

以下のコマンドを実行して、コピーしたキーペアのパブリックキーを【authorized_keys】にペーストします。

#.ssh/authorized_keysを編集
$ vi .ssh/authorized_keys

追加したユーザーアカウントでAWSのEC2にSSH再接続

以下のコマンドを実行してAWSのEC2にSSH再接続します。

$ ssh -i ~/.ssh/秘密鍵名.pem 追加したユーザーアカウント@パブリックDNS

ログイン完了

以下が表示がされたらログイン完了です。

[centos@ip-パブリックDNS ~]$

ブログ記事の転載になります。

続きを読む

AWSのEC2で行うAmazon Linuxの初期設定

AWSのEC2で行うAmazon Linuxの最低限の初期設定をまとめてみました。まだすべき設定が残っているとは思いますので、こちらを更新していければと思っています。

開発環境

  • Mac OS X(El Capitan) 10.11.6
  • Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type – ami-33c25b55

事前に用意しておく必要があるもの

  • 接続先EC2のパブリックDNS
  • デフォルトユーザ(Amazon Linuxの場合デフォルトはec2-user)
  • EC2からダウンロードした秘密鍵(デフォルトは****.pem)

参考

AWSのEC2にSSH接続

秘密鍵の配置設定

以下のコマンドを実行してEC2からダウンロードした秘密鍵を【.ssh】ディレクトリに配置し、管理しやすくします。

$ mv /Users/ユーザ名/Downloads/秘密鍵名.pem ~/.ssh/

秘密鍵の権限設定

SSHを機能させるためには秘密鍵が公開されていないことが必要ですので、以下のコマンドを実行てし権限の設定をします。

$ chmod 400 ~/.ssh/秘密鍵名.pem

SSH接続

以下のコマンドを実行してAWSのEC2にSSH接続します。

$ ssh -i ~/.ssh/秘密鍵名.pem ユーザ名@パブリックDNS

ログイン完了

以下が表示がされたらログイン完了です。

Last login: Mon Jan 15 17:27:41 2018 from ***.***.***.***

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/

Amazon-linuxの初期設定

パッケージの更新

以下のコマンドを実行してAmazon-linuxのパッケージを更新します。

# パッケージの更新
$ sudo yum update -y

パッケージの自動更新設定

以下のコマンドを実行してyum-cronをインストールし、パッケージの自動更新を設定します。

# インストール
$ sudo yum install yum-cron -y

# 有効化確認
$ sudo chkconfig --list yum-cron

# 有効化
$ sudo chkconfig yum-cron on

# 自動更新設定
$ sudo sed -i "s/^apply_updates.*$/apply_updates = yes/g" /etc/yum/yum-cron.conf

# 起動
$ sudo service yum-cron start

# 起動確認
$ sudo service yum-cron status

タイムゾーンの変更

以下のコマンドを実行してインスタンスのローカルタイムとハードウェアクロックを変更します。

# 現在の設定確認
$ date

# ローカルタイムを【Japan】に変更
$ sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime

# ハードウェアクロックを【Japan】に変更
$ sudo sed -i s/ZONE=\"UTC\"/ZONE=\"Japan\"/g /etc/sysconfig/clock

# システム再起動
$ sudo reboot

# 現在の設定確認
$ date

文字コードを日本語に変更

以下のコマンドを実行して文字コードを日本語対応に変更します。

# 文字コードを日本語に変更
$ sudo sed -i s/LANG=\"en_US.UTF-8\"/LANG=\"ja_JP.UTF-8\"/g /etc/sysconfig/i18n

不要なサービスの停止

以下のコマンドを実行してGUIで不要なサービスの停止することができます。

# 不要サービスの一括設定(GUI)
$ sudo ntsysv

ユーザーアカウント追加

ユーザーアカウント追加

以下のコマンドを実行して新規ユーザーアカウントを追加します。今回は【newuser】として作成します。

# newuserを追加
$ sudo adduser newuser

sudo権限の変更

以下のコマンドを実行してsudoersファイルを安全に編集します。

# sudoersファイルの編集
$ sudo visudo

作成したnewuserグループをsudoコマンドがパスワード無しで実行できるように追記します。

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL
+ %newuser       ALL=(ALL)       NOPASSWD: ALL

ユーザーアカウント切り替え

以下のコマンドを実行してnewuserへ切り替えます。

# newuserへ切り替え
$ sudo su - newuser

公開鍵認証設定

公開鍵認証用ファイルの作成

以下のコマンドを実行して公開鍵認証用のディレクトリとファイルを作成します。

# newuserのホームディレクトリに.sshディレクトリを作成
$ mkdir .ssh

# ファイルパーミッションを700(所有者のみ、読み取り、書き込み、削除が可能)に変更
$ chmod 700 .ssh

# authorized_keysを作成
$ touch .ssh/authorized_keys

# ファイルパーミッションを600(所有者のみ、読み取りおよび書き込みが可能)に変更
$ chmod 600 .ssh/authorized_keys

キーペアのパブリックキーをコピー

以下のコマンドを実行してパブリックキーをコンピュータから取得します。

# パブリックキーをコンピュータから取得
$ ssh-keygen -y

# キーを持つファイルのパスを指定
Enter file in which the key is (/Users/****/.ssh/id_rsa): /path_to_key_pair/my-key-pair.pem

表示されたインスタンスのパブリックキー(※以下は例)の末尾の【キーペア名】を除いてコピーします。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClKsfkNkuSevGj3eYhCe53pcjqP3maAhDFcvBS7O6V
hz2ItxCih+PnDSUaw+WNQn/mZphTk/a/gU8jEzoOWbkM4yxyb/wB96xbiFveSFJuOp/d6RJhJOI0iBXr
lsLnBItntckiJ7FbtxJMXLvvwJryDUilBMTjYtwB+QhYXUMOzce5Pjz5/i8SeJtjnV3iAoG/cQk+0FzZ
qaeJAAHco+CY/5WrUBkrHmFJr6HcXkvJdWPkYQS3xqC0+FmUZofz221CBt5IMucxXPkX4rWi+z7wB3Rb
BQoQzd8v7yeb7OzlPnWOyN0qFU0XA246RA8QFYiCNYwI3f05p6KLxEXAMPLE

取得したキーペアのパブリックキーをペースト

以下のコマンドを実行して、コピーしたキーペアのパブリックキーを【authorized_keys】にペーストします。

#.ssh/authorized_keysを編集
$ vi .ssh/authorized_keys

デフォルトユーザ(ec2-user)を削除する場合

追加したユーザーアカウントでAWSのEC2にSSH再接続

以下のコマンドを実行してAWSのEC2にSSH再接続します。

$ ssh -i ~/.ssh/秘密鍵名.pem 追加したユーザーアカウント@パブリックDNS

ログイン完了

以下が表示がされたらログイン完了です。

Last login: Mon Jan 15 17:27:41 2018 from ***.***.***.***

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/

デフォルトユーザーの削除

以下のコマンドを実行してデフォルトユーザ(ec2-user)とそのホームディレクトリを削除します。

# ec2-userとそのホームディレクトリの削除
$ sudo userdel -r ec2-user

ブログ記事の転載になります。

続きを読む