mirror of https://github.com/docker/docs.git
commit
20c557a10b
|
@ -244,8 +244,8 @@ func usage() {
|
|||
// endpoints. The addr should not be exposed externally. For most of these to
|
||||
// work, tls cannot be enabled on the endpoint, so it is generally separate.
|
||||
func debugServer(addr string) {
|
||||
logrus.Info("Debug server listening on", addr)
|
||||
logrus.Infof("Debug server listening on %s", addr)
|
||||
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||
logrus.Fatal("error listening on debug interface: ", err)
|
||||
logrus.Fatalf("error listening on debug interface: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,8 +240,8 @@ func usage() {
|
|||
// endpoints. The addr should not be exposed externally. For most of these to
|
||||
// work, tls cannot be enabled on the endpoint, so it is generally separate.
|
||||
func debugServer(addr string) {
|
||||
log.Println("Debug server listening on", addr)
|
||||
logrus.Infof("Debug server listening on %s", addr)
|
||||
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||
log.Fatalf("error listening on debug interface: %v", err)
|
||||
logrus.Fatalf("error listening on debug interface: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Notary Serer Configuration File"
|
||||
description = "Specifies the configuration file for Notary Server"
|
||||
keywords = ["docker, notary, notary-server, configuration"]
|
||||
[menu.main]
|
||||
parent="mn_notary"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Notary Server Configuration File
|
||||
|
||||
An example (full) server configuration file.
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"http_addr": ":4443",
|
||||
"tls_key_file": "./fixtures/notary-server.key",
|
||||
"tls_cert_file": "./fixtures/notary-server.crt",
|
||||
},
|
||||
"trust_service": {
|
||||
"type": "remote",
|
||||
"hostname": "notarysigner",
|
||||
"port": "7899",
|
||||
"key_algorithm": "ecdsa",
|
||||
"tls_ca_file": "./fixtures/root-ca.crt",
|
||||
"tls_client_cert": "./fixtures/notary-server.crt",
|
||||
"tls_client_key": "./fixtures/notary-server.key"
|
||||
},
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "user:pass@tcp(notarymysql:3306)/databasename?parseTime=true"
|
||||
},
|
||||
"auth": {
|
||||
"type": "token",
|
||||
"options": {
|
||||
"realm": "https://auth.docker.io/token",
|
||||
"service": "notary-server",
|
||||
"issuer": "auth.docker.io",
|
||||
"rootcertbundle": "/path/to/auth.docker.io/cert"
|
||||
}
|
||||
},
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
},
|
||||
"reporting": {
|
||||
"bugsnag": {
|
||||
"api_key": "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
|
||||
"release_stage": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `server` section (required)
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"server": {
|
||||
"http_addr": ":4443",
|
||||
"tls_key_file": "./fixtures/notary-server.key",
|
||||
"tls_cert_file": "./fixtures/notary-server.crt"
|
||||
}
|
||||
```
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>http_addr</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The TCP address (IP and port) to listen on. Examples:
|
||||
<ul>
|
||||
<li><code>":4443"</code> means listen on port 4443 on all IPs (and
|
||||
hence all interfaces, such as those listed when you run
|
||||
<code>ifconfig</code>)</li>
|
||||
<li><code>"127.0.0.1:4443"</code> means listen on port 4443 on
|
||||
localhost only. That means that the server will not be
|
||||
acessible except locally (via SSH tunnel, or just on a local
|
||||
terminal)</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_key_file</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The path to the private key to use for
|
||||
HTTPS. Must be provided together with <code>tls_cert_file</code>,
|
||||
or not at all. If neither are provided, the server will use HTTP
|
||||
instead of HTTPS. The path is relative to the directory of the
|
||||
configuration file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_cert_file</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The path to the certificate to use for HTTPS.
|
||||
Must be provided together with <code>tls_key_file</code>, or not
|
||||
at all. If neither are provided, the server will use HTTP instead
|
||||
of HTTPS. The path is relative to the directory of the
|
||||
configuration file.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## `trust service` section (required)
|
||||
|
||||
This section configures either a remote trust service, such as
|
||||
[Notary Signer](notary-signer.md) or a local in-memory ED25519 trust service.
|
||||
|
||||
Remote trust service example:
|
||||
|
||||
```json
|
||||
"trust_service": {
|
||||
"type": "remote",
|
||||
"hostname": "notarysigner",
|
||||
"port": "7899",
|
||||
"key_algorithm": "ecdsa",
|
||||
"tls_ca_file": "./fixtures/root-ca.crt",
|
||||
"tls_client_key": "./fixtures/notary-server.key",
|
||||
"tls_client_cert": "./fixtures/notary-server.crt"
|
||||
}
|
||||
```
|
||||
|
||||
Local trust service example:
|
||||
|
||||
```json
|
||||
"trust_service": {
|
||||
"type": "local"
|
||||
}
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>type</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">Must be <code>"remote"</code> or <code>"local"</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>hostname</code></td>
|
||||
<td valign="top">yes if remote</td>
|
||||
<td valign="top">The hostname of the remote trust service</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>port</code></td>
|
||||
<td valign="top">yes if remote</td>
|
||||
<td valign="top">The GRPC port of the remote trust service</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>key_algorithm</code></td>
|
||||
<td valign="top">yes if remote</td>
|
||||
<td valign="top">Algorithm to use to generate keys stored on the
|
||||
signing service. Valid values are <code>"ecdsa"</code>,
|
||||
<code>"rsa"</code>, and <code>"ed25519"</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_ca_file</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The path to the root CA that signed the TLS
|
||||
certificate of the remote service. This parameter if said root
|
||||
CA is not in the system's default trust roots. The path is
|
||||
relative to the directory of the configuration file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_client_key</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The path to the private key to use for TLS mutual
|
||||
authentication. This must be provided together with
|
||||
<code>tls_client_cert</code> or not at all. The path is relative
|
||||
to the directory of the configuration file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_client_cert</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The path to the certificate to use for TLS mutual
|
||||
authentication. This must be provided together with
|
||||
<code>tls_client_key</code> or not at all. The path is relative
|
||||
to the directory of the configuration file.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## `storage` section (required)
|
||||
|
||||
The storage section specifies which storage backend the server should use to
|
||||
store TUF metadata. Currently, we only support MySQL or an in-memory store.
|
||||
|
||||
DB storage example:
|
||||
|
||||
```json
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "user:pass@tcp(notarymysql:3306)/databasename?parseTime=true"
|
||||
}
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>backend</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">Must be <code>"mysql"</code> or <code>"memory"</code>.
|
||||
If <code>"memory"</code> is selected, the <code>db_url</code>
|
||||
is ignored.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>db_url</code></td>
|
||||
<td valign="top">yes if not <code>memory</code></td>
|
||||
<td valign="top">The <a href="https://github.com/go-sql-driver/mysql">
|
||||
the Data Source Name used to access the DB.</a>
|
||||
(note: please include "parseTime=true" as part of the the DSN)</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## `auth` section (optional)
|
||||
|
||||
This sections specifies the authentication options for the server.
|
||||
Currently, we only support token authentication.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"auth": {
|
||||
"type": "token",
|
||||
"options": {
|
||||
"realm": "https://auth.docker.io",
|
||||
"service": "notary-server",
|
||||
"issuer": "auth.docker.io",
|
||||
"rootcertbundle": "/path/to/auth.docker.io/cert"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that this entire section is optional. However, if you would like
|
||||
authentication for your server, then you need the required parameters below to
|
||||
configure it.
|
||||
|
||||
**Token authentication:**
|
||||
|
||||
This is an implementation of the same authentication used by
|
||||
[docker registry](https://github.com/docker/distribution). (JTW token-based
|
||||
authentication post login.)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>type</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">Must be `"token"`; all other values will result in no
|
||||
authentication (and the rest of the parameters will be ignored)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>options</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The options for token auth. Please see
|
||||
<a href="https://github.com/docker/distribution/blob/master/docs/configuration.md#token">
|
||||
the registry token configuration documentation</a>
|
||||
for the parameter details.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## `logging` section (optional)
|
||||
|
||||
The logging section sets the log level of the server. If it is not provided
|
||||
or invalid, the server defaults to an ERROR logging level.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
}
|
||||
```
|
||||
|
||||
Note that this entire section is optional. However, if you would like to
|
||||
specify a different log level, then you need the required parameters
|
||||
below to configure it.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>level</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">One of <code>"debug"</code>, <code>"info"</code>,
|
||||
<code>"warning"</code>, <code>"error"</code>, <code>"fatal"</code>,
|
||||
or <code>"panic"</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## `reporting` section (optional)
|
||||
|
||||
The reporting section contains any configuration for useful for running the
|
||||
service, such as reporting errors. Currently, we only support reporting errors
|
||||
to [Bugsnag](https://bugsnag.com).
|
||||
|
||||
See [bugsnag-go](https://github.com/bugsnag/bugsnag-go/) for more information
|
||||
about these configuration parameters.
|
||||
|
||||
```json
|
||||
"reporting": {
|
||||
"bugsnag": {
|
||||
"api_key": "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
|
||||
"release_stage": "production"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that this entire section is optional. However, if you would like to
|
||||
report errors to Bugsnag, then you need to include a `bugsnag` subsection,
|
||||
along with the required parameters below, to configure it.
|
||||
|
||||
**Bugsnag reporting:**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>api_key</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td>The BugSnag API key to use to report errors.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>release_stage</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td>The current release stage, such as "production". You can
|
||||
use this value to filter errors in the Bugsnag dashboard.</td>
|
||||
</tr>
|
||||
</table>
|
|
@ -0,0 +1,189 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Notary Server"
|
||||
description = "Description of the Notary Server"
|
||||
keywords = ["docker, notary, notary-server"]
|
||||
[menu.main]
|
||||
parent="mn_notary"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Notary Server
|
||||
|
||||
The Notary Server stores and updates the signed
|
||||
[TUF metadata files](
|
||||
https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt#L348)
|
||||
for a repository. The root, snapshot, and targets metadata files are generated
|
||||
and signed by clients, and the timestamp metadata file is generated and signed
|
||||
by the server.
|
||||
|
||||
The server creates and stores timestamp keys for each repository (preferably
|
||||
using a remote key storage/signing service such as
|
||||
[Notary Signer](notary-signer.md)).
|
||||
|
||||
When clients upload metadata files, the server checks them for conflicts and
|
||||
verifies the signatures and key references in the files. If everything
|
||||
checks out, the server then signs the timestamp metadata file for the
|
||||
repository, which certifies that the files the client uploaded are the most
|
||||
recent for that repository.
|
||||
|
||||
### Authentication
|
||||
|
||||
Notary Server supports authentication from clients using [JWT](http://jwt.io/)
|
||||
tokens. This requires an authorization server that manages access controls,
|
||||
and a cert bundle from this authorization server containing the public key it
|
||||
uses to sign tokens.
|
||||
|
||||
If token authentication is enabled on Notary Server, then any client that
|
||||
does not have a token will be redirected to the authoriziation server.
|
||||
The client will log in, obtain a token, and then present the token to
|
||||
Notary Server on future requests.
|
||||
|
||||
Notary Server should be configured to trust signatures from that authorization
|
||||
server.
|
||||
|
||||
Please see the docs for [Docker Registry v2 authentication](
|
||||
https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md)
|
||||
for more information.
|
||||
|
||||
### Server storage
|
||||
|
||||
Notary Server uses MySQL as a backend for storing the timestamp
|
||||
public keys and the TUF metadata for each repository. It relies on a signing
|
||||
service to store the private keys.
|
||||
|
||||
### Signing service
|
||||
|
||||
We recommend deploying Notary Server with a separate, remote signing
|
||||
service: [Notary Signer](notary-signer.md). This signing service generates
|
||||
and stores the timestamp private keys and performs signing for the server.
|
||||
|
||||
By using remote a signing service, the private keys would never need to be
|
||||
stored on the server itself.
|
||||
|
||||
Notary Signer supports mutual authentication - when you generate client
|
||||
certificates for your deployment of Notary Server, please make
|
||||
sure that the certificates **are not CAs**. Otherwise if the server is
|
||||
compromised, it can sign any number of other client certs.
|
||||
|
||||
As an example, please see [this script](opensslCertGen.sh) to see how to
|
||||
generate client SSL certs with basic constraints using OpenSSL.
|
||||
|
||||
### How to configure and run Notary Server
|
||||
|
||||
A JSON configuration file is used to configure Notary Server. Please see the
|
||||
[Notary Server configuration document](notary-server-config.md)
|
||||
for more details about the format of the configuration file.
|
||||
|
||||
You can also override the parameters of the configuration by
|
||||
setting environment variables of the form `NOTARY_SERVER_var`.
|
||||
|
||||
`var` is the ALL-CAPS, `"_"`-delimited path of keys from the top level of the
|
||||
configuration JSON.
|
||||
|
||||
For instance, if you wanted to override the storage URL of the Notary Server
|
||||
configuration:
|
||||
|
||||
```json
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "dockercondemo:dockercondemo@tcp(notary-mysql)/dockercondemo"
|
||||
}
|
||||
```
|
||||
|
||||
the full path of keys is `storage -> db_url`. So the environment variable you'd
|
||||
need to set would be `NOTARY_SERVER_STORAGE_DB_URL`.
|
||||
|
||||
For example, if running the binary:
|
||||
|
||||
```
|
||||
$ export NOTARY_SERVER_STORAGE_DB_URL=myuser:mypass@tcp(my-db)/dbname?parseTime=true
|
||||
$ NOTARY_SERVER_LOGGING_LEVEL=info notary-server -config /path/to/config.json
|
||||
```
|
||||
|
||||
Note that you cannot override a key whose value is another map.
|
||||
For instance, setting
|
||||
`NOTARY_SERVER_STORAGE='{"storage": {"backend": "memory"}}'` will not
|
||||
set in-memory storage. It just fails to parse. You can only override keys
|
||||
whose values are strings or numbers.
|
||||
|
||||
#### Running Notary Server
|
||||
|
||||
Configuration options:
|
||||
|
||||
- `-config=<config file>` - The JSON configuration file.
|
||||
|
||||
- `-debug` - Passing this flag enables the debugging server on `localhost:8080`.
|
||||
The debugging server provides [pprof](https://golang.org/pkg/net/http/pprof/)
|
||||
and [expvar](https://golang.org/pkg/expvar/) endpoints.
|
||||
|
||||
|
||||
Get the official Docker image, which comes with [some sane defaults](
|
||||
https://github.com/docker/notary/blob/master/fixtures/server-config-local.json),
|
||||
which include a remote trust service but local in-memory backing store.
|
||||
|
||||
You can override the default configuration with environment variables.
|
||||
For example, if you wanted to run it with just a local signing service instead
|
||||
(not recommended for production):
|
||||
|
||||
```
|
||||
$ docker pull docker.io/docker/notary-server
|
||||
$ docker run -p "4443:4443" \
|
||||
-e NOTARY_SERVER_TRUST_SERVICE_TYPE=local
|
||||
notary-server
|
||||
```
|
||||
|
||||
Alternately, you can run the image with your own configuration file entirely.
|
||||
You just need to mount your configuration directory, and then pass the path to
|
||||
that configuration file as an argument to the `docker run` command:
|
||||
|
||||
```
|
||||
$ docker run -p "4443:4443" \
|
||||
-v /path/to/config/dir/on/host:/etc/docker/notary-server/ \
|
||||
notary-server -config=/etc/docker/notary-server/config.json
|
||||
```
|
||||
|
||||
You can also pass the `-debug` flag to the container in addition to the
|
||||
configuration file, but the debug server port is not exposed by the container.
|
||||
In order to view the debug endpoints, you will have to `docker exec` into
|
||||
your container.
|
||||
|
||||
### What happens if the server is compromised
|
||||
|
||||
The server does not hold any keys for repositories, except the for timestamp
|
||||
keys if you are using a local signing service, so the attacker cannot modify
|
||||
the root, targets, or snapshots metadata.
|
||||
|
||||
If you are using a signer service, an attacker cannot get access to the
|
||||
timestamp key either. They can use the server's credentials to get the signer
|
||||
service to sign arbitrary data, such as an empty timestamp,
|
||||
an invalid timestamp, or an old timestamp.
|
||||
|
||||
However, TOFU (trust on first use) would prevent the attacker from tricking
|
||||
existing clients for existing repositories to download arbitrary data.
|
||||
They would need the original root/target/snapshots keys to do that. The
|
||||
attacker could only, by signing bad timestamps, prevent the such a user from
|
||||
seeing any updated metadata.
|
||||
|
||||
The attacker can also make all new keys, and simply replace the repository
|
||||
metadata with metadata signed with these new keys. New clients who have not
|
||||
seen the repository before will trust this bad data, but older clients will
|
||||
know that something is wrong.
|
||||
|
||||
### Ops features
|
||||
|
||||
Notary Server provides the following features for operational friendliness:
|
||||
|
||||
1. A health endpoint at `/_notary_server/health` which returns 200 and a
|
||||
body of `{}` if the server is healthy, and a 500 with a map of
|
||||
failed services if the server cannot access its storage backend.
|
||||
|
||||
If it cannot contact the signing service, an error will be logged but the
|
||||
service will still be considered healthy, because it can still serve
|
||||
existing metadata. It cannot accept updates, so the service is degraded.
|
||||
|
||||
1. A [Bugsnag](https://bugsnag.com) hook for error logs, if a Bugsnag
|
||||
configuration is provided.
|
||||
|
||||
1. A [prometheus](http://prometheus.io/) endpoint at `/_notary_server/metrics`
|
||||
which provides HTTP stats.
|
|
@ -0,0 +1,290 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Notary Signer Configuration File"
|
||||
description = "Specifies the configuration file for Notary Signer"
|
||||
keywords = ["docker, notary, notary-signer, configuration"]
|
||||
[menu.main]
|
||||
parent="mn_notary"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Notary Signer Configuration File
|
||||
|
||||
An example (full) server configuration file.
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"http_addr": ":4444",
|
||||
"grpc_addr": ":7899",
|
||||
"tls_cert_file": "./fixtures/notary-signer.crt",
|
||||
"tls_key_file": "./fixtures/notary-signer.key",
|
||||
"client_ca_file": "./fixtures/notary-server.crt"
|
||||
},
|
||||
"logging": {
|
||||
"level": 2
|
||||
},
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "user:pass@tcp(notarymysql:3306)/databasename?parseTime=true",
|
||||
"default_alias": "passwordalias1"
|
||||
},
|
||||
"reporting": {
|
||||
"bugsnag": {
|
||||
"api_key": "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
|
||||
"release_stage": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `server` section (required)
|
||||
|
||||
"server" in this case refers to Notary Signer's HTTP/GRPC server, not
|
||||
"Notary Server".
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"server": {
|
||||
"http_addr": ":4444",
|
||||
"grpc_addr": ":7899",
|
||||
"tls_cert_file": "./fixtures/notary-signer.crt",
|
||||
"tls_key_file": "./fixtures/notary-signer.key",
|
||||
"client_ca_file": "./fixtures/notary-server.crt"
|
||||
}
|
||||
```
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>http_addr</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The TCP address (IP and port) to listen for HTTP
|
||||
traffic on. Examples:
|
||||
<ul>
|
||||
<li><code>":4444"</code> means listen on port 4444 on all IPs (and
|
||||
hence all interfaces, such as those listed when you run
|
||||
<code>ifconfig</code>)</li>
|
||||
<li><code>"127.0.0.1:4444"</code> means listen on port 4444 on
|
||||
localhost only. That means that the server will not be
|
||||
acessible except locally (via SSH tunnel, or just on a local
|
||||
terminal)</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>grpc_addr</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The TCP address (IP and port) to listen for GRPC
|
||||
traffic. Examples:
|
||||
<ul>
|
||||
<li><code>":7899"</code> means listen on port 7899 on all IPs (and
|
||||
hence all interfaces, such as those listed when you run
|
||||
<code>ifconfig</code>)</li>
|
||||
<li><code>"127.0.0.1:7899"</code> means listen on port 7899 on
|
||||
localhost only. That means that the server will not be
|
||||
acessible except locally (via SSH tunnel, or just on a local
|
||||
terminal)</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_key_file</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The path to the private key to use for
|
||||
HTTPS. The path is relative to the directory of the
|
||||
configuration file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>tls_cert_file</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">The path to the certificate to use for
|
||||
HTTPS. The path is relative to the directory of the
|
||||
configuration file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>client_ca_file</code></td>
|
||||
<td valign="top">no</td>
|
||||
<td valign="top">The root certificate to trust for
|
||||
mutual authentication. If provided, any clients connecting to
|
||||
Notary Signer will have to have a client certificate signed by
|
||||
this root. If not provided, mutual authentication will not be
|
||||
required. The path is relative to the directory of the
|
||||
configuration file.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## `storage` section (required)
|
||||
|
||||
This is used to store encrypted priate keys. We only support MySQL or an
|
||||
in-memory store, currently.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "user:pass@tcp(notarymysql:3306)/databasename?parseTime=true",
|
||||
"default_alias": "passwordalias1"
|
||||
}
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>backend</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">Must be <code>"mysql"</code> or <code>"memory"</code>.
|
||||
If <code>"memory"</code> is selected, the <code>db_url</code>
|
||||
is ignored.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>db_url</code></td>
|
||||
<td valign="top">yes if not <code>memory</code></td>
|
||||
<td valign="top">The <a href="https://github.com/go-sql-driver/mysql">
|
||||
the Data Source Name used to access the DB.</a>
|
||||
(note: please include "parseTime=true" as part of the the DSN)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>default_alias</code></td>
|
||||
<td valign="top">yes if not <code>memory</code></td>
|
||||
<td valign="top">This parameter specifies the alias of the current
|
||||
password used to encrypt the private keys in the DB. All new
|
||||
private keys will be encrypted using this password, which
|
||||
must also be provided as the environment variable
|
||||
<code>NOTARY_SIGNER_<DEFAULT_ALIAS_VALUE></code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
#### Environment variables (required if using MySQL)
|
||||
|
||||
Notary Signer
|
||||
[stores the private keys in encrypted form](notary-signer.md#signer-storage).
|
||||
The alias of the passphrase used to encrypt the keys is also stored. In order
|
||||
to encrypt the keys for storage and decrypt the keys for signing, the
|
||||
passphrase must be passed in as an environment variable.
|
||||
|
||||
For example, the configuration above specifies the default password alias to be
|
||||
`passwordalias1`.
|
||||
|
||||
If this configuration is used, then you must:
|
||||
|
||||
`export NOTARY_SIGNER_PASSWORDALIAS1=mypassword`
|
||||
|
||||
so that that Notary Signer knows to encrypt all keys with the passphrase
|
||||
"mypassword", and to decrypt any private key stored with password alias
|
||||
"passwordalias1" with the passphrase "mypassword".
|
||||
|
||||
Older passwords may also be provided as environment variables. For instance,
|
||||
let's say that you wanted to change the password that is used to create new
|
||||
keys (rotating the passphrase and re-encrypting all the private keys is not
|
||||
supported yet).
|
||||
|
||||
You could change the config to look like:
|
||||
|
||||
```json
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "user:pass@tcp(notarymysql:3306)/databasename?parseTime=true",
|
||||
"default_alias": "passwordalias2"
|
||||
}
|
||||
```
|
||||
|
||||
Then you can set:
|
||||
|
||||
```
|
||||
export NOTARY_SIGNER_PASSWORDALIAS1=mypassword
|
||||
export NOTARY_SIGNER_PASSWORDALIAS2=mynewfancypassword
|
||||
```
|
||||
|
||||
That way, all new keys will be encrypted and decrypted using the passphrase
|
||||
"mynewfancypassword", but old keys that were encrypted using the passphrase
|
||||
"mypassword" can still be decrypted.
|
||||
|
||||
The environment variables for the older passwords are optional, but Notary
|
||||
Signer will not be able to decrypt older keys if they are not provided, and
|
||||
attempts to sign data using those keys will fail.
|
||||
|
||||
## `logging` section (optional)
|
||||
|
||||
The logging section sets the log level of the server. If it is not provided
|
||||
or invalid, the signer defaults to an ERROR logging level.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
}
|
||||
```
|
||||
|
||||
Note that this entire section is optional. However, if you would like to
|
||||
specify a different log level, then you need the required parameters
|
||||
below to configure it.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>level</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td valign="top">One of <code>"debug"</code>, <code>"info"</code>,
|
||||
<code>"warning"</code>, <code>"error"</code>, <code>"fatal"</code>,
|
||||
or <code>"panic"</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## `reporting` section (optional)
|
||||
|
||||
The reporting section contains any configuration for useful for running the
|
||||
service, such as reporting errors. Currently, we only support reporting errors
|
||||
to [Bugsnag](https://bugsnag.com).
|
||||
|
||||
See [bugsnag-go](https://github.com/bugsnag/bugsnag-go/) for more information
|
||||
about these configuration parameters.
|
||||
|
||||
```json
|
||||
"reporting": {
|
||||
"bugsnag": {
|
||||
"api_key": "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
|
||||
"release_stage": "production"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that this entire section is optional. However, if you would like to
|
||||
report errors to Bugsnag, then you need to include a `bugsnag` subsection,
|
||||
along with the required parameters below, to configure it.
|
||||
|
||||
**Bugsnag reporting:**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Parameter</th>
|
||||
<th>Required</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>api_key</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td>The BugSnag API key to use to report errors.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>release_stage</code></td>
|
||||
<td valign="top">yes</td>
|
||||
<td>The current release stage, such as "production". You can
|
||||
use this value to filter errors in the Bugsnag dashboard.</td>
|
||||
</tr>
|
||||
</table>
|
|
@ -0,0 +1,148 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Notary Signer"
|
||||
description = "Description of the Notary Signer"
|
||||
keywords = ["docker, notary, notary-singer"]
|
||||
[menu.main]
|
||||
parent="mn_notary"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Notary Signer
|
||||
|
||||
The Notary Signer is a remote store for private keys. It creates and delete
|
||||
keys, signs data, and returns public key information on demand via its HTTP or
|
||||
RPC api.
|
||||
|
||||
It is intended to be used as a remote RPC service for a
|
||||
[Notary Server](notary-server.md)'s timestamp private keys.
|
||||
|
||||
### Authentication
|
||||
|
||||
Notary Signer supports mutual TLS authentication from
|
||||
[Notary Server](notary-server.md).
|
||||
|
||||
Note that when you generate client certificates to be used with Notary Signer,
|
||||
please make sure that the certificates **are not CAs**. Otherwise any client
|
||||
that is compromised can sign any number of other client certs.
|
||||
|
||||
As an example, please see [this script](opensslCertGen.sh) to see how to
|
||||
generate client SSL certs with basic constraints using OpenSSL.
|
||||
|
||||
### Signer storage
|
||||
|
||||
Notary Signer uses MySQL as a backend for storing the encrypted private keys
|
||||
that is responsible for. The private keys[wrapped](
|
||||
https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31#section-4.4)
|
||||
and [encrypted](
|
||||
https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31#section-4.8)
|
||||
using [Javascript Object Signing and Encryption](
|
||||
https://github.com/dvsekhvalnov/jose2go).
|
||||
|
||||
The passphrase used to encrypt the keys is passed as an environment variable,
|
||||
the name of which [is specified by the confguration file](
|
||||
notary-signer-config.md#storage-section-required).
|
||||
|
||||
### How to configure and run Notary Signer
|
||||
|
||||
A JSON configuration file is used to configure Notary Signer. Please see the
|
||||
[Notary Signer configuration document](notary-signer-config.md)
|
||||
for more details about the format of the configuration file.
|
||||
|
||||
You can also override the parameters of the configuration by
|
||||
setting environment variables of the form `NOTARY_SIGNER_var`.
|
||||
|
||||
`var` is the ALL-CAPS, `"_"`-delimited path of keys from the top level of the
|
||||
configuration JSON.
|
||||
|
||||
For instance, if you wanted to override the storage URL of the Notary Signer
|
||||
configuration:
|
||||
|
||||
```json
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "dockercondemo:dockercondemo@tcp(notary-mysql)/dockercondemo"
|
||||
}
|
||||
```
|
||||
|
||||
the full path of keys is `storage -> db_url`. So the environment variable you'd
|
||||
need to set would be `NOTARY_SIGNER_STORAGE_DB_URL`.
|
||||
|
||||
Note that you cannot override a key whose value is another map.
|
||||
For instance, setting `NOTARY_SIGNER_STORAGE=""` will not disable the
|
||||
MySQL storage. You can only override keys whose values are strings or numbers.
|
||||
|
||||
For example, if running the binary:
|
||||
|
||||
```
|
||||
$ export NOTARY_SIGNER_STORAGE_DB_URL=myuser:mypass@tcp(my-db)/dbname?parseTime=true
|
||||
$ NOTARY_SIGNER_LOGGING_LEVEL=info notary-signer -config /path/to/config.json
|
||||
```
|
||||
|
||||
Note that you cannot override a key whose value is another map.
|
||||
For instance, setting
|
||||
`NOTARY_SIGNER_STORAGE='{"storage": {"backend": "memory"}}'` will not
|
||||
set in-memory storage. It just fails to parse. You can only override keys
|
||||
whose values are strings or numbers.
|
||||
|
||||
#### Running Notary Signer
|
||||
|
||||
Configuration options:
|
||||
|
||||
- `-config=<config file>` - The JSON configuration file.
|
||||
|
||||
- `-debug` - Passing this flag enables the debugging server on `localhost:8080`.
|
||||
The debugging server provides [pprof](https://golang.org/pkg/net/http/pprof/)
|
||||
and [expvar](https://golang.org/pkg/expvar/) endpoints.
|
||||
|
||||
Get the official Docker image, which comes with [some sane defaults](
|
||||
https://github.com/docker/notary/blob/master/fixtures/signer-config-local.json),
|
||||
which uses a local in-memory backing store (not recommended for production).
|
||||
|
||||
You can override the default configuration with environment variables.
|
||||
For example, if you wanted to run it with your own DB
|
||||
(recommended for production):
|
||||
|
||||
```
|
||||
$ docker pull docker.io/docker/notary-signer
|
||||
$ docker run -p "4444:4444" \
|
||||
-e NOTARY_SIGNER_STORAGE_DB_BACKEND="mysql" \
|
||||
-e NOTARY_SIGNER_STORAGE_DB_URL="myuser:mypass@tcp(my-db)/dbName"
|
||||
notary-signer
|
||||
```
|
||||
|
||||
Alternately, you can run the image with your own configuration file entirely.
|
||||
You just need to mount your configuration directory, and then pass the path to
|
||||
that configuration file as an argument to the `docker run` command:
|
||||
|
||||
```
|
||||
$ docker run -p "4444:4444" \
|
||||
-v /path/to/config/dir/on/host:/etc/docker/notary-signer \
|
||||
notary-signer -config=/etc/docker/notary-server/config.json
|
||||
```
|
||||
|
||||
You can also pass the `-debug` flag to the container in addition to the
|
||||
configuration file, but the debug server port is not exposed by the container.
|
||||
In order to view the debug endpoints, you will have to `docker exec` into
|
||||
your container.
|
||||
|
||||
### What happens if the signer is compromised
|
||||
|
||||
All the timestamp private keys stored on the signer will be compromised, and
|
||||
an attacker can sign anything they wish with the timestamp key.
|
||||
|
||||
However, the attacker cannot do anything useful with the timestamp keys unless
|
||||
they also [compromise the Notary Server](
|
||||
notary-server.md#what-happens-if-the-server-is-compromised)
|
||||
|
||||
The attacker can prevent Notary Signer from signing timestap metadata from
|
||||
Notary Server and return invalid public key IDs when the Notary Server
|
||||
requests it. This means an attacker can execute a denial of service attack
|
||||
that prevents the Notary Server from being able to update any metadata.
|
||||
|
||||
### Ops features
|
||||
|
||||
Notary Signer provides the following features for operational friendliness:
|
||||
|
||||
1. A [Bugsnag](https://bugsnag.com) hook for error logs, if a Bugsnag
|
||||
configuration is provided.
|
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Script to be used for generating testing certs only - for a production system,
|
||||
# a public CA or an internal CA should be used
|
||||
|
||||
|
||||
CLIENT_USAGE=<<EOL
|
||||
Generate a self-signed client cert and key to be used in mutual TLS.
|
||||
|
||||
${0} client [-o <output file prefix>]
|
||||
|
||||
Example:
|
||||
${0} client -o clienttls
|
||||
EOL
|
||||
|
||||
SERVER_USAGE=<<EOL
|
||||
Generate a self-signed cert key and certificate.
|
||||
|
||||
${0} server -n <common name> [-o <output file prefix>]
|
||||
[-r <root key if don't want it self-signed>]
|
||||
[-a <subjectAltName>] [-a <subjectAltName>] ...
|
||||
|
||||
Example:
|
||||
${0} server -o servertls -n notary-server -a DNS:notaryserver \
|
||||
-a DNS:notary_server -a IP:127.0.0.1"
|
||||
EOL
|
||||
|
||||
if [[ -z "${1}" ]]; then
|
||||
printf "${CLIENT_USAGE}\n\n${SERVER_USAGE}\n\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OPENSSLCNF=
|
||||
for path in /etc/openssl/openssl.cnf /etc/ssl/openssl.cnf /usr/local/etc/openssl/openssl.cnf; do
|
||||
if [[ -e ${path} ]]; then
|
||||
OPENSSLCNF=${path}
|
||||
fi
|
||||
done
|
||||
if [[ -z ${OPENSSLCNF} ]]; then
|
||||
printf "Could not find openssl.cnf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${1}" == "client" ]]; then
|
||||
# Generate client keys - ensure that these keys are NOT CA's, otherwise
|
||||
# any client that is compromised can sign any number of other client
|
||||
# certs.
|
||||
OUT="clienttls"
|
||||
while getopts "o:" opt "${@:2}"; do
|
||||
case "${opt}" in
|
||||
o)
|
||||
OUT="${OPTARG}"
|
||||
;;
|
||||
*)
|
||||
printf "${CLIENT_USAGE}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
openssl genrsa -out "${OUT}.key" 4096
|
||||
openssl req -new -key "${OUT}.key" -out "${OUT}.csr" \
|
||||
-subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Notary Testing Client Auth'
|
||||
|
||||
cat > "${OUT}.cnf" <<EOL
|
||||
[ssl_client]
|
||||
basicConstraints = critical,CA:FALSE
|
||||
nsCertType = critical, client
|
||||
keyUsage = critical, digitalSignature, nonRepudiation
|
||||
extendedKeyUsage = critical, clientAuth
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
EOL
|
||||
|
||||
openssl x509 -req -days 3650 -in "${OUT}.csr" -signkey "${OUT}.key" \
|
||||
-out "${OUT}.crt" -extfile "${OUT}.cnf" -extensions ssl_client
|
||||
|
||||
rm "${OUT}.cnf" "${OUT}.csr"
|
||||
fi
|
||||
|
||||
if [[ "${1}" == "server" ]]; then
|
||||
# Create a server certificate
|
||||
|
||||
OUT="servertls"
|
||||
COMMONNAME=
|
||||
SAN=
|
||||
while getopts ":o:n:a:" opt "${@:2}"; do
|
||||
case "${opt}" in
|
||||
o)
|
||||
OUT="${OPTARG}"
|
||||
;;
|
||||
n)
|
||||
COMMONNAME="${OPTARG}"
|
||||
;;
|
||||
a)
|
||||
SAN="${SAN} ${OPTARG}"
|
||||
;;
|
||||
*)
|
||||
printf "${SERVER_USAGE}\n\n"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${COMMONNAME}" ]]; then
|
||||
printf "Please provide a common name/domain for the cert."
|
||||
printf "\n\n${SERVER_USAGE}\n\n"
|
||||
exit 1
|
||||
fi
|
||||
PPRINT_DOMAINS="${COMMONNAME}$(printf ", %s" "${SAN[@]}")"
|
||||
printf "Generating server certificate for domains: ${PPRINT_DOMAINS}\n\n"
|
||||
|
||||
# see https://www.openssl.org/docs/manmaster/apps/x509v3_config.html for
|
||||
# more information on extensions
|
||||
cat "${OPENSSLCNF}" > "${OUT}.cnf"
|
||||
cat >> "${OUT}.cnf" <<EOL
|
||||
[ v3_req ]
|
||||
basicConstraints = critical,CA:FALSE
|
||||
nsCertType = critical, server
|
||||
keyUsage = critical, digitalSignature, nonRepudiation
|
||||
extendedKeyUsage = critical, serverAuth
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
EOL
|
||||
if [[ -n "${SAN}" ]]; then
|
||||
printf "subjectAltName=$(echo ${SAN[@]} | tr ' ' ,)" >> "${OUT}.cnf"
|
||||
fi
|
||||
|
||||
openssl genrsa -out "${OUT}.key" 4096
|
||||
openssl req -new -nodes -key "${OUT}.key" -out "${OUT}.csr" \
|
||||
-subj "/C=US/ST=CA/L=San Francisco/O=Docker/CN=${COMMONNAME}" \
|
||||
-config "${OUT}.cnf" -extensions "v3_req"
|
||||
openssl x509 -req -days 3650 -in "${OUT}.csr" -signkey "${OUT}.key" \
|
||||
-out "${OUT}.crt" -extensions v3_req -extfile "${OUT}.cnf"
|
||||
fi
|
Loading…
Reference in New Issue