yum/dnf on private subnet instances

Yum on instances in Private subnets.

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

  1. How to use NAT gateways
  2. 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

Diagram of yum on instances in privates subnets.

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.

  1. access the dnf repository on the Internet via the NAT gateway and execute dnf *pattern 1
  2. 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.

あわせて読みたい
Accessing Linux instance via SSM Session Manager 【Configure Linux instances to be accessed via SSM Session Manager】 We will check a configuration in which an EC2 instance is accessed via SSM Session Manag...

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.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

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.

To yum for the Internet, set the default route to NAT gateway.

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.

Configure route for S3 endpoint to yum for s3 repository.

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

Route for S3 endpoint contains multiple entries.

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.