How to Build and push with non-root users
Introduction
Building with non-root users may be necessary for an organization due to the security process or stance that an organization has for its environment. Below is information on how to build and push with non-root users
Kaniko Builds
By default, Harness builds utilizing a Kubernetes cluster infrastructure are completed using kaniko for all Build and Push steps. If your team utilizes Kaniko, unfortunately, a Kaniko requirement is to have root access to build the Docker image. It doesn't support non-root users, so users will have to use one of the alternates listed below.
Build X Builds
Customers can also utilize BuildX for their builds. This feature can be enabled by submitting a ticket to Harness Support to enable the flag CI_USE_BUILDX_ON_K8
. We recommend reviewing the notes about this feature on the CI Early Access Features page. You must run BuildX on Kubernetes with Privileged mode enabled.
Drone Docker
It is also possible to utilize drone docker. Please read the following documentation for a full breakdown of drone-docker and how to use it.
Individual Step Root / Buildah plugin
If your Kubernetes cluster builds infrastructure is configured to run as non-root, you can either enable root access individual steps or use the Buildah plugin, which doesn't require root access, but will require privileged access.
For Buildah plugin environments, please keep in mind that settings and requirements will vary. For example, OpenShift Buildah environments have specific settings and requirements differing from others.
Enable root access for a single step
If your build runs as non-root (runAsNonRoot: true
), and you want to run the Build and Push step as root, you can set Run as User to 0
on the Build and Push step to use the root user for that individual step only.
If your security policy doesn't allow running as root for any step, you must use the Buildah plugin.
Use the Buildah plugin
If your security policy doesn't allow running as root for any step, you must use the Buildah plugin in a Plugin step to build and push your image.
buildah requires specific and different settings if the environment is an OpenShift environment. Please make note about the privileged flag. and defining anyuid
for Security Context Constraints
To use the Buildah plugin, you must meet the following requirements:
- You need a CI pipeline with a Build stage.
- The Build stage must use a Kubernetes cluster build infrastructure configured to run as non-root.
- For OpenShift Buildah users
anyuid
SCC is required. For more information, go to the OpenShift documentation on Managing Security Context Constraints.
Add a Plugin step
- Visual
- YAML
At the point in your pipeline where you want to build and upload an image, add a Plugin step that uses the buildah
plugin.
- Name: Enter a name.
- Container Registry: Select a connector corresponding to your push destination.
- Docker Hub: Docker connector
- ACR: Azure connector
- ECR: AWS connector
- GAR/GCR: GCP connector
- Image: Specify the plugin image and tag to use, such as
plugins/buildah-docker:1.1.0-linux-amd64
. If you don't specify a tag, thelatest
tag is used by default. Go to an image's Docker Hub page to browse available tags:- ACR: buildah-acr
- ECR: buildah-ecr
- GAR/GCR: buildah-gcr
- Docker Hub: buildah-docker
- Privileged: Set to
false
for OpenShift clusters. Set totrue
for non-OpenShift clusters. - Run as User: Specify the ID of the non-root user to use for this step, such as
1000
. - Settings: Add the following settings as key-value pairs.
repo
: The name of the repository where you want to store the image, for example,<hub-user>/<repo-name>
. For private registries, specify a fully qualified repo name.tags
: Specify tags for your image.registry
: Specify the registry index, such ashttps://index.docker.io/v2/
. The registry format for ECR isaws_account_id.dkr.ecr.region.amazonaws.com
.dockerfile
: Specify the Dockerfile to use for the build.username
: Provide the username to access the push destination, either as plaintext or an expression referencing a Harness secret or pipeline variable, such as<+pipeline.variables.DOCKER_HUB_USER>
.password
: An expression referencing a Harness secret or pipeline variable containing the password to access the push destination, such as<+pipeline.variables.DOCKER_HUB_SECRET>
.- For more information and additional settings, including AWS S3 settings, go to Buildah plugin settings.
At the point in your pipeline where you want to build and upload an image, add a Plugin step that uses the buildah
plugin, for example:
- step:
type: Plugin
name: buildah-docker
identifier: buildahdocker
spec:
connectorRef: account.harnessImage
image: plugins/buildah-docker:1.1.0-linux-amd64
privileged: false
settings:
repo: myDockerHub1234/test
tags: buildahtest
registry: https://index.docker.io/v2/
dockerfile: Dockerfile
username: <+secrets.getValue("DOCKER_HUB_USER")>
password: <+secrets.getValue("DOCKER_HUB_SECRET")>
runAsUser: "1000"
This step requires the following specifications:
connectorRef
: Provide the ID of a connector corresponding to your push destination.- Docker Hub: Docker connector
- ACR: Azure connector
- ECR: AWS connector
- GAR/GCR: GCP connector
image
: Specify the plugin image and tag to use, such asplugins/buildah-docker:1.1.0-linux-amd64
. If you don't specify a tag, thelatest
tag is used by default. Go to an image's Docker Hub page to browse available tags:- ACR: buildah-acr
- ECR: buildah-ecr
- GAR/GCR: buildah-gcr
- Docker Hub: buildah-docker
privileged
: Set tofalse
for OpenShift clusters. Set totrue
for non-OpenShift clusters.runAsUser
: Specify the ID of the non-root user to use for this step, such as1000
.settings
: Add the following settings as key-value pairs.repo
: The name of the repository where you want to store the image, for example,<hub-user>/<repo-name>
. For private registries, specify a fully qualified repo name.tags
: Specify tags for your image.registry
: Specify the registry index, such ashttps://index.docker.io/v2/
. The registry format for ECR isaws_account_id.dkr.ecr.region.amazonaws.com
.dockerfile
: Specify the Dockerfile to use for the build.username
: Provide the username to access the push destination, either as plaintext or an expression referencing a Harness secret or pipeline variable, such as<+pipeline.variables.DOCKER_HUB_USER>
.password
: An expression referencing a Harness secret or pipeline variable containing the password to access the push destination, such as<+pipeline.variables.DOCKER_HUB_SECRET>
.- For more information and additional settings, including AWS S3 settings, go to Buildah plugin settings.
Buildah plugin settings
For information about Buildah plugin settings, go to the Buildah README, the Buildah Drone Plugins Marketplace page, and the the main.go
file for each destination:
Many Buildah plugin settings correspond with settings for the built-in Build and Push steps. If you're encountering an error with the buildah
plugin configuration, you can reference the settings definitions for the built-in steps for guidance on the expected value for the equivalent Buildah settings. However, keep in mind that the configuration for Build and Push steps (such as field names and location in the YAML) is not an exact match to the Plugin step configuration.
Destination | Buildah image | Buildah main.go | Equivalent Build and Push step |
---|---|---|---|
Docker Hub | buildah-docker | Docker main.go | Build and Push to Docker Registry |
ACR | buildah-acr | ACR main.go | Build and Push to ACR |
ECR | buildah-ecr | ECR main.go | Build and Push to ECR |
GAR/GCR | buildah-grc | GCR main.go | Build and Push to GAR/Build and Push to GCR |
Stage YAML example
This YAML example shows a Build (CI
) stage with a Kubernetes cluster build infrastructure running as non-root (runAsNonRoot: true
and runAsUser: "1000"
) and a Plugin
step running the Buildah plugin.
- stage:
identifier: stage1
type: CI
name: stage1
spec:
cloneCodebase: true
infrastructure:
type: KubernetesDirect
spec:
connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR
namespace: YOUR_NAMESPACE
automountServiceAccountToken: true
nodeSelector: {}
containerSecurityContext:
runAsNonRoot: true
runAsUser: "1000"
os: Linux
execution:
steps:
- step:
identifier: buildah plugin
type: Plugin
name: buildah_plugin
spec:
connectorRef: YOUR_DOCKER_CONNECTOR
image: plugins/buildah-docker:1.1.0-linux-amd64
privileged: true
settings:
repo: myhub/test-repo
tags: builadhrootless
registry: https://index.docker.io/v2/
dockerfile: Dockerfile2
username: <+pipeline.variables.DOCKER_HUB_USER>
password: <+secrets.getValue("MyDockerPAT")>
runAsUser: "1000"
Build an image without pushing
You can use your CI pipeline to test a Dockerfile used in your codebase and verify that the resulting image is correct before you push it to your Docker repository.
The following configuration is valid with the Docker Buildah plugin (plugins/buildah-docker
) only. For other configurations, go to Build without pushing.
- In your CI pipeline, go to the Build stage that includes the Plugin step with the Docker Buildah plugin.
- In the Build stage's Overview tab, expand the Advanced section.
- Select Add Variable and enter the following:
- Name:
PLUGIN_DRY_RUN
- Type: String
- Value:
true
- Name:
- Save and run the pipeline.