ちょっと話題の記事

Systems ManagerのRunCommandでSSHを使わずにShellライクにコマンドを実行する

2018.03.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

おはようございます。加藤です。
今日はSystems Managerを使ってEC2の中身をSSHせずに管理する方法を紹介します。
SSHレスによるメリットは以下のようなものがあります。

  • 公開鍵・秘密鍵を管理しなくてよい
  • ネットワークが繋がっていなくてもインバウンドを許可していなくても操作できる

EC2→SSM APIへのアウトバウンド通信が必要です。よって、インターネットへのアウトバウンドを開放する必要があります。
AWS Systems Manager のセットアップ | Systems Manager の前提条件
アウトバウンドをさらに絞りたい場合は、PrivateLinkを使用します。
PrivateLinkがリリースし新たにEC2, Systems Manager, ELB, Kinesis, Service CatalogがVPCエンドポイントに対応しました

私はTerraformでAWSを触ることが多いので、抜粋ですがTerraformのコードも記載しておきます。

環境・前提

項目 バージョン
MacOS 10.13.3(17D102)
Go 1.9.3
ssm-sh v0.3.0

手順

EC2にアタッチするロールを作成

  1. IAM管理画面に切り替え
  2. ロールメニューを選択
  3. ロール作成
    1. ロールを使用するサービスに"EC2"を選択
    2. "AmazonEC2RoleforSSM"をアタッチ
    3. 任意のロール名を指定する(ここでは"AmazonEC2RoleforSSM"とした)

iam.tf

resource "aws_iam_instance_profile" "ec2role_for_ssm" {
  name  = "ec2role_for_ssm"
  role = "${aws_iam_role.ec2role_for_ssm.name}"
}

resource "aws_iam_role" "ec2role_for_ssm" {
  name = "EC2RoleforSSM"
  path = "/"
  
  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Principal": {
               "Service": "ec2.amazonaws.com"
            },
            "Effect": "Allow",
            "Sid": ""
        }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "ec2role_for_ssm_attachment0" {
    role = "${aws_iam_role.ec2role_for_ssm.name}"
    policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
}

管理するEC2を作成

  1. EC2管理画面に切り替え
  2. セキュリティグループを作成
    1. インバウンド許可なし
    2. アウトバウンド全許可
  3. EC2を2台作成
    1. 作成したセキュリティグループを割り当て
    2. 作成したIAMロールを割り当て

セキュリティグループ

方向 プロトコル ポート範囲 送信元/先
アウトバウンド すべて すべて 0.0.0.0/0
アウトバウンド すべて すべて ::/0

インスタンスパラメータ

インスタンス名 タイプ AMI_ID
amzn t2.micro ami-ceafcba8
amzn2 t2.micro ami-c2680fa4

security_group.tf

## Outbound only
### security group
resource "aws_security_group" "outbound_only" {
  name        = "outbound_only"
  description = "outbound_only"
  vpc_id      = "${aws_vpc.main.id}"

  tags {
    Name = "outbound_only"
    Project = "${var.project["name"]}"
    DeployBy = "Terraform"
  }
}

### security group rule

resource "aws_security_group_rule" "outbound_only_rule_egress0" {
    type = "egress"
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]

    security_group_id = "${aws_security_group.outbound_only.id}"
}

instance.tf

resource "aws_instance" "amzn1" {
    ami = "ami-ceafcba8"
    instance_type = "t2.micro"
    subnet_id = "${aws_subnet.public0.id}"
    vpc_security_group_ids = ["${aws_security_group.outbound_only.id}"]
    key_name = "${aws_key_pair.main.key_name}"
    iam_instance_profile = "${aws_iam_instance_profile.ec2role_for_ssm.name}"

    tags {
      Name = "amzn1"
      Project = "${var.project["name"]}"
      DeployBy = "Terraform"
    }
}
resource "aws_instance" "amzn2" {
    ami = "ami-c2680fa4"
    instance_type = "t2.micro"
    subnet_id = "${aws_subnet.public1.id}"
    vpc_security_group_ids = ["${aws_security_group.outbound_only.id}"]
    key_name = "${aws_key_pair.main.key_name}"
    iam_instance_profile = "${aws_iam_instance_profile.ec2role_for_ssm.name}"

    tags {
      Name = "amzn2"
      Project = "${var.project["name"]}"
      DeployBy = "Terraform"
    }
}

マネジメントコンソール・AWS CLIから操作する

本記事では紹介しません、参考URLを記載しておきます。

ssm-shから操作する

ssm-shはGo言語で書かれたツールです。Systems Managerのsend commandsを利用しSSHせずにShellライクでコマンドを使えます。  

バージョンが<=1、OSSなので、使用は自己責任でお願い致します。  

インストール

go get -u github.com/itsdalmo/ssm-sh

ヘルプ確認

ヘルプを確認してみます。デフォルトリージョンがeu-west-1になっているので、日本リージョンを明示的に指定する必要があるようです。

ssm-sh   --help
Usage:
  ssm-sh [OPTIONS] <list | run | shell>

Application Options:
  -v, --version  Print the version and exit.

AWS Options:
  -p, --profile= AWS Profile to use. (If you are not using Vaulted).
  -r, --region=  Region to target. (default: eu-west-1)

Help Options:
  -h, --help     Show this help message

Available commands:
  list   List managed instances. (aliases: ls)
  run    Run a command on the targeted instances.
  shell  Start an interactive shell. (aliases: sh)

インスタンス一覧取得

listコマンドを使って管理できるインスタンス一覧を取得します。

ssm-sh -r ap-northeast-1 list
Instance ID         | Name  | State   | Image ID     | Platform         | Version | IP         | Status | Last pinged
i-055d87cb9xxxxxxxx | amzn2 | running | ami-c2680fa4 | Amazon Linux     | 2.0     | 10.0.1.195 | Online | 2018-03-06 09:12
i-0219de9d6xxxxxxxx | amzn1 | running | ami-ceafcba8 | Amazon Linux AMI | 2017.09 | 10.0.0.230 | Online | 2018-03-06 09:12

意図した通りの情報を取得できています。

ワンライナー実行

ワンライナーという言い方は適切でないかもしれません...
コマンド実行が完了後にすぐに操作端末のShellに戻ってくるモードです。
試しにコマンドを実行してみます。

ssh-sh -r (リージョン) run -t (インスタンスID) (コマンド)
### amzn

ssm-sh -r ap-northeast-1 run -t i-0219de9d6xxxxxxxx cat /etc/os-release
Initialized with targets: [i-0219de9d6xxxxxxxx]
Use ctrl-c to abort the command early.


i-0219de9d6xxxxxxxx - Success:
NAME="Amazon Linux AMI"
VERSION="2017.09"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2017.09"
PRETTY_NAME="Amazon Linux AMI 2017.09"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2017.09:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"

### amzn2

ssm-sh -r ap-northeast-1 run -t i-055d87cb9xxxxxxxx cat /etc/os-release
Initialized with targets: [i-055d87cb9xxxxxxxx]
Use ctrl-c to abort the command early.


i-055d87cb9xxxxxxxx - Success:
NAME="Amazon Linux"
VERSION="2.0 (2017.12)"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2.0"
PRETTY_NAME="Amazon Linux 2.0 (2017.12) LTS Release Candidate"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2.0"
HOME_URL="https://amazonlinux.com/"

おお!ばっちり動作していますね

Shellライク

ここが本記事のメインです。実際に触ってみます。

ssh-sh -r (リージョン) shell -t (インスタンスID)
ssm-sh -r ap-northeast-1 shell -t i-055d87cb9xxxxxxxx
Initialized with targets: [i-055d87cb9xxxxxxxx]
Type 'exit' to exit. Use ctrl-c to abort running commands.

» pwd

i-055d87cb9xxxxxxxx - Success:
/usr/bin

» whoami

i-055d87cb9xxxxxxxx - Success:
root

» ping -c 3 amazonaws.com

i-055d87cb9xxxxxxxx - Success:
PING amazonaws.com (72.21.206.80) 56(84) bytes of data.
64 bytes from 206-80.amazon.com (72.21.206.80): icmp_seq=1 ttl=223 time=187 ms
64 bytes from 206-80.amazon.com (72.21.206.80): icmp_seq=2 ttl=223 time=187 ms
64 bytes from 206-80.amazon.com (72.21.206.80): icmp_seq=3 ttl=223 time=188 ms

--- amazonaws.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 187.578/187.785/188.156/0.565 ms

» curl https://checkip.amazonaws.com

i-055d87cb9xxxxxxxx - Success:
54.250.xxx.xxx

» cd /root

i-055d87cb9xxxxxxxx - Success:

» pwd

i-055d87cb9xxxxxxxx - Success:
/usr/bin

» exit

しっかりと動作しました!
cdでディレクトリ移動ができないのは想定どおりです、コマンド1つごとのSSMのRunShellScriptが走っていて連続性が無いためです。
なので以下のような操作も行えません。

  • TUI
  • yes/no など応答を求めるもの

Systems Managerを確認するとしっかりとコマンド履歴が残っていました。

あとがき

前回のブログでSSでの管理についても触れて欲しかったとコメントを頂いたのがきっかけでこの記事を書こうと思いました。
今回は扱いませんでしたが、エージェントを入れればオンプレミスにあるサーバもSSM管理下の置くことができます。
SSMは本当に便利ですね、もっと活用していこうと思います。

最初は自分でツールを作ろうとしましたが、社内で相談してみるとこのツールを教えてもらいブログにしました。