@@ -23,7 +23,7 @@ use cb_common::{
2323 config:: StartSignerConfig ,
2424 constants:: { COMMIT_BOOST_COMMIT , COMMIT_BOOST_VERSION } ,
2525 types:: { Chain , Jwt , ModuleId } ,
26- utils:: { decode_jwt, validate_jwt} ,
26+ utils:: { decode_jwt, validate_admin_jwt , validate_jwt} ,
2727} ;
2828use cb_metrics:: provider:: MetricsProvider ;
2929use eyre:: Context ;
@@ -48,6 +48,8 @@ struct SigningState {
4848 /// Map of modules ids to JWT secrets. This also acts as registry of all
4949 /// modules running
5050 jwts : Arc < RwLock < HashMap < ModuleId , String > > > ,
51+ /// Secret for the admin JWT
52+ admin_secret : Arc < RwLock < String > > ,
5153}
5254
5355impl SigningService {
@@ -62,6 +64,7 @@ impl SigningService {
6264 let state = SigningState {
6365 manager : Arc :: new ( RwLock :: new ( start_manager ( config. clone ( ) ) . await ?) ) ,
6466 jwts : Arc :: new ( RwLock :: new ( config. jwts ) ) ,
67+ admin_secret : Arc :: new ( RwLock :: new ( config. admin_secret ) ) ,
6568 } ;
6669
6770 let loaded_consensus = state. manager . read ( ) . await . available_consensus_signers ( ) ;
@@ -71,21 +74,25 @@ impl SigningService {
7174
7275 SigningService :: init_metrics ( config. chain ) ?;
7376
74- let app = axum:: Router :: new ( )
77+ let signer_app = axum:: Router :: new ( )
7578 . route ( REQUEST_SIGNATURE_PATH , post ( handle_request_signature) )
7679 . route ( GET_PUBKEYS_PATH , get ( handle_get_pubkeys) )
7780 . route ( GENERATE_PROXY_KEY_PATH , post ( handle_generate_proxy) )
7881 . route_layer ( middleware:: from_fn_with_state ( state. clone ( ) , jwt_auth) )
82+ . with_state ( state. clone ( ) )
83+ . route_layer ( middleware:: from_fn ( log_request) ) ;
84+
85+ let admin_app = axum:: Router :: new ( )
7986 . route ( RELOAD_PATH , post ( handle_reload) )
8087 . route ( REVOKE_JWT , post ( handle_revoke_jwt) )
88+ . route_layer ( middleware:: from_fn_with_state ( state. clone ( ) , admin_auth) )
8189 . with_state ( state. clone ( ) )
8290 . route_layer ( middleware:: from_fn ( log_request) )
8391 . route ( STATUS_PATH , get ( handle_status) ) ;
84-
8592 let address = SocketAddr :: from ( ( [ 0 , 0 , 0 , 0 ] , config. server_port ) ) ;
8693 let listener = TcpListener :: bind ( address) . await ?;
8794
88- axum:: serve ( listener, app ) . await . wrap_err ( "signer server exited" )
95+ axum:: serve ( listener, signer_app . merge ( admin_app ) ) . await . wrap_err ( "signer server exited" )
8996 }
9097
9198 fn init_metrics ( network : Chain ) -> eyre:: Result < ( ) > {
@@ -125,6 +132,22 @@ async fn jwt_auth(
125132 Ok ( next. run ( req) . await )
126133}
127134
135+ async fn admin_auth (
136+ State ( state) : State < SigningState > ,
137+ TypedHeader ( auth) : TypedHeader < Authorization < Bearer > > ,
138+ req : Request ,
139+ next : Next ,
140+ ) -> Result < Response , SignerModuleError > {
141+ let jwt: Jwt = auth. token ( ) . to_string ( ) . into ( ) ;
142+
143+ validate_admin_jwt ( jwt, & state. admin_secret . read ( ) . await ) . map_err ( |e| {
144+ error ! ( "Unauthorized request. Invalid JWT: {e}" ) ;
145+ SignerModuleError :: Unauthorized
146+ } ) ?;
147+
148+ Ok ( next. run ( req) . await )
149+ }
150+
128151/// Requests logging middleware layer
129152async fn log_request ( req : Request , next : Next ) -> Result < Response , SignerModuleError > {
130153 let url = & req. uri ( ) . clone ( ) ;
@@ -273,6 +296,7 @@ async fn handle_reload(
273296 } ;
274297
275298 state. jwts = Arc :: new ( RwLock :: new ( config. jwts . clone ( ) ) ) ;
299+ state. admin_secret = Arc :: new ( RwLock :: new ( config. admin_secret . clone ( ) ) ) ;
276300
277301 let new_manager = match start_manager ( config) . await {
278302 Ok ( manager) => manager,
0 commit comments