Creating a Proxy Server on AWS with Terraform: A Step-by-Step Guide

In this blog post, we’ll walk through setting up a proxy server on an AWS EC2 instance using Terraform and configuring it with Apache. This setup is useful for redirecting web traffic, enhancing security, or accessing services within a private network.

Apache configuration script

We are going to launch an EC2 instance with Terraform and automatically execute a bash script setup-proxy.sh to configure Apache.

This script effectively turns the Apache server into a proxy that redirects HTTP traffic to a specified URL over HTTPS. The key lies in the ProxyPass and ProxyPassReverse directives, which handle the forwarding and response modification, respectively. Additionally, by using mod_ssl and configuring SSL settings, it ensures that the traffic between the proxy and the backend server remains encrypted, enhancing security.

Please note that every situation is different, and the effectiveness and appropriateness of this setup may vary depending on your specific requirements and the unique characteristics of your network environment.

Let’s break down what each part of the script does.

yum update -y
yum install -y httpd mod_ssl
  • yum update -y: This command updates the package manager’s database on the server. It ensures that you have the latest updates and security patches.
  • yum install -y httpd mod_ssl: Installs httpd, the Apache HTTP Server, and mod_ssl, an Apache module that provides SSL/TLS support.
cat <<'EOF' > /etc/httpd/conf.d/proxy.conf
<VirtualHost *:80>
  <Proxy *>
    Require all granted
  </Proxy>

  ProxyPass / https://target-url.com/
  ProxyPassReverse / https://target-url.com/

  SSLProxyEngine On
  SSLProxyCheckPeerCN off
  SSLProxyCheckPeerName off
  SSLProxyCheckPeerExpire off
  SSLProxyVerify none
</VirtualHost>
EOF

This block creates a new configuration file for Apache:

  • <VirtualHost *:80>: This line begins the definition of a virtual host listening on port 80 (HTTP).
  • Require all granted: This allows all traffic to pass through the proxy.
  • ProxyPass / https://target-url.com/: This line tells Apache to forward all requests received at the root path to the target URL.
  • ProxyPassReverse / https://target-url.com/: This line ensures that any redirection instructions received from the backend server are modified to point to the proxy, maintaining the illusion that the proxy is the origin of the data.
  • SSLProxyEngine On: Enables SSL/TLS for the proxy.
  • SSLProxyCheckPeerCN off, SSLProxyCheckPeerName off, SSLProxyCheckPeerExpire off: These directives disable various checks for the SSL certificates of the proxied requests. It’s important in scenarios where the backend services use self-signed or non-standard certificates.
  • SSLProxyVerify none: Disables SSL verification entirely.
systemctl enable httpd  # start automatically at system's boot
systemctl start httpd   # start immediately

And we finish by enabling and starting Apache.

Configure a security group

After setting up the Apache configuration for our proxy server, it’s crucial to ensure that the server is secure and accessible as intended. This leads us to the next essential component of our setup: defining the security group rules in AWS using Terraform.

Here we assume that the proxy should only be accessible from the VPC. Feel free to change the rules to match your exact use case.

resource "aws_security_group" "proxy" {
  vpc_id = "XXXXXX"   # your VPC id
  name   = "proxy-security-group"

  # Allow all outbound traffic.
  egress {
    from_port   = 0
    protocol    = "-1"
    to_port     = 0
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow inbound SSH (port 22), HTTP (port 80), and HTTPS (port 443) traffic from the VPC's IP range.
  ingress {
    from_port   = 22
    protocol    = "tcp"
    to_port     = 22
    cidr_blocks = ["10.0.0.0/8"]
  }
  ingress {
    from_port   = 80
    protocol    = "tcp"
    to_port     = 80
    cidr_blocks = ["10.0.0.0/8"]
  }
  ingress {
    from_port   = 443
    protocol    = "tcp"
    to_port     = 443
    cidr_blocks = ["10.0.0.0/8"]
  }

  tags = { Name = "proxy-security-group" }
}

Create a key pair

We need a SSH key pair to create the EC2 instance.

In the Terminal, use the ssh-keygen command to generate a new SSH key pair.

You’ll be asked to enter a file name. If you don’t specify a file, the keys will be saved in the default location (~/.ssh/id_rsa for the private key and ~/.ssh/id_rsa.pub for the public key), which is usually fine.

Once the key is generated, navigate to the directory where the key is saved. If you didn’t specify a path, it should be in ~/.ssh/.

You need to access the public key, which will have an extension .pub.

cat ~/path/to/your-key.pub

Copy the entire output of the public key; it will start with ssh-rsa followed by a long string of characters.

We are now ready to import the public key in AWS:

resource "aws_key_pair" "ec2" {
  # this is how the key will be identified in AWS
  key_name = "imported-key"

  # The public key portion of the key pair
  public_key = "ssh-rsa XXXXXXXX"
}

Define the EC2 Instance

With the security group in place and the SSH key pair created, we are now ready to define the AWS EC2 instance that will serve as our proxy server.

resource "aws_instance" "proxy" {
  ami           = "ami-0ed961fa828560210"
  instance_type = "t2.micro"
  
  key_name               = aws_key_pair.ec2.key_name
  subnet_id              = "xxx"
  vpc_security_group_ids = [aws_security_group.proxy.id]

  user_data = file("setup-proxy.sh")

  tags = {Name = "proxy"}
}

A few comments about this code:

  • ami: you can use this one (which is a basic small linux), or use another one
  • t2.micro is chosen here, which is a good starting point for small-scale applications and testing purposes.
  • subnet_id: the id of the subnet in which you want to start your instance
  • key_name: Refers to the SSH key pair for secure access to the instance. This is the key pair we created earlier.
  • user_data: This is a script that runs when the instance is first started. In our setup, it refers to setup-proxy.sh, which configures Apache as a proxy.

Deploy the Configuration

  1. Initialize Terraform: Run terraform init in your project directory to initialize Terraform and download necessary plugins.

  2. Apply the Configuration: Run terraform apply to apply the configuration. Terraform will show you a plan and ask for confirmation before making changes.

  3. Access the Instance: Type the IP address the browser to check that the web proxy is working.

Debugging tools

SSH into the instance: Once the instance is up, you can access it using SSH and the key pair you created. For example:

ssh -i /path/to/your-key.pem ec2-user@your-instance-ip

Verify the Proxy: After logging in, you can verify that Apache is running and configured as a proxy by checking the status of the Apache service and reviewing the proxy configuration.

systemctl status httpd

Verify Apache Configuration: The next step is to verify the Apache configuration, particularly the proxy settings you’ve defined.

cat /etc/httpd/conf.d/proxy.conf

Review logs: Finally, check Apache’s log files for any errors or warnings that might indicate problems with the proxy setup. Apache’s log files are typically located in /var/log/httpd/. The error log file is usually named error_log or error.log.

cat /var/log/httpd/error_log

Complete code

Comments