Terminating TLS connections using Terraform
To create the infrastructure for terminating TLS connections using Terraform:
We will use the my-site.com domain name as an example.
If you no longer need the resources you created, delete them.
Get your cloud ready
Sign up for Yandex Cloud and create a billing account:
- Navigate to the management console
and log in to Yandex Cloud or create a new account. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVEorTRIAL_ACTIVEstatus. If you do not have a billing account, create one and link a cloud to it.
If you have an active billing account, you can create or select a folder for your infrastructure on the cloud page
Learn more about clouds and folders here.
Required paid resources
The cost of supporting the infrastructure for terminating TLS connections includes:
- Fee for continuously running VMs (see Yandex Compute Cloud pricing).
- Fee for using a public static IP address (see Yandex Virtual Private Cloud pricing).
- Fee for using computing resources of the L7 load balancer (see Application Load Balancer pricing).
- Fee for public DNS queries and DNS zones if using Yandex Cloud DNS (see Cloud DNS pricing).
Create your infrastructure
To create an infrastructure using Terraform:
-
Install Terraform, get the credentials, and specify the source for installing the Yandex Cloud provider (see Configure your provider, Step 1).
-
Set up your infrastructure description files:
Ready-made configurationManually-
Clone the repository with configuration files.
git clone https://github.com/yandex-cloud-examples/yc-alb-tls-termination.git -
Navigate to the repository directory. It should now contain the following files:
tls-termination-config.tf: New infrastructure configuration.tls-terminationg.auto.tfvars: User data file.
- Create a folder for configuration files.
- In the folder, create:
-
tls-termination-config.tfconfiguration file:tls-termination-config.tf
# Declaring variables with sensitive data variable "folder_id" { type = string } variable "vm_user" { type = string } variable "ssh_key_path" { type = string } variable "domain" { type = string } variable "certificate" { type = string } variable "private_key" { type = string } # Adding other variables locals { sa_name = "ig-sa" network_name = "network-1" subnet_name_a = "subnet-a" subnet_name_b = "subnet-b" sg_name_balancer = "sg-balancer" sg_name_vms = "sg-vms" cert_name = "imported-cert" site_ig_name = "site-ig" alb_bg_name = "alb-bg" alb_host_name = "alb-host" alb_router_name = "alb-router" alb_name = "alb" alb_zone_name = "alb-zone" } # Configuring the provider terraform { required_providers { yandex = { source = "yandex-cloud/yandex" version = ">= 0.47.0" } } } provider "yandex" { folder_id = var.folder_id } # Creating a service account for an instance group resource "yandex_iam_service_account" "ig-sa" { name = local.sa_name description = "service account to manage IG" } resource "yandex_resourcemanager_folder_iam_member" "editor" { folder_id = var.folder_id role = "editor" member = "serviceAccount:${yandex_iam_service_account.ig-sa.id}" } # Creating a cloud network resource "yandex_vpc_network" "network-1" { name = local.network_name } resource "yandex_vpc_subnet" "subnet-a" { name = local.subnet_name_a zone = "ru-central1-a" v4_cidr_blocks = ["192.168.1.0/24"] network_id = yandex_vpc_network.network-1.id } resource "yandex_vpc_subnet" "subnet-b" { name = local.subnet_name_b zone = "ru-central1-b" v4_cidr_blocks = ["192.168.2.0/24"] network_id = yandex_vpc_network.network-1.id } # Creating a static public IP address resource "yandex_vpc_address" "stat_address" { name = "alb-static-address" external_ipv4_address { zone_id = "ru-central1-a" } } # Creating security groups resource "yandex_vpc_security_group" "sg-balancer" { name = local.sg_name_balancer network_id = yandex_vpc_network.network-1.id egress { protocol = "ANY" description = "any" v4_cidr_blocks = ["0.0.0.0/0"] from_port = 0 to_port = 65535 } ingress { protocol = "TCP" description = "ext-http" v4_cidr_blocks = ["0.0.0.0/0"] port = 80 } ingress { protocol = "TCP" description = "ext-https" v4_cidr_blocks = ["0.0.0.0/0"] port = 443 } } resource "yandex_vpc_security_group" "sg-vms" { name = local.sg_name_vms network_id = yandex_vpc_network.network-1.id ingress { protocol = "TCP" description = "balancer" security_group_id = yandex_vpc_security_group.sg-balancer.id port = 80 } ingress { protocol = "TCP" description = "ssh" v4_cidr_blocks = ["0.0.0.0/0"] port = 22 } } # Importing the website’s TLS certificate resource "yandex_cm_certificate" "imported-cert" { name = local.cert_name self_managed { certificate = "${file("${var.certificate}")}" private_key = "${file("${var.private_key}")}" } } # Creating an instance group for a website resource "yandex_compute_image" "lemp-image" { source_family = "lemp" } resource "yandex_compute_instance_group" "site-ig" { name = local.site_ig_name folder_id = var.folder_id service_account_id = "${yandex_iam_service_account.ig-sa.id}" instance_template { platform_id = "standard-v2" resources { memory = 1 cores = 2 core_fraction = 5 } boot_disk { mode = "READ_WRITE" initialize_params { image_id = yandex_compute_image.lemp-image.id } } network_interface { network_id = yandex_vpc_network.network-1.id subnet_ids = [yandex_vpc_subnet.subnet-a.id,yandex_vpc_subnet.subnet-b.id] security_group_ids = [yandex_vpc_security_group.sg-vms.id] nat = true } metadata = { user-data = "#cloud-config\nusers:\n - name: ${var.vm_user}\n groups: sudo\n shell: /bin/bash\n sudo: 'ALL=(ALL) NOPASSWD:ALL'\n ssh_authorized_keys:\n - ${file("${var.ssh_key_path}")}" } } scale_policy { fixed_scale { size = 2 } } allocation_policy { zones = ["ru-central1-a","ru-central1-b"] } deploy_policy { max_unavailable = 1 max_expansion = 0 } application_load_balancer { target_group_name = "alb-tg" } } # Creating a backend group resource "yandex_alb_backend_group" "alb-bg" { name = local.alb_bg_name http_backend { name = "alb-backend" weight = 1 port = 80 target_group_ids = [yandex_compute_instance_group.site-ig.application_load_balancer[0].target_group_id] healthcheck { timeout = "10s" interval = "2s" healthcheck_port = 80 http_healthcheck { path = "/" } } } } # Creating an HTTP router resource "yandex_alb_http_router" "alb-router" { name = local.alb_router_name } resource "yandex_alb_virtual_host" "alb-host" { name = local.alb_host_name authority = ["${var.domain}"] http_router_id = yandex_alb_http_router.alb-router.id route { name = "alb-route" http_route { http_route_action { backend_group_id = yandex_alb_backend_group.alb-bg.id timeout = "60s" } } } } # Creating an L7 load balancer resource "yandex_alb_load_balancer" "alb" { name = local.alb_name network_id = yandex_vpc_network.network-1.id security_group_ids = [yandex_vpc_security_group.sg-balancer.id] allocation_policy { location { zone_id = "ru-central1-a" subnet_id = yandex_vpc_subnet.subnet-a.id } location { zone_id = "ru-central1-b" subnet_id = yandex_vpc_subnet.subnet-b.id } } listener { name = "list-http" endpoint { address { external_ipv4_address { address = yandex_vpc_address.stat_address.external_ipv4_address[0].address } } ports = [ 80 ] } http { redirects { http_to_https = true } } } listener { name = "listener-http" endpoint { address { external_ipv4_address { address = yandex_vpc_address.stat_address.external_ipv4_address[0].address } } ports = [ 443 ] } tls { default_handler { http_handler { http_router_id = yandex_alb_http_router.alb-router.id } certificate_ids = [yandex_cm_certificate.imported-cert.id] } sni_handler { name = "mysite-sni" server_names = ["${var.domain}"] handler { http_handler { http_router_id = yandex_alb_http_router.alb-router.id } certificate_ids = [yandex_cm_certificate.imported-cert.id] } } } } } # Creating a DNS zone resource "yandex_dns_zone" "alb-zone" { name = local.alb_zone_name description = "Public zone" zone = "${var.domain}." public = true } # Creating a DNS zone resource record resource "yandex_dns_recordset" "alb-record" { zone_id = yandex_dns_zone.alb-zone.id name = "${var.domain}." ttl = 600 type = "A" data = [yandex_alb_load_balancer.alb.listener[0].endpoint[0].address[0].external_ipv4_address[0].address] # description: Resource record description. This is an optional parameter. } -
tls-termination.auto.tfvarsuser data file:tls-termination.auto.tfvars
folder_id = "<folder_ID>" vm_user = "<VM_user_name>" ssh_key_path = "<public_SSH_key_path>" domain = "<domain>" certificate = "<certificate_file_path>" private_key = "<private_key_file_path>"
-
For more on the properties of resources used in Terraform, see these provider guides:
- Network: yandex_vpc_network.
- Subnets: yandex_vpc_subnet.
- Static public IP address: yandex_vpc_address.
- Security groups: yandex_vpc_security_group.
- TLS certificate: yandex_cm_certificate.
- VM image: yandex_compute_image.
- Service account: yandex_iam_service_account.
- Role: yandex_resourcemanager_folder_iam_member.
- Instance group: yandex_compute_instance_group.
- Backend group: yandex_alb_backend_group.
- HTTP router: yandex_alb_http_router.
- Virtual host: yandex_alb_virtual_host.
- L7 load balancer: yandex_alb_load_balancer.
- DNS zone: yandex_dns_zone.
- DNS resource record: yandex_dns_recordset.
-
-
In the
tls-termination.auto.tfvarsfile, set the following user-defined properties:folder_id: Folder ID.vm_user: VM user name.ssh_key_path: Path to the public SSH key file. For more information, see Creating an SSH key pair.domain: Domain to host the website.
To get access to public zone domain names, you need to delegate the domain. Specify the addresses of thens1.yandexcloud.netandns2.yandexcloud.netservers in your account on your registrar's website.certificate: Path to the user certificate file.private_key: Path to the file with the user certificate's private key.
-
Create the resources:
-
In the terminal, navigate to the configuration file directory.
-
Make sure the configuration is correct using this command:
terraform validateIf the configuration is valid, you will get this message:
Success! The configuration is valid. -
Run this command:
terraform planYou will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
-
Apply the configuration changes:
terraform apply -
Type
yesand press Enter to confirm the changes.
-
-
Get the public IP addresses: you will need them later to test the hosting.
After creating the infrastructure, test the hosting.
Test the hosting
To test the hosting:
-
Create the website home page, i.e., the
index.htmlfile.Example of the index.html file
<!DOCTYPE html> <html> <head> <title>My site</title> </head> <body> <h1>This is my site</h1> </body> </html> -
Upload the
index.htmlfile to each VM:-
On the VM page of the management console
, under Network, find the VM's public IP address. -
Connect to the VM over SSH.
-
Grant your user write permissions for the
/var/www/htmldirectory:UbuntuCentOSsudo chown -R "$USER":www-data /var/www/htmlsudo chown -R "$USER":apache /var/www/html -
Upload the website files to the VM via SCP
.Linux/macOSWindowsUse the
scpcommand line utility:scp -r <path_to_directory_with_files> <VM_user_name>@<VM_IP_address>:/var/www/htmlUse WinSCP
to copy the local file directory to/var/www/htmlon the VM.
-
-
Open the website at
http://my-site.comin your browser. A redirect tohttps://my-site.comshould occur with the TLS certificate from Certificate Manager already enabled.
How to delete the resources you created
To stop paying for the resources you created:
-
Open the
tls-termination-config.tffile and delete your infrastructure description from it. -
Apply the changes:
-
In the terminal, navigate to the configuration file directory.
-
Make sure the configuration is correct using this command:
terraform validateIf the configuration is valid, you will get this message:
Success! The configuration is valid. -
Run this command:
terraform planYou will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
-
Apply the configuration changes:
terraform apply -
Type
yesand press Enter to confirm the changes.
-