Systems ManagerのRunCommandでSSHを使わずにShellライクにコマンドを実行する
おはようございます。加藤です。
今日はSystems Managerを使ってEC2の中身をSSHせずに管理する方法を紹介します。
SSHレスによるメリットは以下のようなものがあります。
- 公開鍵・秘密鍵を管理しなくてよい
- ネットワークが繋がっていなくても操作できる
- プライベートなネットワークなど
 
私はTerraformでAWSを触ることが多いので、抜粋ですがTerraformのコードも記載しておきます。
環境・前提
| 項目 | バージョン | 
|---|---|
| MacOS | 10.13.3(17D102) | 
| Go | 1.9.3 | 
| ssm-sh | v0.3.0 | 
- VPCの基本的な操作
- EC2の基本的な操作
- AWS CLIの実行環境
- Credentials情報を配置済み
 
- Go言語の実行環境 > 急いで学ぶGo lang#1 概要とセットアップ
手順
EC2にアタッチするロールを作成
- IAM管理画面に切り替え
- ロールメニューを選択
- ロール作成
- ロールを使用するサービスに"EC2"を選択
- "AmazonEC2RoleforSSM"をアタッチ
- 任意のロール名を指定する(ここでは"AmazonEC2RoleforSSM"とした)
 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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を作成
- EC2管理画面に切り替え
- セキュリティグループを作成
- インバウンド許可なし
- アウトバウンド全許可
 
- EC2を2台作成
- 作成したセキュリティグループを割り当て
- 作成したIAMロールを割り当て
 
セキュリティグループ
| 方向 | プロトコル | ポート範囲 | 送信元/先 | 
|---|---|---|---|
| アウトバウンド | すべて | すべて | 0.0.0.0/0 | 
| アウトバウンド | すべて | すべて | ::/0 | 
インスタンスパラメータ
| インスタンス名 | タイプ | AMI_ID | 
|---|---|---|
| amzn | t2.micro | ami-ceafcba8 | 
| amzn2 | t2.micro | ami-c2680fa4 | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ## Outbound only### security groupresource "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 ruleresource "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}"} | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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なので、使用は自己責任でお願い致します。
インストール
| 1 | go get -u github.com/itsdalmo/ssm-sh | 
ヘルプ確認
ヘルプを確認してみます。デフォルトリージョンがeu-west-1になっているので、日本リージョンを明示的に指定する必要があるようです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ssm-sh   --helpUsage:  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 messageAvailable commands:  list   List managed instances. (aliases: ls)  run    Run a command on the targeted instances.  shell  Start an interactive shell. (aliases: sh) | 
インスタンス一覧取得
listコマンドを使って管理できるインスタンス一覧を取得します。
| 1 | ssm-sh -r ap-northeast-1 list | 
| 1 2 3 | Instance ID         | Name  | State   | Image ID     | Platform         | Version | IP         | Status | Last pingedi-055d87cb9xxxxxxxx | amzn2 | running | ami-c2680fa4 | Amazon Linux     | 2.0     | 10.0.1.195 | Online | 2018-03-06 09:12i-0219de9d6xxxxxxxx | amzn1 | running | ami-ceafcba8 | Amazon Linux AMI | 2017.09 | 10.0.0.230 | Online | 2018-03-06 09:12 | 
意図した通りの情報を取得できています。
ワンライナー実行
ワンライナーという言い方は適切でないかもしれません...
コマンド実行が完了後にすぐに操作端末のShellに戻ってくるモードです。
試しにコマンドを実行してみます。
| 1 | ssh-sh -r (リージョン) run -t (インスタンスID) (コマンド) | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ### amznssm-sh -r ap-northeast-1 run -t i-0219de9d6xxxxxxxx cat /etc/os-releaseInitialized 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/"### amzn2ssm-sh -r ap-northeast-1 run -t i-055d87cb9xxxxxxxx cat /etc/os-releaseInitialized 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ライク
ここが本記事のメインです。実際に触ってみます。
| 1 | ssh-sh -r (リージョン) shell -t (インスタンスID) | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ssm-sh -r ap-northeast-1 shell -t i-055d87cb9xxxxxxxxInitialized with targets: [i-055d87cb9xxxxxxxx]Type 'exit' to exit. Use ctrl-c to abort running commands.» pwdi-055d87cb9xxxxxxxx - Success:/usr/bin» whoamii-055d87cb9xxxxxxxx - Success:root» ping -c 3 amazonaws.comi-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 ms64 bytes from 206-80.amazon.com (72.21.206.80): icmp_seq=2 ttl=223 time=187 ms64 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 2000msrtt min/avg/max/mdev = 187.578/187.785/188.156/0.565 msi-055d87cb9xxxxxxxx - Success:54.250.xxx.xxx» cd /rooti-055d87cb9xxxxxxxx - Success:» pwdi-055d87cb9xxxxxxxx - Success:/usr/bin» exit | 
しっかりと動作しました!
cdでディレクトリ移動ができないのは想定どおりです、コマンド1つごとのSSMのRunShellScriptが走っていて連続性が無いためです。
なので以下のような操作も行えません。
- TUI
- yes/no など応答を求めるもの
Systems Managerを確認するとしっかりとコマンド履歴が残っていました。
あとがき
前回のブログでSSでの管理についても触れて欲しかったとコメントを頂いたのがきっかけでこの記事を書こうと思いました。
今回は扱いませんでしたが、エージェントを入れればオンプレミスにあるサーバもSSM管理下の置くことができます。
SSMは本当に便利ですね、もっと活用していこうと思います。
最初は自分でツールを作ろうとしましたが、社内で相談してみるとこのツールを教えてもらいブログにしました。