Implement AWS IAM resources
- Users - Groups - Roles - Inline policies for the above three - Instance profiles - Managed policies - Access keys This is most of the data types provided by IAM. There are a few things missing, but the functionality here is probably sufficient for 95% of the cases. Makes a dent in #28.
This commit is contained in:
parent
33183c078b
commit
b082117e92
|
@ -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_elasticache_cluster": resourceAwsElasticacheCluster(),
|
||||
"aws_elasticache_subnet_group": resourceAwsElasticacheSubnetGroup(),
|
||||
"aws_elasticache_security_group": resourceAwsElasticacheSecurityGroup(),
|
||||
"aws_eip": resourceAwsEip(),
|
||||
"aws_elasticache_cluster": resourceAwsElasticacheCluster(),
|
||||
"aws_elasticache_security_group": resourceAwsElasticacheSecurityGroup(),
|
||||
"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(),
|
||||
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/awslabs/aws-sdk-go/aws"
|
||||
"github.com/awslabs/aws-sdk-go/service/iam"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsIamGroupPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
// PutGroupPolicy API is idempotent, so these can be the same.
|
||||
Create: resourceAwsIamGroupPolicyPut,
|
||||
Update: resourceAwsIamGroupPolicyPut,
|
||||
|
||||
Read: resourceAwsIamGroupPolicyRead,
|
||||
Delete: resourceAwsIamGroupPolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"group": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamGroupPolicyPut(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.PutGroupPolicyInput{
|
||||
GroupName: aws.String(d.Get("group").(string)),
|
||||
PolicyName: aws.String(d.Get("name").(string)),
|
||||
PolicyDocument: aws.String(d.Get("policy").(string)),
|
||||
}
|
||||
|
||||
if _, err := iamconn.PutGroupPolicy(request); err != nil {
|
||||
return fmt.Errorf("Error putting IAM group policy %s: %s", *request.PolicyName, err)
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s:%s", *request.GroupName, *request.PolicyName))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamGroupPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
group, name := resourceAwsIamGroupPolicyParseId(d)
|
||||
|
||||
request := &iam.GetGroupPolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
GroupName: aws.String(group),
|
||||
}
|
||||
|
||||
getResp, err := iamconn.GetGroupPolicy(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX test me
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM policy %s from group %s: %s", name, group, err)
|
||||
}
|
||||
|
||||
if getResp.PolicyDocument == nil {
|
||||
return fmt.Errorf("GetGroupPolicy returned a nil policy document")
|
||||
}
|
||||
|
||||
policy, err := url.QueryUnescape(*getResp.PolicyDocument)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.Set("policy", policy)
|
||||
}
|
||||
|
||||
func resourceAwsIamGroupPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
group, name := resourceAwsIamGroupPolicyParseId(d)
|
||||
|
||||
request := &iam.DeleteGroupPolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
GroupName: aws.String(group),
|
||||
}
|
||||
|
||||
if _, err := iamconn.DeleteGroupPolicy(request); err != nil {
|
||||
return fmt.Errorf("Error deleting IAM group policy %s: %s", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamGroupPolicyParseId(d *schema.ResourceData) (groupName, policyName string) {
|
||||
parts := strings.SplitN(d.Id(), ":", 2)
|
||||
groupName = parts[0]
|
||||
policyName = parts[1]
|
||||
return
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
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 resourceAwsIamInstanceProfile() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsIamInstanceProfileCreate,
|
||||
Read: resourceAwsIamInstanceProfileRead,
|
||||
Update: resourceAwsIamInstanceProfileUpdate,
|
||||
Delete: resourceAwsIamInstanceProfileDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"create_date": &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,
|
||||
},
|
||||
"roles": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamInstanceProfileCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
name := d.Get("name").(string)
|
||||
|
||||
request := &iam.CreateInstanceProfileInput{
|
||||
InstanceProfileName: aws.String(name),
|
||||
Path: aws.String(d.Get("path").(string)),
|
||||
}
|
||||
|
||||
response, err := iamconn.CreateInstanceProfile(request)
|
||||
if err == nil {
|
||||
err = instanceProfileReadResult(d, response.InstanceProfile)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IAM instance profile %s: %s", name, err)
|
||||
}
|
||||
|
||||
return instanceProfileSetRoles(d, iamconn)
|
||||
}
|
||||
|
||||
func instanceProfileAddRole(iamconn *iam.IAM, profileName, roleName string) error {
|
||||
request := &iam.AddRoleToInstanceProfileInput{
|
||||
InstanceProfileName: aws.String(profileName),
|
||||
RoleName: aws.String(roleName),
|
||||
}
|
||||
|
||||
_, err := iamconn.AddRoleToInstanceProfile(request)
|
||||
return err
|
||||
}
|
||||
|
||||
func instanceProfileRemoveRole(iamconn *iam.IAM, profileName, roleName string) error {
|
||||
request := &iam.RemoveRoleFromInstanceProfileInput{
|
||||
InstanceProfileName: aws.String(profileName),
|
||||
RoleName: aws.String(roleName),
|
||||
}
|
||||
|
||||
_, err := iamconn.RemoveRoleFromInstanceProfile(request)
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func instanceProfileSetRoles(d *schema.ResourceData, iamconn *iam.IAM) error {
|
||||
oldInterface, newInterface := d.GetChange("roles")
|
||||
oldRoles := oldInterface.(*schema.Set)
|
||||
newRoles := newInterface.(*schema.Set)
|
||||
|
||||
currentRoles := schema.CopySet(oldRoles)
|
||||
|
||||
d.Partial(true)
|
||||
|
||||
for _, role := range oldRoles.Difference(newRoles).List() {
|
||||
err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err)
|
||||
}
|
||||
currentRoles.Remove(role)
|
||||
d.Set("roles", currentRoles)
|
||||
d.SetPartial("roles")
|
||||
}
|
||||
|
||||
for _, role := range newRoles.Difference(oldRoles).List() {
|
||||
err := instanceProfileAddRole(iamconn, d.Id(), role.(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error adding role %s to IAM instance profile %s: %s", role, d.Id(), err)
|
||||
}
|
||||
currentRoles.Add(role)
|
||||
d.Set("roles", currentRoles)
|
||||
d.SetPartial("roles")
|
||||
}
|
||||
|
||||
d.Partial(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func instanceProfileRemoveAllRoles(d *schema.ResourceData, iamconn *iam.IAM) error {
|
||||
for _, role := range d.Get("roles").(*schema.Set).List() {
|
||||
err := instanceProfileRemoveRole(iamconn, d.Id(), role.(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error removing role %s from IAM instance profile %s: %s", role, d.Id(), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamInstanceProfileUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
if !d.HasChange("roles") {
|
||||
return nil
|
||||
}
|
||||
|
||||
return instanceProfileSetRoles(d, iamconn)
|
||||
}
|
||||
|
||||
func resourceAwsIamInstanceProfileRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.GetInstanceProfileInput{
|
||||
InstanceProfileName: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
result, err := iamconn.GetInstanceProfile(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM instance profile %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
return instanceProfileReadResult(d, result.InstanceProfile)
|
||||
}
|
||||
|
||||
func resourceAwsIamInstanceProfileDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
if err := instanceProfileRemoveAllRoles(d, iamconn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request := &iam.DeleteInstanceProfileInput{
|
||||
InstanceProfileName: aws.String(d.Id()),
|
||||
}
|
||||
_, err := iamconn.DeleteInstanceProfile(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting IAM instance profile %s: %s", d.Id(), err)
|
||||
}
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func instanceProfileReadResult(d *schema.ResourceData, result *iam.InstanceProfile) error {
|
||||
d.SetId(*result.InstanceProfileName)
|
||||
if err := d.Set("name", result.InstanceProfileName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("path", result.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
roles := &schema.Set{F: schema.HashString}
|
||||
for _, role := range result.Roles {
|
||||
roles.Add(*role.RoleName)
|
||||
}
|
||||
if err := d.Set("roles", roles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccAwsIamInstanceProfile(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAwsIamInstanceProfileConfig,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const testAccAwsIamInstanceProfileConfig = `
|
||||
resource "aws_iam_role" "test" {
|
||||
name = "test"
|
||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "test" {
|
||||
name = "test"
|
||||
roles = ["${aws_iam_role.test.name}"]
|
||||
}
|
||||
`
|
|
@ -0,0 +1,226 @@
|
|||
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 resourceAwsIamPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsIamPolicyCreate,
|
||||
Read: resourceAwsIamPolicyRead,
|
||||
Update: resourceAwsIamPolicyUpdate,
|
||||
Delete: resourceAwsIamPolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
},
|
||||
"path": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "/",
|
||||
ForceNew: true,
|
||||
},
|
||||
"policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamPolicyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
name := d.Get("name").(string)
|
||||
|
||||
request := &iam.CreatePolicyInput{
|
||||
Description: aws.String(d.Get("description").(string)),
|
||||
Path: aws.String(d.Get("path").(string)),
|
||||
PolicyDocument: aws.String(d.Get("policy").(string)),
|
||||
PolicyName: aws.String(name),
|
||||
}
|
||||
|
||||
response, err := iamconn.CreatePolicy(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IAM policy %s: %#v", name, err)
|
||||
}
|
||||
|
||||
return readIamPolicy(d, response.Policy)
|
||||
}
|
||||
|
||||
func resourceAwsIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.GetPolicyInput{
|
||||
PolicyARN: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
response, err := iamconn.GetPolicy(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM policy %s: %#v", d.Id(), err)
|
||||
}
|
||||
|
||||
return readIamPolicy(d, response.Policy)
|
||||
}
|
||||
|
||||
func resourceAwsIamPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
if err := iamPolicyPruneVersions(d.Id(), iamconn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !d.HasChange("policy") {
|
||||
return nil
|
||||
}
|
||||
request := &iam.CreatePolicyVersionInput{
|
||||
PolicyARN: aws.String(d.Id()),
|
||||
PolicyDocument: aws.String(d.Get("policy").(string)),
|
||||
SetAsDefault: aws.Boolean(true),
|
||||
}
|
||||
|
||||
if _, err := iamconn.CreatePolicyVersion(request); err != nil {
|
||||
return fmt.Errorf("Error updating IAM policy %s: %#v", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
if err := iamPolicyDeleteNondefaultVersions(d.Id(), iamconn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request := &iam.DeletePolicyInput{
|
||||
PolicyARN: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
_, err := iamconn.DeletePolicy(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM policy %s: %#v", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// iamPolicyPruneVersions deletes the oldest versions.
|
||||
//
|
||||
// Old versions are deleted until there are 4 or less remaining, which means at
|
||||
// least one more can be created before hitting the maximum of 5.
|
||||
//
|
||||
// The default version is never deleted.
|
||||
|
||||
func iamPolicyPruneVersions(arn string, iamconn *iam.IAM) error {
|
||||
versions, err := iamPolicyListVersions(arn, iamconn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(versions) < 5 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var oldestVersion *iam.PolicyVersion
|
||||
|
||||
for _, version := range versions {
|
||||
if *version.IsDefaultVersion {
|
||||
continue
|
||||
}
|
||||
if oldestVersion == nil ||
|
||||
version.CreateDate.Before(*oldestVersion.CreateDate) {
|
||||
oldestVersion = version
|
||||
}
|
||||
}
|
||||
|
||||
if err := iamPolicyDeleteVersion(arn, *oldestVersion.VersionID, iamconn); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func iamPolicyDeleteNondefaultVersions(arn string, iamconn *iam.IAM) error {
|
||||
versions, err := iamPolicyListVersions(arn, iamconn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, version := range versions {
|
||||
if *version.IsDefaultVersion {
|
||||
continue
|
||||
}
|
||||
if err := iamPolicyDeleteVersion(arn, *version.VersionID, iamconn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func iamPolicyDeleteVersion(arn, versionID string, iamconn *iam.IAM) error {
|
||||
request := &iam.DeletePolicyVersionInput{
|
||||
PolicyARN: aws.String(arn),
|
||||
VersionID: aws.String(versionID),
|
||||
}
|
||||
|
||||
_, err := iamconn.DeletePolicyVersion(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting version %s from IAM policy %s: %#v", versionID, arn, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func iamPolicyListVersions(arn string, iamconn *iam.IAM) ([]*iam.PolicyVersion, error) {
|
||||
request := &iam.ListPolicyVersionsInput{
|
||||
PolicyARN: aws.String(arn),
|
||||
}
|
||||
|
||||
response, err := iamconn.ListPolicyVersions(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error listing versions for IAM policy %s: %#v", arn, err)
|
||||
}
|
||||
return response.Versions, nil
|
||||
}
|
||||
|
||||
func readIamPolicy(d *schema.ResourceData, policy *iam.Policy) error {
|
||||
d.SetId(*policy.ARN)
|
||||
if policy.Description != nil {
|
||||
// the description isn't present in the response to CreatePolicy.
|
||||
if err := d.Set("description", *policy.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := d.Set("path", *policy.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("name", *policy.PolicyName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("arn", *policy.ARN); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: set policy
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
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 resourceAwsIamRole() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsIamRoleCreate,
|
||||
Read: resourceAwsIamRoleRead,
|
||||
// TODO
|
||||
//Update: resourceAwsIamRoleUpdate,
|
||||
Delete: resourceAwsIamRoleDelete,
|
||||
|
||||
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,
|
||||
},
|
||||
"assume_role_policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamRoleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
name := d.Get("name").(string)
|
||||
|
||||
request := &iam.CreateRoleInput{
|
||||
Path: aws.String(d.Get("path").(string)),
|
||||
RoleName: aws.String(name),
|
||||
AssumeRolePolicyDocument: aws.String(d.Get("assume_role_policy").(string)),
|
||||
}
|
||||
|
||||
createResp, err := iamconn.CreateRole(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IAM Role %s: %s", name, err)
|
||||
}
|
||||
return resourceAwsIamRoleReadResult(d, createResp.Role)
|
||||
}
|
||||
|
||||
func resourceAwsIamRoleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.GetRoleInput{
|
||||
RoleName: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
getResp, err := iamconn.GetRole(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX test me
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM Role %s: %s", d.Id(), err)
|
||||
}
|
||||
return resourceAwsIamRoleReadResult(d, getResp.Role)
|
||||
}
|
||||
|
||||
func resourceAwsIamRoleReadResult(d *schema.ResourceData, role *iam.Role) error {
|
||||
d.SetId(*role.RoleName)
|
||||
if err := d.Set("name", role.RoleName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("arn", role.ARN); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("path", role.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("unique_id", role.RoleID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamRoleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.DeleteRoleInput{
|
||||
RoleName: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
if _, err := iamconn.DeleteRole(request); err != nil {
|
||||
return fmt.Errorf("Error deleting IAM Role %s: %s", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/awslabs/aws-sdk-go/aws"
|
||||
"github.com/awslabs/aws-sdk-go/service/iam"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsIamRolePolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
// PutRolePolicy API is idempotent, so these can be the same.
|
||||
Create: resourceAwsIamRolePolicyPut,
|
||||
Update: resourceAwsIamRolePolicyPut,
|
||||
|
||||
Read: resourceAwsIamRolePolicyRead,
|
||||
Delete: resourceAwsIamRolePolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"role": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamRolePolicyPut(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.PutRolePolicyInput{
|
||||
RoleName: aws.String(d.Get("role").(string)),
|
||||
PolicyName: aws.String(d.Get("name").(string)),
|
||||
PolicyDocument: aws.String(d.Get("policy").(string)),
|
||||
}
|
||||
|
||||
if _, err := iamconn.PutRolePolicy(request); err != nil {
|
||||
return fmt.Errorf("Error putting IAM role policy %s: %s", *request.PolicyName, err)
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s:%s", *request.RoleName, *request.PolicyName))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamRolePolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
role, name := resourceAwsIamRolePolicyParseId(d)
|
||||
|
||||
request := &iam.GetRolePolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
RoleName: aws.String(role),
|
||||
}
|
||||
|
||||
getResp, err := iamconn.GetRolePolicy(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX test me
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM policy %s from role %s: %s", name, role, err)
|
||||
}
|
||||
|
||||
if getResp.PolicyDocument == nil {
|
||||
return fmt.Errorf("GetRolePolicy returned a nil policy document")
|
||||
}
|
||||
|
||||
policy, err := url.QueryUnescape(*getResp.PolicyDocument)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.Set("policy", policy)
|
||||
}
|
||||
|
||||
func resourceAwsIamRolePolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
role, name := resourceAwsIamRolePolicyParseId(d)
|
||||
|
||||
request := &iam.DeleteRolePolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
RoleName: aws.String(role),
|
||||
}
|
||||
|
||||
if _, err := iamconn.DeleteRolePolicy(request); err != nil {
|
||||
return fmt.Errorf("Error deleting IAM role policy %s: %s", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamRolePolicyParseId(d *schema.ResourceData) (userName, policyName string) {
|
||||
parts := strings.SplitN(d.Id(), ":", 2)
|
||||
userName = parts[0]
|
||||
policyName = parts[1]
|
||||
return
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
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 resourceAwsIamUser() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsIamUserCreate,
|
||||
Read: resourceAwsIamUserRead,
|
||||
// There is an UpdateUser API call, but goamz doesn't support it yet.
|
||||
// XXX but we aren't using goamz anymore.
|
||||
//Update: resourceAwsIamUserUpdate,
|
||||
Delete: resourceAwsIamUserDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
/*
|
||||
The UniqueID could be used as the Id(), but none of the API
|
||||
calls allow specifying a user by the UniqueID: they require the
|
||||
name. The only way to locate a user by UniqueID is to list them
|
||||
all and that would make this provider unnecessarilly complex
|
||||
and inefficient. Still, there are other reasons one might want
|
||||
the UniqueID, so we can make it availible.
|
||||
*/
|
||||
"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 resourceAwsIamUserCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
name := d.Get("name").(string)
|
||||
|
||||
request := &iam.CreateUserInput{
|
||||
Path: aws.String(d.Get("path").(string)),
|
||||
UserName: aws.String(name),
|
||||
}
|
||||
|
||||
createResp, err := iamconn.CreateUser(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating IAM User %s: %s", name, err)
|
||||
}
|
||||
return resourceAwsIamUserReadResult(d, createResp.User)
|
||||
}
|
||||
|
||||
func resourceAwsIamUserRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.GetUserInput{
|
||||
UserName: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
getResp, err := iamconn.GetUser(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX test me
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM User %s: %s", d.Id(), err)
|
||||
}
|
||||
return resourceAwsIamUserReadResult(d, getResp.User)
|
||||
}
|
||||
|
||||
func resourceAwsIamUserReadResult(d *schema.ResourceData, user *iam.User) error {
|
||||
d.SetId(*user.UserName)
|
||||
if err := d.Set("name", user.UserName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("arn", user.ARN); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("path", user.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("unique_id", user.UserID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamUserDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.DeleteUserInput{
|
||||
UserName: aws.String(d.Id()),
|
||||
}
|
||||
|
||||
if _, err := iamconn.DeleteUser(request); err != nil {
|
||||
return fmt.Errorf("Error deleting IAM User %s: %s", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/awslabs/aws-sdk-go/aws"
|
||||
"github.com/awslabs/aws-sdk-go/service/iam"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsIamUserPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
// PutUserPolicy API is idempotent, so these can be the same.
|
||||
Create: resourceAwsIamUserPolicyPut,
|
||||
Update: resourceAwsIamUserPolicyPut,
|
||||
|
||||
Read: resourceAwsIamUserPolicyRead,
|
||||
Delete: resourceAwsIamUserPolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"policy": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"user": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsIamUserPolicyPut(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
request := &iam.PutUserPolicyInput{
|
||||
UserName: aws.String(d.Get("user").(string)),
|
||||
PolicyName: aws.String(d.Get("name").(string)),
|
||||
PolicyDocument: aws.String(d.Get("policy").(string)),
|
||||
}
|
||||
|
||||
if _, err := iamconn.PutUserPolicy(request); err != nil {
|
||||
return fmt.Errorf("Error putting IAM user policy %s: %s", *request.PolicyName, err)
|
||||
}
|
||||
|
||||
d.SetId(fmt.Sprintf("%s:%s", *request.UserName, *request.PolicyName))
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamUserPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
user, name := resourceAwsIamUserPolicyParseId(d)
|
||||
|
||||
request := &iam.GetUserPolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
UserName: aws.String(user),
|
||||
}
|
||||
|
||||
getResp, err := iamconn.GetUserPolicy(request)
|
||||
if err != nil {
|
||||
if iamerr, ok := err.(aws.APIError); ok && iamerr.Code == "NoSuchEntity" { // XXX test me
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading IAM policy %s from user %s: %s", name, user, err)
|
||||
}
|
||||
|
||||
if getResp.PolicyDocument == nil {
|
||||
return fmt.Errorf("GetUserPolicy returned a nil policy document")
|
||||
}
|
||||
|
||||
policy, err := url.QueryUnescape(*getResp.PolicyDocument)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.Set("policy", policy)
|
||||
}
|
||||
|
||||
func resourceAwsIamUserPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
iamconn := meta.(*AWSClient).iamconn
|
||||
|
||||
user, name := resourceAwsIamUserPolicyParseId(d)
|
||||
|
||||
request := &iam.DeleteUserPolicyInput{
|
||||
PolicyName: aws.String(name),
|
||||
UserName: aws.String(user),
|
||||
}
|
||||
|
||||
if _, err := iamconn.DeleteUserPolicy(request); err != nil {
|
||||
return fmt.Errorf("Error deleting IAM user policy %s: %s", d.Id(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsIamUserPolicyParseId(d *schema.ResourceData) (userName, policyName string) {
|
||||
parts := strings.SplitN(d.Id(), ":", 2)
|
||||
userName = parts[0]
|
||||
policyName = parts[1]
|
||||
return
|
||||
}
|
|
@ -35,11 +35,21 @@ func NewSet(f SchemaSetFunc, items []interface{}) *Set {
|
|||
return s
|
||||
}
|
||||
|
||||
// CopySet returns a copy of another set.
|
||||
func CopySet(otherSet *Set) *Set {
|
||||
return NewSet(otherSet.F, otherSet.List())
|
||||
}
|
||||
|
||||
// Add adds an item to the set if it isn't already in the set.
|
||||
func (s *Set) Add(item interface{}) {
|
||||
s.add(item)
|
||||
}
|
||||
|
||||
// Remove removes an item if it's already in the set. Idempotent.
|
||||
func (s *Set) Remove(item interface{}) {
|
||||
s.remove(item)
|
||||
}
|
||||
|
||||
// Contains checks if the set has the given item.
|
||||
func (s *Set) Contains(item interface{}) bool {
|
||||
_, ok := s.m[s.hash(item)]
|
||||
|
@ -147,6 +157,15 @@ func (s *Set) hash(item interface{}) int {
|
|||
return code
|
||||
}
|
||||
|
||||
func (s *Set) remove(item interface{}) int {
|
||||
s.once.Do(s.init)
|
||||
|
||||
code := s.F(item)
|
||||
delete(s.m, code)
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
func (s *Set) index(item interface{}) int {
|
||||
return sort.SearchInts(s.listCode(), s.hash(item))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_iam_access_key"
|
||||
sidebar_current: "docs-aws-resource-iam-access-key"
|
||||
description: |-
|
||||
Provides an IAM access key. This is a set of credentials that allow API requests to be made as an IAM user.
|
||||
---
|
||||
|
||||
# aws\_iam\_access\_key
|
||||
|
||||
Provides an IAM access key. This is a set of credentials that allow API requests to be made as an IAM user.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_iam_user" "lb" {
|
||||
name = "loadbalancer"
|
||||
path = "/system/"
|
||||
}
|
||||
|
||||
resource "aws_iam_access_key" "lb" {
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
status = "Active"
|
||||
}
|
||||
|
||||
resource "aws_iam_user_policy" "lb_ro" {
|
||||
name = "test"
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"ec2:Describe*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `user` - (Required) The IAM user to associate with this access key.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The access key ID.
|
||||
* `secret` - The secret access key. Note that this will be written to the state file.
|
||||
* `status` - "Active" or "Inactive". Keys are initially active, but can be made
|
||||
inactive by other means.
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_iam_user"
|
||||
sidebar_current: "docs-aws-resource-iam-user"
|
||||
description: |-
|
||||
Provides an IAM user.
|
||||
---
|
||||
|
||||
# aws\_iam\_user
|
||||
|
||||
Provides an IAM user.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_iam_user" "lb" {
|
||||
name = "loadbalancer"
|
||||
path = "/system/"
|
||||
}
|
||||
|
||||
resource "aws_iam_access_key" "lb" {
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
status = "Active"
|
||||
}
|
||||
|
||||
resource "aws_iam_user_policy" "lb_ro" {
|
||||
name = "test"
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"ec2:Describe*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The user's name.
|
||||
* `path` - (Optional, default "/") Path in which to create the user.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `unique_id` - The [unique ID][1] assigned by AWS.
|
||||
* `arn` - The ARN assigned by AWS for this user.
|
||||
|
||||
[1]: http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html#GUIDs
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_iam_user_policy"
|
||||
sidebar_current: "docs-aws-resource-iam-user-policy"
|
||||
description: |-
|
||||
Provides an IAM policy attached to a user.
|
||||
---
|
||||
|
||||
# aws\_iam\_user\_policy
|
||||
|
||||
Provides an IAM policy attached to a user.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_iam_user" "lb" {
|
||||
name = "loadbalancer"
|
||||
path = "/system/"
|
||||
}
|
||||
|
||||
resource "aws_iam_access_key" "lb" {
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
status = "Active"
|
||||
}
|
||||
|
||||
resource "aws_iam_user_policy" "lb_ro" {
|
||||
name = "test"
|
||||
user = "${aws_iam_user.lb.name}"
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"ec2:Describe*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `policy` - (Required) The policy document. This is a JSON formatted string.
|
||||
The heredoc syntax or `file` function is helpful here.
|
||||
* `name` - (Required) Name of the policy.
|
||||
* `user` - (Required) IAM user to which to attach this policy.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
This resource has no attributes.
|
|
@ -49,6 +49,18 @@
|
|||
<a href="/docs/providers/aws/r/elb.html">aws_elb</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-iam=access-key") %>>
|
||||
<a href="/docs/providers/aws/r/iam_access_key.html">aws_iam_access_key</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-iam-user") %>>
|
||||
<a href="/docs/providers/aws/r/iam_user.html">aws_iam_user</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-iam-user-policy") %>>
|
||||
<a href="/docs/providers/aws/r/iam_user_policy.html">aws_iam_user_policy</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-instance") %>>
|
||||
<a href="/docs/providers/aws/r/instance.html">aws_instance</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue