Configuration for running yum/dnf on instance in private subnet
We will check how to run yum/dnf on an instance in a private subnet.
In this case, the following two patterns will be identified
- How to use NAT gateways
- How to use VPC endpoints
Normally, to execute yum/dnf, the instance to be executed is placed on a public subnet, set a public address, and access the Internet directly. However, the method introduced here places the instance on a private subnet and gives it only a private address. This reduces the risk of unauthorized access to the instance from the outside and increases the overall security of the system.
Environment
Create three subnets within the VPC, one public subnet with access to the Internet and the other two private subnets without.
Place one EC2 instance on each of the two private subnets. The instances will be based on the latest Amazon Linux 2023.
Place a NAT gateway in the public subnet.
Place two types of VPC endpoints: the first is for System Manager. The second is a VPC endpoint for S3. It is used to access the S3 bucket, a dnf repository for Amazon Linux, described below.
Scenarios
We will check dnf execution from an instance in a private subnet with the following two patterns.
- access the dnf repository on the Internet via the NAT gateway and execute dnf *pattern 1
- access the dnf repository on the S3 bucket via the VPC endpoint and execute dnf *pattern 2
CloudFormation template files
We will build the above configuration using CloudFormation.
The CloudFormation template is placed at the following URL
https://github.com/awstut-an-r/awstut-fa/tree/main/002
Template file points
Pattern 1: Accessing dnf repositories on the Internet via a NAT gateway
Deploy NAT gateways on public subnets
First, we will check the resources around the public subnet.
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)
Define Internet Gateways and Public Subnets.
A public subnet is a subnet with a direct Internet gateway facing route. This time, we will create a route table for the public subnet and define the default route for the Internet gateway. The default route can be created by specifying “0.0.0.0/0” for the DestinationCidrBlock property.
Place the NAT gateway in the public subnet.
A NAT gateway is a Network Address Translation (NAT) service. You can use a NAT gateway so that instances in a private subnet can connect to services outside your VPC but external services cannot initiate a connection with those instances.
NAT gateways
By deploying NAT gateways, instances 1 in the private subnet described below will be able to perform outbound communication for the Internet.
Configure NAT gateway-oriented routes in route table
Check the resources around the private subnet 1.
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)
The instances in the private subnet 1 will run dnf through the NAT gateway. Therefore, prepare a route table for this subnet and define the default route for the NAT gateway.
Pattern 2: Access dnf repository on S3 bucket via VPC endpoint
Prepare route table for VPC endpoints
Check the resources around the private subnet 2.
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)
The instances in the private subnet 2 will run dnf via the S3 endpoint. Therefore, we need to prepare a route table for this subnet.
The specific route definition will be specified when defining the endpoint.
Allow S3 endpoint to access dnf/yum repository for Amazon Linux
Check the resources related to the S3 endpoint.
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)
Normally, in order to run dnf/yum, you need to access a dnf/yum repository on the Internet. However, as an exception, if the OS of your EC2 instance is Amazon Linux, you can access the dnf/yum repository for that OS without going through the Internet by setting up a VPC endpoint for S3.
Amazon Linux repositories are hosted in Amazon Simple Storage Service (Amazon S3) buckets. To update and install packages on your instance without an internet connection, create an S3 Amazon Virtual Private Cloud (Amazon VPC) gateway endpoint. In the S3 VPC gateway endpoint, include a policy that allows access to the repositories buckets. Then, associate the VPC endpoint with the routing table of your instance subnet.
How can I update yum or install packages without internet access on my EC2 instances running Amazon Linux 1 or Amazon Linux 2?
In this configuration, we will create an EC2 instance of Amazon Linux 2023. The policies required for this instance to access the repository on S3 are mentioned below.
{
"Statement": [
{
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::al2023-repos-us-east-1-de612dc2/*"
]
}
]
}
Code language: JSON / JSON with Comments (json)
Set the Action and Resource properties of the VPC endpoint as described above, and specify the route table for the private subnet (2) in the RouteTableIds property as described above.
Instances in private subnets do not need public address
Check the EC2-related resources.
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)
No special configuration is required.
Place two instances, one on each of the two private subnets.
The point is that there is no need to set a public address.
When instance 1 communicates, it does not need a public address because it uses the Elastic IP address given to the NAT gateway when exiting to the Internet.
Instance 2 does not need a public address because it does not go through the Internet in the first place.
Accessing EC2 instance via SSM Session Manager
The most common way to access EC2 instances is via SSH using a key pair, but it is also possible to access them using SSM Session Manager.
To access an EC2 instance using this service, you need to set up an endpoints for the service, create a security group for the endpoint, create an IAM role that includes permissions to access the service, and attach it to the instance.
Please refer to the following page for details.
Architecting
Using CloudFormation, we will build this environment and check its actual behavior.
Create CloudFormation stack and check resources in stacks
Create a CloudFormation stack.
For instructions on how to run CloudFormation from the AWS CLI, please refer to the following page.
After checking the resources for each stack, the following information is available for the main resources created this time.
- ID of Instance 1: i-02c9af257d624677e
- ID of instance 2: i-0635909198866aa1b
- ID of PrivateSubet1: subnet-091d74d3795b13935
- ID of PrivateSubet2: subnet-0a3135f67e2a4dffd
- ID of NAT gateway: nat-06dc9f13d6fbb74b7
- ID of VPC endpoint for S3: vpce-0ad8a5eb1d7adcfbe
We will also check the resource creation status in the AWS Managemet Console.
First, we will check the route table for pattern 1.
The default route for the NAT gateway is defined, and you can access the dnf/yum repository on the Internet through the NAT gateway.
Next, we will check the route table for pattern 2.
A route to the VPC endpoint for S3 has been defined. A prefix list is set for the destination of this route. The contents of the list are as follows
The CIDR is entered for 10 lines. In other words, by defining one route for the VPC endpoint for S3, if the destination is the above, it will be routed to the same endpoint.
Operation check 1: dnf via NAT gateway
Now that we are ready, let’s check the actual behavior.
First, let’s check the dnf via NAT gateway.
Access instance 1 via SSM Session Manager.
$ aws ssm start-session \
--target i-02c9af257d624677e
...
sh-4.2$
Code language: Bash (bash)
Check if you can access the Internet by pinging it.
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)
Sure enough, you can access the Internet through the NAT gateway.
Now run dnf.
sh-4.2$ sudo dnf install httpd -y
...
Installed:
httpd.x86_64 0:2.4.48-2.amzn2
...
Complete!
Code language: Bash (bash)
I was able to run it successfully.
We found that we could access the dnf repository on the Internet through the NAT gateway and run dnf.
Operation check 2: dnf via VPC endpoint
Next, we will check dnf via S3 endpoint.
Access instance 2 via SSM Session Manager.
$ aws ssm start-session \
--target i-0635909198866aa1b
...
sh-4.2
Code language: Bash (bash)
Check if you can access the Internet by pinging it.
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)
It’s still not possible. This is because there is no route to the Internet in private subnet 2.
Now run dnf.
sh-4.2$ sudo dnf install httpd -y
...
Installed:
httpd.x86_64 0:2.4.48-2.amzn2
...
Complete!
Code language: Bash (bash)
We were able to run it successfully.
We found that we can access the dnf repository on the S3 bucket via the VPC endpoint and run dnf.
Summary
We have identified two patterns for running dnf/yum on an EC2 instance on a private subnet.
The first is to access the dnf/yum repository on the Internet via the NAT gateway and run dnf/yum.
The second method is to access the dnf/yum repository on the S3 bucket via the VPC endpoint and run dnf/yum.
Locating instances on a private subnet reduces the risk of unauthorized access to the instances and increases overall system security. The method described in this article will help in this regard.