-
Notifications
You must be signed in to change notification settings - Fork 1
/
path_issue_cert.go
165 lines (143 loc) · 4.27 KB
/
path_issue_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
156
157
158
159
160
161
162
163
164
165
package pki
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/fatih/structs"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
"vault-plugin-hydrant-pki/pkg/hydrant"
)
func pathIssue(b *Backend) *framework.Path {
ret := &framework.Path{
Pattern: "issue",
Fields: map[string]*framework.FieldSchema{
"cn": {
Type: framework.TypeString,
Description: "Specifies the CN for the certificate.",
Required: true,
},
"ttl": {
Type: framework.TypeInt,
Description: "Specifies the TTL for the certificate (in days). Defaults to 1 year (365 days) if not specified.",
Default: 1,
},
"sans": {
Type: framework.TypeCommaStringSlice,
Description: "Specifies the SANs for the certificate. Comma separated string values e.g.: sans='test0.domain.com, test1.domain.com'",
},
"dl": {
Type: framework.TypeString,
Description: "Specifies the distribution list for the owner of the certificate.",
Required: true,
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleIssueCert,
Summary: "Issue certificate from HydrantID.",
},
},
HelpSynopsis: pathIssueHelpSyn,
HelpDescription: pathIssueHelpDesc,
}
return ret
}
const pathIssueHelpSyn = `
Request a certificate with the provided details.
`
const pathIssueHelpDesc = `
This path allows requesting a certificate to be issued.
The certificate will only be issued if the requested details are allowed by the hydrant policy.
This path returns a certificate with its private key.
`
func pathRenew(b *Backend) *framework.Path {
ret := &framework.Path{
Pattern: "renew/(?P<id>([a-fA-F0-9]+-)+[a-fA-F0-9]+)",
Fields: map[string]*framework.FieldSchema{
"id": {
Type: framework.TypeString,
Description: "Specifies the ID for the certificate.",
Required: true,
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathRenew,
Summary: "Renew certificate from HydrantID.",
},
},
HelpSynopsis: pathRenewHelpSyn,
HelpDescription: pathRenewHelpDesc,
}
return ret
}
const pathRenewHelpSyn = `
Request a certificate renewal for the provided id.
`
const pathRenewHelpDesc = `
Request a certificate renewal for the provided id.
This requires that the policy used to issue this certificate initially allows for csr reuse.
Otherwise, this will fail.
`
func (b *Backend) handleIssueCert(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
if req.ClientToken == "" {
return nil, fmt.Errorf("client token empty")
}
if data.Get("cn") == nil || data.Get("cn") == "" {
return nil, errors.New("cn is empty")
}
if data.Get("dl") == nil || data.Get("dl") == "" {
return nil, errors.New("distribution list dl is empty")
}
cn := data.Get("cn").(string)
ttl := data.Get("ttl").(int)
sans := data.Get("sans").([]string)
dl := data.Get("dl").(string)
hydrantClient, err := b.GetHydrantClient(ctx, req.Storage)
if err != nil {
b.Backend.Logger().Error(err.Error())
return nil, err
}
certificate, err := hydrantClient.IssueCertificate(b.Logger(), &hydrant.IssueCertRequest{
CN: cn,
TTL: ttl,
SANS: sans,
DL: dl,
})
if err != nil {
return nil, err
}
buf, err := json.Marshal(certificate)
if err != nil {
return nil, errwrap.Wrapf("json encoding failed: {{err}}", err)
}
_ = req.Storage.Put(ctx, &logical.StorageEntry{
Key: "certs/" + certificate.Id,
Value: buf,
})
// Generate the response
resp := &logical.Response{
Data: structs.Map(certificate),
}
return resp, nil
}
func (b *Backend) pathRenew(ctx context.Context, request *logical.Request, data *framework.FieldData) (*logical.Response, error) {
id := data.Get("id").(string)
b.Backend.Logger().Info("pathRenew id: " + id)
hydrantClient, err := b.GetHydrantClient(ctx, request.Storage)
if err != nil {
b.Backend.Logger().Error(err.Error())
return nil, err
}
renewedCert, err := hydrantClient.RenewCert(b.Logger(), id)
if err != nil {
return nil, err
}
resp := &logical.Response{
Data: structs.Map(renewedCert),
}
return resp, nil
}