Skip to content

Commit

Permalink
Authenticate for CacheFrom via input credentials on Image (#500)
Browse files Browse the repository at this point in the history
* First pass at auth logic from the image inputs:wq

* Refactor auth functionality into function to reuse

* Log into registry only once

* remove debug statements

* Add documentation to
  • Loading branch information
guineveresaenger authored Feb 16, 2023
1 parent c66fda9 commit 84f4dd6
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 66 deletions.
2 changes: 1 addition & 1 deletion provider/cmd/pulumi-resource-docker/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3062,7 +3062,7 @@
},
"cacheFrom": {
"$ref": "#/types/docker:index/cacheFrom:CacheFrom",
"description": "A list of images to use as build cache"
"description": "A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry."
},
"context": {
"type": "string",
Expand Down
113 changes: 60 additions & 53 deletions provider/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,26 @@ func (p *dockerNativeProvider) dockerBuild(ctx context.Context,
return "", nil, err
}

auths, err := cfg.GetAllCredentials()
if err != nil {
return "", nil, err
}
// read auths to a map of authConfigs for the build options to consume
authConfigs := make(map[string]types.AuthConfig, len(auths))
for k, auth := range auths {
authConfigs[k] = types.AuthConfig(auth)
authConfigs := make(map[string]types.AuthConfig)
var regAuth types.AuthConfig

// sign into registry if we're pushing or setting CacheFrom
// TODO: add functionality for additional registry caches not associated with the stack image
// See: https://github.com/pulumi/pulumi-docker/issues/497
if len(img.Build.CachedImages) > 0 || !img.SkipPush {
auth, msg, err := getRegistryAuth(img, cfg)
if err != nil {
return "", nil, err
}
if msg != "" {
err = p.host.Log(ctx, "warning", urn, msg)
if err != nil {
return "", nil, err
}
}
authConfigs[auth.ServerAddress] = auth // for image cache
regAuth = auth // for image push
}

// make the build options
opts := types.ImageBuildOptions{
Dockerfile: img.Build.Dockerfile,
Expand Down Expand Up @@ -183,50 +193,7 @@ func (p *dockerNativeProvider) dockerBuild(ctx context.Context,
return "", nil, err
}

// authentication for registry push
// we check if the user set creds in the Pulumi program, and use those preferentially,
// otherwise we use host machine creds via authConfigs.
var pushAuthConfig types.AuthConfig

if img.Registry.Username != "" && img.Registry.Password != "" {
pushAuthConfig.Username = img.Registry.Username
pushAuthConfig.Password = img.Registry.Password
pushAuthConfig.ServerAddress, err = getRegistryAddrForAuth(img.Registry.Server, img.Name)
if err != nil {
return "", nil, err
}

} else {
// send warning if user is attempting to use in-program credentials
if img.Registry.Username == "" && img.Registry.Password != "" {
msg := "username was not set, although password was; using host credentials file"
err = p.host.Log(ctx, "warning", urn, msg)
if err != nil {
return "", nil, err
}
}
if img.Registry.Password == "" && img.Registry.Username != "" {
msg := "password was not set, although username was; using host credentials file"
err = p.host.Log(ctx, "warning", urn, msg)
if err != nil {
return "", nil, err
}
}

registryServer, err := getRegistryAddrForAuth(img.Registry.Server, img.Name)
if err != nil {
return "", nil, err
}

cliPushAuthConfig, err := cfg.GetAuthConfig(registryServer)
if err != nil {
return "", nil, err
}

pushAuthConfig = types.AuthConfig(cliPushAuthConfig)
}

authConfigBytes, err := json.Marshal(pushAuthConfig)
authConfigBytes, err := json.Marshal(regAuth)

if err != nil {
return "", nil, fmt.Errorf("error parsing authConfig: %v", err)
Expand Down Expand Up @@ -417,6 +384,46 @@ func getDefaultDockerConfig() (*configfile.ConfigFile, error) {
return cfg, nil
}

func getRegistryAuth(img Image, cfg *configfile.ConfigFile) (types.AuthConfig, string, error) {
// authentication for registry push or cache pull
// we check if the user set creds in the Pulumi program, and use those preferentially,
// otherwise we use host machine creds via authConfigs.
var regAuthConfig types.AuthConfig
var msg string

if img.Registry.Username != "" && img.Registry.Password != "" {
regAuthConfig.Username = img.Registry.Username
regAuthConfig.Password = img.Registry.Password
serverAddr, err := getRegistryAddrForAuth(img.Registry.Server, img.Name)
if err != nil {
return regAuthConfig, msg, err
}
regAuthConfig.ServerAddress = serverAddr

} else {
// send warning if user is attempting to use in-program credentials
if img.Registry.Username == "" && img.Registry.Password != "" {
msg = "username was not set, although password was; using host credentials file"
}
if img.Registry.Password == "" && img.Registry.Username != "" {
msg = "password was not set, although username was; using host credentials file"
}

registryServer, err := getRegistryAddrForAuth(img.Registry.Server, img.Name)
if err != nil {
return regAuthConfig, msg, err
}

cliPushAuthConfig, err := cfg.GetAuthConfig(registryServer)
if err != nil {
return regAuthConfig, msg, err
}

regAuthConfig = types.AuthConfig(cliPushAuthConfig)
}
return regAuthConfig, msg, nil
}

// Because the authConfigs provided by the host may return URIs with the `https://` scheme in the
// map keys, `getRegistryAddrForAuth` ensures we return either the legacy Docker IndexServer's URI,
// which is special cased, or a registry hostname.
Expand Down
5 changes: 4 additions & 1 deletion provider/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ func Provider() tfbridge.ProviderInfo {
Default: "Dockerfile",
},
"cacheFrom": {
Description: "A list of images to use as build cache",
Description: "A list of image names to use as build cache. " +
"Images provided must have a cache manifest. " +
"Must provide authentication to cache registry.",

TypeSpec: schema.TypeSpec{
Ref: "#/types/docker:index/cacheFrom:CacheFrom",
},
Expand Down
2 changes: 1 addition & 1 deletion sdk/dotnet/Inputs/DockerBuildArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public InputMap<string> Args
public Input<Pulumi.Docker.BuilderVersion>? BuilderVersion { get; set; }

/// <summary>
/// A list of images to use as build cache
/// A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
/// </summary>
[Input("cacheFrom")]
public Input<Inputs.CacheFromArgs>? CacheFrom { get; set; }
Expand Down
6 changes: 3 additions & 3 deletions sdk/go/docker/pulumiTypes.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ public Optional<Output<BuilderVersion>> builderVersion() {
}

/**
* A list of images to use as build cache
* A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
*
*/
@Import(name="cacheFrom")
private @Nullable Output<CacheFromArgs> cacheFrom;

/**
* @return A list of images to use as build cache
* @return A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
*
*/
public Optional<Output<CacheFromArgs>> cacheFrom() {
Expand Down Expand Up @@ -201,7 +201,7 @@ public Builder builderVersion(BuilderVersion builderVersion) {
}

/**
* @param cacheFrom A list of images to use as build cache
* @param cacheFrom A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
*
* @return builder
*
Expand All @@ -212,7 +212,7 @@ public Builder cacheFrom(@Nullable Output<CacheFromArgs> cacheFrom) {
}

/**
* @param cacheFrom A list of images to use as build cache
* @param cacheFrom A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
*
* @return builder
*
Expand Down
2 changes: 1 addition & 1 deletion sdk/nodejs/types/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export interface DockerBuild {
*/
builderVersion?: pulumi.Input<enums.BuilderVersion>;
/**
* A list of images to use as build cache
* A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
*/
cacheFrom?: pulumi.Input<inputs.CacheFrom>;
/**
Expand Down
4 changes: 2 additions & 2 deletions sdk/python/pulumi_docker/_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4065,7 +4065,7 @@ def __init__(__self__, *,
The Docker build context
:param pulumi.Input[Mapping[str, pulumi.Input[str]]] args: An optional map of named build-time argument variables to set during the Docker build. This flag allows you to pass build-time variablesthat can be accessed like environment variables inside the RUN instruction.
:param pulumi.Input['BuilderVersion'] builder_version: The version of the Docker builder.
:param pulumi.Input['CacheFromArgs'] cache_from: A list of images to use as build cache
:param pulumi.Input['CacheFromArgs'] cache_from: A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
:param pulumi.Input[str] context: The path to the build context to use.
:param pulumi.Input[str] dockerfile: The path to the Dockerfile to use.
:param pulumi.Input[str] platform: The architecture of the platform you want to build this image for, e.g. `linux/arm64`.
Expand Down Expand Up @@ -4120,7 +4120,7 @@ def builder_version(self, value: Optional[pulumi.Input['BuilderVersion']]):
@pulumi.getter(name="cacheFrom")
def cache_from(self) -> Optional[pulumi.Input['CacheFromArgs']]:
"""
A list of images to use as build cache
A list of image names to use as build cache. Images provided must have a cache manifest. Must provide authentication to cache registry.
"""
return pulumi.get(self, "cache_from")

Expand Down

0 comments on commit 84f4dd6

Please sign in to comment.