Remote-Restart von DB und Webserver ohne root-Login ermöglichen

bitmuncher

Senior-Nerd
Sorry, keinen besseren Platz gefunden, da es einerseits Server-Probleme, als auch Scripting-Probleme und allgemeine Server-Sicherheitsfragen betrifft.

Um den Entwicklern in unserer Firma die Möglichkeit zu bieten den Datenbank- und den Webserver neuzustarten ohne daß ich ihnen einen root-Login geben muß, habe ich ein kleines Perl-Programm (Server und Client) geschrieben, das dies ermöglichen soll. Davon ausgehend, dass niemand (ausser die Entwickler selbst) Zugriff auf die Skripte hat, würde mich nun interessieren, ob ihr die folgende Methode für brauchbar haltet, was die Sicherheit betrifft. Der Server ist so gemacht, daß er Befehle nur als IDEA-verschlüsselte Strings vom Client entgegen nimmt und auch der Client versteht die Antworten des Servers nur, wenn diese mit der richtigen Passphrase verschlüsselt wurden. Im Source sehen die Verschlüsselungs- und Entschlüsselungsroutinen wie folgt aus:

Code:
use Crypt::CBC;

my $cryptkey = 'm31n3p455phr453?';

# encrypt a string
sub encrypt
{
    if(!$_[0]) {
        print "Usage: encrypt(<message>)\n";
        exit;
    }
    my $clear_cmd = $_[0]; # plaintext command
    my $cipher = Crypt::CBC->new($cryptkey, "Crypt::IDEA");
    my $cipherhex = $cipher->encrypt_hex($clear_cmd);
    return $cipherhex;
}

# decrypt a string
sub decrypt
{
    if(!$_[0]) {
        print "Usage: decrypt(<message>)\n";
        exit;
    }
    my $cipherhex = $_[0];
    my $cipher = Crypt::CBC->new($cryptkey, "Crypt::IDEA");
    my $plain = $cipher->decrypt_hex($cipherhex);
    return $plain;
}

Kann ich davon ausgehen, daß ein potentielle Angreifer keine Chance hat an die Passphrase zu kommen, solange er keinen Zugriff auf den Server bzw. die Skripte hat? Bruteforces des Keys werden durch die Firewall unterbunden, da alle beteiligten Rechner feste IPs haben und die Firewall nur "befugte" IPs zu diesem Mini-Server verbinden lässt. Ausserdem wird eine IP explizit vom Server gesperrt, wenn von dieser mehr als 3 Mal ein ungültiger/nicht für den Server verständlicher Befehl gesendet wird. Vertraglich geregelt dürfen unsere Entwickler keine Sourcen rausgeben, die nicht in der Firma als OpenSource geführt werden, so daß auch von dieser Seite keine Gefahr besteht, daß das Client-Skript weitergegeben wird. Einen Login mit Username und Passwort möchte ich aber vermeiden. Im Endeffekt sollen die Entwickler einfach einen Befehl auf dem Entwicklungsserver ausführen (dbserver1restart, dbserver2restart usw.) um damit eine Datenbank des Produktiv-Systems neuzustarten.

Allerdings gibt es dabei noch ein anderes Problem. Ich will das Server-Skript natürlich nicht die ganze Zeit mit root-Rechten laufen lassen. Daher dachte ich mir, daß ich ein setuid() in Perl nachbilde.

Code:
# call a command with setuid(0)
sub suid_call_cmd
{
    if(!$_[0]) {
        print "Usage: suid_call_cmd(<command>)\n";
        exit;
    }
    $command = $_[0];
    $< = $> = 0; # set UID and EUID to 0
    $( = $) = 0; # set GID and EGID to 0
    system($command); # call command
    # set original IDs
    $< = $real_user_id;
    $> = $effective_user_id;
    $( = $real_group_id;
    $) = $effective_group_id;
}

Doch wenn ich das Skript nun mit dem SUID-Flag (+s) versehe und es mit einem Normaluser starten will, bekomme ich die Meldung

Code:
Can't do setuid (cannot exec sperl)

was mir zeigt, daß ich offenbar nicht das "normale" Perl nutzen kann. Weiß jemand, wo ich Debian-Pakete (Sarge) davon bekommen kann? RedHat-Pakete finde ich zuhauf, aber keine DEBs. Oder seht ihr keine Gründe, die gegen das Ausführen des Server-Skripts als root sprechen? (Eigentlich versuche ich das wo immer möglich zu vermeiden.)

Edit: Das Paket, das sperl enthält, konnte ich dank Effenbergs Hilfe im IRC finden. Stellt sich nun nur noch die Frage wie sicher ihr diese Lösung einschätzt.
 
Das ist eine etwas umständliche Lösung aber dadurch flexibel und effektiv. Meine Bedenken:

Der größte Unsicherheitsfaktor hierbei ist wie immer der Mensch. Die Entwickler dürfen zwar keinen Source herausgeben aber niemand sagt, dass sie das freiwillig tun. Ein Trojanisches Pferd (etc.) auf ihren Kisten würde ausreichen, um Deinen Dienst zu kompromittieren, da Du das Passwort in das Script hart-codierst.

Sinnvoller fände ich einen SSL-Webserver-Zugang (sofern möglich), bei dem die Entwickler nur die von Dir freigegebenen Funktionen ausführen können (nach vorheriger Authentifizierung).
 
Original von maedmexx
Sinnvoller fände ich einen SSL-Webserver-Zugang (sofern möglich), bei dem die Entwickler nur die von Dir freigegebenen Funktionen ausführen können (nach vorheriger Authentifizierung).

An einer solchen Möglichkeit arbeite ich gerade (Client wird dann als CGI-Applikation in einen Webserver integriert und der "Management-Server" ist dann in C geschrieben), allerdings werde ich damit noch einige Zeit zu tun haben. Bis dahin muss aber erstmal eine Lösung her, die die Server nicht unnötig gefährdet. Ich bin in der Firma der einzige, der root-Zugriff auf die Server hat und falls ich mal krank oder im Urlaub bin, muss es für unsere Entwickler wenigstens die Möglichkeit geben einzelne Dienste neuzustarten, denn zu oft laden sie nicht ausreichend getestete Skripte hoch, die dann zur Überlastung des Webservers oder der DB führen. Normalerweise sollte man nun sagen "Dann müssen die Entwickler halt mehr testen.", aber das predige ich seit 2 Jahren und bringen tut es garnichts. Daher erstmal diese Lösung. :)
 
Nur mal am Rande gefragt: Was spricht denn gegen einen ssh-Zugang und dann die entsprechende Befehle mittels sudo freigeben? Dann musst du nichts selber frickeln
 
Das hiesse, dass unsere Entwickler mit einer Linux-Shell konfrontiert wären und sich Befehle merken müssten. Das wäre dann doch etwas viel verlangt. ;) Sind nur Webentwickler, die fast alle von Linux keinen blassen Schimmer haben.
 
es gibt da n Tool namens "webmin" damit hast du selber keine Arbeit (bzw fast keine)...

Du kannst User anlegen und ihnen bestimmte Rechte auf deinem Server geben.
Es hat eine grafische oberfläche und ist sehr übersichtlich aufgebaut...

zudem läuft alles uber SSL-Verschlüsselung :)



bin allerdings auch gerade dabei ein kleines Administrationsscript zu schreiben...
Problem sind bei sowas halt immer die Dienste die unter root laufen _müssen_, da das unter Umständen große Sicherheitslücken bilden kann...
 
Webmin ist mir bekannt, erfüllt aber nicht den gewünschten Zweck, da ich nicht mehrere Server in einem Interface verwalten kann. Abgesehen davon halte ich es als Übergangslösung für etwas übertrieben. Die endgültige Lösung in C mit CGI-Client wird, wenn sie erstmal fertig ist, direkt an unser Server-Netzwerk angepasst sein und z.B. auch Zugriff auf die Logs der Entwickler, JBoss-Verwaltung u.a. bieten, was Webmin nicht beherrscht.

Das Problem mit den Diensten, die root-Rechte benötigen, habe ich, wie oben beschrieben, mit einem simplen setuid gelöst. Da der Server nur Befehle entgegen nimmt, die er kennt (alle anderen werden verworfen) und z.B. beim Empfang des Befehls 'wwwrestart' den Befehl für suid_call_cmd() festlegt, der dann ausgeführt wird, hat der User keine Möglichkeit in die setuid-Funktion einzugreifen und den dort verwendeten Befehl zu manipulieren. Im Code sieht das dann etwa so aus:

Code:
...
$message = <$client>;
chomp($message);
$message = decrypt($message)
if($message eq "wwwrestart") {
  suid_call_cmd("/etc/init.d/apachectl start");
...
} else {
  ...
  close($client);
  ...
}
...

Und weil es keine Schleifen oder Bedingungen innerhalb der setuid-Funktion gibt, ist sie auch nicht unterbrechbar. SIGTERM wird via Signal-Handler abgefangen, so daß auch keine Möglichkeit besteht das Programm zu beeinflussen, wenn es geschlossen wird. In der C-Variante werden auch alle anderen Signale während des setuid(0) blockiert und erst wieder freigegeben, wenn die Original-UID wieder angenommen wurde. In dieser Hinsicht sehe ich daher weniger Probleme.

Mir stellt sich eher die Frage, wie einfach oder schwierig es ist, den Key für die Verschlüsselung zu ermitteln, wenn man keinen Zugriff auf den Source hat. Der Server sendet beim Verbindungsaufbau z.B. immer ein verschlüsseltes #-Zeichen, damit der Client erkennt, dass nun ein Befehl vom Server erwartet wird, er also was senden muss und nicht lesen. Gibt es z.B. eine Möglichkeit durch Beziehen dieses Strings die Verschlüsselung zu knacken? Oder ist es möglich irgendwie eine bestehende Verbindung zu "übernehmen" und dadurch an den Key zu kommen? Wäre es vielleicht sogar möglich oder gar besser die Kommunikation über einen UDP-Socket zu machen und nicht über TCP? Hab ich irgendwas nicht bedacht, was die Sicherheit beeinflussen könnte? usw. usf. Auch die Übergangslösung sollte trotz ihrer Einfachheit möglichst sicher sein, denn einige Wochen wird sie wohl Bestand haben, also eine Menge Zeit für potentielle Angreifer.
Für weitere Ideen und Denkanstösse bin ich daher dankbar, nur bitte keine anderen Tools empfehlen. 99% von denen hab ich mir bestimmt schon angeschaut, denn ich habe fast 2 Jahre nach einer brauchbaren Lösung gesucht und verschiedenste Dinge ausprobiert, die alle nicht das wahre waren. Deswegen jetzt der drastische Schritt zur Entwicklung einer eigenen Lösung speziell für unser Netzwerk. Es ist eine Menge Arbeit und ich würde sie mir sicherlich nicht machen, wenn ich nicht alle Möglichkeiten ausgelotet hätte. :)
 
naja...

du könntest:
- einen Teil des Schlüssels auf dem Clientrechner ablegen
- zwischen Server und Client einen SSH-Tunnel aufbauen
- variable Salts verwenden (!! kein direktes Verhältnis zum Schlüssel !!)
- nicht angeben was verboten, sondern was erlaubt ist
- auf dem Client ein verschlüsseltes (möglicherweise auch variables) Zertifikat ablegen, um ihn eindeutig zu identifizieren
- Die gesendeten Daten in scheinbar wahllos durcheinandergewürfelte Pakete zerteilen (natürlich mit einem Bestimmten System dahinter, eventuell auch pro client ein anderer Algorithmus)
- ...

Der Paranioa sind hier keine Grenzen gesetzt^^

ob UDP jetzt sicherer ist als TCP bin ich mir nicht sicher, da ich mich damit noch nie wirklich auseinandergesetzt habe...
 
SSH-Tunnel ist schonmal eine gute Idee. :)

Verbotene Sachen werden ja eh einfach nur ignoriert (es wird dann einfach ein neuer Befehl vom Client angefordert), so daß dieser Punkt schon umgesetzt ist.

Wie das mit dem Ablegen eines Teil-Schlüssels funktionieren soll, ist mir allerdings etwas unklar. Server und Client müssen ja den gleichen Key verwenden, damit sie sich "verstehen" und somit müsste dieser Teil ja irgendwie zum Server kommen, was ohne SSH-Tunnel im Klartext übertragen werden müsste.

Zertifikat wollte ich eigentlich vermeiden, denn dann hätte ich gleich zu OpenSSL greifen können, was ich aber aus verschiedensten Gründen (z.B. die benötigte Rechenleistung) nicht will.

An variable Schlüssel hatte ich auch schon gedacht, allerdings wird das auch erst in der C-Version umgesetzt, wo eine externe DB genutzt wird, auf der der Server den aktuellen Schlüssel ablegt und von der sich der Client selbigen abholt. Somit wird dann für jede neue Verbindung ein neuer Key benutzt (Client baut Verbindung zum Server auf und sendet mit einem festen Schlüssel die Anforderung für einen neuen Key, Server generiert den Key und speichert ihn in der DB, Client holt sich den Key dort ab, Server und Client kommunizieren ab diesem Punkt für 10 Befehle mit diesem Key, nach dem 10. Befehl wird ein neuer Key über die DB ausgetauscht). Die dafür nötigen Routinen habe ich noch aus einem anderen Projekt, will die aber nicht unbedingt auch noch in Perl umsetzen müssen.

Ein Aufteilung der Pakete ist nicht möglich, da ich keinen Raw-Socket verwende, mich also an die Regeln von TCP-Sockets in Perl halten muss.
 
mit meinem 4. Punkt meinte ich, dass du net definierst was net erlaubt ist, sondern das was erlaubt ist...

denn wenn man definiert was verboten ist, übersieht man leicht etwas, und daraus kann ein sehr großes "Loch" entstehen...


wegen Teilschlüssel ablegen... wer sagt dass du nur einen Tunnel aufbauen kannst?
du kannst zum Beispiel einen VPN-Tunnel aufbauen, und in diesem dann ein SSH-Tunnel

oder du baust einen Tunnel auf, übermittelst den Teilschlüsselund baust mit dessen Hilfe einen zweiten, den eigentlichen Tunnel auf...

( du baust einen Tunnel zwischen Server und Client auf, übermittelst über diesen Tunnel vom Server an den Client einen _zufallsbasierten_ temporären Schlüssel udn baust mit dem dann den eigentlichen Tunnel auf )
 
Programmieren bei euch Schwerverbrecher.. oder wieso betreibst Du so einen kranken Aufwand, um ein paar einfache Boot-Optionen zu implementieren?

Sowas zu manipulieren ist doch so attraktiv, wie Erdbeer-Eis mit sauren Gurken.

Das ist ja, als ob Du eine hochkritische Funktion absichern willst.. dabei sollen die nur 'nen Server booten..
 
Unser IDS registriert ca. 200-300 Angriffsversuche pro Tag. Ich denke, dass ich da Grund genug habe etwas mehr Paranoia an den Tag zu legen, als ich es bei "normalen" Webservern tun würde. Unsere Firma kann es sich nicht leisten, dass ein Server wegen einem blöden Hack ausfällt und erst recht nicht, dass jemand durch einen Hack an unsere Daten kommt. Ich habe also meine Gründe, warum ich eine möglichst hohe Sicherheit erreichen will.
 
Das hiesse, dass unsere Entwickler mit einer Linux-Shell konfrontiert wären und sich Befehle merken müssten. Das wäre dann doch etwas viel verlangt. Augenzwinkern Sind nur Webentwickler, die fast alle von Linux keinen blassen Schimmer haben.

Man kann mit ein paar zeilen shell scipt ein menu bauen wo eben nur der eine Punkt aufgefuehrt ist, damit sollte auch nen web-frickler umgehen koennen ;)

Andererseits koenntest du beim ssh login automatisch einen neustart anstarten und den user sofort wieder
ausloggen.

Unter BSD verwende ich fuer sowas noch zusaetzlich pfauth. dh erstmal authentifizieren- dann ueberhaupt den port fuer ssh aufmachen. Unter Linux wirds da sicher etwas aehnliches geben.

Grundsaetzlich wuerde ich von Perl scripten mit execs jeglicher abraten. Aber das ist meine eigene, irrationale Paranoia. ;)

Kann ich davon ausgehen, daß ein potentielle Angreifer keine Chance hat an die Passphrase zu kommen, solange er keinen Zugriff auf den Server bzw. die Skripte hat?

Ja, wenn deine anderen Bedingungen (zu Bruteforce) wahr sind....mhm..plaintext?

Ps. Das letzte worauf ich mich verlassen wuerde sind Mitarbeiter die keine scripte rausgeben.
Was ist wenn das Notebook gestohlen wird etc etc?

Sowas ist hoechst fuzzy
 
Die Skripte kommen auf kein Notebook, sondern ausschliesslich auf die Workstations der Entwickler und auf die Server der Testumgebung, die "von aussen" nicht erreichbar sind. Ausserdem erwähnte ich bereits, dass ich ein Interface für alle Server haben will, was also heisst, dass sich die Entwickler garnicht erst per SSH auf den Servern anmelden sollen. Wenn ich eine restricted Shell wollte, stünden dutzende fertige Tools zur Verfügung. Und ob nun Shell- oder Perl-Skript macht kaum einen Unterschied, ausser dass Perl die bessere Performance und Flexibilität liefert. Ausserdem hasse ich die Syntax von Shell-Skripten. Perl ist syntaktisch näher an C, womit ich wesentlich vertrauter bin und was die Umsetzung gleichartigen Codes in C für die endgültige Version um einiges vereinfacht. Ausserdem soll der Client später in einem CGI-Interface umgesetzt werden, was um einiges einfacher ist, wenn er schon in Perl vorliegt. In der aktuellen Version benutze ich auch kein system(), sondern Backticks um somit auch an die Rückgabe der Befehle zu kommen:

Code:
my $returnvalue = `meinbefehl`;
my $message = encrypt($returnvalue);
$client->send("$message\n");

Dadurch werden Befehle eh mit 'sh -c meinbefehl' ausgeführt, also direkt durch die Shell. In der Hinsicht macht es also keinerlei Unterschied, ob ich Perl- oder Bash-Skript nutze.

Und sonst möchte ich darum bitten, dass hier nicht in Frage gestellt wird warum ich das in dieser Art umsetze oder nicht irgendwelche fertigen Tools nutze. Ich habe mir schon was dabei gedacht, wenn ich die Übergangslösung in Perl schreibe, wenn ich keine fertigen Tools nutze und wenn ich es möglichst sicher haben will. Konstruktive Hinweise auf mögliche Sicherheitslücken und Vorschläge für eine bessere Absicherung wären mir lieber, denn darum geht es hier.
 
Du willst keine pragmatische (Uebergangs)Loesung- du willst frickeln (und das Rad zum 72631263213. mal neu erfinden).
 
Original von Gulliver
Du willst keine pragmatische (Uebergangs)Loesung- du willst frickeln (und das Rad zum 72631263213. mal neu erfinden).

Nein, ich will eine Übergangslösung, die einigen Anforderungen entspricht:
1. Weiterverwendbarkeit als Grundlage für einen in C geschriebenen Server mit CGI-Client
2. möglichst hohe Sicherheit
3. zentrale Verwaltung aller Server über einen Rechner/Client
4. flexible Anpassungsmöglichkeiten, da die von uns eingesetzten Server in Konfiguration, Softwarezusammenstellung usw. recht verschieden sind (vom MySQL-Cluster über verschiedenste Applikations- und Webserver bis hin zu verschiedenen Mailservern)

Und nun zeige mir bitte ein Tool, das dem allen gerecht wird und das es schon gibt. Du wirst nichtmal ein Tool finden, das die gesamte von uns eingesetzte Software "steuern" (restarten, konfigurieren usw.) kann (so wie es in der endgültigen Version der Fall sein wird), was im einzelnen wären: Jboss, Tomcat, Apache, Zope, MySQL, PostgreSQL, Postfix, Courier-IMAP/S, Courier-POP3/S, QMail, Nagios, Snort, AIDE und natürlich der übliche Kram wie Cronjobs erstellen/ändern u.ä. Kurzum: Ich will ein zentrales Management unseres Server-Netzwerks.

Es geht also keineswegs um die Neuerfindung des Rades, sondern schlicht und einfach um ein Tool, das es in dieser Form nur kommerziell gibt und ich habe keine Lust für solchen Sch... einige Tausend Euro auszugeben, für die ich lieber unseren Mitarbeitern z.B. mehr RAM für deren Workstations kaufen kann.

So, ich hoffe, dass das "Warum" nun endlich geklärt ist. Ich werde Beiträge dieser Form nicht mehr beantworten, da es 1. zu nichts führt, 2. ich dutzende Tools ausprobiert habe, bei denen entweder Funktionalitäten oder die Zentralisierung fehlte und 3. hier niemand im Board sich anmaßen kann mir zu unterstellen, dass ich "frickeln" will, solange er/sie mir kein Tool zeigen kann, das in unserem Servernetzwerk funktioniert und all' das beherrscht, was ich für notwendig erachte. Ich bat um konstruktive Vorschläge und nicht um haltlose Unterstellungen. X(
 
Zurück
Oben