こんにちは。よっしーです(^^)
今日は、EC2にセッションマネージャ経由でSSH接続する方法についてご紹介します。
前提
この記事は下記の記事をベースにしています。
背景
先日、セッションマネージャでEC2環境に接続する方法をご紹介しましたが、今回は、セッションマネージャを経由して、SSH接続する方法をご紹介します。
EC2にセッションマネージャ経由でSSH接続する理由は以下の通りです:
- セキュリティの向上: セッションマネージャは、SSH接続を通常のポート(通常は22番ポート)を使用せずに行うため、ポートスキャンやボットの自動化攻撃から保護されます。これにより、EC2インスタンスへの不正なアクセスを防ぐことができます。
- セッションログの取得: セッションマネージャは、SSHセッションのログをAWS CloudTrailに自動的に記録します。これにより、誰がいつ、どのようなコマンドを実行したかなどの監査が可能になります。セキュリティインシデントの追跡と分析に役立ちます。
- IAMロールによるアクセス制御: セッションマネージャはIAMロールを使用してアクセス権を制御することができます。IAMロールを使用することで、必要な権限を持つユーザーにのみアクセスを許可し、不要な特権の付与を回避できます。
- パブリックIPの不要: 通常のSSH接続では、EC2インスタンスがパブリックIPを持っている必要がありますが、セッションマネージャを使用する場合は、パブリックIPが必要ありません。セッションマネージャは、AWS Systems Managerのエージェントを使用してインスタンスに接続し、VPC内のプライベートIPを使用して通信を行います。
- ポートフォワーディング: セッションマネージャを使用すると、ポートフォワーディングを簡単に設定できます。ポートフォワーディングを使用することで、セッションマネージャを経由してリモートサーバーにアクセスし、リモートサーバー経由で別のサーバーやリソースにアクセスすることができます。
これらの理由から、セッションマネージャを使用することでセキュリティを向上させ、効果的なリモートアクセスを実現できるのです。通常のSSH接続よりも安全であるため、セッションマネージャの使用が推奨されています。
修正内容
下記のファイルを更新します。下記の各セクションに各ファイルの修正内容を記載しています。
modified: security.tf
security.tf
8 – 15行目を削除します。
-resource "aws_security_group_rule" "learn_ec2_ingress" {
- type = "ingress"
- from_port = "22"
- to_port = "22"
- protocol = "tcp"
- cidr_blocks = ["0.0.0.0/0"]
- security_group_id = aws_security_group.learn_ec2_sg.id
-}
~/.ssh/config
下記の内容を追記します。
# SSH over Session Manager
host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
動作確認
AWS環境構築
下記のコマンドを実行します。
terraform fmt
terraform validate
terraform apply
下記のような結果になれば成功です。
Apply complete! Resources: 17 added, 0 changed, 0 destroyed.
Outputs:
ec2_global_ips = [
"xxx.xxx.xxx.xxx",
]
ec2_instance_id = [
"xxx",
]
secretsmanager_secret = "xxx"
secretsmanager_secret_version = "xxx"
秘密鍵の取得
下記のコマンドで秘密鍵を取得します。
# 秘密鍵取得
aws secretsmanager --profile terraform get-secret-value --secret-id learn-awc-ec2-keypair | jq -r .SecretString > learn-awc-ec2-keypair.pem
# 秘密鍵のパーミッション修正
chmod 400 learn-awc-ec2-keypair.pem
SSH接続
下記のコマンドを実行して、秘密鍵を使用したSSH接続を試みる。xxx.xxx.xxx.xxxは、ec2_global_ipsに置き換えてください。
ssh -i learn-awc-ec2-keypair.pem ec2-user@xxx.xxx.xxx.xxx
下記のような結果になれば、想定通りです。
% ssh -i learn-awc-ec2-keypair.pem ec2-user@xxx.xxx.xxx.xxx
ssh: connect to host xxx.xxx.xxx.xxx port 22: Operation timed out
これは、22ポートの開放設定を削除したためです。
セッションマネージャ経由によるSSH接続
下記のコマンドを実行します。xxxは、ec2_instance_idに置き換えてください。
export AWS_PROFILE=terraform
ssh -i learn-awc-ec2-keypair.pem ec2-user@xxx
下記のような結果になれば成功です。
% ssh -i learn-awc-ec2-keypair.pem ec2-user@xxx
The authenticity of host 'xxx (<no hostip for proxy command>)' can't be established.
ED25519 key fingerprint is SHA256:---
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
7 package(s) needed for security, out of 7 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-10-0-1-151 ~]$
解説
security.tf
削除したTerraformコードは、AWSのセキュリティグループに対してインバウンドのSSHトラフィックを許可するルールを作成しています。以下は、このコードの詳細な解説です:
resource "aws_security_group_rule" "learn_ec2_ingress"
: これはTerraformのリソースブロックで、AWSのセキュリティグループルールを作成するための設定を記述します。type = "ingress"
: これはセキュリティグループルールのタイプを指定しています。ここでは「ingress」を指定しているため、インバウンドトラフィックを許可するルールを作成します。from_port = "22"
: これは許可するトラフィックの送信元ポートを指定します。ここではSSHのデフォルトポートである22を指定しています。to_port = "22"
: これは許可するトラフィックの送信先ポートを指定します。SSHのデフォルトポートは22なので、from_portと同じく22を指定しています。protocol = "tcp"
: これは許可するトラフィックのプロトコルを指定します。SSHはTCPプロトコルを使用するため、「tcp」を指定しています。cidr_blocks = ["0.0.0.0/0"]
: これは許可するトラフィックの送信元IPアドレス範囲を指定します。ここでは、どのIPアドレスからでもSSH接続を許可するために「0.0.0.0/0」を指定しています。ただし、これはセキュリティ上のリスクを伴う設定であるため、実際の運用ではより厳密な範囲を指定することが推奨されます。security_group_id = aws_security_group.learn_ec2_sg.id
: これはセキュリティグループルールを適用する対象となるセキュリティグループのIDを指定します。aws_security_group.learn_ec2_sg.id
は、別のTerraformリソースで作成されたセキュリティグループのIDを参照しています。
このコードの目的は、EC2インスタンスに対してSSH接続を許可するために、セキュリティグループのインバウンドルールを作成することです。ただし、セキュリティ上の理由から、実際の環境では「0.0.0.0/0」のような広範囲なIPアドレス範囲を指定せず、必要な範囲のみを許可するように設定することが重要ですが、セッションマネージャ経由にすることで、この設定自体を消すことができるようになり、IPアドレスの範囲を設定する必要がなくなります。
~/.ssh/config
このコードは、AWS Systems Managerを介してSSHセッションを確立するためのSSH ProxyCommand
ディレクティブを定義しています。以下は、コードの説明です:
host i-* mi-*
: この行は、「i-」で始まる(EC2インスタンス)または「mi-」で始まる(DocumentDBクラスター)ホスト名にマッチするパターンを定義しています。これにより、対象のインスタンスやクラスターにSSHで接続しようとした際にマッチする対象が指定されます。ProxyCommand
: このディレクティブは、プロキシ経由でSSH接続を確立するためのコマンドを指定します。この場合、次のようにコマンドが定義されています:sh -c
: この部分はAWS CLIコマンドをサブシェルで実行するための部分です。"aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
: これはAWS CLIコマンドであり、AWS Systems Manager(Session Manager)を使用してSSHセッションを開始します。このコマンドでは、start-session
コマンドを使用して次のパラメーターを指定しています:--target %h
:%h
は実際の対象ホスト名(EC2インスタンスまたはDocumentDBクラスターにマッチするもの)に置き換えられます。これにより、接続対象のインスタンスやクラスターが指定されます。--document-name AWS-StartSSHSession
: これはSSHセッションに使用されるSSMドキュメント(オートメーションドキュメント)を指定します。AWS-StartSSHSession
はSSHセッションのための事前定義されたドキュメントです。--parameters 'portNumber=%p'
: このパラメーターはSSH接続に使用されるポート番号を設定します。%p
はSSHの設定に基づいて適切なポート番号に置き換えられます。
ProxyCommand
ディレクティブにより、Session Managerをセキュアなバスティオンとして使用して、EC2インスタンスやDocumentDBクラスターに直接SSHポートを公開せずにアクセスできるようになります。これにより、IAMロールと細かい権限設定を使用してアクセスを管理できるだけでなく、セキュリティの追加レイヤーを提供します。
おわりに
今日は、EC2にセッションマネージャ経由でSSH接続する方法についてご紹介しました。
これで、SSH接続を安全に実施できるようになったと思います。従来の踏み台サーバも不要で助かりますね。
本記事でご紹介したソースは、下記のリポジトリにあります。
何か質問や相談があれば、遠慮なくコメントしてください。また、エンジニア案件についても、いつでも相談にのっていますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント