/
options.go
155 lines (140 loc) · 5.96 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"os"
"path/filepath"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/homedir"
"github.com/docker/go-connections/tlsconfig"
"github.com/spf13/pflag"
)
const (
// DefaultCaFile is the default filename for the CA pem file
DefaultCaFile = "ca.pem"
// DefaultKeyFile is the default filename for the key pem file
DefaultKeyFile = "key.pem"
// DefaultCertFile is the default filename for the cert pem file
DefaultCertFile = "cert.pem"
// FlagTLSVerify is the flag name for the TLS verification option
FlagTLSVerify = "tlsverify"
// FlagTLS is the flag name for the TLS option
FlagTLS = "tls"
// DefaultTLSValue is the default value used for setting the tls option for tcp connections
DefaultTLSValue = false
)
var (
// The configDir (and "DOCKER_CONFIG" environment variable) is now only used
// for the default location for TLS certificates to secure the daemon API.
// It is a leftover from when the "docker" and "dockerd" CLI shared the
// same binary, allowing the DOCKER_CONFIG environment variable to set
// the location for certificates to be used by both.
//
// We need to change this, as there's various issues:
//
// - DOCKER_CONFIG only affects TLS certificates, but does not change the
// location for the actual *daemon configuration* (which defaults to
// "/etc/docker/daemon.json").
// - If no value is set, configDir uses "~/.docker/" as default, but does
// not take $XDG_CONFIG_HOME into account (it uses pkg/homedir.Get, which
// is not XDG_CONFIG_HOME-aware).
// - Using the home directory can be problematic in cases where the CLI and
// daemon actually live on the same host; if DOCKER_CONFIG is set to set
// the "docker" CLI configuration path (and if the daemon shares that
// environment variable, e.g. "sudo -E dockerd"), the daemon may create
// the "~/.docker/" directory, but now the directory may be owned by "root".
//
// We should:
//
// - deprecate DOCKER_CONFIG for the daemon
// - decide where the TLS certs should live by default ("/etc/docker/"?)
// - look at "when" (and when _not_) XDG_CONFIG_HOME should be used. Its
// needed for rootless, but perhaps could be used for non-rootless(?)
// - When changing the location for TLS config, (ideally) they should
// live in a directory separate from "non-sensitive" (configuration-)
// files, so that general configuration can be shared (dotfiles repo
// etc) separate from "sensitive" config (TLS certificates).
//
// TODO(thaJeztah): deprecate DOCKER_CONFIG and re-design daemon config locations. See https://github.com/moby/moby/issues/44640
configDir = os.Getenv("DOCKER_CONFIG")
configFileDir = ".docker"
dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
dockerTLSVerify = os.Getenv("DOCKER_TLS_VERIFY") != ""
)
type daemonOptions struct {
configFile string
daemonConfig *config.Config
flags *pflag.FlagSet
Debug bool
Hosts []string
LogLevel string
TLS bool
TLSVerify bool
TLSOptions *tlsconfig.Options
Validate bool
}
// defaultCertPath uses $DOCKER_CONFIG or ~/.docker, and does not look up
// $XDG_CONFIG_HOME. See the comment on configDir above for further details.
func defaultCertPath() string {
if configDir == "" {
// Set the default path if DOCKER_CONFIG is not set.
configDir = filepath.Join(homedir.Get(), configFileDir)
}
return configDir
}
// newDaemonOptions returns a new daemonFlags
func newDaemonOptions(config *config.Config) *daemonOptions {
return &daemonOptions{
daemonConfig: config,
}
}
// installFlags adds flags for the common options on the FlagSet
func (o *daemonOptions) installFlags(flags *pflag.FlagSet) {
if dockerCertPath == "" {
dockerCertPath = defaultCertPath()
}
flags.BoolVarP(&o.Debug, "debug", "D", false, "Enable debug mode")
flags.BoolVar(&o.Validate, "validate", false, "Validate daemon configuration and exit")
flags.StringVarP(&o.LogLevel, "log-level", "l", "info", `Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")`)
flags.BoolVar(&o.TLS, FlagTLS, DefaultTLSValue, "Use TLS; implied by --tlsverify")
flags.BoolVar(&o.TLSVerify, FlagTLSVerify, dockerTLSVerify || DefaultTLSValue, "Use TLS and verify the remote")
// TODO(thaJeztah): set default TLSOptions in config.New()
o.TLSOptions = &tlsconfig.Options{}
tlsOptions := o.TLSOptions
flags.StringVar(&tlsOptions.CAFile, "tlscacert", filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA")
flags.StringVar(&tlsOptions.CertFile, "tlscert", filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file")
flags.StringVar(&tlsOptions.KeyFile, "tlskey", filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file")
hostOpt := opts.NewNamedListOptsRef("hosts", &o.Hosts, opts.ValidateHost)
flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to")
}
// setDefaultOptions sets default values for options after flag parsing is
// complete
func (o *daemonOptions) setDefaultOptions() {
// Regardless of whether the user sets it to true or false, if they
// specify --tlsverify at all then we need to turn on TLS
// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need
// to check that here as well
if o.flags.Changed(FlagTLSVerify) || o.TLSVerify {
o.TLS = true
}
if o.TLS && !o.flags.Changed(FlagTLSVerify) {
// Enable tls verification unless explicitly disabled
o.TLSVerify = true
}
if !o.TLS {
o.TLSOptions = nil
} else {
o.TLSOptions.InsecureSkipVerify = !o.TLSVerify
// Reset CertFile and KeyFile to empty string if the user did not specify
// the respective flags and the respective default files were not found.
if !o.flags.Changed("tlscert") {
if _, err := os.Stat(o.TLSOptions.CertFile); os.IsNotExist(err) {
o.TLSOptions.CertFile = ""
}
}
if !o.flags.Changed("tlskey") {
if _, err := os.Stat(o.TLSOptions.KeyFile); os.IsNotExist(err) {
o.TLSOptions.KeyFile = ""
}
}
}
}