{"id":7227,"date":"2021-04-06T19:47:35","date_gmt":"2021-04-06T19:47:35","guid":{"rendered":"https:\/\/berg-software.com\/einblicke\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/"},"modified":"2021-04-06T19:47:44","modified_gmt":"2021-04-06T19:47:44","slug":"dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab","status":"publish","type":"post","link":"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/","title":{"rendered":"DynamicIP Remote Access \/ Fernzugriff f\u00fcr Softwareentwickler mit ma\u00dfgeschneiderter L\u00f6sung (Python +Terraform +GitLab)"},"content":{"rendered":"\n\n[et_pb_section fb_built=&#8220;1&#8243; fullwidth=&#8220;on&#8220; _builder_version=&#8220;4.4.1&#8243;][et_pb_fullwidth_post_title meta=&#8220;off&#8220; featured_placement=&#8220;background&#8220; _builder_version=&#8220;4.6.6&#8243; title_font=&#8220;||||||||&#8220; title_text_color=&#8220;#ff6317&#8243; title_font_size=&#8220;3.5em&#8220; meta_font=&#8220;|300|||||||&#8220; meta_text_color=&#8220;#ffffff&#8220; meta_font_size=&#8220;1em&#8220; background_enable_color=&#8220;off&#8220; use_background_color_gradient=&#8220;on&#8220; background_color_gradient_start=&#8220;rgba(248,248,248,0.85)&#8220; background_color_gradient_end=&#8220;rgba(248,248,248,0.75)&#8220; background_color_gradient_overlays_image=&#8220;on&#8220; min_height=&#8220;20vh&#8220; height=&#8220;400px&#8220; custom_padding=&#8220;6vh||6vh||false|false&#8220; global_module=&#8220;403&#8243; locked=&#8220;off&#8220;][\/et_pb_fullwidth_post_title][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>Die Herausforderung der DynamicIP<\/h2>\n<p>Wenn die Entwickler von Berg Software von zu Hause aus arbeiten (wie die meisten Menschen heutzutage), verwenden sie ein VPN, um eine sichere Verbindung zu unserer Infrastruktur am Standort herzustellen. Dies ist in einigen F\u00e4llen vollkommen ausreichend. Beim Zugriff auf die Nicht-Produktions-Infrastruktur gestaltet sich die Situation jedoch ein wenig komplexer:<\/p>\n<ul>\n<li>Erstens ist es aufgrund des <span style=\"text-decoration: underline;\">aktuellen Stands der Technik<\/span> eine Herausforderung: Das Hosting der Nicht-Produktions-Infrastruktur in der Cloud (d. h. \u201eIaC\/Infrastructure as Code\u201c) ist derzeit nicht blo\u00df eine von vielen Optionen, sondern die Norm \u2013 es geht also kein Weg daran vorbei.<\/li>\n<li>Zweitens geht es um <span style=\"text-decoration: underline;\">die Risiken<\/span>: Die Nicht-Produktionsrechner (auf denen die Entwicklung, das Testen und die Qualit\u00e4tssicherung erfolgen) sind etwas, auf das niemand au\u00dferhalb des Entwicklerteams Zugriff haben sollte (und das schlie\u00dft den Client, Indizierungs-Bots usw. ein). Die Nicht-Produktionsrechner sind daher vom Internet abgetrennt, was sie generell unzug\u00e4nglich macht.<\/li>\n<li>Drittens, aber nicht zuletzt, geht es um <span style=\"text-decoration: underline;\">den VPN-Zugang selbst<\/span>: Um den Zugriff auf einen fremden Rechner zu erm\u00f6glichen, erlauben alle Firewalls nur den Zugriff auf bestimmte IP-Adressen. Die IP-Adresse einer Person bleibt jedoch nicht immer zu 100 % unver\u00e4ndert: Es kann sein, dass jemand seinen Router zur\u00fccksetzt oder seinen Dienstanbieter dazu veranlasst, diesen \u201eeinfach so\u201c zur\u00fcckzusetzen. In diesen F\u00e4llen muss unser Operations-Team die IP-Liste aktualisieren \u2013 was m\u00fchsam, langsam und fehleranf\u00e4llig sein kann.<\/li>\n<\/ul>\n<p>Wir haben uns daher eine Dynamic IP-L\u00f6sung ausgedacht, die zwei Dinge erf\u00fcllen soll:<\/p>\n<ul>\n<li>etwas Bekanntes (d. h. einen FQDN\/Fully Qualified Domain Name) in eine IP-Adresse umzuwandeln (wird von den Firewalls zum Erstellen der Zugriffsregeln ben\u00f6tigt);<\/li>\n<li>einen dynamischen DNS-Dienst zu verwenden, um den FQDN mit der neuen IP-Adresse des Entwicklerrechners zu aktualisieren.<\/li>\n<\/ul>\n<p>Unsere L\u00f6sung war ein automatisiertes, zeitgesteuertes Tool, das die Aktualisierung der Firewall\/IP-Liste automatisiert und damit Eingriffe der Operationsabteilung \u00fcberfl\u00fcssig macht sowie Wartezeiten verk\u00fcrzt.<\/p>\n[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.7.7&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;rgba(0,0,0,0)&#8220; sticky_enabled=&#8220;0&#8243;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>Das dynamische DNS<\/h2>\n<p>Um einen DNS-Dienst auszuw\u00e4hlen, haben wir den damaligen Status-quo genutzt, um die Anforderungen zu entwickeln:<\/p>\n<ul>\n<li>Er sollte uns erlauben, Subdomains unter unserem Hauptdomainnamen zu verwenden.<\/li>\n<li>Er sollte dem Operations-Team erlauben, Subdomains nach Bedarf zu erstellen\/zu entfernen.<\/li>\n<li>Es sollte nicht erforderlich sein, dass Entwickler eigene Konten erstellten, und er sollte dem Operations-Team erlauben, den aktualisierten, personalisierten Link f\u00fcr jeden Entwickler in einer zentralisierten Konsole zu generieren.<\/li>\n<li>Es sollte keine Anwendung (\/kein komplizierter Prozess) erforderlich sein, um den FQDN zu aktualisieren.<\/li>\n<li>Die generierten Links sollten kein automatisches Ablaufdatum haben. Wenn einer unserer Entwickler eine statische IP-Adresse hatte, sollte er seinen FQDN nicht aktualisieren m\u00fcssen.<\/li>\n<\/ul>\n<p>Darauf aufbauend haben wir uns f\u00fcr das Premium-DNS-Paket von ClouDNS entschieden: Es verlangt von unseren Entwicklern, einen Link in ihrem regul\u00e4ren Browser als Lesezeichen zu setzen und ihn dann anzuklicken\/zu \u00f6ffnen, um ihren jeweiligen FQDN-Eintrag zu aktualisieren.<\/p>\n<p>Nachdem der FQDN-Eintrag mit der Information \u00fcber die aktualisierte IP des Entwicklers verf\u00fcgbar war, mussten wir die Firewall-Informationen aktualisieren, sobald sich die IP-Adresse \u00e4nderte. Durch die Analyse unserer regul\u00e4ren Tools und Technologien konnten wir drei davon wie folgt kombinieren:<\/p>\n<ul>\n<li><span style=\"text-decoration: underline;\">Python<\/span>: \u00fcbersetzt den FQDN in eine IP-Adresse; und f\u00fchrt eine Liste der letzten bekannten IP-Adressen, damit wir \u00fcberpr\u00fcfen k\u00f6nnen, ob sich etwas ge\u00e4ndert hat. (Dann \u2013 nur wenn sich etwas ge\u00e4ndert hat \u2013 f\u00fchrt man die Skripte aus, um die Firewall zu aktualisieren).<\/li>\n<li><span style=\"text-decoration: underline;\">Terraform<\/span>: aktualisiert die Firewall auf unseren Rechnern.<\/li>\n<li><span style=\"text-decoration: underline;\">GitLab CI\/CD Scheduler<\/span>: f\u00fchrt den Workflow alle paar Minuten aus.<\/li>\n<\/ul>\n<p>Schauen wir uns also jedes einzelne davon an:<\/p>\n[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.7.7&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||0px||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;rgba(0,0,0,0)&#8220; sticky_enabled=&#8220;0&#8243;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>Python<\/h2>\n<p>Wir entschieden uns, Python zu verwenden, um den DNS-Teil der Herausforderung zu l\u00f6sen, weil:<\/p>\n<ul>\n<li>wir die Socket-Bibliothek zur Verf\u00fcgung haben<\/li>\n<li>und <em>socket.gethostbyname(hostname)<\/em> verwenden k\u00f6nnen, um basierend auf dem FQDN die entsprechende IP-Adresse abzurufen.<\/li>\n<\/ul>\n<p>Unser Skript hat drei Hauptziele:<\/p>\n<ul>\n<li>alle FQDNs in IP-Adressen umzuwandeln,<\/li>\n<li>zu \u00fcberpr\u00fcfen, ob eine der IP-Adressen nicht mit dem vorherigen Run-Status \u00fcbereinstimmt, und bei \u00c4nderungen zu aktualisieren,<\/li>\n<li>basierend auf einer Vorlage, die die OpenTelekomCloud-Sicherheitsgruppen-Informationen enth\u00e4lt, eine neue Terraform-Datei zu erstellen, die die aktualisierte IP-Adresse beinhaltet.<\/li>\n<\/ul>\n<p>Hier ist der Auszug aus dem Skript:<\/p>\n[\/et_pb_text][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220; locked=&#8220;off&#8220; sticky_enabled=&#8220;0&#8243;]<pre class=\"python\" style=\"font-family:monospace;\"><span style=\"color: #808080; font-style: italic;\">#!\/usr\/bin\/env python3<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">import<\/span> <span style=\"color: #dc143c;\">socket<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">import<\/span> <span style=\"color: #dc143c;\">sys<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">import<\/span> <span style=\"color: #dc143c;\">os<\/span>\nipfile <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #483d8b;\">'ci\/dynip\/oldips'<\/span>\nhostnames <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: black;\">[<\/span><span style=\"color: #483d8b;\">\"DeveloperFirstName.DeveloperLastName.dyn.myDomain.com\"<\/span><span style=\"color: black;\">]<\/span>\nips<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #483d8b;\">\"\"<\/span>\nold_ips<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #483d8b;\">\"\"<\/span>\ni<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #ff4500;\">1<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">for<\/span> hostname <span style=\"color: #ff7700;font-weight:bold;\">in<\/span> hostnames:\n    <span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span>hostname<span style=\"color: black;\">)<\/span>\n    ip <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #dc143c;\">socket<\/span>.<span style=\"color: black;\">gethostbyname<\/span><span style=\"color: black;\">(<\/span>hostname<span style=\"color: black;\">)<\/span>\n    ips<span style=\"color: #66cc66;\">=<\/span>ips+<span style=\"color: #483d8b;\">'{ip = \"'<\/span>+ip+<span style=\"color: #483d8b;\">'\/32\",name = \"'<\/span>+hostname+<span style=\"color: #483d8b;\">'\"}'<\/span>\n    <span style=\"color: #ff7700;font-weight:bold;\">if<\/span> i <span style=\"color: #66cc66;\">!=<\/span> <span style=\"color: #008000;\">len<\/span><span style=\"color: black;\">(<\/span>hostnames<span style=\"color: black;\">)<\/span>:\n        ips<span style=\"color: #66cc66;\">=<\/span>ips+<span style=\"color: #483d8b;\">\",<span style=\"color: #000099; font-weight: bold;\">\\n<\/span>\"<\/span>\n    i<span style=\"color: #66cc66;\">=<\/span>i+<span style=\"color: #ff4500;\">1<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'Discovered ips:'<\/span><span style=\"color: black;\">)<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span>ips<span style=\"color: black;\">)<\/span>\n<span style=\"color: #808080; font-style: italic;\">### Here tyo add check if the string ips is different to the one we have in the status file. <\/span>\n<span style=\"color: #808080; font-style: italic;\">### If different then continue - else exit<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">def<\/span> inplace_change<span style=\"color: black;\">(<\/span>filename_tmpl<span style=\"color: #66cc66;\">,<\/span> filename_dest<span style=\"color: #66cc66;\">,<\/span> old_string<span style=\"color: #66cc66;\">,<\/span> new_string<span style=\"color: black;\">)<\/span>:\n    <span style=\"color: #808080; font-style: italic;\"># Safely read the input filename using 'with'<\/span>\n    <span style=\"color: #ff7700;font-weight:bold;\">with<\/span> <span style=\"color: #008000;\">open<\/span><span style=\"color: black;\">(<\/span>filename_tmpl<span style=\"color: black;\">)<\/span> <span style=\"color: #ff7700;font-weight:bold;\">as<\/span> fr:\n        s <span style=\"color: #66cc66;\">=<\/span> fr.<span style=\"color: black;\">read<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span>\n        <span style=\"color: #ff7700;font-weight:bold;\">if<\/span> old_string <span style=\"color: #ff7700;font-weight:bold;\">not<\/span> <span style=\"color: #ff7700;font-weight:bold;\">in<\/span> s:\n            <span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'\"{old_string}\" not found in {filename}.'<\/span>.<span style=\"color: black;\">format<\/span><span style=\"color: black;\">(<\/span>**<span style=\"color: #008000;\">locals<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span>\n            <span style=\"color: #ff7700;font-weight:bold;\">return<\/span>\n&nbsp;\n        <span style=\"color: #808080; font-style: italic;\"># Safely write the changed content, if found in the file<\/span>\n        <span style=\"color: #ff7700;font-weight:bold;\">with<\/span> <span style=\"color: #008000;\">open<\/span><span style=\"color: black;\">(<\/span>filename_dest<span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #483d8b;\">'w'<\/span><span style=\"color: black;\">)<\/span> <span style=\"color: #ff7700;font-weight:bold;\">as<\/span> fw:\n            <span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'Changing \"{old_string}\" to \"{new_string}\" in {filename_tmpl}'<\/span>.<span style=\"color: black;\">format<\/span><span style=\"color: black;\">(<\/span>**<span style=\"color: #008000;\">locals<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span>\n            s <span style=\"color: #66cc66;\">=<\/span> s.<span style=\"color: black;\">replace<\/span><span style=\"color: black;\">(<\/span>old_string<span style=\"color: #66cc66;\">,<\/span> new_string<span style=\"color: black;\">)<\/span>\n            fw.<span style=\"color: black;\">write<\/span><span style=\"color: black;\">(<\/span>s<span style=\"color: black;\">)<\/span>\n<span style=\"color: #808080; font-style: italic;\">## inplace_change('ci\/dynip\/secgroups-dynip-tmpl','secgroups-dynip.tf','!!!ADDRESSES!!!',ips)<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">def<\/span> read_file<span style=\"color: black;\">(<\/span>filePathOldIps<span style=\"color: black;\">)<\/span>:\n\t<span style=\"color: #ff7700;font-weight:bold;\">with<\/span> <span style=\"color: #008000;\">open<\/span><span style=\"color: black;\">(<\/span>filePathOldIps<span style=\"color: black;\">)<\/span> <span style=\"color: #ff7700;font-weight:bold;\">as<\/span> fr:\n\t\ts <span style=\"color: #66cc66;\">=<\/span> fr.<span style=\"color: black;\">read<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span>\n\t\t<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'Old ips:'<\/span><span style=\"color: black;\">)<\/span>\n\t\t<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'\"{s}\" found in \"{filePathOldIps}\".'<\/span>.<span style=\"color: black;\">format<\/span><span style=\"color: black;\">(<\/span>**<span style=\"color: #008000;\">locals<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span><span style=\"color: black;\">)<\/span>\n\t\t<span style=\"color: #ff7700;font-weight:bold;\">return<\/span> s\n<span style=\"color: #ff7700;font-weight:bold;\">def<\/span> write_file<span style=\"color: black;\">(<\/span>filePathOldIps<span style=\"color: #66cc66;\">,<\/span> newIps<span style=\"color: black;\">)<\/span>:\n\t<span style=\"color: #ff7700;font-weight:bold;\">with<\/span> <span style=\"color: #008000;\">open<\/span><span style=\"color: black;\">(<\/span>filePathOldIps<span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #483d8b;\">'w+'<\/span><span style=\"color: black;\">)<\/span> <span style=\"color: #ff7700;font-weight:bold;\">as<\/span> fw:\n\t\tfw.<span style=\"color: black;\">write<\/span><span style=\"color: black;\">(<\/span>newIps<span style=\"color: black;\">)<\/span>\n\t\t<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'ips written in {filename}.'<\/span><span style=\"color: black;\">)<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">if<\/span> <span style=\"color: #dc143c;\">os<\/span>.<span style=\"color: black;\">path<\/span>.<span style=\"color: black;\">isfile<\/span><span style=\"color: black;\">(<\/span>ipfile<span style=\"color: black;\">)<\/span>:\n\told_ips <span style=\"color: #66cc66;\">=<\/span> read_file<span style=\"color: black;\">(<\/span>ipfile<span style=\"color: black;\">)<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">if<\/span> old_ips <span style=\"color: #66cc66;\">==<\/span> ips:\n\t<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'no ip was changed'<\/span><span style=\"color: black;\">)<\/span>\n\t<span style=\"color: #dc143c;\">sys<\/span>.<span style=\"color: black;\">exit<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #ff4500;\">666<\/span><span style=\"color: black;\">)<\/span>\n<span style=\"color: #ff7700;font-weight:bold;\">else<\/span>:\n\t<span style=\"color: #ff7700;font-weight:bold;\">print<\/span><span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'ips were changed'<\/span><span style=\"color: black;\">)<\/span>\n\twrite_file<span style=\"color: black;\">(<\/span>ipfile<span style=\"color: #66cc66;\">,<\/span>ips<span style=\"color: black;\">)<\/span>\n\tinplace_change<span style=\"color: black;\">(<\/span><span style=\"color: #483d8b;\">'ci\/dynip\/secgroups-dynip-tmpl'<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #483d8b;\">'secgroups-dynip.tf'<\/span><span style=\"color: #66cc66;\">,<\/span><span style=\"color: #483d8b;\">'!!!ADDRESSES!!!'<\/span><span style=\"color: #66cc66;\">,<\/span>ips<span style=\"color: black;\">)<\/span><\/pre>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.7.7&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||0px||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;rgba(0,0,0,0)&#8220; sticky_enabled=&#8220;0&#8243;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>Terraform<\/h2>\n<p>Um die Wartung und das \u00c4nderungsmanagement unserer Cloud-Infrastruktur zu unterst\u00fctzen, haben wir die Infrastructure-as-a-Code-L\u00f6sung von Terraform mit den OpenTelekomCloud-Modulen verwendet. (Dies liegt daran, dass wir die OTC-Cloud nutzen. Das gleiche Ergebnis kann durch AWS\/Azure mit ihren jeweiligen Modulen erreicht werden).<\/p>\n<p>Hierbei stie\u00dfen wir auf die n\u00e4chsten Herausforderungen: Da das Skript automatisch ausgef\u00fchrt wurde, brauchten wir die M\u00f6glichkeit, die \u00c4nderungen nur f\u00fcr die spezifische Sicherheitsgruppe automatisch zu planen, zu genehmigen und anzuwenden. Alle anderen \u00c4nderungen w\u00fcrden ignoriert werden (z. B. alle \u00c4nderungen, die durch ein neues Basis-Image verursacht werden k\u00f6nnten, oder jede unvollst\u00e4ndig gepr\u00fcfte \u00c4nderung, die im Repo vorgenommen werden w\u00fcrde).<\/p>\n<p>Terraform bietet eine elegante L\u00f6sung f\u00fcr diese Herausforderung, da es uns erlaubt, nur eine bestimmte Terraform-Datei auszuf\u00fchren und die \u00dcbernahme von \u00c4nderungen automatisch zu genehmigen.<\/p>\n<p>Dies kann folgenderma\u00dfen umgesetzt werden:<\/p>\n[\/et_pb_text][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220; locked=&#8220;off&#8220; sticky_enabled=&#8220;0&#8243;]<pre class=\"text\" style=\"font-family:monospace;\">.\/ci\/app\/terraform  plan -target=opentelekomcloud_compute_secgroup_v2.secgrp_everithyng_dynip -out=project-plan02.dat |&amp; tee -a .\/logs\/plan-dyn-$today.log\n\n.\/ci\/app\/terraform apply -var-file=\".\/ci\/secrets\/secret.tfvars\" -auto-approve -target=opentelekomcloud_compute_secgroup_v2.secgrp_everithyng_dynip |&amp; tee -a .\/logs\/planautopply-dyn-$today.log<\/pre>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]Nachdem die Terraform-\u00c4nderungen auf die Infrastruktur angewendet wurden, m\u00fcssen wir auch daf\u00fcr sorgen, dass der terraform.tfstate automatisch an Git \u00fcbermittelt wird. Auf diese Weise erkennt Terraform beim n\u00e4chsten Mal, wenn es ausgef\u00fchrt wird, den korrekten Status.[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.7.7&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||0px||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;rgba(0,0,0,0)&#8220; sticky_enabled=&#8220;0&#8243;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>GitLab CI\/CD<\/h2>\n<p>Wir verwenden GitLab.com zur Versionskontrolle und zum Ausf\u00fchren der CI\/CD-Pipelines unseres Projekts. Daher mussten wir das <em>gitlabci<\/em>-Skript erweitern, um einen neuen Schritt hinzuzuf\u00fcgen, der basierend auf einer Bedingung ausgef\u00fchrt werden kann. Dieser Schritt sollte der Einzige sein, der ausgef\u00fchrt wird, wenn wir die Pipeline vom Scheduler aus starten.<\/p>\n<p>Details zu diesem Schritt:<\/p>\n[\/et_pb_text][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220; locked=&#8220;off&#8220; sticky_enabled=&#8220;0&#8243;]<pre class=\"text\" style=\"font-family:monospace;\">dynip-otc:\n  stage: dynip\n  before_script:\n    - apk --no-cache add bash git openssl py-pip\n  script:\n    - .\/ci\/bin\/x_dynsecurity.sh\n  tags:\n    - project\n  artifacts:\n    paths:\n      - .terraform\/\n      - project-plan02.dat\n      - logs\/\n    expire_in: 1 week\n  only:\n    refs:\n        - master\n    variables:\n      - $SCHEDULED_DYNIP =~ \/^true*\/<\/pre>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]Wir mussten auch einen neuen Scheduler in GitLab erstellen, um diesen Schritt auszuf\u00fchren. Dies kann \u00fcber die GitLab-Benutzeroberfl\u00e4che durchgef\u00fchrt werden:[\/et_pb_text][et_pb_image src=&#8220;https:\/\/berg-software.com\/wp-content\/uploads\/DynamicIP-remote-access-GitLab-01.jpg&#8220; alt=&#8220;DynamicIP remote access GitLab 01&#8243; title_text=&#8220;DynamicIP remote access GitLab 01&#8243; _builder_version=&#8220;4.7.7&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220; hover_enabled=&#8220;0&#8243; locked=&#8220;off&#8220; sticky_enabled=&#8220;0&#8243;][\/et_pb_image][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]Schlie\u00dflich mussten wir einen neuen Scheduler mit folgenden Details hinzuf\u00fcgen:[\/et_pb_text][et_pb_image src=&#8220;https:\/\/berg-software.com\/wp-content\/uploads\/DynamicIP-remote-access-GitLab-02.jpg&#8220; alt=&#8220;DynamicIP remote access GitLab 02&#8243; title_text=&#8220;DynamicIP remote access GitLab 02&#8243; _builder_version=&#8220;4.7.7&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220; hover_enabled=&#8220;0&#8243; locked=&#8220;off&#8220; sticky_enabled=&#8220;0&#8243;][\/et_pb_image][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.7.7&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||0px||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;rgba(0,0,0,0)&#8220; sticky_enabled=&#8220;0&#8243;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<h2>Fazit<\/h2>\n<p>Durch die Verwendung von lediglich drei einfachen und leicht zug\u00e4nglichen Tools (Python, Terraform, GitLab) waren wir in der Lage<\/p>\n<ul>\n<li>unseren Softwareentwicklern ungest\u00f6rtes Arbeiten von zu Hause aus zu erm\u00f6glichen,<\/li>\n<li>mit nahezu Echtzeit-IP-Updates,<\/li>\n<li>ohne umfangreiche\/komplizierte Systeme<\/li>\n<li>und ohne eigenes Personal f\u00fcr manuelle Handlungen\/Aktualisierungen.<\/li>\n<\/ul>\n<p>Und wie machen *Sie* das? <a href=\"https:\/\/berg-software.com\/de\/kontakt-berg-software\/\">M\u00f6chten Sie Ihre L\u00f6sung mit uns teilen?<\/a><\/p>\n[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; gutter_width=&#8220;3&#8243; admin_label=&#8220;\uff3f&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;4vh||8vh||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.6&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;||||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<h2>\uff3f<\/h2>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; _builder_version=&#8220;3.22&#8243; background_color=&#8220;#eeeeee&#8220; custom_padding=&#8220;50px||50px||false|false&#8220; border_color_top=&#8220;#ff6317&#8243; global_module=&#8220;1642&#8243;][et_pb_row column_structure=&#8220;1_3,1_3,1_3&#8243; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;0px|||||&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_social_media_follow _builder_version=&#8220;4.4.4&#8243; text_orientation=&#8220;left&#8220;][et_pb_social_media_follow_network social_network=&#8220;linkedin&#8220; url=&#8220;https:\/\/www.linkedin.com\/company\/berg-computers-srl\/&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#007bb6&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]linkedin[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;twitter&#8220; url=&#8220;https:\/\/twitter.com\/berg_software&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#00aced&#8220; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]twitter[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;facebook&#8220; url=&#8220;https:\/\/www.facebook.com\/bergCOMPUTERS&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#3b5998&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]facebook[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;instagram&#8220; url=&#8220;https:\/\/www.instagram.com\/berg_software\/&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#ea2c59&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]instagram[\/et_pb_social_media_follow_network][\/et_pb_social_media_follow][\/et_pb_column][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_post_nav in_same_term=&#8220;on&#8220; show_next=&#8220;off&#8220; _builder_version=&#8220;4.4.1&#8243; title_text_color=&#8220;#ff6317&#8243; custom_padding=&#8220;|25px|||false|false&#8220;][\/et_pb_post_nav][\/et_pb_column][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_post_nav in_same_term=&#8220;on&#8220; show_prev=&#8220;off&#8220; _builder_version=&#8220;4.4.1&#8243; title_text_color=&#8220;#ff6317&#8243; custom_padding=&#8220;|||25px|false|false&#8220;][\/et_pb_post_nav][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;CONTACT&#8220; _builder_version=&#8220;4.4.1&#8243; background_color=&#8220;#d2d2d2&#8243; custom_padding=&#8220;75px||75px||false|false&#8220; global_module=&#8220;1544&#8243;][et_pb_row column_structure=&#8220;1_4,3_4&#8243; admin_label=&#8220;Service Section Title&#8220; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;||25px||false|false&#8220; animation_direction=&#8220;top&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;1_4&#8243; _builder_version=&#8220;3.25&#8243; custom_padding=&#8220;|||&#8220; custom_padding__hover=&#8220;|||&#8220;][\/et_pb_column][et_pb_column type=&#8220;3_4&#8243; _builder_version=&#8220;3.25&#8243; custom_padding=&#8220;|||&#8220; custom_padding__hover=&#8220;|||&#8220;][et_pb_text _builder_version=&#8220;4.4.1&#8243; text_font=&#8220;|300|||||||&#8220; text_text_color=&#8220;#ffffff&#8220; text_line_height=&#8220;1.1em&#8220; header_5_font=&#8220;|600|||||||&#8220; header_5_text_color=&#8220;#ffffff&#8220; header_5_font_size=&#8220;14px&#8220; header_5_line_height=&#8220;1.5em&#8220; custom_margin=&#8220;||||false|false&#8220;]29 Jahre im Gesch\u00e4ft | 2700 Software-Projekte | 760 Kunden | 24 L\u00e4nder<\/p>\n<h5>Wir verwandeln Ideen in Software. Wie lautet Ihre Idee?<\/h5>[\/et_pb_text][et_pb_text admin_label=&#8220;Title&#8220; _builder_version=&#8220;4.4.6&#8243; header_text_align=&#8220;center&#8220; header_2_font=&#8220;|300|||||||&#8220; header_2_text_align=&#8220;left&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;50px&#8220; header_2_line_height=&#8220;0.9em&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;25px||25px||false|false&#8220;]<h2 id=\"Getintouch\">Kontakt aufnehmen<\/h2>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row column_structure=&#8220;1_4,3_4&#8243; _builder_version=&#8220;4.4.4&#8243;][et_pb_column type=&#8220;1_4&#8243; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_column][et_pb_column type=&#8220;3_4&#8243; _builder_version=&#8220;4.4.4&#8243;][et_pb_contact_form email=&#8220;contact@bergsoftprod.wpengine.com&#8220; custom_message=&#8220;WEBFORM MESSAGE||et_pb_line_break_holder||\uff3f||et_pb_line_break_holder||FROM: %%Name%%||et_pb_line_break_holder||EMAIL: %%Email%%||et_pb_line_break_holder||PHONE NUMBER: %%Phone_number%%||et_pb_line_break_holder||COMPANY: %%Company_name%%||et_pb_line_break_holder||TERMS &amp; CONDITIONS: %%Terms_and_Conditions%%||et_pb_line_break_holder||DATA PRIVACY POLICY: %%Data_Privacy_Policy%%||et_pb_line_break_holder||\uff3f||et_pb_line_break_holder||MESSAGE:||et_pb_line_break_holder||%%Message%%&#8220; success_message=&#8220;Thank you for reaching out! Your message was sent. We will get back to you right away.&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_text_color=&#8220;#ffffff&#8220; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; title_level=&#8220;h2&#8243; title_font=&#8220;|300|||||||&#8220; title_text_color=&#8220;#ff6317&#8243; title_font_size=&#8220;30px&#8220; form_field_line_height=&#8220;1.5em&#8220; custom_button=&#8220;on&#8220; button_text_size=&#8220;14px&#8220; button_text_color=&#8220;#ffffff&#8220; button_bg_color=&#8220;#ff6317&#8243; button_border_width=&#8220;0px&#8220; button_border_radius=&#8220;0px&#8220; button_icon=&#8220;%%3%%&#8220; button_on_hover=&#8220;off&#8220; border_color_all=&#8220;#ffffff&#8220; border_width_bottom=&#8220;1px&#8220;][et_pb_contact_field field_id=&#8220;Name&#8220; field_title=&#8220;Name *&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_text_color=&#8220;#ffffff&#8220; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; border_width_bottom=&#8220;1px&#8220; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Email&#8220; field_title=&#8220;E-Mail-Adresse *&#8220; field_type=&#8220;email&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Phone_number&#8220; field_title=&#8220;Telefonnummer&#8220; required_mark=&#8220;off&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Company_name&#8220; field_title=&#8220;Name des Unternehmens&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Message&#8220; field_title=&#8220;Nachricht *&#8220; field_type=&#8220;text&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; border_width_bottom=&#8220;1px&#8220; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Terms_and_Conditions&#8220; field_title=&#8220; &#8220; field_type=&#8220;checkbox&#8220; checkbox_options=&#8220;%91{%22value%22:%22Ich habe die AGB gelesen und akzeptiert%22,%22checked%22:0,%22dragID%22:-1}%93&#8243; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Data_Privacy_Policy&#8220; field_title=&#8220; &#8220; field_type=&#8220;checkbox&#8220; checkbox_options=&#8220;%91{%22value%22:%22Ich habe die Datenschutzrichtlinie gelesen und akzeptiert%22,%22checked%22:0,%22dragID%22:-1}%93&#8243; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][\/et_pb_contact_form][\/et_pb_column][\/et_pb_row][\/et_pb_section]\n\n","protected":false},"excerpt":{"rendered":"<p>H\u00e4ufig wechselnde IPs sind eine Herausforderung f\u00fcr die Remote-Arbeit von Softwareentwicklern? Wir haben eine einfache, ma\u00dfgeschneiderte L\u00f6sung mit Python, Terraform und GitLab.<\/p>\n","protected":false},"author":16,"featured_media":7167,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[79,141],"tags":[],"class_list":["post-7227","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-einblicke","category-how-to-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v16.1.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>DynamicIP Remote Access \/ Fernzugriff mit Python, Terraform, GitLab | Berg Software<\/title>\n<meta name=\"description\" content=\"H\u00e4ufig wechselnde IPs sind eine Herausforderung f\u00fcr die Remote-Arbeit von Softwareentwicklern? Wir haben eine einfache, ma\u00dfgeschneiderte L\u00f6sung mit Python, Terraform und GitLab.\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DynamicIP Remote Access \/ Fernzugriff mit Python, Terraform, GitLab | Berg Software\" \/>\n<meta property=\"og:description\" content=\"H\u00e4ufig wechselnde IPs sind eine Herausforderung f\u00fcr die Remote-Arbeit von Softwareentwicklern? Wir haben eine einfache, ma\u00dfgeschneiderte L\u00f6sung mit Python, Terraform und GitLab.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\" \/>\n<meta property=\"og:site_name\" content=\"Berg Software\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/bergCOMPUTERS\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-04-06T19:47:35+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-04-06T19:47:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.berg-software.com\/wp-content\/uploads\/DynamicIP-custom-made-solution-with-Python-Terraform-GitLab-1200x600px.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@berg_software\" \/>\n<meta name=\"twitter:site\" content=\"@berg_software\" \/>\n<meta name=\"twitter:label1\" content=\"Gesch\u00e4tzte Lesezeit\">\n\t<meta name=\"twitter:data1\" content=\"21 Minuten\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\",\"name\":\"Berg Software\",\"url\":\"https:\/\/www.berg-software.com\/en\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/bergCOMPUTERS\/\",\"https:\/\/www.instagram.com\/berg_software\/\",\"https:\/\/www.linkedin.com\/company\/berg-computers-srl\/\",\"https:\/\/www.youtube.com\/channel\/UCw1FfcRJnC-CoKPwlcM10Iw\",\"https:\/\/twitter.com\/berg_software\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#logo\",\"inLanguage\":\"de-DE\",\"url\":\"https:\/\/berg-software.com\/wp-content\/uploads\/berg-software-logo.png\",\"contentUrl\":\"https:\/\/berg-software.com\/wp-content\/uploads\/berg-software-logo.png\",\"width\":512,\"height\":512,\"caption\":\"Berg Software\"},\"image\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#website\",\"url\":\"https:\/\/www.berg-software.com\/en\/\",\"name\":\"Berg Software\",\"description\":\"We turn ideas into software.\",\"publisher\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/www.berg-software.com\/en\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de-DE\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#primaryimage\",\"inLanguage\":\"de-DE\",\"url\":\"https:\/\/www.berg-software.com\/wp-content\/uploads\/DynamicIP-custom-made-solution-with-Python-Terraform-GitLab-1200x600px.jpg\",\"contentUrl\":\"https:\/\/www.berg-software.com\/wp-content\/uploads\/DynamicIP-custom-made-solution-with-Python-Terraform-GitLab-1200x600px.jpg\",\"width\":1200,\"height\":600,\"caption\":\"DynamicIP custom-made solution with Python Terraform GitLab\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#webpage\",\"url\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\",\"name\":\"DynamicIP Remote Access \/ Fernzugriff mit Python, Terraform, GitLab | Berg Software\",\"isPartOf\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#primaryimage\"},\"datePublished\":\"2021-04-06T19:47:35+00:00\",\"dateModified\":\"2021-04-06T19:47:44+00:00\",\"description\":\"H\\u00e4ufig wechselnde IPs sind eine Herausforderung f\\u00fcr die Remote-Arbeit von Softwareentwicklern? Wir haben eine einfache, ma\\u00dfgeschneiderte L\\u00f6sung mit Python, Terraform und GitLab.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#breadcrumb\"},\"inLanguage\":\"de-DE\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/category\/einblicke\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/category\/einblicke\/\",\"name\":\"Einblicke\"}},{\"@type\":\"ListItem\",\"position\":3,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/\",\"name\":\"DynamicIP Remote Access \/ Fernzugriff f\\u00fcr Softwareentwickler mit ma\\u00dfgeschneiderter L\\u00f6sung (Python +Terraform +GitLab)\"}}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#webpage\"},\"author\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#\/schema\/person\/89bdf6c90f75385d3302334f6171ccd8\"},\"headline\":\"DynamicIP Remote Access \/ Fernzugriff f\\u00fcr Softwareentwickler mit ma\\u00dfgeschneiderter L\\u00f6sung (Python +Terraform +GitLab)\",\"datePublished\":\"2021-04-06T19:47:35+00:00\",\"dateModified\":\"2021-04-06T19:47:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#webpage\"},\"publisher\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/dynamicip-remote-access-fernzugriff-fuer-softwareentwickler-mit-massgeschneiderter-loesung-python-terraform-gitlab\/#primaryimage\"},\"articleSection\":\"Einblicke,How to\",\"inLanguage\":\"de-DE\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#\/schema\/person\/89bdf6c90f75385d3302334f6171ccd8\",\"name\":\"Eugen Fleseriu\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts\/7227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/comments?post=7227"}],"version-history":[{"count":0,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts\/7227\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/media\/7167"}],"wp:attachment":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/media?parent=7227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/categories?post=7227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/tags?post=7227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}