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

     1  package tls
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/rsa"
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"fmt"
    11  
    12  	"golang.org/x/crypto/ssh"
    13  
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  type keyAlgo func(d *schema.ResourceData) (interface{}, error)
    18  type keyParser func([]byte) (interface{}, error)
    19  
    20  var keyAlgos map[string]keyAlgo = map[string]keyAlgo{
    21  	"RSA": func(d *schema.ResourceData) (interface{}, error) {
    22  		rsaBits := d.Get("rsa_bits").(int)
    23  		return rsa.GenerateKey(rand.Reader, rsaBits)
    24  	},
    25  	"ECDSA": func(d *schema.ResourceData) (interface{}, error) {
    26  		curve := d.Get("ecdsa_curve").(string)
    27  		switch curve {
    28  		case "P224":
    29  			return ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    30  		case "P256":
    31  			return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    32  		case "P384":
    33  			return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
    34  		case "P521":
    35  			return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
    36  		default:
    37  			return nil, fmt.Errorf("invalid ecdsa_curve; must be P224, P256, P384 or P521")
    38  		}
    39  	},
    40  }
    41  
    42  var keyParsers map[string]keyParser = map[string]keyParser{
    43  	"RSA": func(der []byte) (interface{}, error) {
    44  		return x509.ParsePKCS1PrivateKey(der)
    45  	},
    46  	"ECDSA": func(der []byte) (interface{}, error) {
    47  		return x509.ParseECPrivateKey(der)
    48  	},
    49  }
    50  
    51  func resourcePrivateKey() *schema.Resource {
    52  	return &schema.Resource{
    53  		Create: CreatePrivateKey,
    54  		Delete: DeletePrivateKey,
    55  		Read:   ReadPrivateKey,
    56  
    57  		Schema: map[string]*schema.Schema{
    58  			"algorithm": &schema.Schema{
    59  				Type:        schema.TypeString,
    60  				Required:    true,
    61  				Description: "Name of the algorithm to use to generate the private key",
    62  				ForceNew:    true,
    63  			},
    64  
    65  			"rsa_bits": &schema.Schema{
    66  				Type:        schema.TypeInt,
    67  				Optional:    true,
    68  				Description: "Number of bits to use when generating an RSA key",
    69  				ForceNew:    true,
    70  				Default:     2048,
    71  			},
    72  
    73  			"ecdsa_curve": &schema.Schema{
    74  				Type:        schema.TypeString,
    75  				Optional:    true,
    76  				Description: "ECDSA curve to use when generating a key",
    77  				ForceNew:    true,
    78  				Default:     "P224",
    79  			},
    80  
    81  			"private_key_pem": &schema.Schema{
    82  				Type:     schema.TypeString,
    83  				Computed: true,
    84  			},
    85  
    86  			"public_key_pem": &schema.Schema{
    87  				Type:     schema.TypeString,
    88  				Computed: true,
    89  			},
    90  
    91  			"public_key_openssh": &schema.Schema{
    92  				Type:     schema.TypeString,
    93  				Computed: true,
    94  			},
    95  		},
    96  	}
    97  }
    98  
    99  func CreatePrivateKey(d *schema.ResourceData, meta interface{}) error {
   100  	keyAlgoName := d.Get("algorithm").(string)
   101  	var keyFunc keyAlgo
   102  	var ok bool
   103  	if keyFunc, ok = keyAlgos[keyAlgoName]; !ok {
   104  		return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName)
   105  	}
   106  
   107  	key, err := keyFunc(d)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	var keyPemBlock *pem.Block
   113  	switch k := key.(type) {
   114  	case *rsa.PrivateKey:
   115  		keyPemBlock = &pem.Block{
   116  			Type:  "RSA PRIVATE KEY",
   117  			Bytes: x509.MarshalPKCS1PrivateKey(k),
   118  		}
   119  	case *ecdsa.PrivateKey:
   120  		keyBytes, err := x509.MarshalECPrivateKey(k)
   121  		if err != nil {
   122  			return fmt.Errorf("error encoding key to PEM: %s", err)
   123  		}
   124  		keyPemBlock = &pem.Block{
   125  			Type:  "EC PRIVATE KEY",
   126  			Bytes: keyBytes,
   127  		}
   128  	default:
   129  		return fmt.Errorf("unsupported private key type")
   130  	}
   131  	keyPem := string(pem.EncodeToMemory(keyPemBlock))
   132  
   133  	pubKey := publicKey(key)
   134  	pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubKey)
   135  	if err != nil {
   136  		return fmt.Errorf("failed to marshal public key: %s", err)
   137  	}
   138  	pubKeyPemBlock := &pem.Block{
   139  		Type:  "PUBLIC KEY",
   140  		Bytes: pubKeyBytes,
   141  	}
   142  
   143  	d.SetId(hashForState(string((pubKeyBytes))))
   144  	d.Set("private_key_pem", keyPem)
   145  	d.Set("public_key_pem", string(pem.EncodeToMemory(pubKeyPemBlock)))
   146  
   147  	sshPubKey, err := ssh.NewPublicKey(pubKey)
   148  	if err == nil {
   149  		// Not all EC types can be SSH keys, so we'll produce this only
   150  		// if an appropriate type was selected.
   151  		sshPubKeyBytes := ssh.MarshalAuthorizedKey(sshPubKey)
   152  		d.Set("public_key_openssh", string(sshPubKeyBytes))
   153  	} else {
   154  		d.Set("public_key_openssh", "")
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  func DeletePrivateKey(d *schema.ResourceData, meta interface{}) error {
   161  	d.SetId("")
   162  	return nil
   163  }
   164  
   165  func ReadPrivateKey(d *schema.ResourceData, meta interface{}) error {
   166  	return nil
   167  }
   168  
   169  func publicKey(priv interface{}) interface{} {
   170  	switch k := priv.(type) {
   171  	case *rsa.PrivateKey:
   172  		return &k.PublicKey
   173  	case *ecdsa.PrivateKey:
   174  		return &k.PublicKey
   175  	default:
   176  		return nil
   177  	}
   178  }