Skip to content

Commit

Permalink
Use daemonUserUid to opt-out of numeric USER
Browse files Browse the repository at this point in the history
Fixes #1198

Numeric USER directive is now controlled using `daemonUserUid in Docker`, which defaults to `Some("1001")`.

To get back to previous behavior the following can be used:

```scala
daemonUserUid in Docker := None
daemonUser in Docker    := "daemon"
```
  • Loading branch information
eed3si9n committed Feb 8, 2019
1 parent c744526 commit 79d0269
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 36 deletions.
53 changes: 25 additions & 28 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ object DockerPlugin extends AutoPlugin {
val strategy = dockerPermissionStrategy.value
val dockerBaseDirectory = (defaultLinuxInstallLocation in Docker).value
val user = (daemonUser in Docker).value
val uidOpt = (daemonUserUid in Docker).value
val group = (daemonGroup in Docker).value
val gidOpt = (daemonGroupGid in Docker).value
val base = dockerBaseImage.value
val uid = 1001
val gid = 0

val generalCommands = makeFrom(base) +: makeMaintainer((maintainer in Docker).value).toSeq
val stage0name = "stage0"
Expand All @@ -133,7 +133,11 @@ object DockerPlugin extends AutoPlugin {
}

val stage1: Seq[CmdLike] = generalCommands ++
Seq(makeUserAdd(user, uid, gid), makeWorkdir(dockerBaseDirectory)) ++
(uidOpt match {
case Some(_) => Seq(makeUser("root"), makeUserAdd(user, uidOpt, gidOpt))
case _ => Seq()
}) ++
Seq(makeWorkdir(dockerBaseDirectory)) ++
(strategy match {
case DockerPermissionStrategy.MultiStage =>
Seq(makeCopyFrom(dockerBaseDirectory, stage0name, user, group))
Expand All @@ -148,7 +152,11 @@ object DockerPlugin extends AutoPlugin {
dockerEnvVars.value.map(makeEnvVar) ++
makeExposePorts(dockerExposedPorts.value, dockerExposedUdpPorts.value) ++
makeVolumes(dockerExposedVolumes.value, user, group) ++
Seq(makeUser(uid), makeEntrypoint(dockerEntrypoint.value), makeCmd(dockerCmd.value))
Seq(uidOpt match {
case Some(uid) => makeUser(uid)
case _ => makeUser(user)
}) ++
Seq(makeEntrypoint(dockerEntrypoint.value), makeCmd(dockerCmd.value))

stage0 ++ stage1
}
Expand Down Expand Up @@ -188,8 +196,12 @@ object DockerPlugin extends AutoPlugin {
stage := (stage dependsOn dockerGenerateConfig).value,
stagingDirectory := (target in Docker).value / "stage",
target := target.value / "docker",
daemonUser := "daemon",
// pick a user name that's unlikely to exist in base images
daemonUser := "demiourgos728",
// when daemonUserUid is set, we will try to create this user and set numeric USER
daemonUserUid := Some("1001"),
daemonGroup := "root",
daemonGroupGid := Some("0"),
defaultLinuxInstallLocation := "/opt/docker",
validatePackage := Validation
.runAndThrow(validatePackageValidators.value, streams.value.log),
Expand Down Expand Up @@ -316,25 +328,17 @@ object DockerPlugin extends AutoPlugin {

/**
* @param daemonUser
* @param userId
* @param groupId
* @return useradd to create the daemon user with the given userId and groupId
* @param uidOpt
* @param gidOpt
* @return useradd to create the daemon user with the given uidOpt and gidOpt
*/
private final def makeUserAdd(daemonUser: String, userId: Int, groupId: Int): CmdLike =
private final def makeUserAdd(daemonUser: String, uidOpt: Option[String], gidOpt: Option[String]): CmdLike =
Cmd(
"RUN",
"id",
"-u",
daemonUser,
"||",
"useradd",
"--system",
"--create-home",
"--uid",
userId.toString,
"--gid",
groupId.toString,
daemonUser
(List("id", "-u", daemonUser, "2>", "/dev/null", "||", "useradd", "--system", "--create-home") :::
(uidOpt.fold[List[String]](Nil)(List("--uid", _))) :::
(gidOpt.fold[List[String]](Nil)(List("--gid", _))) :::
List(daemonUser)): _*
)

/**
Expand All @@ -344,13 +348,6 @@ object DockerPlugin extends AutoPlugin {
private final def makeUser(daemonUser: String): CmdLike =
Cmd("USER", daemonUser)

/**
* @param userId userId of the daemon user
* @return USER docker command
*/
private final def makeUser(userId: Int): CmdLike =
Cmd("USER", userId.toString)

/**
* @param entrypoint
* @return ENTRYPOINT command
Expand Down
19 changes: 11 additions & 8 deletions src/sbt-test/docker/file-permission/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ lazy val root = (project in file("."))
|RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
|
|FROM fabric8/java-centos-openjdk8-jdk
|RUN id -u daemon || useradd --system --create-home --uid 1001 --gid 0 daemon
|USER root
|RUN id -u demiourgos728 2> /dev/null || useradd --system --create-home --uid 1001 --gid 0 demiourgos728
|WORKDIR /opt/docker
|COPY --from=stage0 --chown=daemon:root /opt/docker /opt/docker
|COPY --from=stage0 --chown=demiourgos728:root /opt/docker /opt/docker
|USER 1001
|ENTRYPOINT ["/opt/docker/bin/file-permission-test"]
|CMD []""".stripMargin.linesIterator.toList)
Expand All @@ -33,7 +34,8 @@ lazy val root = (project in file("."))
val lines = dockerfile.linesIterator.toList
assertEquals(lines,
"""FROM fabric8/java-centos-openjdk8-jdk
|RUN id -u daemon || useradd --system --create-home --uid 1001 --gid 0 daemon
|USER root
|RUN id -u demiourgos728 2> /dev/null || useradd --system --create-home --uid 1001 --gid 0 demiourgos728
|WORKDIR /opt/docker
|COPY opt /opt
|USER 1001
Expand All @@ -46,7 +48,8 @@ lazy val root = (project in file("."))
val lines = dockerfile.linesIterator.toList
assertEquals(lines,
"""FROM openjdk:8
|RUN id -u daemon || useradd --system --create-home --uid 1001 --gid 0 daemon
|USER root
|RUN id -u demiourgos728 2> /dev/null || useradd --system --create-home --uid 1001 --gid 0 demiourgos728
|WORKDIR /opt/docker
|COPY opt /opt
|RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
Expand All @@ -60,10 +63,9 @@ lazy val root = (project in file("."))
val lines = dockerfile.linesIterator.toList
assertEquals(lines,
"""FROM fabric8/java-centos-openjdk8-jdk
|RUN id -u daemon || useradd --system --create-home --uid 1001 --gid 0 daemon
|WORKDIR /opt/docker
|COPY --chown=daemon:root opt /opt
|USER 1001
|USER daemon
|ENTRYPOINT ["/opt/docker/bin/file-permission-test"]
|CMD []""".stripMargin.linesIterator.toList)
},
Expand All @@ -79,9 +81,10 @@ lazy val root = (project in file("."))
|RUN ["chmod", "-R", "u=rwX,g=rwX", "/opt/docker"]
|
|FROM fabric8/java-centos-openjdk8-jdk
|RUN id -u daemon || useradd --system --create-home --uid 1001 --gid 0 daemon
|USER root
|RUN id -u demiourgos728 2> /dev/null || useradd --system --create-home --uid 1001 --gid 0 demiourgos728
|WORKDIR /opt/docker
|COPY --from=stage0 --chown=daemon:root /opt/docker /opt/docker
|COPY --from=stage0 --chown=demiourgos728:root /opt/docker /opt/docker
|USER 1001
|ENTRYPOINT ["/opt/docker/bin/file-permission-test"]
|CMD []""".stripMargin.linesIterator.toList)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ import com.typesafe.sbt.packager.docker._

dockerPermissionStrategy := DockerPermissionStrategy.CopyChown
dockerBaseImage := "fabric8/java-centos-openjdk8-jdk"

// opt-out of numeric USER
daemonUserUid in Docker := None
daemonUser in Docker := "daemon"
11 changes: 11 additions & 0 deletions src/sphinx/formats/docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,17 @@ The files from ``mappings in Docker`` are extracted underneath this directory.
defaultLinuxInstallLocation in Docker := "/opt/docker"
Daemon User
~~~~~~~~~~~
By default, sbt Native Packager will create a daemon user named ``demiourgos728``
whose UID is set to ``1001``, and and emit ``USER 1001`` since running as non-root is considered the best practice.

The following can be used to emit ``USER daemon`` instead:

.. code-block:: scala
daemonUserUid in Docker := None
daemonUser in Docker := "daemon"
File Permission
~~~~~~~~~~~~~~~
Expand Down

0 comments on commit 79d0269

Please sign in to comment.