azureterraformifconfig

No public IP when running ifconfig on publicly accessible Azure instance created via Terraform


I am provisioning a cluster on Azure where I can SSH into each machine using their public IPs. The Terraform file:

provider "azurerm" {
  version = "~>2.0"
  features {}
}

resource "azurerm_resource_group" "main" {
  name     = "${var.name}-resources"
  location = "eastus2"
}

resource "azurerm_virtual_network" "main" {
  name                = "${var.name}-network"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_subnet" "internal" {
  name                 = "internal"
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.0.2.0/24"]
}

resource "azurerm_network_security_group" "nsg" {
  name                = "${var.name}NetworkSecurityGroup"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  security_rule {
    name                       = "SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_public_ip" "publicip" {
  name                = "${var.name}PublicIP-${count.index}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  allocation_method   = "Dynamic"
  count               = 1 + var.workers
}

resource "azurerm_network_interface" "main" {
  name                = "${var.name}-nic-${count.index}"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  count               = 1 + var.workers

  ip_configuration {
    name                          = "${var.name}NICConfig${count.index}"
    subnet_id                     = azurerm_subnet.internal.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.publicip[count.index].id
  }
}

resource "azurerm_network_interface_security_group_association" "main" {
  count                     = 1 + var.workers
  network_interface_id      = azurerm_network_interface.main[count.index].id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

resource "azurerm_linux_virtual_machine" "main" {
  name                  = "${var.name}-${count.index}"
  resource_group_name   = azurerm_resource_group.main.name
  location              = azurerm_resource_group.main.location
  size                  = "Standard_D8s_v3"
  count                 = 1 + var.workers
  admin_username        = "adminuser"
  network_interface_ids = [azurerm_network_interface.main[count.index].id]

  admin_ssh_key {
    username   = "adminuser"
    public_key = file("~/.ssh/id_rsa.pub")
  }

  source_image_reference {
    publisher = "OpenLogic"
    offer     = "CentOS"
    sku       = "7.7"
    version   = "7.7.2020042900"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }
}

output "ips" {
  value = ["${azurerm_linux_virtual_machine.main.*.public_ip_address}"]
}

However, once I am on the machine, I can see that the virtual machine doesn't have a public IP when running ifconfig:

Last login: Mon Jul 20 10:14:45 2020 from 78.141.104.252
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.2.5  netmask 255.255.255.0  broadcast 10.0.2.255
        inet6 fe80::20d:3aff:fe0e:8428  prefixlen 64  scopeid 0x20<link>
        ether 00:0d:3a:0e:84:28  txqueuelen 1000  (Ethernet)
        RX packets 146462  bytes 156556974 (149.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 62320  bytes 12974670 (12.3 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 84  bytes 4400 (4.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 84  bytes 4400 (4.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

This is a problem when using kubeadm on these instances as I need the public IP to be an existing network interface. Is there something I can set in the Terraform file to make this happen? I don't understand why the public IP isn't there if I can SSH into the machine using this public IP.


Solution

  • As answered by Taguada, Azure machines are unaware of their public IPs. To make them aware of it, Azure provides a tutorial.

    In my case, on CentOS 7.7, I ran this Ansible script on all of my hosts:

    ---
    - name: Set public IP
      gather_facts: No
      hosts: all
      become: true
    
      tasks:
        - name: Set public IP in instance
          blockinfile:
            path: /etc/sysconfig/network-scripts/ifcfg-eth0:0
            block: |
              DEVICE=eth0:0
              BOOTPROTO=static
              ONBOOT=yes
              IPADDR={{ ansible_ssh_host }}
              NETMASK=255.255.255.0
            create: true
        - name: restart network
          shell: /etc/init.d/network restart
    

    And the machines were then aware of their public IPs.