Search code examples
c#pulumiazure-hybrid-connections

How do you create an Azure Hybrid Connection using Pulumi?


Pre-requisite:

  • Cannot have a duplicate App Service Hybrid Connection within the same App Service Plan configured on your app services

Using the example provided from their website (https://www.pulumi.com/docs/reference/pkg/azure/appservice/hybridconnection/):

using Pulumi;
using Azure = Pulumi.Azure;
using Pulumi.AzureNextGen; 

class MyStack : Stack
{
    public MyStack()
    {
        var exampleResourceGroup = new Azure.Core.ResourceGroup("exampleResourceGroup", new Azure.Core.ResourceGroupArgs
        {
            Location = "West Europe",
        });
        var examplePlan = new Azure.AppService.Plan("examplePlan", new Azure.AppService.PlanArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            Sku = new Azure.AppService.Inputs.PlanSkuArgs
            {
                Tier = "Standard",
                Size = "S1",
            },
        });
        var exampleAppService = new Azure.AppService.AppService("exampleAppService", new Azure.AppService.AppServiceArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            AppServicePlanId = examplePlan.Id,
        });
        var exampleNamespace = new Azure.Relay.Namespace("exampleNamespace", new Azure.Relay.NamespaceArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            SkuName = "Standard",
        });
        var exampleHybridConnection = new Azure.Relay.HybridConnection("exampleHybridConnection", new Azure.Relay.HybridConnectionArgs
        {
            ResourceGroupName = exampleResourceGroup.Name,
            RelayNamespaceName = exampleNamespace.Name,
            UserMetadata = "examplemetadata",
        });
        var exampleAppservice_hybridConnectionHybridConnection = new Azure.AppService.HybridConnection("exampleAppservice/hybridConnectionHybridConnection", new Azure.AppService.HybridConnectionArgs
        {
            AppServiceName = exampleAppService.Name,
            ResourceGroupName = exampleResourceGroup.Name,
            RelayId = exampleHybridConnection.Id,
            Hostname = "testhostname.example",
            Port = 8080,
            SendKeyName = "RootManageSharedAccessKey",
        });
    }

}

I get the following error:

Error: unable to List Access Keys for Namespace "XXX" (Resource Group "XXX"): relay.NamespacesClient#ListKeys: Failure responding to request: StatusCode=404 -- Original Error: autorest/azure: error response cannot be parsed: ""The requested resource defaultSender does not exist."" error: json: cannot unmarshal string into Go value of type azure.RequestError

To fix this I had to add a Relay Namespace Authorization rule:

using Pulumi;
using Azure = Pulumi.Azure;
using Pulumi.AzureNextGen;

class MyStack : Stack
{
    public MyStack()
    {
        var exampleResourceGroup = new Azure.Core.ResourceGroup("exampleResourceGroup", new Azure.Core.ResourceGroupArgs
        {
            Location = "West Europe",
        });
        var examplePlan = new Azure.AppService.Plan("examplePlan", new Azure.AppService.PlanArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            Sku = new Azure.AppService.Inputs.PlanSkuArgs
            {
                Tier = "Standard",
                Size = "S1",
            },
        });
        var exampleAppService = new Azure.AppService.AppService("exampleAppService", new Azure.AppService.AppServiceArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            AppServicePlanId = examplePlan.Id,
        });
        var exampleNamespace = new Azure.Relay.Namespace("exampleNamespace", new Azure.Relay.NamespaceArgs
        {
            Location = exampleResourceGroup.Location,
            ResourceGroupName = exampleResourceGroup.Name,
            SkuName = "Standard",
        });

var defaultSenderAuthorizationRule = new Pulumi.AzureNextGen.Relay.Latest.NamespaceAuthorizationRule("defaultSenderAuthorizationRule",
                new AzureProviderNextGen.Relay.Latest.NamespaceAuthorizationRuleArgs
                {
                    AuthorizationRuleName = "defaultSender",
                    NamespaceName = exampleNamespace .Name,
                    ResourceGroupName = exampleNamespace .ResourceGroupName,
                    Rights =
                    {
                        "Manage",
                        "Listen",
                        "Send",
                    },
                });


        var exampleHybridConnection = new Azure.Relay.HybridConnection("exampleHybridConnection", new Azure.Relay.HybridConnectionArgs
        {
            ResourceGroupName = exampleResourceGroup.Name,
            RelayNamespaceName = exampleNamespace.Name,
            UserMetadata = "examplemetadata",
        });
        var exampleAppservice_hybridConnectionHybridConnection = new Azure.AppService.HybridConnection("exampleAppservice/hybridConnectionHybridConnection", new Azure.AppService.HybridConnectionArgs
        {
            AppServiceName = exampleAppService.Name,
            ResourceGroupName = exampleResourceGroup.Name,
            RelayId = exampleHybridConnection.Id,
            Hostname = "testhostname.example",
            Port = 8080,
            SendKeyName = "RootManageSharedAccessKey",
        });
    }

}

After this, it works fine and the stack completes saying my Appservice:HybridConnection has been created. Yet, when I navigate to the app service Network/HybridConnection settings it's not there.

Expected behavior:

When the AppService.HybridConnection is created successfully then it should appear in the Hybrid Connection list of the App Service in the Azure Portal.

Actual behavior:

The AppService.HybridConnection is created successfully but does not appear in the App Service\Hybrid Connection list


Solution

  • In looking at the Azure Activity logs it seems that the resource gets created then swiftly deleted right after.

    The solution for this was to..

    1. Update the UserMetadata in the Relay.HybridConnection so that it includes the Endpoint key with the Hostname and Port
    var exampleHybridConnection = new Azure.Relay.HybridConnection("exampleHybridConnection", new Azure.Relay.HybridConnectionArgs
            {
                ResourceGroupName = exampleResourceGroup.Name,
                RelayNamespaceName = exampleNamespace.Name,
                UserMetadata = "[{\"key\":\"endpoint\",\"value\":\"testhostname.example:8080\"}]",
            });
    
    1. Add Authorization Rules to the Relay.HybridConnection.
    var defaultListenerRule = new Pulumi.AzureNextGen.Relay.Latest.HybridConnectionAuthorizationRule("defaultListener",
                    new Pulumi.AzureNextGen.Relay.Latest.HybridConnectionAuthorizationRuleArgs
                    {
                        AuthorizationRuleName = "defaultListener",
                        HybridConnectionName = exampleHybridConnection.Name,
                        NamespaceName = exampleHybridConnection.RelayNamespaceName,
                        ResourceGroupName = exampleHybridConnection.ResourceGroupName,
                        Rights =
                        {
                            "Listen",
                        },
                    });
    
                var defaultSenderRule = new Pulumi.AzureNextGen.Relay.Latest.HybridConnectionAuthorizationRule("defaultSender",
                    new Pulumi.AzureNextGen.Relay.Latest.HybridConnectionAuthorizationRuleArgs
                    {
                        AuthorizationRuleName = "defaultSender",
                        HybridConnectionName = exampleHybridConnection.Name,
                        NamespaceName = exampleHybridConnection.RelayNamespaceName,
                        ResourceGroupName = exampleHybridConnection.ResourceGroupName,
                        Rights =
                        {
                            "Send",
                        },
                    });
    
    1. Then add a CustomResourceOptions argument "DeleteBeforeReplace = true" on the AppService.HybridConnection.
    var exampleAppservice_hybridConnectionHybridConnection = new Azure.AppService.HybridConnection("exampleAppservice/hybridConnectionHybridConnection", new Azure.AppService.HybridConnectionArgs
                {
                    AppServiceName = exampleAppService.Name,
                    ResourceGroupName = exampleResourceGroup.Name,
                    RelayId = exampleHybridConnection.Id,
                    Hostname = "testhostname.example",
                    Port = 8080,
                    SendKeyName = "exampleSharedAccessKey",
                }, new CustomResourceOptions { DeleteBeforeReplace = true });
    
    

    After its created, everything will be linked & show up both in Hybrid Connection Manager & Azure's Portal.