[{"content":" \"Any sufficiently advanced technology is indistinguishable from magic.\"\n— Arthur C. Clarke \"The best way to predict the future is to invent it.\"\n— Alan Kay \"Talk is cheap. Show me the code.\"\n— Linus Torvalds ","date":"17 April 2023","externalUrl":null,"permalink":"/","section":" ","summary":"","title":" ","type":"page"},{"content":"„Sich nie wieder sorgen um auslaufende Zertifikate machen“, das klingt fantastisch? Easy! Über eine DNS-Abfrage lassen sich über Let´s Enrcypt automatisch Zertifikate erstellen. Dabei habe ich bisher oft das Argument gehört „Naja, Let´s Encrypt Zertifikate sind nicht Enterprise und die Hostnames tauchen in öffentlichen Listen auf“. Meine bisherige Erfahrung mit diesen Zertifikaten ist jedoch durchweg positiv. Kein Browser hatte diese Zertifikate bisher als unsicher eingestuft und die Hostnames konnte ich in keiner öffentlichen Liste finden.\nAzure Konfiguration # Bevor wir loslegen können, müssen wir eine Kleinigkeit in Azure vorbereiten. Der Initiator (z.B. Certbot) muss für eine erfolgreiche DNS Challange einen TXT Record im DNS hinterlegen können. Dazu eignet sich ein Azure Service Principal (Azure SP) für die OAuth Authentifizierung. Über die Azure CLI können wir mit einem einzigen Befehl ein SP anlegen:\naz ad sp create-for-rbac --name sp-acme-dns-challange \\ --role \u0026#34;DNS Zone Contributor\u0026#34; \\ --scopes \u0026lt;scope\u0026gt; Dem Argument “role” geben wir das Value „DNS Zone Contributor“ mit, um die Berechtigungen auf das nötigste zu beschränken. Das Argument „scope“ erhält den Pfad zur DNS-Zone Ressource. Der Pfad lässt sich schnell über die GUI kopieren, wenn du dir den JSON View direkt in der DNS Ressource anzeigen lässt. Sobald du den Befehl abgesetzt hast, erhältst du wichtige Informationen als Response. Notiere dir die appID, das Passwort und die Tenant ID. Über folgenden Befehl kannst du dir nochmal die Details zu deinem Azure Service Principal anzeigen lassen:\naz ad sp show --id \u0026lt;service principal id\u0026gt; Über die Azure GUI findest du das Service Principal unter den Enterprise Applications, du musst jedoch den Application type Filter auf „All Applications“ einstellen.\nCertbot # Wir verwenden unser Beispiel Certbot und Linux Ubuntu. Zunächst solltest du Certbot gemäß der Dokumentation installieren. Anschließend legen wir eine Datei an, um die Azure Service Principal Credentials abzuspeichern.\n# credentials-file # Using a service principal (option 1) dns_azure_sp_client_id = \u0026lt;azure_sp_client_id\u0026gt; dns_azure_sp_client_secret = \u0026lt;azure_sp_client_secret\u0026gt; dns_azure_tenant_id = \u0026lt;azure_tenant_id\u0026gt; # Zones (at least one always required) dns_azure_zone1 = \u0026lt;resource id dns zone\u0026gt; dns_azure_zone2 = \u0026lt;resource id dns zone\u0026gt; Du solltest für diese Datei die passenden Berechtigungen einstellen, damit nicht jeder User auf dem Server die Datei lesen kann.\nchmod 0600 credentials-file \\ chown root:root credentials-file Jetzt können wir den Certbot Command absetzen:\ncertbot certonly --authenticator dns-azure --preferred-challenges dns --noninteractive --agree-tos --email someone@mydomain.online --renew-by-default --dns-azure-config credentials-file -d mydomain.online Du kannst optional das Flag „—noninteractive“ weglassen, dann siehst du den Fortschritt, dann werden optionale Eigenschaften für die Zertifikatsanfrage abgefragt. Als nächstes konfigurierst du noch einen Cronjob, um das Zertifikat automatisch erneuern zu lassen.\n0 12 * * * root /opt/certbot/bin/python -c \u0026#39;import random; import time; time.sleep(random.random() * 3600)\u0026#39; \u0026amp;\u0026amp; sudo certbot renew -q ","date":"17 April 2023","externalUrl":null,"permalink":"/blog/acme-challanges-mit-azure-dns/","section":"Blog","summary":"","title":"ACME Challanges mit Azure DNS","type":"blog"},{"content":"","date":"17 April 2023","externalUrl":null,"permalink":"/blog/","section":"Blog","summary":"","title":"Blog","type":"blog"},{"content":"Der NGINX Reverse Proxy Manager ist eine nützliche Tool Sammlung in Form eines Docker Containers. Das Deployment gestaltet sich als enorm einfach und wir können blitzschnell die ersten Proxy Hosts definieren und den Container als Reverse Proxy verwenden. Wollen wir jedoch bestimmt Konfigurationen individuell anpassen, muss man einige Dinge beachten. Viele Webapplikation verwenden zum Beispiel gzip als Kompression, welche in NGINX manuell aktiviert werden muss.\nAnpassungen am Container Deployment erforderlich # Damit wir Snippets von einzelnen Konfigurationselementen für den Container bereitstellen können, müssen wir ein lokales Linux Verzeichnis als Mount bereitstellen. Am einfachsten erstellen wir den Container mittels docker-compose und geben die entsprechenden Volumes an.\n--- #... volumes: - /srv/nginx-rpm/data:/data - /srv/nginx-rpm/letsencrypt:/etc/letsencrypt #... Die Syntax für die Angabe von Filesystem Volumes gestaltet sich folgendermaßen:\n--- #... volumes: - \u0026lt;Pfad des lokalen Filesystem\u0026gt;:\u0026lt;Pfad im Container\u0026gt; - \u0026lt;Pfad des lokalen Filesystem\u0026gt;:\u0026lt;Pfad im Container\u0026gt; #... Erklärung der Konfigurationen # Um das Setup besser zu verstehen, sollten wir einmal in den Container springen und uns die NGINX Konfiguration anschauen.\ndocker exec -it nginx-proxy-manager_app_1 /bin/bash [root@docker-def72057c4b9:/app]# cat /etc/nginx/nginx.conf | grep include In dem folgenden Segment sehen wir, welche Dateien von NGINX über das „include“ Statement geladen werden. Wichtig sind uns hier die eingebundenen „proxy_host“ Konfigurationen.\ninclude /etc/nginx/modules/*.conf; include /etc/nginx/mime.types; include /etc/nginx/conf.d/include/resolvers.conf; include conf.d/include/ip_ranges.conf; include /data/nginx/custom/http_top[.]conf; include /etc/nginx/conf.d/*.conf; include /data/nginx/default_host/*.conf; include /data/nginx/proxy_host/*.conf; include /data/nginx/redirection_host/*.conf; include /data/nginx/dead_host/*.conf; include /data/nginx/temp/*.conf; include /data/nginx/custom/http[.]conf; include /data/nginx/stream/*.conf; include /data/nginx/custom/stream[.]conf; include /data/nginx/custom/root[.]conf; Wir können uns jetzt die einzelnen proxy_host Dateien anschauen und sehen dabei, dass in diesen Dateien wieder ein „include“ Statement angegeben ist.\n[root@docker-def72057c4b9:/app]# cd /data/nginx/proxy_host/ [root@docker-def72057c4b9:/data/nginx/proxy_host]# ls 1.conf 2.conf 4.conf 6.conf 7.conf 8.conf [root@docker-def72057c4b9:/data/nginx/proxy_host]# cat 1.conf | grep include include conf.d/include/letsencrypt-acme-challenge.conf; include conf.d/include/ssl-ciphers.conf; include conf.d/include/force-ssl.conf; include conf.d/include/proxy.conf; include /data/nginx/custom/server_proxy[.]conf; gzip Konfiguration # Wir folgen jetzt der „server_proxy[.]conf“ Pfadangabe in unserer proxy_host Datei und legen im Filesystem für unser Volume Mount das entsprechende Snippet File unter „srv/nginx-rpm/data/nginx/custom/server_proxy.conf“ ab. Wir definieren in diesem Snippet unsere gewünschte gzip Konfiguration.\ngzip on; gzip_proxied any; gzip_types text/css text/javascript text/xml text/plain application/javascript application/x-javascript application/json; Jetzt nur noch den Container neu starten, damit die neue Konfiguration geladen wird.\ndocker restart nginx-proxy-manager_app_1 ","date":"31 January 2023","externalUrl":null,"permalink":"/blog/nginx-reverse-proxy-manager-gzip-aktivierung/","section":"Blog","summary":"","title":"NGINX Reverse Proxy Manager – gzip Aktivierung","type":"blog"},{"content":"Interaktive Skripts remote ausführen und die Eingaben vordefiniert abarbeiten lassen? Mit dem „Expect“ Modul von Ansible ist das kein Problem. Meiner Meinung nach ist diese Ansible Erweiterung einer der Mächtigsten – ohne übertreiben zu wollen ;). Immerhin hatte dieses Modul eines meiner bisher wichtigsten Projekte in trockene Tücher gelegt. Nach ungefähr 800 Zeilen YAML Code stand ich auf einmal vor der Herausforderung, zwei interaktive Scripts auszuführen. Mir kam zuerst in den Sinn, dass auszuführende Bash Script zu analysieren und mittels YAML für Ansible zu übersetzen – der Termindruck verhinderte dies jedoch. Also begann die Suche nach einer Alternative, mit Erfolg! Ansible Expect brachte genau das, wonach ich gesucht hatte.\nWhat we expect # “Expect the unexpected”. Nein, das Zitat ist an dieser Stelle leider falsch. Wir müssen genau wissen was uns erwartet. Bevor wir mit dem YAML Code starten, sollten wir das zu automatisierende Skript vollständig durchlaufen und uns die einzelnen Eingaben zwischenspeichern. Es ist außerdem ratsam, die Ausführungen zuerst in einer Testumgebung laufen zu lassen. Um die ersten Schritte zu veranschaulichen, möchte ich eine pgadmin4 web Installation unter Linux vorschlagen. Für die Initialisierung des Apache Webservers muss ein Bash Skript ausgeführt werden – perfekt für Ansible Expect! Nachdem wir für unser Beispiel das setup-web.sh Skript ausgeführt und uns alle interaktiven Eingaben notiert haben, können wir mit dem YAML Code für Ansible starten. Wir definieren das Expect Modul und geben als command den Pfad zum Bash Skript an.\n- name: install pgAdmin4-web become: true expect: command: /usr/pgadmin4/bin/setup-web.sh Danach geben wir unsere Responses als Dictonary an. Als Key geben wir die Abfrage im Skript in Form einer Regular Expression (RegEx) an. Unser Value ist dann die Eingabe.\n- name: install pgAdmin4-web become: true expect: command: /usr/pgadmin4/bin/setup-web.sh responses: \u0026#39;Email\\ address:\u0026#39;: \u0026#34;me@mydomain.de\u0026#34; \u0026#39;Password\u0026#39;: \u0026#34;mypassword\u0026#34; \u0026#39;Retype\\ password:\u0026#39;: \u0026#34;mypassword\u0026#34; \u0026#39;Do\\ you\\ wish\\ to\\ continue\\ \\(y\\/n\\)\\?\u0026#39;: \u0026#34;y\u0026#34; \u0026#39;The\\ Apache\\ web\\ server\\ is\\ running\\ and\\ must\\ be\\ restarted\\ for\\ the\\ pgAdmin\\ 4\\ installation\\ to\\ complete\\.\\ Continue\\ \\(y\\/n\\)\\? \u0026#39;: \u0026#34;y\u0026#34; Mehr ist tatsächlich nicht zu machen. Noch eine Empfehlung dazu: Damit das Skript nicht mit jedem Ansible Run ausgeführt wird, sollte die Ausführung des Expect Moduls innerhalb eines Blocks und einer Condition ausgeführt werden. Das könnte für pgadmin4 web beispielsweise so aussehen:\n- name: check pgadmin4-web installation state ignore_errors: true shell: apt list --installed | grep pgadmin4-web register: pgadmin4_installation_state - name: skip the installation if pgadmin4-web is already installed block: ### installation ### ### expect ### when: \u0026#34;\u0026#39;pgadmin4-web\u0026#39; not in pgadmin4_installation_state.stdout\u0026#34; Sich wiederholende Abfragen # Es kann auf vorkommen, dass sich gleiche Abfragen innerhalb eines Skripts wiederholen. Zum Beispiel „Sind Sie sicher?“. Solche Abfragen können bei der Ausführung von Expect für Probleme sorgen, besonders wenn wir auf die gleiche Frage auch unterschiedliche Antworten liefern möchten. Aber auch dafür gibt es eine Lösung: Als Value eines Response kann eine Liste angegeben werden. Die Liste wird dann in der angegeben Reihenfolge abgearbeitet.\n- name: run some script expect: command: /path/to/my/script responses: \u0026#39;Email\\ address:\u0026#39;: \u0026#34;me@mydomain.de\u0026#34; \u0026#39;Password\u0026#39;: \u0026#34;mypassword\u0026#34; \u0026#39;(?i)Enter\\ a\\ number\\,\\ and\\ hit\\ ENTER\\:\\ \u0026#39; - \u0026#34;5\u0026#34; - \u0026#34;1\u0026#34; Bei der ersten „Enter a number, and hin ENTER:“ Abfrage wird die Eingabe „5“ durchgeführt. Wenn „Enter a number, and hin ENTER:“ zum zweiten Mal abgefragt wird, gibt Ansible die „1“ an.\n","date":"16 January 2023","externalUrl":null,"permalink":"/blog/ansible-expect-und-respones/","section":"Blog","summary":"","title":"Ansible – Expect und Respones","type":"blog"},{"content":"Es gibt heutzutage einige Möglichkeiten, die komplette Rotation bzw. den Lifecycle der Mobilgeräte in einem Unternehmen zu automatisieren. Bereits bei der Bestellung eines iPhones sollte der Provider oder Reseller das Gerät für den Kunden im Enterprise Mobility Management (EMM) provisionieren. Für Apple gibt es den Apple Business Manager und unter Android kann die Zerotouch Konsole verwendet werden. Diese EMM-Portale müssen mit dem verwendeten Mobile Device Management (MDM) verknüpft werden. Dadurch lässt sich ein hoher Automatisierungsgrad erreichen.\nWozu jetzt die ganze Arbeit? # Im Endausbau gestaltet sich durch die Kombination aus EMM und MDM folgendes Ergebnis: Das iPhone/Smartphone wird bestellt, direkt an den Endbenutzer ausgeliefert und die personalisierte Konfiguration wird automatisch zur Verfügung gestellt. Die IT-Abteilung wird dadurch enorm entlastet. Ein echter Business Value!\nWomit fange ich jetzt am besten an? # Lasst uns zuerst den Blick nach Kalifornien richten und mit Apple Produkten anfangen. Im ersten Schritt ist ein Unternehmensaccount für den Apple Business Manager (ABM) erforderlich. Apple möchte hier einige Informationen zum Unternehmen haben. Mehr dazu kannst du hier nachlesen: https://support.apple.com/de-de/guide/apple-business-manager/axm402206497/web . Sobald du einen Account hast, solltest du weitere Administratoren bestimmen. Du kannst maximal 5 Personen als Administrator konfigurieren. Als nächstes solltest du deine Domains im Apple Business Manager registrieren. Unter den Account Einstellungen kannst du Domains hinzufügen, für die Verifizierung musst du einen TXT Record in deinem DNS hinterlegen. Die darauffolgende Challenge bestätigt die Inhaberschaft.\nFederated Authentication # In vielen Unternehmen wird inzwischen ein Azure Active Directory (AAD) gepflegt. Dadurch bietet sich die Chance, unseren Apple Business Manager mit dem Active Directory zu verknüpfen. Benutzer:innen können sich jetzt eine neue Apple ID über deine registrierte Domain anlegen und sich direkt mit dem Microsoft/AAD Konto authentifizieren – praktisch. Auch hier wird die IT-Abteilung weiterhin entlastet. Durch die Federated Authentication in Kombination mit der registrierten Domain, werden die erstellen Apple IDs zu verwalteten Apple IDs. Verlorene Apple ID Kennwörter sind somit kein Problem mehr, wir verwenden schließlich das AAD-Konto!\nKommen wir auch mal zu den iPhones? # Nicht so schnell. Ein gutes Konzept benötigt Planung und sauberes Vorgehen. Falls nicht schon vorhanden, benötigst du jetzt einen zertifizierten Apple Reseller, wie z.B. die Telekom. Du musst deinen Provider/Reseller bzgl. des Apple Device Enrollment Programm (Apple DEP) anfragen. Hier wird ein entsprechender Vertrag aufbereitet und eine Pauschale erhoben. Zusätzlich fällt eine kleine Gebühr für jedes bestellte Gerät an. Du wirst unter anderem deine ABM Organisations-ID übermitteln müssen. Diese findest du direkt unter den Registrierungsinformationen in deinem Apple Business Manager.\nMobile Device Management # Sind die bisherigen Schritte erfolgreich umgesetzt, kann jetzt eine Verknüpfung zu deinem Mobile Device Management hergestellt werden. Du kannst das MDM direkt im Apple Business Manager registrieren. Über den Austausch von Tokens erhält das MDM direkte Informationen zu neuen Geräten, die im Apple Business Manager importiert werden. Du kannst jetzt Profile und Konfigurationen hinterlegen, die automatisch an die Synchronisierten Geräte geknüpft werden.\nJa, jetzt kommen endlich die iPhones # Neue iPhones werden ab jetzt vom Reseller in deinem Apple Business Manager registriert. Über die zuvor konfigurierte Verknüpfung werden die iPhones direkt in dein MDM importiert und anhand deiner hinterlegten Konfigurationen konfiguriert.\nWas gibt es sonst noch? # Bei Mobilgeräten müssen wir noch über Themen wie das Apple Volume Purchase Programm sprechen. Außerdem gibt es das Android Pendant zum Apple Business Manager: Den Managed Google Play Store. Es wird in Zukunft noch weitere Posts zu diesen Themen geben.\n","date":"13 January 2023","externalUrl":null,"permalink":"/blog/emmmdm-automatisierungen-und-lifecycles/","section":"Blog","summary":"","title":"EMM/MDM Automatisierungen und Lifecycles","type":"blog"},{"content":" Warum Terraform für vSphere und das Deployment virtueller Maschinen? # Der Code ist die Dokumentation! In diesem Fall trifft das vollkommen zu – jedenfalls wenn es um den Aufbau der Maschine und die ursprünglichen Spezifikationen geht. Wir hinterlegen in einer Terraform Datei den kompletten Bauplan unserer Maschine. Wie viel RAM, CPU, Festplattenkapazität und welches Image benötigen wir? Das alles hinterlegen wir einfach im Code. Außerdem werden unsere virtuellen Maschinen zu einem „Wegwerfartikel”. Natürlich nur, sofern die Maschine stateless ist, keine Datenbank vorzeigt und wir ein Configuration Management wie z.B. Ansible beherrschen. Bevor wir also lange an einer fehlerhaften Maschine troubleshooting Betreiben, erstellen wir diese einfach neu. Abhängig von der Serverumgebung benötigt Terraform im Schnitt 2 Minuten für das Deployment einer Maschine.\nGolden Image in der Content Library – ein Segen # Wenn wir über Linux und Windows Deployments sprechen, sollten wir für Terraform unter vSphere auch ein vorbereitetes Virtual Machine Template bereithalten. Bei größeren Umgebungen mit mehreren Datacenter/Standorten eignet sich dazu die Content Library von VMware. Wir Synchronisieren dann die Templates über alle Standorte hinweg – praktisch. Das Template sollte direkt für unser Configuration Management vorbereitet sein.\nUnd was bedeutet das jetzt? Wir können innerhalb weniger Minuten komplett individualisierte und zugleich standardisierte Server aufbauen. Die Basis wird immer durch das gleiche Virtual Machine Template gebildet. Konkret: Wir führen Terraform aus und lassen im Anschluss das Configuration Management laufen. Danach haben wir beispielsweise sofort unseren fertigen Webserver, Appserver, Reverse Proxy etc.\nEin eigenes Terraform vSphere Modul schreiben # Die ganze Konfiguration für ein Deployment unter vSphere kann natürlich über ein einziges Terraform File durchgeführt werden. Diese Vorgehensweise ist jedoch eher ungünstig, wenn wir große Umgebungen betreuen möchten. Hier sollte direkt ein passendes Terrafom Modul geschrieben werden. Ich werde im folgenden Beispiel das reine Server Deployment Modul beschreiben, es müssen dazu Datendefinitionen und Variablen deklariert werden. Vielleicht werde ich dazu nochmal einen weiteren Blogpost verfassen. Wir beginnen mit unserer server.tf und hinterlegen fürs Erste eine resource definition.\nresource \u0026#34;vsphere_virtual_machine\u0026#34; \u0026#34;server\u0026#34; { count = var.guest_id == \u0026#34;ubuntu64Guest\u0026#34; ? 1 : 0 name = var.virtual_machine_name datastore_id = data.vsphere_datastore.datastore.id resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id num_cpus = var.cpus memory = var.memory guest_id = var.guest_id tags = [data.vsphere_tag.tag.id] scsi_type = var.scsi_type „count“ bestimmt, ob wir einen Windows Server oder einen Linux Server erstellen. Die „guest_id“ muss dann im späteren Deployment angegeben werden. Wir sollten jetzt zwingend ein „lifecycle“ Statement verfassen, sonst löschen wir vielleicht unbeabsichtigt produktive Maschinen.\nlifecycle { prevent_destroy = true ignore_changes = all } Als nächstes bauen wir noch das Netzwerkinterface für unsere Maschine ein.\nnetwork_interface { network_id = data.vsphere_network.network.id } Es kann gut sein, dass unser Server mehr als eine Festplatte halten soll. Daher können wir in Terraform eine Schleife deklarieren, um es uns im späteren Deployment möglichst einfach zu machen.\ndynamic \u0026#34;disk\u0026#34; { for_each = [for s in var.disks: { label = s.label unit_number = s.unit_number size = s.size }] content { label = disk.value.label unit_number = disk.value.unit_number size = disk.value.size } } Jetzt kommt der wichtige Teil. Mit dem „clone“ Block legen wir das Template und die Optionen der virtuellen Maschine fest.\nclone { template_uuid = data.vsphere_content_library_item.content_library_item.id customize { linux_options { host_name = var.host_name domain = var.domain } network_interface { ipv4_address = var.ipv4_address ipv4_netmask = var.ipv4_netmask } ipv4_gateway = var.ipv4_gateway dns_server_list = var.dns_server_list } } Mit der „template_uuid“ Datendefinition holen wir uns die uuid des gewünschten Content Library Objekts, um dieses für unser Deployment zu verwenden. Hier nochmal der komplette Code unserer server.tf\nresource \u0026#34;vsphere_virtual_machine\u0026#34; \u0026#34;server\u0026#34; { count = var.guest_id == \u0026#34;ubuntu64Guest\u0026#34; ? 1 : 0 name = var.virtual_machine_name datastore_id = data.vsphere_datastore.datastore.id resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id num_cpus = var.cpus memory = var.memory guest_id = var.guest_id tags = [data.vsphere_tag.tag.id] scsi_type = var.scsi_type lifecycle { prevent_destroy = true ignore_changes = all } network_interface { network_id = data.vsphere_network.network.id } dynamic \u0026#34;disk\u0026#34; { for_each = [for s in var.disks: { label = s.label unit_number = s.unit_number size = s.size }] content { label = disk.value.label unit_number = disk.value.unit_number size = disk.value.size } } clone { template_uuid = data.vsphere_content_library_item.content_library_item.id customize { linux_options { host_name = var.host_name domain = var.domain } network_interface { ipv4_address = var.ipv4_address ipv4_netmask = var.ipv4_netmask } ipv4_gateway = var.ipv4_gateway dns_server_list = var.dns_server_list } } } resource \u0026#34;vsphere_virtual_machine\u0026#34; \u0026#34;windows_server\u0026#34; { count = var.guest_id == \u0026#34;windows2019srv_64Guest\u0026#34; ? 1 : 0 name = var.virtual_machine_name datastore_id = data.vsphere_datastore.datastore.id firmware = \u0026#34;efi\u0026#34; resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id num_cpus = var.cpus memory = var.memory guest_id = var.guest_id tags = [data.vsphere_tag.tag.id] scsi_type = \u0026#34;lsilogic-sas\u0026#34; lifecycle { prevent_destroy = true ignore_changes = all } network_interface { network_id = data.vsphere_network.network.id } dynamic \u0026#34;disk\u0026#34; { for_each = [for s in var.disks: { label = s.label unit_number = s.unit_number size = s.size }] content { label = disk.value.label unit_number = disk.value.unit_number size = disk.value.size } } clone { template_uuid = data.vsphere_content_library_item.content_library_item.id customize { windows_options { computer_name = var.host_name } network_interface { ipv4_address = var.ipv4_address ipv4_netmask = var.ipv4_netmask } ipv4_gateway = var.ipv4_gateway dns_server_list = var.dns_server_list } } } ","date":"12 January 2023","externalUrl":null,"permalink":"/blog/terraform-and-vsphere/","section":"Blog","summary":"","title":"Terraform \u0026 vSphere","type":"blog"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"Nicht jedes Ticket verdient eine Seite. Diese Projekte schon.\n2020 # Mobile Device Management – Rollout für 1.200 Endgeräte # Einführung einer unternehmensweiten MDM-Lösung in Kombination mit einem EMM-Provider zur automatisierten Provisionierung von rund 1.200 mobilen Endgeräten. Zero-Touch-Enrollment ermöglichte eine skalierbare Geräteverteilung ohne manuellen Aufwand.\n2021 # KIM-Infrastruktur – Ansible-gesteuertes Multi-Site-Deployment # Für die Einführung des KIM-Standards (Kommunikation im Medizinwesen) wurden an mehreren Standorten dedizierte Linux-Server aufgebaut und konfiguriert. Das gesamte Setup – von der Systemkonfiguration bis zur Anwendungsinstallation – wurde vollständig in Ansible abgebildet, um ein reproduzierbares und wartbares Deployment zu gewährleisten.\n2022 # Datenbankplattform-Migration – Informix zu PostgreSQL (Multi-Site) # Im Rahmen einer technischen Modernisierung wurde die Datenbankinfrastruktur eines Krankenhausinformationssystems an rund 17 Akutstandorten von Informix auf PostgreSQL migriert. Die zugehörigen Linux-Server wurden dabei vollständig erneuert. Durch eine generische Ansible-Automatisierung und Terraform-basierte VM-Provisionierung konnte der Rollout skalierbar und konsistent über alle Standorte hinweg umgesetzt werden.\n2023 # Migration der SIP-Trunk-Infrastruktur # Eine gewachsene Voice-Backend-Infrastruktur – veraltete Betriebssysteme, kein aktiver Sicherheitspatch-Zyklus, keine Redundanz – wurde vollständig modernisiert. Der Stack umfasste Kamailio als SIP-Proxy sowie die RTPEngine für die Mediaverarbeitung. Neben dem OS-Upgrade und der Härtung aller Komponenten wurde erstmals ein durchgängiges Configuration Management eingeführt, das reproduzierbare Deployments und automatisches Reconciling ermöglicht. Das Ergebnis: eine hochverfügbare, wartbare SIP-Trunk-Plattform mit sauber getrennter Signalisierungs- und Mediaebene.\nConfiguration Management Replatforming # Das gewachsene und schwer wartbare Configuration Management wurde von Grund auf neu konzipiert. Ziel war eine saubere, versionierte Ansible-Infrastruktur mit automatischem Reconcile-Mechanismus. Da gängige Out-of-the-Box-Lösungen wie Foreman oder Ansible AWX nicht den erforderlichen Grad an Flexibilität boten, wurde ein maßgeschneidertes Jenkins-Setup entwickelt, das zyklisches Reconciling über den gesamten Serverbestand ermöglicht.\n2023 – 2024 # Ansible Pull – Configuration Management für ~13.000 Linux-Systeme # Bei einer Flotte von rund 13.000 homogenen Linux-Systemen schied ein klassischer Puppet-Ansatz aufgrund von Komplexität und unzureichender Modulpflege aus. Stattdessen wurde eine speziell entwickelte Ansible-Pull-Lösung konzipiert – schlanker, transparenter und besser auf generische, gleichartige Zielsysteme zugeschnitten.\nSkalierbare Monitoring-Plattform – Prometheus, Thanos \u0026amp; Grafana # Die Ablösung einer bestehenden Monitoring-Lösung war notwendig, da sie bei dieser Systemanzahl an ihre Grenzen stieß – insbesondere hinsichtlich Agentenverteilung und Skalierbarkeit. Im Mittelpunkt der neuen Architektur stand eine maßgeschneiderte Prometheus Service Discovery, die dynamisch auf den Bestand reagiert. Kombiniert mit Thanos für langfristige Metrikspeicherung via Object Storage und Grafana als Visualisierungsschicht entstand eine vollständig selbst entwickelte, hochskalierbare Observability-Plattform.\n2025 # On-Premise Kubernetes Platform # Um interne Workloads und Applikationen auf Kubernetes zu überführen, wurde eine produktionsreife On-Premise-Plattform von Grund auf konzipiert und aufgebaut. Die Herausforderungen lagen dabei nicht nur in der Wahl der richtigen Container-Engine, sondern auch in der Konzeption von Netzwerksicherheit, Backup-Strategie, Admission-Control-Policies, Ingress-Architektur und einer privaten Container-Registry – ein vollständiger, aufeinander abgestimmter Kubernetes-Stack.\n","externalUrl":null,"permalink":"/projects/","section":" ","summary":"","title":"Projekte","type":"page"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":" Seit 2015 in der IT – von der Krankenhaus-EDV bis zu latenzsensibler VoIP-Infrastruktur. Heute bringe ich Systeme zum Laufen, die es sich nicht leisten können, auszufallen.\nMeine IT-Reise begann 2015 mit einer Ausbildung in der Krankenhaus-IT – einem Umfeld, das einen schnell auf Trab hält. Komplexe Systeme, hoher Verfügbarkeitsdruck und das ständige Spannungsfeld zwischen Stabilität und Wandel haben mich früh gelernt, unter echten Bedingungen zu arbeiten. Nicht trotz der Herausforderungen, sondern durch sie. In dieser Zeit entwickelte ich eine tiefe Leidenschaft für Cloud-Architekturen und Automatisierung – die Überzeugung, dass gut durchdachte Infrastruktur nicht nur funktionieren, sondern sich anfühlen sollte wie ein präzises Werkzeug. Heute arbeite ich als DevOps Engineer bei der Starface GmbH, einem auf Telekommunikation spezialisierten Softwareunternehmen. Dort habe ich mich vollständig in die Linux- und Open-Source-Welt vertieft: von der Optimierung hochperformanter Linux-Systeme über VoIP-Protokolle wie SIP und RTP bis hin zu latenzsensibler Mediaverarbeitung. In Umgebungen, in denen Millisekunden zählen und Ausfälle keine Option sind, ist präzises Engineering kein Bonus – es ist Pflicht. Parallel dazu begleitet mich ein zweites großes Thema: Hochverfügbarkeit. Von ausfallsicheren Datenbankarchitekturen im Backend bis hin zu produktionsreifen Kubernetes-Clustern und containerisierten Applikationen – ich baue Systeme, die auch dann laufen, wenn es darauf ankommt.\nLeadership \u0026amp; Management # Projektleitung (API-Integrationen, Ansible-/Terraform-Rollouts, klinikspezifische IT-Projekte) Teamleitung IT DevOps Abteilungsleitung Krankenhaus-IT Cloud Platforms # Azure (VMs, Virtual Networks, Route Tables, Load Balancer, App Services, Function Apps, Enterprise Applications, App Registrations, AKS, Service Bus, Azure Monitor, AZ CLI) Azure DevOps Virtualisierung \u0026amp; On-Premise # Proxmox VMware vSphere / ESXi KVM / QEMU Kubernetes \u0026amp; Container # Kubernetes (AKS, K3s, RKE2, Kubeadm) Rancher Helm Kustomize Docker / Containerd / Podman Harbor (Container Registry) Infrastructure as Code # Terraform / OpenTofu Crossplane Configuration Management # Ansible Puppet CI/CD \u0026amp; GitOps # ArgoCD / FluxCD GitLab CI/CD Jenkins Networking \u0026amp; Telekommunikation # SIP / RTP / VoIP Linux Networking (iptables, nftables, routing, namespaces) BGP / OSPF (Grundlagen) VLAN / Switching Extreme Networks Cloud Netbox (IPAM / DCIM) Keepalived HAProxy / Nginx / Traefik (Load Balancing \u0026amp; Reverse Proxy) Observability \u0026amp; Monitoring # Prometheus / Thanos Grafana Alertmanager Graylog Icinga Tempo OpenTelemetry (Grundlagen) Datenbanken # PostgreSQL MySQL / MariaDB Redis Patroni (HA-Clustering) etcd Identity \u0026amp; Access Management # Keycloak Okta OAuth2 / OIDC / SAML Security \u0026amp; Secrets Management # OpenBao Vault Bitnami Sealed Secrets Cert-Manager / Let\u0026rsquo;s Encrypt Trivy (Container Security, auch in CI Pipelines) NeuVector Scripting \u0026amp; Programmierung # Bash Python Go (Grundlagen) YAML / JSON / TOML Storage \u0026amp; Backup # Proxmox Backup Server Ceph Longhorn NFS / iSCSI Velero (Kubernetes Backup) ","externalUrl":null,"permalink":"/about_me/","section":" ","summary":"","title":"Über mich","type":"page"}]