はじめに
今回は、AmazonLinux2023のEC2を使用してプロキシをCloudFormationで作成していきます。
本記事は、環境構築編ということで、後述の構成図の構成をCloudFormationで構築するところまでの回となります。
次回検証編で、SSM SessionManagerを使用してプライベートサブネットに配置したEC2インスタンスにアクセスするためにVPCエンドポイントを作成します。CloudFormationで作成するため以下を参考にしていきます。
Systems Manager のために VPC エンドポイントを使用して EC2 インスタンスのセキュリティを強化する - AWS Systems Manager
Amazon VPC でインターフェイス VPC エンドポイントを使用するように Systems Manager を設定することで、マネージドインスタンスのセキュリティ体制をさらに改善する方法を説明します。
構成図

CloudFormationで構築
CloudFormationテンプレートは以下にございます。
ダウンロードしてデスクトップなど任意のフォルダに保存します。
GitHub - kosments/forward-proxy-ec2
Contribute to kosments/forward-proxy-ec2 development by creating an account on GitHub.
CloudFormation:YAMLテンプレートのポイント
YAMLテンプレートのポイントを記述します。
forward-proxy-vpc.yml
- VPC (Virtual Private Cloud): これは仮想ネットワークで、AWSリソースが起動するプライベートな分離された領域です。このコードでは、
CidrBlock
(VPCのIPv4 CIDRブロック)を指定し、DNSサポートとDNSホスト名を有効にしています。 - Internet Gateway: VPCとインターネットとの間のゲートウェイです。これにより、VPC内のインスタンスがインターネットにアクセスできるようになります。
- Subnets: VPC内に作成されるサブネットです。このコードではパブリックサブネットとプライベートサブネットが作成されます。それぞれ異なるCIDRブロックと利用可能ゾーンが指定されています。
- Route Tables: ネットワークトラフィックのルーティングを制御するためのルートテーブルです。このコードではパブリックルートテーブルとプライベートルートテーブルが作成されます。パブリックルートテーブルにはインターネットゲートウェイへのルートが追加されています。
- Route Table Associations: サブネットとルートテーブルの関連付けです。これにより、サブネットから送信されるトラフィックが適切なルートテーブルを使用するようになります。
Resources:
# ------------------------------ #
# VPC
# ------------------------------ #
Vpc:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'vpc']]
# ------------------------------ #
# InternetGateway
# ------------------------------ #
Igw:
Type: 'AWS::EC2::InternetGateway'
Properties:
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'igw']]
AttachGateway:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
VpcId: !Ref Vpc
InternetGatewayId: !Ref Igw
# ------------------------------ #
# Subnet
# ------------------------------ #
PublicSubnet1a:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PublicSubnet1aCidr
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'pblcsbnt1a']]
PrivateSubnet1a:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PrivateSubnet1aCidr
AvailabilityZone: ap-northeast-1a
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'prvtsbnt1a']]
# ------------------------------ #
# RouteTable
# ------------------------------ #
PublicRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'pblcrttbl']]
PublicRoute:
Type: 'AWS::EC2::Route'
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref Igw
PrivateRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Join ['-', [!Ref 'Env', !Ref 'ResourceName', 'prvtrttbl']]
# ------------------------------ #
# RouteTableAssociation
# ------------------------------ #
PublicSubnetRouteTableAssociation1a:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref PublicSubnet1a
RouteTableId: !Ref PublicRouteTable
PrivateSubnetRouteTableAssociation1a:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref PrivateSubnet1a
RouteTableId: !Ref PrivateRouteTable
forward-proxy-ec2.yml
- Launch Templates:
ProxyLaunchTemplate
とClientLaunchTemplate
は、それぞれプロキシサーバとクライアントサーバのEC2インスタンスを起動するためのテンプレートです。これらは、インスタンスタイプ、AMI ID、キーペア、IAMインスタンスプロファイル、ネットワークインターフェース設定など、インスタンス起動時の設定を定義します。 - EC2 Instances:
ProxyEc2Instance
とClientEc2Instance
は、上記の起動テンプレートを使用して作成されるEC2インスタンスです。プロキシサーバはパブリックサブネットに、クライアントサーバはプライベートサブネットに配置されます。Amiの指定をパラメータで受け取るようにしています。AmiIDは、EC2コンソール>[AMI]>[AMIカタログ]からAmazonLinux2023のIDを使用します。 - Security Group:
EC2SecurityGroup
は、これらのEC2インスタンスに適用されるセキュリティグループです。このセキュリティグループは、インバウンドとアウトバウンドのトラフィックを制御します。 - User Data: これらのEC2インスタンスにはユーザデータが指定されています。これは、インスタンス起動時に実行されるシェルスクリプトです。プロキシサーバではSquidをインストールし設定し、クライアントサーバではcurlコマンドのプロキシ設定を行っています。

Resources:
# ------------------------------ #
# Proxy LaunchTemplate
# ------------------------------ #
ProxyLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Join ['-', [!Ref Env, !Ref ResourceName, 'proxy-launchtemplate']]
LaunchTemplateData:
KeyName: !Ref Keypair
ImageId: !Ref AmiId
InstanceType: t2.micro
IamInstanceProfile:
Arn: !GetAtt Ec2InstanceProfile.Arn
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: 0
SubnetId: !Ref PublicSubnetId
Groups:
- !Ref EC2SecurityGroup
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Name
Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'ec2-proxy']]
UserData:
Fn::Base64: |
#!/bin/bash
yum -y update
yum -y install squid
# Squid設定ファイルのバックアップ
cp /etc/squid/squid.conf /etc/squid/squid.conf.bak
# Squid設定ファイルの編集
sed -i 's/#cache_dir ufs \/var\/spool\/squid 100 16 256/cache_dir ufs \/var\/spool\/squid 100 16 256/g' /etc/squid/squid.conf
echo ".google.com" >> /etc/squid/blacklist.acl
echo -e "acl BLACKLIST dstdomain \"/etc/squid/blacklist.acl\"\nhttp_access deny BLACKLIST\nhttp_access allow all\n$(cat /etc/squid/squid.conf)" > /etc/squid/squid.conf
systemctl start squid
systemctl enable squid
lsof -i:3128
# ------------------------------ #
# Client LaunchTemplate
# ------------------------------ #
ClientLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Join ['-', [!Ref Env, !Ref ResourceName, 'client-launchtemplate']]
LaunchTemplateData:
KeyName: !Ref Keypair
ImageId: !Ref AmiId
InstanceType: t2.micro
IamInstanceProfile:
Arn: !GetAtt Ec2InstanceProfile.Arn
NetworkInterfaces:
- AssociatePublicIpAddress: false
DeviceIndex: 0
SubnetId: !Ref PrivateSubnetId
Groups:
- !Ref EC2SecurityGroup
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Name
Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'ec2-client']]
UserData:
Fn::Base64: |
#!/bin/bash
echo 'proxy = "http://10.0.0.x:3128"' >> ~/.curlrc
# ------------------------------ #
# Proxy EC2Instance
# ------------------------------ #
ProxyEc2Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref ProxyLaunchTemplate
Version: !GetAtt ProxyLaunchTemplate.LatestVersionNumber
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: 0
SubnetId: !Ref PublicSubnetId
GroupSet:
- !Ref EC2SecurityGroup
# ------------------------------ #
# Client EC2Instance
# ------------------------------ #
ClientEc2Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref ClientLaunchTemplate
Version: !GetAtt ClientLaunchTemplate.LatestVersionNumber
NetworkInterfaces:
- AssociatePublicIpAddress: false
DeviceIndex: 0
SubnetId: !Ref PrivateSubnetId
GroupSet:
- !Ref EC2SecurityGroup
# ------------------------------ #
# EC2 SecurityGroup
# ------------------------------ #
EC2SecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupName: !Join ['-', [!Ref Env, !Ref ResourceName, 'sg-for-ec2']]
GroupDescription: Security group for WebApServerEC2
VpcId: !ImportValue Vpc
Tags:
- Key: Name
Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'sg-for-ec2']]
# ------------------------------ #
# SSM Endpoint SecurityGroup
# ------------------------------ #
SsmEndpointSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: !ImportValue Vpc
GroupName: !Join ['-', [!Ref Env, !Ref ResourceName, 'sg-for-ssm-endpoint']]
GroupDescription: Security group for SsmEndpoint
Tags:
- Key: Name
Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'sg-for-ssm-endpoint']]
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: Allow https traffic
# ------------------------------ #
# VPC Endpoint
# ------------------------------ #
EC2Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ec2"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !ImportValue Vpc
SubnetIds:
- !Ref PrivateSubnetId
SecurityGroupIds:
- !Ref SsmEndpointSecurityGroup
# Tags:
# - Key: Name
# Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'endpoint-ec2']]
EC2MessageEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ec2messages"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !ImportValue Vpc
SubnetIds:
- !Ref PrivateSubnetId
SecurityGroupIds:
- !Ref SsmEndpointSecurityGroup
# Tags:
# - Key: Name
# Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'endpoint-ec2messages']]
SsmEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssm"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !ImportValue Vpc
SubnetIds:
- !Ref PrivateSubnetId
SecurityGroupIds:
- !Ref SsmEndpointSecurityGroup
# Tags:
# - Key: Name
# Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'endpoint-ssm']]
SsmAgentEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ssmmessages"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !ImportValue Vpc
SubnetIds:
- !Ref PrivateSubnetId
SecurityGroupIds:
- !Ref SsmEndpointSecurityGroup
# Tags:
# - Key: Name
# Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'endpoint-ssmagent']]
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !ImportValue Vpc
RouteTableIds:
- !ImportValue PrivateRouteTable
# Tags:
# - Key: Name
# Value: !Join ['-', [!Ref Env, !Ref ResourceName, 'endpoint-s3']]
スタックの作成
早速、CloudFormationを使用してリソースを作成していきます。
手順は、以下の通りで、リンクにも詳細がございます。
- CloudFormation画面を開きスタックの作成>新しいソースを使用(標準)を選択
- テンプレートの準備完了>テンプレートファイルのアップロードを選択して、保存したymlを選択
- スタックに任意の名称を入力して、パラメータは環境に合わせて変更>次へを選択。※後述の手順に従う場合、デフォルト値でOK
- スタックオプションは特に変更せず、次へを選択
- レビュー画面を確認して送信を選択
forward-proxy-vpc.ymlの実行
問題なくスタックが作成されました。

forward-proxy-ec2.ymlの実行
こちらも問題なくスタックが作成されましたので、構成図のような形でリソースが揃いました。

まとめ
今回は、プロキシサーバとしてのEC2インスタンスの構築を実施しました。 次回検証編では、実際にクライアントのEC2インスタンスからインターネットに通信してみて、プロキシサーバの動作を確認していきます。
最後までご覧いただきありがとうございました。
コメント