SSHで踏み台サーバにログインし、VPC内のインスタンスに対するIP到達性を確認する

## Pythonスクリプトで作業を自動化

### ユースケース
+ **Pythonスクリプト** と **シェルスクリプト** を組み合わせる。
+ Pythonの**paramiko**モジュールを使って、AWS VPC内の踏み台サーバに自動ログインする
+ 自動ログイン後に、シェルスクリプトで対象のインスタンスに対して踏み台サーバからpingコマンドを複数回実行する

### 想定する環境
+ AWSのVPCは以下のような構成
+ VPC内はICMPが通るように、セキュリティグループを設定済み
+ K-EC2-ProxyHost-1を踏み台としている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699739/aa7764bd-4187-d7d6-a071-70cc3af293f0.png)

#### スクリプト実行環境
macOS Montrey (12.4)
Python 3.10.4

#### 踏み台サーバ環境
Ubuntu jammy (22.04 LTS)
Bash 5.1.16

※　以下の3つのファイルを同じディレクトリに保存してください
+ ssh_ping_check.py 
+ ping_check.sh
+ aws_instance.txt

**AWS Instance List**
``` aws_instance.txt
172.20.10.11
172.20.10.12
172.20.10.254
172.20.20.11
172.20.20.12
```
**Python Script**
``` ssh_ping_check.py
import paramiko

aws_host = 'k-ec2-proxyhost-1.sample.com'
aws_port = 22
aws_user = 'ubuntu'
aws_key_file = '/Users/mashcannu/.ssh/awskey.pem'

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    client.connect(hostname=aws_host, port=aws_port,
                username=aws_user, key_filename=aws_key_file)
except:
    print('Error: Cannot connect to a target host.')
    
ping_script = open('./ping_check.sh').read()
stdin, stdout, stderr = client.exec_command(ping_script)
print(stdout.read().decode())

client.close()
del client, stdin, stdout, stderr
```
**Shell Script**
``` ping_check.sh
#! /bin/sh

input_file=aws_instance.txt

IFS=$'\n';
for target_ip in `cat $input_file`
    do
        ping $target_ip -c 1 -W 1 > /dev/null
            if [ $? -eq '0' ]; then
                echo "Host: $target_ip is reachable"
            else
                echo "Host: $target_ip is NOT reachable"
            fi
    done
```
**実行結果**
```
Host: 172.20.10.11 is reachable
Host: 172.20.10.12 is reachable
Host: 172.20.10.254 is NOT reachable
Host: 172.20.20.11 is reachable
Host: 172.20.20.12 is reachable
```

#### コード解説(Python)

```line.py
import paramiko

aws_host = 'k-ec2-proxyhost-1.sample.com'
aws_port = 22
aws_user = 'ubuntu'
aws_key_file = '/Users/mashcannu/.ssh/awskey.pem'

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
```
+ paramiko モジュールを読み込む
+ ホスト、ポート、ユーザ、鍵ファイル を変数として設定する 

+ SSHClient（）でインスタンスを作成
+ set_missing_host_key_policyは、ホスト鍵が不明なサーバーへの接続時に使用するポリシーの設定

``` line.py
try:
    client.connect(hostname=aws_host, port=aws_port,
                username=aws_user, key_filename=aws_key_file)
except:
    print('Error: Cannot connect to a target host.')
```
+　try節のなかで以下を実施
+　"ssh -i /Users/mashcannu/.ssh/awskey.pem ubuntu@k-ec2-proxyhost-1.sample.com" を実行している

```line.py
ping_script = open('./ping_check.sh').read()
stdin, stdout, stderr = client.exec_command(ping_script)
print(stdout.read().decode())
```
+ シェルスクリプト ping_check.sh を開く
+ **client.exec_command(ping_script)** でシェルスクリプトを実行 ※ここ重要
+ 実行結果を表示

``` line.py
client.close()
del client, stdin, stdout, stderr
```
+ sshセッションをクローズする。
+ 最後の入れないと、色々メッセージが残るのでここで削除
※　[詳しくはこちら](https://github.com/paramiko/paramiko/issues/1078)



#### コード解説(Shell)

``` line.sh
input_file=aws_instance.txt

IFS=$'\n';
for target_ip in `cat $input_file`
```
+ インスタンスリストを呼び込む
+　IFSで、改行(\n)を指定
+　`バッククォート`ではさみcatコマンドを実行。リストを1行ずつ読み込みtarget_ipに代入する


```line.sh
ping $target_ip -c 1 -W 1 > /dev/null
    if [ $? -eq '0' ]; then
        echo "Host: $target_ip is reachable"
    else
        echo "Host: $target_ip is NOT reachable"
    fi
```
+ forループでtarget_ipに対してpingを実行ubuntuでpingコマンドを実行している