Skip to content

Commit

Permalink
ssc
Browse files Browse the repository at this point in the history
  • Loading branch information
DrFaust92 committed Feb 10, 2022
1 parent 60bd245 commit b1f1ada
Show file tree
Hide file tree
Showing 6 changed files with 482 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .changelog/16185.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_iam_service_specific_credential
```
47 changes: 24 additions & 23 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1384,29 +1384,30 @@ func Provider() *schema.Provider {
"aws_guardduty_publishing_destination": guardduty.ResourcePublishingDestination(),
"aws_guardduty_threatintelset": guardduty.ResourceThreatintelset(),

"aws_iam_access_key": iam.ResourceAccessKey(),
"aws_iam_account_alias": iam.ResourceAccountAlias(),
"aws_iam_account_password_policy": iam.ResourceAccountPasswordPolicy(),
"aws_iam_group": iam.ResourceGroup(),
"aws_iam_group_membership": iam.ResourceGroupMembership(),
"aws_iam_group_policy": iam.ResourceGroupPolicy(),
"aws_iam_group_policy_attachment": iam.ResourceGroupPolicyAttachment(),
"aws_iam_instance_profile": iam.ResourceInstanceProfile(),
"aws_iam_openid_connect_provider": iam.ResourceOpenIDConnectProvider(),
"aws_iam_policy": iam.ResourcePolicy(),
"aws_iam_policy_attachment": iam.ResourcePolicyAttachment(),
"aws_iam_role": iam.ResourceRole(),
"aws_iam_role_policy": iam.ResourceRolePolicy(),
"aws_iam_role_policy_attachment": iam.ResourceRolePolicyAttachment(),
"aws_iam_saml_provider": iam.ResourceSamlProvider(),
"aws_iam_server_certificate": iam.ResourceServerCertificate(),
"aws_iam_service_linked_role": iam.ResourceServiceLinkedRole(),
"aws_iam_user": iam.ResourceUser(),
"aws_iam_user_group_membership": iam.ResourceUserGroupMembership(),
"aws_iam_user_login_profile": iam.ResourceUserLoginProfile(),
"aws_iam_user_policy": iam.ResourceUserPolicy(),
"aws_iam_user_policy_attachment": iam.ResourceUserPolicyAttachment(),
"aws_iam_user_ssh_key": iam.ResourceUserSSHKey(),
"aws_iam_access_key": iam.ResourceAccessKey(),
"aws_iam_account_alias": iam.ResourceAccountAlias(),
"aws_iam_account_password_policy": iam.ResourceAccountPasswordPolicy(),
"aws_iam_group": iam.ResourceGroup(),
"aws_iam_group_membership": iam.ResourceGroupMembership(),
"aws_iam_group_policy": iam.ResourceGroupPolicy(),
"aws_iam_group_policy_attachment": iam.ResourceGroupPolicyAttachment(),
"aws_iam_instance_profile": iam.ResourceInstanceProfile(),
"aws_iam_openid_connect_provider": iam.ResourceOpenIDConnectProvider(),
"aws_iam_policy": iam.ResourcePolicy(),
"aws_iam_policy_attachment": iam.ResourcePolicyAttachment(),
"aws_iam_role": iam.ResourceRole(),
"aws_iam_role_policy": iam.ResourceRolePolicy(),
"aws_iam_role_policy_attachment": iam.ResourceRolePolicyAttachment(),
"aws_iam_saml_provider": iam.ResourceSamlProvider(),
"aws_iam_server_certificate": iam.ResourceServerCertificate(),
"aws_iam_service_linked_role": iam.ResourceServiceLinkedRole(),
"aws_iam_service_specific_credential": iam.ResourceServiceSpecificCredential(),
"aws_iam_user": iam.ResourceUser(),
"aws_iam_user_group_membership": iam.ResourceUserGroupMembership(),
"aws_iam_user_login_profile": iam.ResourceUserLoginProfile(),
"aws_iam_user_policy": iam.ResourceUserPolicy(),
"aws_iam_user_policy_attachment": iam.ResourceUserPolicyAttachment(),
"aws_iam_user_ssh_key": iam.ResourceUserSSHKey(),

"aws_imagebuilder_component": imagebuilder.ResourceComponent(),
"aws_imagebuilder_distribution_configuration": imagebuilder.ResourceDistributionConfiguration(),
Expand Down
37 changes: 37 additions & 0 deletions internal/service/iam/find.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iam

import (
"fmt"
"regexp"

"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -171,3 +172,39 @@ func FindRoleByName(conn *iam.IAM, name string) (*iam.Role, error) {

return output.Role, nil
}

func FindServiceSpecificCredential(conn *iam.IAM, serviceName, userName string) (*iam.ServiceSpecificCredentialMetadata, error) {
input := &iam.ListServiceSpecificCredentialsInput{
ServiceName: aws.String(serviceName),
UserName: aws.String(userName),
}

output, err := conn.ListServiceSpecificCredentials(input)

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if len(output.ServiceSpecificCredentials) == 0 || output.ServiceSpecificCredentials[0] == nil {
return nil, tfresource.NewEmptyResultError(output)
}

if count := len(output.ServiceSpecificCredentials); count > 1 {
return nil, tfresource.NewTooManyResultsError(count, output)
}

cred := output.ServiceSpecificCredentials[0]

if aws.StringValue(cred.ServiceName) != serviceName && aws.StringValue(cred.UserName) != userName {
return nil, tfresource.NewEmptyResultError(fmt.Sprintf("%s:%s", serviceName, userName))
}

return cred, nil
}
171 changes: 171 additions & 0 deletions internal/service/iam/service_specific_credential.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package iam

import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func ResourceServiceSpecificCredential() *schema.Resource {
return &schema.Resource{
Create: resourceServiceSpecificCredentialCreate,
Read: resourceServiceSpecificCredentialRead,
Update: resourceServiceSpecificCredentialUpdate,
Delete: resourceServiceSpecificCredentialDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"service_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"user_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 64),
},
"status": {
Type: schema.TypeString,
Optional: true,
Default: iam.StatusTypeActive,
ValidateFunc: validation.StringInSlice(iam.StatusType_Values(), false),
},
"service_password": {
Type: schema.TypeString,
Sensitive: true,
Computed: true,
},
"service_user_name": {
Type: schema.TypeString,
Computed: true,
},
"service_specific_credential_id": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceServiceSpecificCredentialCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).IAMConn

input := &iam.CreateServiceSpecificCredentialInput{
ServiceName: aws.String(d.Get("service_name").(string)),
UserName: aws.String(d.Get("user_name").(string)),
}

out, err := conn.CreateServiceSpecificCredential(input)
if err != nil {
return fmt.Errorf("error creating IAM Service Specific Credential: %w", err)
}

cred := out.ServiceSpecificCredential

d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(cred.ServiceName), aws.StringValue(cred.UserName)))
d.Set("service_password", cred.ServicePassword)

if v, ok := d.GetOk("status"); ok && v.(string) != iam.StatusTypeActive {
updateInput := &iam.UpdateServiceSpecificCredentialInput{
ServiceSpecificCredentialId: cred.ServiceSpecificCredentialId,
UserName: cred.UserName,
Status: aws.String(v.(string)),
}

_, err := conn.UpdateServiceSpecificCredential(updateInput)
if err != nil {
return fmt.Errorf("error settings IAM Service Specific Credential status: %w", err)
}
}

return resourceServiceSpecificCredentialRead(d, meta)
}

func resourceServiceSpecificCredentialRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).IAMConn

serviceName, userName, err := DecodeServiceSpecificCredentialId(d.Id())
if err != nil {
return err
}

outputRaw, err := tfresource.RetryWhenNewResourceNotFound(PropagationTimeout, func() (interface{}, error) {
return FindServiceSpecificCredential(conn, serviceName, userName)
}, d.IsNewResource())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] IAM Role (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading IAM Service Specific Credential (%s): %w", d.Id(), err)
}

cred := outputRaw.(*iam.ServiceSpecificCredentialMetadata)

d.Set("service_specific_credential_id", cred.ServiceSpecificCredentialId)
d.Set("service_user_name", cred.ServiceUserName)
d.Set("service_name", cred.ServiceName)
d.Set("user_name", cred.UserName)
d.Set("status", cred.Status)

return nil
}

func resourceServiceSpecificCredentialUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).IAMConn

request := &iam.UpdateServiceSpecificCredentialInput{
ServiceSpecificCredentialId: aws.String(d.Get("service_specific_credential_id").(string)),
UserName: aws.String(d.Get("user_name").(string)),
Status: aws.String(d.Get("status").(string)),
}
_, err := conn.UpdateServiceSpecificCredential(request)
if err != nil {
return fmt.Errorf("Error updating IAM Service Specific Credential %s: %s", d.Id(), err)
}

return resourceServiceSpecificCredentialRead(d, meta)
}

func resourceServiceSpecificCredentialDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).IAMConn

request := &iam.DeleteServiceSpecificCredentialInput{
ServiceSpecificCredentialId: aws.String(d.Get("service_specific_credential_id").(string)),
UserName: aws.String(d.Get("user_name").(string)),
}

if _, err := conn.DeleteServiceSpecificCredential(request); err != nil {
if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return nil
}
return fmt.Errorf("Error deleting IAM Service Specific Credential %s: %s", d.Id(), err)
}
return nil
}

func DecodeServiceSpecificCredentialId(id string) (string, string, error) {
creds := strings.Split(id, ":")
if len(creds) != 2 {
return "", "", fmt.Errorf("unknown IAM Service Specific Credential ID format")
}
serviceName := creds[0]
userName := creds[1]

return serviceName, userName, nil
}
Loading

0 comments on commit b1f1ada

Please sign in to comment.