github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/vault/resource_generic_secret.go (about)

     1  package vault
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"log"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  
    10  	"github.com/hashicorp/vault/api"
    11  )
    12  
    13  func genericSecretResource() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: genericSecretResourceWrite,
    16  		Update: genericSecretResourceWrite,
    17  		Delete: genericSecretResourceDelete,
    18  		Read:   genericSecretResourceRead,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"path": &schema.Schema{
    22  				Type:        schema.TypeString,
    23  				Required:    true,
    24  				ForceNew:    true,
    25  				Description: "Full path where the generic secret will be written.",
    26  			},
    27  
    28  			// Data is passed as JSON so that an arbitrary structure is
    29  			// possible, rather than forcing e.g. all values to be strings.
    30  			"data_json": &schema.Schema{
    31  				Type:        schema.TypeString,
    32  				Required:    true,
    33  				Description: "JSON-encoded secret data to write.",
    34  				// We rebuild the attached JSON string to a simple singleline
    35  				// string. This makes terraform not want to change when an extra
    36  				// space is included in the JSON string. It is also necesarry
    37  				// when allow_read is true for comparing values.
    38  				StateFunc:    NormalizeDataJSON,
    39  				ValidateFunc: ValidateDataJSON,
    40  			},
    41  
    42  			"allow_read": &schema.Schema{
    43  				Type:        schema.TypeBool,
    44  				Optional:    true,
    45  				Default:     false,
    46  				Description: "True if the provided token is allowed to read the secret from vault",
    47  			},
    48  		},
    49  	}
    50  }
    51  
    52  func ValidateDataJSON(configI interface{}, k string) ([]string, []error) {
    53  	dataJSON := configI.(string)
    54  	dataMap := map[string]interface{}{}
    55  	err := json.Unmarshal([]byte(dataJSON), &dataMap)
    56  	if err != nil {
    57  		return nil, []error{err}
    58  	}
    59  	return nil, nil
    60  }
    61  
    62  func NormalizeDataJSON(configI interface{}) string {
    63  	dataJSON := configI.(string)
    64  
    65  	dataMap := map[string]interface{}{}
    66  	err := json.Unmarshal([]byte(dataJSON), &dataMap)
    67  	if err != nil {
    68  		// The validate function should've taken care of this.
    69  		return ""
    70  	}
    71  
    72  	ret, err := json.Marshal(dataMap)
    73  	if err != nil {
    74  		// Should never happen.
    75  		return dataJSON
    76  	}
    77  
    78  	return string(ret)
    79  }
    80  
    81  func genericSecretResourceWrite(d *schema.ResourceData, meta interface{}) error {
    82  	client := meta.(*api.Client)
    83  
    84  	path := d.Get("path").(string)
    85  
    86  	var data map[string]interface{}
    87  	err := json.Unmarshal([]byte(d.Get("data_json").(string)), &data)
    88  	if err != nil {
    89  		return fmt.Errorf("data_json %#v syntax error: %s", d.Get("data_json"), err)
    90  	}
    91  
    92  	log.Printf("[DEBUG] Writing generic Vault secret to %s", path)
    93  	_, err = client.Logical().Write(path, data)
    94  	if err != nil {
    95  		return fmt.Errorf("error writing to Vault: %s", err)
    96  	}
    97  
    98  	d.SetId(path)
    99  
   100  	return nil
   101  }
   102  
   103  func genericSecretResourceDelete(d *schema.ResourceData, meta interface{}) error {
   104  	client := meta.(*api.Client)
   105  
   106  	path := d.Id()
   107  
   108  	log.Printf("[DEBUG] Deleting generic Vault from %s", path)
   109  	_, err := client.Logical().Delete(path)
   110  	if err != nil {
   111  		return fmt.Errorf("error deleting from Vault: %s", err)
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  func genericSecretResourceRead(d *schema.ResourceData, meta interface{}) error {
   118  	allowed_to_read := d.Get("allow_read").(bool)
   119  	path := d.Get("path").(string)
   120  
   121  	if allowed_to_read {
   122  		client := meta.(*api.Client)
   123  
   124  		log.Printf("[DEBUG] Reading %s from Vault", path)
   125  		secret, err := client.Logical().Read(path)
   126  		if err != nil {
   127  			return fmt.Errorf("error reading from Vault: %s", err)
   128  		}
   129  
   130  		// Ignoring error because this value came from JSON in the
   131  		// first place so no reason why it should fail to re-encode.
   132  		jsonDataBytes, _ := json.Marshal(secret.Data)
   133  		d.Set("data_json", string(jsonDataBytes))
   134  	}
   135  
   136  	d.SetId(path)
   137  	log.Printf("[WARN] vault_generic_secret does not automatically refresh if allow_read is set to false")
   138  	return nil
   139  }