-
Notifications
You must be signed in to change notification settings - Fork 537
/
provider.go
210 lines (187 loc) · 8.05 KB
/
provider.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package vault
import (
"fmt"
"io/ioutil"
"log"
"strings"
"github.com/hashicorp/terraform/helper/logging"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/vault/api"
"github.com/mitchellh/go-homedir"
)
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"address": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_ADDR", nil),
Description: "URL of the root of the target Vault server.",
},
"token": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_TOKEN", ""),
Description: "Token to use to authenticate to Vault.",
},
"ca_cert_file": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_CACERT", ""),
Description: "Path to a CA certificate file to validate the server's certificate.",
},
"ca_cert_dir": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_CAPATH", ""),
Description: "Path to directory containing CA certificate files to validate the server's certificate.",
},
"client_auth": {
Type: schema.TypeList,
Optional: true,
Description: "Client authentication credentials.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cert_file": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_CLIENT_CERT", ""),
Description: "Path to a file containing the client certificate.",
},
"key_file": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_CLIENT_KEY", ""),
Description: "Path to a file containing the private key that the certificate was issued for.",
},
},
},
},
"skip_tls_verify": {
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("VAULT_SKIP_VERIFY", ""),
Description: "Set this to true only if the target Vault server is an insecure development instance.",
},
"max_lease_ttl_seconds": {
Type: schema.TypeInt,
Optional: true,
// Default is 20min, which is intended to be enough time for
// a reasonable Terraform run can complete but not
// significantly longer, so that any leases are revoked shortly
// after Terraform has finished running.
DefaultFunc: schema.EnvDefaultFunc("TERRAFORM_VAULT_MAX_TTL", 1200),
Description: "Maximum TTL for secret leases requested by this provider",
},
},
ConfigureFunc: providerConfigure,
DataSourcesMap: map[string]*schema.Resource{
"vault_approle_auth_backend_role_id": approleAuthBackendRoleIDDataSource(),
"vault_aws_access_credentials": awsAccessCredentialsDataSource(),
"vault_generic_secret": genericSecretDataSource(),
},
ResourcesMap: map[string]*schema.Resource{
"vault_approle_auth_backend_login": approleAuthBackendLoginResource(),
"vault_approle_auth_backend_role": approleAuthBackendRoleResource(),
"vault_approle_auth_backend_role_secret_id": approleAuthBackendRoleSecretIDResource(),
"vault_auth_backend": authBackendResource(),
"vault_token_auth_backend_role": tokenAuthBackendRoleResource(),
"vault_aws_auth_backend_cert": awsAuthBackendCertResource(),
"vault_aws_auth_backend_client": awsAuthBackendClientResource(),
"vault_aws_auth_backend_identity_whitelist": awsAuthBackendIdentityWhitelistResource(),
"vault_aws_auth_backend_login": awsAuthBackendLoginResource(),
"vault_aws_auth_backend_role": awsAuthBackendRoleResource(),
"vault_aws_auth_backend_role_tag": awsAuthBackendRoleTagResource(),
"vault_aws_auth_backend_sts_role": awsAuthBackendSTSRoleResource(),
"vault_aws_secret_backend": awsSecretBackendResource(),
"vault_aws_secret_backend_role": awsSecretBackendRoleResource(),
"vault_consul_secret_backend": consulSecretBackendResource(),
"vault_database_secret_backend_connection": databaseSecretBackendConnectionResource(),
"vault_database_secret_backend_role": databaseSecretBackendRoleResource(),
"vault_gcp_auth_backend_role": gcpAuthBackendRoleResource(),
"vault_cert_auth_backend_role": certAuthBackendRoleResource(),
"vault_generic_secret": genericSecretResource(),
"vault_okta_auth_backend": oktaAuthBackendResource(),
"vault_okta_auth_backend_user": oktaAuthBackendUserResource(),
"vault_okta_auth_backend_group": oktaAuthBackendGroupResource(),
"vault_ldap_auth_backend": ldapAuthBackendResource(),
"vault_ldap_auth_backend_user": ldapAuthBackendUserResource(),
"vault_ldap_auth_backend_group": ldapAuthBackendGroupResource(),
"vault_policy": policyResource(),
"vault_mount": mountResource(),
"vault_audit": auditResource(),
},
}
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
config := api.DefaultConfig()
config.Address = d.Get("address").(string)
clientAuthI := d.Get("client_auth").([]interface{})
if len(clientAuthI) > 1 {
return nil, fmt.Errorf("client_auth block may appear only once")
}
clientAuthCert := ""
clientAuthKey := ""
if len(clientAuthI) == 1 {
clientAuth := clientAuthI[0].(map[string]interface{})
clientAuthCert = clientAuth["cert_file"].(string)
clientAuthKey = clientAuth["key_file"].(string)
}
err := config.ConfigureTLS(&api.TLSConfig{
CACert: d.Get("ca_cert_file").(string),
CAPath: d.Get("ca_cert_dir").(string),
Insecure: d.Get("skip_tls_verify").(bool),
ClientCert: clientAuthCert,
ClientKey: clientAuthKey,
})
if err != nil {
return nil, fmt.Errorf("failed to configure TLS for Vault API: %s", err)
}
config.HttpClient.Transport = logging.NewTransport("Vault", config.HttpClient.Transport)
client, err := api.NewClient(config)
if err != nil {
return nil, fmt.Errorf("failed to configure Vault API: %s", err)
}
token := d.Get("token").(string)
if token == "" {
// Use the vault CLI's token, if present.
homePath, err := homedir.Dir()
if err != nil {
return nil, fmt.Errorf("can't find home directory when looking for ~/.vault-token: %s", err)
}
tokenBytes, err := ioutil.ReadFile(homePath + "/.vault-token")
if err != nil {
return nil, fmt.Errorf("no vault token found: %s", err)
}
token = strings.TrimSpace(string(tokenBytes))
}
// In order to enforce our relatively-short lease TTL, we derive a
// temporary child token that inherits all of the policies of the
// token we were given but expires after max_lease_ttl_seconds.
//
// The intent here is that Terraform will need to re-fetch any
// secrets on each run and so we limit the exposure risk of secrets
// that end up stored in the Terraform state, assuming that they are
// credentials that Vault is able to revoke.
//
// Caution is still required with state files since not all secrets
// can explicitly be revoked, and this limited scope won't apply to
// any secrets that are *written* by Terraform to Vault.
client.SetToken(token)
renewable := false
childTokenLease, err := client.Auth().Token().Create(&api.TokenCreateRequest{
DisplayName: "terraform",
TTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
ExplicitMaxTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
Renewable: &renewable,
})
if err != nil {
return nil, fmt.Errorf("failed to create limited child token: %s", err)
}
childToken := childTokenLease.Auth.ClientToken
policies := childTokenLease.Auth.Policies
log.Printf("[INFO] Using Vault token with the following policies: %s", strings.Join(policies, ", "))
client.SetToken(childToken)
return client, nil
}