/
cert.go
155 lines (137 loc) · 4.37 KB
/
cert.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 (
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
"github.com/chef/automate/api/config/shared"
"github.com/chef/automate/components/automate-cli/pkg/docs"
"github.com/chef/automate/components/automate-cli/pkg/status"
"github.com/chef/automate/components/automate-deployment/pkg/client"
)
type certCmdFlagSet struct {
hostname string
filepath string
}
var certCmdFlags = certCmdFlagSet{}
func init() {
certCmd := certCmd()
certCmd.PersistentFlags().StringVarP(
&certCmdFlags.hostname,
"hostname",
"n",
"",
"Hostname for the automate TLS certificate",
)
certCmd.PersistentFlags().StringVarP(
&certCmdFlags.filepath,
"file",
"f",
"",
"File path to save automate TLS certifcate to.",
)
RootCmd.AddCommand(certCmd)
}
func certCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "external-cert COMMAND",
Short: "Manage Chef Automate's external certificate",
Long: "Manage Chef Automate's external certificate authority. Used for establishing TLS/SSL communication with automate.",
Annotations: map[string]string{
docs.Tag: docs.FrontEnd,
},
}
certShow := &cobra.Command{
Use: "show",
Short: "Show the external TLS/SSL certificates in Automate. Optionally, save the certificates to a file in the specified path.",
RunE: runCertShowCmd,
Args: cobra.MaximumNArgs(2),
Annotations: map[string]string{
docs.Tag: docs.FrontEnd,
},
}
cmd.AddCommand(certShow)
return cmd
}
func runCertShowCmd(*cobra.Command, []string) error {
res, err := client.GetAutomateConfig(int64(client.DefaultClientTimeout))
if err != nil {
return status.Wrap(
err,
status.DeploymentServiceUnreachableError,
"Connecting to deployment-service failed",
)
}
tlsCreds := res.Config.GetGlobal().GetV1().GetFrontendTls()
if certCmdFlags.hostname != "" && certCmdFlags.filepath != "" {
for _, tlsCred := range tlsCreds {
if tlsCred.GetServerName() == certCmdFlags.hostname {
return writeToFile(tlsCred.GetCert())
}
}
hostnames := gatherHostnames(tlsCreds)
// Error no matching hostname found in the automate frontend_tls cert configuration
return status.Wrap(
err,
status.CommandExecutionError,
fmt.Sprintf("Unable to find matching certificate configuration for hostname %s. Available Hostnames: %q", certCmdFlags.filepath, hostnames),
)
} else if certCmdFlags.hostname != "" {
for _, tlsCred := range tlsCreds {
if tlsCred.GetServerName() == certCmdFlags.hostname {
// Print hostname on stderr so that we can pipe the cert with other cmds
writer.Errorf("Hostname: %s\n", tlsCred.GetServerName())
writer.Printf(tlsCred.GetCert())
return nil
}
}
// Error no matching hostname found in the automate frontend_tls cert configuration
hostnames := gatherHostnames(tlsCreds)
return status.Wrap(
err,
status.CommandExecutionError,
fmt.Sprintf("Unable to find matching certificate configuration for hostname %s. Available hostnames: %q", certCmdFlags.filepath, hostnames),
)
} else if certCmdFlags.filepath != "" {
if len(tlsCreds) > 1 {
// There is more than one cert and it is unclear which one to save to the cert file
hostnames := gatherHostnames(tlsCreds)
return status.Wrap(
err,
status.CommandExecutionError,
fmt.Sprintf("Found more than one host certificate configured, please specify a hostname using the -hostname flag. Available Hostnames: %q", hostnames),
)
}
return writeToFile(tlsCreds[0].GetCert())
} // Print all certs to stdout
for _, tlsCred := range tlsCreds {
if tlsCred.GetServerName() != "" {
// Print hostname on stderr so that we can pipe the cert with other cmds
writer.Errorf("Hostname: %s\n", tlsCred.GetServerName())
writer.Println(tlsCred.GetCert())
} else {
// Don't print the hostname if it isn't there
// It is most likely not set, so let's keep it simple
writer.Println(tlsCred.GetCert())
}
}
return nil
}
func writeToFile(cert string) error {
err := ioutil.WriteFile(certCmdFlags.filepath, []byte(cert), 0644)
if err != nil {
return status.Wrap(
err,
status.FileAccessError,
fmt.Sprintf("Unable to write to file %s", certCmdFlags.filepath),
)
}
return nil
}
func gatherHostnames(tlsCreds []*shared.FrontendTLSCredential) []string {
// Gather certificate server names (hostnames)
hostnames := make([]string, len(tlsCreds))
for i, tlsCred := range tlsCreds {
hostnames[i] = tlsCred.GetServerName()
}
return hostnames
}