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 connectivity endpoints, authentication methods, and edge placement. This guide focuses on three capabilities: OPC UA inbound endpoint configuration, authentication methods (username/password, anonymous, X.509), and outbound Event Grid messaging.

Devices depend on an existing namespace, a CustomLocation for edge deployment, and secret storage for credentials. The examples are intentionally small. Combine them with your own namespace, CustomLocation, and secret management infrastructure.

Connect to OPC UA servers with username and password

Industrial IoT deployments often connect to OPC UA servers on factory equipment using username and password authentication when certificate infrastructure isn’t available.

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 endpoints.inbound map defines named connections to OPC UA servers. Each endpoint specifies an address (the OPC UA server URL), an endpointType (“microsoft.opcua/v1”), and authentication details. The usernamePasswordCredentials property references secret names stored in the CustomLocation’s secret store. The extendedLocation property places the device on an Azure Arc-enabled edge location where it can reach the OPC UA server.

Connect to OPC UA servers without authentication

Development environments sometimes expose OPC UA servers that allow anonymous connections.

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 authentication.method to Anonymous removes the credential requirement. The device connects to the OPC UA server without presenting username, password, or certificates. This configuration is useful for testing but should not be used in production environments.

Authenticate with X.509 certificates and trust lists

Production OPC UA deployments require certificate-based authentication for secure communication.

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 certificate secret for client authentication. The trustSettings.trustList property references a secret containing trusted certificate authorities, enabling the device to validate the OPC UA server’s certificate. This example shows two endpoints: one with basic certificate authentication, another adding trust list validation for enhanced security.

Send device data to Event Grid topics

Devices can publish telemetry to Azure Event Grid for routing to downstream applications.

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 endpoints.outbound.assigned map defines named outbound connections. Each endpoint specifies an address (the Event Grid topic URL) and an endpointType (“Microsoft.EventGrid”). The device publishes events to this endpoint, which Event Grid then routes according to topic subscriptions.

Beyond these examples

These snippets focus on specific device-level features: OPC UA inbound connectivity with multiple authentication methods, outbound Event Grid integration, and edge deployment via CustomLocations. They’re intentionally minimal rather than full IoT solutions.

The examples reference pre-existing infrastructure such as Azure Arc CustomLocations for edge placement, Device Registry namespaces, secret stores for credentials and certificates, and Event Grid topics for outbound messaging. They focus on configuring the device rather than provisioning the surrounding infrastructure.

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

  • Device attributes and metadata (attributes property)
  • Device enablement state (enabled property)
  • Discovered device references (discoveredDeviceRef)
  • Operating system and manufacturer details

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 usernameSecretName and passwordSecretName
  3. Certificate - Requires x509Credentials with certificateSecretName
How do I configure certificate authentication with trust validation?
Set authentication.method to Certificate and provide x509Credentials.certificateSecretName. For trust validation, add trustSettings.trustList with a reference to your trust list secret.
How do I reference secrets for authentication credentials?
Use secret name references in credential fields (e.g., passwordSecretName: "pwd-ref", usernameSecretName: "user-ref", certificateSecretName: "cert-secret"). These reference secrets stored in your secret management system.
Device Configuration
What properties can't be changed after creating a device?
The following properties are immutable: location, extendedLocation, deviceName, externalDeviceId, discoveredDeviceRef, manufacturer, model, operatingSystem, and resourceGroupName. Changing these requires replacing the resource.
What's the default state for a newly created device?
Devices are enabled by default (enabled: true). You can explicitly set enabled: false to create a disabled device.
What is extendedLocation and when is it required?
extendedLocation specifies the Azure Arc custom location for edge-enabled devices. It’s required for devices deployed to edge environments and must include a name (custom location resource ID) and type (typically CustomLocation).
Endpoints & Connectivity
What's the difference between inbound and outbound endpoints?
Inbound endpoints receive data from devices (e.g., OPC UA servers connecting to your device). Outbound endpoints send data to external services (e.g., Event Grid topics). Configure them under endpoints.inbound or endpoints.outbound.assigned.
What endpoint types are supported?
The examples show microsoft.opcua/v1 for OPC UA inbound endpoints and Microsoft.EventGrid for Event Grid outbound endpoints. Each endpoint requires an address, endpointType, and authentication configuration.
How do I configure an OPC UA inbound endpoint?
Create an entry in endpoints.inbound with an address (e.g., opc.tcp://192.168.86.23:51211/UA/SampleServer), set endpointType to microsoft.opcua/v1, specify version, and configure authentication with your chosen method.
Advanced Features
What is discoveredDeviceRef used for?
discoveredDeviceRef is an immutable property populated only when a device is created from the discovery flow. It references the discovered device name and cannot be set manually.

Using a different cloud?

Explore integration guides for other cloud providers: