logo
Menu
AWS Client VPN - A way to access VPC resources as developer?

AWS Client VPN - A way to access VPC resources as developer?

Internal enterprise applications are often hosted on private subnets. This article shows you how to access these resources as a developer using AWS Client VPN.

Published May 10, 2024
Internal enterprise applications are often hosted on private subnets so that they cannot be accessed via the public web. But how can you, as a developer, access these resources? For testing and debugging, it's often helpful to have access to these applications when network connectivity to the intranet has not yet been established or when you don't have access to the intranet.

Port forwarding with AWS Systems Manager

One way to archive this requirement is to use port forwarding to a remote host with AWS Systems Manager. An EC2 instance such as a Bastion host must be set up and connected to AWS Systems Manager. The following command can be used to redirect a port to a developer machine.
1
2
3
4
aws ssm start-session \
--target i-07575de8a3540b971 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["https://internal-url"],"portNumber":["80"], "localPortNumber":["8080"]}'
Port forwarding has some limitations. The hostname is changed, which leads to problems with HTTPS communication. Complex applications with separate frontend and backend domains are not supported because only one domain is forwarded.

AWS Client VPN as an alternative?

VPN connections can be used to connect to remote networks. AWS Client VPN is an AWS service that meets this requirement. But as a developer, is it easy to set up just for testing and debugging?
In region eu-west-1 (Ireland), an AWS Client VPN endpoint association costs $0.10 per hour and each AWS Client VPN connection costs $0.05 per hour. So there is no high cost to test this AWS service.
AWS Client VPN offers different authentication options:
  • mutual authentication using client certificates
  • user-based authentication using Active Directory or SAML
Setting up an Active Directory adds cost and configuration overhead. SAML authentication requires an identity provider, which also requires additional configuration. However, client certificates can be created as self-signed certificates at no additional cost. Therefore, this example uses mutual authentication with self-signed certificates.

Setting up a VPC with only private subnets

To demonstrate the AWS Client VPN capabilities, this article uses a VPC, an Application Load Balancer, and a Route53 record as infrastructure. Everything can be built as an AWS CDK project.
A VPC is created with private isolated subnets (no NAT gateways, no internet access).
1
2
3
4
5
6
7
8
9
const vpc = new ec2.Vpc(this, 'Vpc', {
subnetConfiguration: [
{
cidrMask: 24,
name: 'PrivateIsolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});
An Application Load Balancer with a Lambda target serves as the backend for the application.
1
2
3
4
5
6
7
8
9
10
11
12
13
const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
vpc,
internetFacing: false,
});

const websiteHandler = new nodejs.NodejsFunction(this, 'website', {
entry: path.join(__dirname, 'website.handler.ts'),
});

const listener = lb.addListener('Listener', { port: 80 });
listener.addTargets('Targets', {
targets: [new targets.LambdaTarget(websiteHandler)],
});
The Lambda handler simply returns a static dummy web page with no additional programming logic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ALBEvent, ALBResult } from "aws-lambda";

export async function handler(event: ALBEvent): Promise<ALBResult> {
const body = "<html>\n<body>\n\n<h1>It works!</h1>\n\n" +
"<p>It works!</p>\n\n</body>\n</html>";
body
return {
statusCode: 200,
headers: {
'Content-Type': 'text/html; charset=utf-8',
},
body,
}
}
A Route53 record points to the Application Load Balancer.
1
2
3
4
5
6
7
8
9
10
const hostedZone = new route53.PrivateHostedZone(this, 'MyPrivateHostedZone', {
zoneName: 'my-app.julian',
vpc,
});

new route53.ARecord(this, 'Alias', {
zone: hostedZone,
target: route53.RecordTarget.fromAlias(new route53Targets.LoadBalancerTarget(lb)),
recordName: 'test',
});

AWS Client VPN configuration

As a prerequisite, certificates and private keys must be created for mutual authentication. AWS documentation provides step-by-step instructions for creating them. As a result, the client and server certificate/key are uploaded to AWS Certificate Manager. For this demo, use the file names from the documentation without changing them.
AWS CDK has an L2 construct called ClientVpnEndpoint for deploying the AWS Client VPN. Add the VPC cidr and dnsServers. The DNS server is the .2 address in the VPC, for example 10.0.0.2 in a VPC with CIDR 10.0.0.0/8. A split tunnel VPN is configured using the splitTunnel property. Only traffic to the previously specified CIDR will be routed through this VPN tunnel. For serverCertificateArn and serverCertificateArn, use the certificate ARNs you previously created in AWS Certificate Manager.
1
2
3
4
5
6
7
8
9
10
11
const vpn = new ec2.ClientVpnEndpoint(this, 'ClientVpnEndpoint', {
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
cidr: '10.100.0.0/16',
dnsServers: ['10.0.0.2'],
splitTunnel: true,
serverCertificateArn: 'arn:aws:acm:eu-west-1:012345678901:certificate/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
clientCertificateArn: 'arn:aws:acm:eu-west-1:012345678901:certificate/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY',
});
Of course, instead of configuring AWS Client VPN with AWS CDK, you can also configure it manually or using another infrastructure as code solution.
Next, open "Client VPN endpoints" in the AWS console (it is part of the VPC dashboard). Select the VPN endpoint and download the client configuration.
Select "Download client configuration" in Client VPN endpoints
Move the downloaded file downloaded-client-config.ovpn to the folder that contains the certificates and keys (called custom_folder in the documentation). Open the file in a text editor and add the following lines at the end of the file to reference the client certificate and the client key.
1
2
cert client1.domain.tld.crt
key client1.domain.tld.key
AWS Client VPN is based on OpenVPN. Download and install the OpenVPN Connect client software. Import the configuration file downloaded-client-config.ovpn into OpenVPN. The connection will start automatically.
OpenVPN client software
As a result, the demo application running at http://test.my-app.julian can be opened in a web browser.
Demo application in Chrome browser

Summary

When using AWS Client VPN with mutual authentication and client certificates, configuration is simple. AWS Client VPN is integrated with AWS CDK and requires only a few manual configuration tasks such as client certificate generation. Because AWS Client VPN is based on OpenVPN, only this VPN solution is required on developer notebooks. You get direct access to the resources. Testing and debugging can be done in a very helpful way.
Are you using AWS Client VPN for this use case as well? Or as a developer, how do you access private VPN resources in your project?
 

Comments