github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_iam_server_certificate.go (about) 1 package aws 2 3 import ( 4 "crypto/sha1" 5 "encoding/hex" 6 "fmt" 7 "log" 8 "strings" 9 "time" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/aws/awserr" 13 "github.com/aws/aws-sdk-go/service/iam" 14 "github.com/hashicorp/terraform/helper/resource" 15 "github.com/hashicorp/terraform/helper/schema" 16 ) 17 18 func resourceAwsIAMServerCertificate() *schema.Resource { 19 return &schema.Resource{ 20 Create: resourceAwsIAMServerCertificateCreate, 21 Read: resourceAwsIAMServerCertificateRead, 22 Delete: resourceAwsIAMServerCertificateDelete, 23 Importer: &schema.ResourceImporter{ 24 State: resourceAwsIAMServerCertificateImport, 25 }, 26 27 Schema: map[string]*schema.Schema{ 28 "certificate_body": { 29 Type: schema.TypeString, 30 Required: true, 31 ForceNew: true, 32 StateFunc: normalizeCert, 33 }, 34 35 "certificate_chain": { 36 Type: schema.TypeString, 37 Optional: true, 38 ForceNew: true, 39 StateFunc: normalizeCert, 40 }, 41 42 "path": { 43 Type: schema.TypeString, 44 Optional: true, 45 Default: "/", 46 ForceNew: true, 47 }, 48 49 "private_key": { 50 Type: schema.TypeString, 51 Required: true, 52 ForceNew: true, 53 StateFunc: normalizeCert, 54 Sensitive: true, 55 }, 56 57 "name": { 58 Type: schema.TypeString, 59 Optional: true, 60 Computed: true, 61 ForceNew: true, 62 ConflictsWith: []string{"name_prefix"}, 63 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 64 value := v.(string) 65 if len(value) > 128 { 66 errors = append(errors, fmt.Errorf( 67 "%q cannot be longer than 128 characters", k)) 68 } 69 return 70 }, 71 }, 72 73 "name_prefix": { 74 Type: schema.TypeString, 75 Optional: true, 76 ForceNew: true, 77 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 78 value := v.(string) 79 if len(value) > 30 { 80 errors = append(errors, fmt.Errorf( 81 "%q cannot be longer than 30 characters, name is limited to 128", k)) 82 } 83 return 84 }, 85 }, 86 87 "arn": { 88 Type: schema.TypeString, 89 Optional: true, 90 Computed: true, 91 }, 92 }, 93 } 94 } 95 96 func resourceAwsIAMServerCertificateCreate(d *schema.ResourceData, meta interface{}) error { 97 conn := meta.(*AWSClient).iamconn 98 99 var sslCertName string 100 if v, ok := d.GetOk("name"); ok { 101 sslCertName = v.(string) 102 } else if v, ok := d.GetOk("name_prefix"); ok { 103 sslCertName = resource.PrefixedUniqueId(v.(string)) 104 } else { 105 sslCertName = resource.UniqueId() 106 } 107 108 createOpts := &iam.UploadServerCertificateInput{ 109 CertificateBody: aws.String(d.Get("certificate_body").(string)), 110 PrivateKey: aws.String(d.Get("private_key").(string)), 111 ServerCertificateName: aws.String(sslCertName), 112 } 113 114 if v, ok := d.GetOk("certificate_chain"); ok { 115 createOpts.CertificateChain = aws.String(v.(string)) 116 } 117 118 if v, ok := d.GetOk("path"); ok { 119 createOpts.Path = aws.String(v.(string)) 120 } 121 122 log.Printf("[DEBUG] Creating IAM Server Certificate with opts: %s", createOpts) 123 resp, err := conn.UploadServerCertificate(createOpts) 124 if err != nil { 125 if awsErr, ok := err.(awserr.Error); ok { 126 return fmt.Errorf("[WARN] Error uploading server certificate, error: %s: %s", awsErr.Code(), awsErr.Message()) 127 } 128 return fmt.Errorf("[WARN] Error uploading server certificate, error: %s", err) 129 } 130 131 d.SetId(*resp.ServerCertificateMetadata.ServerCertificateId) 132 d.Set("name", sslCertName) 133 134 return resourceAwsIAMServerCertificateRead(d, meta) 135 } 136 137 func resourceAwsIAMServerCertificateRead(d *schema.ResourceData, meta interface{}) error { 138 conn := meta.(*AWSClient).iamconn 139 resp, err := conn.GetServerCertificate(&iam.GetServerCertificateInput{ 140 ServerCertificateName: aws.String(d.Get("name").(string)), 141 }) 142 143 if err != nil { 144 if awsErr, ok := err.(awserr.Error); ok { 145 if awsErr.Code() == "NoSuchEntity" { 146 log.Printf("[WARN] IAM Server Cert (%s) not found, removing from state", d.Id()) 147 d.SetId("") 148 return nil 149 } 150 return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s: %s", awsErr.Code(), awsErr.Message()) 151 } 152 return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s", err) 153 } 154 155 d.SetId(*resp.ServerCertificate.ServerCertificateMetadata.ServerCertificateId) 156 157 // these values should always be present, and have a default if not set in 158 // configuration, and so safe to reference with nil checks 159 d.Set("certificate_body", normalizeCert(resp.ServerCertificate.CertificateBody)) 160 161 c := normalizeCert(resp.ServerCertificate.CertificateChain) 162 if c != "" { 163 d.Set("certificate_chain", c) 164 } 165 166 d.Set("path", resp.ServerCertificate.ServerCertificateMetadata.Path) 167 d.Set("arn", resp.ServerCertificate.ServerCertificateMetadata.Arn) 168 169 return nil 170 } 171 172 func resourceAwsIAMServerCertificateDelete(d *schema.ResourceData, meta interface{}) error { 173 conn := meta.(*AWSClient).iamconn 174 log.Printf("[INFO] Deleting IAM Server Certificate: %s", d.Id()) 175 err := resource.Retry(3*time.Minute, func() *resource.RetryError { 176 _, err := conn.DeleteServerCertificate(&iam.DeleteServerCertificateInput{ 177 ServerCertificateName: aws.String(d.Get("name").(string)), 178 }) 179 180 if err != nil { 181 if awsErr, ok := err.(awserr.Error); ok { 182 if awsErr.Code() == "DeleteConflict" && strings.Contains(awsErr.Message(), "currently in use by arn") { 183 log.Printf("[WARN] Conflict deleting server certificate: %s, retrying", awsErr.Message()) 184 return resource.RetryableError(err) 185 } 186 if awsErr.Code() == "NoSuchEntity" { 187 log.Printf("[WARN] IAM Server Certificate (%s) not found, removing from state", d.Id()) 188 d.SetId("") 189 return nil 190 } 191 } 192 return resource.NonRetryableError(err) 193 } 194 return nil 195 }) 196 197 if err != nil { 198 return err 199 } 200 201 d.SetId("") 202 return nil 203 } 204 205 func resourceAwsIAMServerCertificateImport( 206 d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { 207 d.Set("name", d.Id()) 208 // private_key can't be fetched from any API call 209 return []*schema.ResourceData{d}, nil 210 } 211 212 func normalizeCert(cert interface{}) string { 213 if cert == nil || cert == (*string)(nil) { 214 return "" 215 } 216 217 var rawCert string 218 switch cert.(type) { 219 case string: 220 rawCert = cert.(string) 221 case *string: 222 rawCert = *cert.(*string) 223 default: 224 return "" 225 } 226 227 cleanVal := sha1.Sum(stripCR([]byte(strings.TrimSpace(rawCert)))) 228 return hex.EncodeToString(cleanVal[:]) 229 } 230 231 // strip CRs from raw literals. Lifted from go/scanner/scanner.go 232 // See https://github.com/golang/go/blob/release-branch.go1.6/src/go/scanner/scanner.go#L479 233 func stripCR(b []byte) []byte { 234 c := make([]byte, len(b)) 235 i := 0 236 for _, ch := range b { 237 if ch != '\r' { 238 c[i] = ch 239 i++ 240 } 241 } 242 return c[:i] 243 }