Remove trust package

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2015-09-16 13:28:19 -07:00
parent 011bfd666e
commit cba4bbad4f
9 changed files with 0 additions and 694 deletions

View file

@ -50,7 +50,6 @@ import (
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/registry"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/trust"
volumedrivers "github.com/docker/docker/volume/drivers"
"github.com/docker/docker/volume/local"
"github.com/docker/docker/volume/store"
@ -738,10 +737,6 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
if err := system.MkdirAll(trustDir, 0700); err != nil {
return nil, err
}
trustService, err := trust.NewStore(trustDir)
if err != nil {
return nil, fmt.Errorf("could not create trust store: %s", err)
}
eventsService := events.New()
logrus.Debug("Creating repository list")
@ -750,7 +745,6 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
Key: trustKey,
Registry: registryService,
Events: eventsService,
Trust: trustService,
}
repositories, err := graph.NewTagStore(filepath.Join(config.Root, "repositories-"+d.driver.String()), tagCfg)
if err != nil {

View file

@ -101,12 +101,6 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
for _, endpoint := range endpoints {
logrus.Debugf("Trying to pull %s from %s %s", repoInfo.LocalName, endpoint.URL, endpoint.Version)
if !endpoint.Mirror && (endpoint.Official || endpoint.Version == registry.APIVersion2) {
if repoInfo.Official {
s.trustService.UpdateBase()
}
}
puller, err := NewPuller(s, endpoint, repoInfo, imagePullConfig, sf)
if err != nil {
lastErr = err

View file

@ -20,7 +20,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/registry"
"github.com/docker/docker/trust"
"github.com/docker/docker/utils"
"github.com/docker/libtrust"
)
@ -41,7 +40,6 @@ type TagStore struct {
pushingPool map[string]*broadcaster.Buffered
registryService *registry.Service
eventsService *events.Events
trustService *trust.Store
}
// Repository maps tags to image IDs.
@ -77,8 +75,6 @@ type TagStoreConfig struct {
Registry *registry.Service
// Events is the events service to use for logging.
Events *events.Events
// Trust is the trust service to use for push and pull operations.
Trust *trust.Store
}
// NewTagStore creates a new TagStore at specified path, using the parameters
@ -98,7 +94,6 @@ func NewTagStore(path string, cfg *TagStoreConfig) (*TagStore, error) {
pushingPool: make(map[string]*broadcaster.Buffered),
registryService: cfg.Registry,
eventsService: cfg.Events,
trustService: cfg.Trust,
}
// Load the json file if it exists, otherwise create it.
if err := store.reload(); os.IsNotExist(err) {

View file

@ -13,7 +13,6 @@ import (
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
"github.com/docker/docker/graph/tags"
"github.com/docker/docker/image"
"github.com/docker/docker/trust"
"github.com/docker/docker/utils"
)
@ -63,15 +62,9 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
t.Fatal(err)
}
trust, err := trust.NewStore(root + "/trust")
if err != nil {
t.Fatal(err)
}
tagCfg := &TagStoreConfig{
Graph: graph,
Events: events.New(),
Trust: trust,
}
store, err := NewTagStore(path.Join(root, "tags"), tagCfg)
if err != nil {

View file

@ -1,59 +0,0 @@
package trust
import (
"fmt"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/libtrust"
)
// NotVerifiedError reports a error when doing the key check.
// For example if the graph is not verified or the key has expired.
type NotVerifiedError string
func (e NotVerifiedError) Error() string {
return string(e)
}
// CheckKey verifies that the given public key is allowed to perform
// the given action on the given node according to the trust graph.
func (t *Store) CheckKey(ns string, key []byte, perm uint16) (bool, error) {
if len(key) == 0 {
return false, fmt.Errorf("Missing PublicKey")
}
pk, err := libtrust.UnmarshalPublicKeyJWK(key)
if err != nil {
return false, fmt.Errorf("Error unmarshalling public key: %v", err)
}
if perm == 0 {
perm = 0x03
}
t.RLock()
defer t.RUnlock()
if t.graph == nil {
return false, NotVerifiedError("no graph")
}
// Check if any expired grants
verified, err := t.graph.Verify(pk, ns, perm)
if err != nil {
return false, fmt.Errorf("Error verifying key to namespace: %s", ns)
}
if !verified {
logrus.Debugf("Verification failed for %s using key %s", ns, pk.KeyID())
return false, NotVerifiedError("not verified")
}
if t.expiration.Before(time.Now()) {
return false, NotVerifiedError("expired")
}
return true, nil
}
// UpdateBase retrieves updated base graphs. This function cannot error, it
// should only log errors.
func (t *Store) UpdateBase() {
t.fetch()
}

View file

@ -1,201 +0,0 @@
package trust
import (
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"sync"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/libtrust/trustgraph"
)
// Store defines a TrustStore : stores trusted certificates and permissions
// which are used to verify the signature keys on manifests.
// Note: This is being deprecated by the notary work.
type Store struct {
path string
caPool *x509.CertPool
graph trustgraph.TrustGraph
expiration time.Time
fetcher *time.Timer
fetchTime time.Duration
autofetch bool
httpClient *http.Client
baseEndpoints map[string]*url.URL
sync.RWMutex
}
// defaultFetchtime represents the starting duration to wait between
// fetching sections of the graph. Unsuccessful fetches should
// increase time between fetching.
const defaultFetchtime = 45 * time.Second
var baseEndpoints = map[string]string{"official": "https://dvjy3tqbc323p.cloudfront.net/trust/official.json"}
// NewStore creates a TrustStore from a given path, if the path is not
// relative, it will be joined with the working directory.
func NewStore(path string) (*Store, error) {
abspath, err := filepath.Abs(path)
if err != nil {
return nil, err
}
// Create base graph url map
endpoints := map[string]*url.URL{}
for name, endpoint := range baseEndpoints {
u, err := url.Parse(endpoint)
if err != nil {
return nil, err
}
endpoints[name] = u
}
// Load grant files
t := &Store{
path: abspath,
caPool: nil,
httpClient: &http.Client{},
fetchTime: time.Millisecond,
baseEndpoints: endpoints,
}
if err := t.reload(); err != nil {
return nil, err
}
return t, nil
}
func (t *Store) reload() error {
t.Lock()
defer t.Unlock()
matches, err := filepath.Glob(filepath.Join(t.path, "*.json"))
if err != nil {
return err
}
statements := make([]*trustgraph.Statement, len(matches))
for i, match := range matches {
f, err := os.Open(match)
if err != nil {
return fmt.Errorf("Error opening %q: %s", match, err)
}
statements[i], err = trustgraph.LoadStatement(f, nil)
if err != nil {
f.Close()
return fmt.Errorf("Error loading %q: %s", match, err)
}
f.Close()
}
if len(statements) == 0 {
if t.autofetch {
logrus.Debugf("No grants, fetching")
t.fetcher = time.AfterFunc(t.fetchTime, t.fetch)
}
return nil
}
grants, expiration, err := trustgraph.CollapseStatements(statements, true)
if err != nil {
return err
}
t.expiration = expiration
t.graph = trustgraph.NewMemoryGraph(grants)
logrus.Debugf("Reloaded graph with %d grants expiring at %s", len(grants), expiration)
if t.autofetch {
nextFetch := expiration.Sub(time.Now())
if nextFetch < 0 {
nextFetch = defaultFetchtime
} else {
nextFetch = time.Duration(0.8 * (float64)(nextFetch))
}
t.fetcher = time.AfterFunc(nextFetch, t.fetch)
}
return nil
}
func (t *Store) fetchBaseGraph(u *url.URL) (*trustgraph.Statement, error) {
req := &http.Request{
Method: "GET",
URL: u,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: make(http.Header),
Body: nil,
Host: u.Host,
}
resp, err := t.httpClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode == 404 {
return nil, errors.New("base graph does not exist")
}
defer resp.Body.Close()
return trustgraph.LoadStatement(resp.Body, t.caPool)
}
// fetch retrieves updated base graphs. This function cannot error, it
// should only log errors
func (t *Store) fetch() {
t.Lock()
defer t.Unlock()
if t.autofetch && t.fetcher == nil {
// Do nothing ??
return
}
fetchCount := 0
for bg, ep := range t.baseEndpoints {
statement, err := t.fetchBaseGraph(ep)
if err != nil {
logrus.Infof("Trust graph fetch failed: %s", err)
continue
}
b, err := statement.Bytes()
if err != nil {
logrus.Infof("Bad trust graph statement: %s", err)
continue
}
// TODO check if value differs
if err := ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600); err != nil {
logrus.Infof("Error writing trust graph statement: %s", err)
}
fetchCount++
}
logrus.Debugf("Fetched %d base graphs at %s", fetchCount, time.Now())
if fetchCount > 0 {
go func() {
if err := t.reload(); err != nil {
logrus.Infof("Reload of trust graph failed: %s", err)
}
}()
t.fetchTime = defaultFetchtime
t.fetcher = nil
} else if t.autofetch {
maxTime := 10 * defaultFetchtime
t.fetchTime = time.Duration(1.5 * (float64)(t.fetchTime+time.Second))
if t.fetchTime > maxTime {
t.fetchTime = maxTime
}
t.fetcher = time.AfterFunc(t.fetchTime, t.fetch)
}
}

View file

@ -1,50 +0,0 @@
package trustgraph
import "github.com/docker/libtrust"
// TrustGraph represents a graph of authorization mapping
// public keys to nodes and grants between nodes.
type TrustGraph interface {
// Verifies that the given public key is allowed to perform
// the given action on the given node according to the trust
// graph.
Verify(libtrust.PublicKey, string, uint16) (bool, error)
// GetGrants returns an array of all grant chains which are used to
// allow the requested permission.
GetGrants(libtrust.PublicKey, string, uint16) ([][]*Grant, error)
}
// Grant represents a transfer of permission from one part of the
// trust graph to another. This is the only way to delegate
// permission between two different sub trees in the graph.
type Grant struct {
// Subject is the namespace being granted
Subject string
// Permissions is a bit map of permissions
Permission uint16
// Grantee represents the node being granted
// a permission scope. The grantee can be
// either a namespace item or a key id where namespace
// items will always start with a '/'.
Grantee string
// statement represents the statement used to create
// this object.
statement *Statement
}
// Permissions
// Read node 0x01 (can read node, no sub nodes)
// Write node 0x02 (can write to node object, cannot create subnodes)
// Read subtree 0x04 (delegates read to each sub node)
// Write subtree 0x08 (delegates write to each sub node, included create on the subject)
//
// Permission shortcuts
// ReadItem = 0x01
// WriteItem = 0x03
// ReadAccess = 0x07
// WriteAccess = 0x0F
// Delegate = 0x0F

View file

@ -1,133 +0,0 @@
package trustgraph
import (
"strings"
"github.com/docker/libtrust"
)
type grantNode struct {
grants []*Grant
children map[string]*grantNode
}
type memoryGraph struct {
roots map[string]*grantNode
}
func newGrantNode() *grantNode {
return &grantNode{
grants: []*Grant{},
children: map[string]*grantNode{},
}
}
// NewMemoryGraph returns a new in memory trust graph created from
// a static list of grants. This graph is immutable after creation
// and any alterations should create a new instance.
func NewMemoryGraph(grants []*Grant) TrustGraph {
roots := map[string]*grantNode{}
for _, grant := range grants {
parts := strings.Split(grant.Grantee, "/")
nodes := roots
var node *grantNode
var nodeOk bool
for _, part := range parts {
node, nodeOk = nodes[part]
if !nodeOk {
node = newGrantNode()
nodes[part] = node
}
if part != "" {
node.grants = append(node.grants, grant)
}
nodes = node.children
}
}
return &memoryGraph{roots}
}
func (g *memoryGraph) getGrants(name string) []*Grant {
nameParts := strings.Split(name, "/")
nodes := g.roots
var node *grantNode
var nodeOk bool
for _, part := range nameParts {
node, nodeOk = nodes[part]
if !nodeOk {
return nil
}
nodes = node.children
}
return node.grants
}
func isSubName(name, sub string) bool {
if strings.HasPrefix(name, sub) {
if len(name) == len(sub) || name[len(sub)] == '/' {
return true
}
}
return false
}
type walkFunc func(*Grant, []*Grant) bool
func foundWalkFunc(*Grant, []*Grant) bool {
return true
}
func (g *memoryGraph) walkGrants(start, target string, permission uint16, f walkFunc, chain []*Grant, visited map[*Grant]bool, collect bool) bool {
if visited == nil {
visited = map[*Grant]bool{}
}
grants := g.getGrants(start)
subGrants := make([]*Grant, 0, len(grants))
for _, grant := range grants {
if visited[grant] {
continue
}
visited[grant] = true
if grant.Permission&permission == permission {
if isSubName(target, grant.Subject) {
if f(grant, chain) {
return true
}
} else {
subGrants = append(subGrants, grant)
}
}
}
for _, grant := range subGrants {
var chainCopy []*Grant
if collect {
chainCopy = make([]*Grant, len(chain)+1)
copy(chainCopy, chain)
chainCopy[len(chainCopy)-1] = grant
} else {
chainCopy = nil
}
if g.walkGrants(grant.Subject, target, permission, f, chainCopy, visited, collect) {
return true
}
}
return false
}
func (g *memoryGraph) Verify(key libtrust.PublicKey, node string, permission uint16) (bool, error) {
return g.walkGrants(key.KeyID(), node, permission, foundWalkFunc, nil, nil, false), nil
}
func (g *memoryGraph) GetGrants(key libtrust.PublicKey, node string, permission uint16) ([][]*Grant, error) {
grants := [][]*Grant{}
collect := func(grant *Grant, chain []*Grant) bool {
grantChain := make([]*Grant, len(chain)+1)
copy(grantChain, chain)
grantChain[len(grantChain)-1] = grant
grants = append(grants, grantChain)
return false
}
g.walkGrants(key.KeyID(), node, permission, collect, nil, nil, true)
return grants, nil
}

View file

@ -1,227 +0,0 @@
package trustgraph
import (
"crypto/x509"
"encoding/json"
"io"
"io/ioutil"
"sort"
"strings"
"time"
"github.com/docker/libtrust"
)
type jsonGrant struct {
Subject string `json:"subject"`
Permission uint16 `json:"permission"`
Grantee string `json:"grantee"`
}
type jsonRevocation struct {
Subject string `json:"subject"`
Revocation uint16 `json:"revocation"`
Grantee string `json:"grantee"`
}
type jsonStatement struct {
Revocations []*jsonRevocation `json:"revocations"`
Grants []*jsonGrant `json:"grants"`
Expiration time.Time `json:"expiration"`
IssuedAt time.Time `json:"issuedAt"`
}
func (g *jsonGrant) Grant(statement *Statement) *Grant {
return &Grant{
Subject: g.Subject,
Permission: g.Permission,
Grantee: g.Grantee,
statement: statement,
}
}
// Statement represents a set of grants made from a verifiable
// authority. A statement has an expiration associated with it
// set by the authority.
type Statement struct {
jsonStatement
signature *libtrust.JSONSignature
}
// IsExpired returns whether the statement has expired
func (s *Statement) IsExpired() bool {
return s.Expiration.Before(time.Now().Add(-10 * time.Second))
}
// Bytes returns an indented json representation of the statement
// in a byte array. This value can be written to a file or stream
// without alteration.
func (s *Statement) Bytes() ([]byte, error) {
return s.signature.PrettySignature("signatures")
}
// LoadStatement loads and verifies a statement from an input stream.
func LoadStatement(r io.Reader, authority *x509.CertPool) (*Statement, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
js, err := libtrust.ParsePrettySignature(b, "signatures")
if err != nil {
return nil, err
}
payload, err := js.Payload()
if err != nil {
return nil, err
}
var statement Statement
err = json.Unmarshal(payload, &statement.jsonStatement)
if err != nil {
return nil, err
}
if authority == nil {
_, err = js.Verify()
if err != nil {
return nil, err
}
} else {
_, err = js.VerifyChains(authority)
if err != nil {
return nil, err
}
}
statement.signature = js
return &statement, nil
}
// CreateStatements creates and signs a statement from a stream of grants
// and revocations in a JSON array.
func CreateStatement(grants, revocations io.Reader, expiration time.Duration, key libtrust.PrivateKey, chain []*x509.Certificate) (*Statement, error) {
var statement Statement
err := json.NewDecoder(grants).Decode(&statement.jsonStatement.Grants)
if err != nil {
return nil, err
}
err = json.NewDecoder(revocations).Decode(&statement.jsonStatement.Revocations)
if err != nil {
return nil, err
}
statement.jsonStatement.Expiration = time.Now().UTC().Add(expiration)
statement.jsonStatement.IssuedAt = time.Now().UTC()
b, err := json.MarshalIndent(&statement.jsonStatement, "", " ")
if err != nil {
return nil, err
}
statement.signature, err = libtrust.NewJSONSignature(b)
if err != nil {
return nil, err
}
err = statement.signature.SignWithChain(key, chain)
if err != nil {
return nil, err
}
return &statement, nil
}
type statementList []*Statement
func (s statementList) Len() int {
return len(s)
}
func (s statementList) Less(i, j int) bool {
return s[i].IssuedAt.Before(s[j].IssuedAt)
}
func (s statementList) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// CollapseStatements returns a single list of the valid statements as well as the
// time when the next grant will expire.
func CollapseStatements(statements []*Statement, useExpired bool) ([]*Grant, time.Time, error) {
sorted := make(statementList, 0, len(statements))
for _, statement := range statements {
if useExpired || !statement.IsExpired() {
sorted = append(sorted, statement)
}
}
sort.Sort(sorted)
var minExpired time.Time
var grantCount int
roots := map[string]*grantNode{}
for i, statement := range sorted {
if statement.Expiration.Before(minExpired) || i == 0 {
minExpired = statement.Expiration
}
for _, grant := range statement.Grants {
parts := strings.Split(grant.Grantee, "/")
nodes := roots
g := grant.Grant(statement)
grantCount = grantCount + 1
for _, part := range parts {
node, nodeOk := nodes[part]
if !nodeOk {
node = newGrantNode()
nodes[part] = node
}
node.grants = append(node.grants, g)
nodes = node.children
}
}
for _, revocation := range statement.Revocations {
parts := strings.Split(revocation.Grantee, "/")
nodes := roots
var node *grantNode
var nodeOk bool
for _, part := range parts {
node, nodeOk = nodes[part]
if !nodeOk {
break
}
nodes = node.children
}
if node != nil {
for _, grant := range node.grants {
if isSubName(grant.Subject, revocation.Subject) {
grant.Permission = grant.Permission &^ revocation.Revocation
}
}
}
}
}
retGrants := make([]*Grant, 0, grantCount)
for _, rootNodes := range roots {
retGrants = append(retGrants, rootNodes.grants...)
}
return retGrants, minExpired, nil
}
// FilterStatements filters the statements to statements including the given grants.
func FilterStatements(grants []*Grant) ([]*Statement, error) {
statements := map[*Statement]bool{}
for _, grant := range grants {
if grant.statement != nil {
statements[grant.statement] = true
}
}
retStatements := make([]*Statement, len(statements))
var i int
for statement := range statements {
retStatements[i] = statement
i++
}
return retStatements, nil
}