github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 }