github.com/rhenning/terraform@v0.8.0-beta2/builtin/providers/vault/provider.go (about) 1 package vault 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 "github.com/hashicorp/terraform/terraform" 10 "github.com/hashicorp/vault/api" 11 ) 12 13 func Provider() terraform.ResourceProvider { 14 return &schema.Provider{ 15 Schema: map[string]*schema.Schema{ 16 "address": &schema.Schema{ 17 Type: schema.TypeString, 18 Required: true, 19 DefaultFunc: schema.EnvDefaultFunc("VAULT_ADDR", nil), 20 Description: "URL of the root of the target Vault server.", 21 }, 22 "token": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 DefaultFunc: schema.EnvDefaultFunc("VAULT_TOKEN", nil), 26 Description: "Token to use to authenticate to Vault.", 27 }, 28 "ca_cert_file": &schema.Schema{ 29 Type: schema.TypeString, 30 Optional: true, 31 ConflictsWith: []string{"ca_cert_dir"}, 32 DefaultFunc: schema.EnvDefaultFunc("VAULT_CACERT", nil), 33 Description: "Path to a CA certificate file to validate the server's certificate.", 34 }, 35 "ca_cert_dir": &schema.Schema{ 36 Type: schema.TypeString, 37 Optional: true, 38 ConflictsWith: []string{"ca_cert_file"}, 39 DefaultFunc: schema.EnvDefaultFunc("VAULT_CAPATH", nil), 40 Description: "Path to directory containing CA certificate files to validate the server's certificate.", 41 }, 42 "client_auth": &schema.Schema{ 43 Type: schema.TypeList, 44 Optional: true, 45 Description: "Client authentication credentials.", 46 Elem: &schema.Resource{ 47 Schema: map[string]*schema.Schema{ 48 "cert_file": &schema.Schema{ 49 Type: schema.TypeString, 50 Required: true, 51 DefaultFunc: schema.EnvDefaultFunc("VAULT_CLIENT_CERT", nil), 52 Description: "Path to a file containing the client certificate.", 53 }, 54 "key_file": &schema.Schema{ 55 Type: schema.TypeString, 56 Required: true, 57 DefaultFunc: schema.EnvDefaultFunc("VAULT_CLIENT_KEY", nil), 58 Description: "Path to a file containing the private key that the certificate was issued for.", 59 }, 60 }, 61 }, 62 }, 63 "skip_tls_verify": &schema.Schema{ 64 Type: schema.TypeBool, 65 Optional: true, 66 DefaultFunc: schema.EnvDefaultFunc("VAULT_SKIP_VERIFY", nil), 67 Description: "Set this to true only if the target Vault server is an insecure development instance.", 68 }, 69 "max_lease_ttl_seconds": &schema.Schema{ 70 Type: schema.TypeInt, 71 Optional: true, 72 73 // Default is 20min, which is intended to be enough time for 74 // a reasonable Terraform run can complete but not 75 // significantly longer, so that any leases are revoked shortly 76 // after Terraform has finished running. 77 DefaultFunc: schema.EnvDefaultFunc("TERRAFORM_VAULT_MAX_TTL", 1200), 78 79 Description: "Maximum TTL for secret leases requested by this provider", 80 }, 81 }, 82 83 ConfigureFunc: providerConfigure, 84 85 DataSourcesMap: map[string]*schema.Resource{ 86 "vault_generic_secret": genericSecretDataSource(), 87 }, 88 89 ResourcesMap: map[string]*schema.Resource{ 90 "vault_generic_secret": genericSecretResource(), 91 }, 92 } 93 } 94 95 func providerConfigure(d *schema.ResourceData) (interface{}, error) { 96 config := &api.Config{ 97 Address: d.Get("address").(string), 98 } 99 100 clientAuthI := d.Get("client_auth").([]interface{}) 101 if len(clientAuthI) > 1 { 102 return nil, fmt.Errorf("client_auth block may appear only once") 103 } 104 105 clientAuthCert := "" 106 clientAuthKey := "" 107 if len(clientAuthI) == 1 { 108 clientAuth := clientAuthI[0].(map[string]interface{}) 109 clientAuthCert = clientAuth["cert_file"].(string) 110 clientAuthKey = clientAuth["key_file"].(string) 111 } 112 113 config.ConfigureTLS(&api.TLSConfig{ 114 CACert: d.Get("ca_cert_file").(string), 115 CAPath: d.Get("ca_cert_dir").(string), 116 Insecure: d.Get("skip_tls_verify").(bool), 117 118 ClientCert: clientAuthCert, 119 ClientKey: clientAuthKey, 120 }) 121 122 client, err := api.NewClient(config) 123 if err != nil { 124 return nil, fmt.Errorf("failed to configure Vault API: %s", err) 125 } 126 127 // In order to enforce our relatively-short lease TTL, we derive a 128 // temporary child token that inherits all of the policies of the 129 // token we were given but expires after max_lease_ttl_seconds. 130 // 131 // The intent here is that Terraform will need to re-fetch any 132 // secrets on each run and so we limit the exposure risk of secrets 133 // that end up stored in the Terraform state, assuming that they are 134 // credentials that Vault is able to revoke. 135 // 136 // Caution is still required with state files since not all secrets 137 // can explicitly be revoked, and this limited scope won't apply to 138 // any secrets that are *written* by Terraform to Vault. 139 140 client.SetToken(d.Get("token").(string)) 141 renewable := false 142 childTokenLease, err := client.Auth().Token().Create(&api.TokenCreateRequest{ 143 DisplayName: "terraform", 144 TTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)), 145 ExplicitMaxTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)), 146 Renewable: &renewable, 147 }) 148 if err != nil { 149 return nil, fmt.Errorf("failed to create limited child token: %s", err) 150 } 151 152 childToken := childTokenLease.Auth.ClientToken 153 policies := childTokenLease.Auth.Policies 154 155 log.Printf("[INFO] Using Vault token with the following policies: %s", strings.Join(policies, ", ")) 156 157 client.SetToken(childToken) 158 159 return client, nil 160 }