Browse code

oadm ca, oadm create-node-config, oadm create-api-client-config, openshift start: add --expire-days and --signer-expire-days options.

Slava Semushin authored on 2016/11/08 02:06:34
Showing 17 changed files
... ...
@@ -11,8 +11,9 @@ import (
11 11
 
12 12
 	kapi "k8s.io/kubernetes/pkg/api"
13 13
 	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
14
-	"k8s.io/kubernetes/pkg/util/crypto"
14
+	kcrypto "k8s.io/kubernetes/pkg/util/crypto"
15 15
 
16
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
16 17
 	"github.com/openshift/origin/pkg/cmd/templates"
17 18
 )
18 19
 
... ...
@@ -24,6 +25,8 @@ type CreateClientOptions struct {
24 24
 	ClientDir string
25 25
 	BaseName  string
26 26
 
27
+	ExpireDays int
28
+
27 29
 	User   string
28 30
 	Groups []string
29 31
 
... ...
@@ -41,7 +44,11 @@ var createClientLong = templates.LongDesc(`
41 41
 	master as the provided user.`)
42 42
 
43 43
 func NewCommandCreateClient(commandName string, fullName string, out io.Writer) *cobra.Command {
44
-	options := &CreateClientOptions{SignerCertOptions: NewDefaultSignerCertOptions(), Output: out}
44
+	options := &CreateClientOptions{
45
+		SignerCertOptions: NewDefaultSignerCertOptions(),
46
+		ExpireDays:        crypto.DefaultCertificateLifetimeInDays,
47
+		Output:            out,
48
+	}
45 49
 
46 50
 	cmd := &cobra.Command{
47 51
 		Use:   commandName,
... ...
@@ -71,6 +78,7 @@ func NewCommandCreateClient(commandName string, fullName string, out io.Writer)
71 71
 	flags.StringVar(&options.APIServerURL, "master", "https://localhost:8443", "The API server's URL.")
72 72
 	flags.StringVar(&options.PublicAPIServerURL, "public-master", "", "The API public facing server's URL (if applicable).")
73 73
 	flags.StringSliceVar(&options.APIServerCAFiles, "certificate-authority", []string{"openshift.local.config/master/ca.crt"}, "Files containing signing authorities to use to verify the API server's serving certificate.")
74
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
74 75
 
75 76
 	// autocompletion hints
76 77
 	cmd.MarkFlagFilename("client-dir")
... ...
@@ -96,7 +104,7 @@ func (o CreateClientOptions) Validate(args []string) error {
96 96
 		return errors.New("certificate-authority must be provided")
97 97
 	} else {
98 98
 		for _, caFile := range o.APIServerCAFiles {
99
-			if _, err := crypto.CertPoolFromFile(caFile); err != nil {
99
+			if _, err := kcrypto.CertPoolFromFile(caFile); err != nil {
100 100
 				return fmt.Errorf("certificate-authority must be a valid certificate file: %v", err)
101 101
 			}
102 102
 		}
... ...
@@ -108,7 +116,9 @@ func (o CreateClientOptions) Validate(args []string) error {
108 108
 	if err := o.SignerCertOptions.Validate(); err != nil {
109 109
 		return err
110 110
 	}
111
-
111
+	if o.ExpireDays <= 0 {
112
+		return errors.New("expire-days must be valid number of days")
113
+	}
112 114
 	return nil
113 115
 }
114 116
 
... ...
@@ -128,12 +138,16 @@ func (o CreateClientOptions) CreateClientFolder() error {
128 128
 		SignerCertOptions: o.SignerCertOptions,
129 129
 		CertFile:          clientCertFile,
130 130
 		KeyFile:           clientKeyFile,
131
+		ExpireDays:        o.ExpireDays,
131 132
 
132 133
 		User:      o.User,
133 134
 		Groups:    o.Groups,
134 135
 		Overwrite: true,
135 136
 		Output:    o.Output,
136 137
 	}
138
+	if err := createClientCertOptions.Validate(nil); err != nil {
139
+		return err
140
+	}
137 141
 	if _, err := createClientCertOptions.CreateClientCert(); err != nil {
138 142
 		return err
139 143
 	}
... ...
@@ -17,6 +17,8 @@ type CreateClientCertOptions struct {
17 17
 	CertFile string
18 18
 	KeyFile  string
19 19
 
20
+	ExpireDays int
21
+
20 22
 	User   string
21 23
 	Groups []string
22 24
 
... ...
@@ -34,6 +36,9 @@ func (o CreateClientCertOptions) Validate(args []string) error {
34 34
 	if len(o.KeyFile) == 0 {
35 35
 		return errors.New("key must be provided")
36 36
 	}
37
+	if o.ExpireDays <= 0 {
38
+		return errors.New("expire-days must be valid number of days")
39
+	}
37 40
 	if len(o.User) == 0 {
38 41
 		return errors.New("user must be provided")
39 42
 	}
... ...
@@ -60,9 +65,9 @@ func (o CreateClientCertOptions) CreateClientCert() (*crypto.TLSCertificateConfi
60 60
 	written := true
61 61
 	userInfo := &user.DefaultInfo{Name: o.User, Groups: o.Groups}
62 62
 	if o.Overwrite {
63
-		cert, err = signerCert.MakeClientCertificate(o.CertFile, o.KeyFile, userInfo)
63
+		cert, err = signerCert.MakeClientCertificate(o.CertFile, o.KeyFile, userInfo, o.ExpireDays)
64 64
 	} else {
65
-		cert, written, err = signerCert.EnsureClientCertificate(o.CertFile, o.KeyFile, userInfo)
65
+		cert, written, err = signerCert.EnsureClientCertificate(o.CertFile, o.KeyFile, userInfo, o.ExpireDays)
66 66
 	}
67 67
 	if written {
68 68
 		glog.V(3).Infof("Generated new client cert as %s and key as %s\n", o.CertFile, o.KeyFile)
... ...
@@ -14,9 +14,10 @@ import (
14 14
 
15 15
 	kapi "k8s.io/kubernetes/pkg/api"
16 16
 	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
17
-	"k8s.io/kubernetes/pkg/util/crypto"
17
+	kcrypto "k8s.io/kubernetes/pkg/util/crypto"
18 18
 	utilerrors "k8s.io/kubernetes/pkg/util/errors"
19 19
 
20
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
20 21
 	"github.com/openshift/origin/pkg/cmd/templates"
21 22
 	"github.com/openshift/origin/pkg/util/parallel"
22 23
 )
... ...
@@ -72,6 +73,9 @@ type CreateMasterCertsOptions struct {
72 72
 	CertDir    string
73 73
 	SignerName string
74 74
 
75
+	ExpireDays       int
76
+	SignerExpireDays int
77
+
75 78
 	APIServerCAFiles []string
76 79
 	CABundleFile     string
77 80
 
... ...
@@ -85,7 +89,11 @@ type CreateMasterCertsOptions struct {
85 85
 }
86 86
 
87 87
 func NewCommandCreateMasterCerts(commandName string, fullName string, out io.Writer) *cobra.Command {
88
-	options := &CreateMasterCertsOptions{Output: out}
88
+	options := &CreateMasterCertsOptions{
89
+		ExpireDays:       crypto.DefaultCertificateLifetimeInDays,
90
+		SignerExpireDays: crypto.DefaultCACertificateLifetimeInDays,
91
+		Output:           out,
92
+	}
89 93
 
90 94
 	cmd := &cobra.Command{
91 95
 		Use:   commandName,
... ...
@@ -113,6 +121,9 @@ func NewCommandCreateMasterCerts(commandName string, fullName string, out io.Wri
113 113
 	flags.StringSliceVar(&options.Hostnames, "hostnames", options.Hostnames, "Every hostname or IP that server certs should be valid for (comma-delimited list)")
114 114
 	flags.BoolVar(&options.Overwrite, "overwrite", false, "Overwrite all existing cert/key/config files (WARNING: includes signer/CA)")
115 115
 
116
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
117
+	flags.IntVar(&options.SignerExpireDays, "signer-expire-days", options.SignerExpireDays, "Validity of the CA certificate in days (defaults to 5 years). WARNING: extending this above default value is highly discouraged.")
118
+
116 119
 	// set dynamic value annotation - allows man pages  to be generated and verified
117 120
 	flags.SetAnnotation("signer-name", "manpage-def-value", []string{"openshift-signer@<current_timestamp>"})
118 121
 
... ...
@@ -136,6 +147,12 @@ func (o CreateMasterCertsOptions) Validate(args []string) error {
136 136
 	if len(o.SignerName) == 0 {
137 137
 		return errors.New("signer-name must be provided")
138 138
 	}
139
+	if o.ExpireDays <= 0 {
140
+		return errors.New("expire-days must be valid number of days")
141
+	}
142
+	if o.SignerExpireDays <= 0 {
143
+		return errors.New("signer-expire-days must be valid number of days")
144
+	}
139 145
 	if len(o.APIServerURL) == 0 {
140 146
 		return errors.New("master must be provided")
141 147
 	} else if u, err := url.Parse(o.APIServerURL); err != nil {
... ...
@@ -153,7 +170,7 @@ func (o CreateMasterCertsOptions) Validate(args []string) error {
153 153
 	}
154 154
 
155 155
 	for _, caFile := range o.APIServerCAFiles {
156
-		if _, err := crypto.CertPoolFromFile(caFile); err != nil {
156
+		if _, err := kcrypto.CertPoolFromFile(caFile); err != nil {
157 157
 			return fmt.Errorf("certificate authority must be a valid certificate file: %v", err)
158 158
 		}
159 159
 	}
... ...
@@ -168,6 +185,7 @@ func (o CreateMasterCertsOptions) CreateMasterCerts() error {
168 168
 		CertFile:   DefaultCertFilename(o.CertDir, CAFilePrefix),
169 169
 		KeyFile:    DefaultKeyFilename(o.CertDir, CAFilePrefix),
170 170
 		SerialFile: DefaultSerialFilename(o.CertDir, CAFilePrefix),
171
+		ExpireDays: o.SignerExpireDays,
171 172
 		Name:       o.SignerName,
172 173
 		Overwrite:  o.Overwrite,
173 174
 		Output:     o.Output,
... ...
@@ -261,11 +279,16 @@ func (o CreateMasterCertsOptions) createClientCert(clientCertInfo ClientCertInfo
261 261
 		CertFile: clientCertInfo.CertLocation.CertFile,
262 262
 		KeyFile:  clientCertInfo.CertLocation.KeyFile,
263 263
 
264
+		ExpireDays: o.ExpireDays,
265
+
264 266
 		User:      clientCertInfo.User,
265 267
 		Groups:    clientCertInfo.Groups.List(),
266 268
 		Overwrite: o.Overwrite,
267 269
 		Output:    o.Output,
268 270
 	}
271
+	if err := clientCertOptions.Validate(nil); err != nil {
272
+		return err
273
+	}
269 274
 	if _, err := clientCertOptions.CreateClientCert(); err != nil {
270 275
 		return err
271 276
 	}
... ...
@@ -295,6 +318,8 @@ func (o CreateMasterCertsOptions) createServerCerts(getSignerCertOptions *Signer
295 295
 			CertFile: serverCertInfo.CertFile,
296 296
 			KeyFile:  serverCertInfo.KeyFile,
297 297
 
298
+			ExpireDays: o.ExpireDays,
299
+
298 300
 			Hostnames: o.Hostnames,
299 301
 			Overwrite: o.Overwrite,
300 302
 			Output:    o.Output,
... ...
@@ -333,6 +358,7 @@ func (o CreateMasterCertsOptions) createServiceSigningCA(getSignerCertOptions *S
333 333
 		CertFile:   caInfo.CertFile,
334 334
 		KeyFile:    caInfo.KeyFile,
335 335
 		SerialFile: "", // we want the random cert serial for this one
336
+		ExpireDays: o.SignerExpireDays,
336 337
 		Name:       DefaultServiceServingCertSignerName(),
337 338
 		Output:     o.Output,
338 339
 
... ...
@@ -18,11 +18,12 @@ import (
18 18
 	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
19 19
 	"k8s.io/kubernetes/pkg/master/ports"
20 20
 	"k8s.io/kubernetes/pkg/runtime"
21
-	"k8s.io/kubernetes/pkg/util/crypto"
21
+	kcrypto "k8s.io/kubernetes/pkg/util/crypto"
22 22
 
23 23
 	"github.com/openshift/origin/pkg/cmd/flagtypes"
24 24
 	configapi "github.com/openshift/origin/pkg/cmd/server/api"
25 25
 	latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest"
26
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
26 27
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
27 28
 	"github.com/openshift/origin/pkg/cmd/util/variable"
28 29
 )
... ...
@@ -47,6 +48,7 @@ type CreateNodeConfigOptions struct {
47 47
 	ClientKeyFile     string
48 48
 	ServerCertFile    string
49 49
 	ServerKeyFile     string
50
+	ExpireDays        int
50 51
 	NodeClientCAFile  string
51 52
 	APIServerCAFiles  []string
52 53
 	APIServerURL      string
... ...
@@ -92,6 +94,7 @@ func NewCommandNodeConfig(commandName string, fullName string, out io.Writer) *c
92 92
 	flags.StringVar(&options.ClientKeyFile, "client-key", "", "The client key file for the node to contact the API.")
93 93
 	flags.StringVar(&options.ServerCertFile, "server-certificate", "", "The server cert file for the node to serve secure traffic.")
94 94
 	flags.StringVar(&options.ServerKeyFile, "server-key", "", "The server key file for the node to serve secure traffic.")
95
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
95 96
 	flags.StringVar(&options.NodeClientCAFile, "node-client-certificate-authority", options.NodeClientCAFile, "The file containing signing authorities to use to verify requests to the node. If empty, all requests will be allowed.")
96 97
 	flags.StringVar(&options.APIServerURL, "master", options.APIServerURL, "The API server's URL.")
97 98
 	flags.StringSliceVar(&options.APIServerCAFiles, "certificate-authority", options.APIServerCAFiles, "Files containing signing authorities to use to verify the API server's serving certificate.")
... ...
@@ -111,7 +114,10 @@ func NewCommandNodeConfig(commandName string, fullName string, out io.Writer) *c
111 111
 }
112 112
 
113 113
 func NewDefaultCreateNodeConfigOptions() *CreateNodeConfigOptions {
114
-	options := &CreateNodeConfigOptions{SignerCertOptions: NewDefaultSignerCertOptions()}
114
+	options := &CreateNodeConfigOptions{
115
+		SignerCertOptions: NewDefaultSignerCertOptions(),
116
+		ExpireDays:        crypto.DefaultCertificateLifetimeInDays,
117
+	}
115 118
 	options.VolumeDir = "openshift.local.volumes"
116 119
 	// TODO: replace me with a proper round trip of config options through decode
117 120
 	options.DNSDomain = "cluster.local"
... ...
@@ -160,7 +166,7 @@ func (o CreateNodeConfigOptions) Validate(args []string) error {
160 160
 		return fmt.Errorf("--certificate-authority must be a valid certificate file")
161 161
 	} else {
162 162
 		for _, caFile := range o.APIServerCAFiles {
163
-			if _, err := crypto.CertPoolFromFile(caFile); err != nil {
163
+			if _, err := kcrypto.CertPoolFromFile(caFile); err != nil {
164 164
 				return fmt.Errorf("--certificate-authority must be a valid certificate file: %v", err)
165 165
 			}
166 166
 		}
... ...
@@ -197,6 +203,10 @@ func (o CreateNodeConfigOptions) Validate(args []string) error {
197 197
 		}
198 198
 	}
199 199
 
200
+	if o.ExpireDays < 0 {
201
+		return errors.New("expire-days must be valid number of days")
202
+	}
203
+
200 204
 	return nil
201 205
 }
202 206
 
... ...
@@ -285,6 +295,8 @@ func (o CreateNodeConfigOptions) MakeClientCert(clientCertFile, clientKeyFile st
285 285
 			CertFile: clientCertFile,
286 286
 			KeyFile:  clientKeyFile,
287 287
 
288
+			ExpireDays: o.ExpireDays,
289
+
288 290
 			User:   "system:node:" + o.NodeName,
289 291
 			Groups: []string{bootstrappolicy.NodesGroup},
290 292
 			Output: o.Output,
... ...
@@ -317,6 +329,8 @@ func (o CreateNodeConfigOptions) MakeAndWriteServerCert(serverCertFile, serverKe
317 317
 			CertFile: serverCertFile,
318 318
 			KeyFile:  serverKeyFile,
319 319
 
320
+			ExpireDays: o.ExpireDays,
321
+
320 322
 			Hostnames: o.Hostnames,
321 323
 			Output:    o.Output,
322 324
 		}
... ...
@@ -75,6 +75,7 @@ func makeSignerCert(t *testing.T) (string, string, string) {
75 75
 		CertFile:   certFile.Name(),
76 76
 		KeyFile:    keyFile.Name(),
77 77
 		SerialFile: serialFile.Name(),
78
+		ExpireDays: 365,
78 79
 		Name:       "unit-test-signer",
79 80
 		Overwrite:  true,
80 81
 	}
... ...
@@ -23,6 +23,8 @@ type CreateServerCertOptions struct {
23 23
 	CertFile string
24 24
 	KeyFile  string
25 25
 
26
+	ExpireDays int
27
+
26 28
 	Hostnames []string
27 29
 	Overwrite bool
28 30
 	Output    io.Writer
... ...
@@ -46,7 +48,11 @@ var createServerLong = templates.LongDesc(`
46 46
 	`)
47 47
 
48 48
 func NewCommandCreateServerCert(commandName string, fullName string, out io.Writer) *cobra.Command {
49
-	options := &CreateServerCertOptions{SignerCertOptions: NewDefaultSignerCertOptions(), Output: out}
49
+	options := &CreateServerCertOptions{
50
+		SignerCertOptions: NewDefaultSignerCertOptions(),
51
+		ExpireDays:        crypto.DefaultCertificateLifetimeInDays,
52
+		Output:            out,
53
+	}
50 54
 
51 55
 	cmd := &cobra.Command{
52 56
 		Use:   commandName,
... ...
@@ -72,6 +78,8 @@ func NewCommandCreateServerCert(commandName string, fullName string, out io.Writ
72 72
 	flags.StringSliceVar(&options.Hostnames, "hostnames", options.Hostnames, "Every hostname or IP you want server certs to be valid for. Comma delimited list")
73 73
 	flags.BoolVar(&options.Overwrite, "overwrite", true, "Overwrite existing cert files if found.  If false, any existing file will be left as-is.")
74 74
 
75
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificate in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
76
+
75 77
 	// autocompletion hints
76 78
 	cmd.MarkFlagFilename("cert")
77 79
 	cmd.MarkFlagFilename("key")
... ...
@@ -93,6 +101,10 @@ func (o CreateServerCertOptions) Validate(args []string) error {
93 93
 		return errors.New("key must be provided")
94 94
 	}
95 95
 
96
+	if o.ExpireDays <= 0 {
97
+		return errors.New("expire-days must be valid number of days")
98
+	}
99
+
96 100
 	if o.SignerCertOptions == nil {
97 101
 		return errors.New("signer options are required")
98 102
 	}
... ...
@@ -114,9 +126,9 @@ func (o CreateServerCertOptions) CreateServerCert() (*crypto.TLSCertificateConfi
114 114
 	var ca *crypto.TLSCertificateConfig
115 115
 	written := true
116 116
 	if o.Overwrite {
117
-		ca, err = signerCert.MakeAndWriteServerCert(o.CertFile, o.KeyFile, sets.NewString([]string(o.Hostnames)...))
117
+		ca, err = signerCert.MakeAndWriteServerCert(o.CertFile, o.KeyFile, sets.NewString([]string(o.Hostnames)...), o.ExpireDays)
118 118
 	} else {
119
-		ca, written, err = signerCert.EnsureServerCert(o.CertFile, o.KeyFile, sets.NewString([]string(o.Hostnames)...))
119
+		ca, written, err = signerCert.EnsureServerCert(o.CertFile, o.KeyFile, sets.NewString([]string(o.Hostnames)...), o.ExpireDays)
120 120
 	}
121 121
 	if written {
122 122
 		glog.V(3).Infof("Generated new server certificate as %s, key as %s\n", o.CertFile, o.KeyFile)
... ...
@@ -20,6 +20,7 @@ type CreateSignerCertOptions struct {
20 20
 	CertFile   string
21 21
 	KeyFile    string
22 22
 	SerialFile string
23
+	ExpireDays int
23 24
 	Name       string
24 25
 	Output     io.Writer
25 26
 
... ...
@@ -33,6 +34,8 @@ func BindCreateSignerCertOptions(options *CreateSignerCertOptions, flags *pflag.
33 33
 	flags.StringVar(&options.Name, prefix+"name", DefaultSignerName(), "The name of the signer.")
34 34
 	flags.BoolVar(&options.Overwrite, prefix+"overwrite", options.Overwrite, "Overwrite existing cert files if found.  If false, any existing file will be left as-is.")
35 35
 
36
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificate in days (defaults to 5 years). WARNING: extending this above default value is highly discouraged.")
37
+
36 38
 	// set dynamic value annotation - allows man pages  to be generated and verified
37 39
 	flags.SetAnnotation(prefix+"name", "manpage-def-value", []string{"openshift-signer@<current_timestamp>"})
38 40
 
... ...
@@ -46,7 +49,11 @@ var createSignerLong = templates.LongDesc(`
46 46
 	Create a self-signed CA key/cert for signing certificates used by server components.`)
47 47
 
48 48
 func NewCommandCreateSignerCert(commandName string, fullName string, out io.Writer) *cobra.Command {
49
-	options := &CreateSignerCertOptions{Overwrite: true, Output: out}
49
+	options := &CreateSignerCertOptions{
50
+		ExpireDays: crypto.DefaultCACertificateLifetimeInDays,
51
+		Output:     out,
52
+		Overwrite:  true,
53
+	}
50 54
 
51 55
 	cmd := &cobra.Command{
52 56
 		Use:   commandName,
... ...
@@ -78,6 +85,9 @@ func (o CreateSignerCertOptions) Validate(args []string) error {
78 78
 	if len(o.KeyFile) == 0 {
79 79
 		return errors.New("key must be provided")
80 80
 	}
81
+	if o.ExpireDays <= 0 {
82
+		return errors.New("expire-days must be valid number of days")
83
+	}
81 84
 	if len(o.Name) == 0 {
82 85
 		return errors.New("name must be provided")
83 86
 	}
... ...
@@ -91,9 +101,9 @@ func (o CreateSignerCertOptions) CreateSignerCert() (*crypto.CA, error) {
91 91
 	var err error
92 92
 	written := true
93 93
 	if o.Overwrite {
94
-		ca, err = crypto.MakeCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name)
94
+		ca, err = crypto.MakeCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name, o.ExpireDays)
95 95
 	} else {
96
-		ca, written, err = crypto.EnsureCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name)
96
+		ca, written, err = crypto.EnsureCA(o.CertFile, o.KeyFile, o.SerialFile, o.Name, o.ExpireDays)
97 97
 	}
98 98
 	if written {
99 99
 		glog.V(3).Infof("Generated new CA for %s: cert in %s and key in %s\n", o.Name, o.CertFile, o.KeyFile)
... ...
@@ -174,12 +174,9 @@ func GetTLSCertificateConfig(certFile, keyFile string) (*TLSCertificateConfig, e
174 174
 	return &TLSCertificateConfig{certs, key}, nil
175 175
 }
176 176
 
177
-var (
178
-	// Default ca certs to be long-lived
179
-	caLifetime = time.Hour * 24 * 365 * 5
180
-
181
-	// Default templates to last for two years
182
-	lifetime = time.Hour * 24 * 365 * 2
177
+const (
178
+	DefaultCertificateLifetimeInDays   = 365 * 2 // 2 years
179
+	DefaultCACertificateLifetimeInDays = 365 * 5 // 5 years
183 180
 
184 181
 	// Default keys are 2048 bits
185 182
 	keyBits = 2048
... ...
@@ -261,11 +258,11 @@ func (s *RandomSerialGenerator) Next(template *x509.Certificate) (int64, error)
261 261
 
262 262
 // EnsureCA returns a CA, whether it was created (as opposed to pre-existing), and any error
263 263
 // if serialFile is empty, a RandomSerialGenerator will be used
264
-func EnsureCA(certFile, keyFile, serialFile, name string) (*CA, bool, error) {
264
+func EnsureCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, bool, error) {
265 265
 	if ca, err := GetCA(certFile, keyFile, serialFile); err == nil {
266 266
 		return ca, false, err
267 267
 	}
268
-	ca, err := MakeCA(certFile, keyFile, serialFile, name)
268
+	ca, err := MakeCA(certFile, keyFile, serialFile, name, expireDays)
269 269
 	return ca, true, err
270 270
 }
271 271
 
... ...
@@ -293,17 +290,14 @@ func GetCA(certFile, keyFile, serialFile string) (*CA, error) {
293 293
 }
294 294
 
295 295
 // if serialFile is empty, a RandomSerialGenerator will be used
296
-func MakeCA(certFile, keyFile, serialFile, name string) (*CA, error) {
296
+func MakeCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, error) {
297 297
 	glog.V(2).Infof("Generating new CA for %s cert, and key in %s, %s", name, certFile, keyFile)
298 298
 	// Create CA cert
299 299
 	rootcaPublicKey, rootcaPrivateKey, err := NewKeyPair()
300 300
 	if err != nil {
301 301
 		return nil, err
302 302
 	}
303
-	rootcaTemplate, err := newSigningCertificateTemplate(pkix.Name{CommonName: name})
304
-	if err != nil {
305
-		return nil, err
306
-	}
303
+	rootcaTemplate := newSigningCertificateTemplate(pkix.Name{CommonName: name}, expireDays, time.Now)
307 304
 	rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey)
308 305
 	if err != nil {
309 306
 		return nil, err
... ...
@@ -335,10 +329,10 @@ func MakeCA(certFile, keyFile, serialFile, name string) (*CA, error) {
335 335
 	}, nil
336 336
 }
337 337
 
338
-func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.String) (*TLSCertificateConfig, bool, error) {
338
+func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.String, expireDays int) (*TLSCertificateConfig, bool, error) {
339 339
 	certConfig, err := GetServerCert(certFile, keyFile, hostnames)
340 340
 	if err != nil {
341
-		certConfig, err = ca.MakeAndWriteServerCert(certFile, keyFile, hostnames)
341
+		certConfig, err = ca.MakeAndWriteServerCert(certFile, keyFile, hostnames, expireDays)
342 342
 		return certConfig, true, err
343 343
 	}
344 344
 
... ...
@@ -363,10 +357,10 @@ func GetServerCert(certFile, keyFile string, hostnames sets.String) (*TLSCertifi
363 363
 	return nil, fmt.Errorf("Existing server certificate in %s was missing some hostnames (%v) or IP addresses (%v).", certFile, missingDns, missingIps)
364 364
 }
365 365
 
366
-func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.String) (*TLSCertificateConfig, error) {
366
+func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.String, expireDays int) (*TLSCertificateConfig, error) {
367 367
 	glog.V(4).Infof("Generating server certificate in %s, key in %s", certFile, keyFile)
368 368
 
369
-	server, err := ca.MakeServerCert(hostnames)
369
+	server, err := ca.MakeServerCert(hostnames, expireDays)
370 370
 	if err != nil {
371 371
 		return nil, err
372 372
 	}
... ...
@@ -376,9 +370,9 @@ func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.St
376 376
 	return server, nil
377 377
 }
378 378
 
379
-func (ca *CA) MakeServerCert(hostnames sets.String) (*TLSCertificateConfig, error) {
379
+func (ca *CA) MakeServerCert(hostnames sets.String, expireDays int) (*TLSCertificateConfig, error) {
380 380
 	serverPublicKey, serverPrivateKey, _ := NewKeyPair()
381
-	serverTemplate, _ := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List())
381
+	serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), expireDays, time.Now)
382 382
 	serverCrt, err := ca.signCertificate(serverTemplate, serverPublicKey)
383 383
 	if err != nil {
384 384
 		return nil, err
... ...
@@ -390,17 +384,17 @@ func (ca *CA) MakeServerCert(hostnames sets.String) (*TLSCertificateConfig, erro
390 390
 	return server, nil
391 391
 }
392 392
 
393
-func (ca *CA) EnsureClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificateConfig, bool, error) {
393
+func (ca *CA) EnsureClientCertificate(certFile, keyFile string, u user.Info, expireDays int) (*TLSCertificateConfig, bool, error) {
394 394
 	certConfig, err := GetTLSCertificateConfig(certFile, keyFile)
395 395
 	if err != nil {
396
-		certConfig, err = ca.MakeClientCertificate(certFile, keyFile, u)
396
+		certConfig, err = ca.MakeClientCertificate(certFile, keyFile, u, expireDays)
397 397
 		return certConfig, true, err // true indicates we wrote the files.
398 398
 	}
399 399
 
400 400
 	return certConfig, false, nil
401 401
 }
402 402
 
403
-func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificateConfig, error) {
403
+func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info, expireDays int) (*TLSCertificateConfig, error) {
404 404
 	glog.V(4).Infof("Generating client cert in %s and key in %s", certFile, keyFile)
405 405
 	// ensure parent dirs
406 406
 	if err := os.MkdirAll(filepath.Dir(certFile), os.FileMode(0755)); err != nil {
... ...
@@ -411,7 +405,7 @@ func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info) (*TLS
411 411
 	}
412 412
 
413 413
 	clientPublicKey, clientPrivateKey, _ := NewKeyPair()
414
-	clientTemplate, _ := newClientCertificateTemplate(x509request.UserToSubject(u))
414
+	clientTemplate := newClientCertificateTemplate(x509request.UserToSubject(u), expireDays, time.Now)
415 415
 	clientCrt, err := ca.signCertificate(clientTemplate, clientPublicKey)
416 416
 	if err != nil {
417 417
 		return nil, err
... ...
@@ -455,31 +449,53 @@ func NewKeyPair() (crypto.PublicKey, crypto.PrivateKey, error) {
455 455
 }
456 456
 
457 457
 // Can be used for CA or intermediate signing certs
458
-func newSigningCertificateTemplate(subject pkix.Name) (*x509.Certificate, error) {
458
+func newSigningCertificateTemplate(subject pkix.Name, expireDays int, currentTime func() time.Time) *x509.Certificate {
459
+	var caLifetimeInDays = DefaultCACertificateLifetimeInDays
460
+	if expireDays > 0 {
461
+		caLifetimeInDays = expireDays
462
+	}
463
+
464
+	if caLifetimeInDays > DefaultCACertificateLifetimeInDays {
465
+		warnAboutCertificateLifeTime(subject.CommonName, DefaultCACertificateLifetimeInDays)
466
+	}
467
+
468
+	caLifetime := time.Duration(caLifetimeInDays) * 24 * time.Hour
469
+
459 470
 	return &x509.Certificate{
460 471
 		Subject: subject,
461 472
 
462 473
 		SignatureAlgorithm: x509.SHA256WithRSA,
463 474
 
464
-		NotBefore:    time.Now().Add(-1 * time.Second),
465
-		NotAfter:     time.Now().Add(caLifetime),
475
+		NotBefore:    currentTime().Add(-1 * time.Second),
476
+		NotAfter:     currentTime().Add(caLifetime),
466 477
 		SerialNumber: big.NewInt(1),
467 478
 
468 479
 		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
469 480
 		BasicConstraintsValid: true,
470 481
 		IsCA: true,
471
-	}, nil
482
+	}
472 483
 }
473 484
 
474 485
 // Can be used for ListenAndServeTLS
475
-func newServerCertificateTemplate(subject pkix.Name, hosts []string) (*x509.Certificate, error) {
486
+func newServerCertificateTemplate(subject pkix.Name, hosts []string, expireDays int, currentTime func() time.Time) *x509.Certificate {
487
+	var lifetimeInDays = DefaultCertificateLifetimeInDays
488
+	if expireDays > 0 {
489
+		lifetimeInDays = expireDays
490
+	}
491
+
492
+	if lifetimeInDays > DefaultCertificateLifetimeInDays {
493
+		warnAboutCertificateLifeTime(subject.CommonName, DefaultCertificateLifetimeInDays)
494
+	}
495
+
496
+	lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour
497
+
476 498
 	template := &x509.Certificate{
477 499
 		Subject: subject,
478 500
 
479 501
 		SignatureAlgorithm: x509.SHA256WithRSA,
480 502
 
481
-		NotBefore:    time.Now().Add(-1 * time.Second),
482
-		NotAfter:     time.Now().Add(lifetime),
503
+		NotBefore:    currentTime().Add(-1 * time.Second),
504
+		NotAfter:     currentTime().Add(lifetime),
483 505
 		SerialNumber: big.NewInt(1),
484 506
 
485 507
 		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
... ...
@@ -489,7 +505,7 @@ func newServerCertificateTemplate(subject pkix.Name, hosts []string) (*x509.Cert
489 489
 
490 490
 	template.IPAddresses, template.DNSNames = IPAddressesDNSNames(hosts)
491 491
 
492
-	return template, nil
492
+	return template
493 493
 }
494 494
 
495 495
 func IPAddressesDNSNames(hosts []string) ([]net.IP, []string) {
... ...
@@ -542,20 +558,37 @@ func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
542 542
 }
543 543
 
544 544
 // Can be used as a certificate in http.Transport TLSClientConfig
545
-func newClientCertificateTemplate(subject pkix.Name) (*x509.Certificate, error) {
545
+func newClientCertificateTemplate(subject pkix.Name, expireDays int, currentTime func() time.Time) *x509.Certificate {
546
+	var lifetimeInDays = DefaultCertificateLifetimeInDays
547
+	if expireDays > 0 {
548
+		lifetimeInDays = expireDays
549
+	}
550
+
551
+	if lifetimeInDays > DefaultCertificateLifetimeInDays {
552
+		warnAboutCertificateLifeTime(subject.CommonName, DefaultCertificateLifetimeInDays)
553
+	}
554
+
555
+	lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour
556
+
546 557
 	return &x509.Certificate{
547 558
 		Subject: subject,
548 559
 
549 560
 		SignatureAlgorithm: x509.SHA256WithRSA,
550 561
 
551
-		NotBefore:    time.Now().Add(-1 * time.Second),
552
-		NotAfter:     time.Now().Add(lifetime),
562
+		NotBefore:    currentTime().Add(-1 * time.Second),
563
+		NotAfter:     currentTime().Add(lifetime),
553 564
 		SerialNumber: big.NewInt(1),
554 565
 
555 566
 		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
556 567
 		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
557 568
 		BasicConstraintsValid: true,
558
-	}, nil
569
+	}
570
+}
571
+
572
+func warnAboutCertificateLifeTime(name string, defaultLifetimeInDays int) {
573
+	defaultLifetimeInYears := defaultLifetimeInDays / 365
574
+	fmt.Fprintf(os.Stderr, "WARNING: Validity period of the certificate for %q is greater than %d years!\n", name, defaultLifetimeInYears)
575
+	fmt.Fprintln(os.Stderr, "WARNING: By security reasons it is strongly recommended to change this period and make it smaller!")
559 576
 }
560 577
 
561 578
 func signCertificate(template *x509.Certificate, requestKey crypto.PublicKey, issuer *x509.Certificate, issuerKey crypto.PrivateKey) (*x509.Certificate, error) {
... ...
@@ -6,8 +6,11 @@ import (
6 6
 	"crypto/x509/pkix"
7 7
 	"fmt"
8 8
 	"testing"
9
+	"time"
9 10
 )
10 11
 
12
+const certificateLifetime = 365 * 2
13
+
11 14
 func TestCrypto(t *testing.T) {
12 15
 	roots := x509.NewCertPool()
13 16
 	intermediates := x509.NewCertPool()
... ...
@@ -78,10 +81,7 @@ func buildCA(t *testing.T) (crypto.PrivateKey, *x509.Certificate) {
78 78
 	if err != nil {
79 79
 		t.Fatalf("Unexpected error: %#v", err)
80 80
 	}
81
-	caTemplate, err := newSigningCertificateTemplate(pkix.Name{CommonName: "CA"})
82
-	if err != nil {
83
-		t.Fatalf("Unexpected error: %#v", err)
84
-	}
81
+	caTemplate := newSigningCertificateTemplate(pkix.Name{CommonName: "CA"}, certificateLifetime, time.Now)
85 82
 	caCrt, err := signCertificate(caTemplate, caPublicKey, caTemplate, caPrivateKey)
86 83
 	if err != nil {
87 84
 		t.Fatalf("Unexpected error: %#v", err)
... ...
@@ -94,10 +94,7 @@ func buildIntermediate(t *testing.T, signingKey crypto.PrivateKey, signingCrt *x
94 94
 	if err != nil {
95 95
 		t.Fatalf("Unexpected error: %#v", err)
96 96
 	}
97
-	intermediateTemplate, err := newSigningCertificateTemplate(pkix.Name{CommonName: "Intermediate"})
98
-	if err != nil {
99
-		t.Fatalf("Unexpected error: %#v", err)
100
-	}
97
+	intermediateTemplate := newSigningCertificateTemplate(pkix.Name{CommonName: "Intermediate"}, certificateLifetime, time.Now)
101 98
 	intermediateCrt, err := signCertificate(intermediateTemplate, intermediatePublicKey, signingCrt, signingKey)
102 99
 	if err != nil {
103 100
 		t.Fatalf("Unexpected error: %#v", err)
... ...
@@ -113,10 +110,8 @@ func buildServer(t *testing.T, signingKey crypto.PrivateKey, signingCrt *x509.Ce
113 113
 	if err != nil {
114 114
 		t.Fatalf("Unexpected error: %#v", err)
115 115
 	}
116
-	serverTemplate, err := newServerCertificateTemplate(pkix.Name{CommonName: "Server"}, []string{"127.0.0.1", "localhost", "www.example.com"})
117
-	if err != nil {
118
-		t.Fatalf("Unexpected error: %#v", err)
119
-	}
116
+	hosts := []string{"127.0.0.1", "localhost", "www.example.com"}
117
+	serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: "Server"}, hosts, certificateLifetime, time.Now)
120 118
 	serverCrt, err := signCertificate(serverTemplate, serverPublicKey, signingCrt, signingKey)
121 119
 	if err != nil {
122 120
 		t.Fatalf("Unexpected error: %#v", err)
... ...
@@ -132,10 +127,7 @@ func buildClient(t *testing.T, signingKey crypto.PrivateKey, signingCrt *x509.Ce
132 132
 	if err != nil {
133 133
 		t.Fatalf("Unexpected error: %#v", err)
134 134
 	}
135
-	clientTemplate, err := newClientCertificateTemplate(pkix.Name{CommonName: "Client"})
136
-	if err != nil {
137
-		t.Fatalf("Unexpected error: %#v", err)
138
-	}
135
+	clientTemplate := newClientCertificateTemplate(pkix.Name{CommonName: "Client"}, certificateLifetime, time.Now)
139 136
 	clientCrt, err := signCertificate(clientTemplate, clientPublicKey, signingCrt, signingKey)
140 137
 	if err != nil {
141 138
 		t.Fatalf("Unexpected error: %#v", err)
... ...
@@ -167,11 +159,118 @@ func TestRandomSerialGenerator(t *testing.T) {
167 167
 	generator := &RandomSerialGenerator{}
168 168
 
169 169
 	hostnames := []string{"foo", "bar"}
170
-	template, err := newServerCertificateTemplate(pkix.Name{CommonName: hostnames[0]}, hostnames)
171
-	if err != nil {
172
-		t.Fatalf("unexpected error: %v", err)
173
-	}
170
+	template := newServerCertificateTemplate(pkix.Name{CommonName: hostnames[0]}, hostnames, certificateLifetime, time.Now)
174 171
 	if _, err := generator.Next(template); err != nil {
175 172
 		t.Fatalf("unexpected error: %v", err)
176 173
 	}
177 174
 }
175
+
176
+func TestValidityPeriodOfClientCertificate(t *testing.T) {
177
+	currentTime := time.Now()
178
+
179
+	currentFakeTime := func() time.Time {
180
+		return currentTime
181
+	}
182
+
183
+	tests := []struct {
184
+		passedExpireDays int
185
+		realExpireDays   int
186
+	}{
187
+		{
188
+			passedExpireDays: 100,
189
+			realExpireDays:   100,
190
+		},
191
+		{
192
+			passedExpireDays: 0,
193
+			realExpireDays:   DefaultCertificateLifetimeInDays,
194
+		},
195
+		{
196
+			passedExpireDays: -1,
197
+			realExpireDays:   DefaultCertificateLifetimeInDays,
198
+		},
199
+	}
200
+
201
+	for _, test := range tests {
202
+		cert := newClientCertificateTemplate(pkix.Name{CommonName: "client"}, test.passedExpireDays, currentFakeTime)
203
+		expirationDate := cert.NotAfter
204
+		expectedExpirationDate := currentTime.Add(time.Duration(test.realExpireDays) * 24 * time.Hour)
205
+		if expectedExpirationDate != expirationDate {
206
+			t.Errorf("expected that client certificate will expire at %v but found %v", expectedExpirationDate, expirationDate)
207
+		}
208
+	}
209
+}
210
+
211
+func TestValidityPeriodOfServerCertificate(t *testing.T) {
212
+	currentTime := time.Now()
213
+
214
+	currentFakeTime := func() time.Time {
215
+		return currentTime
216
+	}
217
+
218
+	tests := []struct {
219
+		passedExpireDays int
220
+		realExpireDays   int
221
+	}{
222
+		{
223
+			passedExpireDays: 100,
224
+			realExpireDays:   100,
225
+		},
226
+		{
227
+			passedExpireDays: 0,
228
+			realExpireDays:   DefaultCertificateLifetimeInDays,
229
+		},
230
+		{
231
+			passedExpireDays: -1,
232
+			realExpireDays:   DefaultCertificateLifetimeInDays,
233
+		},
234
+	}
235
+
236
+	for _, test := range tests {
237
+		cert := newServerCertificateTemplate(
238
+			pkix.Name{CommonName: "server"},
239
+			[]string{"www.example.com"},
240
+			test.passedExpireDays,
241
+			currentFakeTime,
242
+		)
243
+		expirationDate := cert.NotAfter
244
+		expectedExpirationDate := currentTime.Add(time.Duration(test.realExpireDays) * 24 * time.Hour)
245
+		if expectedExpirationDate != expirationDate {
246
+			t.Errorf("expected that server certificate will expire at %v but found %v", expectedExpirationDate, expirationDate)
247
+		}
248
+	}
249
+}
250
+
251
+func TestValidityPeriodOfSigningCertificate(t *testing.T) {
252
+	currentTime := time.Now()
253
+
254
+	currentFakeTime := func() time.Time {
255
+		return currentTime
256
+	}
257
+
258
+	tests := []struct {
259
+		passedExpireDays int
260
+		realExpireDays   int
261
+	}{
262
+		{
263
+			passedExpireDays: 100,
264
+			realExpireDays:   100,
265
+		},
266
+		{
267
+			passedExpireDays: 0,
268
+			realExpireDays:   DefaultCACertificateLifetimeInDays,
269
+		},
270
+		{
271
+			passedExpireDays: -1,
272
+			realExpireDays:   DefaultCACertificateLifetimeInDays,
273
+		},
274
+	}
275
+
276
+	for _, test := range tests {
277
+		cert := newSigningCertificateTemplate(pkix.Name{CommonName: "CA"}, test.passedExpireDays, currentFakeTime)
278
+		expirationDate := cert.NotAfter
279
+		expectedExpirationDate := currentTime.Add(time.Duration(test.realExpireDays) * 24 * time.Hour)
280
+		if expectedExpirationDate != expirationDate {
281
+			t.Errorf("expected that CA certificate will expire at %v but found %v", expectedExpirationDate, expirationDate)
282
+		}
283
+	}
284
+}
... ...
@@ -23,6 +23,7 @@ import (
23 23
 
24 24
 	"github.com/openshift/origin/pkg/cmd/server/admin"
25 25
 	configapi "github.com/openshift/origin/pkg/cmd/server/api"
26
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
26 27
 	"github.com/openshift/origin/pkg/cmd/server/start/kubernetes"
27 28
 	"github.com/openshift/origin/pkg/cmd/templates"
28 29
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
... ...
@@ -33,6 +34,8 @@ type AllInOneOptions struct {
33 33
 
34 34
 	NodeArgs *NodeArgs
35 35
 
36
+	ExpireDays         int
37
+	SignerExpireDays   int
36 38
 	ConfigDir          util.StringFlag
37 39
 	NodeConfigFile     string
38 40
 	PrintIP            bool
... ...
@@ -63,7 +66,14 @@ var allInOneLong = templates.LongDesc(`
63 63
 
64 64
 // NewCommandStartAllInOne provides a CLI handler for 'start' command
65 65
 func NewCommandStartAllInOne(basename string, out, errout io.Writer) (*cobra.Command, *AllInOneOptions) {
66
-	options := &AllInOneOptions{Output: out, MasterOptions: &MasterOptions{Output: out}}
66
+	options := &AllInOneOptions{
67
+		MasterOptions: &MasterOptions{
68
+			Output: out,
69
+		},
70
+		ExpireDays:       crypto.DefaultCertificateLifetimeInDays,
71
+		SignerExpireDays: crypto.DefaultCACertificateLifetimeInDays,
72
+		Output:           out,
73
+	}
67 74
 	options.MasterOptions.DefaultsFromName(basename)
68 75
 
69 76
 	cmds := &cobra.Command{
... ...
@@ -100,6 +110,8 @@ func NewCommandStartAllInOne(basename string, out, errout io.Writer) (*cobra.Com
100 100
 	flags.BoolVar(&options.MasterOptions.CreateCertificates, "create-certs", true, "Indicates whether missing certs should be created.")
101 101
 	flags.BoolVar(&options.PrintIP, "print-ip", false, "Print the IP that would be used if no master IP is specified and exit.")
102 102
 	flags.StringVar(&options.ServiceNetworkCIDR, "portal-net", NewDefaultNetworkArgs().ServiceNetworkCIDR, "The CIDR string representing the network that portal/service IPs will be assigned from. This must not overlap with any IP ranges assigned to nodes for pods.")
103
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
104
+	flags.IntVar(&options.SignerExpireDays, "signer-expire-days", options.SignerExpireDays, "Validity of the CA certificate in days (defaults to 5 years). WARNING: extending this above default value is highly discouraged.")
103 105
 
104 106
 	masterArgs, nodeArgs, listenArg, imageFormatArgs, _ := GetAllInOneArgs()
105 107
 	options.MasterOptions.MasterArgs, options.NodeArgs = masterArgs, nodeArgs
... ...
@@ -194,6 +206,13 @@ func (o AllInOneOptions) Validate(args []string) error {
194 194
 		return errors.New("all-in-one cannot start with a remote Kubernetes server, start the master instead")
195 195
 	}
196 196
 
197
+	if o.ExpireDays < 0 {
198
+		return errors.New("expire-days must be valid number of days")
199
+	}
200
+	if o.SignerExpireDays < 0 {
201
+		return errors.New("signer-expire-days must be valid number of days")
202
+	}
203
+
197 204
 	return nil
198 205
 }
199 206
 
... ...
@@ -268,11 +287,18 @@ func (o AllInOneOptions) StartAllInOne() error {
268 268
 		return nil
269 269
 	}
270 270
 	masterOptions := *o.MasterOptions
271
+	masterOptions.ExpireDays = o.ExpireDays
272
+	masterOptions.SignerExpireDays = o.SignerExpireDays
271 273
 	if err := masterOptions.RunMaster(); err != nil {
272 274
 		return err
273 275
 	}
274 276
 
275
-	nodeOptions := NodeOptions{o.NodeArgs, o.NodeConfigFile, o.MasterOptions.Output}
277
+	nodeOptions := NodeOptions{
278
+		NodeArgs:   o.NodeArgs,
279
+		ExpireDays: o.ExpireDays,
280
+		ConfigFile: o.NodeConfigFile,
281
+		Output:     o.MasterOptions.Output,
282
+	}
276 283
 	if err := nodeOptions.RunNode(); err != nil {
277 284
 		return err
278 285
 	}
... ...
@@ -33,6 +33,7 @@ import (
33 33
 	configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
34 34
 	"github.com/openshift/origin/pkg/cmd/server/api/validation"
35 35
 	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
36
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
36 37
 	"github.com/openshift/origin/pkg/cmd/server/etcd"
37 38
 	"github.com/openshift/origin/pkg/cmd/server/etcd/etcdserver"
38 39
 	"github.com/openshift/origin/pkg/cmd/server/kubernetes"
... ...
@@ -49,6 +50,8 @@ type MasterOptions struct {
49 49
 	MasterArgs *MasterArgs
50 50
 
51 51
 	CreateCertificates bool
52
+	ExpireDays         int
53
+	SignerExpireDays   int
52 54
 	ConfigFile         string
53 55
 	Output             io.Writer
54 56
 	DisabledFeatures   []string
... ...
@@ -81,7 +84,11 @@ var masterLong = templates.LongDesc(`
81 81
 
82 82
 // NewCommandStartMaster provides a CLI handler for 'start master' command
83 83
 func NewCommandStartMaster(basename string, out, errout io.Writer) (*cobra.Command, *MasterOptions) {
84
-	options := &MasterOptions{Output: out}
84
+	options := &MasterOptions{
85
+		ExpireDays:       crypto.DefaultCertificateLifetimeInDays,
86
+		SignerExpireDays: crypto.DefaultCACertificateLifetimeInDays,
87
+		Output:           out,
88
+	}
85 89
 	options.DefaultsFromName(basename)
86 90
 
87 91
 	cmd := &cobra.Command{
... ...
@@ -127,6 +134,8 @@ func NewCommandStartMaster(basename string, out, errout io.Writer) (*cobra.Comma
127 127
 	flags.Var(options.MasterArgs.ConfigDir, "write-config", "Directory to write an initial config into.  After writing, exit without starting the server.")
128 128
 	flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.")
129 129
 	flags.BoolVar(&options.CreateCertificates, "create-certs", true, "Indicates whether missing certs should be created")
130
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
131
+	flags.IntVar(&options.SignerExpireDays, "signer-expire-days", options.SignerExpireDays, "Validity of the CA certificate in days (defaults to 5 years). WARNING: extending this above default value is highly discouraged.")
130 132
 
131 133
 	BindMasterArgs(options.MasterArgs, flags, "")
132 134
 	BindListenArg(options.MasterArgs.ListenArg, flags, "")
... ...
@@ -168,6 +177,13 @@ func (o MasterOptions) Validate(args []string) error {
168 168
 
169 169
 	}
170 170
 
171
+	if o.ExpireDays < 0 {
172
+		return errors.New("expire-days must be valid number of days")
173
+	}
174
+	if o.SignerExpireDays < 0 {
175
+		return errors.New("signer-expire-days must be valid number of days")
176
+	}
177
+
171 178
 	return nil
172 179
 }
173 180
 
... ...
@@ -320,6 +336,8 @@ func (o MasterOptions) CreateCerts() error {
320 320
 	mintAllCertsOptions := admin.CreateMasterCertsOptions{
321 321
 		CertDir:            o.MasterArgs.ConfigDir.Value(),
322 322
 		SignerName:         signerName,
323
+		ExpireDays:         o.ExpireDays,
324
+		SignerExpireDays:   o.SignerExpireDays,
323 325
 		Hostnames:          hostnames.List(),
324 326
 		APIServerURL:       masterAddr.String(),
325 327
 		APIServerCAFiles:   o.MasterArgs.APIServerCAFiles,
... ...
@@ -19,6 +19,7 @@ import (
19 19
 	configapi "github.com/openshift/origin/pkg/cmd/server/api"
20 20
 	configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
21 21
 	"github.com/openshift/origin/pkg/cmd/server/api/validation"
22
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
22 23
 	"github.com/openshift/origin/pkg/cmd/templates"
23 24
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
24 25
 	"github.com/openshift/origin/pkg/cmd/util/docker"
... ...
@@ -28,7 +29,8 @@ import (
28 28
 )
29 29
 
30 30
 type NodeOptions struct {
31
-	NodeArgs *NodeArgs
31
+	NodeArgs   *NodeArgs
32
+	ExpireDays int
32 33
 
33 34
 	ConfigFile string
34 35
 	Output     io.Writer
... ...
@@ -46,7 +48,10 @@ var nodeLong = templates.LongDesc(`
46 46
 
47 47
 // NewCommandStartNode provides a CLI handler for 'start node' command
48 48
 func NewCommandStartNode(basename string, out, errout io.Writer) (*cobra.Command, *NodeOptions) {
49
-	options := &NodeOptions{Output: out}
49
+	options := &NodeOptions{
50
+		ExpireDays: crypto.DefaultCertificateLifetimeInDays,
51
+		Output:     out,
52
+	}
50 53
 
51 54
 	cmd := &cobra.Command{
52 55
 		Use:   "node",
... ...
@@ -60,6 +65,7 @@ func NewCommandStartNode(basename string, out, errout io.Writer) (*cobra.Command
60 60
 	flags := cmd.Flags()
61 61
 
62 62
 	flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.")
63
+	flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.")
63 64
 
64 65
 	options.NodeArgs = NewDefaultNodeArgs()
65 66
 
... ...
@@ -137,6 +143,10 @@ func (o NodeOptions) Validate(args []string) error {
137 137
 		return errors.New("no arguments are supported for start node")
138 138
 	}
139 139
 
140
+	if o.ExpireDays < 0 {
141
+		return errors.New("expire-days must be valid number of days")
142
+	}
143
+
140 144
 	if o.IsWriteConfigOnly() {
141 145
 		if o.IsRunFromConfig() {
142 146
 			return errors.New("--config may not be set if you're only writing the config")
... ...
@@ -264,6 +274,7 @@ func (o NodeOptions) CreateNodeConfig() error {
264 264
 		APIServerCAFiles: []string{admin.DefaultCABundleFile(o.NodeArgs.MasterCertDir)},
265 265
 
266 266
 		NodeClientCAFile: getSignerOptions.CertFile,
267
+		ExpireDays:       o.ExpireDays,
267 268
 		Output:           cmdutil.NewGLogWriterV(3),
268 269
 	}
269 270
 
... ...
@@ -196,7 +196,8 @@ func (sc *ServiceServingCertController) syncService(key string) error {
196 196
 
197 197
 	dnsName := service.Name + "." + service.Namespace + ".svc"
198 198
 	fqDNSName := dnsName + "." + sc.dnsSuffix
199
-	servingCert, err := sc.ca.MakeServerCert(sets.NewString(dnsName, fqDNSName))
199
+	certificateLifetime := 365 * 2 // 2 years
200
+	servingCert, err := sc.ca.MakeServerCert(sets.NewString(dnsName, fqDNSName), certificateLifetime)
200 201
 	if err != nil {
201 202
 		return err
202 203
 	}
... ...
@@ -233,7 +233,8 @@ func (sc *ServiceServingCertUpdateController) syncSecret(key string) error {
233 233
 
234 234
 	dnsName := secret.Annotations[ServiceNameAnnotation] + "." + secret.Namespace + ".svc"
235 235
 	fqDNSName := dnsName + "." + sc.dnsSuffix
236
-	servingCert, err := sc.ca.MakeServerCert(sets.NewString(dnsName, fqDNSName))
236
+	certificateLifetime := 365 * 2 // 2 years
237
+	servingCert, err := sc.ca.MakeServerCert(sets.NewString(dnsName, fqDNSName), certificateLifetime)
237 238
 	if err != nil {
238 239
 		return err
239 240
 	}
240 241
new file mode 100755
... ...
@@ -0,0 +1,405 @@
0
+#!/bin/bash
1
+
2
+source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh"
3
+trap os::test::junit::reconcile_output EXIT
4
+
5
+os::test::junit::declare_suite_start "cmd/admin/certs-validation"
6
+
7
+CERT_DIR="${BASETMPDIR}/certs"
8
+mkdir -p -- "${CERT_DIR}"
9
+
10
+pushd "${CERT_DIR}" >/dev/null
11
+
12
+# oadm ca create-signer-cert should generate certificate for 5 years by default
13
+os::cmd::expect_success_and_not_text \
14
+    "oadm ca create-signer-cert --cert='${CERT_DIR}/ca.crt' \
15
+                                --key='${CERT_DIR}/ca.key' \
16
+                                --serial='${CERT_DIR}/ca.serial.txt' \
17
+                                --overwrite=true" \
18
+    'WARNING: .* is greater than 5 years'
19
+
20
+expected_year="$(TZ=GMT date -d "+$((365*5)) days" +'%Y')"
21
+
22
+os::cmd::expect_success_and_text \
23
+    "openssl x509 -in '${CERT_DIR}/ca.crt' -enddate -noout | awk '{print \$4}'" \
24
+    "${expected_year}"
25
+
26
+# oadm ca create-signer-cert should generate certificate with specified number of days and show warning
27
+os::cmd::expect_success_and_text \
28
+    "oadm ca create-signer-cert --cert='${CERT_DIR}/ca.crt' \
29
+                                --key='${CERT_DIR}/ca.key' \
30
+                                --serial='${CERT_DIR}/ca.serial.txt' \
31
+                                --overwrite=true \
32
+                                --expire-days=$((365*6))" \
33
+    'WARNING: .* is greater than 5 years'
34
+
35
+expected_year="$(TZ=GMT date -d "+$((365*6)) days" +'%Y')"
36
+
37
+os::cmd::expect_success_and_text \
38
+    "openssl x509 -in '${CERT_DIR}/ca.crt' -enddate -noout | awk '{print \$4}'" \
39
+    "${expected_year}"
40
+
41
+
42
+# oadm create-node-config should generate certificates for 2 years by default
43
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
44
+
45
+# we have to remove these files otherwise oadm create-node-config won't generate new ones
46
+rm -f -- ${CERT_DIR}/master-client.crt ${CERT_DIR}/server.crt
47
+
48
+os::cmd::expect_success_and_not_text \
49
+    "oadm create-node-config \
50
+            --node-dir='${CERT_DIR}' \
51
+            --node=example \
52
+            --hostnames=example.org \
53
+            --certificate-authority='${CERT_DIR}/ca.crt' \
54
+            --node-client-certificate-authority='${CERT_DIR}/ca.crt' \
55
+            --signer-cert='${CERT_DIR}/ca.crt' \
56
+            --signer-key='${CERT_DIR}/ca.key' \
57
+            --signer-serial='${CERT_DIR}/ca.serial.txt'" \
58
+    'WARNING: .* is greater than 2 years'
59
+
60
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
61
+for CERT_FILE in master-client.crt server.crt; do
62
+    os::cmd::expect_success_and_text \
63
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
64
+        "${expected_year}"
65
+done
66
+
67
+# oadm create-node-config should generate certificates with specified number of days and show warning
68
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
69
+
70
+# we have to remove these files otherwise oadm create-node-config won't generate new ones
71
+rm -f -- ${CERT_DIR}/master-client.crt ${CERT_DIR}/server.crt
72
+
73
+os::cmd::expect_success_and_text \
74
+    "oadm create-node-config \
75
+            --node-dir='${CERT_DIR}' \
76
+            --node=example \
77
+            --hostnames=example.org \
78
+            --certificate-authority='${CERT_DIR}/ca.crt' \
79
+            --node-client-certificate-authority='${CERT_DIR}/ca.crt' \
80
+            --signer-cert='${CERT_DIR}/ca.crt' \
81
+            --signer-key='${CERT_DIR}/ca.key' \
82
+            --signer-serial='${CERT_DIR}/ca.serial.txt' \
83
+            --expire-days=$((365*3))" \
84
+    'WARNING: .* is greater than 2 years'
85
+
86
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
87
+
88
+for CERT_FILE in master-client.crt server.crt; do
89
+    os::cmd::expect_success_and_text \
90
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
91
+        "${expected_year}"
92
+done
93
+
94
+
95
+# oadm create-api-client-config should generate certificates for 2 years by default
96
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
97
+
98
+os::cmd::expect_success_and_not_text \
99
+    "oadm create-api-client-config \
100
+            --client-dir='${CERT_DIR}' \
101
+            --user=test-user \
102
+            --certificate-authority='${CERT_DIR}/ca.crt' \
103
+            --signer-cert='${CERT_DIR}/ca.crt' \
104
+            --signer-key='${CERT_DIR}/ca.key' \
105
+            --signer-serial='${CERT_DIR}/ca.serial.txt'" \
106
+    'WARNING: .* is greater than 2 years'
107
+
108
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
109
+os::cmd::expect_success_and_text \
110
+    "openssl x509 -in '${CERT_DIR}/test-user.crt' -enddate -noout | awk '{print \$4}'" \
111
+    "${expected_year}"
112
+
113
+# oadm create-api-client-config should generate certificates with specified number of days and show warning
114
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
115
+
116
+os::cmd::expect_success_and_text \
117
+    "oadm create-api-client-config \
118
+            --client-dir='${CERT_DIR}' \
119
+            --user=test-user \
120
+            --certificate-authority='${CERT_DIR}/ca.crt' \
121
+            --signer-cert='${CERT_DIR}/ca.crt' \
122
+            --signer-key='${CERT_DIR}/ca.key' \
123
+            --signer-serial='${CERT_DIR}/ca.serial.txt' \
124
+            --expire-days=$((365*3))" \
125
+    'WARNING: .* is greater than 2 years'
126
+
127
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
128
+os::cmd::expect_success_and_text \
129
+    "openssl x509 -in '${CERT_DIR}/test-user.crt' -enddate -noout | awk '{print \$4}'" \
130
+    "${expected_year}"
131
+
132
+
133
+# oadm ca create-server-cert should generate certificate for 2 years by default
134
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
135
+os::cmd::expect_success_and_not_text \
136
+    "oadm ca create-server-cert --signer-cert='${CERT_DIR}/ca.crt' \
137
+                                --signer-key='${CERT_DIR}/ca.key' \
138
+                                --signer-serial='${CERT_DIR}/ca.serial.txt' \
139
+                                --overwrite=true \
140
+                                --hostnames=example.org \
141
+                                --cert='${CERT_DIR}/example.org.crt' \
142
+                                --key='${CERT_DIR}/example.org.key'" \
143
+    'WARNING: .* is greater than 2 years'
144
+
145
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
146
+
147
+os::cmd::expect_success_and_text \
148
+    "openssl x509 -in '${CERT_DIR}/example.org.crt' -enddate -noout | awk '{print \$4}'" \
149
+    "${expected_year}"
150
+
151
+# oadm ca create-server-cert should generate certificate with specified number of days and show warning
152
+# NOTE: tests order is important here because this test uses CA certificate that was generated before
153
+os::cmd::expect_success_and_text \
154
+    "oadm ca create-server-cert --signer-cert='${CERT_DIR}/ca.crt' \
155
+                                --signer-key='${CERT_DIR}/ca.key' \
156
+                                --signer-serial='${CERT_DIR}/ca.serial.txt' \
157
+                                --overwrite=true --hostnames=example.org \
158
+                                --cert='${CERT_DIR}/example.org.crt' \
159
+                                --key='${CERT_DIR}/example.org.key' \
160
+                                --expire-days=$((365*3))" \
161
+    'WARNING: .* is greater than 2 years'
162
+
163
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
164
+
165
+os::cmd::expect_success_and_text \
166
+    "openssl x509 -in '${CERT_DIR}/example.org.crt' -enddate -noout | awk '{print \$4}'" \
167
+    "${expected_year}"
168
+
169
+# oadm ca create-master-certs should generate certificates for 2 years and CA for 5 years by default
170
+os::cmd::expect_success_and_not_text \
171
+    "oadm ca create-master-certs --cert-dir='${CERT_DIR}' \
172
+                                 --hostnames=example.org \
173
+                                 --overwrite=true" \
174
+    'WARNING: .* is greater than'
175
+
176
+expected_ca_year="$(TZ=GMT date -d "+$((365*5)) days" +'%Y')"
177
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
178
+    os::cmd::expect_success_and_text \
179
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
180
+        "${expected_ca_year}"
181
+done
182
+
183
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
184
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
185
+    os::cmd::expect_success_and_text \
186
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
187
+        "${expected_year}"
188
+done
189
+
190
+# oadm ca create-master-certs should generate certificates with specified number of days and show warnings
191
+os::cmd::expect_success_and_text \
192
+    "oadm ca create-master-certs --cert-dir='${CERT_DIR}' \
193
+                                 --hostnames=example.org \
194
+                                 --overwrite=true \
195
+                                 --expire-days=$((365*3)) \
196
+                                 --signer-expire-days=$((365*6))" \
197
+    'WARNING: .* is greater than'
198
+
199
+expected_ca_year="$(TZ=GMT date -d "+$((365*6)) days" +'%Y')"
200
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
201
+    os::cmd::expect_success_and_text \
202
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
203
+        "${expected_ca_year}"
204
+done
205
+
206
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
207
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
208
+    os::cmd::expect_success_and_text \
209
+        "openssl x509 -in '${CERT_DIR}/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
210
+        "${expected_year}"
211
+done
212
+
213
+# Preparation for "openshift start node" tests
214
+# NOTE: tests order is important here because this test uses client and CA certificates that were generated before
215
+
216
+# Pre-create directory with certificates because "openshift start node" doesn't have options to specify
217
+# alternative path to the certificates
218
+mkdir -p -- "${CERT_DIR}/start-node/openshift.local.config/master"
219
+cp "${CERT_DIR}/ca-bundle.crt" \
220
+    "${CERT_DIR}/ca.crt" \
221
+    "${CERT_DIR}/ca.key" \
222
+    "${CERT_DIR}/ca.serial.txt" \
223
+    "${CERT_DIR}/start-node/openshift.local.config/master"
224
+
225
+# Pre-create kubeconfig that is required by "openshift start node"
226
+oadm create-kubeconfig \
227
+    --client-certificate="${CERT_DIR}/master-client.crt" \
228
+    --client-key="${CERT_DIR}/master-client.key" \
229
+    --certificate-authority="${CERT_DIR}/ca.crt" \
230
+    --kubeconfig="${CERT_DIR}/start-node/cert-test.kubeconfig"
231
+
232
+# openshift start node should generate certificates for 2 years by default
233
+pushd start-node >/dev/null
234
+
235
+# we have to remove these files otherwise openshift start node won't generate new ones
236
+rm -rf openshift.local.config/node/
237
+
238
+os::cmd::expect_failure_and_not_text \
239
+    "timeout 30 openshift start node \
240
+        --kubeconfig='${CERT_DIR}/start-node/cert-test.kubeconfig' \
241
+        --volume-dir='${CERT_DIR}/volumes'" \
242
+    'WARNING: .* is greater than'
243
+
244
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
245
+for CERT_FILE in master-client.crt server.crt; do
246
+    os::cmd::expect_success_and_text \
247
+        "openssl x509 -in '${CERT_DIR}/start-node/openshift.local.config/node/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
248
+        "${expected_year}"
249
+done
250
+
251
+popd >/dev/null
252
+
253
+
254
+# openshift start node should generate certificates with specified number of days and show warning
255
+# NOTE: tests order is important here because this test uses client and CA certificates that were generated before
256
+pushd start-node >/dev/null
257
+
258
+# we have to remove these files otherwise openshift start node won't generate new ones
259
+rm -rf openshift.local.config/node/
260
+
261
+os::cmd::expect_failure_and_text \
262
+    "timeout 30 openshift start node \
263
+        --kubeconfig='${CERT_DIR}/start-node/cert-test.kubeconfig' \
264
+        --volume-dir='${CERT_DIR}/volumes' \
265
+        --expire-days=$((365*3))" \
266
+    'WARNING: .* is greater than'
267
+
268
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
269
+for CERT_FILE in master-client.crt server.crt; do
270
+    os::cmd::expect_success_and_text \
271
+        "openssl x509 -in '${CERT_DIR}/start-node/openshift.local.config/node/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
272
+        "${expected_year}"
273
+done
274
+
275
+popd >/dev/null
276
+
277
+
278
+# openshift start master should generate certificates for 2 years and CA for 5 years by default
279
+
280
+# we have to remove these files otherwise openshift start master won't generate new ones
281
+rm -rf start-master
282
+mkdir -p start-master
283
+
284
+os::cmd::expect_success_and_not_text \
285
+    "timeout 30 openshift start master --write-config='${CERT_DIR}/start-master'" \
286
+    'WARNING: .* is greater than'
287
+
288
+expected_ca_year="$(TZ=GMT date -d "+$((365*5)) days" +'%Y')"
289
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
290
+    os::cmd::expect_success_and_text \
291
+        "openssl x509 -in '${CERT_DIR}/start-master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
292
+        "${expected_ca_year}"
293
+done
294
+
295
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
296
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
297
+    os::cmd::expect_success_and_text \
298
+        "openssl x509 -in '${CERT_DIR}/start-master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
299
+        "${expected_year}"
300
+done
301
+
302
+# openshift start master should generate certificates with specified number of days and show warnings
303
+
304
+# we have to remove these files otherwise openshift start master won't generate new ones
305
+rm -rf start-master
306
+mkdir -p start-master
307
+
308
+os::cmd::expect_success_and_text \
309
+    "timeout 30 openshift start master --write-config='${CERT_DIR}/start-master' \
310
+                            --expire-days=$((365*3)) \
311
+                            --signer-expire-days=$((365*6))" \
312
+    'WARNING: .* is greater than'
313
+
314
+expected_ca_year="$(TZ=GMT date -d "+$((365*6)) days" +'%Y')"
315
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
316
+    os::cmd::expect_success_and_text \
317
+        "openssl x509 -in '${CERT_DIR}/start-master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
318
+        "${expected_ca_year}"
319
+done
320
+
321
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
322
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
323
+    os::cmd::expect_success_and_text \
324
+        "openssl x509 -in '${CERT_DIR}/start-master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
325
+        "${expected_year}"
326
+done
327
+
328
+
329
+# openshift start should generate certificates for 2 years and CA for 5 years by default
330
+
331
+# we have to remove these files otherwise openshift start won't generate new ones
332
+rm -rf start-all
333
+mkdir -p start-all
334
+
335
+pushd start-all >/dev/null
336
+os::cmd::expect_success_and_not_text \
337
+    "timeout 30 openshift start --write-config='${CERT_DIR}/start-all' \
338
+                     --hostname=example.org" \
339
+    'WARNING: .* is greater than'
340
+
341
+expected_ca_year="$(TZ=GMT date -d "+$((365*5)) days" +'%Y')"
342
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
343
+    os::cmd::expect_success_and_text \
344
+        "openssl x509 -in '${CERT_DIR}/start-all/master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
345
+        "${expected_ca_year}"
346
+done
347
+
348
+expected_year="$(TZ=GMT date -d "+$((365*2)) days" +'%Y')"
349
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
350
+    os::cmd::expect_success_and_text \
351
+        "openssl x509 -in '${CERT_DIR}/start-all/master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
352
+        "${expected_year}"
353
+done
354
+
355
+for CERT_FILE in master-client.crt server.crt; do
356
+    os::cmd::expect_success_and_text \
357
+        "openssl x509 -in '${CERT_DIR}/start-all/node-example.org/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
358
+        "${expected_year}"
359
+done
360
+
361
+popd >/dev/null
362
+
363
+# openshift start should generate certificates with specified number of days and show warnings
364
+
365
+# we have to remove these files otherwise openshift start won't generate new ones
366
+rm -rf start-all
367
+mkdir -p start-all
368
+
369
+pushd start-all >/dev/null
370
+os::cmd::expect_success_and_text \
371
+    "timeout 30 openshift start --write-config='${CERT_DIR}/start-all' \
372
+                     --hostname=example.org \
373
+                     --expire-days=$((365*3)) \
374
+                     --signer-expire-days=$((365*6))" \
375
+    'WARNING: .* is greater than'
376
+
377
+expected_ca_year="$(TZ=GMT date -d "+$((365*6)) days" +'%Y')"
378
+for CERT_FILE in ca.crt ca-bundle.crt service-signer.crt; do
379
+    os::cmd::expect_success_and_text \
380
+        "openssl x509 -in '${CERT_DIR}/start-all/master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
381
+        "${expected_ca_year}"
382
+done
383
+
384
+expected_year="$(TZ=GMT date -d "+$((365*3)) days" +'%Y')"
385
+for CERT_FILE in admin.crt {master,etcd}.server.crt master.{etcd,kubelet,proxy}-client.crt openshift-{master,registry,router}.crt; do
386
+    os::cmd::expect_success_and_text \
387
+        "openssl x509 -in '${CERT_DIR}/start-all/master/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
388
+        "${expected_year}"
389
+done
390
+
391
+for CERT_FILE in master-client.crt server.crt; do
392
+    os::cmd::expect_success_and_text \
393
+        "openssl x509 -in '${CERT_DIR}/start-all/node-example.org/${CERT_FILE}' -enddate -noout | awk '{print \$4}'" \
394
+        "${expected_year}"
395
+done
396
+
397
+popd >/dev/null
398
+
399
+os::test::junit::declare_suite_end
400
+
401
+popd >/dev/null
402
+
403
+# remove generated files only if tests passed
404
+rm -rf -- "${CERT_DIR}"
... ...
@@ -92,6 +92,7 @@ func TestOAuthCertFallback(t *testing.T) {
92 92
 		path.Join(fakecadir, "fakeclient.crt"),
93 93
 		path.Join(fakecadir, "fakeclient.key"),
94 94
 		&user.DefaultInfo{Name: "fakeuser"},
95
+		365*2, /* 2 years */
95 96
 	)
96 97
 	if err != nil {
97 98
 		t.Fatalf("Unexpected error: %v", err)
... ...
@@ -28,6 +28,7 @@ import (
28 28
 
29 29
 	// install all APIs
30 30
 	_ "github.com/openshift/origin/pkg/api/install"
31
+	"github.com/openshift/origin/pkg/cmd/server/crypto"
31 32
 	_ "k8s.io/kubernetes/pkg/api/install"
32 33
 	_ "k8s.io/kubernetes/pkg/apis/extensions/install"
33 34
 )
... ...
@@ -177,6 +178,9 @@ func CreateMasterCerts(masterArgs *start.MasterArgs) error {
177 177
 		SignerName: admin.DefaultSignerName(),
178 178
 		Hostnames:  hostnames.List(),
179 179
 
180
+		ExpireDays:       crypto.DefaultCertificateLifetimeInDays,
181
+		SignerExpireDays: crypto.DefaultCACertificateLifetimeInDays,
182
+
180 183
 		APIServerURL:       masterURL.String(),
181 184
 		PublicAPIServerURL: publicMasterURL.String(),
182 185
 
... ...
@@ -227,7 +231,9 @@ func DefaultAllInOneOptions() (*configapi.MasterConfig, *configapi.NodeConfig, *
227 227
 	startOptions.NodeArgs.AllowDisabledDocker = true
228 228
 	startOptions.NodeArgs.Components.Disable("plugins", "proxy", "dns")
229 229
 	startOptions.ServiceNetworkCIDR = start.NewDefaultNetworkArgs().ServiceNetworkCIDR
230
-	startOptions.Complete()
230
+	if err := startOptions.Complete(); err != nil {
231
+		return nil, nil, nil, err
232
+	}
231 233
 	startOptions.MasterOptions.MasterArgs.ConfigDir.Default(path.Join(util.GetBaseDir(), "openshift.local.config", "master"))
232 234
 	startOptions.NodeArgs.ConfigDir.Default(path.Join(util.GetBaseDir(), "openshift.local.config", admin.DefaultNodeDir(startOptions.NodeArgs.NodeName)))
233 235
 	startOptions.NodeArgs.MasterCertDir = startOptions.MasterOptions.MasterArgs.ConfigDir.Value()