I am using terraform to build up an infastructure. I've built up a virtual machine with terraform which says on azure that it is running and has a public ip. However I can't seem to reach the VM by searching for the ip in my webbrowser. Is there something wrong in my code or what am i missing? Below shows the terraform code which creates the VM.
resource "azurerm_virtual_machine" "myterraformvm" {
name = "myVM"
location = "westeurope"
resource_group_name = "${azurerm_resource_group.myterraformgroup.name}"
network_interface_ids = ["${azurerm_network_interface.myterraformnic.id}"]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04.0-LTS"
version = "latest"
}
os_profile {
computer_name = "myvm"
admin_username = "azureuser"
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/azureuser/.ssh/authorized_keys"
key_data = "ssh-rsa here is a valid SSH key in my original code"
}
}
boot_diagnostics {
enabled = "true"
storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}"
}
tags {
environment = "Igaaas"
}
}
For your issue, If you want to use your webbrowser to access the Azure VM via the public IP. You need to have a web server in your VM and listen to a port.
For example, you have a web server in the VM and listen to port 80, so you can use your webbrowser to access the VM via vm_puvlicIP:80.
I see you set ssh key in the code. If you want to ssh your VM, you should have an ssh tool. Then you can use the ssh tool to connect your Ubuntu via the public IP and the ssh key.
For Terraform, it's just a tool used to create the resources, such as VM. Like Azure template.
Related
I have created a virtual machine using the below terraform code:
Here is the VM code:
# demo instance
resource "azurerm_virtual_machine" "demo-instance" {
name = "${var.prefix}-vm"
location = var.resource_group_location
resource_group_name = var.resource_group_name
network_interface_ids = [
azurerm_network_interface.demo-instance.id]
vm_size = "Standard_A1_v2"
# this is a demo instance, so we can delete all data on termination
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = "RedHat"
offer = "RHEL"
sku = "7-RAW"
version = "7.5.2018042521"
}
storage_os_disk {
name = "RED-HAT-osdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "MyOS"
admin_username = "MyUsername"
admin_password = "Password1234!"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
resource "azurerm_network_interface" "demo-instance" {
name = "${var.prefix}-instance1"
location = var.resource_group_location
resource_group_name = var.resource_group_name
ip_configuration {
name = "instance1"
subnet_id = azurerm_subnet.demo-internal-1.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.demo-instance.id
}
}
resource "azurerm_network_interface_security_group_association" "allow-ssh" {
network_interface_id = azurerm_network_interface.demo-instance.id
network_security_group_id = azurerm_network_security_group.allow-ssh.id
}
resource "azurerm_public_ip" "demo-instance" {
name = "instance1-public-ip"
location = var.resource_group_location
resource_group_name = var.resource_group_name
allocation_method = "Dynamic"
}
and here is the network config:
resource "azurerm_virtual_network" "demo" {
name = "${var.prefix}-network"
location = var.resource_group_location
resource_group_name = var.resource_group_name
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "demo-internal-1" {
name = "${var.prefix}-internal-1"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.demo.name
address_prefixes = ["10.0.0.0/24"]
}
resource "azurerm_network_security_group" "allow-ssh" {
name = "${var.prefix}-allow-ssh"
location = var.resource_group_location
resource_group_name = var.resource_group_name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = var.ssh-source-address
destination_address_prefix = "*"
}
}
As a result, i am able to connect to the virtual-machine using SSH. However, when i try to connect using RDP, i face with the below error:
What i have tried:
I read this document and added an inbound role into my network
However, i am not still able to get connect with RDP.
So, far i know that my VM is in network because it has a password and i know it is running because i can connect using SSH. But, i still don't know why the RDP does not work.
Since this is a Linux VM, you can only connect via SSH protocol even though you have allowed both 3389 and 22 in the NSG.
I see from the screenshot that you have allowed RDP traffic in the VM you are creating now. But the VM you create is RHEL server, you won't be able to take RDP into that, you can SSH only. Only windows vm can be logged in by using RDP.
If you want to login RHEL server from a particular Windows Jump box, that is possible, deploy a windows VM with opening RDP port and add one rule for RHEL server where source IP would be the windows VM. Then you can login to windows VM as bastion and take ssh to RHEL from this bastion. Let me know if your query is cleared.
I am creating my Ubuntu VMs with terraform and will subsequently configure them with ansible.
However, ansible needs a user and ssh keys set up to connect so the public key used for ansible needs to be in the authorized_keys file on the server.
If I use my ssh public key it will work on my machine but it wont work on other machines or on the build server as they wont have the private key.
What is the command to create a new key and not overwrite my current key?
Should I check this key into git so that the same key is passed to terraform?
How do I change my terraform task to use the key from version control?
Current Terraform task:
resource "azurerm_virtual_machine" "client-vm" {
name = "${var.prefix}-${var.client_name}-vm"
resource_group_name = var.resource_group_name
location = var.resource_group_location
network_interface_ids = [azurerm_network_interface.network-interface.id]
vm_size = "Standard_D2s_v3"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
#TODO: Switch to SSH Keys
os_profile {
computer_name = "${var.client_name}"
admin_username = var.username
admin_password = var.password
}
os_profile_linux_config {
disable_password_authentication = false
}
}
Yes, at least if this is how your cloud provider handles SSH keys.. (e.g. AWS does):
resource "aws_instance" "web" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
key_name = "name_of_the_aws_keypair"
}
I'm new to Terraform and have so far managed to get a basic VM (plus Resource Manager trimmings) up and running on Azure. The next task I have in mind is to have Terraform copy a file from my local machine into the newly created instance. Ideally I'm after a solution where the file will be copied each time the apply command is run.
I feel like I'm pretty close but so far I just get endless "Still creating..." statements once I apply (the file is 0kb so after a couple of mins it feels safe to give up).
So far, this is what I've got (based on this code): https://stackoverflow.com/a/37866044/4941009
Network
resource "azurerm_public_ip" "pub-ip" {
name = "PublicIp"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
public_ip_address_allocation = "Dynamic"
domain_name_label = "${var.hostname}"
}
VM
resource "azurerm_virtual_machine" "vm" {
name = "${var.hostname}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
vm_size = "${var.vm_size}"
network_interface_ids = ["${azurerm_network_interface.nic.id}"]
storage_image_reference {
publisher = "${var.image_publisher}"
offer = "${var.image_offer}"
sku = "${var.image_sku}"
version = "${var.image_version}"
}
storage_os_disk {
name = "${var.hostname}osdisk1"
vhd_uri = "${azurerm_storage_account.stor.primary_blob_endpoint}${azurerm_storage_container.cont.name}/${var.hostname}osdisk.vhd"
os_type = "${var.os_type}"
caching = "ReadWrite"
create_option = "FromImage"
}
os_profile {
computer_name = "${var.hostname}"
admin_username = "${var.admin_username}"
admin_password = "${var.admin_password}"
}
os_profile_windows_config {
provision_vm_agent = true
}
boot_diagnostics {
enabled = true
storage_uri = "${azurerm_storage_account.stor.primary_blob_endpoint}"
}
tags {
environment = "${var.environment}"
}
}
File Provisioner
resource "null_resource" "copy-test-file" {
connection {
type = "ssh"
host = "${azurerm_virtual_machine.vm.ip_address}"
user = "${var.admin_username}"
password = "${var.admin_password}"
}
provisioner "file" {
source = "test.txt"
destination = "/tmp/test.txt"
}
}
As an aside, if I pass incorrect login details to the provisioner (ie rerun this after the VM has already been created and supply a different password to the provisioner) the behaviour is the same. Can anyone suggest where I'm going wrong?
I eventually got this working. Honestly, I kind of forgot about this question so I can't remember what my exact issue was, the example below though seems to work on my instance:
resource "null_resource" remoteExecProvisionerWFolder {
provisioner "file" {
source = "test.txt"
destination = "/tmp/test.txt"
}
connection {
host = "${azurerm_virtual_machine.vm.ip_address}"
type = "ssh"
user = "${var.admin_username}"
password = "${var.admin_password}"
agent = "false"
}
}
So it looks like the only difference here is the addition of agent = "false". This would make some sense as there's only one SSH authentication agent for windows and it's probable I hadn't explicitly specified to use that agent before. However it could well be that I ultimately changed something elsewhere in the configuration. Sorry future people for not being much help on this one.
FYI, windows instances you can connect via type winrm
resource "null_resource" "provision_web" {
connection {
host = "${azurerm_virtual_machine.vm.ip_address}"
type = "winrm"
user = "alex"
password = "alexiscool1!"
}
provisioner "file" {
source = "path/to/folder"
destination = "C:/path/to/destination"
}
}
I am using Terraform to create Azure VMs, but since those don't have much functionality installed, I was investigating on other Azure resources. I found the Azure Data Science VM is the one that covers most of my requirements, so I was wondering if there is a way to create those with Terraform. I can't see it in the documentation, but maybe there is a workaround.
Any orientation on this would be great!
Assumption
Azure Resource Model.
Steps
There will be several steps to this process. You'll firstly need to retrieve a platform image.
data "azurerm_platform_image" "test" {
location = "West Europe"
publisher = "Microsoft"
offer = "xx"
sku = "xx"
}
Before you can fully populate this however, you will need to retrieve the SKU and Offer. Annoyingly, this isn't readily available on the internet and requires an API call or Powershell fun.
This link will help you achieve this.
Once you've got the above terraform populated, you can then utilise this to create a virtual machine.
resource "azurerm_virtual_machine" "test" {
name = "acctvm"
location = "West US 2"
resource_group_name = "${azurerm_resource_group.test.name}"
network_interface_ids = ["${azurerm_network_interface.test.id}"]
vm_size = "Standard_DS1_v2"
storage_image_reference {
id = "${data.azurerm_platform_image.test.id}"
}
storage_os_disk {
name = "myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
# Optional data disks
storage_data_disk {
name = "datadisk_new"
managed_disk_type = "Standard_LRS"
create_option = "Empty"
lun = 0
disk_size_gb = "1023"
}
storage_data_disk {
name = "${azurerm_managed_disk.test.name}"
managed_disk_id = "${azurerm_managed_disk.test.id}"
create_option = "Attach"
lun = 1
disk_size_gb = "${azurerm_managed_disk.test.disk_size_gb}"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
os_profile_linux_config {
disable_password_authentication = false
}
tags {
environment = "staging"
}
}
Follow steps here. To fill the terraform "storage_image_reference" part you can use the Azure CLI to get the information. So for example:
az vm image list --offer linux-data-science-vm --all --output table
Or
az vm image list --offer windows-data-science-vm --all --output table
Here is the list of SKUs and Offers for the Azure Data Science VM.
Windows Server 2016 edition: offer=windows-data-science-vm sku=windows2016
Ubuntu edition: offer=linux-data-science-vm-ubuntu sku=linuxdsvmubuntu
Windows Server 2012 edition: offer=standard-data-science-vm sku=standard-data-science-vm
CentOS edition: offer=linux-data-science-vm sku=linuxdsvm
Publisher for all these is microsoft-ads
I have successfully created a VM as part of a Resource Group on Azure using Terraform. Next step is to ssh in the new machine and run a few commands. For that, I have created a provisioner as part of the VM resource and set up an SSH connection:
resource "azurerm_virtual_machine" "helloterraformvm" {
name = "terraformvm"
location = "West US"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
network_interface_ids = ["${azurerm_network_interface.helloterraformnic.id}"]
vm_size = "Standard_A0"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "14.04.2-LTS"
version = "latest"
}
os_profile {
computer_name = "hostname"
user = "some_user"
password = "some_password"
}
os_profile_linux_config {
disable_password_authentication = false
}
provisioner "remote-exec" {
inline = [
"sudo apt-get install docker.io -y"
]
connection {
type = "ssh"
user = "some_user"
password = "some_password"
}
}
}
If I run "terraform apply", it seems to get into an infinite loop trying to ssh unsuccessfully, repeating this log over and over:
azurerm_virtual_machine.helloterraformvm (remote-exec): Connecting to remote host via SSH...
azurerm_virtual_machine.helloterraformvm (remote-exec): Host:
azurerm_virtual_machine.helloterraformvm (remote-exec): User: testadmin
azurerm_virtual_machine.helloterraformvm (remote-exec): Password: true
azurerm_virtual_machine.helloterraformvm (remote-exec): Private key: false
azurerm_virtual_machine.helloterraformvm (remote-exec): SSH Agent: true
I'm sure I'm doing something wrong, but I don't know what it is :(
EDIT:
I have tried setting up this machine without the provisioner, and I can SSH to it no problems with the given username/passwd. However I need to look up the host name in the Azure portal because I don't know how to retrieve it from Terraform. It's suspicious that the "Host:" line in the log is empty, so I wonder if it has anything to do with that?
UPDATE:
I've tried with different things like indicating the host name in the connection with
host = "${azurerm_public_ip.helloterraformip.id}"
and
host = "${azurerm_public_ip.helloterraformips.ip_address}"
as indicated in the docs, but with no success.
I've also tried using ssh-keys instead of password, but same result - infinite loop of connection tries, with no clear error message as of why it's not connecting.
I have managed to make this work. I changed several things:
Gave name of host to connection.
Configured SSH keys properly - they need to be unencrypted.
Took the connection element out of the provisioner element.
Here's the full working Terraform file, replacing the data like SSH keys, etc.:
# Configure Azure provider
provider "azurerm" {
subscription_id = "${var.azure_subscription_id}"
client_id = "${var.azure_client_id}"
client_secret = "${var.azure_client_secret}"
tenant_id = "${var.azure_tenant_id}"
}
# create a resource group if it doesn't exist
resource "azurerm_resource_group" "rg" {
name = "sometestrg"
location = "ukwest"
}
# create virtual network
resource "azurerm_virtual_network" "vnet" {
name = "tfvnet"
address_space = ["10.0.0.0/16"]
location = "ukwest"
resource_group_name = "${azurerm_resource_group.rg.name}"
}
# create subnet
resource "azurerm_subnet" "subnet" {
name = "tfsub"
resource_group_name = "${azurerm_resource_group.rg.name}"
virtual_network_name = "${azurerm_virtual_network.vnet.name}"
address_prefix = "10.0.2.0/24"
#network_security_group_id = "${azurerm_network_security_group.nsg.id}"
}
# create public IPs
resource "azurerm_public_ip" "ip" {
name = "tfip"
location = "ukwest"
resource_group_name = "${azurerm_resource_group.rg.name}"
public_ip_address_allocation = "dynamic"
domain_name_label = "sometestdn"
tags {
environment = "staging"
}
}
# create network interface
resource "azurerm_network_interface" "ni" {
name = "tfni"
location = "ukwest"
resource_group_name = "${azurerm_resource_group.rg.name}"
ip_configuration {
name = "ipconfiguration"
subnet_id = "${azurerm_subnet.subnet.id}"
private_ip_address_allocation = "static"
private_ip_address = "10.0.2.5"
public_ip_address_id = "${azurerm_public_ip.ip.id}"
}
}
# create storage account
resource "azurerm_storage_account" "storage" {
name = "someteststorage"
resource_group_name = "${azurerm_resource_group.rg.name}"
location = "ukwest"
account_type = "Standard_LRS"
tags {
environment = "staging"
}
}
# create storage container
resource "azurerm_storage_container" "storagecont" {
name = "vhd"
resource_group_name = "${azurerm_resource_group.rg.name}"
storage_account_name = "${azurerm_storage_account.storage.name}"
container_access_type = "private"
depends_on = ["azurerm_storage_account.storage"]
}
# create virtual machine
resource "azurerm_virtual_machine" "vm" {
name = "sometestvm"
location = "ukwest"
resource_group_name = "${azurerm_resource_group.rg.name}"
network_interface_ids = ["${azurerm_network_interface.ni.id}"]
vm_size = "Standard_A0"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
storage_os_disk {
name = "myosdisk"
vhd_uri = "${azurerm_storage_account.storage.primary_blob_endpoint}${azurerm_storage_container.storagecont.name}/myosdisk.vhd"
caching = "ReadWrite"
create_option = "FromImage"
}
os_profile {
computer_name = "testhost"
admin_username = "testuser"
admin_password = "Password123"
}
os_profile_linux_config {
disable_password_authentication = false
ssh_keys = [{
path = "/home/testuser/.ssh/authorized_keys"
key_data = "ssh-rsa xxx email#something.com"
}]
}
connection {
host = "sometestdn.ukwest.cloudapp.azure.com"
user = "testuser"
type = "ssh"
private_key = "${file("~/.ssh/id_rsa_unencrypted")}"
timeout = "1m"
agent = true
}
provisioner "remote-exec" {
inline = [
"sudo apt-get update",
"sudo apt-get install docker.io -y",
"git clone https://github.com/somepublicrepo.git",
"cd Docker-sample",
"sudo docker build -t mywebapp .",
"sudo docker run -d -p 5000:5000 mywebapp"
]
}
tags {
environment = "staging"
}
}
According to your description, Azure Custom Script Extension is an option for you.
The Custom Script Extension downloads and executes scripts on Azure
virtual machines. This extension is useful for post deployment
configuration, software installation, or any other configuration /
management task.
Remove provisioner "remote-exec" instead of below:
resource "azurerm_virtual_machine_extension" "helloterraformvm" {
name = "hostname"
location = "West US"
resource_group_name = "${azurerm_resource_group.helloterraformvm.name}"
virtual_machine_name = "${azurerm_virtual_machine.helloterraformvm.name}"
publisher = "Microsoft.OSTCExtensions"
type = "CustomScriptForLinux"
type_handler_version = "1.2"
settings = <<SETTINGS
{
"commandToExecute": "apt-get install docker.io -y"
}
SETTINGS
}
Note: Command is executed by root user, don't use sudo.
More information please refer to this link: azurerm_virtual_machine_extension.
For a list of possible extensions, you can use the Azure CLI command az vm extension image list -o table
Update: The above example only supports single command. If you need to multiple commands. Like install docker on your VM, you need
apt-get update
apt-get install docker.io -y
Save it as a file named script.sh and save it to Azure Storage account or GitHub(The file should be public). Modify terraform file like below:
settings = <<SETTINGS
{
"fileUris": ["https://gist.githubusercontent.com/Walter-Shui/dedb53f71da126a179544c91d267cdce/raw/bb3e4d90e3291530570eca6f4ff7981fdcab695c/script.sh"],
"commandToExecute": "sh script.sh"
}
SETTINGS