Working with /etc/hosts file using Azure IoT and OSConfig

Important

Version 1.0.3 (published 28 June 2022) includes breaking changes to member names which may impact existing users. For more information, see: Member names transition from PascalCase to camelCase in version 1.0.3

Audience and scope

This article is designed to support people who provision or manage devices with Azure IoT. If that doesn't sound like you, consider taking a look at Audiences for OSConfig documentation.

This article is about getting and setting the contents of the /etc/hosts file, used by devices for name resolution. In edge/IoT scenarios, hosts file entries are often used to augment broader name resolution technology such as DNS. For example, you may need all devices on a certain manufacturing floor to map the name "controller-endpoint" to a specific on-prem IP address. Similarly, you might need a set of devices to map the name "camera-feed" to a loopback IP address.

Prerequisites

If you are using this article for reference (for example, you are here to copy a property name), there are no pre-requisites.

If you want to try the examples on live systems (recommended), then:

  1. You will need an Azure account with an IoT Hub

    This article assumes some familiarity with IoT Hub and related tools. For example, it assumes you are comfortable creating IoT Hubs and attaching devices. If you prefer a more prescriptive step-by-step introduction to installing and using OSConfig from scratch, see: Quickstart: Manage a single virtual IoT device using Azure CLI instead.

  2. You will need at least one Linux device with the OSConfig agent installed and connected to Azure IoT.

    For more information, see: How and where to install the OSConfig agent for Linux.

  3. You will use Azure Portal or Azure CLI to interact with the devices via your IoT Hub

    For further steps, choose your preferred experience:

  1. Ensure you are signed in to the Azure Portal and can access your IoT Hub's Overview page Screenshot showing IoT Hub and devices from the Azure Portal

The object model

The following are the key desired and reported properties related to the hosts file contents.

Important

Version 1.0.3 (published 28 June 2022) includes breaking changes to member names which may impact existing users. For more information, see: Member names transition from PascalCase to camelCase in version 1.0.3

Primary use Populated by Notes
reported.HostName.hosts Get scenarios OSConfig agent Analogous to cat /etc/hosts on most Linux systems; see below for the data format
desired.HostName.desiredHosts Set scenarios Admin or admin tools Analogous to overwriting cat /etc/hosts on most Linux systems; see below for the data format
reported.HostName.desiredHosts.value Set scenarios OSConfig agent Acknowledges receipt of desired hosts details; should match desiredHosts
reported.HostName.desiredHosts.ac Set scenarios OSConfig agent Status for reaching desired state for hosts details; 200 indicates success

Important

desiredHosts represents a replace operation (not add or merge) for the contents of /etc/hosts. Please ensure that any value you place in desiredHosts contains all of the entries you need.

Hosts files typically include multiple entries separated by line breaks. To project these as a single string value in IoT Hub, the Hosts and desiredHosts properties use semicolons in place of line breaks. Also, comment lines in the existing hosts file are ignored when OSConfig is populating the Hosts property. For example, assume a hosts file like:

## a comment line
192.168.1.139 host.docker.internal
127.0.0.1 localhost

The corresponding value of the Hosts property would be: 192.168.1.139 host.docker.internal;127.0.0.1 localhost. To see examples from a real device's OSConfig twin in IoT Hub, see the reference section at the end of this article.

A. Examples for individual devices

The following demonstrate specific use cases. You can use these as starting points and adapt for your unique environment. For at-scale examples, see: B. At-scale examples for fleets of devices.

Example A.1. How to check hosts file contents for a single device

In this example, we will get the reported.HostName.hosts property, which reflects the hosts file content on the device.

  1. Using Azure Portal, navigate to the osconfig module twin, then scroll down to find reported.HostName.hosts

    Screen capture showing how to get desiredHosts property from Azure Portal

Example A.2. How to modify hosts file contents for single device

In this example, you will replace the contents of /etc/hosts on a device.

  1. Using Azure Portal, set the desiredHosts property in the osconfig module twin.

    Screen capture showing how to set desiredHosts property from Azure Portal

  2. You can verify the change is made successfully from the module twin itself or you can verify the contents of /etc/hosts file on the device has been updated. Scroll down the module twin to find reported properties for HostName .

B. At-scale examples for fleets of devices

Example B.1. How to set and report/audit hosts file content for fleet of devices

In this example you will create an IoT Hub Configuration (also known as IoT Hub Automatic Device Management [ADM]). For any devices which meet the target criteria, the IoT Hub Configuration will set the value of desiredHosts.

  1. From your Azure IoT Hub's portal page, choose Device management --> Configurations --> Add Module Configuration.

  2. Specify a name and update the Twin Settings with the desired host configuration. Set Module Twin Property to properties.desired.HostName and set the Module Twin Property Content to the desired content, {"desiredHosts": <YOUR LIST HERE>}, replacing <YOUR LIST HERE> with your semi-colon delimited list of hostnames and ip addresses.

  3. Create a Custom Metric with name successfullyConfigured and the Metric Criteria of SELECT deviceId from devices.modules where moduleId='osconfig' AND properties.reported.HostName.desiredHosts.ac=200.

  4. For the Target Modules, specify the criteria for which devices are in scope. In this example, we will target all devices with OSConfig capabilities, using a Target Condition of FROM devices.modules where moduleId='osconfig'

    Screen capture showing how to update hosts file using Configuration from Azure Portal

    Tip

    The background jobs which power IoT Hub Configurations run every few minutes. In the following steps you might initially see results indicating nothing has happened yet. If you encounter this, wait 5 minutes.

  5. To observe which devices' twins have been updated (cloud side), see the Applied metric (also known as appliedCount)

    Screen capture showing how to verify applied metrics from Configuration

  6. To observe which devices have completed the configuration (device has acknowledged successful change), see the successfullyConfigured metric.

    Screen capture showing how to verify custom metrics from Configuration

  7. (optional step) You can also observe the new value of the Hosts property using IoT Hub Queries. Navigate to Device Management --> Queries and run the query SELECT deviceId, properties.reported.HostName.hosts FROM devices.modules WHERE moduleId='osconfig'"

    Screen capture that shows how to query current host configuration from Azure Portal

Reference: Example twin from Iot Hub

The following is excerpted from an osconfig module twin in IoT Hub. For context it includes most of the raw twin, with certain properties (like $metadata) removed for brevity. The properties related to this article are highlighted.

{
    "deviceId": "device03",
    "moduleId": "osconfig",
    "connectionState": "Connected",
    "modelId": "dtmi:osconfig:deviceosconfiguration;5",
    "version": 28,
    "properties": {
        "desired": {
            "Settings": {
                "__t": "c",
                "DeviceHealthTelemetryConfiguration": 2,
                "DeliveryOptimizationPolicies": {
                    "PercentageDownloadThrottle": 50,
                    "CacheHostSource": 1,
                    "CacheHost": "http://mycachehost"
                }
            },
            "CommandRunner": {
                "__t": "c",
                "CommandArguments": {
                    "CommandId": "set_timezone__And_report_back",
                    "Arguments": "timedatectl set-timezone UTC; timedatect l grep zone | tr -d '[:space:]'",
                    "SingleLineTextResult": false,
                    "Action": 3
                }
            },
            "HostName": {
                "__t": "c",
                "DesiredName": "NewHostName123",
                "DesiredHosts": "127.0.0.1 localhost;::1 ip6-localhost ip6-loopback;fe00::0 ip6-localnet;ff00::0 ip6-mcastprefix;ff02::1 ip6-allnodes;ff02::2 ip6-allrouters;ff02::3 ip6-allhosts;10.1.2.3 my-on-prem-equipment"
            },
            "Ztsi": {
                "__t": "c",
                "DesiredServiceUrl": "https://my-attestation-endpoint",
                "DesiredEnabled": true
            },
            "$version": 8
        },
        "reported": {
            "Firewall": {
                "__t": "c",
                "FirewallState": 1,
                "FirewallFingerprint": "86cadaa93d8c0e0ee42e36190413265c2e218c87a0c494c026cf7de601765e72"
            },
            "CommandRunner": {
                "__t": "c",
                "CommandStatus": {
                    "CommandId": "set_timezone__And_report_back",
                    "ResultCode": 0,
                    "TextResult": "",
                    "CurrentState": 2
                },
                "CommandArguments": {
                    "value": {
                        "CommandId": "set_timezone__And_report_back",
                        "Arguments": "timedatectl set-timezone UTC; timedatect l grep zone | tr -d '[:space:]'",
                        "SingleLineTextResult": false,
                        "Action": 3
                    },
                    "ac": 200,
                    "ad": "-",
                    "av": 4
                }
            },
            "HostName": {
                "__t": "c",
                "Name": "NewHostName123",
                "Hosts": "127.0.0.1 localhost;::1 ip6-localhost ip6-loopback;fe00::0 ip6-localnet;ff00::0 ip6-mcastprefix;ff02::1 ip6-allnodes;ff02::2 ip6-allrouters;ff02::3 ip6-allhosts;10.1.2.3 my-on-prem-equipment",
                "DesiredName": {
                    "value": "NewHostName123",
                    "ac": 200,
                    "ad": "-",
                    "av": 5
                },
                "DesiredHosts": {
                    "value": "127.0.0.1 localhost;::1 ip6-localhost ip6-loopback;fe00::0 ip6-localnet;ff00::0 ip6-mcastprefix;ff02::1 ip6-allnodes;ff02::2 ip6-allrouters;ff02::3 ip6-allhosts;10.1.2.3 my-on-prem-equipment",
                    "ac": 200,
                    "ad": "-",
                    "av": 6
                }
            },
            "Networking": {
                "__t": "c",
                "NetworkConfiguration": {
                    "InterfaceTypes": "eth0=ether;lo=loopback",
                    "MacAddresses": "eth0=00:22:48:7b:04:39;lo=00:00:00:00:00:00",
                    "IpAddresses": "eth0=10.0.0.6,fe80::222:48ff:fe7b:439;lo=127.0.0.1,::1",
                    "SubnetMasks": "eth0=/24,/64;lo=/8,/128",
                    "DefaultGateways": "eth0=10.0.0.1",
                    "DnsServers": "eth0=168.63.129.16",
                    "DhcpEnabled": "eth0=false;lo=false",
                    "Enabled": "eth0=true;lo=unknown",
                    "Connected": "eth0=true;lo=true"
                }
            },
            "Tpm": {
                "__t": "c",
                "TpmStatus": 2
            },
            "Ztsi": {
                "__t": "c",
                "Enabled": 0,
                "ServiceUrl": "",
                "DesiredServiceUrl": {
                    "value": "https://my-attestation-endpoint",
                    "ac": 200,
                    "ad": "-",
                    "av": 7
                },
                "DesiredEnabled": {
                    "value": true,
                    "ac": 200,
                    "ad": "-",
                    "av": 8
                }
            },
            "Settings": {
                "__t": "c",
                "DeviceHealthTelemetryConfiguration": {
                    "value": 2,
                    "ac": 200,
                    "ad": "-",
                    "av": 2
                },
                "DeliveryOptimizationPolicies": {
                    "value": {
                        "PercentageDownloadThrottle": 50,
                        "CacheHostSource": 1,
                        "CacheHost": "http://mycachehost"
                    },
                    "ac": 400,
                    "ad": "-",
                    "av": 3
                }
            },
            "$version": 20
        }
    }
}

Next steps

For an overview of OSConfig scenarios and capabilities, see:

For specific practical examples, see: