@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory
12
12
import scala .collection .JavaConverters ._
13
13
import scala .concurrent .{Await , ExecutionContext }
14
14
import scala .concurrent .duration ._
15
+ import scala .util .matching .Regex
15
16
import scala .util .Try
16
17
17
18
/**
@@ -32,6 +33,9 @@ import scala.util.Try
32
33
*/
33
34
object JobServer {
34
35
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)\" "
35
39
36
40
class InvalidConfiguration (error : String ) extends RuntimeException (error)
37
41
@@ -49,8 +53,12 @@ object JobServer {
49
53
} else {
50
54
defaultConfig
51
55
}
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))
54
62
55
63
// TODO: Hardcode for now to get going. Make it configurable later.
56
64
val system = makeSystem(config)
@@ -122,6 +130,35 @@ object JobServer {
122
130
new WebApi (system, config, port, binManager, dataManager, supervisor, jobInfo).start()
123
131
}
124
132
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
+
125
162
private def parseInitialBinaryConfig (key : String , config : Config ): Map [String , String ] = {
126
163
if (config.hasPath(key)) {
127
164
val initialJarsConfig = config.getConfig(key).root
0 commit comments