blob: a863d21d4a101f94fc46d4e2d78db1b7cc8848d8 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001package api
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/mitchellh/mapstructure"
8)
9
10// CAConfig is the structure for the Connect CA configuration.
11type CAConfig struct {
12 // Provider is the CA provider implementation to use.
13 Provider string
14
15 // Configuration is arbitrary configuration for the provider. This
16 // should only contain primitive values and containers (such as lists
17 // and maps).
18 Config map[string]interface{}
19
20 CreateIndex uint64
21 ModifyIndex uint64
22}
23
24// CommonCAProviderConfig is the common options available to all CA providers.
25type CommonCAProviderConfig struct {
26 LeafCertTTL time.Duration
27}
28
29// ConsulCAProviderConfig is the config for the built-in Consul CA provider.
30type ConsulCAProviderConfig struct {
31 CommonCAProviderConfig `mapstructure:",squash"`
32
33 PrivateKey string
34 RootCert string
35 RotationPeriod time.Duration
36}
37
38// ParseConsulCAConfig takes a raw config map and returns a parsed
39// ConsulCAProviderConfig.
40func ParseConsulCAConfig(raw map[string]interface{}) (*ConsulCAProviderConfig, error) {
41 var config ConsulCAProviderConfig
42 decodeConf := &mapstructure.DecoderConfig{
43 DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
44 ErrorUnused: true,
45 Result: &config,
46 WeaklyTypedInput: true,
47 }
48
49 decoder, err := mapstructure.NewDecoder(decodeConf)
50 if err != nil {
51 return nil, err
52 }
53
54 if err := decoder.Decode(raw); err != nil {
55 return nil, fmt.Errorf("error decoding config: %s", err)
56 }
57
58 return &config, nil
59}
60
61// CARootList is the structure for the results of listing roots.
62type CARootList struct {
63 ActiveRootID string
64 TrustDomain string
65 Roots []*CARoot
66}
67
68// CARoot represents a root CA certificate that is trusted.
69type CARoot struct {
70 // ID is a globally unique ID (UUID) representing this CA root.
71 ID string
72
73 // Name is a human-friendly name for this CA root. This value is
74 // opaque to Consul and is not used for anything internally.
75 Name string
76
77 // RootCertPEM is the PEM-encoded public certificate.
78 RootCertPEM string `json:"RootCert"`
79
80 // Active is true if this is the current active CA. This must only
81 // be true for exactly one CA. For any method that modifies roots in the
82 // state store, tests should be written to verify that multiple roots
83 // cannot be active.
84 Active bool
85
86 CreateIndex uint64
87 ModifyIndex uint64
88}
89
90// LeafCert is a certificate that has been issued by a Connect CA.
91type LeafCert struct {
92 // SerialNumber is the unique serial number for this certificate.
93 // This is encoded in standard hex separated by :.
94 SerialNumber string
95
96 // CertPEM and PrivateKeyPEM are the PEM-encoded certificate and private
97 // key for that cert, respectively. This should not be stored in the
98 // state store, but is present in the sign API response.
99 CertPEM string `json:",omitempty"`
100 PrivateKeyPEM string `json:",omitempty"`
101
102 // Service is the name of the service for which the cert was issued.
103 // ServiceURI is the cert URI value.
104 Service string
105 ServiceURI string
106
107 // ValidAfter and ValidBefore are the validity periods for the
108 // certificate.
109 ValidAfter time.Time
110 ValidBefore time.Time
111
112 CreateIndex uint64
113 ModifyIndex uint64
114}
115
116// CARoots queries the list of available roots.
117func (h *Connect) CARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
118 r := h.c.newRequest("GET", "/v1/connect/ca/roots")
119 r.setQueryOptions(q)
120 rtt, resp, err := requireOK(h.c.doRequest(r))
121 if err != nil {
122 return nil, nil, err
123 }
124 defer resp.Body.Close()
125
126 qm := &QueryMeta{}
127 parseQueryMeta(resp, qm)
128 qm.RequestTime = rtt
129
130 var out CARootList
131 if err := decodeBody(resp, &out); err != nil {
132 return nil, nil, err
133 }
134 return &out, qm, nil
135}
136
137// CAGetConfig returns the current CA configuration.
138func (h *Connect) CAGetConfig(q *QueryOptions) (*CAConfig, *QueryMeta, error) {
139 r := h.c.newRequest("GET", "/v1/connect/ca/configuration")
140 r.setQueryOptions(q)
141 rtt, resp, err := requireOK(h.c.doRequest(r))
142 if err != nil {
143 return nil, nil, err
144 }
145 defer resp.Body.Close()
146
147 qm := &QueryMeta{}
148 parseQueryMeta(resp, qm)
149 qm.RequestTime = rtt
150
151 var out CAConfig
152 if err := decodeBody(resp, &out); err != nil {
153 return nil, nil, err
154 }
155 return &out, qm, nil
156}
157
158// CASetConfig sets the current CA configuration.
159func (h *Connect) CASetConfig(conf *CAConfig, q *WriteOptions) (*WriteMeta, error) {
160 r := h.c.newRequest("PUT", "/v1/connect/ca/configuration")
161 r.setWriteOptions(q)
162 r.obj = conf
163 rtt, resp, err := requireOK(h.c.doRequest(r))
164 if err != nil {
165 return nil, err
166 }
167 defer resp.Body.Close()
168
169 wm := &WriteMeta{}
170 wm.RequestTime = rtt
171 return wm, nil
172}