func (s *DockerDaemonSuite) TestDaemonKeyMigration(c *check.C) { // TODO: skip or update for Windows daemon os.Remove("/etc/docker/key.json") k1, err := libtrust.GenerateECP256PrivateKey() if err != nil { c.Fatalf("Error generating private key: %s", err) } if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0755); err != nil { c.Fatalf("Error creating .docker directory: %s", err) } if err := libtrust.SaveKey(filepath.Join(os.Getenv("HOME"), ".docker", "key.json"), k1); err != nil { c.Fatalf("Error saving private key: %s", err) } if err := s.d.Start(); err != nil { c.Fatalf("Could not start daemon: %v", err) } s.d.Stop() k2, err := libtrust.LoadKeyFile("/etc/docker/key.json") if err != nil { c.Fatalf("Error opening key file") } if k1.KeyID() != k2.KeyID() { c.Fatalf("Key not migrated") } }
func main() { // Load server key. serverKey, err := libtrust.LoadKeyFile(privateKeyFilename) if err != nil { log.Fatal(err) } // Generate server certificate. selfSignedServerCert, err := libtrust.GenerateSelfSignedServerCert( serverKey, []string{"localhost"}, []net.IP{net.ParseIP("127.0.0.1")}, ) if err != nil { log.Fatal(err) } // Load authorized client keys. authorizedClients, err := libtrust.LoadKeySetFile(authorizedClientsFilename) if err != nil { log.Fatal(err) } // Create CA pool using trusted client keys. caPool, err := libtrust.GenerateCACertPool(serverKey, authorizedClients) if err != nil { log.Fatal(err) } // Create TLS config, requiring client certificates. tlsConfig := &tls.Config{ Certificates: []tls.Certificate{ tls.Certificate{ Certificate: [][]byte{selfSignedServerCert.Raw}, PrivateKey: serverKey.CryptoPrivateKey(), Leaf: selfSignedServerCert, }, }, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: caPool, } // Create HTTP server with simple request handler. server := &http.Server{ Addr: serverAddress, Handler: http.HandlerFunc(requestHandler), } // Listen and server HTTPS using the libtrust TLS config. listener, err := net.Listen("tcp", server.Addr) if err != nil { log.Fatal(err) } tlsListener := tls.NewListener(listener, tlsConfig) server.Serve(tlsListener) }
// MakeToken makes a valid jwt token based on parms. func MakeToken(username, service string, access []*token.ResourceActions) (token string, expiresIn int, issuedAt *time.Time, err error) { pk, err := libtrust.LoadKeyFile(privateKey) if err != nil { return "", 0, nil, err } tk, expiresIn, issuedAt, err := makeTokenCore(issuer, username, service, expiration, access, pk) if err != nil { return "", 0, nil, err } rs := fmt.Sprintf("%s.%s", tk.Raw, base64UrlEncode(tk.Signature)) return rs, expiresIn, issuedAt, nil }
func main() { key, err := libtrust.LoadKeyFile(clientPrivateKeyFilename) if err != nil { log.Fatal(err) } keyPEMBlock, err := key.PEMBlock() if err != nil { log.Fatal(err) } encodedPrivKey := pem.EncodeToMemory(keyPEMBlock) fmt.Printf("Client Key:\n\n%s\n", string(encodedPrivKey)) cert, err := libtrust.GenerateSelfSignedClientCert(key) if err != nil { log.Fatal(err) } encodedCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) fmt.Printf("Client Cert:\n\n%s\n", string(encodedCert)) trustedServerKeys, err := libtrust.LoadKeySetFile(trustedHostsFilename) if err != nil { log.Fatal(err) } hostname, _, err := net.SplitHostPort(serverAddress) if err != nil { log.Fatal(err) } trustedServerKeys, err = libtrust.FilterByHosts(trustedServerKeys, hostname, false) if err != nil { log.Fatal(err) } caCert, err := libtrust.GenerateCACert(key, trustedServerKeys[0]) if err != nil { log.Fatal(err) } encodedCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCert.Raw}) fmt.Printf("CA Cert:\n\n%s\n", string(encodedCert)) }
func (s *DockerDaemonSuite) TestDaemonKeyGeneration(c *check.C) { // TODO: skip or update for Windows daemon os.Remove("/etc/docker/key.json") if err := s.d.Start(); err != nil { c.Fatalf("Could not start daemon: %v", err) } s.d.Stop() k, err := libtrust.LoadKeyFile("/etc/docker/key.json") if err != nil { c.Fatalf("Error opening key file") } kid := k.KeyID() // Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF) if len(kid) != 59 { c.Fatalf("Bad key ID: %s", kid) } }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil }
func getKeys(keys []string) ([]trust.PrivateKey, error) { var pkeys []trust.PrivateKey if len(keys) != 0 { for _, k := range keys { pkey, err := trust.LoadKeyFile(k) if err != nil { return nil, err } if verbose { fmt.Printf("Signing with: %s\n", pkey.KeyID()) } pkeys = append(pkeys, pkey) } } return pkeys, nil }
func TestDaemonKeyGeneration(t *testing.T) { // TODO: skip or update for Windows daemon os.Remove("/etc/docker/key.json") d := NewDaemon(t) if err := d.Start(); err != nil { t.Fatalf("Could not start daemon: %v", err) } d.Stop() k, err := libtrust.LoadKeyFile("/etc/docker/key.json") if err != nil { t.Fatalf("Error opening key file") } kid := k.KeyID() // Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF) if len(kid) != 59 { t.Fatalf("Bad key ID: %s", kid) } logDone("daemon - key generation") }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) if err != nil { return nil, fmt.Errorf("Error serializing key: %s", err) } if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := os.MkdirAll(path.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } dir, file := path.Split(trustKeyPath) // Save public key if err := libtrust.SavePublicKey(path.Join(dir, "public-"+file), trustKey.PublicKey()); err != nil { return nil, fmt.Errorf("Error saving public key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file: %s", err) } return trustKey, nil }
// NewApp takes a configuration and returns a configured app, ready to serve // requests. The app only implements ServeHTTP and can be wrapped in other // handlers accordingly. func NewApp(ctx context.Context, config *configuration.Configuration) *App { app := &App{ Config: config, Context: ctx, router: v2.RouterWithPrefix(config.HTTP.Prefix), isCache: config.Proxy.RemoteURL != "", } // Register the handler dispatchers. app.register(v2.RouteNameBase, func(ctx *Context, r *http.Request) http.Handler { return http.HandlerFunc(apiBase) }) app.register(v2.RouteNameManifest, imageManifestDispatcher) app.register(v2.RouteNameCatalog, catalogDispatcher) app.register(v2.RouteNameTags, tagsDispatcher) app.register(v2.RouteNameBlob, blobDispatcher) app.register(v2.RouteNameBlobUpload, blobUploadDispatcher) app.register(v2.RouteNameBlobUploadChunk, blobUploadDispatcher) // override the storage driver's UA string for registry outbound HTTP requests storageParams := config.Storage.Parameters() if storageParams == nil { storageParams = make(configuration.Parameters) } storageParams["useragent"] = fmt.Sprintf("docker-distribution/%s %s", version.Version, runtime.Version()) var err error app.driver, err = factory.Create(config.Storage.Type(), storageParams) if err != nil { // TODO(stevvooe): Move the creation of a service into a protected // method, where this is created lazily. Its status can be queried via // a health check. panic(err) } purgeConfig := uploadPurgeDefaultConfig() if mc, ok := config.Storage["maintenance"]; ok { if v, ok := mc["uploadpurging"]; ok { purgeConfig, ok = v.(map[interface{}]interface{}) if !ok { panic("uploadpurging config key must contain additional keys") } } if v, ok := mc["readonly"]; ok { readOnly, ok := v.(map[interface{}]interface{}) if !ok { panic("readonly config key must contain additional keys") } if readOnlyEnabled, ok := readOnly["enabled"]; ok { app.readOnly, ok = readOnlyEnabled.(bool) if !ok { panic("readonly's enabled config key must have a boolean value") } } } } startUploadPurger(app, app.driver, ctxu.GetLogger(app), purgeConfig) app.driver, err = applyStorageMiddleware(app.driver, config.Middleware["storage"]) if err != nil { panic(err) } app.configureSecret(config) app.configureEvents(config) app.configureRedis(config) app.configureLogHook(config) options := registrymiddleware.GetRegistryOptions() if config.Compatibility.Schema1.TrustKey != "" { app.trustKey, err = libtrust.LoadKeyFile(config.Compatibility.Schema1.TrustKey) if err != nil { panic(fmt.Sprintf(`could not load schema1 "signingkey" parameter: %v`, err)) } } else { // Generate an ephemeral key to be used for signing converted manifests // for clients that don't support schema2. app.trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { panic(err) } } options = append(options, storage.Schema1SigningKey(app.trustKey)) if config.HTTP.Host != "" { u, err := url.Parse(config.HTTP.Host) if err != nil { panic(fmt.Sprintf(`could not parse http "host" parameter: %v`, err)) } app.httpHost = *u } if app.isCache { options = append(options, storage.DisableDigestResumption) } // configure deletion if d, ok := config.Storage["delete"]; ok { e, ok := d["enabled"] if ok { if deleteEnabled, ok := e.(bool); ok && deleteEnabled { options = append(options, storage.EnableDelete) } } } // configure redirects var redirectDisabled bool if redirectConfig, ok := config.Storage["redirect"]; ok { v := redirectConfig["disable"] switch v := v.(type) { case bool: redirectDisabled = v default: panic(fmt.Sprintf("invalid type for redirect config: %#v", redirectConfig)) } } if redirectDisabled { ctxu.GetLogger(app).Infof("backend redirection disabled") } else { options = append(options, storage.EnableRedirect) } // configure storage caches if cc, ok := config.Storage["cache"]; ok { v, ok := cc["blobdescriptor"] if !ok { // Backwards compatible: "layerinfo" == "blobdescriptor" v = cc["layerinfo"] } switch v { case "redis": if app.redis == nil { panic("redis configuration required to use for layerinfo cache") } cacheProvider := rediscache.NewRedisBlobDescriptorCacheProvider(app.redis) localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider)) app.registry, err = storage.NewRegistry(app, app.driver, localOptions...) if err != nil { panic("could not create registry: " + err.Error()) } ctxu.GetLogger(app).Infof("using redis blob descriptor cache") case "inmemory": cacheProvider := memorycache.NewInMemoryBlobDescriptorCacheProvider() localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider)) app.registry, err = storage.NewRegistry(app, app.driver, localOptions...) if err != nil { panic("could not create registry: " + err.Error()) } ctxu.GetLogger(app).Infof("using inmemory blob descriptor cache") default: if v != "" { ctxu.GetLogger(app).Warnf("unknown cache type %q, caching disabled", config.Storage["cache"]) } } } if app.registry == nil { // configure the registry if no cache section is available. app.registry, err = storage.NewRegistry(app.Context, app.driver, options...) if err != nil { panic("could not create registry: " + err.Error()) } } app.registry, err = applyRegistryMiddleware(app, app.registry, config.Middleware["registry"]) if err != nil { panic(err) } authType := config.Auth.Type() if authType != "" { accessController, err := auth.GetAccessController(config.Auth.Type(), config.Auth.Parameters()) if err != nil { panic(fmt.Sprintf("unable to configure authorization (%s): %v", authType, err)) } app.accessController = accessController ctxu.GetLogger(app).Debugf("configured %q access controller", authType) } // configure as a pull through cache if config.Proxy.RemoteURL != "" { app.registry, err = proxy.NewRegistryPullThroughCache(ctx, app.registry, app.driver, config.Proxy) if err != nil { panic(err.Error()) } app.isCache = true ctxu.GetLogger(app).Info("Registry configured as a proxy cache to ", config.Proxy.RemoteURL) } return app }
func main() { var ( issuer = &TokenIssuer{} pkFile string addr string debug bool err error passwdFile string realm string cert string certKey string ) flag.StringVar(&issuer.Issuer, "issuer", "distribution-token-server", "Issuer string for token") flag.StringVar(&pkFile, "key", "", "Private key file") flag.StringVar(&addr, "addr", "localhost:8080", "Address to listen on") flag.BoolVar(&debug, "debug", false, "Debug mode") flag.StringVar(&passwdFile, "passwd", ".htpasswd", "Passwd file") flag.StringVar(&realm, "realm", "", "Authentication realm") flag.StringVar(&cert, "tlscert", "", "Certificate file for TLS") flag.StringVar(&certKey, "tlskey", "", "Certificate key for TLS") flag.Parse() if debug { logrus.SetLevel(logrus.DebugLevel) } if pkFile == "" { issuer.SigningKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { logrus.Fatalf("Error generating private key: %v", err) } logrus.Debugf("Using newly generated key with id %s", issuer.SigningKey.KeyID()) } else { issuer.SigningKey, err = libtrust.LoadKeyFile(pkFile) if err != nil { logrus.Fatalf("Error loading key file %s: %v", pkFile, err) } logrus.Debugf("Loaded private key with id %s", issuer.SigningKey.KeyID()) } if realm == "" { logrus.Fatalf("Must provide realm") } ac, err := auth.GetAccessController("htpasswd", map[string]interface{}{ "realm": realm, "path": passwdFile, }) if err != nil { logrus.Fatalf("Error initializing access controller: %v", err) } // TODO: Make configurable issuer.Expiration = 15 * time.Minute ctx := context.Background() ts := &tokenServer{ issuer: issuer, accessController: ac, refreshCache: map[string]refreshToken{}, } router := mux.NewRouter() router.Path("/token/").Methods("GET").Handler(handlerWithContext(ctx, ts.getToken)) router.Path("/token/").Methods("POST").Handler(handlerWithContext(ctx, ts.postToken)) if cert == "" { err = http.ListenAndServe(addr, router) } else if certKey == "" { logrus.Fatalf("Must provide certficate (-tlscert) and key (-tlskey)") } else { err = http.ListenAndServeTLS(addr, cert, certKey, router) } if err != nil { logrus.Infof("Error serving: %v", err) } }
func main() { // Load Client Key. clientKey, err := libtrust.LoadKeyFile(privateKeyFilename) if err != nil { log.Fatal(err) } // Generate Client Certificate. selfSignedClientCert, err := libtrust.GenerateSelfSignedClientCert(clientKey) if err != nil { log.Fatal(err) } // Load trusted host keys. hostKeys, err := libtrust.LoadKeySetFile(trustedHostsFilename) if err != nil { log.Fatal(err) } // Ensure the host we want to connect to is trusted! host, _, err := net.SplitHostPort(serverAddress) if err != nil { log.Fatal(err) } serverKeys, err := libtrust.FilterByHosts(hostKeys, host, false) if err != nil { log.Fatalf("%q is not a known and trusted host", host) } // Generate a CA pool with the trusted host's key. caPool, err := libtrust.GenerateCACertPool(clientKey, serverKeys) if err != nil { log.Fatal(err) } // Create HTTP Client. client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ Certificates: []tls.Certificate{ tls.Certificate{ Certificate: [][]byte{selfSignedClientCert.Raw}, PrivateKey: clientKey.CryptoPrivateKey(), Leaf: selfSignedClientCert, }, }, RootCAs: caPool, }, }, } var makeRequest = func(url string) { resp, err := client.Get(url) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } log.Println(resp.Status) log.Println(string(body)) } // Make the request to the trusted server! makeRequest(fmt.Sprintf("https://%s", serverAddress)) }
func outputManifestFor(target string) { var pkey trust.PrivateKey if key != "" { var err error pkey, err = trust.LoadKeyFile(key) if err != nil { fmt.Printf("error loading key: %s\n", err.Error()) return } } if verbose { fmt.Errorf("signing with: %s\n", pkey.KeyID()) } f, err := os.Open(target) if err != nil { fmt.Printf("error opening file: %s\n", err.Error()) return } defer func() { if err := f.Close(); err != nil { panic(err) } }() var ( repo, tag string ) layers := LayerMap{} t := tar.NewReader(bufio.NewReader(f)) for { hdr, err := t.Next() if err == io.EOF { break } if strings.HasSuffix(hdr.Name, "layer.tar") { id := getLayerPrefix(hdr.Name) sum, _ := blobSumLayer(t) if _, ok := layers[id]; !ok { layers[id] = &Layer{Id: id} } else { layers[id].BlobSum = sum } } if strings.HasSuffix(hdr.Name, "json") { data, _ := ioutil.ReadAll(t) parent, id, _ := getLayerInfo(data) if _, ok := layers[id]; !ok { layers[id] = &Layer{Id: id, Parent: parent} } else { layers[id].Parent = parent } var img image.Image json.Unmarshal(data, &img) b, _ := json.Marshal(img) layers[id].Data = string(b) + "\n" } if hdr.Name == "repositories" { r, _ := ioutil.ReadAll(t) var raw map[string]interface{} if err := json.Unmarshal(r, &raw); err != nil { return } repo, tag = getRepoInfo(raw) if !strings.Contains(repo, "/") { repo = "library/" + repo } } } m := manifest.Manifest{ Versioned: versioned.Versioned{ SchemaVersion: 1, }, Name: repo, Tag: tag, Architecture: "amd64"} ll := getLayersFromMap(layers) for _, l := range getLayersInOrder(ll) { m.FSLayers = append(m.FSLayers, manifest.FSLayer{BlobSum: l.BlobSum}) m.History = append(m.History, manifest.History{V1Compatibility: l.Data}) } var x []byte if pkey != nil { var sm *manifest.SignedManifest sm, err = manifest.Sign(&m, pkey) x, err = sm.MarshalJSON() } else { x, err = json.MarshalIndent(m, "", " ") } if print_digest { dgstr, _ := digest.FromBytes(x) fmt.Println(string(dgstr)) } fmt.Println(string(x)) }
func main() { if reexec.Init() { return } flag.Parse() // FIXME: validate daemon flags here if *flVersion { showVersion() return } if *flDebug { os.Setenv("DEBUG", "1") } if len(flHosts) == 0 { defaultHost := os.Getenv("DOCKER_HOST") if defaultHost == "" || *flDaemon { // If we do not have a host, default to unix socket defaultHost = fmt.Sprintf("unix://%s", api.DEFAULTUNIXSOCKET) } defaultHost, err := api.ValidateHost(defaultHost) if err != nil { log.Fatal(err) } flHosts = append(flHosts, defaultHost) } if *flDaemon { mainDaemon() return } if len(flHosts) > 1 { log.Fatal("Please specify only one -H") } protoAddrParts := strings.SplitN(flHosts[0], "://", 2) err := os.MkdirAll(path.Dir(*flTrustKey), 0700) if err != nil { log.Fatal(err) } trustKey, keyErr := libtrust.LoadKeyFile(*flTrustKey) if keyErr == libtrust.ErrKeyFileDoesNotExist { trustKey, keyErr = libtrust.GenerateECP256PrivateKey() if keyErr == nil { keyErr = libtrust.SaveKey(*flTrustKey, trustKey) } } if keyErr != nil { log.Fatal(keyErr) } var ( cli *client.DockerCli tlsConfig tls.Config ) tlsConfig.InsecureSkipVerify = true // If we should verify the server, we need to load a trusted ca if *flTlsVerify { *flTls = true certPool := x509.NewCertPool() file, err := ioutil.ReadFile(*flCa) if err != nil { log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err) } certPool.AppendCertsFromPEM(file) tlsConfig.RootCAs = certPool tlsConfig.InsecureSkipVerify = false } // If tls is enabled, try to load and send client certificates if *flTls || *flTlsVerify { _, errCert := os.Stat(*flCert) _, errKey := os.Stat(*flKey) if errCert == nil && errKey == nil { *flTls = true cert, err := tls.LoadX509KeyPair(*flCert, *flKey) if err != nil { log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err) } tlsConfig.Certificates = []tls.Certificate{cert} } } if *flTls || *flTlsVerify { cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, trustKey, protoAddrParts[0], protoAddrParts[1], &tlsConfig) } else { cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, trustKey, protoAddrParts[0], protoAddrParts[1], nil) } if err := cli.Cmd(flag.Args()...); err != nil { if sterr, ok := err.(*utils.StatusError); ok { if sterr.Status != "" { log.Println(sterr.Status) } os.Exit(sterr.StatusCode) } log.Fatal(err) } }