{"id":4194,"date":"2025-09-29T07:00:00","date_gmt":"2025-09-29T05:00:00","guid":{"rendered":"https:\/\/www.my-it-brain.de\/wordpress\/?p=4194"},"modified":"2025-09-10T09:49:26","modified_gmt":"2025-09-10T07:49:26","slug":"wenn-ansible-builtin-ping-kein-pong-zurueckgibt","status":"publish","type":"post","link":"https:\/\/www.my-it-brain.de\/wordpress\/wenn-ansible-builtin-ping-kein-pong-zurueckgibt\/","title":{"rendered":"Wenn ansible.builtin.ping kein pong zur\u00fcckgibt,\u2026"},"content":{"rendered":"\n<p>\u2026dann k\u00f6nnen keine Ansible-Playbooks auf dem Zielsystem ausgef\u00fchrt werden, Sysadmins lassen vom Schreiben der Playbooks ab und wenden sich der Fehleranalyse zu. Genau das mache ich n\u00e4mlich gerade.<\/p>\n\n\n\n<p>Und damit ihr auch etwas davon habt, halte ich das Ganze in diesen Beitrag fest. Die Gr\u00fcnde daf\u00fcr sind vielf\u00e4ltig:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unerfahrene Sysadmins k\u00f6nnen lernen, wie man bei einer Fehleranalyse vorgehen kann, um nach endlich vielen Schritten zu einem Ergebnis zu kommen<\/li>\n\n\n\n<li>Falls ich meine Arbeit unterbrechen muss, kann ich mich mithilfe dieses Textes besser erinnern, was ich schon getestet habe und meine Arbeit fortsetzen<\/li>\n\n\n\n<li>Falls ich Expertenrat einholen muss, kann ich zeigen, was ich schon alles versucht habe<\/li>\n<\/ul>\n\n\n\n<p>Die erfahrenen Supporter und Sysadmins unter euch sind gerne eingeladen, in den Kommentaren zu erg\u00e4nzen, wie ihr bei so einem Problem vorgeht und was ich h\u00e4tte besser machen k\u00f6nnen. So lernen wir alle etwas dabei.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"methode\">Die Methode<\/h2>\n\n\n\n<p>Bei einer Fehleranalyse stochert man nicht einfach im Heuhaufen herum, in der Hoffnung eine Nadel zu finden. Ich gehe w\u00e4hrend der Fehleranalyse in folgender Schleife (Pseudocode) vor:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Solange das Problem besteht:\n  Sichte und bewerte die vorhandenen Informationen;\n  Forumuliere eine Hypothese zur Ursache des Problems;\n  \u00dcberpr\u00fcfe die Hypothese;\n  Hast du damit das Problem gefunden, stelle es ab und h\u00f6re auf;\n  Hast du das Problem damit noch nicht gefunden, nimm die gewonnenen Erkenntnisse und iteriere;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"problem\">Das Problem<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ansible -i hosts host.example.com -m ping\nhost.example.com | FAILED! =&gt; {\n    \"ansible_facts\": {\n        \"discovered_interpreter_python\": \"\/usr\/bin\/python3.9\"\n    },\n    \"changed\": false,\n    \"module_stderr\": \"Shared connection to host.example.com closed.\\r\\n\",\n    \"module_stdout\": \"\/usr\/bin\/python3.9: can't open file '\/home\/tronde\/.ansible\/tmp\/ansible-tmp-1757269581.9965136-5304-74956742819711\/AnsiballZ_ping.py': &#91;Errno 1] Operation not permitted\\r\\n\",\n    \"msg\": \"MODULE FAILURE: No start of json char found\\nSee stdout\/stderr for the exact error\",\n    \"rc\": 2\n}<\/code><\/pre>\n\n\n\n<p>Der obige Code-Block zeigt das fehlgeschlagene Ansible-Ad-hoc-Kommando. Das Kommando f\u00fchrt das Module <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/collections\/ansible\/builtin\/ping_module.html\">ansible.builtin.ping<\/a> aus, welches pr\u00fcft, ob eine Verbindung zum Zielsystem hergestellt werden kann und eine nutzbare Python-Umgebung gefunden wird. Wenn dies erfolgreich ist, sieht die Ausgabe wie im folgenden Code-Block aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ansible -i hosts host2.example.com -m ping\nhost2.example.com | SUCCESS =&gt; {\n    \"ansible_facts\": {\n        \"discovered_interpreter_python\": \"\/usr\/bin\/python3.9\"\n    },\n    \"changed\": false,\n    \"ping\": \"pong\"\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ausgangslage\">Die Ausgangslage<\/h2>\n\n\n\n<p>Bevor ich mit der Fehleranalyse beginne, schreibe ich auf, was ich \u00fcber meinen Ansible Control Node und meine beiden Managed Nodes wei\u00df.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ansible Control Node<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Fedora release 42 (Adams)<\/li>\n\n\n\n<li>ansible [core 2.18.6]\n<ul class=\"wp-block-list\">\n<li>config file = \/etc\/ansible\/ansible.cfg<\/li>\n\n\n\n<li>ansible python module location = \/usr\/lib\/python3.13\/site-packages\/ansible<\/li>\n\n\n\n<li>executable location = \/usr\/bin\/ansible<\/li>\n\n\n\n<li>python version = 3.13.7 (main, Aug 14 2025, 00:00:00) <a href=\"\/usr\/bin\/python3\">GCC 15.2.1 20250808 (Red Hat 15.2.1-1)<\/a><\/li>\n\n\n\n<li>jinja version = 3.1.6<\/li>\n\n\n\n<li>libyaml = True<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Ansible Managed Nodes<\/h3>\n\n\n\n<p>\u00dcber <code>host.example.com<\/code> und <code>host2.example.com<\/code> ist bekannt, dass es:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>sich um Red Hat Enterprise Linux release 9.6 (Plow) handelt<\/li>\n\n\n\n<li>Ich mich mit dem User <code>tronde<\/code> und SSH-Private-Key einloggen kann\n<ul class=\"wp-block-list\">\n<li>Bei <code>tronde<\/code> handelt es sich um einen unprivilegierten Benutzer<\/li>\n\n\n\n<li>Dieser darf <code>sudo<\/code> nutzen, um seine Rechte auszuweiten; dazu muss ein Passwort eingegeben werden<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>SELinux auf <code>Enforcing<\/code> steht<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Die Fehlermeldung<\/h3>\n\n\n\n<p>Und ich habe nat\u00fcrlich eine Fehlermeldung:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"module_stdout\": \"\/usr\/bin\/python3.9: can't open file '\/home\/tronde\/.ansible\/tmp\/ansible-tmp-1757269581.9965136-5304-74956742819711\/AnsiballZ_ping.py': &#91;Errno 1] Operation not permitted\\r\\n\",<\/code><\/pre>\n\n\n\n<p>Python meldet, dass die Ausf\u00fchrung von <code>AnsiballZ_ping.py<\/code> nicht zugelassen ist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-1\">Hypothese 1: Es liegt nicht an AnsiballZ_ping.py<\/h2>\n\n\n\n<p>Wenn dieses Python-Skript nicht ausgef\u00fchrt werden kann, kann ein anderes Python-Skript ebenfalls nicht ausgef\u00fchrt weden. Um diese Hypothese zur \u00fcberpr\u00fcfen, versuche ich, die UID des Benutzers mit dem Modul <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/collections\/ansible\/builtin\/command_module.html\">ansible.builtin.command<\/a> abzufragen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ansible -i hosts host.example.com -m command -a 'id'\nhost.example.com | FAILED! =&gt; {\n    \"ansible_facts\": {\n        \"discovered_interpreter_python\": \"\/usr\/bin\/python3.9\"\n    },\n    \"changed\": false,\n    \"module_stderr\": \"Shared connection to host.example.com closed.\\r\\n\",\n    \"module_stdout\": \"\/usr\/bin\/python3.9: can't open file '\/home\/tronde\/.ansible\/tmp\/ansible-tmp-1757271016.543905-6189-111082369101490\/AnsiballZ_command.py': &#91;Errno 1] Operation not permitted\\r\\n\",\n    \"msg\": \"MODULE FAILURE: No start of json char found\\nSee stdout\/stderr for the exact error\",\n    \"rc\": 2\n}<\/code><\/pre>\n\n\n\n<p>Damit ist bewiesen, dass die Fehlerursache nicht allein im Skript <code>AnsiballZ_ping.py<\/code> liegt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-2\">Hypothese 2: Es ist ein Problem mit Berechtigungen<\/h2>\n\n\n\n<p>Die Meldung <code>[Errno 1] Operation not permitted<\/code> deutet an, dass fehlende Berechtigungen die Ursache sein k\u00f6nnen. Also f\u00fchre ich das Kommando auf dem betroffenen Managed Node einmal als <code>root<\/code> aus.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ansible -i hosts host.example.com -m ping -b -K\nBECOME password: \nhost.example.com | SUCCESS =&gt; {\n    \"ansible_facts\": {\n        \"discovered_interpreter_python\": \"\/usr\/bin\/python3.9\"\n    },\n    \"changed\": false,\n    \"ping\": \"pong\"\n}<\/code><\/pre>\n\n\n\n<p>Root darf also, was <code>tronde<\/code> nicht darf, denn mit erweiterten Berechtigungen kann das Kommando erfolgreich ausgef\u00fchrt werden. Die Python-Skripte, die <code>tronde<\/code> nicht ausf\u00fchren darf, liegen im Pfad <code>\/home\/tronde\/.ansible\/tmp\/&lt;von-Ansible-tempor\u00e4r-erstelltes-Verzeichnis>\/AnsiballZ_{command,ping}.py<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-3\">Hypothese 3: tronde darf keine Python-Skripte ausf\u00fchren<\/h2>\n\n\n\n<p>Genauer gesagt, <code>tronde<\/code> darf keine Python-Skripte ausf\u00fchren, welche unterhalb von <code>\/home\/tronde\/.ansible\/tmp\/<\/code> abgelegt sind. Auch diese These wird direkt gepr\u00fcft. Dazu logge ich mich per SSH als User <code>tronde<\/code> auf dem Zielsystem ein, erstelle ein einfaches Python-Skript und versuche dieses auszuf\u00fchren:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ mkdir \/home\/tronde\/.ansible\/tmp\/test\n$ cat &lt;&lt; EOF &gt; \/home\/tronde\/.ansible\/tmp\/test\/hello.py\n&gt; #!\/usr\/bin\/env python3.9\n&gt; print(\"Hello World\")\n&gt; EOF\n$ chmod u+x \/home\/tronde\/.ansible\/tmp\/test\/hello.py\n$ \/usr\/bin\/python3.9 \/home\/tronde\/.ansible\/tmp\/test\/hello.py\n\/usr\/bin\/python3.9: can't open file '\/home\/tronde\/.ansible\/tmp\/test\/hello.py': &#91;Errno 1] Operation not permitted<\/code><\/pre>\n\n\n\n<p>Durch diesen Test habe die Hypothese verifiziert und zus\u00e4tzlich folgendes gelernt: Meine Ansible-Konfiguration auf meinem Ansible Control Node hat nichts mit dem Problem zu tun, da das Problem auftritt, wenn Ansible gar nicht beteiligt ist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-4\">Hypothese 4: Falsche Datei-Berechigungen verhindern die Ausf\u00fchrung der Datei<\/h2>\n\n\n\n<p>Ich schaue mir die Datei-Berechtigungen bis zur Datei <code>hello.py<\/code> mit dem Programm <code>namei(1)<\/code> an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ namei -mo \/home\/tronde\/.ansible\/tmp\/test\/hello.py\nf: \/home\/tronde\/.ansible\/tmp\/test\/hello.py\n dr-xr-xr-x root      root      \/\n drwxr-xr-x root      root      home\n drwxr-x--- tronde tronde tronde\n drwxrwxr-x tronde tronde .ansible\n drwx------ tronde tronde tmp\n drwxr-xr-x tronde tronde test\n -rwxr--r-- tronde tronde hello.py<\/code><\/pre>\n\n\n\n<p>Das sieht auf den ersten Blick nicht verkehrt aus. Ich wechsel in das Verzeichnis und lasse mir die Attribute der Datei mit verschiedenen Programmen anzeigen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd .ansible\/tmp\/test\/\n$ stat hello.py\n  File: hello.py\n  Size: 46        \tBlocks: 8          IO Block: 4096   regular file\nDevice: fd06h\/64774d\tInode: 51511298    Links: 1\nAccess: (0744\/-rwxr--r--)  Uid: ( 1000\/tronde)   Gid: ( 1000\/tronde)\nContext: unconfined_u:object_r:user_home_t:s0\nAccess: 2025-09-07 21:21:08.201875001 +0200\nModify: 2025-09-07 21:23:04.564787755 +0200\nChange: 2025-09-07 21:23:25.642771941 +0200\n Birth: 2025-09-07 21:21:08.201875001 +0200\n\n$ getfacl hello.py\n# file: hello.py\n# owner: tronde\n# group: tronde\nuser::rwx\ngroup::r--\nother::r--\n\n$ file hello.py \nhello.py: writable, executable, regular file, no read permission<\/code><\/pre>\n\n\n\n<p>Datei-Berechtigungen und Linux-ACL bescheinigen dem User <code>tronde<\/code> Lesezugriff auf die Datei <code>hello.py<\/code>. Das <code>file<\/code>-Kommando bescheinigt jedoch <code>no read permission<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-5\">Hypothese 5: Das chmod u+x verursacht das Problem<\/h2>\n\n\n\n<p>Nach der Erstellung des Skripts habe ich dieses mit <code>chmod u+x<\/code> ausf\u00fchrbar gemacht. Vielleicht verursacht erst dieser Befehl das Problem. Also schaue ich mir die Informationen zum Dateityp vor und nach dem Kommando an. Dazu erstelle ich ein neues Skript.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cat &lt;&lt;EOF &gt;hello2.py\n&gt; #!\/usr\/bin\/env python3.9\n&gt; print(\"Hello Sysadmin.\")\n&gt; EOF\n$ file hello2.py \nhello2.py: writable, regular file, no read permission<\/code><\/pre>\n\n\n\n<p>Damit kann ich <code>chmod<\/code> ebenfalls als Fehlerquelle ausschlie\u00dfen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-6\">Hypothese 6: Shebang verursacht das Problem<\/h2>\n\n\n\n<p>Die <a href=\"https:\/\/de.wikipedia.org\/wiki\/Shebang\">Shebang<\/a> <code>#!<\/code> sorgt daf\u00fcr, dass das folgende Kommando mit dem Dateinamen als Argument ausgef\u00fchrt wird. Gleichzeitig gibt die <code>Shebang<\/code> auch dem Programm <code>file<\/code> einen Hinweis darauf, um welchen Dateityp es sich handelt.<\/p>\n\n\n\n<p>Zur \u00dcberpr\u00fcfung dieser Hypothese erhebe ich zuerst die Antworten zu folgenden Fragen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Kann das Skript ohne Shebang ausgef\u00fchrt werden?<\/h3>\n\n\n\n<p>Bei der \u00dcberpr\u00fcfung von Hypothese 2 habe ich verifiziert, dass <code>root<\/code> die Dateien wie gewohnt ausf\u00fchren kann. Nun editiere ich die Datei <code>hello2.py<\/code> mit root-Rechten und entferne die <code>Shebang<\/code>. Anschlie\u00dfend versuche ich als User <code>tronde<\/code>, die Datei mit Hilfe des Python3.9-Interpreters auszuf\u00fchren.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ file hello2.py \nhello2.py: ASCII text\n$ cat hello2.py \nprint(\"Hello Sysadmin.\")\n$ \/usr\/bin\/python3.9 hello2.py \nHello Sysadmin.<\/code><\/pre>\n\n\n\n<p>Ohne Shebang kann ich das Skript ausf\u00fchren. F\u00fcge ich die Shebang wieder ein, ist der Fehler zur\u00fcck. Ich kann die Datei noch nicht mal mehr lesen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cat hello2.py \ncat: hello2.py: Operation not permitted\n\n$ sudo !!\nsudo cat hello2.py \n#!\/usr\/bin\/python3.9\nprint(\"Hello Sysadmin.\")<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Zeigen Bash-Skripte mit Shebang das gleiche Verhalten?<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cat &lt;&lt;EOF &gt;world.sh\n&gt; #!\/usr\/bin\/env bash\n&gt; echo \"Hello world.\"\n&gt; EOF\n\n$ file world.sh \nworld.sh: Bourne-Again shell script, ASCII text executable\n\n$ cat world.sh \n#!\/usr\/bin\/env bash\necho \"Hello world.\"\n\n$ bash world.sh \nHello world.\n\n$ chmod u+x world.sh\n\n$ .\/world.sh \nHello world.<\/code><\/pre>\n\n\n\n<p>Hier ist das Verhalten wie erwartet. Damit ist zwar noch nicht sicher bewiesen, dass das Shebang-Problem mit dem Python-Interpreter zusammenh\u00e4ngt, es gibt aber einen ersten Hinweis.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wie sieht die Ausgabe von <code>file<\/code> auf einem Referenzsystem aus?<\/h3>\n\n\n\n<p>Mit <code>host2<\/code> habe ich ja ein System, das Python-Skripte ohne Fehler ausf\u00fchrt. Ich erstelle auch hier das <code>hello.py<\/code>-Skript inkl. Shebang und lasse mir die Ausgabe von <code>file<\/code> anzeigen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cat &lt;&lt;EOF &gt;hello.py\n&gt; #!\/usr\/bin\/env python3.9\n&gt; print(\"Hello, world.\")\n&gt; EOF\n\n$ file hello.py \nhello.py: Python script, ASCII text executable<\/code><\/pre>\n\n\n\n<p>Hier findet sich kein Hinweis auf <code>no read permission<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hypothese-7\">Hypothese 7: Es ist nur der User tronde betroffen<\/h2>\n\n\n\n<p>Um diese Hypothese zu pr\u00fcfen, erstelle ich einen neuen Benutzer <code>test<\/code>, ein Python-Skript und pr\u00fcfe, ob das Problem auftritt:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># useradd test\n# su - test\n$ pwd\n\/home\/test\n$ cat &lt;&lt;EOF &gt;hello.py\n&gt; #!\/usr\/bin\/env python3\n&gt; print(\"Hello, world.\")\n&gt; EOF\n$ cat hello.py \ncat: hello.py: Operation not permitted<\/code><\/pre>\n\n\n\n<p>Das Problem ist nicht auf den User <code>tronde<\/code> beschr\u00e4nkt. Es scheint alle nicht privilegierten User zu betreffen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"zwischenfazit\">Zwischenfazit<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Das Problem scheint Host-spezifisch zu sein, da es auf einem Referenzsystem nicht auftritt<\/li>\n\n\n\n<li>Das Problem tritt nur auf, wenn nicht privilegierte User ein Python-Skript ausf\u00fchren, welches eine <code>Shebang<\/code> enth\u00e4lt\n<ul class=\"wp-block-list\">\n<li>Diese Skripte k\u00f6nnen jedoch mit root-Rechten ausgef\u00fchrt werden<\/li>\n\n\n\n<li>Ohne die <code>Shebang<\/code> k\u00f6nnen die Skripte mittels <code>\/usr\/bin\/python3 &lt;scriptname&gt;<\/code> ausgef\u00fchrt werden<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Ist eine <code>Shebang<\/code> enthalten, die einen Python-Interpreter enth\u00e4lt, verlieren unprivilegierte User den Lesezugriff auf die Datei (<code>cat<\/code>, <code>less<\/code>, etc. sind dann ebenfalls betroffen)<\/li>\n\n\n\n<li>Trage ich eine andere <code>Shebang<\/code> z.B. <code>#!\/usr\/bin\/bash<\/code> ein, kann ich das Skript als unprivilegierter User mittels `python3 &lt;scriptname&gt;` korrekt ausf\u00fchren<\/li>\n<\/ul>\n\n\n\n<p>F\u00fcr mich bedeutet das leider, dass ich mir nun Hilfe suchen muss, da mir die Ideen ausgehen. Also beginne ich mit einer Internetsuche nach &#8222;troubleshooting shebang in python3&#8243;\u2026 und frage anschlie\u00dfend eine Kollegin um Rat. Vielen lieben Dank Michi f\u00fcr deine Zeit und Ideen!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ursache\">Die Ursache<\/h2>\n\n\n\n<p>Michi und ich haben uns in einer Videokonferenz zusammengefunden und das Problem gemeinsam untersucht. Dabei sind wir nach obigen Muster vorgegangen:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Genau <strong>eine<\/strong> Sache \u00fcberpr\u00fcfen<\/li>\n\n\n\n<li>Ergebnis auswerten<\/li>\n\n\n\n<li><strong>Eine<\/strong> weitere Vermutung pr\u00fcfen<\/li>\n\n\n\n<li>Ergebnis auswerten usw.<\/li>\n<\/ol>\n\n\n\n<p>Dabei haben wir uns SELinux, das Audit-Log, die Linux-ACLs, das Environment, <code>alias<\/code>, <code>locale<\/code> und die Ausgabe diverser <code>strace<\/code>-Kommandos angeschaut. Die Details spare ich an dieser Stelle ein und komme zum Wesentlichen. Michi fand diesen Foreneintrag: <a href=\"https:\/\/forums.rockylinux.org\/t\/non-root-users-unable-to-read-perl-scripts\/7028\/4\">Non-root users unable to read perl scripts<\/a>. Darin wird <code>fapolicyd<\/code> als Fehlerquelle identifiziert. Und das ist tats\u00e4chlich auch in meinem Fall der \u00dcbelt\u00e4ter.<\/p>\n\n\n\n<p>Stoppe ich <code>fapolicyd.service<\/code>, kann ich die Python-Skripte mit <code>Shebang<\/code> wieder ausf\u00fchren. Starte ich den Dienst erneut, ist auch das Problem zur\u00fcck. Die Ursache ist identifiziert.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Moment, was ist fapolicyd?<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Das Software-Framework <strong>fapolicyd<\/strong> steuert die Ausf\u00fchrung von Anwendungen basierend auf einer benutzerdefinierten Richtlinie. Dies ist eine der effizientesten Methoden, um die Ausf\u00fchrung nicht vertrauensw\u00fcrdiger und potenziell b\u00f6sartiger Anwendungen auf dem System zu verhindern.<\/p>\n<cite>\u00dcbersetzung aus <a href=\"https:\/\/docs.redhat.com\/en\/documentation\/red_hat_enterprise_linux\/10\/html\/security_hardening\/blocking-and-allowing-applications-by-using-fapolicyd#introduction-to-fapolicyd\">Introduction to fapolicyd<\/a><\/cite><\/blockquote>\n\n\n\n<p>Die von Ansible generierten und die von mir zum Test erstellten Python-Skripte wurden in der Ausf\u00fchrung blockiert, da diese als nicht vertrauensw\u00fcrdig eingestuft wurden.<\/p>\n\n\n\n<p>Allerdings f\u00e4llt das in diesem Fall in die Kategorie \u201eGut gemeint ist nicht gleich gut gemacht\u201c. Denn w\u00e4hrend zwar der Zugriff auf Python-Skripte mit <code>Shebang<\/code> f\u00fcr nicht-privilegierte User blockiert wird, k\u00f6nnen Skripte ohne entsprechende <code>Shebang<\/code> weiterhin ausgef\u00fchrt werden. Wirkliche Sicherheit bietet dies nicht. Ich mache mir dazu mal eine Notiz, um das beobachtete Verhalten im Nachgang mit den Entwicklern zu diskutieren. Vielleicht habe ich das Design und Konzept von <code>fapolicyd<\/code> noch nicht ganz verstanden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Warum ich da nicht fr\u00fcher drauf gekommen bin<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Keine Ausgabe gab einen Hinweis darauf, dass <code>fapolicyd<\/code> die Ausf\u00fchrung blockiert<\/li>\n\n\n\n<li>Ich habe <code>fapolicyd<\/code> vor langer Zeit zum Test auf diesem Host installiert und vergessen, dass es l\u00e4uft<\/li>\n\n\n\n<li>Durch fehlende Konfiguration gab es keine Eintr\u00e4ge im Audit-Log, die auf die Ursache h\u00e4tten hinweisen k\u00f6nnen<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Wie findet man die Ursache, wenn man wei\u00df, dass <code>fapolicyd<\/code> l\u00e4uft?<\/h3>\n\n\n\n<p>Erstmal muss man wissen bzw. sich in meinem Fall daran erinnern, dass <code>fapolicyd<\/code> l\u00e4uft. Dann kann man f\u00fcr einen schnellen Test <code>fapolicyd.service<\/code> stoppen und pr\u00fcfen, ob das Problem noch besteht.<\/p>\n\n\n\n<p>Um nun herauszufinden, warum <code>fapolicyd<\/code> die Ausf\u00fchrung von Python-Skripten mit <code>Shebang<\/code> blockiert, folge ich der Dokumentation in Kapitel <a href=\"https:\/\/docs.redhat.com\/en\/documentation\/red_hat_enterprise_linux\/9\/html\/security_hardening\/assembly_blocking-and-allowing-applications-using-fapolicyd_security-hardening#ref_troubleshooting-problems-related-to-fapolicyd_assembly_blocking-and-allowing-applications-using-fapolicyd\">12.6.&nbsp;Troubleshooting problems related to fapolicyd<\/a>. Ich stoppe <code>fapolicyd.service<\/code> und starte den Dienst mit dem Befehl <code>fapolicyd --debug-deny<\/code>. Damit werden nur Eintr\u00e4ge ausgegeben, die blockierte Zugriffe zeigen. In diesem Modus f\u00fchre ich den urspr\u00fcnglichen Ansible-Ad-hoc-Befehl <code>ansible -i hosts host.example.com -m ping<\/code> aus, der wie erwartet fehlschl\u00e4gt. In der Ausgabe auf <code>host.example.com<\/code> sehe ich nun:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>09\/08\/2025 20:39:07 &#91; DEBUG ]: Rule number API supported yes                                            \n09\/08\/2025 20:39:08 &#91; DEBUG ]: rule=11 dec=deny_audit perm=open auid=1000 pid=693342 exe=\/usr\/bin\/python3.9 : path=\/home\/tronde\/.ansible\/tmp\/ansible-tmp-1757356747.8650832-23284-14960045792104\/AnsiballZ_ping.py ftype=text\/x-python trust=0\n09\/08\/2025 20:39:08 &#91; DEBUG ]: rule=11 dec=deny_audit perm=open auid=1000 pid=693342 exe=\/usr\/bin\/python3.9 : path=\/home\/tronde\/.ansible\/tmp\/ansible-tmp-1757356747.8650832-23284-14960045792104\/AnsiballZ_ping.py ftype=text\/x-python trust=0<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"loesung\">Die L\u00f6sung<\/h2>\n\n\n\n<p>Damit ich <code>host.example.com<\/code> mit Ansible verwalten kann, muss ich die Ausf\u00fchrung von Python-Skripten unterhalb von <code>\/home\/tronde\/.ansible\/tmp\/<\/code> erlauben. Das dazu erforderliche Vorgehen ist in der Dokumentation in Kapitel <a href=\"https:\/\/docs.redhat.com\/en\/documentation\/red_hat_enterprise_linux\/9\/html-single\/security_hardening\/index#proc_adding-custom-allow-and-deny-rules-for-fapolicyd_assembly_blocking-and-allowing-applications-using-fapolicyd\">12.4.&nbsp;Adding custom allow and deny rules for fapolicyd<\/a> beschrieben. F\u00fcr meinen konkreten Fall sehen die einzelnen Schritte wie folgt aus:<\/p>\n\n\n\n<p>Nach obiger Ausgabe habe ich Regel 11 (<code>rule=11<\/code>) getriggert. Also schaue ich mir zuerst an, was in Regel 11 steht und anschlie\u00dfend, in welcher Datei unterhalb von <code>\/etc\/fapolicyd\/rules.d<\/code> diese Regel steht:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~]# fapolicyd-cli --list | grep 11\n11. deny_audit perm=any all : ftype=%languages\n\n~]# grep 'deny_audit perm=any all : ftype=%languages' \/etc\/fapolicyd\/rules.d\/*\n\/etc\/fapolicyd\/rules.d\/70-trusted-lang.rules:deny_audit perm=any all : ftype=%languages<\/code><\/pre>\n\n\n\n<p>Anschlie\u00dfend erstelle ich eine Allow-Regel, in einer neuen Datei. Diese muss lexikalisch vor obiger Datei mit der Deny-Regel liegen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>~]# cat &lt;&lt;EOF &gt;\/etc\/fapolicyd\/rules.d\/69-trusted-ansible-scripts.rules\n&gt; allow perm=any exe=\/usr\/bin\/python3.9 trust=1 : dir=\/home\/tronde\/.ansible\/tmp\/ trust=0\n&gt; EOF\n\n~]# fagenrules --check\n\/sbin\/fagenrules: Rules have changed and should be updated\n\n~]# fagenrules --load\n~]#<\/code><\/pre>\n\n\n\n<p>Anschlie\u00dfend f\u00fchre ich zum Test folgende Kommandos aus:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Auf <code>host.example.com<\/code>: <code>fapolicy --debug-deny<\/code><\/li>\n\n\n\n<li>Auf meinem Ansible Control Node: <code>$ ansible -i inventory host.example.com -m ping<\/code><\/li>\n<\/ol>\n\n\n\n<p>Ich bestaune das gew\u00fcnschte Ergebnis:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>host.example.com | SUCCESS =&gt; {\n    \"ansible_facts\": {\n        \"discovered_interpreter_python\": \"\/usr\/bin\/python3\"\n    },\n    \"changed\": false,\n    \"ping\": \"pong\"\n}<\/code><\/pre>\n\n\n\n<p>Nun beende ich den Debug-Modus und starte <code>fapolicyd.service<\/code>. Fehleranalyse und Entst\u00f6rung sind damit beendet.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">F\u00fcr welche Anwendungsf\u00e4lle diese L\u00f6sung funktioniert<\/h3>\n\n\n\n<p>Die obige L\u00f6sung sorgt daf\u00fcr, dass Python-Skripte unterhalb des Verzeichnisses <code>\/home\/tronde\/.ansible\/tmp\/<\/code>, welche eine Python-Shebang beinhalten, mit dem Python-Interpreter <code>\/usr\/bin\/python3.9<\/code> ausgef\u00fchrt werden k\u00f6nnen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Diese L\u00f6sung funktioniert nicht<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>F\u00fcr andere unprivilegierte User au\u00dfer <code>tronde<\/code><\/li>\n\n\n\n<li>F\u00fcr andere Python-Interpreter wie z.B. <code>\/usr\/bin\/python3<\/code> oder <code>\/usr\/bin\/python3.11<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Hinterher ist man immer schlauer<\/h3>\n\n\n\n<p>Jetzt, wo ich wei\u00df, wonach ich suchen muss, finde ich auch direkt mehrere Treffer in den Red Hat Solutions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/access.redhat.com\/solutions\/5336451\">Why do I get unexpected \u201cOperation not permitted\u201d errors when trying to access files<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/access.redhat.com\/solutions\/7052379\">No FANOTIFY event seen in the audit log despite fapolicyd blocking operations<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/access.redhat.com\/solutions\/6997136\">Fapolicyd : Configure ansible automation execution for non-root users<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/access.redhat.com\/solutions\/7012798\">[AAP] Ansible job callback get &#8222;PermissionError&#8220; &#8222;Operation not permitted&#8220; due to fapolicyd deny rule<\/a><\/li>\n<\/ul>\n\n\n\n<p>Dokumentation findet sich neben der Manpage <code>fapolicyd(8)<\/code> z.B. auch im <a href=\"https:\/\/docs.redhat.com\/en\/documentation\/red_hat_enterprise_linux\/9\/html-single\/security_hardening\/index#assembly_blocking-and-allowing-applications-using-fapolicyd_security-hardening\">RHEL 9 Security Hardening Guide ab Kapitel 12<\/a>. Mit <a href=\"https:\/\/issues.redhat.com\/browse\/RHELDOCS-20981\">RHELDOCS-20981<\/a> &#8211; Improve section &#8222;Deploying fapolicyd&#8220; in RHEL Security Hardening Guide &#8211; habe ich zudem einen Verbesserungsvorschlag eingereicht.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p>Dieser Text hat an einem konkreten Beispiel gezeigt, wie eine strukturierte Fehleranalyse durchgef\u00fchrt wird. Diese f\u00fchrt \u00fcber die Problembeschreibung sowie das Formulieren von Hypothesen und deren Falsifizierung\/Verifizierung nach endlich vielen Schritten zu einer L\u00f6sung.<\/p>\n\n\n\n<p>Die L\u00e4nge des Textes zeigt, wie aufw\u00e4ndig eine Fehleranalyse werden kann. Wenn man keinen direkten Zugriff auf das betroffene System hat und mit jemandem ausschlie\u00dflich \u00fcber ein Ticket-System kommunizieren kann, wird schnell klar, dass sich ein Fall \u00fcber mehrere Tage und Wochen hinziehen kann.<\/p>\n\n\n\n<p>Ich war irgendwann geistig ersch\u00f6pft und hatte keine Lust mehr allein weiterzumachen, da mir die Ideen ausgingen. In diesem Fall hilft es, sich einen frischen Geist zur Unterst\u00fctzung zu holen. Gemeinsam mit meiner Kollegin Michi konnte die Ursache (<code>fapolicyd<\/code>) identifiziert werden.<\/p>\n\n\n\n<p>Mit Hilfe der Dokumentation war ich dann auch in der Lage, das Problem zu l\u00f6sen. Ich kann nun Ansible-Playbooks auf dem Zielsystem ausf\u00fchren.<\/p>\n\n\n\n<p>Der Dienst <code>fapolicyd<\/code> \u00fcberzeugt mich nicht. Meine Gedanken dazu werde ich in einem Folgeartikel mit euch teilen.<\/p>\n\n\n\n<p>In einem weiteren Folgeartikel werde ich dar\u00fcber schreiben, was Hilfesuchende und Supporter tun k\u00f6nnen, damit beide Seiten eine m\u00f6glichst gute Support-Erfahrung haben.<\/p>\n\n\n\n<p>Ich freue mich nun \u00fcber ein gel\u00f6stes Problem und schreibe an meinem Ansible-Playbook weiter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u2026dann k\u00f6nnen keine Ansible-Playbooks auf dem Zielsystem ausgef\u00fchrt werden, Sysadmins lassen vom Schreiben der Playbooks ab und wenden sich der Fehleranalyse zu. Genau das mache ich n\u00e4mlich gerade. Und damit ihr auch etwas davon habt, halte ich das Ganze in diesen Beitrag fest. Die Gr\u00fcnde daf\u00fcr sind vielf\u00e4ltig: Die erfahrenen Supporter und Sysadmins unter euch<span class=\"continue-reading\"> <a href=\"https:\/\/www.my-it-brain.de\/wordpress\/wenn-ansible-builtin-ping-kein-pong-zurueckgibt\/\">[Weiterlesen&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_metis_text_type":"standard","_metis_text_length":19788,"_post_count":0,"footnotes":""},"categories":[532],"tags":[896,898,430,305,897],"class_list":["post-4194","post","type-post","status-publish","format-standard","hentry","category-ansible","tag-fapolicyd","tag-fehleranalyse","tag-osbn","tag-planet","tag-troubleshooting"],"public_identification_id":"80260a07112d476081d050ca77efbc1c","private_identification_id":"60d9d4f94f9e48d3bb73548cdb5f0859","_links":{"self":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/4194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/comments?post=4194"}],"version-history":[{"count":14,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/4194\/revisions"}],"predecessor-version":[{"id":4212,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/posts\/4194\/revisions\/4212"}],"wp:attachment":[{"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/media?parent=4194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/categories?post=4194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.my-it-brain.de\/wordpress\/wp-json\/wp\/v2\/tags?post=4194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}