SSH接続を理解して、ポートフォワーディングでプライベートネットワークのインスタンスへアクセス
SSHとは
SSH(Secure Shell)は、ネットワーク上で安全に通信するためのプロトコルです。
特にリモートサーバーへの接続に使用され、暗号化された通信を可能とする。
SSHの利用用途
たとえば、SSHは以下のような目的で使用されます:
- リモートサーバーへの接続:
サーバーにログインしてコマンドを実行できます。 - ファイル転送:
scp や sftp コマンドで、安全にファイルを転送します。 - ポートフォワーディング:
通信を暗号化し、VPNのようにセキュアに接続できます。
SSHを実現するために必要なもの
-
リモートサーバーのIPアドレスまたはホスト名
接続先のサーバーのアドレスです(例: 192.168.1.10 や example.com)。 -
SSHクライアント
接続元のコンピュータで、SSHプロトコルを使用するためのソフトウェアです。
LinuxやmacOSには標準でインストールされています。Windowsの場合、PowerShell または Windows Terminal からも利用できますが、PuTTY や OpenSSH for Windows がよく使われます。 -
認証情報(以下のいずれかが必要)
ユーザー名とパスワード
SSH鍵ペア(公開鍵・秘密鍵)
鍵認証方式はセキュリティが高く、推奨されています。接続先のサーバーと接続元の双方で情報が共有されている必要があります。 -
SSHサーバー側の設定
リモートサーバーに SSHサーバー(sshd)がインストールされ、設定が正しく行われている必要があります。 また、クライアント(接続元)からの通信を許可している必要があります。
SSHの基本構文
ssh [オプション] [ユーザー名]@[ホスト名またはIPアドレス]
例:
ssh -i ~/.ssh/id_rsa ec2-user@hostname
ポートフォワーディング
ポートフォワーディングとは
特定のネットワークポートに到達する通信を別の場所に転送する機能です。主に、SSHを用いたSSHポートフォワーディングとして使用される。
主な目的
- リモートサーバー上のサービスに安全にアクセスする
- ファイアウォールやNATによってブロックされている通信を迂回する
- ローカル環境やリモート環境のポートをトンネリングする
ポートフォワーディングの種類
ローカルポートフォワーディング(Local Port Forwarding)
リモートポートフォワーディング(Remote Port Forwarding) ※今回は割愛
ダイナミックポートフォワーディング(Dynamic Port Forwarding) ※今回は割愛
ローカルポートフォワーディング
ローカルホストからリモートサーバーに対してSSHトンネルを構築し、ローカルホストへのパケット通信をリモートサーバーに対して転送する仕組みです。
下記のコマンドを実行すると、ローカルマシンの localhost:9999 への通信は、SSHトンネルを経由してリモートサーバー上の localhost:5432 に転送されます。
ssh -L 9999:localhost:5432 user@remote-server -i ~/.ssh/id_rsa(秘密キー)
※remote-serverがssh接続できることが前提です
SSHトンネルが構築されている状態なので下記をリクエストすると、remote-server:5432にpsql接続ができます。(remote-serverの5432でpsqlからのリクエストを対応できるとする前提)
psql -h localhost -p 9999 -U user dbname
ローカルポートフォワーディングを利用して、ローカルからプライベートネットワークへアクセス
ローカルホストからプライベートネットワークのサーバーに対してポートフォワーディングを利用して、アクセスします。
リソースはTerraformで記載したのでご確認ください。
- bastionはパブリネットワークに存在して、ssh接続可能です。
- targetをプライベートネットワークに存在して、bastionからアクセス可能です。
SSHトンネルを実行するコマンド
ssh -L 9999:<targetのprivate-ip>:5432 ec2-user@<bastionのpublic-ip> -i <bastionのsshに利用する秘密鍵> -N
アクセスしてみる
curl localhost:9999
>> curl: (56) Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
が返ってきました。targetの5432にサービスが何も動いていないですが、targetにアクセスすることが出来ています。
AWSリソース作成
resource "aws_vpc" "example_vpc" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.example_vpc.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
}
resource "aws_subnet" "private_subnet" {
vpc_id = aws_vpc.example_vpc.id
cidr_block = "10.0.2.0/24"
}
resource "aws_internet_gateway" "gateway" {
vpc_id = aws_vpc.example_vpc.id
}
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.example_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gateway.id
}
}
resource "aws_route_table_association" "public_rt_assoc" {
subnet_id = aws_subnet.public_subnet.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_security_group" "bastion_sg" {
vpc_id = aws_vpc.example_vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "target_sg" {
vpc_id = aws_vpc.example_vpc.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["10.0.1.0/24"] # 踏み台サーバーからのみ許可
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "bastion" {
ami = "ami-034bc4e4fcccfe844"
instance_type = "t3.micro"
subnet_id = aws_subnet.public_subnet.id
vpc_security_group_ids = [aws_security_group.bastion_sg.id]
key_name = "iac-key" # 作成したキーペア名を指定
tags = {
Name = "bastion"
}
}
resource "aws_instance" "target" {
ami = "ami-034bc4e4fcccfe844"
instance_type = "t3.micro"
subnet_id = aws_subnet.private_subnet.id
vpc_security_group_ids = [aws_security_group.target_sg.id
]
tags = {
Name = "target"
}
}
output "target_private_id" {
value = aws_instance.target.private_ip
}
output "bastion_public_ip" {
value = aws_instance.bastion.public_ip
}
Discussion