2009-05-28 4 views
16

Abbiamo alcune applicazioni che a volte entrano in uno stato negativo, ma solo in produzione (ovviamente!). Durante l'acquisizione di un dump dell'heap può aiutare a raccogliere informazioni di stato, è spesso più facile usare un debugger remoto. L'impostazione di questo up è facile - basti solo aggiungere questo per la sua linea di comando:JVM Secure Debugging per produzione

-Xdebug -Xrunjdwp: trasporti = dt_socket, server = y, sospendere = n, indirizzo = PORT

Non sembra esserci alcuna meccanismo di sicurezza disponibile, quindi attivare il debugging in produzione consentirebbe effettivamente l'esecuzione di codice arbitrario (tramite hotswap).

Abbiamo un mix di 1.4.2 e 1.5 Sun JVM in esecuzione su Solaris 9 e Linux (Redhat Enterprise 4). Come possiamo abilitare il debugging sicuro? Altri modi per raggiungere il nostro obiettivo di ispezione del server di produzione?

Aggiornamento: Per JVM JDK 1.5+, è possibile specificare un'interfaccia e una porta a cui il debugger deve eseguire il binding. Quindi, il suggerimento di KarlP di legare a loopback e usare semplicemente un tunnel SSH a una finestra di sviluppo locale dovrebbe funzionare dato che SSH è configurato correttamente sui server.

Tuttavia, sembra che JDK1.4x non consenta di specificare un'interfaccia per la porta di debug. Quindi, possiamo bloccare l'accesso alla porta di debug da qualche parte nella rete o fare qualche blocco specifico del sistema nel sistema operativo stesso (IPChains come suggerito da Jared, ecc.)?

Aggiornamento # 2: Si tratta di un hack che ci permetterà di limitare il nostro rischio, anche su 1.4.2 JVM:

comando params linea:

-Xdebug 
-Xrunjdwp: 
    transport=dt_socket, 
    server=y, 
    suspend=n, 
    address=9001, 
    onthrow=com.whatever.TurnOnDebuggerException, 
    launch=nothing 

codice Java per accendere debugger:

try { 
    throw new TurnOnDebuggerException(); 
} catch (TurnOnDebugger td) { 
    //Nothing 
} 

L'eccezione TurnOnDebuggerException può essere qualsiasi eccezione garantita per non essere generata da nessun'altra parte.

Ho provato questo su una casella di Windows per dimostrare che (1) la porta del debugger non riceve inizialmente le connessioni e (2) lanciando l'eccezione di TurnOnDebugger come mostrato sopra fa sì che il debugger diventi vivo. Il parametro di lancio era obbligatorio (almeno su JDK1.4.2), ma JVM gestiva con garbo un valore obsoleto.

Stiamo pianificando di creare un piccolo servlet che, dietro un'adeguata sicurezza, ci consenta di attivare il debugger. Naturalmente, non è possibile disattivarlo in seguito, e il debugger è ancora in ascolto promiscuo una volta acceso. Ma queste sono limitazioni che siamo disposti ad accettare in quanto il debug di un sistema di produzione risulterà sempre in un riavvio successivo.

Aggiornamento # 3: ho finito per scrivere tre classi: (1) TurnOnDebuggerException, un 'eccezione pianura ol Java, (2) DebuggerPoller, un thread in background le verifiche per l'esistenza di un file specificato nel file system, e (3) DebuggerMainWrapper, una classe che avvia il thread di polling e quindi chiama in modo riflessivo il metodo principale di un'altra classe specificata.

Questo è come la sua utilizzate:

  1. Sostituisci la tua classe "principale" con DebuggerMainWrapper negli script di start-up
  2. aggiungere due sistemi (-D) params, uno che specifica la vera classe principale, e l'altro che specifica un file sul filesystem.
  3. Configurare il debugger sulla riga di comando con la parte onthrow = com.whatever.TurnOnDebuggerException aggiunta
  4. Aggiungere un jar con le tre classi sopra menzionate al classpath.

Ora, quando si avvia la JVM, tutto è lo stesso eccetto che viene avviato un thread di polling in background. Presumendo che il file (il nostro è chiamato TurnOnDebugger) inizialmente non esiste, il poller lo controlla ogni N secondi. Quando il poller lo nota per la prima volta, lancia e cattura immediatamente l'eccezione TurnOnDebuggerException. Quindi, l'agente viene avviato.

Non puoi trasformarlo indietro, e la macchina non è terribilmente sicuro quando la sua via. Sul lato positivo, non penso che il debugger consenta più connessioni simultanee, quindi mantenere una connessione di debug è la miglior difesa. Abbiamo scelto il metodo di notifica dei file perché ci ha consentito di utilizzare il nostro authen/autore Unix esistente specificando il file trigger in una directory in cui solo gli usi appropriati hanno diritti. Potresti facilmente creare un piccolo file di guerra che ha raggiunto lo stesso scopo tramite una connessione socket. Ovviamente, dato che non possiamo disattivare il debugger, lo useremo solo per raccogliere dati prima di eliminare un'applicazione malata. Se qualcuno vuole questo codice, per favore fatemelo sapere. Tuttavia, ti bastano pochi minuti per metterlo insieme da solo.

risposta

8

Se si utilizza SSH è possibile consentire il tunneling e tunnel di una porta al vostro host locale. Nessuno sviluppo richiesto, tutto fatto usando sshd, ssh e/o stucco.

Il socket di debug sul server java può essere impostato sull'interfaccia locale 127.0.0.1.

+0

Se funziona (prova ora), sembra la migliore opzione per noi. Non è che eseguiamo regolarmente il debug, ma vogliamo la capacità di catturare una JVM in uno stato di comportamento anomalo. – ShabbyDoo

+1

Penso che questo funziona solo su JDK 1.5+: http://java.sun.com/j2se/1.5.0/docs/guide/jpda/enhancements.html Vedere "il trasporto dt_socket è stata modificata per prendere un indirizzo locale quando si esegue in modalità server "nel link sopra. – ShabbyDoo

+0

@Shabby - sì - sembra che funzioni 1.5+, ed è un'ottima soluzione. L'alternativa è bloccare le porte di debug tramite un firewall (software o hardware.) Forse check-out ipchains per i tuoi host linux? (http://tldp.org/HOWTO/IPCHAINS-HOWTO.html) – Jared

0

esportare le informazioni/servizi in JMX e quindi utilizzare RMI + SSL per accedere da remoto. La tua situazione è ciò per cui JMX è progettato (la sigla M sta per Management).

+0

Sono d'accordo che le metriche comuni dovrebbero essere esposte tramite JMX. Stiamo attualmente utilizzando un profiler di produzione leggero (Wily), ma non è molto utile per acquisire informazioni sullo stato e può funzionare bene solo se limitato a tracce con grana grossa. L'altro problema è che alcune di queste app sono (parzialmente) di terze parti, quindi faremo il debug con la fonte decompilata al meglio. – ShabbyDoo

+1

Continuo a sostenere che collegare il debugger a un'applicazione di produzione è una cattiva idea. Gli utenti non avranno idea di cosa sta succedendo quando si raggiunge un punto di interruzione e si passano alcuni momenti in memoria. Proverei a trovare i punti nel codice che stanno avendo problemi ed esporre lo stato corrente tramite JMX e mantenere i registri di controllo dettagliati di ciò che sta accadendo. – Kevin

+1

Prima di eseguire il debug, dovremmo effettivamente prelevare l'istanza che si comporta male dal nostro cluster con bilanciamento del carico. Sono d'accordo sul fatto che il debug di un'applicazione con utenti attivi sarebbe una pessima idea. – ShabbyDoo

2

Hai perfettamente ragione: l'API Java Debug è intrinsecamente insicuro. Tuttavia, è possibile limitarlo a socket di dominio UNIX e scrivere un proxy con SSL/SSH per consentire l'accesso a connessioni esterne autenticate e crittografate che vengono quindi inoltrate al socket del dominio UNIX. Questo almeno riduce la tua esposizione a qualcuno che può ottenere un processo nel server, o qualcuno che può rompere il tuo SSL.

+0

È possibile mappare una porta sull'interfaccia predefinita a un socket di dominio? Il problema che ho (che ho scoperto dopo il mio post iniziale) è che la JVM Sun. 1.4.x può collegarsi solo all'interfaccia predefinita (?). Pertanto, sarebbe necessaria una mappatura magica in modo che questa porta non venisse esposta all'esterno della VM. – ShabbyDoo

0

Buona domanda.

Io non sono a conoscenza di alcun built-in capacità di crittografare le connessioni alla porta di debug.

Ci può essere un molto migliore/soluzione più facile, ma vorrei fare quanto segue:

  1. Mettere la macchina di produzione dietro un firewall che blocca l'accesso alla porta di debug (s).
  2. eseguire un processo di proxy sull'host sé che si collega alla porta, e crittografa ingresso e uscita dalla presa.
  3. eseguire un client proxy sulla stazione di lavoro di debug che crittografa anche/decodifica l'input. Questo si collega al proxy del server. La comunicazione tra di loro sarebbe crittografata.
  4. Connetti il ​​tuo debugger al client proxy.
+0

Come nota a margine: i nostri server di produzione sono protetti da un firewall, ma sono esposti a segmenti interni della rete. – ShabbyDoo