Azure Functions für eigenen DynDNS Dienst

Standard

Azure Functions nutzen, um einen eigenen DynDNS Dienst nachzubauen. Ganz einfach! Was dynamische DNS Anbieter sind, weiß jeder. Da diese meist kostenlos sind, bieten diese nur eine festgelegte Domäne an, in der man eine Subdomäne (sofern Sie noch frei ist) erhalten kann. Möchte man eine eigene Domäne verwenden, wird es meistens kostenpflichtig. Zudem stelle ich mir immer die Frage, was der Dienstanbieter mit meinen Daten so anstellt?

Irgendwie muss man das Ganze doch auch mit Azure nachbauen können. Ein eigener DynDNS-Dienst mit Azure Functions mit eigener Domäne und voller Kontrolle!

Wie das geht?

Inhalt

  1. Wie funktioniert das ganz grob?
  2. Welche Komponenten benötige ich?
  3. Was muss ich entwickeln?

Ich gehe in diesem Beitrag davon aus, dass Du bereits grundlegende Erfahrungen mit Azure hast. Dies ist keine Klickanleitung.

1. Grobaufbau und Anforderungen

Der Router (Fritzbox) soll, genau wie bei den anderen DynDNS-Diensten auch, regelmäßig die eigenen Veränderung der öffentlichen IP an eine API im Internet melden. Mit dieser Information soll dann ein A-Eintrag einer Domäne im DNS verändert werden. Damit bin ich dann in der Lage über die Domäne bspw. einen Homeserver (o. ä.) im privaten LAN zu erreichen. Der Aufruf soll möglichst sicher vor Manipulation sein. Ich benötige also ein Art Authentifizierung. Ich muss eine automatische Ermittlung der IP einbauen, weil die Fritzbox das nicht kann und ich darauf auch keinen Einfluss habe.

2. Komponenten und deren Konfiguration

2.1 Azure DNS

Azure bietet den Dienst Azure DNS. Mit diesem Azure Dienst bist Du in der Lage eine eigene öffentliche Domäne (Zone) zu verwalten. Erstelle in Azure eine DNS Zone. Du erwirbst dann eine Domäne bei Deinem Hoster des Vertrauens und erstellst eine Delegation auf die Server von Azure. Da bedeutet, dass Du Deinem Hoster sagst, dass andere DNS-Server als die vom Hoster die Namensauflösung machen sollen. Bei Azure sind es diese Server.

Azure Functions DNS Server

Erstellen einer Azure DNS Zone

2.2 Azure Functions

Nun benötige ich Azure Functions. Azure Functions ist eine sehr einfache Möglichkeit mit einfachsten Mitteln schnell und unkompliziert eine API im Internet (aber auch nur privates LAN) zu veröffentlichen. Azure Functions ist eine serverless Laufzeitumgebung für Programme. Ich benötige keine VM, keinen App-Server mehr. Nur noch deployen und freuen.

Azure Functions können (u. a.) per HTTP Request Trigger aufgerufen werden. Der Request wird durch einen Token gegen Missbrauch abgesichert. Der Token befindet sich in der Aufruf-URL.

https://functionapp21171231022519.azurewebsites.net/api/HttpTriggerCSharp/name/deinedomaene.de?code=raNyv38NbuvxDoWVyySarket2pyL8vJOB5yfvfh7w85QAAERPkDi2W==

Dies ist eine Beispiel URL, die die Fritzbox (oder andere Router) nutzt, um den DNS Eintrag zu ändern. Diese besteht aus dem Hostnamen (functionapp…), die Route die ich konfigurieren kann, einen Parameter den ich übergebe (Domänennamen) und dem Sicherheitstoken. Der Sicherheitstoken ist geschützt, da der komplette Aufruf über HTTPS läuft.

Du brauchst den Azure Functions Dienst nicht vorher per Hand anlegen, dass macht die Entwicklungsumgebung später automatisch für Dich.

2.3 Azure Active Directory App Registration

Damit die API später Aktionen ausführen darf, muss sie im selben Tenant im Azure Active Directory registriert werden. Dabei werden die  folgenden Informationen generiert, die in den Applications-Code eingefügt werden müssen.

  • Die AppID (auch CientID) identifiziert die App
  • Das ClientSecret ist wie ein Token zu betrachten
  • Die TenantID identifiziert den Tenant in dem die App betrieben wird
  • Die SubscriptionID identifiziert die dazugehörige Subscription

Hinzufügen einer App (Unsere API) zum Azure Active Directory

2.4. Azure Management Libraries

Die Azure Management Libraries für .NET bieten eine umfangreiche API zur Azure Welt. Die brandfrische FLUENT Version ist in der Handhabung nocheinmal einfacher geworden.

Die Libraries benötigen wird später im Entwicklungsprojekt und werden per Nuget importiert.

Zum Einlesen

3. Wie entwickle ich den Code

3.1 Projekt anlegen (Name: DnsUpdate)

Ich erstelle mit Visual Studio 2017 ein Projekt vom Typ Azure Functions. Damit Visual Studio das kann, muss das entsprechende Modul installiert sein.

Azure Functions

3.2 Abhängigkeiten importieren

Ich brauche zunächst die folgenden Nuget-Pakete.

Azure Functions

Installieren

Dann benötige ich noch ein paar Assemblies

Azure Functions

Damit sind alle notwendigen Abhängigkeiten in das Projekt importiert.

3.3  Dann eine neue Klasse (Name: Update) anlegen.

Der Code  sieht folgendermaßen aus:

using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using System.Web;
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using System;
using System.ServiceModel.Channels;

namespace DnsUpdate
{
 public static class Update
 {
 [FunctionName("Update")]
 public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "HttpTriggerCSharp/name/{name}")]HttpRequestMessage req, string name, TraceWriter log)
 {
 // Variable für die neue IP initialisieren
 string ip = null;
 // IP Adresse aus dem HTTP-Request auslesen. Wichtig dabei ist, dass die IP Adresse sich nicht immer in den selben Objekten 
 // finden läßt, daher die Iteration über mehrere Möglichkeiten.
 if (req.Properties.ContainsKey("MS_HttpContext"))
 {
 ip = ((HttpContextWrapper)req.Properties["MS_HttpContext"]).Request.UserHostAddress;
 }
 else if (req.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
 {
 RemoteEndpointMessageProperty prop = (RemoteEndpointMessageProperty)req.Properties[RemoteEndpointMessageProperty.Name];
 ip = prop.Address;
 }
 else if (HttpContext.Current != null)
 {
 ip = HttpContext.Current.Request.UserHostAddress;
 }
 //Der Parameter "name" wird in der URL übergeben und hier ausgelesen. 
 string CustomDomainName = name;
 log.Info(ip);
 // Nun versuche ich die Information an Azure DNS zu übergeben. Dafür nutze ich das Azure Management Fluent Framework
 try
 {
 // Hier die Informationen aus dem Azure Active Directory
 var clientId = "Deine ClientID";
 var clientSecret = "Dein Client Secret";
 var tenantId = "Deinen AAD Tenant";
 var subscriptionID = "Deine Subscription";
 // Mit diesen Informationen baue ich ein Credential-Object
 var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);
 // Dann baue ich ein Azure-Management-Objekt
 var azure = Azure
 .Configure()
 .WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
 .Authenticate(credentials)
 .WithSubscription(subscriptionID);
 // Nun wirds ernst. Ich holen mir aus Azure die vorhandene DNS Zone 
 var rootDnsZone = azure.DnsZones.GetByResourceGroup("dns", CustomDomainName);
 // Dann führe ich ein Update für den A-Record "www" durch
 rootDnsZone = rootDnsZone.Update()
 .DefineARecordSet("www")
 .WithIPv4Address(ip)
 .Attach()
 .Apply();
 log.Info("Updated root DNS zone " + rootDnsZone.Name);
 log.Info("Getting ARecord record set in the root DNS zone " + CustomDomainName + "...");
 // Nun hole ich mir alle Records und gebe sie zur Kontrolle einmal auf der Konsole aus
 var aRecordSets = rootDnsZone
 .ARecordSets
 .List();
 foreach (var aRecordSet in aRecordSets)
 {
 log.Info("Name: " + aRecordSet.Name);
 foreach (var ipv4Address in aRecordSet.IPv4Addresses)
 {
 log.Info(" " + ipv4Address);
 }
 }
 }
 catch (Exception e)
 {
 log.Info(e.ToString());
 }
 return req.CreateResponse(HttpStatusCode.OK, "IP: " + ip);
 }
 }
}

3.4 Deployment

Dann muss ich das Ganze nur noch in Azure veröffentlichen. Der erste Aufruf erstellt initial eine Azure Function. Alle weiteren Deployments gehen in die dann vorhandenen Azure Function.

Azure Functions

Der Wizard legt automatisch  für mich in der gewünschten Subscription eine neue Azure Function an.

3.5 Test

Um per Browser zu testen benötige ich die tatsächliche URl. Diese erhalte ich mit einem Klick auf

„</> Get function URL“

Azure Functions

 

Diese URL füge ich dann auch in der Fritzbox ein. 

Hinweis: Die Fritzbox fragt nach den Parametern Domain, Benutzername und Passwort, obwohl wir diese Informationen nicht benötigen. Einfach irgendwas da eintragen. Zudem schmeißt die Fritzbox nach einem Update der Domain eine Fehlemeldung: DynDNS-Fehler. Der angegebene Domainname kann trotz erfolgreicher Aktualisierung nicht aufgelöst werden. Das kann ignoriert werden.

Viele Spaß beim Nachbauen! Frohe Weihnachten und einen guten Rutsch.

Wer Fragen hat