Skip to content

Commit

Permalink
Merge pull request #939 from bitglue/iam
Browse files Browse the repository at this point in the history
Implement a subset of IAM resources
  • Loading branch information
catsby committed May 5, 2015
2 parents 7b082d0 + d76719b commit 18b43b7
Show file tree
Hide file tree
Showing 28 changed files with 2,532 additions and 7 deletions.
23 changes: 16 additions & 7 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,28 @@ func Provider() terraform.ResourceProvider {
},

ResourcesMap: map[string]*schema.Resource{
"aws_autoscaling_group": resourceAwsAutoscalingGroup(),
"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
"aws_autoscaling_group": resourceAwsAutoscalingGroup(),
"aws_customer_gateway": resourceAwsCustomerGateway(),
"aws_db_instance": resourceAwsDbInstance(),
"aws_db_parameter_group": resourceAwsDbParameterGroup(),
"aws_db_security_group": resourceAwsDbSecurityGroup(),
"aws_db_subnet_group": resourceAwsDbSubnetGroup(),
"aws_ebs_volume": resourceAwsEbsVolume(),
"aws_eip": resourceAwsEip(),
"aws_elasticache_cluster": resourceAwsElasticacheCluster(),
"aws_elasticache_subnet_group": resourceAwsElasticacheSubnetGroup(),
"aws_elasticache_security_group": resourceAwsElasticacheSecurityGroup(),
"aws_eip": resourceAwsEip(),
"aws_elasticache_subnet_group": resourceAwsElasticacheSubnetGroup(),
"aws_elb": resourceAwsElb(),
"aws_iam_access_key": resourceAwsIamAccessKey(),
"aws_iam_group_policy": resourceAwsIamGroupPolicy(),
"aws_iam_group": resourceAwsIamGroup(),
"aws_iam_instance_profile": resourceAwsIamInstanceProfile(),
"aws_iam_policy": resourceAwsIamPolicy(),
"aws_iam_role_policy": resourceAwsIamRolePolicy(),
"aws_iam_role": resourceAwsIamRole(),
"aws_iam_user_policy": resourceAwsIamUserPolicy(),
"aws_iam_user": resourceAwsIamUser(),
"aws_instance": resourceAwsInstance(),
"aws_internet_gateway": resourceAwsInternetGateway(),
"aws_key_pair": resourceAwsKeyPair(),
Expand All @@ -107,15 +116,15 @@ func Provider() terraform.ResourceProvider {
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
"aws_route53_record": resourceAwsRoute53Record(),
"aws_route53_zone": resourceAwsRoute53Zone(),
"aws_route_table": resourceAwsRouteTable(),
"aws_route_table_association": resourceAwsRouteTableAssociation(),
"aws_route_table": resourceAwsRouteTable(),
"aws_s3_bucket": resourceAwsS3Bucket(),
"aws_security_group": resourceAwsSecurityGroup(),
"aws_subnet": resourceAwsSubnet(),
"aws_vpc": resourceAwsVpc(),
"aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(),
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
"aws_vpc_dhcp_options": resourceAwsVpcDhcpOptions(),
"aws_vpc_peering_connection": resourceAwsVpcPeeringConnection(),
"aws_vpc": resourceAwsVpc(),
"aws_vpn_connection": resourceAwsVpnConnection(),
"aws_vpn_connection_route": resourceAwsVpnConnectionRoute(),
"aws_vpn_gateway": resourceAwsVpnGateway(),
Expand Down
116 changes: 116 additions & 0 deletions builtin/providers/aws/resource_aws_iam_access_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package aws

import (
"fmt"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/iam"

"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsIamAccessKey() *schema.Resource {
return &schema.Resource{
Create: resourceAwsIamAccessKeyCreate,
Read: resourceAwsIamAccessKeyRead,
Delete: resourceAwsIamAccessKeyDelete,

Schema: map[string]*schema.Schema{
"user": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"status": &schema.Schema{
Type: schema.TypeString,
// this could be settable, but goamz does not support the
// UpdateAccessKey API yet.
Computed: true,
},
"secret": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsIamAccessKeyCreate(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn

request := &iam.CreateAccessKeyInput{
UserName: aws.String(d.Get("user").(string)),
}

createResp, err := iamconn.CreateAccessKey(request)
if err != nil {
return fmt.Errorf(
"Error creating access key for user %s: %s",
*request.UserName,
err,
)
}

if err := d.Set("secret", createResp.AccessKey.SecretAccessKey); err != nil {
return err
}
return resourceAwsIamAccessKeyReadResult(d, &iam.AccessKeyMetadata{
AccessKeyID: createResp.AccessKey.AccessKeyID,
CreateDate: createResp.AccessKey.CreateDate,
Status: createResp.AccessKey.Status,
UserName: createResp.AccessKey.UserName,
})
}

func resourceAwsIamAccessKeyRead(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn

request := &iam.ListAccessKeysInput{
UserName: aws.String(d.Get("user").(string)),
}

getResp, err := iamconn.ListAccessKeys(request)
if err != nil {
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX TEST ME
// the user does not exist, so the key can't exist.
d.SetId("")
return nil
}
return fmt.Errorf("Error reading IAM acces key: %s", err)
}

for _, key := range getResp.AccessKeyMetadata {
if key.AccessKeyID != nil && *key.AccessKeyID == d.Id() {
return resourceAwsIamAccessKeyReadResult(d, key)
}
}

// Guess the key isn't around anymore.
d.SetId("")
return nil
}

func resourceAwsIamAccessKeyReadResult(d *schema.ResourceData, key *iam.AccessKeyMetadata) error {
d.SetId(*key.AccessKeyID)
if err := d.Set("user", key.UserName); err != nil {
return err
}
if err := d.Set("status", key.Status); err != nil {
return err
}
return nil
}

func resourceAwsIamAccessKeyDelete(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn

request := &iam.DeleteAccessKeyInput{
AccessKeyID: aws.String(d.Id()),
UserName: aws.String(d.Get("user").(string)),
}

if _, err := iamconn.DeleteAccessKey(request); err != nil {
return fmt.Errorf("Error deleting access key %s: %s", d.Id(), err)
}
return nil
}
117 changes: 117 additions & 0 deletions builtin/providers/aws/resource_aws_iam_access_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package aws

import (
"fmt"
"testing"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/iam"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAccessKey_normal(t *testing.T) {
var conf iam.AccessKeyMetadata

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAccessKeyDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSAccessKeyConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf),
testAccCheckAWSAccessKeyAttributes(&conf),
),
},
},
})
}

func testAccCheckAWSAccessKeyDestroy(s *terraform.State) error {
iamconn := testAccProvider.Meta().(*AWSClient).iamconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_access_key" {
continue
}

// Try to get access key
resp, err := iamconn.ListAccessKeys(&iam.ListAccessKeysInput{
UserName: aws.String(rs.Primary.ID),
})
if err == nil {
if len(resp.AccessKeyMetadata) > 0 {
return fmt.Errorf("still exist.")
}
return nil
}

// Verify the error is what we want
ec2err, ok := err.(aws.APIError)
if !ok {
return err
}
if ec2err.Code != "NoSuchEntity" {
return err
}
}

return nil
}

func testAccCheckAWSAccessKeyExists(n string, res *iam.AccessKeyMetadata) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No Role name is set")
}

iamconn := testAccProvider.Meta().(*AWSClient).iamconn

resp, err := iamconn.ListAccessKeys(&iam.ListAccessKeysInput{
UserName: aws.String("testuser"),
})
if err != nil {
return err
}

if len(resp.AccessKeyMetadata) != 1 ||
*resp.AccessKeyMetadata[0].UserName != "testuser" {
return fmt.Errorf("User not found not found")
}

*res = *resp.AccessKeyMetadata[0]

return nil
}
}

func testAccCheckAWSAccessKeyAttributes(accessKeyMetadata *iam.AccessKeyMetadata) resource.TestCheckFunc {
return func(s *terraform.State) error {
if *accessKeyMetadata.UserName != "testuser" {
return fmt.Errorf("Bad username: %s", *accessKeyMetadata.UserName)
}

if *accessKeyMetadata.Status != "Active" {
return fmt.Errorf("Bad status: %s", *accessKeyMetadata.Status)
}

return nil
}
}

const testAccAWSAccessKeyConfig = `
resource "aws_iam_user" "a_user" {
name = "testuser"
}
resource "aws_iam_access_key" "a_key" {
user = "${aws_iam_user.a_user.name}"
}
`
106 changes: 106 additions & 0 deletions builtin/providers/aws/resource_aws_iam_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package aws

import (
"fmt"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/iam"

"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsIamGroup() *schema.Resource {
return &schema.Resource{
Create: resourceAwsIamGroupCreate,
Read: resourceAwsIamGroupRead,
// TODO
//Update: resourceAwsIamGroupUpdate,
Delete: resourceAwsIamGroupDelete,

Schema: map[string]*schema.Schema{
"arn": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"unique_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"path": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "/",
ForceNew: true,
},
},
}
}

func resourceAwsIamGroupCreate(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn
name := d.Get("name").(string)

request := &iam.CreateGroupInput{
Path: aws.String(d.Get("path").(string)),
GroupName: aws.String(name),
}

createResp, err := iamconn.CreateGroup(request)
if err != nil {
return fmt.Errorf("Error creating IAM Group %s: %s", name, err)
}
return resourceAwsIamGroupReadResult(d, createResp.Group)
}

func resourceAwsIamGroupRead(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn

request := &iam.GetGroupInput{
GroupName: aws.String(d.Id()),
}

getResp, err := iamconn.GetGroup(request)
if err != nil {
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" {
d.SetId("")
return nil
}
return fmt.Errorf("Error reading IAM Group %s: %s", d.Id(), err)
}
return resourceAwsIamGroupReadResult(d, getResp.Group)
}

func resourceAwsIamGroupReadResult(d *schema.ResourceData, group *iam.Group) error {
d.SetId(*group.GroupName)
if err := d.Set("name", group.GroupName); err != nil {
return err
}
if err := d.Set("arn", group.ARN); err != nil {
return err
}
if err := d.Set("path", group.Path); err != nil {
return err
}
if err := d.Set("unique_id", group.GroupID); err != nil {
return err
}
return nil
}

func resourceAwsIamGroupDelete(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn

request := &iam.DeleteGroupInput{
GroupName: aws.String(d.Id()),
}

if _, err := iamconn.DeleteGroup(request); err != nil {
return fmt.Errorf("Error deleting IAM Group %s: %s", d.Id(), err)
}
return nil
}
Loading

0 comments on commit 18b43b7

Please sign in to comment.