How To Set Up A Secure AWS Client VPN With Okta Integration (SSO and Self-service) Using Terraform (PART 2)
Tags: cloud, aws, terraform, devops
Published: 2023-04-09 14:22:18

In the previous part of this article, we explored how to generate the SAML applications metadata using Okta. In this second part, we will continue with the next steps to set up an AWS Client VPN endpoint and associate it with a VPC network, and then configure it to authenticate Okta users. By integrating AWS Client VPN with Okta, we can ensure secure and centralized access control for remote users. Let's dive in and explore the remaining steps involved in setting up AWS Client VPN.

<u>Requirements:</u>

To follow along with this tutorial, you need to have the following prerequisites:

- AWS Account
- Terraform installed on your machine
- An Okta account and Okta SAML application metadata .xml file from part 1

Steps:

The following steps will guide you through the process to complete the integration of Okta with AWS to setup a Client VPN using Terraform.

## STEP 1: Generate the server and client certificates with keys to be uploaded to ACM

- Clone the OpenVPN easy-rsa repo to your local computer and navigate to the easy-rsa/easyrsa3 folder.

$ git clone https://github.com/OpenVPN/easy-rsa.git
$ cd easy-rsa/easyrsa3

- Initialize a new PKI environment.
$ ./easyrsa init-pki

- To build a new certificate authority (CA), run this command and follow the prompts.

$ ./easyrsa build-ca nopass

- Generate the server certificate and key.

$ ./easyrsa build-client-full client1.domain.tld nopass

- Copy the server certificate and key and the client certificate and key to a custom folder. you can use the same custom folder for the downloaded provider's metadata.

## STEP 2: Write the terraform to deploy necessary resources

In the main.tf file, this section creates two resources of aws_acm_certificate type to upload the server certificate and client certificate to the AWS Certificate Manager (ACM). The certificates are uploaded from the local computer. The private_key, certificate_body, and certificate_chain arguments specify the location of the certificate files, and the tags argument adds a name tag to the certificates for easy identification.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xy5lfgtil2y7gwf85vfp.jpeg)
#####<u>Create the SAML provider</u>

To create a SAML provider, you need to provide the SAML metadata file in either XML or JSON format. You can either upload the file directly to AWS or provide the file path to the aws_iam_saml_provider resource in your Terraform configuration.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7w4chqb1ybqxj58s5mhs.jpeg)

#####<u>Create a Client VPN endpoint</u>

The resource block "aws_ec2_client_vpn_endpoint" create the Client VPN endpoint. The endpoint is associated with the server certificate uploaded earlier. The authentication_options block defines the SAML provider ARNs for federated authentication and self-service authentication. The client_cidr_block argument specifies the IP address range for the Client VPN subnet, and dns_servers argument provides a list of DNS servers that will be used by clients to resolve domain names. The split_tunnel argument defines whether or not to split the client's internet traffic over the VPN. The self_service_portal argument specifies whether to enable or disable the self-service portal. The connection_log_options argument specifies whether to enable or disable connection logging.

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

####<u>Associate a target network</u>

This section creates a resource of aws_ec2_client_vpn_network_association type to associate the Client VPN endpoint with a target network. The count argument is set to the number of subnets created in the next step, and the client_vpn_endpoint_id argument specifies the ID of the Client VPN endpoint created. The subnet_id argument specifies the ID of the subnet to which the endpoint is associated. The security_groups argument specifies the ID of the security group to apply to the endpoint. The ignore_changes argument is set to ignore any changes made to the subnet_id argument.

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

####<u>Add an authorization rule for the VPC</u>

This block creates a resource of aws_ec2_client_vpn_authorization_rule type to add an authorization rule for the VPC. The client_vpn_endpoint_id argument specifies the ID of the Client VPN endpoint created. The target_network_cidr argument specifies the IP address range of the target VPC. The authorize_all_groups argument allows all clients in the target network to connect to the Client VPN endpoint.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wpk0ujkjbjvhxh1v9lh.jpeg)

####<u>Provide access to the internet to vpn user</u>

This step creates a resource of aws_ec2_client_vpn_route type to provide internet access to the connected clients. The count argument is set to the number of subnets created. The client_vpn_endpoint_id argument specifies the ID of the Client VPN endpoint created. The destination_cidr_block argument specifies the IP address range of the internet.destination_cidr_block = "0.0.0.0/0" - This is defining the destination CIDR block for this route. In this case, it is "0.0.0.0/0", which means all traffic will be routed through this VPN.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ci10ogsphzl3g4g1y7a.jpeg)

####<u>Verify security group requirements</u>

This step creates a resource of aws_security_group type to verify security group requirements. The vpc_id argument specifies the ID of the VPC created in previous steps. The name argument assigns a name to the security group. The ingress and egress blocks define inbound and outbound rules for the security group, respectively. The inbound rule allows UDP traffic on port 443 from any source IP address.

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

To properly organize the project, I created a separate terraform file(vpc.tf) that contains all resources associated with creating the VPC and Subnet to which the VPN Client is connecting to.

```
resource "aws_vpc" "main" {
  cidr_block = "172.20.0.0/16"

  enable_dns_hostnames = true
  enable_dns_support = true
  instance_tenancy = "default"
  tags = local.global_tags

}

resource "aws_default_security_group" "default" {
  vpc_id = aws_vpc.main.id

  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = local.global_tags
}

resource "aws_subnet" "sn_az" {
  count = length(local.availability_zones)

  availability_zone = local.availability_zones[count.index]

  vpc_id = aws_vpc.main.id
  map_public_ip_on_launch = false

  cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 5, count.index+1)

  
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id

}

resource "aws_route_table" "rt" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }

 
}

resource "aws_route_table_association" "rt_assoc" {
  count = length(aws_subnet.sn_az)

  route_table_id = aws_route_table.rt.id
  subnet_id = aws_subnet.sn_az[count.index].id
}

data "aws_availability_zones" "available" {
  state = "available"
}

locals {
  region = "us-east-2"
  global_tags = {
    "environment" = "vpn-example"
  }
  availability_zones = sort(data.aws_availability_zones.available.names)
}
```
## STEP 3: Run terraform commands to deploy the resources to AWS
cd into the directory containing the terraform files and run the terraform commands to deploy the VPN to AWS

$ terraform init
$ terraform plan
$ terraform apply

## STEP 4: Download the client config from the AWS console or the user Self-service portal 

They are two way to get the Client Configuration

1. The AWS console

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

2. The Self-service portal for end users

Login to the service portal with the link
**LINK**: https://self-service.clientvpn.amazonaws.com/endpoints/Client VPN endpoint ID
Note: End users will the okta Verify app to complete the login to generate login MFA code

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

## STEP 5: Download the Client VPN app either from the self-service page or the link below

Download link: https://aws.amazon.com/vpn/client-vpn-download/

## STEP 6: Configure the VPN app by adding the VPN client configuration that was downloaded from the self-service page

To connect using the AWS provided client for Windows

1. Open the AWS VPN Client app.
2. Choose File, Manage Profiles.
3. Choose Add Profile.

The Display Name can be Anything 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75qp47od9wecl128mjqh.jpeg)

## STEP 7: Verify the connection to the VPC by checking that the “Connected” text shows above the display name.

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

Thanks for reading.

You can find the module to this project on my [GitHub Page](https://github.com/devmatthew1/terraform-aws-clientvpn-okta-2).

Visit [Part 1](https://dev.to/surelay/how-to-set-up-a-secure-aws-client-vpn-with-terraform-and-okta-integration-for-sso-and-self-service-part-1-4nmm) if you missed it

Please like, comment and share to help improve this article.