-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpath_creds_create.go
More file actions
128 lines (108 loc) · 3.77 KB
/
path_creds_create.go
File metadata and controls
128 lines (108 loc) · 3.77 KB
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
package cloudflare
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
// maxTokenNameLength is the maximum length for the name of a Nomad access
// token
const maxTokenNameLength = 120
func createTokenName(role string) string {
lowerRole := strings.ToLower(role)
tokenName := fmt.Sprintf("vault-%s-%d", lowerRole, time.Now().UnixNano())
// Note: if the given role name is sufficiently long, the UnixNano() portion
// of the pseudo randomized token name is the part that gets trimmed off,
// weakening it's randomness.
if len(tokenName) > maxTokenNameLength {
tokenName = tokenName[:maxTokenNameLength]
}
return tokenName
}
func pathCredsCreate(b *backend) *framework.Path {
return &framework.Path{
Pattern: "creds/" + framework.GenericNameRegex("role"),
Fields: map[string]*framework.FieldSchema{
"role": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Create a cloudflare token from a Vault role",
},
"condition": &framework.FieldSchema{
Type: framework.TypeString,
Description: "JSON-encoded cloudflare IP constraints to apply to the token. Useful for limiting token usage to the IP of a service. See https://api.cloudflare.com/#user-api-tokens-create-token for more information.",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathCredsRead,
},
}
}
func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
condition := cloudflare.APITokenCondition{}
policies := []cloudflare.APITokenPolicies{}
role := d.Get("role").(string)
if _, ok := d.GetOk("condition"); ok {
conditionRaw := d.Get("condition").(string)
if len(conditionRaw) > 0 {
err := json.Unmarshal([]byte(conditionRaw), &condition)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("err while decoding 'condition'. err: %s", err)), nil
}
}
}
roleEntry, err := b.roleRead(ctx, req.Storage, role)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("err while getting role configuration for '%s'. err: %s", role, err)), nil
}
if roleEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("could not find entry for role '%s', did you configure it?", role)), nil
}
if roleEntry.PolicyDocument != "" {
err = json.Unmarshal([]byte(roleEntry.PolicyDocument), &policies)
if err != nil {
return logical.ErrorResponse("failed to marshal '%s' into a list of cloudflare policies. ensure your configuration is correct", roleEntry.PolicyDocument), nil
}
}
// Get the http client
c, err := b.client(ctx, req.Storage)
if err != nil {
return nil, err
}
lease, err := b.LeaseConfig(ctx, req.Storage)
if err != nil {
return nil, err
}
if lease == nil {
lease = &configLease{}
}
ttl, _, err := framework.CalculateTTL(b.System(), 0, lease.TTL, 0, lease.MaxTTL, 0, time.Time{})
if err != nil {
return logical.ErrorResponse("failed to caluclate ttl. err: %s", err), nil
}
var expirationDate time.Time = time.Now().UTC().Add(ttl).Truncate(time.Second)
token := cloudflare.APIToken{
Name: createTokenName(role),
Policies: policies,
Condition: &condition,
ExpiresOn: &expirationDate,
}
createdToken, err := c.CreateAPIToken(ctx, token)
if err != nil {
return logical.ErrorResponse("failed to create token. err: %s", err), nil
}
// Use the helper to create the secret
resp := b.Secret(SecretTokenType).Response(map[string]interface{}{
"id": createdToken.ID,
"token": createdToken.Value,
}, map[string]interface{}{
"id": createdToken.ID,
"token": createdToken.Value,
})
resp.Secret.TTL = lease.TTL
resp.Secret.MaxTTL = lease.MaxTTL
return resp, nil
}