forked from hashicorp/terraform
-
Notifications
You must be signed in to change notification settings - Fork 7
/
resource_generic_secret.go
139 lines (112 loc) · 3.62 KB
/
resource_generic_secret.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
package vault
import (
"encoding/json"
"fmt"
"log"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/vault/api"
)
func genericSecretResource() *schema.Resource {
return &schema.Resource{
Create: genericSecretResourceWrite,
Update: genericSecretResourceWrite,
Delete: genericSecretResourceDelete,
Read: genericSecretResourceRead,
Schema: map[string]*schema.Schema{
"path": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Full path where the generic secret will be written.",
},
// Data is passed as JSON so that an arbitrary structure is
// possible, rather than forcing e.g. all values to be strings.
"data_json": &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "JSON-encoded secret data to write.",
// We rebuild the attached JSON string to a simple singleline
// string. This makes terraform not want to change when an extra
// space is included in the JSON string. It is also necesarry
// when allow_read is true for comparing values.
StateFunc: NormalizeDataJSON,
ValidateFunc: ValidateDataJSON,
},
"allow_read": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "True if the provided token is allowed to read the secret from vault",
},
},
}
}
func ValidateDataJSON(configI interface{}, k string) ([]string, []error) {
dataJSON := configI.(string)
dataMap := map[string]interface{}{}
err := json.Unmarshal([]byte(dataJSON), &dataMap)
if err != nil {
return nil, []error{err}
}
return nil, nil
}
func NormalizeDataJSON(configI interface{}) string {
dataJSON := configI.(string)
dataMap := map[string]interface{}{}
err := json.Unmarshal([]byte(dataJSON), &dataMap)
if err != nil {
// The validate function should've taken care of this.
return ""
}
ret, err := json.Marshal(dataMap)
if err != nil {
// Should never happen.
return dataJSON
}
return string(ret)
}
func genericSecretResourceWrite(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
path := d.Get("path").(string)
var data map[string]interface{}
err := json.Unmarshal([]byte(d.Get("data_json").(string)), &data)
if err != nil {
return fmt.Errorf("data_json %#v syntax error: %s", d.Get("data_json"), err)
}
log.Printf("[DEBUG] Writing generic Vault secret to %s", path)
_, err = client.Logical().Write(path, data)
if err != nil {
return fmt.Errorf("error writing to Vault: %s", err)
}
d.SetId(path)
return nil
}
func genericSecretResourceDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)
path := d.Id()
log.Printf("[DEBUG] Deleting generic Vault from %s", path)
_, err := client.Logical().Delete(path)
if err != nil {
return fmt.Errorf("error deleting from Vault: %s", err)
}
return nil
}
func genericSecretResourceRead(d *schema.ResourceData, meta interface{}) error {
allowed_to_read := d.Get("allow_read").(bool)
path := d.Get("path").(string)
if allowed_to_read {
client := meta.(*api.Client)
log.Printf("[DEBUG] Reading %s from Vault", path)
secret, err := client.Logical().Read(path)
if err != nil {
return fmt.Errorf("error reading from Vault: %s", err)
}
// Ignoring error because this value came from JSON in the
// first place so no reason why it should fail to re-encode.
jsonDataBytes, _ := json.Marshal(secret.Data)
d.Set("data_json", string(jsonDataBytes))
}
d.SetId(path)
log.Printf("[WARN] vault_generic_secret does not automatically refresh if allow_read is set to false")
return nil
}