@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory
1212import scala .collection .JavaConverters ._
1313import scala .concurrent .{Await , ExecutionContext }
1414import scala .concurrent .duration ._
15+ import scala .util .matching .Regex
1516import scala .util .Try
1617
1718/**
@@ -32,6 +33,9 @@ import scala.util.Try
3233 */
3334object JobServer {
3435 val logger = LoggerFactory .getLogger(getClass)
36+ final val DEFAULT_CREDENTIAL_PATTERN = " (?i)credentials|secret|password|token"
37+ final val EMPTY_VALUE_PATTERN = " \"\" ,?" .r
38+ final val REDACTION_REPLACEMENT_TEXT = " \" *********(redacted)\" "
3539
3640 class InvalidConfiguration (error : String ) extends RuntimeException (error)
3741
@@ -49,8 +53,12 @@ object JobServer {
4953 } else {
5054 defaultConfig
5155 }
52- logger.info(" Starting JobServer with config {}" , config.getConfig(" spark" ).root.render())
53- logger.info(" Spray config: {}" , config.getConfig(" spray.can.server" ).root.render())
56+
57+ val credentialPattern = credentialRegex(config)
58+ val sparkConfig = config.getConfig(" spark" ).root.render()
59+ logger.info(" Starting JobServer with config {}" , maskCredentials(sparkConfig, credentialPattern))
60+ val sprayConfig = config.getConfig(" spray.can.server" ).root.render()
61+ logger.info(" Spray config: {}" , maskCredentials(sprayConfig, credentialPattern))
5462
5563 // TODO: Hardcode for now to get going. Make it configurable later.
5664 val system = makeSystem(config)
@@ -122,6 +130,35 @@ object JobServer {
122130 new WebApi (system, config, port, binManager, dataManager, supervisor, jobInfo).start()
123131 }
124132
133+ private def maskCredentials (lines : String , credentialRegex : Regex ): String = {
134+ lines
135+ .split(" \n " )
136+ .toSeq
137+ .map {
138+ line => line.split(" :" ) match {
139+ // if key matches credential keys pattern and value is not empty, mask credentials
140+ case Array (key, value) if (credentialRegex.findFirstIn(key).nonEmpty
141+ && EMPTY_VALUE_PATTERN .findFirstIn(value.stripMargin).isEmpty) =>
142+ Array (key, REDACTION_REPLACEMENT_TEXT ).mkString(" :" )
143+ case _ => line
144+ }
145+ }.mkString(" \n " )
146+ }
147+
148+ private def credentialRegex (config : Config ): Regex = {
149+ // Use default credential keys if spark.ui.confidentialKeys is not set
150+ val credentialPattern = try {
151+ config.getString(" spark.redaction.regex" )
152+ } catch {
153+ case _ : Exception =>
154+ logger.info(s " spark.redaction.regex is not set, " +
155+ s " use default credential pattern $DEFAULT_CREDENTIAL_PATTERN" )
156+ DEFAULT_CREDENTIAL_PATTERN
157+ }
158+
159+ credentialPattern.r
160+ }
161+
125162 private def parseInitialBinaryConfig (key : String , config : Config ): Map [String , String ] = {
126163 if (config.hasPath(key)) {
127164 val initialJarsConfig = config.getConfig(key).root
0 commit comments