Skip to content

Commit c28e4ac

Browse files
author
Gabriel Monroy
committed
Merge pull request #2905 from gabrtv/config-logic
Refactor deisctl config logic and add docs on Router SSL
2 parents 00a31ef + 42931ab commit c28e4ac

3 files changed

Lines changed: 131 additions & 21 deletions

File tree

deisctl/config/config.go

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ import (
99
"github.com/deis/deis/deisctl/utils"
1010
)
1111

12+
// fileKeys define config keys to be read from local files
13+
var fileKeys = []string{
14+
"/deis/platform/sshPrivateKey",
15+
"/deis/router/sslCert",
16+
"/deis/router/sslKey"}
17+
18+
// b64Keys define config keys to be base64 encoded before stored
19+
var b64Keys = []string{"/deis/platform/sshPrivateKey"}
20+
1221
// Config runs the config subcommand
1322
func Config(args map[string]interface{}) error {
1423
return doConfig(args)
@@ -62,25 +71,14 @@ func doConfigSet(client *etcdClient, root string, kvs []string) ([]string, error
6271
for _, kv := range kvs {
6372

6473
// split k/v from args
65-
split := strings.Split(kv, "=")
66-
if len(split) != 2 {
67-
return result, fmt.Errorf("invalid argument: %v", kv)
68-
}
74+
split := strings.SplitN(kv, "=", 2)
6975
k, v := split[0], split[1]
7076

7177
// prepare path and value
7278
path := root + k
73-
var val string
74-
75-
// special handling for sshKey
76-
if path == "/deis/platform/sshPrivateKey" {
77-
b64, err := readSSHPrivateKey(utils.ResolvePath(v))
78-
if err != nil {
79-
return result, err
80-
}
81-
val = b64
82-
} else {
83-
val = v
79+
val, err := valueForPath(path, v)
80+
if err != nil {
81+
return result, err
8482
}
8583

8684
// set key/value in etcd
@@ -106,13 +104,31 @@ func doConfigGet(client *etcdClient, root string, keys []string) ([]string, erro
106104
return result, nil
107105
}
108106

109-
// readSSHPrivateKey reads the key file and returns a base64 encoded string
110-
func readSSHPrivateKey(path string) (string, error) {
107+
// valueForPath returns the canonical value for a user-defined path and value
108+
func valueForPath(path string, v string) (string, error) {
111109

112-
bytes, err := ioutil.ReadFile(path)
113-
if err != nil {
114-
return "", err
110+
// check if path is part of fileKeys
111+
for _, p := range fileKeys {
112+
113+
if path == p {
114+
115+
// read value from filesystem
116+
bytes, err := ioutil.ReadFile(utils.ResolvePath(v))
117+
if err != nil {
118+
return "", err
119+
}
120+
121+
// see if we should return base64 encoded value
122+
for _, pp := range b64Keys {
123+
if path == pp {
124+
return base64.StdEncoding.EncodeToString(bytes), nil
125+
}
126+
}
127+
128+
return string(bytes), nil
129+
}
115130
}
116131

117-
return base64.StdEncoding.EncodeToString(bytes), nil
132+
return v, nil
133+
118134
}

deisctl/config/config_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package config
2+
3+
import (
4+
"encoding/base64"
5+
"io/ioutil"
6+
"os"
7+
"testing"
8+
)
9+
10+
// TestConfigSSHPrivateKey ensures private keys are base64 encoded from file path
11+
func TestConfigSSHPrivateKey(t *testing.T) {
12+
13+
f, err := writeTempFile("private-key")
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
18+
val, err := valueForPath("/deis/platform/sshPrivateKey", f.Name())
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
23+
encoded := base64.StdEncoding.EncodeToString([]byte("private-key"))
24+
25+
if val != encoded {
26+
t.Fatalf("expected: %v, got: %v", encoded, val)
27+
}
28+
}
29+
30+
func TestConfigRouterKey(t *testing.T) {
31+
32+
f, err := writeTempFile("router-key")
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
37+
val, err := valueForPath("/deis/router/sslKey", f.Name())
38+
if err != nil {
39+
t.Fatal(err)
40+
}
41+
42+
if val != "router-key" {
43+
t.Fatalf("expected: router-key, got: %v", val)
44+
}
45+
46+
}
47+
48+
func TestConfigRouterCert(t *testing.T) {
49+
50+
f, err := writeTempFile("router-cert")
51+
if err != nil {
52+
t.Fatal(err)
53+
}
54+
55+
val, err := valueForPath("/deis/router/sslCert", f.Name())
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
60+
if val != "router-cert" {
61+
t.Fatalf("expected: router-cert, got: %v", val)
62+
}
63+
64+
}
65+
66+
func writeTempFile(data string) (*os.File, error) {
67+
f, err := ioutil.TempFile("", "deisctl")
68+
if err != nil {
69+
return nil, err
70+
}
71+
72+
f.Write([]byte(data))
73+
defer f.Close()
74+
75+
return f, nil
76+
}

docs/managing_deis/ssl-endpoints.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,23 @@ See your vendor's specific instructions on installing SSL on your load balancer.
6969
documentation on `installing an SSL cert for load balancing`_. For Rackspace, see their
7070
`Product FAQ`_.
7171

72+
Installing SSL on the Deis Routers
73+
----------------------------------
74+
75+
You can also use the Deis routers to terminate SSL connections.
76+
Use ``deisctl`` to install the certificate and private keys:
77+
78+
.. code-block:: console
79+
80+
$ deisctl config router set sslKey=<path-to-key> sslCert=<path-to-cert>
81+
82+
If your certificate has intermediate certs that need to be presented as part of a
83+
certificate chain, append the intermediate certs to the bottom of the sslCert value.
84+
85+
.. note::
86+
87+
To secure all endpoints on the platform domain, you must use a wildcard certificate.
88+
89+
7290
.. _`installing an SSL cert for load balancing`: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/ssl-server-cert.html
7391
.. _`Product FAQ`: http://www.rackspace.com/knowledge_center/product-faq/cloud-load-balancers

0 commit comments

Comments
 (0)