terraform-aws-client-vpn-endpoint
AWS Client VPN endpoint
How to create Application for VPN in AWS Single Sign-On
Open AWS SSO service page. Select Applications from the sidebar
Choose Add a new application
Select Add a custom SAML 2.0 application
Fill Display name and Description
Set session duration (VPN session duration) - 12h
Select "If you don't have a metadata file, you can manually type your metadata values."
Application ACS URL: http://127.0.0.1:35001
Application SAML audience: urn:amazon:webservices:clientvpn
Save changes
Download AWS SSO SAML metadata file (file for vpn secret)
Select tab "Attribute mappings":
Subject -> ${user:subject} -> emailAddress
NameID -> ${user:email} -> basic
memberOf -> ${user:groups} -> unspecified
Select tab "Assigned users"
Assign users or groups created on previous step
# Get metadata.xml file from AWS SSO/Applications
# Encode file with base64 `base64 -w 0` (linux only) or `openssl base64 -A`
# Create secret `saml_metadata` with key `saml_metadata_xml` and value base64
data "aws_secretsmanager_secret" "saml" {
name = " saml_metadata"
}
data "aws_secretsmanager_secret_version" "saml" {
secret_id = data. aws_secretsmanager_secret . saml . id
version_stage = " AWSCURRENT"
}
resource "aws_iam_saml_provider" "vpn" {
name = var. vpn_saml_provider_name # could be anything that satisfy regular expression pattern: [\w._-]+
saml_metadata_document = base64decode (jsondecode (data. aws_secretsmanager_secret_version . saml . secret_string )[" saml_metadata_xml" ]) # saml_metadata_xml
tags = var. tags
}
module "vpn" {
source = " fivexl/client-vpn-endpoint/aws"
endpoint_name = " myvpn"
endpoint_client_cidr_block = " 10.100.0.0/16"
endpoint_subnets = [module . vpc . intra_subnets [0 ]] # Attach VPN to single subnet. Reduce cost
endpoint_vpc_id = module. vpc . vpc_id
tls_subject_common_name = " int.example.com"
saml_provider_arn = aws_iam_saml_provider. vpn . arn
authorization_rules = {}
additional_routes = {
" ${module.vpc.intra_subnets[0]}" = " 172.16.0.0/24"
}
authorization_rules_all_groups = {
full_access_private_subnet_0 = module.vpc.private_subnets_cidr_blocks[0 ]
}
tags = var. tags
}
Example without split tunnel (classic VPN)
# Get metadata.xml file from AWS SSO/Applications
# Encode file with base64 `base64 -w 0` (linux only) or `openssl base64 -A`
# Create secret `saml_metadata` with key `saml_metadata_xml` and value base64
data "aws_secretsmanager_secret" "saml" {
name = " saml_metadata"
}
data "aws_secretsmanager_secret_version" "saml" {
secret_id = data. aws_secretsmanager_secret . saml . id
version_stage = " AWSCURRENT"
}
resource "aws_iam_saml_provider" "vpn" {
name = var. vpn_saml_provider_name # could be anything that satisfy regular expression pattern: [\w._-]+
saml_metadata_document = base64decode (jsondecode (data. aws_secretsmanager_secret_version . saml . secret_string )[" saml_metadata_xml" ]) # saml_metadata_xml
tags = var. tags
}
module "vpn" {
source = " fivexl/client-vpn-endpoint/aws"
endpoint_name = " myvpn"
endpoint_client_cidr_block = " 10.100.0.0/16"
endpoint_subnets = [module . vpc . private_subnets [0 ]] # Attach VPN to single subnet. Reduce cost
endpoint_vpc_id = module. vpc . vpc_id
tls_subject_common_name = " int.example.com"
saml_provider_arn = aws_iam_saml_provider. vpn . arn
authorization_rules = {}
additional_routes = {
" ${module.vpc.private_subnets[0]}" = " 0.0.0.0/0"
}
authorization_rules_all_groups = {
worldwide = " 0.0.0.0/0"
}
enable_split_tunnel = false
tags = var. tags
}
variable "vpn_access_public" {
description = " List of SSO Group IDs for accessing public subnets"
type = list (string )
default = []
}
variable "vpn_access_private" {
description = " List of SSO Group IDs for accessing private subnets"
type = list (string )
default = []
}
variable "vpn_access_intra" {
description = " List of SSO Group IDs for accessing intra subnets"
type = list (string )
default = []
}
variable "vpn_access_db" {
description = " List of SSO Group IDs for accessing db subnets"
type = list (string )
default = []
}
variable "vpn_access_elasticache" {
description = " List of SSO Group IDs for accessing elasticache subnets"
type = list (string )
default = []
}
variable "vpn_access_all" {
description = " List of SSO Group IDs for accessing all subnets"
type = list (string )
default = []
}
# https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/limits.html
# Authorization rules per Client VPN endpoint defaul quota is 50
# https://console.aws.amazon.com/servicequotas/home/services/ec2/quotas/L-9A1BC94B
locals {
vpn_authorization_rules_public = { for item in setproduct (module. vpc . public_subnets_cidr_blocks , var. vpn_access_public ) : " public_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules_private = { for item in setproduct (module. vpc . private_subnets_cidr_blocks , var. vpn_access_private ) : " private_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules_intra = { for item in setproduct (module. vpc . intra_subnets_cidr_blocks , var. vpn_access_intra ) : " intra_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules_db = { for item in setproduct (module. vpc . database_subnets_cidr_blocks , var. vpn_access_db ) : " db_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules_elasticache = { for item in setproduct (module. vpc . elasticache_subnets_cidr_blocks , var. vpn_access_elasticache ) : " elasticache_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules_all = { for item in setproduct ([module . vpc . vpc_cidr_block ], var. vpn_access_all ) : " all_${ item [0 ]} _${ item [1 ]} " => " ${ item [0 ]} ,${ item [1 ]} " }
vpn_authorization_rules = merge (
local. vpn_authorization_rules_public ,
local. vpn_authorization_rules_private ,
local. vpn_authorization_rules_intra ,
local. vpn_authorization_rules_db ,
local. vpn_authorization_rules_elasticache ,
local. vpn_authorization_rules_all
)
}
module "vpn" {
source = " fivexl/client-vpn-endpoint/aws"
endpoint_name = " myvpn"
endpoint_client_cidr_block = " 10.100.0.0/16"
endpoint_subnets = [module . vpc . intra_subnets [0 ]] # Attach VPN to single subnet. Reduce cost
endpoint_vpc_id = module. vpc . vpc_id
tls_subject_common_name = " int.example.com"
saml_provider_arn = data. aws_ssm_parameter . iam_vpn_saml_provider_arn . value
authorization_rules = local. vpn_authorization_rules
authorization_rules_all_groups = {}
tags = var. tags
}
Name
Version
aws
>= 4.0
tls
>= 3.2.0
No modules.
Name
Description
Type
Default
Required
additional_routes
A list of maps where each map contains a subnet ID of endpoint subnet for network association and a list of cidrs to where traffic should be routed from that subnet. Useful in cases if you need to route beyond the VPC subnet, for instance peered VPC
list(map(string))
{}
no
authorization_rules
Map containing authorization rule configuration. rule_name = "target_network_cidr, access_group_id" .
map(string)
{}
no
authorization_rules_all_groups
Map containing authorization rule configuration with authorize_all_groups=true. rule_name = "target_network_cidr" .
map(string)
{}
no
certificate_arn
The ARN of ACM certigicate to use for the VPN server config.
string
null
no
cloudwatch_log_group_name_prefix
Specifies the name prefix of CloudWatch Log Group for VPC flow logs.
string
"/aws/client-vpn-endpoint/"
no
cloudwatch_log_group_retention_in_days
Specifies the number of days you want to retain log events in the specified log group for VPN connection logs.
number
30
no
create_endpoint
Create Client VPN Endpoint
bool
true
no
dns_servers
DNS servers to be used for DNS resolution. A Client VPN endpoint can have up to two DNS servers. If no DNS server is specified, the DNS address of the connecting device is used. Conflict with use_vpc_internal_dns
list(string)
[]
no
enable_split_tunnel
Indicates whether split-tunnel is enabled on VPN endpoint
bool
true
no
endpoint_client_cidr_block
The IPv4 address range, in CIDR notation, from which to assign client IP addresses. The address range cannot overlap with the local CIDR of the VPC in which the associated subnet is located, or the routes that you add manually. The address range cannot be changed after the Client VPN endpoint has been created. The CIDR block should be /22 or greater.
string
"10.100.100.0/24"
no
endpoint_name
Name to be used on the Client VPN Endpoint
string
n/a
yes
endpoint_subnets
List of IDs of endpoint subnets for network association
list(string)
n/a
yes
endpoint_vpc_id
VPC where the VPN will be connected.
string
n/a
yes
saml_provider_arn
The ARN of the IAM SAML identity provider.
string
n/a
yes
tags
A map of tags to add to all resources
map(string)
{}
no
tls_subject_common_name
The common_name for subject for which a certificate is being requested. RFC5280. Not used if certificate_arn provided.
string
"vpn.example.com"
no
tls_validity_period_hours
Specifies the number of hours after initial issuing that the certificate will become invalid. Not used if certificate_arn provided.
number
47400
no
transport_protocol
The transport protocol to be used by the VPN session.
string
"udp"
no
use_vpc_internal_dns
Use VPC Internal DNS as is DNS servers
bool
true
no