github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/vault/provider.go (about)

     1  package vault
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"github.com/hashicorp/vault/api"
    12  	"github.com/mitchellh/go-homedir"
    13  )
    14  
    15  func Provider() terraform.ResourceProvider {
    16  	return &schema.Provider{
    17  		Schema: map[string]*schema.Schema{
    18  			"address": &schema.Schema{
    19  				Type:        schema.TypeString,
    20  				Required:    true,
    21  				DefaultFunc: schema.EnvDefaultFunc("VAULT_ADDR", nil),
    22  				Description: "URL of the root of the target Vault server.",
    23  			},
    24  			"token": &schema.Schema{
    25  				Type:        schema.TypeString,
    26  				Required:    true,
    27  				DefaultFunc: schema.EnvDefaultFunc("VAULT_TOKEN", ""),
    28  				Description: "Token to use to authenticate to Vault.",
    29  			},
    30  			"ca_cert_file": &schema.Schema{
    31  				Type:        schema.TypeString,
    32  				Optional:    true,
    33  				DefaultFunc: schema.EnvDefaultFunc("VAULT_CACERT", ""),
    34  				Description: "Path to a CA certificate file to validate the server's certificate.",
    35  			},
    36  			"ca_cert_dir": &schema.Schema{
    37  				Type:        schema.TypeString,
    38  				Optional:    true,
    39  				DefaultFunc: schema.EnvDefaultFunc("VAULT_CAPATH", ""),
    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", ""),
    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", ""),
    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", ""),
    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_auth_backend":   authBackendResource(),
    91  			"vault_generic_secret": genericSecretResource(),
    92  			"vault_policy":         policyResource(),
    93  		},
    94  	}
    95  }
    96  
    97  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
    98  	config := api.DefaultConfig()
    99  	config.Address = d.Get("address").(string)
   100  
   101  	clientAuthI := d.Get("client_auth").([]interface{})
   102  	if len(clientAuthI) > 1 {
   103  		return nil, fmt.Errorf("client_auth block may appear only once")
   104  	}
   105  
   106  	clientAuthCert := ""
   107  	clientAuthKey := ""
   108  	if len(clientAuthI) == 1 {
   109  		clientAuth := clientAuthI[0].(map[string]interface{})
   110  		clientAuthCert = clientAuth["cert_file"].(string)
   111  		clientAuthKey = clientAuth["key_file"].(string)
   112  	}
   113  
   114  	err := config.ConfigureTLS(&api.TLSConfig{
   115  		CACert:   d.Get("ca_cert_file").(string),
   116  		CAPath:   d.Get("ca_cert_dir").(string),
   117  		Insecure: d.Get("skip_tls_verify").(bool),
   118  
   119  		ClientCert: clientAuthCert,
   120  		ClientKey:  clientAuthKey,
   121  	})
   122  	if err != nil {
   123  		return nil, fmt.Errorf("failed to configure TLS for Vault API: %s", err)
   124  	}
   125  
   126  	client, err := api.NewClient(config)
   127  	if err != nil {
   128  		return nil, fmt.Errorf("failed to configure Vault API: %s", err)
   129  	}
   130  
   131  	token := d.Get("token").(string)
   132  	if token == "" {
   133  		// Use the vault CLI's token, if present.
   134  		homePath, err := homedir.Dir()
   135  		if err != nil {
   136  			return nil, fmt.Errorf("Can't find home directory when looking for ~/.vault-token: %s", err)
   137  		}
   138  		tokenBytes, err := ioutil.ReadFile(homePath + "/.vault-token")
   139  		if err != nil {
   140  			return nil, fmt.Errorf("No vault token found: %s", err)
   141  		}
   142  
   143  		token = strings.TrimSpace(string(tokenBytes))
   144  	}
   145  
   146  	// In order to enforce our relatively-short lease TTL, we derive a
   147  	// temporary child token that inherits all of the policies of the
   148  	// token we were given but expires after max_lease_ttl_seconds.
   149  	//
   150  	// The intent here is that Terraform will need to re-fetch any
   151  	// secrets on each run and so we limit the exposure risk of secrets
   152  	// that end up stored in the Terraform state, assuming that they are
   153  	// credentials that Vault is able to revoke.
   154  	//
   155  	// Caution is still required with state files since not all secrets
   156  	// can explicitly be revoked, and this limited scope won't apply to
   157  	// any secrets that are *written* by Terraform to Vault.
   158  
   159  	client.SetToken(token)
   160  	renewable := false
   161  	childTokenLease, err := client.Auth().Token().Create(&api.TokenCreateRequest{
   162  		DisplayName:    "terraform",
   163  		TTL:            fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
   164  		ExplicitMaxTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
   165  		Renewable:      &renewable,
   166  	})
   167  	if err != nil {
   168  		return nil, fmt.Errorf("failed to create limited child token: %s", err)
   169  	}
   170  
   171  	childToken := childTokenLease.Auth.ClientToken
   172  	policies := childTokenLease.Auth.Policies
   173  
   174  	log.Printf("[INFO] Using Vault token with the following policies: %s", strings.Join(policies, ", "))
   175  
   176  	client.SetToken(childToken)
   177  
   178  	return client, nil
   179  }