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:
- Sostituisci la tua classe "principale" con DebuggerMainWrapper negli script di start-up
- aggiungere due sistemi (-D) params, uno che specifica la vera classe principale, e l'altro che specifica un file sul filesystem.
- Configurare il debugger sulla riga di comando con la parte onthrow = com.whatever.TurnOnDebuggerException aggiunta
- 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.
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
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
@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