プライベートサブネット内のインスタンスでyum/dnfを実行する構成
プライベートサブネット内のインスタンスで、yum/dnfを実行する方法を確認します。
今回は以下の2パターンを確認します。
- NATゲートウェイを使用する方法
- VPCエンドポイントを使用する方法
通常、yum/dnfを実行するためには、実行するインスタンスをパブリックサブネットに配置した上で、パブリックアドレスを設定し、直接インターネットにアクセスする形となります。しかし今回ご紹介する方法では、インスタンスにプライベートサブネットに配置し、プライベートアドレスだけを付与します。そのため外部からインスタンスに不正にアクセスされるリスクを低減することができ、システム全体のセキュリティを高めることができます。
構築する環境
VPC内の3つのサブネットを作成します。1つはインターネットにアクセス可能なパブリックサブネットとし、残りの2つは不可なプライベートサブネットとします。
2つのプライベートサブネットにEC2インスタンスを1つずつ配置します。インスタンスは最新のAmazon Linux 2023ベースとします。
パブリックサブネット内にNATゲートウェイを配置します。
2種類のVPCエンドポイントを配置します。1つ目はSystem Manager用のエンドポイントです。同サービスのSession Manager機能で、プライベートサブネット内のインスタンスにアクセスするために使用します。2つ目はS3用のVPCエンドポイントです。後述のAmazon Linux用のdnfリポジトリであるS3バケットにアクセスするために使用します。
検証のシナリオ
プライベートサブネット内のインスタンスからdnfの実行を、以下の2つのパターンで確認します。
- NATゲートウェイを経由して、インターネット上のdnfリポジトリにアクセスし、dnfを実行する ※パターン1
- VPCエンドポイントを経由して、S3バケット上のdnfリポジトリにアクセスし、dnfを実行する ※パターン2
環境構築用のCloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/002
テンプレートファイルのポイント解説
パターン1:NATゲートウェイを経由して、インターネット上のdnfリポジトリにアクセスする
パブリックサブネットにNATゲートウェイを配置する
まずパブリックサブネット周りのリソースを確認します。
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidrBlock
EnableDnsHostnames: true
EnableDnsSupport: true
IGW:
Type: AWS::EC2::InternetGateway
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref IGW
EIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NATGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIP.AllocationId
SubnetId: !Ref PublicSubnet
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp1
VpcId: !Ref VPC
AvailabilityZone: !Sub ${AWS::Region}${AvailabilityZone1}
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
RouteToInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
Code language: YAML (yaml)
インターネットゲートウェイおよびパブリックサブネットを定義します。
パブリックサブネットとは、直接のインターネットゲートウェイ向きのルートを持つサブネットのことです。
今回はパブリックサブネット用のルートテーブルを作成し、インターネットゲートウェイ向けのデフォルトルートを定義します。
デフォルトルートはDestinationCidrBlockプロパティに「0.0.0.0/0」を指定することで作成することができます。
パブリックサブネット内にNATゲートウェイを配置します。
NAT ゲートウェイは、ネットワークアドレス変換 (NAT) サービスです。NAT ゲートウェイを使用すると、プライベートサブネット内のインスタンスは VPC 外のサービスに接続できますが、外部サービスはそれらのインスタンスとの接続を開始できません。
NAT ゲートウェイ
NATゲートウェイを配置することによって、後述のプライベートサブネット内のインスタンス①が、インターネット向けのアウトバウンド通信を実行できるようになります。
ルートテーブルにNATゲートウェイ向きのルートを設定する
プライベートサブネット①周りのリソースを確認します。
Resources:
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp2
VpcId: !Ref VPC
AvailabilityZone: !Sub ${AWS::Region}${AvailabilityZone1}
PrivateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
RouteToNATGateway:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway
PrivateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable1
Code language: YAML (yaml)
プライベートサブネット①内のインスタンスは、NATゲートウェイを経由してdnfを実行します。
そのため同サブネット用のルートテーブルを用意し、NATゲートウェイ向けのデフォルトルートを定義します。
パターン2:VPCエンドポイントを経由して、S3バケット上のdnfリポジトリにアクセスする
VPCエンドポイント向きのルートテーブルを用意する
プライベートサブネット②周りのリソースを確認します。
Resources:
PrivateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PrivateSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRouteTable2
Code language: YAML (yaml)
プライベートサブネット②内のインスタンスは、S3エンドポイント経由でdnfを実行します。そのため同サブネット用のルートテーブルを用意します。
なお具体的なルートの定義は、エンドポイント定義時に指定します。
S3エンドポイントはAmazon Linux用のdnf/yumリポジトリへのアクセスを許可する
S3エンドポイント関係のリソースを確認します。
Resources:
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: '*'
Action:
- s3:GetObject
Resource:
- !Sub "arn:aws:s3:::al2023-repos-${AWS::Region}-de612dc2/*"
RouteTableIds:
- !Ref PrivateRouteTable2
ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
VpcId: !Ref VPC
Code language: YAML (yaml)
通常、dnf/yumを実行するためには、インターネット上にあるdnf/yumリポジトリにアクセスする必要があります。ただ例外的に、EC2インスタンスのOSがAmazon Linux系の場合、S3用のVPCエンドポイントを設置することで、インターネットを経由することなく、同OS用のdnf/yumリポジトリにアクセスすることができます。
Amazon Linux リポジトリは、Amazon Simple Storage Service (Amazon S3) バケットでホストされます。インターネット接続なしでインスタンスにパッケージを更新したりインストールしたりするには、S3 Amazon Virtual Private Cloud (Amazon VPC) ゲートウェイエンドポイントを作成します。S3 VPC ゲートウェイエンドポイントに、リポジトリバケットへのアクセスを許可するポリシーを含めます。次に、VPC エンドポイントをインスタンスサブネットのルーティングテーブルに関連付けます。
Amazon Linux 1 または Amazon Linux 2 を実行している EC2 インスタンスで、インターネットにアクセスせずに yum を更新したり、パッケージをインストールしたりするにはどうすればよいですか?
今回の構成では、Amazon Linux 2023のEC2インスタンスを作成します。同インスタンスがS3上のリポジトリにアクセスするために必要なポリシーに関しては、以下の通り言及されています。
{
"Statement": [
{
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::al2023-repos-us-east-1-de612dc2/*"
]
}
]
}
Code language: JSON / JSON with Comments (json)
上記に従い、VPCエンドポイントのAction・Resourceプロパティを設定します。RouteTableIdsプロパティに、先述のプライベートサブネット②用のルートテーブルを指定します。
プライベートサブネット内のインスタンスには、パブリックアドレスは不要
EC2関係のリソースを確認します。
Resources:
Instance1:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref InstanceProfile
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet1
GroupSet:
- !Ref InstanceSecurityGroup
Instance2:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref InstanceProfile
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet2
GroupSet:
- !Ref InstanceSecurityGroup
Code language: YAML (yaml)
特別な設定は不要です。
2つのインスタンスを、2つのプライベートサブネットに1つずつ配置します。
ポイントはパブリックアドレスを設定する必要はないという点です。
インスタンス①が通信する場合、インターネットに抜ける際に、NATゲートウェイに付与したElastic IPアドレスを使用するため、パブリックアドレスは不要です。
インスタンス②の場合は、そもそもインターネットを経由しないため、パブリックアドレスが不要です。
SSM Session Manager経由でEC2インスタンスにアクセスする
EC2インスタンスへのアクセスは、キーペアを使用したSSHによるアクセスが一般的ですが、SSM Session Managerを使用することでもアクセスすることが可能です。
同サービスを使用してEC2インスタンスにアクセスするためには、同サービス向けのエンドポイントの設置、同エンドポイント用のセキュリティグループの作成、同サービスにアクセスする権限を含むIAMロールの作成とインスタンスへのアタッチが必要となります。
詳細は以下のページをご確認ください。
環境構築
CloudFormationを使用して本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
AWS CLIからCloudFormationを実行する手順については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- インスタンス1のID:i-02c9af257d624677e
- インスタンス2のID:i-0635909198866aa1b
- PrivateSubet1のID:subnet-091d74d3795b13935
- PrivateSubet2のID:subnet-0a3135f67e2a4dffd
- NATゲートウェイのID:nat-06dc9f13d6fbb74b7
- S3用VPCエンドポイントのID:vpce-0ad8a5eb1d7adcfbe
AWS Managemet Consoleでもリソースの作成状況を確認します。
まずパターン1のルートテーブルを確認します。
NATゲートウェイ向けのデフォルトルートが定義されています。このルートによって、NATゲートウェイを通じてインターネット上のdnf/yumリポジトリにアクセスすることができます。
次にパターン2のルートテーブルを確認します。
S3用VPCエンドポイント向けのルートが定義されています。このルートの送信先にはプレフィックスリストが設定されています。リストの中身は以下の通りです。
10行分のCIDRがエントリーされています。つまり先ほどのルート1行を定義することによって、送信先が上記だった場合は、S3用VPCエンドポイントにルーティングされるということになります。
動作確認1:NATゲートウェイ経由のdnf
準備が整いましたので、実際に挙動を確認します。
まずNATゲートウェイ経由のdnfを確認します。
インスタンス①にSSM Session Manager経由でアクセスします。
<meta charset="utf-8">$ aws ssm start-session \
--target i-02c9af257d624677e
...
sh-4.2$
Code language: Bash (bash)
インターネットにアクセスできるかPingで確認します。
sh-4.2$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=104 time=2.88 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=104 time=2.43 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=104 time=2.47 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=104 time=2.48 ms
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 2.432/2.568/2.888/0.185 ms
Code language: Bash (bash)
確かにNATゲートウェイ経由で、インターネットにアクセスすることができます。
それではdnfを実行します。
sh-4.2$ sudo dnf install httpd -y
...
Installed:
httpd.x86_64 0:2.4.48-2.amzn2
...
Complete!
Code language: Bash (bash)
正常に実行できました。
NATゲートウェイを経由して、インターネット上のdnfリポジトリにアクセスし、dnfが実行できることがわかりました。
動作確認2:VPCエンドポイント経由のdnf
続いてS3エンドポイント経由のdnfを確認します。
インスタンス②にSSM Session Manager経由でアクセスします。
$ aws ssm start-session \
--target i-0635909198866aa1b
...
sh-4.2
Code language: Bash (bash)
インターネットにアクセスできるかPingで確認します。
sh-4.2$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
28 packets transmitted, 0 received, 100% packet loss, time 27624ms
Code language: Bash (bash)
やはりできません。プライベートサブネット②には、インターネットに抜けられるルートがないためです。
それではdnfを実行します。
sh-4.2$ sudo dnf install httpd -y
...
Installed:
httpd.x86_64 0:2.4.48-2.amzn2
...
Complete!
Code language: Bash (bash)
正常に実行できました。
VPCエンドポイントを経由して、S3バケット上のdnfリポジトリにアクセスし、dnfを実行できることがわかりました。
まとめ
プライベートサブネット上のEC2インスタンスで、dnf/yumを実行する方法を2パターン確認しました。
1つ目はNATゲートウェイを経由して、インターネット上のdnf/yumリポジトリにアクセスし、dnf/yumを実行する方法です。
2つ目はVPCエンドポイントを経由して、S3バケット上のdnf/yumリポジトリにアクセスし、dnf/yumを実行する方法です。
プライベートサブネットにインスタンスを配置することによって、インスタンスに不正にアクセスされるリスクを低減することができ、システム全体のセキュリティを高めることができます。今回ご紹介した方法は、その一助となるでしょう。