Skip to content

Commit

Permalink
Merge pull request #23161 from DrFaust92/iam_signing_cert
Browse files Browse the repository at this point in the history
r/iam_signing_certificate
  • Loading branch information
ewbankkit committed Feb 13, 2022
2 parents a8ce8f5 + 4a1a071 commit ac0a1be
Show file tree
Hide file tree
Showing 8 changed files with 559 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .changelog/23161.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_iam_signing_certificate
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,7 @@ func Provider() *schema.Provider {
"aws_iam_server_certificate": iam.ResourceServerCertificate(),
"aws_iam_service_linked_role": iam.ResourceServiceLinkedRole(),
"aws_iam_service_specific_credential": iam.ResourceServiceSpecificCredential(),
"aws_iam_signing_certificate": iam.ResourceSigningCertificate(),
"aws_iam_user": iam.ResourceUser(),
"aws_iam_user_group_membership": iam.ResourceUserGroupMembership(),
"aws_iam_user_login_profile": iam.ResourceUserLoginProfile(),
Expand Down
39 changes: 39 additions & 0 deletions internal/service/iam/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,42 @@ func FindServiceSpecificCredential(conn *iam.IAM, serviceName, userName, credID

return cred, nil
}

func FindSigningCertificate(conn *iam.IAM, userName, certId string) (*iam.SigningCertificate, error) {
input := &iam.ListSigningCertificatesInput{
UserName: aws.String(userName),
}

output, err := conn.ListSigningCertificates(input)

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

if err != nil {
return nil, err
}

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

var cert *iam.SigningCertificate

for _, crt := range output.Certificates {
if aws.StringValue(crt.UserName) == userName &&
aws.StringValue(crt.CertificateId) == certId {
cert = crt
break
}
}

if cert == nil {
return nil, tfresource.NewEmptyResultError(cert)
}

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

import ( // nosemgrep: aws-sdk-go-multiple-service-imports

"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 ResourceSigningCertificate() *schema.Resource {
return &schema.Resource{
Create: resourceSigningCertificateCreate,
Read: resourceSigningCertificateRead,
Update: resourceSigningCertificateUpdate,
Delete: resourceSigningCertificateDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"certificate_body": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: suppressNormalizeCertRemoval,
},
"certificate_id": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Optional: true,
Default: iam.StatusTypeActive,
ValidateFunc: validation.StringInSlice(iam.StatusType_Values(), false),
},
"user_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

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

createOpts := &iam.UploadSigningCertificateInput{
CertificateBody: aws.String(d.Get("certificate_body").(string)),
UserName: aws.String(d.Get("user_name").(string)),
}

log.Printf("[DEBUG] Creating IAM Signing Certificate with opts: %s", createOpts)
resp, err := conn.UploadSigningCertificate(createOpts)
if err != nil {
return fmt.Errorf("error uploading IAM Signing Certificate: %w", err)
}

cert := resp.Certificate
certId := cert.CertificateId
d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(certId), aws.StringValue(cert.UserName)))

if v, ok := d.GetOk("status"); ok && v.(string) != iam.StatusTypeActive {
updateInput := &iam.UpdateSigningCertificateInput{
CertificateId: certId,
UserName: aws.String(d.Get("user_name").(string)),
Status: aws.String(v.(string)),
}

_, err := conn.UpdateSigningCertificate(updateInput)
if err != nil {
return fmt.Errorf("error settings IAM Signing Certificate status: %w", err)
}
}

return resourceSigningCertificateRead(d, meta)
}

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

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

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

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

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

resp := outputRaw.(*iam.SigningCertificate)

d.Set("certificate_body", resp.CertificateBody)
d.Set("certificate_id", resp.CertificateId)
d.Set("user_name", resp.UserName)
d.Set("status", resp.Status)

return nil
}

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

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

updateInput := &iam.UpdateSigningCertificateInput{
CertificateId: aws.String(certId),
UserName: aws.String(userName),
Status: aws.String(d.Get("status").(string)),
}

_, err = conn.UpdateSigningCertificate(updateInput)
if err != nil {
return fmt.Errorf("error updating IAM Signing Certificate: %w", err)
}

return resourceSigningCertificateRead(d, meta)
}

func resourceSigningCertificateDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).IAMConn
log.Printf("[INFO] Deleting IAM Signing Certificate: %s", d.Id())

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

input := &iam.DeleteSigningCertificateInput{
CertificateId: aws.String(certId),
UserName: aws.String(userName),
}

if _, err := conn.DeleteSigningCertificate(input); err != nil {
if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return nil
}
return fmt.Errorf("Error deleting IAM Signing Certificate %s: %s", d.Id(), err)
}

return nil
}

func DecodeSigningCertificateId(id string) (string, string, error) {
creds := strings.Split(id, ":")
if len(creds) != 2 {
return "", "", fmt.Errorf("unknown IAM Signing Certificate ID format")
}

certId := creds[0]
userName := creds[1]

return certId, userName, nil
}
Loading

0 comments on commit ac0a1be

Please sign in to comment.