Configure Azure Device Registry Namespace Devices

The azure-native:deviceregistry:NamespaceDevice resource, part of the Pulumi Azure Native provider, defines a device within a Device Registry namespace: its endpoints, authentication methods, and edge location placement. This guide focuses on three capabilities: OPC UA endpoint authentication methods, inbound connectivity from edge devices, and outbound messaging to Azure services.

Devices belong to a Device Registry namespace and run on Azure Arc-enabled edge locations. They reference secrets for credentials and may connect to Event Grid or other Azure services. The examples are intentionally small. Combine them with your own namespace, CustomLocation, and secret management.

Connect to OPC UA servers with username and password

Industrial deployments often start by connecting to OPC UA servers using username and password authentication.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const namespaceDevice = new azure_native.deviceregistry.NamespaceDevice("namespaceDevice", {
    attributes: {
        deviceCategory: 16,
        deviceOwner: "IT",
        deviceType: "sensor",
    },
    deviceName: "namespace-device-on-edge",
    enabled: true,
    endpoints: {
        inbound: {
            theOnlyOPCUABroker: {
                address: "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                authentication: {
                    method: azure_native.deviceregistry.AuthenticationMethod.UsernamePassword,
                    usernamePasswordCredentials: {
                        passwordSecretName: "pwd-ref",
                        usernameSecretName: "user-ref",
                    },
                },
                endpointType: "microsoft.opcua/v1",
                version: "2",
            },
        },
    },
    extendedLocation: {
        name: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        type: "CustomLocation",
    },
    externalDeviceId: "unique-edge-device-identifier",
    location: "West Europe",
    namespaceName: "adr-namespace-gbk0925-n01",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

namespace_device = azure_native.deviceregistry.NamespaceDevice("namespaceDevice",
    attributes={
        "deviceCategory": 16,
        "deviceOwner": "IT",
        "deviceType": "sensor",
    },
    device_name="namespace-device-on-edge",
    enabled=True,
    endpoints={
        "inbound": {
            "theOnlyOPCUABroker": {
                "address": "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                "authentication": {
                    "method": azure_native.deviceregistry.AuthenticationMethod.USERNAME_PASSWORD,
                    "username_password_credentials": {
                        "password_secret_name": "pwd-ref",
                        "username_secret_name": "user-ref",
                    },
                },
                "endpoint_type": "microsoft.opcua/v1",
                "version": "2",
            },
        },
    },
    extended_location={
        "name": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        "type": "CustomLocation",
    },
    external_device_id="unique-edge-device-identifier",
    location="West Europe",
    namespace_name="adr-namespace-gbk0925-n01",
    resource_group_name="myResourceGroup")
package main

import (
	deviceregistry "github.com/pulumi/pulumi-azure-native-sdk/deviceregistry/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := deviceregistry.NewNamespaceDevice(ctx, "namespaceDevice", &deviceregistry.NamespaceDeviceArgs{
			Attributes: pulumi.Any(map[string]interface{}{
				"deviceCategory": 16,
				"deviceOwner":    "IT",
				"deviceType":     "sensor",
			}),
			DeviceName: pulumi.String("namespace-device-on-edge"),
			Enabled:    pulumi.Bool(true),
			Endpoints: &deviceregistry.MessagingEndpointsArgs{
				Inbound: deviceregistry.InboundEndpointsMap{
					"theOnlyOPCUABroker": &deviceregistry.InboundEndpointsArgs{
						Address: pulumi.String("opc.tcp://192.168.86.23:51211/UA/SampleServer"),
						Authentication: &deviceregistry.HostAuthenticationArgs{
							Method: pulumi.String(deviceregistry.AuthenticationMethodUsernamePassword),
							UsernamePasswordCredentials: &deviceregistry.UsernamePasswordCredentialsArgs{
								PasswordSecretName: pulumi.String("pwd-ref"),
								UsernameSecretName: pulumi.String("user-ref"),
							},
						},
						EndpointType: pulumi.String("microsoft.opcua/v1"),
						Version:      pulumi.String("2"),
					},
				},
			},
			ExtendedLocation: &deviceregistry.ExtendedLocationArgs{
				Name: pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1"),
				Type: pulumi.String("CustomLocation"),
			},
			ExternalDeviceId:  pulumi.String("unique-edge-device-identifier"),
			Location:          pulumi.String("West Europe"),
			NamespaceName:     pulumi.String("adr-namespace-gbk0925-n01"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var namespaceDevice = new AzureNative.DeviceRegistry.NamespaceDevice("namespaceDevice", new()
    {
        Attributes = new Dictionary<string, object?>
        {
            ["deviceCategory"] = 16,
            ["deviceOwner"] = "IT",
            ["deviceType"] = "sensor",
        },
        DeviceName = "namespace-device-on-edge",
        Enabled = true,
        Endpoints = new AzureNative.DeviceRegistry.Inputs.MessagingEndpointsArgs
        {
            Inbound = 
            {
                { "theOnlyOPCUABroker", new AzureNative.DeviceRegistry.Inputs.InboundEndpointsArgs
                {
                    Address = "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                    Authentication = new AzureNative.DeviceRegistry.Inputs.HostAuthenticationArgs
                    {
                        Method = AzureNative.DeviceRegistry.AuthenticationMethod.UsernamePassword,
                        UsernamePasswordCredentials = new AzureNative.DeviceRegistry.Inputs.UsernamePasswordCredentialsArgs
                        {
                            PasswordSecretName = "pwd-ref",
                            UsernameSecretName = "user-ref",
                        },
                    },
                    EndpointType = "microsoft.opcua/v1",
                    Version = "2",
                } },
            },
        },
        ExtendedLocation = new AzureNative.DeviceRegistry.Inputs.ExtendedLocationArgs
        {
            Name = "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
            Type = "CustomLocation",
        },
        ExternalDeviceId = "unique-edge-device-identifier",
        Location = "West Europe",
        NamespaceName = "adr-namespace-gbk0925-n01",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.deviceregistry.NamespaceDevice;
import com.pulumi.azurenative.deviceregistry.NamespaceDeviceArgs;
import com.pulumi.azurenative.deviceregistry.inputs.MessagingEndpointsArgs;
import com.pulumi.azurenative.deviceregistry.inputs.ExtendedLocationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var namespaceDevice = new NamespaceDevice("namespaceDevice", NamespaceDeviceArgs.builder()
            .attributes(Map.ofEntries(
                Map.entry("deviceCategory", 16),
                Map.entry("deviceOwner", "IT"),
                Map.entry("deviceType", "sensor")
            ))
            .deviceName("namespace-device-on-edge")
            .enabled(true)
            .endpoints(MessagingEndpointsArgs.builder()
                .inbound(Map.of("theOnlyOPCUABroker", InboundEndpointsArgs.builder()
                    .address("opc.tcp://192.168.86.23:51211/UA/SampleServer")
                    .authentication(HostAuthenticationArgs.builder()
                        .method("UsernamePassword")
                        .usernamePasswordCredentials(UsernamePasswordCredentialsArgs.builder()
                            .passwordSecretName("pwd-ref")
                            .usernameSecretName("user-ref")
                            .build())
                        .build())
                    .endpointType("microsoft.opcua/v1")
                    .version("2")
                    .build()))
                .build())
            .extendedLocation(ExtendedLocationArgs.builder()
                .name("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1")
                .type("CustomLocation")
                .build())
            .externalDeviceId("unique-edge-device-identifier")
            .location("West Europe")
            .namespaceName("adr-namespace-gbk0925-n01")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  namespaceDevice:
    type: azure-native:deviceregistry:NamespaceDevice
    properties:
      attributes:
        deviceCategory: 16
        deviceOwner: IT
        deviceType: sensor
      deviceName: namespace-device-on-edge
      enabled: true
      endpoints:
        inbound:
          theOnlyOPCUABroker:
            address: opc.tcp://192.168.86.23:51211/UA/SampleServer
            authentication:
              method: UsernamePassword
              usernamePasswordCredentials:
                passwordSecretName: pwd-ref
                usernameSecretName: user-ref
            endpointType: microsoft.opcua/v1
            version: '2'
      extendedLocation:
        name: /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1
        type: CustomLocation
      externalDeviceId: unique-edge-device-identifier
      location: West Europe
      namespaceName: adr-namespace-gbk0925-n01
      resourceGroupName: myResourceGroup

The inbound endpoints map defines named connections to OPC UA servers. Each endpoint specifies an address (the OPC UA server URL), an authentication method, and credential references. The usernamePasswordCredentials property points to secret names that store the username and password. The extendedLocation property places the device on a specific Azure Arc CustomLocation, which determines where the device agent runs.

Connect to OPC UA servers without authentication

Development environments sometimes expose OPC UA servers without authentication for quick prototyping.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const namespaceDevice = new azure_native.deviceregistry.NamespaceDevice("namespaceDevice", {
    attributes: {
        deviceCategory: 16,
        deviceOwner: "OT",
        deviceType: "dough-maker",
    },
    deviceName: "namespace-device-on-edge",
    enabled: true,
    endpoints: {
        inbound: {
            theOnlyOPCUABroker: {
                address: "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                authentication: {
                    method: azure_native.deviceregistry.AuthenticationMethod.Anonymous,
                },
                endpointType: "microsoft.opcua/v1",
                version: "2",
            },
        },
    },
    extendedLocation: {
        name: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        type: "CustomLocation",
    },
    externalDeviceId: "unique-edge-device-identifier",
    location: "West Europe",
    namespaceName: "adr-namespace-gbk0925-n01",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

namespace_device = azure_native.deviceregistry.NamespaceDevice("namespaceDevice",
    attributes={
        "deviceCategory": 16,
        "deviceOwner": "OT",
        "deviceType": "dough-maker",
    },
    device_name="namespace-device-on-edge",
    enabled=True,
    endpoints={
        "inbound": {
            "theOnlyOPCUABroker": {
                "address": "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                "authentication": {
                    "method": azure_native.deviceregistry.AuthenticationMethod.ANONYMOUS,
                },
                "endpoint_type": "microsoft.opcua/v1",
                "version": "2",
            },
        },
    },
    extended_location={
        "name": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        "type": "CustomLocation",
    },
    external_device_id="unique-edge-device-identifier",
    location="West Europe",
    namespace_name="adr-namespace-gbk0925-n01",
    resource_group_name="myResourceGroup")
package main

import (
	deviceregistry "github.com/pulumi/pulumi-azure-native-sdk/deviceregistry/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := deviceregistry.NewNamespaceDevice(ctx, "namespaceDevice", &deviceregistry.NamespaceDeviceArgs{
			Attributes: pulumi.Any(map[string]interface{}{
				"deviceCategory": 16,
				"deviceOwner":    "OT",
				"deviceType":     "dough-maker",
			}),
			DeviceName: pulumi.String("namespace-device-on-edge"),
			Enabled:    pulumi.Bool(true),
			Endpoints: &deviceregistry.MessagingEndpointsArgs{
				Inbound: deviceregistry.InboundEndpointsMap{
					"theOnlyOPCUABroker": &deviceregistry.InboundEndpointsArgs{
						Address: pulumi.String("opc.tcp://192.168.86.23:51211/UA/SampleServer"),
						Authentication: &deviceregistry.HostAuthenticationArgs{
							Method: pulumi.String(deviceregistry.AuthenticationMethodAnonymous),
						},
						EndpointType: pulumi.String("microsoft.opcua/v1"),
						Version:      pulumi.String("2"),
					},
				},
			},
			ExtendedLocation: &deviceregistry.ExtendedLocationArgs{
				Name: pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1"),
				Type: pulumi.String("CustomLocation"),
			},
			ExternalDeviceId:  pulumi.String("unique-edge-device-identifier"),
			Location:          pulumi.String("West Europe"),
			NamespaceName:     pulumi.String("adr-namespace-gbk0925-n01"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var namespaceDevice = new AzureNative.DeviceRegistry.NamespaceDevice("namespaceDevice", new()
    {
        Attributes = new Dictionary<string, object?>
        {
            ["deviceCategory"] = 16,
            ["deviceOwner"] = "OT",
            ["deviceType"] = "dough-maker",
        },
        DeviceName = "namespace-device-on-edge",
        Enabled = true,
        Endpoints = new AzureNative.DeviceRegistry.Inputs.MessagingEndpointsArgs
        {
            Inbound = 
            {
                { "theOnlyOPCUABroker", new AzureNative.DeviceRegistry.Inputs.InboundEndpointsArgs
                {
                    Address = "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                    Authentication = new AzureNative.DeviceRegistry.Inputs.HostAuthenticationArgs
                    {
                        Method = AzureNative.DeviceRegistry.AuthenticationMethod.Anonymous,
                    },
                    EndpointType = "microsoft.opcua/v1",
                    Version = "2",
                } },
            },
        },
        ExtendedLocation = new AzureNative.DeviceRegistry.Inputs.ExtendedLocationArgs
        {
            Name = "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
            Type = "CustomLocation",
        },
        ExternalDeviceId = "unique-edge-device-identifier",
        Location = "West Europe",
        NamespaceName = "adr-namespace-gbk0925-n01",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.deviceregistry.NamespaceDevice;
import com.pulumi.azurenative.deviceregistry.NamespaceDeviceArgs;
import com.pulumi.azurenative.deviceregistry.inputs.MessagingEndpointsArgs;
import com.pulumi.azurenative.deviceregistry.inputs.ExtendedLocationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var namespaceDevice = new NamespaceDevice("namespaceDevice", NamespaceDeviceArgs.builder()
            .attributes(Map.ofEntries(
                Map.entry("deviceCategory", 16),
                Map.entry("deviceOwner", "OT"),
                Map.entry("deviceType", "dough-maker")
            ))
            .deviceName("namespace-device-on-edge")
            .enabled(true)
            .endpoints(MessagingEndpointsArgs.builder()
                .inbound(Map.of("theOnlyOPCUABroker", InboundEndpointsArgs.builder()
                    .address("opc.tcp://192.168.86.23:51211/UA/SampleServer")
                    .authentication(HostAuthenticationArgs.builder()
                        .method("Anonymous")
                        .build())
                    .endpointType("microsoft.opcua/v1")
                    .version("2")
                    .build()))
                .build())
            .extendedLocation(ExtendedLocationArgs.builder()
                .name("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1")
                .type("CustomLocation")
                .build())
            .externalDeviceId("unique-edge-device-identifier")
            .location("West Europe")
            .namespaceName("adr-namespace-gbk0925-n01")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  namespaceDevice:
    type: azure-native:deviceregistry:NamespaceDevice
    properties:
      attributes:
        deviceCategory: 16
        deviceOwner: OT
        deviceType: dough-maker
      deviceName: namespace-device-on-edge
      enabled: true
      endpoints:
        inbound:
          theOnlyOPCUABroker:
            address: opc.tcp://192.168.86.23:51211/UA/SampleServer
            authentication:
              method: Anonymous
            endpointType: microsoft.opcua/v1
            version: '2'
      extendedLocation:
        name: /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1
        type: CustomLocation
      externalDeviceId: unique-edge-device-identifier
      location: West Europe
      namespaceName: adr-namespace-gbk0925-n01
      resourceGroupName: myResourceGroup

Setting the authentication method to Anonymous removes the need for credentials. The device connects directly to the OPC UA server without presenting username, password, or certificates. This simplifies testing but should not be used in production.

Authenticate with X.509 certificates and trust lists

Production deployments require certificate-based authentication to meet security standards.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const namespaceDevice = new azure_native.deviceregistry.NamespaceDevice("namespaceDevice", {
    attributes: {
        deviceCategory: 16,
        deviceOwner: "OT",
        deviceType: "OPCUAServers",
    },
    deviceName: "namespace-device-on-edge",
    enabled: true,
    endpoints: {
        inbound: {
            theV1OPCUAEndpoint: {
                address: "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                authentication: {
                    method: azure_native.deviceregistry.AuthenticationMethod.Certificate,
                    x509Credentials: {
                        certificateSecretName: "cert-secret",
                    },
                },
                endpointType: "microsoft.opcua/v1",
                version: "2",
            },
            theV2OPCUAEndpoint: {
                address: "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                authentication: {
                    method: azure_native.deviceregistry.AuthenticationMethod.Certificate,
                    x509Credentials: {
                        certificateSecretName: "cert-secret",
                    },
                },
                endpointType: "microsoft.opcua/v1",
                trustSettings: {
                    trustList: "trust-secret-reference",
                },
                version: "2",
            },
        },
    },
    extendedLocation: {
        name: "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        type: "CustomLocation",
    },
    externalDeviceId: "unique-edge-device-identifier",
    location: "West Europe",
    namespaceName: "adr-namespace-gbk0925-n01",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

namespace_device = azure_native.deviceregistry.NamespaceDevice("namespaceDevice",
    attributes={
        "deviceCategory": 16,
        "deviceOwner": "OT",
        "deviceType": "OPCUAServers",
    },
    device_name="namespace-device-on-edge",
    enabled=True,
    endpoints={
        "inbound": {
            "theV1OPCUAEndpoint": {
                "address": "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                "authentication": {
                    "method": azure_native.deviceregistry.AuthenticationMethod.CERTIFICATE,
                    "x509_credentials": {
                        "certificate_secret_name": "cert-secret",
                    },
                },
                "endpoint_type": "microsoft.opcua/v1",
                "version": "2",
            },
            "theV2OPCUAEndpoint": {
                "address": "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                "authentication": {
                    "method": azure_native.deviceregistry.AuthenticationMethod.CERTIFICATE,
                    "x509_credentials": {
                        "certificate_secret_name": "cert-secret",
                    },
                },
                "endpoint_type": "microsoft.opcua/v1",
                "trust_settings": {
                    "trust_list": "trust-secret-reference",
                },
                "version": "2",
            },
        },
    },
    extended_location={
        "name": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
        "type": "CustomLocation",
    },
    external_device_id="unique-edge-device-identifier",
    location="West Europe",
    namespace_name="adr-namespace-gbk0925-n01",
    resource_group_name="myResourceGroup")
package main

import (
	deviceregistry "github.com/pulumi/pulumi-azure-native-sdk/deviceregistry/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := deviceregistry.NewNamespaceDevice(ctx, "namespaceDevice", &deviceregistry.NamespaceDeviceArgs{
			Attributes: pulumi.Any(map[string]interface{}{
				"deviceCategory": 16,
				"deviceOwner":    "OT",
				"deviceType":     "OPCUAServers",
			}),
			DeviceName: pulumi.String("namespace-device-on-edge"),
			Enabled:    pulumi.Bool(true),
			Endpoints: &deviceregistry.MessagingEndpointsArgs{
				Inbound: deviceregistry.InboundEndpointsMap{
					"theV1OPCUAEndpoint": &deviceregistry.InboundEndpointsArgs{
						Address: pulumi.String("opc.tcp://192.168.86.23:51211/UA/SampleServer"),
						Authentication: &deviceregistry.HostAuthenticationArgs{
							Method: pulumi.String(deviceregistry.AuthenticationMethodCertificate),
							X509Credentials: &deviceregistry.X509CredentialsArgs{
								CertificateSecretName: pulumi.String("cert-secret"),
							},
						},
						EndpointType: pulumi.String("microsoft.opcua/v1"),
						Version:      pulumi.String("2"),
					},
					"theV2OPCUAEndpoint": &deviceregistry.InboundEndpointsArgs{
						Address: pulumi.String("opc.tcp://192.168.86.23:51211/UA/SampleServer"),
						Authentication: &deviceregistry.HostAuthenticationArgs{
							Method: pulumi.String(deviceregistry.AuthenticationMethodCertificate),
							X509Credentials: &deviceregistry.X509CredentialsArgs{
								CertificateSecretName: pulumi.String("cert-secret"),
							},
						},
						EndpointType: pulumi.String("microsoft.opcua/v1"),
						TrustSettings: &deviceregistry.TrustSettingsArgs{
							TrustList: pulumi.String("trust-secret-reference"),
						},
						Version: pulumi.String("2"),
					},
				},
			},
			ExtendedLocation: &deviceregistry.ExtendedLocationArgs{
				Name: pulumi.String("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1"),
				Type: pulumi.String("CustomLocation"),
			},
			ExternalDeviceId:  pulumi.String("unique-edge-device-identifier"),
			Location:          pulumi.String("West Europe"),
			NamespaceName:     pulumi.String("adr-namespace-gbk0925-n01"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var namespaceDevice = new AzureNative.DeviceRegistry.NamespaceDevice("namespaceDevice", new()
    {
        Attributes = new Dictionary<string, object?>
        {
            ["deviceCategory"] = 16,
            ["deviceOwner"] = "OT",
            ["deviceType"] = "OPCUAServers",
        },
        DeviceName = "namespace-device-on-edge",
        Enabled = true,
        Endpoints = new AzureNative.DeviceRegistry.Inputs.MessagingEndpointsArgs
        {
            Inbound = 
            {
                { "theV1OPCUAEndpoint", new AzureNative.DeviceRegistry.Inputs.InboundEndpointsArgs
                {
                    Address = "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                    Authentication = new AzureNative.DeviceRegistry.Inputs.HostAuthenticationArgs
                    {
                        Method = AzureNative.DeviceRegistry.AuthenticationMethod.Certificate,
                        X509Credentials = new AzureNative.DeviceRegistry.Inputs.X509CredentialsArgs
                        {
                            CertificateSecretName = "cert-secret",
                        },
                    },
                    EndpointType = "microsoft.opcua/v1",
                    Version = "2",
                } },
                { "theV2OPCUAEndpoint", new AzureNative.DeviceRegistry.Inputs.InboundEndpointsArgs
                {
                    Address = "opc.tcp://192.168.86.23:51211/UA/SampleServer",
                    Authentication = new AzureNative.DeviceRegistry.Inputs.HostAuthenticationArgs
                    {
                        Method = AzureNative.DeviceRegistry.AuthenticationMethod.Certificate,
                        X509Credentials = new AzureNative.DeviceRegistry.Inputs.X509CredentialsArgs
                        {
                            CertificateSecretName = "cert-secret",
                        },
                    },
                    EndpointType = "microsoft.opcua/v1",
                    TrustSettings = new AzureNative.DeviceRegistry.Inputs.TrustSettingsArgs
                    {
                        TrustList = "trust-secret-reference",
                    },
                    Version = "2",
                } },
            },
        },
        ExtendedLocation = new AzureNative.DeviceRegistry.Inputs.ExtendedLocationArgs
        {
            Name = "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1",
            Type = "CustomLocation",
        },
        ExternalDeviceId = "unique-edge-device-identifier",
        Location = "West Europe",
        NamespaceName = "adr-namespace-gbk0925-n01",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.deviceregistry.NamespaceDevice;
import com.pulumi.azurenative.deviceregistry.NamespaceDeviceArgs;
import com.pulumi.azurenative.deviceregistry.inputs.MessagingEndpointsArgs;
import com.pulumi.azurenative.deviceregistry.inputs.ExtendedLocationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var namespaceDevice = new NamespaceDevice("namespaceDevice", NamespaceDeviceArgs.builder()
            .attributes(Map.ofEntries(
                Map.entry("deviceCategory", 16),
                Map.entry("deviceOwner", "OT"),
                Map.entry("deviceType", "OPCUAServers")
            ))
            .deviceName("namespace-device-on-edge")
            .enabled(true)
            .endpoints(MessagingEndpointsArgs.builder()
                .inbound(Map.ofEntries(
                    Map.entry("theV1OPCUAEndpoint", InboundEndpointsArgs.builder()
                        .address("opc.tcp://192.168.86.23:51211/UA/SampleServer")
                        .authentication(HostAuthenticationArgs.builder()
                            .method("Certificate")
                            .x509Credentials(X509CredentialsArgs.builder()
                                .certificateSecretName("cert-secret")
                                .build())
                            .build())
                        .endpointType("microsoft.opcua/v1")
                        .version("2")
                        .build()),
                    Map.entry("theV2OPCUAEndpoint", InboundEndpointsArgs.builder()
                        .address("opc.tcp://192.168.86.23:51211/UA/SampleServer")
                        .authentication(HostAuthenticationArgs.builder()
                            .method("Certificate")
                            .x509Credentials(X509CredentialsArgs.builder()
                                .certificateSecretName("cert-secret")
                                .build())
                            .build())
                        .endpointType("microsoft.opcua/v1")
                        .trustSettings(TrustSettingsArgs.builder()
                            .trustList("trust-secret-reference")
                            .build())
                        .version("2")
                        .build())
                ))
                .build())
            .extendedLocation(ExtendedLocationArgs.builder()
                .name("/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1")
                .type("CustomLocation")
                .build())
            .externalDeviceId("unique-edge-device-identifier")
            .location("West Europe")
            .namespaceName("adr-namespace-gbk0925-n01")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  namespaceDevice:
    type: azure-native:deviceregistry:NamespaceDevice
    properties:
      attributes:
        deviceCategory: 16
        deviceOwner: OT
        deviceType: OPCUAServers
      deviceName: namespace-device-on-edge
      enabled: true
      endpoints:
        inbound:
          theV1OPCUAEndpoint:
            address: opc.tcp://192.168.86.23:51211/UA/SampleServer
            authentication:
              method: Certificate
              x509Credentials:
                certificateSecretName: cert-secret
            endpointType: microsoft.opcua/v1
            version: '2'
          theV2OPCUAEndpoint:
            address: opc.tcp://192.168.86.23:51211/UA/SampleServer
            authentication:
              method: Certificate
              x509Credentials:
                certificateSecretName: cert-secret
            endpointType: microsoft.opcua/v1
            trustSettings:
              trustList: trust-secret-reference
            version: '2'
      extendedLocation:
        name: /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/myResourceGroup/providers/microsoft.extendedlocation/customlocations/location1
        type: CustomLocation
      externalDeviceId: unique-edge-device-identifier
      location: West Europe
      namespaceName: adr-namespace-gbk0925-n01
      resourceGroupName: myResourceGroup

The x509Credentials property references a secret containing the client certificate. The optional trustSettings property specifies a trust list that validates the server’s certificate chain. This example shows two endpoints: one with basic certificate authentication, another that also validates the server certificate against a trust list.

Send device data to Event Grid topics

Devices can publish telemetry to Azure Event Grid for cloud processing.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const namespaceDevice = new azure_native.deviceregistry.NamespaceDevice("namespaceDevice", {
    attributes: {
        deviceCategory: 16,
        deviceOwner: "IT",
        deviceType: "sensor",
    },
    deviceName: "dev-namespace-gbk0925-n01",
    enabled: true,
    endpoints: {
        outbound: {
            assigned: {
                eventGridEndpoint: {
                    address: "https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events",
                    endpointType: "Microsoft.EventGrid",
                },
            },
        },
    },
    externalDeviceId: "adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f",
    location: "West Europe",
    namespaceName: "adr-namespace-gbk0925-n01",
    resourceGroupName: "myResourceGroup",
});
import pulumi
import pulumi_azure_native as azure_native

namespace_device = azure_native.deviceregistry.NamespaceDevice("namespaceDevice",
    attributes={
        "deviceCategory": 16,
        "deviceOwner": "IT",
        "deviceType": "sensor",
    },
    device_name="dev-namespace-gbk0925-n01",
    enabled=True,
    endpoints={
        "outbound": {
            "assigned": {
                "eventGridEndpoint": {
                    "address": "https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events",
                    "endpoint_type": "Microsoft.EventGrid",
                },
            },
        },
    },
    external_device_id="adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f",
    location="West Europe",
    namespace_name="adr-namespace-gbk0925-n01",
    resource_group_name="myResourceGroup")
package main

import (
	deviceregistry "github.com/pulumi/pulumi-azure-native-sdk/deviceregistry/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := deviceregistry.NewNamespaceDevice(ctx, "namespaceDevice", &deviceregistry.NamespaceDeviceArgs{
			Attributes: pulumi.Any(map[string]interface{}{
				"deviceCategory": 16,
				"deviceOwner":    "IT",
				"deviceType":     "sensor",
			}),
			DeviceName: pulumi.String("dev-namespace-gbk0925-n01"),
			Enabled:    pulumi.Bool(true),
			Endpoints: &deviceregistry.MessagingEndpointsArgs{
				Outbound: &deviceregistry.OutboundEndpointsArgs{
					Assigned: deviceregistry.DeviceMessagingEndpointMap{
						"eventGridEndpoint": &deviceregistry.DeviceMessagingEndpointArgs{
							Address:      pulumi.String("https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events"),
							EndpointType: pulumi.String("Microsoft.EventGrid"),
						},
					},
				},
			},
			ExternalDeviceId:  pulumi.String("adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f"),
			Location:          pulumi.String("West Europe"),
			NamespaceName:     pulumi.String("adr-namespace-gbk0925-n01"),
			ResourceGroupName: pulumi.String("myResourceGroup"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var namespaceDevice = new AzureNative.DeviceRegistry.NamespaceDevice("namespaceDevice", new()
    {
        Attributes = new Dictionary<string, object?>
        {
            ["deviceCategory"] = 16,
            ["deviceOwner"] = "IT",
            ["deviceType"] = "sensor",
        },
        DeviceName = "dev-namespace-gbk0925-n01",
        Enabled = true,
        Endpoints = new AzureNative.DeviceRegistry.Inputs.MessagingEndpointsArgs
        {
            Outbound = new AzureNative.DeviceRegistry.Inputs.OutboundEndpointsArgs
            {
                Assigned = 
                {
                    { "eventGridEndpoint", new AzureNative.DeviceRegistry.Inputs.DeviceMessagingEndpointArgs
                    {
                        Address = "https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events",
                        EndpointType = "Microsoft.EventGrid",
                    } },
                },
            },
        },
        ExternalDeviceId = "adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f",
        Location = "West Europe",
        NamespaceName = "adr-namespace-gbk0925-n01",
        ResourceGroupName = "myResourceGroup",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.deviceregistry.NamespaceDevice;
import com.pulumi.azurenative.deviceregistry.NamespaceDeviceArgs;
import com.pulumi.azurenative.deviceregistry.inputs.MessagingEndpointsArgs;
import com.pulumi.azurenative.deviceregistry.inputs.OutboundEndpointsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var namespaceDevice = new NamespaceDevice("namespaceDevice", NamespaceDeviceArgs.builder()
            .attributes(Map.ofEntries(
                Map.entry("deviceCategory", 16),
                Map.entry("deviceOwner", "IT"),
                Map.entry("deviceType", "sensor")
            ))
            .deviceName("dev-namespace-gbk0925-n01")
            .enabled(true)
            .endpoints(MessagingEndpointsArgs.builder()
                .outbound(OutboundEndpointsArgs.builder()
                    .assigned(Map.of("eventGridEndpoint", DeviceMessagingEndpointArgs.builder()
                        .address("https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events")
                        .endpointType("Microsoft.EventGrid")
                        .build()))
                    .build())
                .build())
            .externalDeviceId("adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f")
            .location("West Europe")
            .namespaceName("adr-namespace-gbk0925-n01")
            .resourceGroupName("myResourceGroup")
            .build());

    }
}
resources:
  namespaceDevice:
    type: azure-native:deviceregistry:NamespaceDevice
    properties:
      attributes:
        deviceCategory: 16
        deviceOwner: IT
        deviceType: sensor
      deviceName: dev-namespace-gbk0925-n01
      enabled: true
      endpoints:
        outbound:
          assigned:
            eventGridEndpoint:
              address: https://myeventgridtopic.westeurope-1.eventgrid.azure.net/api/events
              endpointType: Microsoft.EventGrid
      externalDeviceId: adr-smart-device3-7a848b15-af47-40a7-8c06-a3f43314d44f
      location: West Europe
      namespaceName: adr-namespace-gbk0925-n01
      resourceGroupName: myResourceGroup

The outbound endpoints configuration routes device messages to Azure services. The assigned map defines named destinations; here, an Event Grid topic receives device events. The endpointType identifies the target service, and the address specifies the Event Grid topic URL.

Beyond these examples

These snippets focus on specific device-level features: OPC UA endpoint authentication, inbound and outbound messaging configuration, and edge location placement and device metadata. They’re intentionally minimal rather than full IoT solutions.

The examples reference pre-existing infrastructure such as Azure Arc CustomLocation for edge deployment, Device Registry namespace, secrets for credentials and certificates, and Event Grid topics for outbound examples. They focus on configuring the device rather than provisioning the surrounding infrastructure.

To keep things focused, common device patterns are omitted, including:

  • Device discovery and automatic registration (discoveredDeviceRef)
  • Device status monitoring and health checks
  • Multiple endpoint configurations per device
  • Device attributes and custom metadata beyond basic examples

These omissions are intentional: the goal is to illustrate how each device feature is wired, not provide drop-in IoT modules. See the NamespaceDevice resource reference for all available configuration options.

Let's configure Azure Device Registry Namespace Devices

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Authentication & Security
What authentication methods are available for device endpoints?

Three authentication methods are supported:

  1. Anonymous - No credentials required, set method to Anonymous
  2. UsernamePassword - Requires usernamePasswordCredentials with passwordSecretName and usernameSecretName
  3. Certificate - Requires x509Credentials with certificateSecretName, optionally with trustSettings.trustList for certificate validation
How do I provide credentials for authentication?
Credentials are provided as secret references, not inline values. For username/password authentication, specify passwordSecretName and usernameSecretName. For certificate authentication, specify certificateSecretName. These reference secrets stored in your secret management system.
Edge Device Configuration
What's required to create an edge-enabled device?
Edge-enabled devices require an extendedLocation property with type set to CustomLocation and a name referencing your custom location resource. This connects the device to your edge infrastructure.
How do I connect a device to an OPC UA server?
Configure an inbound endpoint with address pointing to your OPC UA server (e.g., opc.tcp://192.168.86.23:51211/UA/SampleServer), set endpointType to microsoft.opcua/v1, specify the version, and configure your chosen authentication method.
Endpoints & Connectivity
What's the difference between inbound and outbound endpoints?
Inbound endpoints allow edge devices to connect to data sources like OPC UA servers. Outbound endpoints enable devices to send data to cloud services like Event Grid. Configure them under endpoints.inbound or endpoints.outbound respectively.
Can I configure multiple endpoints on a single device?
Yes, you can configure multiple named endpoints within the inbound or outbound properties. Each endpoint can have different addresses, authentication methods, and configurations.
Device Properties & Immutability
What properties can't be changed after device creation?
The following properties are immutable and require device replacement if changed: location, deviceName, extendedLocation, externalDeviceId, discoveredDeviceRef, manufacturer, model, and operatingSystem.
What's the purpose of the enabled property?
The enabled property controls whether the device is active. It defaults to true and can be toggled to disable a device without deleting it.
How do I use custom attributes on a device?
Use the attributes property to set custom key-value pairs like deviceCategory, deviceOwner, or deviceType. These help organize and categorize your devices.

Using a different cloud?

Explore integration guides for other cloud providers: