Automatically generate a HTTP secret if none is provided

Log a warning if the registry generates its own secret.

Update configuration doc, and remove the default secret from the
development config file.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2015-07-29 12:50:43 -07:00
parent 01e6dde2fd
commit 70d9a9d543
3 changed files with 25 additions and 2 deletions

View file

@ -30,7 +30,6 @@ storage:
enabled: false enabled: false
http: http:
addr: :5000 addr: :5000
secret: asecretforlocaldevelopment
debug: debug:
addr: localhost:5001 addr: localhost:5001
redis: redis:

View file

@ -1184,7 +1184,12 @@ should have both preceding and trailing slashes, for example <code>/path/</code>
<td> <td>
A random piece of data. This is used to sign state that may be stored with the A random piece of data. This is used to sign state that may be stored with the
client to protect against tampering. For production environments you should generate a client to protect against tampering. For production environments you should generate a
random piece of data using a cryptographically secure random generator. random piece of data using a cryptographically secure random generator. This
configuration parameter may be omitted, in which case the registry will automatically
generate a secret at launch.
<p />
<b>WARNING: If you are building a cluster of registries behind a load balancer, you MUST
ensure the secret is the same for all registries.</b>
</td> </td>
</tr> </tr>
</table> </table>

View file

@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
cryptorand "crypto/rand"
"expvar" "expvar"
"fmt" "fmt"
"math/rand" "math/rand"
@ -30,6 +31,10 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// randomSecretSize is the number of random bytes to generate if no secret
// was specified.
const randomSecretSize = 32
// App is a global registry application object. Shared resources can be placed // App is a global registry application object. Shared resources can be placed
// on this object that will be accessible from all requests. Any writable // on this object that will be accessible from all requests. Any writable
// fields should be protected. // fields should be protected.
@ -102,6 +107,7 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
panic(err) panic(err)
} }
app.configureSecret(&configuration)
app.configureEvents(&configuration) app.configureEvents(&configuration)
app.configureRedis(&configuration) app.configureRedis(&configuration)
app.configureLogHook(&configuration) app.configureLogHook(&configuration)
@ -337,6 +343,19 @@ func (app *App) configureLogHook(configuration *configuration.Configuration) {
} }
} }
// configureSecret creates a random secret if a secret wasn't included in the
// configuration.
func (app *App) configureSecret(configuration *configuration.Configuration) {
if configuration.HTTP.Secret == "" {
var secretBytes [randomSecretSize]byte
if _, err := cryptorand.Read(secretBytes[:]); err != nil {
panic(fmt.Sprintf("could not generate random bytes for HTTP secret: %v", err))
}
configuration.HTTP.Secret = string(secretBytes[:])
ctxu.GetLogger(app).Warn("No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable.")
}
}
func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() // ensure that request body is always closed. defer r.Body.Close() // ensure that request body is always closed.