1
0
mirror of https://github.com/docker/docs.git synced 2026-10-31 10:34:26 +03:00

Merge pull request #210 from docker/client-side-config

Adding client-side root-ca server and server config
This commit is contained in:
Ying Li
2015-10-12 18:46:40 -07:00
9 changed files with 189 additions and 64 deletions

View File

@@ -42,7 +42,7 @@ Prerequisites:
- [docker and docker-compose](http://docs.docker.com/compose/install/)
- [Notary server configuration](#configure-notary-server)
As setup, lets build notary and then start up a local notary-server.
As setup, lets build notary and then start up a local notary-server (don't forget to add `127.0.0.1 notary-server` to your `/etc/hosts`, or if using docker-machine, add `$(docker-machine ip) notary-server`).
```sh
make binaries
@@ -50,7 +50,8 @@ docker-compose build
docker-compose up -d
```
Note: To use the local notary server append `-s http://localhost:4443` to all of the commands below.
Note: In order to have notary use the local notary server and development root CA we can load the local development configuration by appending `-c cmd/notary/config.json` to every command. If you would rather not have to use `-c` on every command, copy `cmd/notary/config.json and cmd/notary/root-ca.crt` to `~/.notary`.
First, lets initiate a notary collection called `example.com/scripts`
@@ -95,7 +96,7 @@ expand this to other storage options.
## Setup for Development
The notary repository comes with Dockerfiles and a docker-compose file
to faciliate development. Simply run the following commands to start
to facilitate development. Simply run the following commands to start
a notary server with a temporary MySQL database in containers:
```
@@ -110,6 +111,16 @@ by running `boot2docker ip`, with kitematic, `echo $DOCKER_HOST` should
show the IP of the VM). If you are using the default Linux setup,
you need to add `127.0.0.1 notary` to your hosts file.
## Successfully connecting over TLS
By default notary-server runs with TLS with certificates signed by a local
CA. In order to be able to successfully connect to it using
either `curl` or `openssl`, you will have to use the root CA file in `fixtures/root-ca.crt`.
OpenSSL example:
`openssl s_client -connect notary-server:4443 -CAfile fixtures/root-ca.crt`
## Compiling Notary Server
Prerequisites:
@@ -166,9 +177,17 @@ either via the CA of your choice, or a self signed certificate.
If using the pem and key provided in fixtures, either:
- add `fixtures/root-ca.crt` to your trusted root certificates
- use the default configuration for notary client that loads the CA root for you by using the flag `-c ./cmd/notary/config.json`
- disable TLS verification by adding the following option notary configuration file in `~/.notary/config.json`:
"skipTLSVerify": true
Otherwise, you will see TLS errors or X509 errors upon initializing the
notary collection.
notary collection:
```
$ notary list diogomonica.com/openvpn
* fatal: Get https://notary-server:4443/v2/: x509: certificate signed by unknown authority
$ notary list diogomonica.com/openvpn -c cmd/notary/config.json
latest b1df2ad7cbc19f06f08b69b4bcd817649b509f3e5420cdd2245a85144288e26d 4056
```

View File

@@ -1,6 +1,8 @@
{
"server": {
"addr": ":4443"
"addr": ":4443",
"tls_key_file": "./fixtures/notary-server.key",
"tls_cert_file": "./fixtures/notary-server.crt"
},
"trust_service": {
"type": "remote",

View File

@@ -1,20 +0,0 @@
{
"server": {
"addr": ":4443",
"tls_key_file": "./fixtures/notary-server.key",
"tls_cert_file": "./fixtures/notary-server.crt"
},
"trust_service": {
"type": "local",
"hostname": "",
"port": "",
"key_algorithm": "ed25519"
},
"logging": {
"level": "debug"
},
"storage": {
"backend": "mysql",
"db_url": "root@tcp(localhost:3306)/notary"
}
}

7
cmd/notary/config.json Normal file
View File

@@ -0,0 +1,7 @@
{
"remote_server": {
"url": "https://notary-server:4443",
"root_ca": "root-ca.crt"
}
}

View File

@@ -7,24 +7,30 @@ import (
"strings"
"github.com/Sirupsen/logrus"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/docker/notary/pkg/passphrase"
"github.com/docker/notary/version"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const configFileName string = "config"
const defaultTrustDir string = ".notary/"
const defaultServerURL = "https://notary-server:4443"
const idSize = 64
const (
configDir = ".notary/"
defaultServerURL = "https://notary-server:4443"
idSize = 64
)
var rawOutput bool
var trustDir string
var remoteTrustServer string
var verbose bool
var retriever passphrase.Retriever
var (
rawOutput bool
verbose bool
trustDir string
configFile string
remoteTrustServer string
configPath string
configFileName = "config"
configFileExt = "json"
retriever passphrase.Retriever
)
func init() {
retriever = getPassphraseRetriever()
@@ -45,17 +51,27 @@ func parseConfig() {
if homeDir == "" {
fatalf("cannot get current user home directory")
}
trustDir = filepath.Join(homeDir, filepath.Dir(defaultTrustDir))
trustDir = filepath.Join(homeDir, filepath.Dir(configDir))
logrus.Debugf("no trust directory provided, using default: %s", trustDir)
} else {
logrus.Debugf("trust directory provided: %s", trustDir)
}
// Setup the configuration details
// If there was a commandline configFile set, we parse that.
// If there wasn't we attempt to find it on the default location ~/.notary/config
if configFile != "" {
configFileExt = strings.TrimPrefix(filepath.Ext(configFile), ".")
configFileName = strings.TrimSuffix(filepath.Base(configFile), filepath.Ext(configFile))
configPath = filepath.Dir(configFile)
} else {
configPath = trustDir
}
// Setup the configuration details into viper
viper.SetConfigName(configFileName)
viper.AddConfigPath(trustDir)
viper.SetConfigType("json")
viper.SetConfigType(configFileExt)
viper.AddConfigPath(configPath)
// Find and read the config file
err := viper.ReadInConfig()
@@ -69,11 +85,6 @@ func parseConfig() {
}
func main() {
serverURL := os.Getenv("NOTARY_SERVER_URL")
if serverURL == "" {
serverURL = defaultServerURL
}
var notaryCmd = &cobra.Command{
Use: "notary",
Short: "notary allows the creation of trusted collections.",
@@ -92,25 +103,26 @@ func main() {
notaryCmd.AddCommand(versionCmd)
notaryCmd.PersistentFlags().StringVarP(&trustDir, "trustdir", "d", "", "directory where the trust data is persisted to")
notaryCmd.PersistentFlags().StringVarP(&configFile, "configFile", "c", "", "path to the configuration file to use")
notaryCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
notaryCmd.AddCommand(cmdKey)
notaryCmd.AddCommand(cmdCert)
notaryCmd.AddCommand(cmdTufInit)
cmdTufInit.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location")
cmdTufInit.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location")
notaryCmd.AddCommand(cmdTufList)
cmdTufList.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary list to output a nonpretty printed version of the targets list. Useful if you need to parse the list.")
cmdTufList.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location")
cmdTufList.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location")
notaryCmd.AddCommand(cmdTufAdd)
notaryCmd.AddCommand(cmdTufRemove)
notaryCmd.AddCommand(cmdTufStatus)
notaryCmd.AddCommand(cmdTufPublish)
cmdTufPublish.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location")
cmdTufPublish.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location")
notaryCmd.AddCommand(cmdTufLookup)
cmdTufLookup.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary lookup to output a nonpretty printed version of the targets list. Useful if you need to parse the list.")
cmdTufLookup.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location")
cmdTufLookup.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location")
notaryCmd.AddCommand(cmdVerify)
cmdVerify.Flags().StringVarP(&remoteTrustServer, "server", "s", serverURL, "Remote trust server location")
cmdVerify.Flags().StringVarP(&remoteTrustServer, "server", "s", "", "Remote trust server location")
notaryCmd.Execute()
}

33
cmd/notary/root-ca.crt Normal file
View File

@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFhjCCA26gAwIBAgIJAMJ4Mtt6YhNLMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEPMA0G
A1UECgwGRG9ja2VyMRowGAYDVQQDDBFOb3RhcnkgVGVzdGluZyBDQTAeFw0xNTA3
MTYwNDI1MDBaFw0yNTA3MTMwNDI1MDBaMF8xCzAJBgNVBAYTAlVTMQswCQYDVQQI
DAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEPMA0GA1UECgwGRG9ja2VyMRow
GAYDVQQDDBFOb3RhcnkgVGVzdGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMzUzq2O07tm3A/4emCN/294jUBnNeGlM4TgsB8W9ingw9CU7oBn
CRTK94cGDHTb5ofcj9Kt4/dSL52uJpkZshmAga4fDDhtntnUHaKYzjoZSKZtq7qV
hC1Dah7s3zftZn4NHiRe82loXH/W0//0MWdQCaLc8E0rd/amrd6EO+5SUwF4dXSk
nWoo3oxtOEnb1uQcWWIiwLRmd1pw3PW/bt/SHssD5dJ+78/nR1qCHhJyLVpylMiy
WijkMKW7mbQFefuCOsQ0QvGG3BrTLu+fVs9GYNzHC+L1bSQbfts4nOSodcB/klhd
mbgVW8mrgeHww/jgb2WJW9Y3RFNp/VEuhVrHiz/NW2qE3nPLEnu0vd50jYIXbvBm
fbhCoJntYAiCY0l8v+POgP3ACtsS41rcn8VyD3Ho4u4186ki71+QRQTsUk2MXRV6
AKQ9u4Cl4d0tV1oHjVyiKDv8PNakNrI48KmnF9R9wMgzDHIoBVQZraVTyPwW9HvS
8K3Lsm6QAE7pErideOyBViOiiqvW7rUaLERTkhGirX2RChwhYLtYIj0LitgzdaT4
JD1JxonqN30g2jk1+mJKMEeWBMTjFqtzuQPYH3HkHKxoNfvEuL5fsZSmhV/mR+yW
lSe1f8r1qpAACj/K3mome/z8UhNxzEW8TCYkwamLkAPF485W64KIYI1tAgMBAAGj
RTBDMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgFGMB0GA1UdDgQW
BBR1DNVNxOFsi9Z7xXfnT2PH+DtoWTANBgkqhkiG9w0BAQsFAAOCAgEAUbbrI3OQ
5XO8HHpoTwVqFzSzKOuSSrcMGrv67rn+2HvVJYfxtusZBS6+Rw7QVG3daPS+pSNX
NM1qyin3BjpNR2lI771yyK/yjjNH9pZPR+8ThJ8/77roLJudTCCPt49PoYgSQQsp
IB75PlqnTWVwccW9pm2zSdqDxFeZpTpwEvgyX8MNCfYeynxp5+S81593z8iav16u
t2I38NyFJKuxin9zNkxkpf/a9Pr/Gk56gw1OfHXp+sW/6KIzx8fjQuL6P8HEpwVG
zXXA8fMX91cIFI4+DTc8mPjtYvT6/PzDWE/q6FZZnbHJ50Ngg5D8uFN5lLgZFNtf
ITeoNjTk2koq8vvTW8FDpMkb50zqGdBoIdDtRFd3oot+MEg+6mba+Kttwg05aJ9a
SIIxjvU4NH6qOXBSgzaI1hMr7DTBnaXxMEBiaNaPg2nqi6uhaUOcVw3F01yBfGfX
aGsNLKpFiKFYQfOR1M2ho/7AL19GYQD3IFWDJqk0/eQLfFR74iKVMz6ndwt9F7A8
0xxGXGpw2NJQTWLQui4Wzt33q541ihzL7EDtybBScUdIOIEO20mHr2czFoTL9IKx
rU0Ck5BMyMBB+DOppP+TeKjutAI1yRVsNoabOuK4oo/FmqysgQoHEE+gVUThrrpE
wV1EBILkX6O4GiMqu1+x92/yCmlKEg0Q6MM=
-----END CERTIFICATE-----

View File

@@ -4,12 +4,14 @@ import (
"bufio"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
@@ -20,6 +22,7 @@ import (
"github.com/docker/distribution/registry/client/transport"
"github.com/docker/docker/pkg/term"
notaryclient "github.com/docker/notary/client"
"github.com/docker/notary/trustmanager"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@@ -93,7 +96,7 @@ func tufAdd(cmd *cobra.Command, args []string) {
parseConfig()
// no online operations are performed by add so the transport argument
// should be nil
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever)
if err != nil {
fatalf(err.Error())
}
@@ -118,7 +121,7 @@ func tufInit(cmd *cobra.Command, args []string) {
gun := args[0]
parseConfig()
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, false), retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, false), retriever)
if err != nil {
fatalf(err.Error())
}
@@ -160,7 +163,7 @@ func tufList(cmd *cobra.Command, args []string) {
gun := args[0]
parseConfig()
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever)
if err != nil {
fatalf(err.Error())
}
@@ -186,7 +189,7 @@ func tufLookup(cmd *cobra.Command, args []string) {
targetName := args[1]
parseConfig()
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever)
if err != nil {
fatalf(err.Error())
}
@@ -208,7 +211,7 @@ func tufStatus(cmd *cobra.Command, args []string) {
gun := args[0]
parseConfig()
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever)
if err != nil {
fatalf(err.Error())
}
@@ -242,7 +245,7 @@ func tufPublish(cmd *cobra.Command, args []string) {
fmt.Println("Pushing changes to ", gun, ".")
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, false), retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, false), retriever)
if err != nil {
fatalf(err.Error())
}
@@ -264,7 +267,7 @@ func tufRemove(cmd *cobra.Command, args []string) {
// no online operation are performed by remove so the transport argument
// should be nil.
repo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, nil, retriever)
repo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), nil, retriever)
if err != nil {
fatalf(err.Error())
}
@@ -291,7 +294,7 @@ func verify(cmd *cobra.Command, args []string) {
gun := args[0]
targetName := args[1]
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, remoteTrustServer, getTransport(gun, true), retriever)
nRepo, err := notaryclient.NewNotaryRepository(trustDir, gun, getRemoteTrustServer(), getTransport(gun, true), retriever)
if err != nil {
fatalf(err.Error())
}
@@ -357,11 +360,28 @@ func (ps passwordStore) Basic(u *url.URL) (string, string) {
}
func getTransport(gun string, readOnly bool) http.RoundTripper {
// Attempt to get a root CA from the config file. Nil is the host defaults.
rootPool := x509.NewCertPool()
rootCAFile := viper.GetString("remote_server.root_ca")
if rootCAFile != "" {
// If we haven't been given an Absolute path, we assume it's relative
// from the configuration directory (~/.notary by default)
if !filepath.IsAbs(rootCAFile) {
rootCAFile = filepath.Join(configPath, rootCAFile)
}
rootCert, err := trustmanager.LoadCertFromFile(rootCAFile)
if err != nil {
fatalf("could not load root ca file. %s", err.Error())
}
rootPool.AddCert(rootCert)
}
// skipTLSVerify is false by default so verification will
// be performed.
tlsConfig := &tls.Config{
InsecureSkipVerify: viper.GetBool("skipTLSVerify"),
InsecureSkipVerify: viper.GetBool("remote_server.skipTLSVerify"),
MinVersion: tls.VersionTLS10,
RootCAs: rootPool,
}
base := &http.Transport{
@@ -386,9 +406,13 @@ func tokenAuth(baseTransport *http.Transport, gun string, readOnly bool) http.Ro
Transport: authTransport,
Timeout: 5 * time.Second,
}
endpoint, err := url.Parse(remoteTrustServer)
trustServerURL := getRemoteTrustServer()
endpoint, err := url.Parse(trustServerURL)
if err != nil {
fatalf("could not parse remote trust server url (%s): %s", remoteTrustServer, err.Error())
fatalf("could not parse remote trust server url (%s): %s", trustServerURL, err.Error())
}
if endpoint.Scheme == "" {
fatalf("trust server url has to be in the form of http(s)://URL:PORT. Got: %s", trustServerURL)
}
subPath, err := url.Parse("v2/")
if err != nil {
@@ -416,3 +440,15 @@ func tokenAuth(baseTransport *http.Transport, gun string, readOnly bool) http.Ro
modifier := transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
return transport.NewTransport(baseTransport, modifier)
}
func getRemoteTrustServer() string {
if remoteTrustServer == "" {
configRemote := viper.GetString("remote_server.url")
if configRemote != "" {
remoteTrustServer = configRemote
} else {
remoteTrustServer = defaultServerURL
}
}
return remoteTrustServer
}

View File

@@ -1,4 +1,4 @@
FROM diogomonica/golang-softhsm2
FROM dockersecurity/golang-softhsm2
MAINTAINER Diogo Monica "diogo@docker.com"
# CHANGE-ME: Default values for SoftHSM2 PIN and SOPIN, used to initialize the first token

36
signer/Dockerfile Normal file
View File

@@ -0,0 +1,36 @@
FROM golang:1.5.1
MAINTAINER Diogo Monica "diogo@docker.com"
RUN apt-get update && apt-get install -y \
sqlite3 \
&& rm -rf /var/lib/apt/lists/*
RUN buildDeps=' \
autoconf \
automake \
build-essential \
libtool \
libssl-dev \
libsqlite3-dev \
' \
&& set -x \
&& apt-get update && apt-get install -y $buildDeps --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& git clone https://github.com/opendnssec/SoftHSMv2.git /usr/src/SoftHSMv2 \
&& cd /usr/src/SoftHSMv2 \
&& sh autogen.sh \
&& ./configure --with-objectstore-backend-db \
&& make \
&& make install \
&& rm -rf /usr/src/SoftHSMv2 \
&& apt-get purge -y --auto-remove $buildDeps \
&& mkdir -p /softhsm2/tokens
# Default locations for the SoftHSM2 configuration and PKCS11 bindings
ENV SOFTHSM2_CONF="/etc/softhsm2/softhsm2.conf"
ENV LIBDIR="/usr/local/lib/softhsm/"
COPY ./softhsm2.conf /etc/softhsm2/softhsm2.conf
ENTRYPOINT ["softhsm2-util"]