mirror of https://github.com/docker/cli.git
Support for docker content trust for plugins
Add integration test for docker content trust Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
2825296deb
commit
fcaa89f296
|
@ -170,7 +170,7 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
|
||||||
|
|
||||||
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
||||||
var err error
|
var err error
|
||||||
trustedRef, err = image.TrustedReference(ctx, dockerCli, ref)
|
trustedRef, err = image.TrustedReference(ctx, dockerCli, ref, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error {
|
||||||
var resolvedTags []*resolvedTag
|
var resolvedTags []*resolvedTag
|
||||||
if command.IsTrusted() {
|
if command.IsTrusted() {
|
||||||
translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
|
translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||||
return TrustedReference(ctx, dockerCli, ref)
|
return TrustedReference(ctx, dockerCli, ref, nil)
|
||||||
}
|
}
|
||||||
// Wrap the tar archive to replace the Dockerfile entry with the rewritten
|
// Wrap the tar archive to replace the Dockerfile entry with the rewritten
|
||||||
// Dockerfile which uses trusted pulls.
|
// Dockerfile which uses trusted pulls.
|
||||||
|
|
|
@ -39,6 +39,11 @@ func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry
|
||||||
|
|
||||||
defer responseBody.Close()
|
defer responseBody.Close()
|
||||||
|
|
||||||
|
return PushTrustedReference(cli, repoInfo, ref, authConfig, responseBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushTrustedReference pushes a canonical reference to the trust server.
|
||||||
|
func PushTrustedReference(cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, in io.Reader) error {
|
||||||
// If it is a trusted push we would like to find the target entry which match the
|
// If it is a trusted push we would like to find the target entry which match the
|
||||||
// tag provided in the function and then do an AddTarget later.
|
// tag provided in the function and then do an AddTarget later.
|
||||||
target := &client.Target{}
|
target := &client.Target{}
|
||||||
|
@ -75,14 +80,14 @@ func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry
|
||||||
default:
|
default:
|
||||||
// We want trust signatures to always take an explicit tag,
|
// We want trust signatures to always take an explicit tag,
|
||||||
// otherwise it will act as an untrusted push.
|
// otherwise it will act as an untrusted push.
|
||||||
if err = jsonmessage.DisplayJSONMessagesToStream(responseBody, cli.Out(), nil); err != nil {
|
if err := jsonmessage.DisplayJSONMessagesToStream(in, cli.Out(), nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintln(cli.Out(), "No tag specified, skipping trust metadata push")
|
fmt.Fprintln(cli.Out(), "No tag specified, skipping trust metadata push")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = jsonmessage.DisplayJSONMessagesToStream(responseBody, cli.Out(), handleTarget); err != nil {
|
if err := jsonmessage.DisplayJSONMessagesToStream(in, cli.Out(), handleTarget); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +320,16 @@ func imagePullPrivileged(ctx context.Context, cli *command.DockerCli, authConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrustedReference returns the canonical trusted reference for an image reference
|
// TrustedReference returns the canonical trusted reference for an image reference
|
||||||
func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (reference.Canonical, error) {
|
func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged, rs registry.Service) (reference.Canonical, error) {
|
||||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
var (
|
||||||
|
repoInfo *registry.RepositoryInfo
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if rs != nil {
|
||||||
|
repoInfo, err = rs.ResolveRepository(ref)
|
||||||
|
} else {
|
||||||
|
repoInfo, err = registry.ParseRepositoryInfo(ref)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -332,7 +345,7 @@ func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference
|
||||||
|
|
||||||
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, trust.NotaryError(repoInfo.FullName(), err)
|
||||||
}
|
}
|
||||||
// Only list tags in the top level targets role or the releases delegation role - ignore
|
// Only list tags in the top level targets role or the releases delegation role - ignore
|
||||||
// all other delegation roles
|
// all other delegation roles
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
|
"github.com/docker/docker/cli/command/image"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
"github.com/docker/docker/reference"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
@ -46,6 +47,8 @@ func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
flags.BoolVar(&options.disable, "disable", false, "Do not enable the plugin on install")
|
flags.BoolVar(&options.disable, "disable", false, "Do not enable the plugin on install")
|
||||||
flags.StringVar(&options.alias, "alias", "", "Local name for plugin")
|
flags.StringVar(&options.alias, "alias", "", "Local name for plugin")
|
||||||
|
|
||||||
|
command.AddTrustedFlags(flags, true)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +66,24 @@ func getRepoIndexFromUnnormalizedRef(ref distreference.Named) (*registrytypes.In
|
||||||
return repoInfo.Index, nil
|
return repoInfo.Index, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pluginRegistryService struct {
|
||||||
|
registry.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s pluginRegistryService) ResolveRepository(name reference.Named) (repoInfo *registry.RepositoryInfo, err error) {
|
||||||
|
repoInfo, err = s.Service.ResolveRepository(name)
|
||||||
|
if repoInfo != nil {
|
||||||
|
repoInfo.Class = "plugin"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRegistryService() registry.Service {
|
||||||
|
return pluginRegistryService{
|
||||||
|
Service: registry.NewService(registry.ServiceOptions{V2Only: true}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
||||||
// Parse name using distribution reference package to support name
|
// Parse name using distribution reference package to support name
|
||||||
// containing both tag and digest. Names with both tag and digest
|
// containing both tag and digest. Names with both tag and digest
|
||||||
|
@ -85,13 +106,41 @@ func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
||||||
}
|
}
|
||||||
alias = aref.String()
|
alias = aref.String()
|
||||||
}
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
index, err := getRepoIndexFromUnnormalizedRef(ref)
|
index, err := getRepoIndexFromUnnormalizedRef(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
remote := ref.String()
|
||||||
|
|
||||||
|
_, isCanonical := ref.(distreference.Canonical)
|
||||||
|
if command.IsTrusted() && !isCanonical {
|
||||||
|
if alias == "" {
|
||||||
|
alias = ref.String()
|
||||||
|
}
|
||||||
|
var nt reference.NamedTagged
|
||||||
|
named, err := reference.ParseNamed(ref.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if tagged, ok := ref.(distreference.Tagged); ok {
|
||||||
|
nt, err = reference.WithTag(named, tagged.Tag())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
named = reference.WithDefaultTag(named)
|
||||||
|
nt = named.(reference.NamedTagged)
|
||||||
|
}
|
||||||
|
|
||||||
|
trusted, err := image.TrustedReference(ctx, dockerCli, nt, newRegistryService())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
remote = trusted.String()
|
||||||
|
}
|
||||||
|
|
||||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, index)
|
authConfig := command.ResolveAuthConfig(ctx, dockerCli, index)
|
||||||
|
|
||||||
|
@ -104,7 +153,7 @@ func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
||||||
|
|
||||||
options := types.PluginInstallOptions{
|
options := types.PluginInstallOptions{
|
||||||
RegistryAuth: encodedAuth,
|
RegistryAuth: encodedAuth,
|
||||||
RemoteRef: ref.String(),
|
RemoteRef: remote,
|
||||||
Disabled: opts.disable,
|
Disabled: opts.disable,
|
||||||
AcceptAllPermissions: opts.grantPerms,
|
AcceptAllPermissions: opts.grantPerms,
|
||||||
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.name),
|
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.name),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
|
"github.com/docker/docker/cli/command/image"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
"github.com/docker/docker/reference"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
@ -22,6 +23,11 @@ func newPushCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
return runPush(dockerCli, args[0])
|
return runPush(dockerCli, args[0])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags := cmd.Flags()
|
||||||
|
|
||||||
|
command.AddTrustedFlags(flags, true)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,5 +61,11 @@ func runPush(dockerCli *command.DockerCli, name string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer responseBody.Close()
|
defer responseBody.Close()
|
||||||
|
|
||||||
|
if command.IsTrusted() {
|
||||||
|
repoInfo.Class = "plugin"
|
||||||
|
return image.PushTrustedReference(dockerCli, repoInfo, named, authConfig, responseBody)
|
||||||
|
}
|
||||||
|
|
||||||
return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil)
|
return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,8 +147,19 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope := auth.RepositoryScope{
|
||||||
|
Repository: repoInfo.FullName(),
|
||||||
|
Actions: actions,
|
||||||
|
Class: repoInfo.Class,
|
||||||
|
}
|
||||||
creds := simpleCredentialStore{auth: authConfig}
|
creds := simpleCredentialStore{auth: authConfig}
|
||||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoInfo.FullName(), actions...)
|
tokenHandlerOptions := auth.TokenHandlerOptions{
|
||||||
|
Transport: authTransport,
|
||||||
|
Credentials: creds,
|
||||||
|
Scopes: []auth.Scope{scope},
|
||||||
|
ClientID: registry.AuthClientID,
|
||||||
|
}
|
||||||
|
tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
|
||||||
basicHandler := auth.NewBasicHandler(creds)
|
basicHandler := auth.NewBasicHandler(creds)
|
||||||
modifiers = append(modifiers, transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)))
|
modifiers = append(modifiers, transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)))
|
||||||
tr := transport.NewTransport(base, modifiers...)
|
tr := transport.NewTransport(base, modifiers...)
|
||||||
|
|
Loading…
Reference in New Issue