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
- Wie funktioniert das ganz grob?
- Welche Komponenten benötige ich?
- 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.
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.
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.
3.2 Abhängigkeiten importieren
Ich brauche zunächst die folgenden Nuget-Pakete.
Dann benötige ich noch ein paar Assemblies
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.
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“
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.