github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/aws/resource_aws_iam_user_login_profile.go (about)

     1  package aws
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"math/rand"
     8  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/iam"
    13  	"github.com/hashicorp/errwrap"
    14  	"github.com/hashicorp/terraform/helper/encryption"
    15  	"github.com/hashicorp/terraform/helper/schema"
    16  )
    17  
    18  func resourceAwsIamUserLoginProfile() *schema.Resource {
    19  	return &schema.Resource{
    20  		Create: resourceAwsIamUserLoginProfileCreate,
    21  		Read:   schema.Noop,
    22  		Update: schema.Noop,
    23  		Delete: schema.RemoveFromState,
    24  
    25  		Schema: map[string]*schema.Schema{
    26  			"user": {
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  			},
    30  			"pgp_key": {
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  			},
    34  			"password_reset_required": {
    35  				Type:     schema.TypeBool,
    36  				Optional: true,
    37  				Default:  true,
    38  			},
    39  			"password_length": {
    40  				Type:         schema.TypeInt,
    41  				Optional:     true,
    42  				Default:      20,
    43  				ValidateFunc: validateAwsIamLoginProfilePasswordLength,
    44  			},
    45  
    46  			"key_fingerprint": {
    47  				Type:     schema.TypeString,
    48  				Computed: true,
    49  			},
    50  			"encrypted_password": {
    51  				Type:     schema.TypeString,
    52  				Computed: true,
    53  			},
    54  		},
    55  	}
    56  }
    57  
    58  func validateAwsIamLoginProfilePasswordLength(v interface{}, _ string) (_ []string, es []error) {
    59  	length := v.(int)
    60  	if length < 4 {
    61  		es = append(es, errors.New("minimum password_length is 4 characters"))
    62  	}
    63  	if length > 128 {
    64  		es = append(es, errors.New("maximum password_length is 128 characters"))
    65  	}
    66  	return
    67  }
    68  
    69  // generatePassword generates a random password of a given length using
    70  // characters that are likely to satisfy any possible AWS password policy
    71  // (given sufficient length).
    72  func generatePassword(length int) string {
    73  	charsets := []string{
    74  		"abcdefghijklmnopqrstuvwxyz",
    75  		"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    76  		"012346789",
    77  		"!@#$%^&*()_+-=[]{}|'",
    78  	}
    79  
    80  	// Use all character sets
    81  	random := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
    82  	components := make(map[int]byte, length)
    83  	for i := 0; i < length; i++ {
    84  		charset := charsets[i%len(charsets)]
    85  		components[i] = charset[random.Intn(len(charset))]
    86  	}
    87  
    88  	// Randomise the ordering so we don't end up with a predictable
    89  	// lower case, upper case, numeric, symbol pattern
    90  	result := make([]byte, length)
    91  	i := 0
    92  	for _, b := range components {
    93  		result[i] = b
    94  		i = i + 1
    95  	}
    96  
    97  	return string(result)
    98  }
    99  
   100  func resourceAwsIamUserLoginProfileCreate(d *schema.ResourceData, meta interface{}) error {
   101  	iamconn := meta.(*AWSClient).iamconn
   102  
   103  	encryptionKey, err := encryption.RetrieveGPGKey(d.Get("pgp_key").(string))
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	username := d.Get("user").(string)
   109  	passwordResetRequired := d.Get("password_reset_required").(bool)
   110  	passwordLength := d.Get("password_length").(int)
   111  
   112  	_, err = iamconn.GetLoginProfile(&iam.GetLoginProfileInput{
   113  		UserName: aws.String(username),
   114  	})
   115  	if err != nil {
   116  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() != "NoSuchEntity" {
   117  			// If there is already a login profile, bring it under management (to prevent
   118  			// resource creation diffs) - we will never modify it, but obviously cannot
   119  			// set the password.
   120  			d.SetId(username)
   121  			d.Set("key_fingerprint", "")
   122  			d.Set("encrypted_password", "")
   123  			return nil
   124  		}
   125  	}
   126  
   127  	initialPassword := generatePassword(passwordLength)
   128  	fingerprint, encrypted, err := encryption.EncryptValue(encryptionKey, initialPassword, "Password")
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	request := &iam.CreateLoginProfileInput{
   134  		UserName:              aws.String(username),
   135  		Password:              aws.String(initialPassword),
   136  		PasswordResetRequired: aws.Bool(passwordResetRequired),
   137  	}
   138  
   139  	log.Println("[DEBUG] Create IAM User Login Profile request:", request)
   140  	createResp, err := iamconn.CreateLoginProfile(request)
   141  	if err != nil {
   142  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "EntityAlreadyExists" {
   143  			// If there is already a login profile, bring it under management (to prevent
   144  			// resource creation diffs) - we will never modify it, but obviously cannot
   145  			// set the password.
   146  			d.SetId(username)
   147  			d.Set("key_fingerprint", "")
   148  			d.Set("encrypted_password", "")
   149  			return nil
   150  		}
   151  		return errwrap.Wrapf(fmt.Sprintf("Error creating IAM User Login Profile for %q: {{err}}", username), err)
   152  	}
   153  
   154  	d.SetId(*createResp.LoginProfile.UserName)
   155  	d.Set("key_fingerprint", fingerprint)
   156  	d.Set("encrypted_password", encrypted)
   157  	return nil
   158  }