Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support insecure registries #1140

Merged
merged 38 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b884906
Add the support to the new --insecure-registry parameter
Jul 4, 2023
fb1095b
Add the support to the new --insecure-registry parameter in the creat…
Jul 5, 2023
4a9ccac
Add keychain mock and handler test
Jul 20, 2023
894608f
Add support for a single insecure registry
Jul 21, 2023
1e6a3e8
Add support to multiple insecure registries
Jul 25, 2023
ea87988
Adjusted flag name
Jul 25, 2023
c1afa7e
Fix problem with the mock
Jul 26, 2023
7f008ae
InsecureRegistry to InsecureRegistries
Aug 7, 2023
f5504fb
Address comment on FlagTags parity
Aug 7, 2023
ac3feac
Parse the InsecureRegistry env variable with comma separated values
Aug 7, 2023
4a38897
Changed InsecureRegistry to InsecureRegistries
Aug 8, 2023
e2b9509
Changing name at the env variable
Aug 8, 2023
7bf1824
Exporter now accept insecure registries
Aug 8, 2023
4661ea3
Bump up toward the latest version of imgutil
Aug 21, 2023
851bc6a
Remove legacy guard
Aug 22, 2023
473e101
Add WithRegistrySetting with insecure registries into restorer
Aug 22, 2023
321948d
Add support for insecure registries to the rebaser
Aug 24, 2023
edd2f01
Add rebaser testdata directory to .gitignore
Aug 24, 2023
1becb76
Cleaned testdata directory
Aug 25, 2023
70b35a0
Remove testdata rebaser entries from .gitignore
Aug 28, 2023
b062743
Add support to insecure registies for the read-write registry check
Aug 28, 2023
6589463
Move registryHandler into its own file into the image package
Aug 28, 2023
d2b731e
Add dockerfile.windows
Aug 29, 2023
979d57e
Introducing GetInsecureRegistryOptions
Aug 30, 2023
ee32fbe
Fix linter problems
Aug 30, 2023
bc0920d
Remove legacy guards and add test support to arm64
Aug 30, 2023
72f8159
Remove duplication and utilize new GetInsecureRegistryOptions function
Aug 31, 2023
e667328
Extract common code for getting insecure registry options from imageRef
Aug 31, 2023
1abe227
Added cli flags behind proper guards
Sep 4, 2023
760fdf9
Bumped up to the imgutil latest version with the insecure adjustment …
Sep 13, 2023
b20b7e8
Make the getInsecureOptions a static method as a temporary solution t…
Sep 13, 2023
d4e45cc
Added insecure registry to the runImage in the rebaser
Sep 14, 2023
8783bbc
Bump up to the latest version of imgutil with the multiple registries…
Sep 19, 2023
22114fc
Go mod tidy
Sep 19, 2023
baf4c82
Remove insecure-registry filter based on the imageRef
Sep 20, 2023
17e5b1d
Remove reduntant for loop and added a test for multiple GetInsecureOp…
Sep 20, 2023
eb4dad1
Don't remove whitespaces between buildpacks names
Sep 20, 2023
1ac4480
Add FlagInsecureRegistries behind 0.13 guards
Sep 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
.tool-versions
/out
.vscode

acceptance/testdata/*/**/container/cnb/lifecycle/*
acceptance/testdata/*/**/container/docker-config/*

acceptance/testdata/exporter/container/cnb/run.toml
acceptance/testdata/exporter/container/layers/*analyzed.toml
acceptance/testdata/exporter/container/other_layers/*analyzed.toml

acceptance/testdata/restorer/container/layers/*analyzed.toml
3 changes: 2 additions & 1 deletion acceptance/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ var (

func TestBuilder(t *testing.T) {
h.SkipIf(t, runtime.GOOS == "windows", "Builder acceptance tests are not yet supported on Windows")
h.SkipIf(t, runtime.GOARCH != "amd64", "Builder acceptance tests are not yet supported on non-amd64")

info, err := h.DockerCli(t).Info(context.TODO())
h.AssertNil(t, err)
Expand All @@ -39,6 +38,8 @@ func TestBuilder(t *testing.T) {
builderDaemonArch = info.Architecture
if builderDaemonArch == "x86_64" {
builderDaemonArch = "amd64"
} else if builderDaemonArch == "aarch64" {
builderDaemonArch = "arm64"
}

h.MakeAndCopyLifecycle(t, builderDaemonOS, builderDaemonArch, builderBinaryDir)
Expand Down
25 changes: 19 additions & 6 deletions acceptance/detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package acceptance

import (
"context"
"fmt"
"os"
"os/exec"
Expand All @@ -22,17 +23,29 @@ import (
)

var (
detectDockerContext = filepath.Join("testdata", "detector")
detectorBinaryDir = filepath.Join("testdata", "detector", "container", "cnb", "lifecycle")
detectImage = "lifecycle/acceptance/detector"
userID = "1234"
detectDockerContext = filepath.Join("testdata", "detector")
detectorBinaryDir = filepath.Join("testdata", "detector", "container", "cnb", "lifecycle")
detectImage = "lifecycle/acceptance/detector"
userID = "1234"
detectorDaemonOS, detectorDaemonArch string
)

func TestDetector(t *testing.T) {
h.SkipIf(t, runtime.GOOS == "windows", "Detector acceptance tests are not yet supported on Windows")
h.SkipIf(t, runtime.GOARCH != "amd64", "Detector acceptance tests are not yet supported on non-amd64")

h.MakeAndCopyLifecycle(t, "linux", "amd64", detectorBinaryDir)
info, err := h.DockerCli(t).Info(context.TODO())
h.AssertNil(t, err)

detectorDaemonOS = info.OSType
detectorDaemonArch = info.Architecture
if detectorDaemonArch == "x86_64" {
detectorDaemonArch = "amd64"
}
if detectorDaemonArch == "aarch64" {
detectorDaemonArch = "arm64"
}

h.MakeAndCopyLifecycle(t, detectorDaemonOS, detectorDaemonArch, detectorBinaryDir)
h.DockerBuild(t,
detectImage,
detectDockerContext,
Expand Down
27 changes: 27 additions & 0 deletions acceptance/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,33 @@ func testExporterFunc(platformAPI string) func(t *testing.T, when spec.G, it spe
})
})

when("app using insecure registry", func() {
it.Before(func() {
h.SkipIf(t, api.MustParse(platformAPI).LessThan("0.12"), "")
})

it("does an http request", func() {
var exportFlags []string
exportArgs := append([]string{ctrPath(exporterPath)}, exportFlags...)
exportedImageName = exportTest.RegRepoName("some-insecure-exported-image-" + h.RandString(10))
exportArgs = append(exportArgs, exportedImageName)
insecureRegistry := "host.docker.internal/bar"
insecureAnalyzed := "/layers/analyzed_insecure.toml"

_, _, err := h.DockerRunWithError(t,
exportImage,
h.WithFlags(
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_INSECURE_REGISTRIES="+insecureRegistry,
"--env", "CNB_ANALYZED_PATH="+insecureAnalyzed,
"--network", exportRegNetwork,
),
h.WithArgs(exportArgs...),
)
h.AssertStringContains(t, err.Error(), "http://host.docker.internal")
})
})

when("SOURCE_DATE_EPOCH is set", func() {
it("Image CreatedAt is set to SOURCE_DATE_EPOCH", func() {
h.SkipIf(t, api.MustParse(platformAPI).LessThan("0.9"), "SOURCE_DATE_EPOCH support added in 0.9")
Expand Down
59 changes: 59 additions & 0 deletions acceptance/rebaser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//go:build acceptance
// +build acceptance

package acceptance

import (
"path/filepath"
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
h "github.com/buildpacks/lifecycle/testhelpers"
)

var (
rebaserTest *PhaseTest
rebaserPath string
rebaserImage string
)

func TestRebaser(t *testing.T) {
testImageDockerContextFolder := filepath.Join("testdata", "rebaser")
rebaserTest = NewPhaseTest(t, "rebaser", testImageDockerContextFolder)
rebaserTest.Start(t, updateTOMLFixturesWithTestRegistry)
defer rebaserTest.Stop(t)

rebaserImage = rebaserTest.testImageRef
rebaserPath = rebaserTest.containerBinaryPath

for _, platformAPI := range api.Platform.Supported {
spec.Run(t, "acceptance-rebaser/"+platformAPI.String(), testRebaser(platformAPI.String()), spec.Sequential(), spec.Report(report.Terminal{}))
}
}

func testRebaser(platformAPI string) func(t *testing.T, when spec.G, it spec.S) {
return func(t *testing.T, when spec.G, it spec.S) {
when("called with insecure registry flag", func() {
it.Before(func() {
h.SkipIf(t, api.MustParse(platformAPI).LessThan("0.12"), "")
})
it("should do an http request", func() {
insecureRegistry := "host.docker.internal"
rebaserOutputImageName := insecureRegistry + "/bar"
_, _, err := h.DockerRunWithError(t,
rebaserImage,
h.WithFlags(
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_INSECURE_REGISTRIES="+insecureRegistry,
),
h.WithArgs(ctrPath(rebaserPath), rebaserOutputImageName),
)

h.AssertStringContains(t, err.Error(), "http://host.docker.internal")
})
})
}
}
22 changes: 21 additions & 1 deletion acceptance/restorer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ var (

func TestRestorer(t *testing.T) {
h.SkipIf(t, runtime.GOOS == "windows", "Restorer acceptance tests are not yet supported on Windows")
h.SkipIf(t, runtime.GOARCH != "amd64", "Restorer acceptance tests are not yet supported on non-amd64")
dlion marked this conversation as resolved.
Show resolved Hide resolved

testImageDockerContext := filepath.Join("testdata", "restorer")
restoreTest = NewPhaseTest(t, "restorer", testImageDockerContext)
Expand Down Expand Up @@ -106,6 +105,27 @@ func testRestorerFunc(platformAPI string) func(t *testing.T, when spec.G, it spe

h.AssertStringContains(t, output, "Restoring metadata for \"some-buildpack-id:launch-layer\"")
})

when("restores app metadata using an insecure registry", func() {
it.Before(func() {
h.SkipIf(t, api.MustParse(platformAPI).LessThan("0.12"), "")
})
it("does an http request ", func() {
insecureRegistry := "host.docker.internal"

_, _, err := h.DockerRunWithError(t,
restoreImage,
h.WithFlags(append(
dockerSocketMount,
"--env", "CNB_PLATFORM_API="+platformAPI,
"--env", "CNB_INSECURE_REGISTRIES="+insecureRegistry,
"--env", "CNB_BUILD_IMAGE="+insecureRegistry+"/bar",
)...),
)

h.AssertStringContains(t, err.Error(), "http://host.docker.internal")
})
})
})

when("using cache-dir", func() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run-image]
reference = "host.docker.internal/bar"
3 changes: 3 additions & 0 deletions acceptance/testdata/rebaser/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM ubuntu:bionic

COPY ./container/ /
10 changes: 10 additions & 0 deletions acceptance/testdata/rebaser/Dockerfile.windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM mcr.microsoft.com/windows/nanoserver:1809
USER ContainerAdministrator

COPY container /

ENV CNB_USER_ID=1

ENV CNB_GROUP_ID=1

ENV CNB_PLATFORM_API=${cnb_platform_api}
4 changes: 2 additions & 2 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type AnalyzerFactory struct {
cacheHandler CacheHandler
configHandler ConfigHandler
imageHandler image.Handler
registryHandler RegistryHandler
registryHandler image.RegistryHandler
}

func NewAnalyzerFactory(
Expand All @@ -29,7 +29,7 @@ func NewAnalyzerFactory(
cacheHandler CacheHandler,
configHandler ConfigHandler,
imageHandler image.Handler,
registryHandler RegistryHandler,
registryHandler image.RegistryHandler,
) *AnalyzerFactory {
return &AnalyzerFactory{
platformAPI: platformAPI,
Expand Down
5 changes: 3 additions & 2 deletions cmd/lifecycle/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (a *analyzeCmd) DefineFlags() {
cli.FlagLayoutDir(&a.LayoutDir)
cli.FlagUseLayout(&a.UseLayout)
cli.FlagRunPath(&a.RunPath)
cli.FlagInsecureRegistries(&a.InsecureRegistries)
fallthrough
case a.PlatformAPI.AtLeast("0.9"):
cli.FlagLaunchCacheDir(&a.LaunchCacheDir)
Expand Down Expand Up @@ -99,8 +100,8 @@ func (a *analyzeCmd) Exec() error {
&cmd.BuildpackAPIVerifier{},
NewCacheHandler(a.keychain),
lifecycle.NewConfigHandler(),
image.NewHandler(a.docker, a.keychain, a.LayoutDir, a.UseLayout),
NewRegistryHandler(a.keychain),
image.NewHandler(a.docker, a.keychain, a.LayoutDir, a.UseLayout, a.InsecureRegistries),
image.NewRegistryHandler(a.keychain, a.InsecureRegistries),
)
analyzer, err := factory.NewAnalyzer(a.AdditionalTags, a.CacheImageRef, a.LaunchCacheDir, a.LayersDir, a.OutputImageRef, a.PreviousImageRef, a.RunImageRef, a.SkipLayers, cmd.DefaultLogger)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions cmd/lifecycle/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ func FlagForceRebase(force *bool) {
flagSet.BoolVar(force, "force", *force, "execute rebase even if operation is unsafe")
}

// FlagInsecureRegistries sets insecure-registry parameter as available
func FlagInsecureRegistries(insecureRegistries *str.Slice) {
flagSet.Var(insecureRegistries, "insecure-registry", "insecure registries")
}

// deprecated

func DeprecatedFlagRunImage(deprecatedRunImage *string) {
Expand Down
5 changes: 3 additions & 2 deletions cmd/lifecycle/creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (c *createCmd) DefineFlags() {
cli.FlagLayoutDir(&c.LayoutDir)
cli.FlagUseLayout(&c.UseLayout)
cli.FlagRunPath(&c.RunPath)
cli.FlagInsecureRegistries(&c.InsecureRegistries)
}
if c.PlatformAPI.AtLeast("0.11") {
cli.FlagBuildConfigDir(&c.BuildConfigDir)
Expand Down Expand Up @@ -124,8 +125,8 @@ func (c *createCmd) Exec() error {
&cmd.BuildpackAPIVerifier{},
NewCacheHandler(c.keychain),
lifecycle.NewConfigHandler(),
image.NewHandler(c.docker, c.keychain, c.LayoutDir, c.UseLayout),
NewRegistryHandler(c.keychain),
image.NewHandler(c.docker, c.keychain, c.LayoutDir, c.UseLayout, c.InsecureRegistries),
image.NewRegistryHandler(c.keychain, c.InsecureRegistries),
)
analyzer, err := analyzerFactory.NewAnalyzer(c.AdditionalTags, c.CacheImageRef, c.LaunchCacheDir, c.LayersDir, c.OutputImageRef, c.PreviousImageRef, c.RunImageRef, c.SkipLayers, cmd.DefaultLogger)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions cmd/lifecycle/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func (e *exportCmd) DefineFlags() {
cli.FlagLayoutDir(&e.LayoutDir)
cli.FlagRunPath(&e.RunPath)
cli.FlagUseLayout(&e.UseLayout)
cli.FlagInsecureRegistries(&e.InsecureRegistries)
} else {
cli.FlagStackPath(&e.StackPath)
}
Expand Down Expand Up @@ -340,6 +341,7 @@ func (e *exportCmd) initRemoteAppImage(analyzedMD files.Analyzed) (imgutil.Image
var opts = []remote.ImageOption{
remote.FromBaseImage(e.RunImageRef),
}

if e.supportsRunImageExtension() {
extendedConfig, err := e.getExtendedConfig(analyzedMD.RunImage)
if err != nil {
Expand All @@ -355,6 +357,8 @@ func (e *exportCmd) initRemoteAppImage(analyzedMD files.Analyzed) (imgutil.Image
opts = append(opts, remote.WithHistory())
}

opts = append(opts, image.GetInsecureOptions(e.InsecureRegistries)...)

if analyzedMD.PreviousImageRef() != "" {
cmd.DefaultLogger.Infof("Reusing layers from image '%s'", analyzedMD.PreviousImageRef())
opts = append(opts, remote.WithPreviousImage(analyzedMD.PreviousImageRef()))
Expand Down
55 changes: 0 additions & 55 deletions cmd/lifecycle/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"path/filepath"
"strings"

"github.com/buildpacks/imgutil/remote"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/pkg/errors"

Expand Down Expand Up @@ -112,60 +111,6 @@ func (ch *DefaultCacheHandler) InitCache(cacheImageRef string, cacheDir string,
return cacheStore, nil
}

type DefaultRegistryHandler struct {
keychain authn.Keychain
}

func NewRegistryHandler(keychain authn.Keychain) *DefaultRegistryHandler {
return &DefaultRegistryHandler{
keychain: keychain,
}
}

func (rv *DefaultRegistryHandler) EnsureReadAccess(imageRefs ...string) error {
for _, imageRef := range imageRefs {
if err := verifyReadAccess(imageRef, rv.keychain); err != nil {
return err
}
}
return nil
}

func (rv *DefaultRegistryHandler) EnsureWriteAccess(imageRefs ...string) error {
for _, imageRef := range imageRefs {
if err := verifyReadWriteAccess(imageRef, rv.keychain); err != nil {
return err
}
}
return nil
}

func verifyReadAccess(imageRef string, keychain authn.Keychain) error {
if imageRef == "" {
return nil
}
img, _ := remote.NewImage(imageRef, keychain)
canRead, err := img.CheckReadAccess()
if !canRead {
cmd.DefaultLogger.Debugf("Error checking read access: %s", err)
return errors.Errorf("ensure registry read access to %s", imageRef)
}
return nil
}

func verifyReadWriteAccess(imageRef string, keychain authn.Keychain) error {
if imageRef == "" {
return nil
}
img, _ := remote.NewImage(imageRef, keychain)
canReadWrite, err := img.CheckReadWriteAccess()
if !canReadWrite {
cmd.DefaultLogger.Debugf("Error checking read/write access: %s", err)
return errors.Errorf("ensure registry read/write access to %s", imageRef)
}
return nil
}

// helpers

func initCache(cacheImageTag, cacheDir string, keychain authn.Keychain, deletionEnabled bool) (lifecycle.Cache, error) {
Expand Down
Loading