Connecting a Private Windows EC2 Instance to VPC Resources via S3 Gateway Endpoint
Tags: cloud, cloudcomputing, aws, cloudpractitioner
Published: 2024-07-07 21:01:07

I recently had to connect a private Windows EC2 instance to VPC resources through an S3 Gateway endpoint and run into a couple of issues which has prompted me to write this article.

Many of the online resources that I found focused on Linux servers and provisioning resources from the terminal or as a service. I, however, was doing it via the AWS console and not provisioning the resources through Infrastructure as a service. 

Here are a couple of problems I faced and how I resolved them as well as a step by step guide on how to provision a similar cloud system. If you're a Mac user, download Microsoft Remote Desktop from the App Store. If you're a Windows user, search for remote connection on the Windows start tab.


## Testing your implementation
To test that your implementation works as it should be - a user outside the VPC should not be able to download or upload images to the S3 bucket while a user within the VPC should be able to access the items in the S3 bucket.

This being the case and considering that we're doing all these in a private subnet without internet connection, how do we :

- Download python from the internet?
- Install the aws cli?
- Interact with AWS resources from the terminal?

I spent quite a while trying to understand how to manoeuvre this problem.

A public VPC is public by virtue of it being accessible to the internet.

A private VPC is private by virtue of it being unaccessible to the internet. This is where we're going to place the private EC2 instance.

Now that you have downloaded Microsoft Remote Desktop, lets start.

## Step 1: Create 2 Windows EC2 instances, one public, one private

We're going to use the public EC2 instance as a jump box/ Bastion host, and then connect to the private EC2 instance from the Bastion Host. Both EC2 instances should have a Windows Amazon Machine Image (AMI).


Within Network settings, we're going to specify the subnets. The public EC2 instance should be in the public subnet, while the private  EC2 instance should be in the private subnet.

To ensure that our connections are right, check the route tables. The public subnet should have a local and an internet gateway attached, while the private subnet should only have the local route attached.

Ideally, your VPC's route table should be resemble this - which means you'll have to create a separate route table for the private subnet.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97ycgfo1qtx9qey91j70.png)


## Create the S3 bucket and the VPC S3 gateway endpoint

To create an S3 bucket, navigate to S3 and create one, making sure to block all public S3 access.

To create a VPC S3 gateway endpoint, under VPC navigate to endpoints, search for gateway and create the endpoint. Make sure to attach it to the VPC you created earlier.

Your options while creating could look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mesht73cuwjypts4p17l.png)

For our bucket to now use the S3 endpoint, we need to update the S3 bucket policy. AWS offers a resource to generate S3 bucket policies based on your needs. Mine looks like this:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:SourceVpc": "vpc-id"
                }
            }
        }
    ]
}

```

Essentially, we're denying any S3 interaction with resources that are outside the VPC. Replace bucket name and VPC id with the actual bucket name and VPC Id. 

Your routes should look like these:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/830nqtxc83wnlkn07eae.png)

## Connect the private EC2 instance to the internet via a Nat Gateway
I did a lot of research to avoid using the Nat gateway to get internet access on the private instance but I had to anyway.


[Here's how to create a NAT Gateway.
](https://dev.to/awscloudclubs/vpc-nat-gateway-tutorial-4ibp)

However, be advised that you can't connect to the private subnet with a Nat gateway and a VPC S3 gateway endpoint at the same time. The S3 endpoint gets dropped, and the Nat gateway remains.

To access the Internet on the private subnet, attach the Nat Gateway on the private subnet and then:
- Connect to the public EC2 instance via RDP by passing in the the it's public IP address and the password. You can generate the password by clicking on connect on the EC2, and parsing the  key/value pair you created while creating the EC2 instance.
- Now that you're inside/within the public instance, repeat step 1. Pass the private IP address and the password generated when you click on connect on the private EC2 instance.

Now that you're connected to the private EC2 instance, configure AWS by:
- Opening Microsoft Edge within the private EC2 instance and downloading the latest version of Python for Windows.
- Run the python installer.
- Download a random image from the internet.
- Open the Windows command line and run the following command. You should see python installed, indicating successful installation

```
python --version 
```

- Install the AWS CLI using pip 

```
pip install awscli
```

-  Verify AWS CLI installation by running this command. You should see the installed version of the awscli.

```
aws --version
```

- Now run the following command to configure AWS 

```
aws configure
```

To configure AWS, you'll need:
- Your AWS access key ID which you can find under 'My security credentials'
- Your AWS secret key.
- Specify the region. You can find the region by hovering on the region next to your name on the top right corner of your screen.
- Default output format - json format.


## To NAT Gateway or to S3 gateway 
This depends on your needs. If you want to continue accessing the internet on the private instance, you can continue using the NAT Gateway but be ware of AWS charges before committing.

If you choose to use S3 gateway, drop the NAT Gateway, reattach the S3 gateway endpoint and use endpoint only after you have configured AWS for the private EC2.

## If you choose the S3 gateway endpoint 

And you want to test the connection, follow these instructions:
- Upload an image to the S3 bucket from the private EC2 instance by running the following command on the Windows command line. This should be successful.

```
 aws s3 cp <image> <bucket name>/

```

- On your Mac terminal/ Windows command line outside the VPC, try downloading the image using the following command. Replace with actual names. This should result in a Fatal/ forbidden error.

```
aws s3 cp s3://<bucket name>/<image>
```


## Conclusion
This was a fun and tough project to work on and using Windows made it a bit more complex. Figuring out how to work the remote connection which can raise its own errors can be tedious, but hopefully this gives you a roadmap if you want to interact with Windows EC2 instances.

Another solution would be to provision this through infrastructure as code.