Experimental Notary Support for Helm

Notary v1 is the initial implementation of theUpdateFramework.
This framework basically helps understand the security issues,
that come up when updating a repo and addresses them by
adding multilevel signature checking.

Using Notary OCI Artifacts can also be provenance checked. and
Helm Charts can also benefit from it. With that in mind,
there needs to be an interface between pushing and pulling the
charts, to and from the remote registries, to check if the right
chart is being downloaded.

Here --sign is used with helm chart pull/push to verify/set
signatures in Notary.

--ca-cert is given to set the CA Cert
--trust-server would be the Notary Server
--trust-dir would be the directory used instead of the trust server

Co-authored-by: Radu Matei <root@radu.sh>
Co-authored-by: Vibhav Bobade <vibhav.bobde@gmail.com>
Signed-off-by: Vibhav Bobade <vibhav.bobde@gmail.com>
pull/7829/head
Vibhav Bobade 6 years ago
parent c2da4fd53d
commit 4a83bb5c3b

@ -17,7 +17,17 @@ limitations under the License.
package main package main
import ( import (
"encoding/hex"
"fmt"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/trustpinning"
"github.com/theupdateframework/notary/tuf/data"
"helm.sh/helm/v3/internal/experimental/registry"
"helm.sh/helm/v3/pkg/helmpath"
"io" "io"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -32,7 +42,8 @@ This will store the chart in the local registry cache to be used later.
` `
func newChartPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newChartPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return &cobra.Command{ signOpts := &signatureOptions{}
cmd := &cobra.Command{
Use: "pull [ref]", Use: "pull [ref]",
Short: "pull a chart from remote", Short: "pull a chart from remote",
Long: chartPullDesc, Long: chartPullDesc,
@ -40,7 +51,107 @@ func newChartPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Hidden: !FeatureGateOCI.IsEnabled(), Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0] ref := args[0]
return action.NewChartPull(cfg).Run(out, ref) err := action.NewChartPull(cfg).Run(out, ref)
if err != nil {
return err
}
if signOpts.Sign {
sha, err := GetSHA(signOpts.trustDir, signOpts.trustServer, ref, signOpts.caCert, signOpts.rootKey)
if err != nil {
return err
}
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
c, err := registry.NewCache(
registry.CacheOptWriter(out),
registry.CacheOptRoot(filepath.Join(helmpath.CachePath(), "registry", registry.CacheRootDir)))
cs, err := c.FetchReference(r)
if err != nil {
return err
}
if cs.Digest.Hex() != sha {
fmt.Fprintf(out, "digests do not match: %v and %v", cs.Digest.Hex(), sha)
_, err = c.DeleteReference(r)
return err
}
}
return nil
}, },
} }
td := filepath.Join(helmpath.ConfigPath(), ".trust")
cmd.Flags().StringVarP(&signOpts.trustServer, "trust-server", "", "", "The trust server to use for signature verification")
cmd.Flags().StringVarP(&signOpts.trustDir, "trust-dir", "", td, "Location where trust data is stored")
cmd.Flags().StringVarP(&signOpts.rootKey, "root-key", "", "", "Root Key to initialize repository with")
cmd.Flags().StringVarP(&signOpts.caCert, "ca-cert", "", "", "Trust certs signed only by this CA will be considered")
cmd.Flags().BoolVarP(&signOpts.Sign, "sign", "", true, "Enable signature checking")
return cmd
}
func GetSHA(trustDir, trustServer, ref, tlscacert, rootKey string) (string, error) {
r, tag := GetRepoAndTag(ref)
target, err := GetTargetWithRole(r, tag, trustServer, tlscacert, trustDir)
if err != nil {
return "", err
}
return hex.EncodeToString(target.Hashes["sha256"]), nil
} }
func GetRepoAndTag(ref string) (string, string) {
parts := strings.Split(ref, "/")
return strings.Split(parts[1], ":")[0], strings.Split(parts[1], ":")[1]
}
func GetTargetWithRole(gun, name, trustServer, tlscacert, trustDir string) (*client.TargetWithRole, error) {
targets, err := GetTargets(gun, trustServer, tlscacert, trustDir)
if err != nil {
return nil, fmt.Errorf("cannot list targets:%v", err)
}
for _, target := range targets {
if target.Name == name {
return target, nil
}
}
return nil, fmt.Errorf("cannot find target %v in trusted collection %v", name, gun)
}
// GetTargets returns all targets for a given gun from the trusted collection
func GetTargets(gun, trustServer, tlscacert, trustDir string) ([]*client.TargetWithRole, error) {
if err := ensureTrustDir(trustDir); err != nil {
return nil, fmt.Errorf("cannot ensure trust directory: %v", err)
}
transport, err := action.MakeTransport(trustServer, gun, tlscacert)
if err != nil {
return nil, fmt.Errorf("cannot make transport: %v", err)
}
repo, err := client.NewFileCachedRepository(
trustDir,
data.GUN(gun),
trustServer,
transport,
nil,
trustpinning.TrustPinConfig{},
)
if err != nil {
return nil, fmt.Errorf("cannot create new file cached repository: %v", err)
}
return repo.ListTargets()
}
// ensureTrustDir ensures the trust directory exists
func ensureTrustDir(trustDir string) error {
return os.MkdirAll(trustDir, 0700)
}

@ -17,7 +17,9 @@ limitations under the License.
package main package main
import ( import (
"helm.sh/helm/v3/pkg/helmpath"
"io" "io"
"path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -33,8 +35,18 @@ Note: the ref must already exist in the local registry cache.
Must first run "helm chart save" or "helm chart pull". Must first run "helm chart save" or "helm chart pull".
` `
// Used if --check-signature flag is used
type signatureOptions struct {
Sign bool
trustServer string
trustDir string
caCert string
rootKey string
}
func newChartPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newChartPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return &cobra.Command{ signOpts := &signatureOptions{}
cmd := &cobra.Command{
Use: "push [ref]", Use: "push [ref]",
Short: "push a chart to remote", Short: "push a chart to remote",
Long: chartPushDesc, Long: chartPushDesc,
@ -42,7 +54,28 @@ func newChartPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Hidden: !FeatureGateOCI.IsEnabled(), Hidden: !FeatureGateOCI.IsEnabled(),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0] ref := args[0]
if signOpts.Sign {
err := action.NewChartSign(
cfg,
signOpts.trustServer,
signOpts.trustDir,
signOpts.caCert,
signOpts.rootKey).Run(out, ref)
if err != nil {
return err
}
}
return action.NewChartPush(cfg).Run(out, ref) return action.NewChartPush(cfg).Run(out, ref)
}, },
} }
td := filepath.Join(helmpath.ConfigPath(), ".trust")
cmd.Flags().StringVarP(&signOpts.trustServer, "trust-server", "", "", "The trust server to use for signature verification")
cmd.Flags().StringVarP(&signOpts.trustDir, "trust-dir", "", td, "Location where trust data is stored")
cmd.Flags().StringVarP(&signOpts.rootKey, "root-key", "", "", "Root Key to initialize repository with")
cmd.Flags().StringVarP(&signOpts.caCert, "ca-cert", "", "", "Trust certs signed only by this CA will be considered")
cmd.Flags().BoolVarP(&signOpts.Sign, "sign", "", true, "Enable signature checking")
return cmd
} }

@ -11,8 +11,10 @@ require (
github.com/containerd/containerd v1.3.2 github.com/containerd/containerd v1.3.2
github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin v0.2.2
github.com/deislabs/oras v0.8.1 github.com/deislabs/oras v0.8.1
github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492
github.com/docker/distribution v2.7.1+incompatible github.com/docker/distribution v2.7.1+incompatible
github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce
github.com/docker/go v1.5.1-1 // indirect
github.com/docker/go-units v0.4.0 github.com/docker/go-units v0.4.0
github.com/evanphx/json-patch v4.5.0+incompatible github.com/evanphx/json-patch v4.5.0+incompatible
github.com/gobwas/glob v0.2.3 github.com/gobwas/glob v0.2.3
@ -27,6 +29,7 @@ require (
github.com/spf13/cobra v0.0.5 github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
github.com/theupdateframework/notary v0.6.1
github.com/xeipuuv/gojsonschema v1.1.0 github.com/xeipuuv/gojsonschema v1.1.0
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
k8s.io/api v0.18.0 k8s.io/api v0.18.0
@ -37,6 +40,7 @@ require (
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0
k8s.io/kubectl v0.18.0 k8s.io/kubectl v0.18.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412
) )
replace ( replace (

@ -48,6 +48,9 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 h1:iPf1jQ8yKTms6k6L5vYSE7RZJpjEe5vLTOmzRZdpnKc=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -129,6 +132,8 @@ github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce h1:KXS1Jg+ddGcWA8e
github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k=
github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 h1:yWHOI+vFjEsAakUTSrtqc/SAHrhSkmn48pqjidZX3QA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 h1:yWHOI+vFjEsAakUTSrtqc/SAHrhSkmn48pqjidZX3QA=
@ -459,6 +464,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0=
github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=

@ -0,0 +1,302 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/types"
"github.com/docker/distribution/registry/client/auth"
"github.com/docker/distribution/registry/client/auth/challenge"
"github.com/docker/distribution/registry/client/transport"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/cryptoservice"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustmanager"
"github.com/theupdateframework/notary/trustpinning"
"github.com/theupdateframework/notary/tuf/data"
"github.com/theupdateframework/notary/tuf/utils"
"helm.sh/helm/v3/internal/experimental/registry"
"helm.sh/helm/v3/pkg/helmpath"
)
// ChartPush performs a chart sign operation
type ChartSign struct {
cfg *Configuration
trustDir string
trustServer string
ref string
caCert string
rootKey string
}
// NewChartPush creates a new ChartPush object with the given configuration.
func NewChartSign(cfg *Configuration, trustServer, ref, caCert, rootKey string) *ChartSign {
return &ChartSign{
cfg: cfg,
trustServer: trustServer,
ref: ref,
caCert: caCert,
rootKey: rootKey,
}
}
// Run executes the chart push operation
func (a *ChartSign) Run(out io.Writer, ref string) error {
// Init Registry Cache
cacheDir := filepath.Join(helmpath.CachePath(), "registry", registry.CacheRootDir)
cache, err := registry.NewCache(registry.CacheOptWriter(out), registry.CacheOptRoot(cacheDir))
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
cacheSummary, err := cache.FetchReference(r)
if err != nil {
return err
}
cachedChart := filepath.Join(cacheDir, "blobs", "sha256", strings.Split(cacheSummary.Digest.String(), ":")[1])
/// Export to action and tuf experimental
transport, err := MakeTransport(a.trustServer, r.Repo, a.caCert)
if err != nil {
return fmt.Errorf("cannot make transport: %v", err)
}
passphraseRetriever := passphrase.PromptRetriever()
repo, err := client.NewFileCachedRepository(
a.trustDir,
data.GUN(r.Repo),
a.trustServer,
transport,
passphraseRetriever,
trustpinning.TrustPinConfig{},
)
if err != nil {
return fmt.Errorf("cannot create new file cached repository: %v", err)
}
err = clearChangeList(repo)
if err != nil {
return fmt.Errorf("cannot clear change list: %v", err)
}
if _, err = repo.ListTargets(); err != nil {
switch err.(type) {
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
rootKeyIDs, err := importRootKey(a.rootKey, repo, passphraseRetriever)
if err != nil {
return err
}
if err = repo.Initialize(rootKeyIDs); err != nil {
return fmt.Errorf("cannot initialize repo: %v", err)
}
default:
return fmt.Errorf("cannot list targets: %v", err)
}
}
target, err := client.NewTarget(r.Tag, cachedChart, nil)
if err != nil {
return err
}
// TODO - Radu M
// decide whether to allow actually passing roles as flags
// If roles is empty, we default to adding to targets
if err = repo.AddTarget(target, data.NewRoleList([]string{})...); err != nil {
return err
}
err = repo.Publish()
defer clearChangeList(repo)
return err
}
func MakeTransport(server, gun, tlsCaCert string) (http.RoundTripper, error) {
modifiers := []transport.RequestModifier{
transport.NewHeaderRequestModifier(http.Header{
"User-Agent": []string{"signy"},
}),
}
base := http.DefaultTransport
if tlsCaCert != "" {
caCert, err := ioutil.ReadFile(tlsCaCert)
if err != nil {
return nil, fmt.Errorf("cannot read cert file: %v", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
base = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
},
}
}
authTransport := transport.NewTransport(base, modifiers...)
pingClient := &http.Client{
Transport: authTransport,
Timeout: 5 * time.Second,
}
req, err := http.NewRequest("GET", server+"/v2/", nil)
if err != nil {
return nil, fmt.Errorf("cannot create HTTP request: %v", err)
}
challengeManager := challenge.NewSimpleManager()
resp, err := pingClient.Do(req)
if err != nil {
return nil, fmt.Errorf("cannot get response from ping client: %v", err)
}
defer resp.Body.Close()
if err := challengeManager.AddResponse(resp); err != nil {
return nil, fmt.Errorf("cannot add response to challenge manager: %v", err)
}
defaultAuth, err := getDefaultAuth()
if err != nil {
return nil, fmt.Errorf("cannot get default credentials: %v", err)
}
creds := simpleCredentialStore{auth: defaultAuth}
tokenHandler := auth.NewTokenHandler(base, creds, gun, "push", "pull")
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler))
return transport.NewTransport(base, modifiers...), nil
}
// clearChangelist clears the notary staging changelist
func clearChangeList(notaryRepo client.Repository) error {
cl, err := notaryRepo.GetChangelist()
if err != nil {
return err
}
return cl.Clear("")
}
func getDefaultAuth() (types.AuthConfig, error) {
cfg, err := config.Load(defaultCfgDir())
if err != nil {
return types.AuthConfig{}, err
}
return cfg.AuthConfigs["https://index.docker.io/v1/"], nil
}
type simpleCredentialStore struct {
auth types.AuthConfig
}
func (scs simpleCredentialStore) Basic(u *url.URL) (string, string) {
return scs.auth.Username, scs.auth.Password
}
func (scs simpleCredentialStore) RefreshToken(u *url.URL, service string) string {
return scs.auth.IdentityToken
}
func (scs simpleCredentialStore) SetRefreshToken(*url.URL, string, string) {
}
func defaultCfgDir() string {
homeEnvPath := os.Getenv("HOME")
if homeEnvPath == "" && runtime.GOOS == "windows" {
homeEnvPath = os.Getenv("USERPROFILE")
}
return filepath.Join(homeEnvPath, ".docker")
}
func importRootKey(rootKey string, nRepo client.Repository, retriever notary.PassRetriever) ([]string, error) {
var rootKeyList []string
if rootKey != "" {
privKey, err := readKey(data.CanonicalRootRole, rootKey, retriever)
if err != nil {
return nil, err
}
// add root key to repo
err = nRepo.GetCryptoService().AddKey(data.CanonicalRootRole, "", privKey)
if err != nil {
return nil, fmt.Errorf("Error importing key: %v", err)
}
rootKeyList = []string{privKey.ID()}
} else {
rootKeyList = nRepo.GetCryptoService().ListKeys(data.CanonicalRootRole)
}
if len(rootKeyList) > 0 {
// Chooses the first root key available, which is initialization specific
// but should return the HW one first.
rootKeyID := rootKeyList[0]
fmt.Printf("Root key found, using: %s\n", rootKeyID)
return []string{rootKeyID}, nil
}
return []string{}, nil
}
func readKey(role data.RoleName, keyFilename string, retriever notary.PassRetriever) (data.PrivateKey, error) {
pemBytes, err := ioutil.ReadFile(keyFilename)
if err != nil {
return nil, fmt.Errorf("Error reading input root key file: %v", err)
}
isEncrypted := true
if err = cryptoservice.CheckRootKeyIsEncrypted(pemBytes); err != nil {
if role == data.CanonicalRootRole {
return nil, err
}
isEncrypted = false
}
var privKey data.PrivateKey
if isEncrypted {
privKey, _, err = trustmanager.GetPasswdDecryptBytes(retriever, pemBytes, "", data.CanonicalRootRole.String())
} else {
privKey, err = utils.ParsePEMPrivateKey(pemBytes, "")
}
if err != nil {
return nil, err
}
return privKey, nil
}
Loading…
Cancel
Save