github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/trust/trusts.go (about) 1 package trust 2 3 import ( 4 "crypto/x509" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "os" 11 "path" 12 "path/filepath" 13 "sync" 14 "time" 15 16 "github.com/Sirupsen/logrus" 17 "github.com/docker/libtrust/trustgraph" 18 ) 19 20 // Store defines a TrustStore : stores trusted certificates and permissions 21 // which are used to verify the signature keys on manifests. 22 // Note: This is being deprecated by the notary work. 23 type Store struct { 24 path string 25 caPool *x509.CertPool 26 graph trustgraph.TrustGraph 27 expiration time.Time 28 fetcher *time.Timer 29 fetchTime time.Duration 30 autofetch bool 31 httpClient *http.Client 32 baseEndpoints map[string]*url.URL 33 34 sync.RWMutex 35 } 36 37 // defaultFetchtime represents the starting duration to wait between 38 // fetching sections of the graph. Unsuccessful fetches should 39 // increase time between fetching. 40 const defaultFetchtime = 45 * time.Second 41 42 var baseEndpoints = map[string]string{"official": "https://dvjy3tqbc323p.cloudfront.net/trust/official.json"} 43 44 // NewStore creates a TrustStore from a given path, if the path is not 45 // relative, it will be joined with the working directory. 46 func NewStore(path string) (*Store, error) { 47 abspath, err := filepath.Abs(path) 48 if err != nil { 49 return nil, err 50 } 51 52 // Create base graph url map 53 endpoints := map[string]*url.URL{} 54 for name, endpoint := range baseEndpoints { 55 u, err := url.Parse(endpoint) 56 if err != nil { 57 return nil, err 58 } 59 endpoints[name] = u 60 } 61 62 // Load grant files 63 t := &Store{ 64 path: abspath, 65 caPool: nil, 66 httpClient: &http.Client{}, 67 fetchTime: time.Millisecond, 68 baseEndpoints: endpoints, 69 } 70 71 if err := t.reload(); err != nil { 72 return nil, err 73 } 74 75 return t, nil 76 } 77 78 func (t *Store) reload() error { 79 t.Lock() 80 defer t.Unlock() 81 82 matches, err := filepath.Glob(filepath.Join(t.path, "*.json")) 83 if err != nil { 84 return err 85 } 86 statements := make([]*trustgraph.Statement, len(matches)) 87 for i, match := range matches { 88 f, err := os.Open(match) 89 if err != nil { 90 return fmt.Errorf("Error opening %q: %s", match, err) 91 } 92 statements[i], err = trustgraph.LoadStatement(f, nil) 93 if err != nil { 94 f.Close() 95 return fmt.Errorf("Error loading %q: %s", match, err) 96 } 97 f.Close() 98 } 99 if len(statements) == 0 { 100 if t.autofetch { 101 logrus.Debugf("No grants, fetching") 102 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 103 } 104 return nil 105 } 106 107 grants, expiration, err := trustgraph.CollapseStatements(statements, true) 108 if err != nil { 109 return err 110 } 111 112 t.expiration = expiration 113 t.graph = trustgraph.NewMemoryGraph(grants) 114 logrus.Debugf("Reloaded graph with %d grants expiring at %s", len(grants), expiration) 115 116 if t.autofetch { 117 nextFetch := expiration.Sub(time.Now()) 118 if nextFetch < 0 { 119 nextFetch = defaultFetchtime 120 } else { 121 nextFetch = time.Duration(0.8 * (float64)(nextFetch)) 122 } 123 t.fetcher = time.AfterFunc(nextFetch, t.fetch) 124 } 125 126 return nil 127 } 128 129 func (t *Store) fetchBaseGraph(u *url.URL) (*trustgraph.Statement, error) { 130 req := &http.Request{ 131 Method: "GET", 132 URL: u, 133 Proto: "HTTP/1.1", 134 ProtoMajor: 1, 135 ProtoMinor: 1, 136 Header: make(http.Header), 137 Body: nil, 138 Host: u.Host, 139 } 140 141 resp, err := t.httpClient.Do(req) 142 if err != nil { 143 return nil, err 144 } 145 if resp.StatusCode == 404 { 146 return nil, errors.New("base graph does not exist") 147 } 148 149 defer resp.Body.Close() 150 151 return trustgraph.LoadStatement(resp.Body, t.caPool) 152 } 153 154 // fetch retrieves updated base graphs. This function cannot error, it 155 // should only log errors 156 func (t *Store) fetch() { 157 t.Lock() 158 defer t.Unlock() 159 160 if t.autofetch && t.fetcher == nil { 161 // Do nothing ?? 162 return 163 } 164 165 fetchCount := 0 166 for bg, ep := range t.baseEndpoints { 167 statement, err := t.fetchBaseGraph(ep) 168 if err != nil { 169 logrus.Infof("Trust graph fetch failed: %s", err) 170 continue 171 } 172 b, err := statement.Bytes() 173 if err != nil { 174 logrus.Infof("Bad trust graph statement: %s", err) 175 continue 176 } 177 // TODO check if value differs 178 if err := ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600); err != nil { 179 logrus.Infof("Error writing trust graph statement: %s", err) 180 } 181 fetchCount++ 182 } 183 logrus.Debugf("Fetched %d base graphs at %s", fetchCount, time.Now()) 184 185 if fetchCount > 0 { 186 go func() { 187 if err := t.reload(); err != nil { 188 logrus.Infof("Reload of trust graph failed: %s", err) 189 } 190 }() 191 t.fetchTime = defaultFetchtime 192 t.fetcher = nil 193 } else if t.autofetch { 194 maxTime := 10 * defaultFetchtime 195 t.fetchTime = time.Duration(1.5 * (float64)(t.fetchTime+time.Second)) 196 if t.fetchTime > maxTime { 197 t.fetchTime = maxTime 198 } 199 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 200 } 201 }