github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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_generic_secret": genericSecretResource(),
    91  			"vault_policy":         policyResource(),
    92  		},
    93  	}
    94  }
    95  
    96  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
    97  	config := api.DefaultConfig()
    98  	config.Address = d.Get("address").(string)
    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  	err := 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  	if err != nil {
   122  		return nil, fmt.Errorf("failed to configure TLS for Vault API: %s", err)
   123  	}
   124  
   125  	client, err := api.NewClient(config)
   126  	if err != nil {
   127  		return nil, fmt.Errorf("failed to configure Vault API: %s", err)
   128  	}
   129  
   130  	token := d.Get("token").(string)
   131  	if token == "" {
   132  		// Use the vault CLI's token, if present.
   133  		homePath, err := homedir.Dir()
   134  		if err != nil {
   135  			return nil, fmt.Errorf("Can't find home directory when looking for ~/.vault-token: %s", err)
   136  		}
   137  		tokenBytes, err := ioutil.ReadFile(homePath + "/.vault-token")
   138  		if err != nil {
   139  			return nil, fmt.Errorf("No vault token found: %s", err)
   140  		}
   141  
   142  		token = strings.TrimSpace(string(tokenBytes))
   143  	}
   144  
   145  	// In order to enforce our relatively-short lease TTL, we derive a
   146  	// temporary child token that inherits all of the policies of the
   147  	// token we were given but expires after max_lease_ttl_seconds.
   148  	//
   149  	// The intent here is that Terraform will need to re-fetch any
   150  	// secrets on each run and so we limit the exposure risk of secrets
   151  	// that end up stored in the Terraform state, assuming that they are
   152  	// credentials that Vault is able to revoke.
   153  	//
   154  	// Caution is still required with state files since not all secrets
   155  	// can explicitly be revoked, and this limited scope won't apply to
   156  	// any secrets that are *written* by Terraform to Vault.
   157  
   158  	client.SetToken(token)
   159  	renewable := false
   160  	childTokenLease, err := client.Auth().Token().Create(&api.TokenCreateRequest{
   161  		DisplayName:    "terraform",
   162  		TTL:            fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
   163  		ExplicitMaxTTL: fmt.Sprintf("%ds", d.Get("max_lease_ttl_seconds").(int)),
   164  		Renewable:      &renewable,
   165  	})
   166  	if err != nil {
   167  		return nil, fmt.Errorf("failed to create limited child token: %s", err)
   168  	}
   169  
   170  	childToken := childTokenLease.Auth.ClientToken
   171  	policies := childTokenLease.Auth.Policies
   172  
   173  	log.Printf("[INFO] Using Vault token with the following policies: %s", strings.Join(policies, ", "))
   174  
   175  	client.SetToken(childToken)
   176  
   177  	return client, nil
   178  }