Skip to content

Commit 9989908

Browse files
committed
DSP-19490 mask credentials in config
1 parent 8b6dd5e commit 9989908

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

job-server/src/main/scala/spark/jobserver/JobServer.scala

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory
1212
import scala.collection.JavaConverters._
1313
import scala.concurrent.{Await, ExecutionContext}
1414
import scala.concurrent.duration._
15+
import scala.util.matching.Regex
1516
import scala.util.Try
1617

1718
/**
@@ -32,6 +33,9 @@ import scala.util.Try
3233
*/
3334
object 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

Comments
 (0)