From 42cf3e55ff775345b562e09dd93e926f0cf38659 Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Tue, 14 Nov 2023 14:55:37 -0500 Subject: [PATCH] Allow oci_push to use plain HTTP for a specific host. Right now, we can only push to HTTPS, which is creating some problems for a project I'm working on where we'd really like to push to a local registry container. We can in theory add a self-signed cert to that registry container, but the hoops you have to jump through to make that work on Docker Desktop for Mac are considerable and definitely require manual intervention, so it'd be really, really nice if we could instead optionally push to a `http` host. This adds a new attribute to `oci_push`, `plain_http_host`, which is a string value for a Docker registry host, including port if needed. This is an optional attribute, defaulting to the empty string. It'll be passed to the `ocitool` call as `--plain-http-host=""`, and onwards from there to `ResolverWithHeaders` and on to `credhelper.RegistryHostsFromDockerConfig`. If it's non-empty, the returned `docker.RegistryHosts` function will check if the `host` parameter matches `plainHTTPHost`, and if so, it'll change the `Scheme` for the host from `https` to `http. Signed-off-by: Andrew Bayer --- go/cmd/ocitool/main.go | 3 +++ go/cmd/ocitool/push_cmd.go | 4 +++- go/pkg/credhelper/docker.go | 6 +++++- go/pkg/ociutil/push.go | 10 +++++----- oci/push.bzl | 7 +++++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/go/cmd/ocitool/main.go b/go/cmd/ocitool/main.go index 71831a4..0b0059b 100644 --- a/go/cmd/ocitool/main.go +++ b/go/cmd/ocitool/main.go @@ -137,6 +137,9 @@ var app = &cli.App{ &cli.StringFlag{ Name: "parent-tag", }, + &cli.StringFlag{ + Name: "plain-http-host", + }, &cli.GenericFlag{ Name: "headers", Value: &flagutil.KeyValueFlag{}, diff --git a/go/cmd/ocitool/push_cmd.go b/go/cmd/ocitool/push_cmd.go index 55ecb4e..c7e58f5 100644 --- a/go/cmd/ocitool/push_cmd.go +++ b/go/cmd/ocitool/push_cmd.go @@ -33,7 +33,9 @@ func PushCmd(c *cli.Context) error { headers["X-Meta-"+k] = v } - resolver := ociutil.ResolverWithHeaders(headers) + plainHTTPHost := c.String("plain-http-host") + + resolver := ociutil.ResolverWithHeaders(headers, plainHTTPHost) ref := c.String("target-ref") diff --git a/go/pkg/credhelper/docker.go b/go/pkg/credhelper/docker.go index e4746d3..4fdd7fc 100644 --- a/go/pkg/credhelper/docker.go +++ b/go/pkg/credhelper/docker.go @@ -99,7 +99,7 @@ func seedAuthHeaders(host docker.RegistryHost) error { return nil } -func RegistryHostsFromDockerConfig() docker.RegistryHosts { +func RegistryHostsFromDockerConfig(plainHTTPHost string) docker.RegistryHosts { return func(host string) ([]docker.RegistryHost, error) { // FIXME This should be cached somewhere cfg, err := ReadHostDockerConfig() @@ -119,6 +119,10 @@ func RegistryHostsFromDockerConfig() docker.RegistryHosts { Capabilities: docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush, } + if plainHTTPHost != "" && host == plainHTTPHost { + registryHost.Scheme = "http" + } + helperName, ok := cfg.CredentialHelpers[host] if !ok { // If no credential helper is specified, fall back on the default behavior. diff --git a/go/pkg/ociutil/push.go b/go/pkg/ociutil/push.go index 274b293..7390cb0 100644 --- a/go/pkg/ociutil/push.go +++ b/go/pkg/ociutil/push.go @@ -24,23 +24,23 @@ import ( // DefaultResolver returns a resolver with credential helper auth and ocitool // extensions. func DefaultResolver() Resolver { - return newResolver(nil) + return newResolver(nil, "") } // ResolverWithHeaders returns a resolver with credential helper auth and ocitool // extensions. -func ResolverWithHeaders(headers map[string]string) Resolver { - return newResolver(headers) +func ResolverWithHeaders(headers map[string]string, plainHTTPHost string) Resolver { + return newResolver(headers, plainHTTPHost) } -func newResolver(headers map[string]string) Resolver { +func newResolver(headers map[string]string, plainHTTPHost string) Resolver { hdrs := http.Header{} for k, v := range headers { hdrs.Add(k, v) } hosts := docker.Registries( - credhelper.RegistryHostsFromDockerConfig(), + credhelper.RegistryHostsFromDockerConfig(plainHTTPHost), // Support for Docker Hub docker.ConfigureDefaultRegistries(), ) diff --git a/oci/push.bzl b/oci/push.bzl index 9bd933b..769bd94 100755 --- a/oci/push.bzl +++ b/oci/push.bzl @@ -48,6 +48,7 @@ def _oci_push_impl(ctx): --desc {desc} \\ --target-ref {ref} \\ --parent-tag \"{tag}\" \\ + --plain-http-host \"{plain_http_host}\" \\ {headers} \\ {xheaders} \\ @@ -60,6 +61,7 @@ def _oci_push_impl(ctx): desc = ctx.attr.manifest[OCIDescriptor].descriptor_file.short_path, ref = ref, tag = tag, + plain_http_host = ctx.attr.plain_http_host, debug = str(ctx.attr._debug[DebugInfo].debug), headers = headers, xheaders = xheaders, @@ -114,6 +116,11 @@ oci_push = rule( (optional) A tag to include in the target reference. This will not be included on child images." """, ), + "plain_http_host": attr.string( + doc = """ + (optional) A hostname which should be pushed to using http, rather than https." + """, + ), "headers": attr.string_dict( doc = """ (optional) A list of key/values to to be sent to the registry as headers.