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