mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
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:
@@ -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.
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user