build: Remove rootless image variant

All published OPA images now run with a non-root uid/gid.
The uid:gid is set to 1000:1000 for all images. As a result
there is no longer a need for the --rootless image variant
hence it will not be published as part of future releases.
This change is in line with container security best practices.
OPA can still be run with root privileges by explicitly setting the user,
either with the --user argument for docker run, or by specifying
the securityContext in the Kubernetes Pod specification.

Fixes: #4295

Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
This commit is contained in:
Ashutosh Narkar
2023-11-01 16:32:36 -07:00
parent 030923998d
commit eade10ae0e
6 changed files with 0 additions and 345 deletions
-7
View File
@@ -9,13 +9,6 @@ FROM ${BASE}
LABEL org.opencontainers.image.authors="Torin Sandall <torinsandall@gmail.com>"
LABEL org.opencontainers.image.source="https://github.com/open-policy-agent/opa"
# Temporarily allow us to identify whether running from within an offical
# Docker image with a "rootless" tag, so that we may print a warning that this image tag
# will not be published after 0.50.0. Remove after 0.50.0 release.
ARG OPA_DOCKER_IMAGE_TAG
ENV OPA_DOCKER_IMAGE_TAG=${OPA_DOCKER_IMAGE_TAG}
# Any non-zero number will do, and unfortunately a named user will not, as k8s
# pod securityContext runAsNonRoot can't resolve the user ID:
# https://github.com/kubernetes/kubernetes/issues/40958.
-16
View File
@@ -341,13 +341,6 @@ ifneq ($(GOARCH),arm64) # build only static images for arm64
--build-arg BIN_DIR=$(RELEASE_DIR) \
--platform linux/$* \
.
$(DOCKER) build \
-t $(DOCKER_IMAGE):$(VERSION)-rootless \
--build-arg OPA_DOCKER_IMAGE_TAG=rootless \
--build-arg BASE=cgr.dev/chainguard/glibc-dynamic:latest \
--build-arg BIN_DIR=$(RELEASE_DIR) \
--platform linux/$* \
.
endif
$(DOCKER) build \
-t $(DOCKER_IMAGE):$(VERSION)-static \
@@ -384,15 +377,6 @@ push-manifest-list-%: ensure-executable-bin
--provenance=false \
--push \
.
$(DOCKER) buildx build \
--tag $(DOCKER_IMAGE):$*-rootless \
--build-arg OPA_DOCKER_IMAGE_TAG=rootless \
--build-arg BASE=cgr.dev/chainguard/glibc-dynamic:latest \
--build-arg BIN_DIR=$(RELEASE_DIR) \
--platform $(DOCKER_PLATFORMS) \
--provenance=false \
--push \
.
$(DOCKER) buildx build \
--tag $(DOCKER_IMAGE):$*-static \
-13
View File
@@ -9,8 +9,6 @@ import (
"path"
"github.com/spf13/cobra"
"github.com/open-policy-agent/opa/cmd/internal/deprecation"
)
// RootCommand is the base CLI command that all subcommands are added to.
@@ -18,15 +16,4 @@ var RootCommand = &cobra.Command{
Use: path.Base(os.Args[0]),
Short: "Open Policy Agent (OPA)",
Long: "An open source project to policy-enable your service.",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
message, fatal := deprecation.CheckWarnings(os.Environ(), cmd.Use)
if message != "" {
cmd.PrintErr(message)
if fatal {
os.Exit(1)
}
}
},
}
-54
View File
@@ -1,54 +0,0 @@
package deprecation
// TODO: these warnings can be removed when the rootless images are no longer published.
const rootlessWarningMessage = `OPA appears to be running in a deprecated -rootless image.
Since v0.50.0, the default OPA images have been configured to use a non-root
user.
This image will soon cease to be updated. The following images should now be
used instead:
* openpolicyagent/opa:latest and NOT (openpolicyagent/opa:latest-rootless)
* openpolicyagent/opa:edge and NOT (openpolicyagent/opa:edge-rootless)
* openpolicyagent/opa:X.Y.Z and NOT (openpolicyagent/opa:X.Y.Z-rootless)
You can choose to acknowledge and ignore this message by unsetting:
OPA_DOCKER_IMAGE_TAG=rootless
`
// warningRootless is a fatal warning is triggered when the user is running OPA
// in a deprecated rootless image.
var warningRootless = warning{
MatchEnv: func(env []string) bool {
for _, e := range env {
if e == "OPA_DOCKER_IMAGE_TAG=rootless" {
return true
}
}
return false
},
MatchCommand: func(name string) bool {
return name != "run"
},
Fatal: true,
Message: rootlessWarningMessage,
}
// warningRootlessRun is a non-fatal version of the warning reserved for opa run.
// The warning for run is non-fatal to avoid production disruption
var warningRootlessRun = warning{
MatchEnv: func(env []string) bool {
for _, e := range env {
if e == "OPA_DOCKER_IMAGE_TAG=rootless" {
return true
}
}
return false
},
MatchCommand: func(name string) bool {
return name == "run"
},
Fatal: false,
Message: rootlessWarningMessage,
}
-92
View File
@@ -1,92 +0,0 @@
package deprecation
import (
"bytes"
"fmt"
"io"
"strings"
)
const width, border = 80, 3
const titleChar, dividerChar = "#", "-"
// warning is a struct which can be used to define deprecation warnings based on
// the environment and command being run.
type warning struct {
MatchEnv func([]string) bool
MatchCommand func(string) bool
Fatal bool
Message string
}
// CheckWarnings runs messageForWarnings with a default set of real warnings.
func CheckWarnings(env []string, command string) (string, bool) {
warnings := []warning{
warningRootless,
warningRootlessRun,
}
return messageForWarnings(warnings, env, command)
}
// messageForWarnings returns an obnoxious banner with the contents of all firing warnings.
// If no warnings fire, it returns an empty string.
// If any warnings are fatal, it returns true for the second return value.
func messageForWarnings(warnings []warning, env []string, command string) (string, bool) {
var messages []string
var fatal bool
for _, w := range warnings {
if w.MatchEnv(env) && w.MatchCommand(command) {
messages = append(messages, w.Message)
if w.Fatal {
fatal = true
}
}
}
buf := bytes.NewBuffer(nil)
if len(messages) == 0 {
return "", false
}
title := "Deprecation Warnings"
if fatal {
title = "Fatal Deprecation Warnings"
}
printFormattedTitle(buf, title)
for i, msg := range messages {
fmt.Fprintln(buf, strings.TrimSpace(msg))
if i < len(messages)-1 {
printFormattedDivider(buf)
}
}
printFormattedTitle(buf, "end "+title)
return buf.String(), fatal
}
func printFormattedTitle(out io.Writer, title string) {
padding := (width - len(title) - border*2) / 2
fmt.Fprintln(out, strings.Repeat(titleChar, width))
fmt.Fprintln(out,
strings.Join(
[]string{
strings.Repeat(titleChar, border),
strings.Repeat(" ", padding), strings.ToUpper(title), strings.Repeat(" ", padding),
strings.Repeat(titleChar, border),
},
"",
),
)
fmt.Fprintln(out, strings.Repeat(titleChar, width))
}
func printFormattedDivider(out io.Writer) {
fmt.Fprintln(out, strings.Repeat(dividerChar, width))
}
-163
View File
@@ -1,163 +0,0 @@
package deprecation
import (
"testing"
)
func TestMessageForWarnings(t *testing.T) {
testCases := map[string]struct {
Env []string
Command string
Warnings []warning
ExpectedMessage string
ExpectedFatal bool
}{
"warning that does not fire": {
Env: []string{"OPA_FOOBAR=1"},
Command: "foobar",
Warnings: []warning{
{
MatchEnv: func(env []string) bool {
return false
},
MatchCommand: func(command string) bool {
return false
},
Fatal: true,
Message: "fatal warning",
},
},
ExpectedFatal: false,
ExpectedMessage: "",
},
"warning that fires": {
Env: []string{"OPA_FOOBAR=1"},
Command: "foobar",
Warnings: []warning{
{
MatchEnv: func(env []string) bool {
for _, e := range env {
if e == "OPA_FOOBAR=1" {
return true
}
}
return false
},
MatchCommand: func(command string) bool {
return command == "foobar"
},
Fatal: true,
Message: "fatal warning for foobar",
},
},
ExpectedMessage: `################################################################################
### FATAL DEPRECATION WARNINGS ###
################################################################################
fatal warning for foobar
################################################################################
### END FATAL DEPRECATION WARNINGS ###
################################################################################
`,
ExpectedFatal: true,
},
"two warnings that fire, one fatally": {
Env: []string{"OPA_FOOBAR=1"},
Command: "foobar",
Warnings: []warning{
{
MatchEnv: func(env []string) bool {
for _, e := range env {
if e == "OPA_FOOBAR=1" {
return true
}
}
return false
},
MatchCommand: func(command string) bool {
return command == "foobar"
},
Fatal: true,
Message: "fatal warning for foobar",
},
{
MatchEnv: func(env []string) bool {
return true
},
MatchCommand: func(command string) bool {
return command == "foobar"
},
Fatal: false,
Message: "non fatal warning for foobar",
},
},
ExpectedMessage: `################################################################################
### FATAL DEPRECATION WARNINGS ###
################################################################################
fatal warning for foobar
--------------------------------------------------------------------------------
non fatal warning for foobar
################################################################################
### END FATAL DEPRECATION WARNINGS ###
################################################################################
`,
ExpectedFatal: true,
},
"two warnings that fire, neither fatally": {
Env: []string{"OPA_FOOBAR=1"},
Command: "foobar",
Warnings: []warning{
{
MatchEnv: func(env []string) bool {
for _, e := range env {
if e == "OPA_FOOBAR=1" {
return true
}
}
return false
},
MatchCommand: func(command string) bool {
return command == "foobar"
},
Fatal: false,
Message: "warning for foobar",
},
{
MatchEnv: func(env []string) bool {
return true
},
MatchCommand: func(command string) bool {
return command == "foobar"
},
Fatal: false,
Message: "another warning for foobar",
},
},
ExpectedMessage: `################################################################################
### DEPRECATION WARNINGS ###
################################################################################
warning for foobar
--------------------------------------------------------------------------------
another warning for foobar
################################################################################
### END DEPRECATION WARNINGS ###
################################################################################
`,
ExpectedFatal: false,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
message, fatal := messageForWarnings(tc.Warnings, tc.Env, tc.Command)
if fatal != tc.ExpectedFatal {
t.Errorf("Expected fatal to be %v but got %v", tc.ExpectedFatal, fatal)
}
if message != tc.ExpectedMessage {
t.Errorf("Expected message\n%s\nbut got\n%s", tc.ExpectedMessage, message)
}
})
}
}