Dev Talks

[AWS] 如何透過 Systems Manager(SSM) 來連線 Private EC2

CY Chen, 網站工程師 Oct 20, 2022

照片來源:AWS Official website


前言

以往我們連接 private subnet 的 private EC2,會是去透過 Bastion host (跳板機)來進行 private EC2 的連線。

但我們真的需要跳板機才能進行連線嗎?今天將帶大家來使用 AWS Systems Manager (SSM)來取代 Bastion host (跳板機) ,並搭配 AWS CLI 和 proxy-command 來直接讓我們在終端機就可以連線到 private EC2,無需走外網,把安全性再提高一個層級。

行前準備


基礎設置

  • 需要一個 AWS 帳戶,並且擁有 EC2 和 IAM 服務的使用權限。
  • 準備好 VPC 和 VPC endpoints,以及 private subnet。
  • 檢查 EC2 instance AMI 是否有順利安裝好

Systems Manager Agent

P.S. VPC endpoints 的設置可以根據我們的需求,搭配下方前置文件的 5、6、7 點來進行設置。

參考:AWS Systems Manager 前置文件

IAM 設定

User(ssm-user)

  • STS(Security Token Service)。
  • AmazonEC2FullAccess。
  • AmazonSSMFullAccess。

筆者這邊將使用者直接加入 AmazonSSMFullAccess 來使用 SSM 服務,但其實可以根據我們的需求,調整需要開放的權限即可,而不用到全開。

Role(ssm-ec2-role)

  • AmazonEC2RoleforSSM。

我們將讓 EC2 instance 透過 AmazonEC2RoleforSSM,讓我們的 EC2 可以被 AWS 套入角色,就可以使 EC2 來使用 SSM 的某些服務了。

透過 AWS CLI 建立 SSM session

當以上設定完成,我們將具備一個可以使用 SSM 的 EC2 instance,我們將使用終端機搭配 AWS CLI 來開啟 session。

根據 aws-ssm-ec2-proxy-command Readme 來設定

來到這邊,我們已經完成一半了,但離要在終端機,使用 ssh 連接機器,還有一項任務要完成。

AWS 文件 得知使用 ProxyCommand 來建立 ssh 連線,並和遠端機器搭起連線的橋樑,接下來我們將來完成這項任務。再次提醒,必須在前置作業完成的基礎下,才可以使用這種連線方式。

備註

SSH session 是建立一個 TCP 連線。

ProxyCommand 是SSH client 和 server 搭建連接通道的技術,建立一個通道加在另一個通道之上。因此我們透過 SSH session 來啟動 ProxyCommand 通道,進一步進行連線。

操作文件配置

  • 新增 ~/.ssh/aws-ssm-ec2-proxy-command.sh,並貼上以下內容
#!/usr/bin/env sh
######## Source ################################################################
#
# https://github.com/qoomon/aws-ssm-ec2-proxy-command
#
######## Usage #################################################################
# https://github.com/qoomon/aws-ssm-ec2-proxy-command/blob/master/README.md
#
# Install Proxy Command
#   - Move this script to ~/.ssh/aws-ssm-ec2-proxy-command.sh
#   - Ensure it is executable (chmod +x ~/.ssh/aws-ssm-ec2-proxy-command.sh)
#
# Add following SSH Config Entry to ~/.ssh/config
#   host i-* mi-*
#     IdentityFile ~/.ssh/id_rsa
#     ProxyCommand ~/.ssh/aws-ssm-ec2-proxy-command.sh %h %r %p ~/.ssh/id_rsa.pub
#     StrictHostKeyChecking no
#
# Ensure SSM Permissions for Target Instance Profile
#   https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html
#
# Open SSH Connection
#   ssh <INSTACEC_USER>@<INSTANCE_ID>
#   
#   Ensure AWS CLI environemnt variables are set properly
#   e.g. AWS_PROFILE='default' ssh ec2-user@i-xxxxxxxxxxxxxxxx
#
#   If default region does not match instance region you need to provide it like this
#   ssh <INSTACEC_USER>@<INSTANCE_ID>--<INSTANCE_REGION>
#
################################################################################
set -eu

REGION_SEPARATOR='--'

ec2_instance_id="$1"
ssh_user="$2"
ssh_port="$3"
ssh_public_key_path="$4"
ssh_public_key="$(cat "${ssh_public_key_path}")"

if echo "${ec2_instance_id}" | grep -qe "${REGION_SEPARATOR}"
then
  export AWS_DEFAULT_REGION="${ec2_instance_id##*${REGION_SEPARATOR}}"
  ec2_instance_id="${ec2_instance_id%%${REGION_SEPARATOR}*}"
fi

>/dev/stderr echo "Add public key ${ssh_public_key_path} to instance ${ec2_instance_id} for 60 seconds"
aws ssm send-command \
  --instance-ids "${ec2_instance_id}" \
  --document-name 'AWS-RunShellScript' \
  --comment "Add an SSH public key to authorized_keys for 60 seconds" \
  --parameters commands="\"
    mkdir -p ~${ssh_user}/.ssh
    cd ~${ssh_user}/.ssh || exit 1
    authorized_key='${ssh_public_key} ssm-session'
    echo \\\"\${authorized_key}\\\" >> authorized_keys
    sleep 60
    grep -v -F \\\"\${authorized_key}\\\" authorized_keys > .authorized_keys
    mv .authorized_keys authorized_keys
  \""

>/dev/stderr echo "Start ssm session to instance ${ec2_instance_id}"
aws ssm start-session \
  --target "${ec2_instance_id}" \
  --document-name 'AWS-StartSSHSession' \
  --parameters "portNumber=${ssh_port}"
  • 新增 ~/.ssh/config
host i-* mi-*
  IdentityFile ~/.ssh/id_rsa
  ProxyCommand ~/.ssh/aws-ssm-ec2-proxy-command.sh %h %r %p ~/.ssh/id_rsa.pub
  StrictHostKeyChecking no
  • 新增~/.aws/config
[default]
region = ap-northeast-1
output = json
  • 新增 ~/.aws/credentials
[default]
aws_access_key_id =  ...
aws_secret_access_key = ...

參閱文件: aws-ssm-ec2-proxy-command

使用 aws configure 來設定 configuration

參閱文件:aws-ssm-ec2-proxy-command

SSH 連線

ssh ec2-user@i-5xrubytest


結語

最後補充和複習:

  • 透過 SSM Session Manager 我們可以不需要 Bastion host (跳板機) 以及管理 ssh key。
  • 使用 Proxycommand 為我們建立 SSH Tunneling,讓我們更輕鬆及安全進行連線。
  • 加上 AWS CLI SSO 驗證登入,讓系統安全性大幅提升。

以上是對 Systems Manager(SSM) 來連線 Private EC2 初步介紹,此篇文章有任何問題歡迎來信與我討論。 最後,希望透過這篇文章,能讓大家更輕鬆及安全進行連線。 謝謝你的閱讀!


想要閱讀更多來自五倍紅寶石軟體開發的技術分享?歡迎訂閱我們的月報,每月將自動幫你送上最新文章。


分享