IPの認証の壁を超えるためのbackdoorを構築して、そのサーバー経由で色々とやりとりしたいので、その定石設定とコマンド解説。
やりたいことのイメージ
# 構成イメージ
Local PC ← | ssh / when running | → Backdoor Svr ← | ssh/IP Filter | → Remote Svr
# backdoorの起動制御イメージ
python backdoor.py (start|stop)
知識・スキル要件
- viなどのCUI上でのテキストエディティング
- AWSのEC2の構築とAPI経由での操作
- CUIリテラシー
- Python仮想環境構築とコーディング
環境
- Local Client PC: MacOS
- Backdoor Sever: Ubuntu
- Cloud: EC2@aws
Backdoor Serverセットアップ
Backdoor Server
(踏み台サーバー)は、使う時に立ち上げ、不要な時に止めるスクリプトを準備する。まずは、EC2を立ち上げElastic IPを割り当てる。
EC2セットアップ手順
- AWSのWEB ConsoleへログインしEC2メニューへ
- OSはUbuntuを選びInstanceを立ち上げpemを取得し
BACKDOORSVR.pem
で保存 - 立ち上げたEC2のタグ
Name
にBACKDOORSVR
などユニーク値を設定 - セキュリティグループのInboudにSSH(Port 22)を割り当てる
- Elastic IPを取得し立ち上げたEC2に割り当て、固定のIPを取得
- 念のため
AMI
を作成しておく
pemを保存
$ mkdir ~/.pem
$ cd pemの保存先/
$ mv BACDOORSVR.pem ~/.pem/BACKDOORSVR.pem
$ chmod 0600 ~/.pem/BACKDOORSVR.pem
AWS APIへの接続
作業環境準備
-
Pythonの仮想環境の構築を準備し
boto3
をインストールする
kiyota@local:~ $ source ./venv/bin/activate
(venv) kiyota@local:~ $ pip install boto3
AWS APIの認証設定
- EC2が操作できる
aws_access_key_id
とaws_secret_access_key
を取得し~/.aws/credentials
へ追加 - [BACKDOORSVR] は、EC2のインスタンスのタグ名などにすると分かりやすい
- region は、利用中のEC2のAWSのリージョンを指定
cat <<EOF | tee -a ~/.aws/credentials
[BACKDOORSVR]
region = ap-northeast-1
aws_access_key_id = ********************
aws_secret_access_key = ********************
EOF
EC2インスタンスのStart/Stopスクリプト
使い方
python backdoor.py (start|stop)
backdoor.pyスクリプト
import boto3
import sys
PROFILE_NAME = "BACKDOORSVR" # APIの認証設定のプロファイル名を指定
TAG_VALUE = "BACKDOORSVR" # タグNameの設定値を指定
def manage_ec2_instances_by_tag(operation):
session = boto3.Session(profile_name=PROFILE_NAME)
ec2 = session.client('ec2')
filters = [{
'Name': 'tag:Name',
'Values': [TAG_VALUE]
}]
instances = ec2.describe_instances(Filters=filters)
instance_ids = [instance['InstanceId'] for reservation in instances['Reservations'] for instance in reservation['Instances']]
if not instance_ids:
print("No instances found.")
return
if operation == 'stop':
ec2.stop_instances(InstanceIds=instance_ids)
elif operation == 'start':
ec2.start_instances(InstanceIds=instance_ids)
else:
print("Invalid operation. Use 'stop' or 'start'")
return
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python backdoor.py <operation>")
else:
manage_ec2_instances_by_tag(sys.argv[1])
セキュリティ設定
プライベートキーをssh-addで登録
必ず行う
$ ssh-add ~/.ssh/BACKDOORSVR.pem
$ ssh-add -l # 登録されているキーを確認
2048 SHA256:************************* ~/.pem/BACKDOORSVR.pem (RSA)
- 公開鍵を準備する
公開キーをサーバーへの登録
必ず行う
Backdoor Serverに鍵を転送
# Backdoor Server の ~/.ssh/authorized_keys に登録される
ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@ec2-PUBLIC-IP.ap-northeast-1.compute.amazonaws.com
Remove Serverに鍵を登録
# 公開書きをコピーして
(venv) kiyota@local:~ $ cat ~/.ssh/id_rsa.pub |pbcopy
(venv) kiyota@local:~ $ ssh ubuntu@ec2-PUBLIC-IP.ap-northeast-1.compute.amazonaws.com
kiyota@dev:~ $ ssh ユーザー名@リモートサーバー
kiyota@リモートサーバー: ~ $ # pbcopyした鍵を "~/.ssh/authorized_keys2" 追加
各種シェルサンプル
ダウンロード
リモートサーバーからファイルを bash download.sh filepath/file.txt
でダウンロード
#!/bin/bash
PUBLIC_IP=000-000-000-000 # AWS EC2を参照
REMOTE_BASEDIR=/REMOTE_SERVER/HOME/DIR
FILEPATH=$1
DIRPATH=`dirname ${FILEPATH}`
# ディレクトリなければ作成
if [ ! -d ${DIRPATH} ]; then
mkdir -p ${DIRPATH}
fi
echo "FILEPATH: ${FILEPATH}"
scp -o ProxyJump=ubuntu@ec2-${PUBLIC_IP}.ap-northeast-1.compute.amazonaws.com リモートユーザー@リモートサーバー:${REMOTE_BASEDIR}/${FILEPATH} ${FILEPATH}
転送(アップロード)
Local ClientからRemote Serverへbash upload.sh filepath/file.txt
でファイルの転送
#!/bin/bash
PUBLIC_IP=000-000-000-000 # AWS EC2を参照
REMOTE_BASEDIR=/home/ark-dev/ark-site
FILEPATH=$1
echo "FILEPATH: ${FILEPATH}"
scp -o ProxyJump=ubuntu@ec2-${PUBLIC_IP}.ap-northeast-1.compute.amazonaws.com ${FILEPATH} リモートユーザー@リモートサーバー:${REMOTE_BASEDIR}/${FILEPATH}
リモートサーバーのファイル一覧を取得
リモートコマンド bash remote_cmd.sh
を使ってファイル一覧を取得
#!/bin/bash
PUBLIC_IP=000-000-000-000 # AWS EC2を参照
REMOTE_BASEDIR=/home/ark-dev/ark-site
DIRPATH=$1
echo "DIRPATH: ${DIRPATH}"
ssh -o ProxyJump=ubuntu@ec2-${PUBLIC_IP}.ap-northeast-1.compute.amazonaws.com ark-リモートユーザー@リモートサーバー "ls -al ${REMOTE_BASEDIR}/${DIRPATH}"
vimとの連動
Local Client PC上で、Vimを使って特定の作業ディレクトリ内でファイルを編集し保存した時、そのファイルをRemove Serverへ転送する設定
autocmd BufWritePost /作業ディレクトリ/* let fullpath = expand("%:p") | let relpath = substitute(fullpath, "/作業ディレクトリ/", "", "") | execute '!echo "File changed. Running scp." && /アップロードスクリプトがあるディレクトリ/upload.sh '.relpath.' && echo "Upload complete"'
まとめ
個別にスクリプトを準備しエディターと連動させるなどすると結構色々とできるから便利。vscodeとか他にも優秀なエディターがあるが、サーバーサイドでCUIコンソール上でのエンジニアリングが必要なことが多い場合、やはりCUI作業とコーディングを並行してできると便利。レガシーなスタイルかもしれないが、個人的にはこの方法は結構好き。