以下のAWSのブログにある通りAWS Systems Manager Session Managerでポートフォワーディング機能を使ってリモートホストにアクセスすることができます。
Webサーバーでも同じように接続できるのかやってみました。
構成
- 構成図は今回メインとなる部分を抜粋して記載しています。
- EC2への接続はSession Managerを使用するのでインターフェイス型VPCエンドポイントを作成します。
- EC2ではAmazon Linux2を使用してWebサーバーにApacheを使用します。
- こちらのドキュメントに記載されている通りAmazon Linux2のリポジトリはS3にあるので構成図には記載していませんがゲートウェイ型VPCエンドポイントを作成します。
環境作成
EC2などの環境は全て以下のCloudFormationテンプレートで作成しました。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: port forwarding Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PrivateSubnet01CIDR
- Label:
default: Parameters for EC2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
VPCCIDR:
Default: 10.1.0.0/16
Type: String
PrivateSubnet01CIDR:
Default: 10.1.0.0/24
Type: String
EC2VolumeSize:
Default: 32
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: ami-0ffac3e16de16665e
Type: AWS::EC2::Image::Id
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: test-vpc
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PrivateSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PrivateSubnet01CIDR
Tags:
- Key: Name
Value: test-private-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: test-private-rtb
PrivateRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet01
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SGSSM:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for EC2
GroupName: EC2-sg-ssm
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
Tags:
- Key: Name
Value: EC2-sg-ssm
VpcId: !Ref VPC
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for EC2
GroupName: EC2-sg-web
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SGSSM
FromPort: 80
IpProtocol: tcp
ToPort: 80
Tags:
- Key: Name
Value: EC2-sg-web
VpcId: !Ref VPC
VPCEndpointSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for Systems Manager
GroupName: SystemsManager-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref EC2SGSSM
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: SystemsManager-sg
VpcId: !Ref VPC
# ------------------------------------------------------------#
# VPC Endpoint
# ------------------------------------------------------------#
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref PrivateRouteTable
ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
VpcEndpointType: Gateway
VpcId: !Ref VPC
SystemsManagerEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
VpcId: !Ref VPC
SubnetIds:
- !Ref PrivateSubnet01
SecurityGroupIds:
- !Ref VPCEndpointSG
SystemsManagerMessageEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
PrivateDnsEnabled: true
ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
VpcId: !Ref VPC
SubnetIds:
- !Ref PrivateSubnet01
SecurityGroupIds:
- !Ref VPCEndpointSG
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EC2IAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:GetObject"
Resource:
- !Join
- ''
- - 'arn:aws:s3:::amazonlinux.'
- !Sub ${AWS::Region}
- '.amazonaws.com/*'
- !Join
- ''
- - 'arn:aws:s3:::amazonlinux-2-repos-'
- !Sub ${AWS::Region}
- '/*'
ManagedPolicyName: iam-policy-ec2
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- !Ref EC2IAMPolicy
RoleName: iam-role-ec2
Tags:
- Key: Name
Value: iam-role-ec2
EC2IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: iam-instanceprofile-ec2
Roles:
- !Ref EC2IAMRole
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
NetworkInterfaces:
- DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PrivateSubnet01
Tags:
- Key: Name
Value: test-ec2-web
UserData: !Base64 |
#!/bin/bash
yum update -y
yum install httpd -y
systemctl start httpd
systemctl enable httpd
echo "Session Manager Port Forwarding Test" > /var/www/html/index.html
EC2SSM:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
NetworkInterfaces:
- DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SGSSM
SubnetId: !Ref PrivateSubnet01
Tags:
- Key: Name
Value: test-ec2-ssm
上記のCloudFormationテンプレートでEC2を2台作成していますが、Nameタグが「test-ec2-ssm」になっているものがSSMマネージドEC2、「test-ec2-web」になっているものがWebサーバーになります。
デプロイは以下のコマンドを実行します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --capabilities CAPABILITY_NAMED_IAM
動作確認
動作確認はローカルPCから行うのでAWS CLIとSession Managerプラグインを準備してください。
インストールは以下のブログを参考にしてください。
AWS CLIとSession Managerプラグインが準備できたら以下のコマンドを実行します。
aws ssm start-session --target test-ec2-ssmのインスタンスID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{"portNumber":["80"],"localPortNumber":["8080"],"host":["test-ec2-webのプライベートIPアドレス"]}'
PowerShellで実行する場合は以下のようにダブルクォーテーションをエスケープしてください
aws ssm start-session --target test-ec2-ssmのインスタンスID --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters '{\"portNumber\":[\"80\"],\"localPortNumber\":[\"8080\"],\"host\":[\"test-ec2-webのプライベートIPアドレス\"]}'
実行したら「http://localhost:8080」にブラウザでアクセスします。
アクセスして以下のように「Session Manager Port Forwarding Test」と表示されれば成功です。
さいごに
今回のようにアクセスが制限された環境で接続確認を行いたい際にインターネットゲートウェイを無理やり置いたり、ALBに繋げたりする必要が無いのでかなり便利な機能だと思いました。