Secure password transmission to an initialization script with the help of Terraform
To create a VM while protecting sensitive information in its initialization script using Terraform:
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 infrastructure support cost includes:
- Fee for continuously running VMs (see Yandex Compute Cloud pricing).
- Fee for using an image (depends on the image).
- Fee for using a KMS key (see KMS pricing).
- Fee for using a secret (see Yandex Lockbox pricing).
Create an infrastructure
With Terraform
Terraform is distributed under the Business Source License
For more information about the provider resources, see the relevant documentation on the Terraform
To create your infrastructure via Terraform:
-
Install Terraform, obtain authentication credentials, and specify the source for installing the Yandex Cloud provider. For details, see Configure your provider, step 1.
-
Set up your infrastructure description files:
Ready-made configurationManually-
Clone the repository containing the configuration files.
git clone https://github.com/yandex-cloud-examples/yc-secured-password.git -
Navigate to the repository directory. It should now contain the following files:
yc-secured-password.tf: New infrastructure configuration.script.tpl: Script template for creating administrator and user accounts.yc-secured-password.auto.tfvars: User data file.
- Create a folder for configuration files.
- In the folder, create:
-
yc-secured-password.tfconfiguration file:yc-secured-password.tf
# Configuring the provider terraform { required_providers { yandex = { source = "yandex-cloud/yandex" version = ">= 0.47.0" } } } provider "yandex" { folder_id = var.folder_id } # Declaring variables with sensitive data variable "zone" { type = string } variable "folder_id" { type = string } variable "admin_pass" { type = string sensitive = true } variable "username" { type = string } variable "user_pass" { type = string sensitive = true } variable "image_family" { type = string } # Creating a cloud network and a subnet resource "yandex_vpc_network" "network-1" { name = "win-network" } # Creating a subnet resource "yandex_vpc_subnet" "subnet-a" { name = "win-subnet" zone = var.zone v4_cidr_blocks = ["192.168.1.0/24"] network_id = yandex_vpc_network.network-1.id } # Creating a security group resource "yandex_vpc_security_group" "vm-sg" { name = "vm_security_group" network_id = yandex_vpc_network.network-1.id egress { protocol = "ANY" description = "any" from_port = 0 to_port = 65535 v4_cidr_blocks = ["0.0.0.0/0"] } 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 } ingress { protocol = "TCP" description = "ext-https" v4_cidr_blocks = ["0.0.0.0/0"] port = 3389 } } # Creating a service account resource "yandex_iam_service_account" "my-sa" { name = "win-secret-sa" } # Assigning permissions to a service account resource "yandex_resourcemanager_folder_iam_member" "view-keys" { folder_id = var.folder_id role = "kms.keys.encrypterDecrypter" member = "serviceAccount:${yandex_iam_service_account.my-sa.id}" } resource "yandex_resourcemanager_folder_iam_member" "view-payload" { folder_id = var.folder_id role = "lockbox.payloadViewer" member = "serviceAccount:${yandex_iam_service_account.my-sa.id}" } # Creating a symmetric KMS encryption key resource "yandex_kms_symmetric_key" "key-a" { name = "win-secret-key" default_algorithm = "AES_128" rotation_period = "8760h" } # Creating a secret resource "yandex_lockbox_secret" "win_secret" { name = "win-secret" folder_id = var.folder_id kms_key_id = yandex_kms_symmetric_key.key-a.id } # Creating a secret version resource "yandex_lockbox_secret_version_hashed" "win_secret_version" { secret_id = yandex_lockbox_secret.win_secret.id key_1 = "Administrator" text_value_1 = var.admin_pass key_2 = var.username text_value_2 = var.user_pass } # Creating a boot disk for the VM data "yandex_compute_image" "default" { family = var.image_family } resource "yandex_compute_disk" "boot-disk" { type = "network-ssd" zone = var.zone size = "100" image_id = data.yandex_compute_image.default.id } # Creating a VM resource "yandex_compute_instance" "my-vm" { name = "win-test" platform_id = "standard-v2" zone = var.zone service_account_id = yandex_iam_service_account.my-sa.id resources { cores = "2" memory = "4" } boot_disk { disk_id = yandex_compute_disk.boot-disk.id } network_interface { subnet_id = yandex_vpc_subnet.subnet-a.id nat = true security_group_ids = ["${yandex_vpc_security_group.vm-sg.id}"] } metadata = { serial-port-enable = 1 user-data = templatefile("script.tpl", { MYSECRET_ID = yandex_lockbox_secret.win_secret.id }) } } -
script.tpl: Script template for creating administrator and user accounts:script.tpl
#ps1 # logging Start-Transcript -Path "$ENV:SystemDrive\provision2.txt" -IncludeInvocationHeader -Force "Bootstrap script started" | Write-Host # SECRET'S ID: $SecretID = "${MYSECRET_ID}" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $SecretURL = "https://payload.lockbox.api.cloud.yandex.net/lockbox/v1/secrets/$SecretID/payload" "Secret ID is $SecretID" "Payload URL is $SecretURL" $YCToken = (Invoke-RestMethod -Headers @{'Metadata-Flavor'='Google'} -Uri "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token").access_token if (!$YCToken) { throw "Service Account doesn't connected to VM. Please, add Service account with roles lockbox.payloadViewer and kms.key.encryptorDecryptor to VM and try again." } # Creating parameters for REST-invokations $Headers = @{ Authorization="Bearer $YCToken" } $Params = @{ Uri = $SecretURL Method = "GET" Headers = $Headers } # Getting secret via REST invoke $Secret = Invoke-RestMethod @Params $SecretAdministratorPlainTextPassword = $Secret.entries[0].textValue # inserting value's from terraform if (-not [string]::IsNullOrEmpty($SecretAdministratorPlainTextPassword)) { "Set local administrator password" | Write-Host $SecretAdministratorPassword = $SecretAdministratorPlainTextPassword | ConvertTo-SecureString -AsPlainText -Force # S-1-5-21domain-500 is a well-known SID for Administrator # https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows $Administrator = Get-LocalUser | Where-Object -Property "SID" -like "S-1-5-21-*-500" $Administrator | Set-LocalUser -Password $SecretAdministratorPassword } # Creating new users if any if($Secret.entries.count -gt 1) { foreach($User in $Secret.entries[1..($Secret.entries.count-1)]){ $SecretUserPassword = $User.textValue | ConvertTo-SecureString -AsPlainText -Force New-LocalUser -Name $User.key -Password $SecretUserPassword -FullName $User.key Add-LocalGroupMember -Group Users -Member $User.key Add-LocalGroupMember -Group "Remote Desktop Users" -Member $User.key } } "Bootstrap script ended" | Write-Host -
yc-secured-password.auto.tfvarsuser data file:zone = "<availability_zone>" folder_id = "<folder_ID>" admin_pass = "<administrator_password>" username = "<username>" user_pass = "<user_password>" image_family = "<image_family>"
-
For more information about Terraform resource properties, see the relevant provider guides:
- Cloud network: yandex_vpc_network.
- Subnet: yandex_vpc_subnet.
- Security group: yandex_vpc_security_group.
- Service account: yandex_iam_service_account.
- Assigning permissions: yandex_resourcemanager_folder_iam_member.
- Symmetric encryption key: yandex_kms_symmetric_key
- Secret: yandex_lockbox_secret.
- Secret version: yandex_lockbox_secret_version_hashed.
- Image: yandex_compute_image
- Disk: yandex_compute_disk
- VM instance: yandex_compute_instance.
-
-
In the
yc-secured-password.auto.tfvarsfile, specify these custom settings:-
zone: Availability zone. -
folder_id: Folder ID. -
admin_pass: Admin password.Warning
When selecting passwords, make sure to comply with mandatory password requirements.
These password requirements are:- At least 8 characters long.
- Does not incude the account name.
- Must include three of the following:
- Latin uppercase letters (A-Z)
- Latin lowercase letters (a-z)
- Numbers (0-9)
- Non-alphanumeric characters (
!,?,%,$,#, etc.)
-
username: Username. -
user_pass: Password. -
image_family: Family of one of the VM images with the required OS version.
-
-
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.
-
After creating the infrastructure, log in to the Windows OS.
Log in to Windows
To make sure the setup created user accounts from your secret, log in to Windows on your VM:
-
In the management console
, select your VM folder. -
Go to Compute Cloud.
-
Select the
win-testVM. -
Navigate to the Serial console tab.
-
Under Serial console, select
COM2and click Connect. You will see the command line prompt:Computer is booting, SAC started and initialized. Use the "ch -?" command for information about using channels. Use the "?" command for general help. SAC> EVENT: The CMD command is now available. -
Show the list of open channels:
SAC>ch Channel List (Use "ch -?" for information on using channels) # Status Channel Name 0 (AV) SAC -
Create a new channel with a shell instance, if required.
SAC>cmd The Command Prompt session was successfully launched. SAC> EVENT: A new channel has been created. Use "ch -?" for channel help. Channel: Cmd0001 -
To switch to a channel, press ESC + TAB or run the following command:
SAC>ch -sn Cmd0001 Name: Cmd0001 Description: Command Type: VT-UTF8 Channel GUID: e203fb79-d80d-11ea-87e3-c2679e14957d Application Type GUID: 63d02271-8aa4-11d5-bccf-00b0d014a2d0 Press <esc><tab> for next channel. Press <esc><tab>0 to return to the SAC channel. Use any other key to view this channel. -
Press Enter and specify the following:
- Username.
- Domain, if you logged in under a domain account; otherwise, enter your host name or nothing.
- Password.
Please enter login credentials. Username: Administrator Domain : Password: *************** -
If you logged in successfully, you will see the Windows command prompt:
C:\Windows\system32>A successful login means that the setup created user accounts from your secret.
How to delete the resources you created
To stop incurring charges for the resources you created:
-
Open the
yc-secured-password.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.
-