Welche Interfaces werden von 127.0.0.1 outgoing verwendet?

kali-hi

Lieutenant
Registriert
Sep. 2025
Beiträge
699
Diese Frage erscheint wahrscheinlich ein bisschen doof, aber welches Interface wird vom Host / von localhost genutzt?


Hintergrund ist folgender:

  • MySQL im Docker installiert, mit Port 3306
  • dieser Port soll nicht von außerhalb erreichbar sein, aber von localhost schon

Mir fallen nur zwei Lösungswege ein:

  • a) den Port localhost:3306:3306 im Service binden
  • oder b) das Docker host network nutzen

b) erscheint mir nicht sinnvoll (das würde das bridge network übergehen).


Es muss doch eine Möglichkeit geben, um vom Host / von localhost auf das Docker bridge network, port 3306 zuzugreifen (ohne a oder b).

"nc -zv localhost 3306" geht nicht ...
"nc -zv servicename 3306" geht nicht ...
"nc -zv 0.0.0.0 3306" ganz böse ...

"iptables" sagt Folgendes:

Code:
# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.18.0.0/16        anywhere
MASQUERADE  all  --  172.17.0.0/16        anywhere

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere
DNAT       tcp usw...

172.17.0.0/16 oder 172.18.0.0/16 kann also vom Docker bridge network genutzt werden.


Hat jemand eine Idee, also eine Möglichkeit c)?
 
127.0.0.1 verlässt das Interface nicht.

localhost - Welcher? Innerhalb von docker, auf dem Host?

kali-hi schrieb:
  • dieser Port soll nicht von außerhalb erreichbar sein, aber von localhost schon

Geht es um Enterprise Security oder Port Konflikte oder nur um Sicherheit?


kali-hi schrieb:
nc -zv servicename 3306" geht nicht ..

Von wo wird das ausgeführt? Gleicher, andere Docker?


Pauschal: Entweder machst du ein eigenes Docker Netz oder published die Ports und gehst dann gegen die "echte" IP vom Host.

Der Host hat sicherlich einen Firewall und bei mariadb/etc kannst du auch hinterlegen welche IP zugreifen darf.
 
  • Gefällt mir
Reaktionen: kali-hi, GTrash81 und KillerCow
JumpingCat schrieb:
Der Host hat sicherlich einen Firewall
Vorsicht bei Docker und Firewalls. Docker leitet die Pakete ins Dockernetzwerk, bevor der Host z.B. mit IPTables eingreifen kann! Sowas in der Richtung steht zumindest in der Doku beim bridged network, wenn ich das richtig in Erinnerung habe.
Ergänzung ()

Ein Container mit network=host nutzt denselben Namespace wie der Host. Dann klappt auch nen connect vom Host gegen localhost.
Im bridged network musst du die Container-IP im docker netzwerk kennen (doofe lösung) oder via --publish die gewünschten Ports des Containers an Hostports binden. Vermutlich klappt es dann auch mit localhost vom Host und mit jeder anderen IP des Hosts.
 
  • Gefällt mir
Reaktionen: kali-hi und JumpingCat
JumpingCat schrieb:
Von wo wird das ausgeführt? Gleicher, andere Docker?
Vom Host.
Ergänzung ()

KillerCow schrieb:
Im bridged network musst du die Container-IP im docker netzwerk kennen (doofe lösung)
Genau das ist das Problem. Ich möchte einen Service vom Host aus über seinen Servicenamen, nicht ip kontaktieren.
Ergänzung ()

JumpingCat schrieb:
Der Host hat sicherlich einen Firewall und bei mariadb/etc kannst du auch hinterlegen welche IP zugreifen darf.
Hat er. Die Frage ist, wie diese Regel lautet?

Würde
"sudo ufw route allow proto tcp from 127.0.0.1 to 172.16.0.0/12 port 3306"
Sinn ergeben?

Ich traue mich noch nicht, den Befehl abzusetzen...
Ergänzung ()

JumpingCat schrieb:
Von wo wird das ausgeführt? Gleicher, andere Docker?
Die Crux ist ja auch... von einem anderen Container aus, ist das erlaubt (da beide im bridged).
Ergänzung ()

KillerCow schrieb:
Docker leitet die Pakete ins Dockernetzwerk, bevor der Host z.B. mit IPTables eingreifen kann!
Verstehe ich nicht richtig... Dachte, Docker nutzt die Forward-Chain?
 
Zuletzt bearbeitet:
kali-hi schrieb:
Die Crux ist ja auch... von einem anderen Container aus, ist das erlaubt (da beide im bridged).
Dein Problem wird hier nicht das „dürfen“ sein, sondern dass dein host den servicenamen nicht per DNS auflösen kann. Weil über die interne Docker in deines Containers kommst du ja ran, du müsstest nur dynamisch einen Eintrag in deinem Hosts file setzen. Was anderes wird in Containern innerhalb des Docker Netzwerkes meines Wissens nach auch nicht getan.
 
  • Gefällt mir
Reaktionen: JumpingCat und kali-hi
Workaround ist in Docker einen DNS laufen zu laufen lassen weil der auch an den docker internen namespace drankommt. Wie z.B. https://theorangeone.net/posts/expose-docker-internal-dns/ . Ist halt etwas Gefrickel und allgemein keine gute Idee. Ausserdem klappt das auch nur bei 1 Host.

Du könntest aber einen Loadbalancer wie z.B. haproxy nehmen und die Ports pro Container verschieden setzen.
 
  • Gefällt mir
Reaktionen: kali-hi
Ich danke euch beiden! @NJay hat recht, Problem ist hier die Namensauflösung:

User-defined bridges provide automatic DNS resolution between containers.

https://docs.docker.com/engine/netw...n-user-defined-bridges-and-the-default-bridge

(Also extra noch einmal erwähnt, NUR zwischen Containern, nicht beim Host)

Port mapping ensures that published ports are accessible on the host's network addresses, which are likely to be routable for any external clients. No routes are normally set up in the host's network for container addresses that exist within a host.

But, particularly with IPv6 you may prefer to avoid using NAT and instead arrange for external routing to container addresses ("direct routing").

To access containers on a bridge network from outside the Docker host, you must first set up routing to the bridge network via an address on the Docker host. This can be achieved ...

https://docs.docker.com/engine/network/packet-filtering-firewalls/#direct-routing

(Und hier auch noch mal: Normalerweise werden im Netzwerk des Hosts keine Routen für Containeradressen eingerichtet, die innerhalb eines Hosts existieren.)

Desweiteren:

(ufw) is a frontend that ships with Debian and Ubuntu, and it lets you manage firewall rules. Docker and ufw use iptables in ways that make them incompatible with each other.

When you publish a container's ports using Docker, traffic to and from that container gets diverted before it goes through the ufw firewall settings. Docker routes container traffic in the nat table, which means that packets are diverted before it reaches the INPUT and OUTPUT chains that ufw uses. Packets are routed before the firewall rules can be applied, effectively ignoring your firewall configuration.

https://docs.docker.com/engine/network/packet-filtering-firewalls/#docker-and-ufw

(Ich denke, so etwas Ähnliches meinte @KillerCow ... Docker und ufw sind nur schwer miteinander vereinbar. (Möglicherweise ist aber auch die Docker Doc an dieser Stelle outdated?))

Was ich zurzeit mache, ist im Prinzip hier beschrieben: https://github.com/chaifeng/ufw-docker?tab=readme-ov-file#solving-ufw-and-docker-issues

(Also zum Beispiel: "ufw route allow proto tcp from any to any port 80" ...)

Jetzt zurück zum Thema ... Das Problem ist dabei aber immer noch, dass der Zugriff zwar theoretisch möglich ist, die Namensauflösung jedoch nicht.

JumpingCat schrieb:
Workaround ist in Docker einen DNS laufen zu laufen lassen weil der auch an den docker internen namespace drankommt.
Nein, das ist mir doch zu umständlich ... Ich nutze jetzt "-p localhost:3306:3306" und einen (selbst geschriebenen) Host-Microservice, der sich mit "jdbc:mariadb://localhost:3306/..." anstatt "jdbc:mariadb://mariadb:3306/..." verbindet.
 
Aber ich finde es... dumm, dass die Kinder zwar untereinander sprechen dürfen, bzw. sich sehen können, der Host seine Kinder jedoch nicht (einfach) kontaktieren kann. Unterläuft das nicht das Sicherheitskonzept?
 
kali-hi schrieb:
Unterläuft das nicht das Sicherheitskonzept?
Er kann sie ja einfach kontaktieren, es ist ja eben keine Firewall Regel gesetzt. Welches Sicherheitskontrolle sollte das unterlaufen, wenn nur kein DNS-Eintrag gesetzt ist?

Du kannst das ja auch einfach umgehen in dem du dem Container sagt, welche IPs er im docker Netzwerk er bekommen soll oder eben in dem du den Port an localhost bindest, dann weißt du ja wie du ihn erreichst.

Normalerweise sollen ja alle Anwendung containerized sein und nur der userfacing Teil wird nach außen gegeben.
 
  • Gefällt mir
Reaktionen: kali-hi
NJay schrieb:
Normalerweise sollen ja alle Anwendung containerized sein und nur der userfacing Teil wird nach außen gegeben.
Jein... Zum einen stimmt das, aber zum anderen geht es nur um einen kleinen Microservice, den ich alle 3 Stunden ausführen möchte, und der je einen kleinen Eintrag in der DB erstellen soll. Ich dachte, das könnte der Host gut erledigen... und müsste anderenfalls einen eigenen Container dafür erstellen.

Hm, gibt es den Crontab als Docker Image? Oder, andere Frage, kann man docker compose services periodisch ausführen? Was ist da der beste Weg?
 
Du verweist in der crontab ( oder neuerdings systemd-Timer ) auf ein bash-Skript. Dort wird dann ein docker exec... oder docker run reinpacken.

Oder willst du wieder einen weiteren Container dafür haben? Gibt sogar welche mit GUI wie z.B. https://cronicle.net/
 
kali-hi schrieb:
den ich alle 3 Stunden ausführen möchte, und der je einen kleinen Eintrag in der DB erstellen soll. Ich dachte, das könnte der Host gut erledigen...
Kannst du ja. Binde die DB einfach an einen Port auf localhost. Was spricht dagegen?

Alternativ einfach einen Docker Container ins gleiche Docker-compose der einfach dauerhaft läuft aber in sich per cron den Job ausführt.
 
  • Gefällt mir
Reaktionen: kali-hi
Wir sind ja hier in Programmieren...

Bash:
    command:
      - bash
      - -c
      - |
        set -e
        cd /dir1/
        sleep_interval=$((60*120)) # every 2 hours
        sleep_offset=$((60*30))
        while true; do
          seconds=$(date +%s)
          sleep_until=$(((seconds/sleep_interval+1)*sleep_interval+sleep_offset))
          sleep_until_time=$(date --date @${sleep_until})
          echo "Sleep until $sleep_until_time ..."
          sleep $((sleep_until-seconds))
          echo "Start the job ..."
          #...
        done

Weiß jemand, wie ich das @-Zeichen in dieser Yaml Docker Compose Service Command Definition quoten muss?

Der Job soll alle zwei Stunden, jeweils um Halb, ausgeführt werden.

Aus der offiziellen Yaml-Doc werde ich nicht schlau: https://yaml.org/spec/1.2.2/#:~:text=Example 5.9-,Directive Indicator,-%

Wenn ich das starte, kommt immer die Fehlermeldung: "date: invalid date `@'"

Ich kann das nicht nachvollziehen, alternativ würde ich die Ausgabe ganz weglassen... aber mit wäre natürlich schöner.
Ergänzung ()

Gelöst 😅

Ich war auf der falschen Fährte...

Jedes $-Char muss noch einmal maskiert werden: $$

Bash:
    command:
      - bash
      - -c
      - |
        set -e
        cd /dir1/
        sleep_interval=$$((60*120)) # every 2 hours
        sleep_offset=$$((60*30))
        while true; do
          seconds=$$(date +%s)
          sleep_until=$$(((seconds/sleep_interval+1)*sleep_interval+sleep_offset))
          echo "Sleep until $$(date --date @$$sleep_until) ..."
          sleep $$((sleep_until-seconds))
          echo "Start the job ..."
          #...
        done

https://stackoverflow.com/a/76711938

Jetzt funktioniert es zu 100 %, wie ein Schweizer Uhrwerk.

(Das Offset muss jedoch immer kleiner als das Intervall gewählt werden, aber das ist klar.)
 
Zuletzt bearbeitet:
Zurück
Oben